mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
socket: Move SO_SETFIB handling to protocol layers
In particular, we store a FIB number in both struct socket and in struct inpcb. When updating the FIB number with setsockopt(SO_SETFIB), make the update atomic. This is required to support the new bind_all_fibs mode, since in that mode changing the FIB of a bound socket is not permitted. This requires a bit more code, but avoids a layering violation in sosetopt(), where we hard-code the list of protocol families that implement SO_SETFIB. Reviewed by: glebius MFC after: 2 weeks Sponsored by: Klara, Inc. Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D48666 (cherry picked from commit caccbaef8e263b1d769e7bcac1c4617bdc12d484)
This commit is contained in:
parent
d2ae0070a1
commit
a55bde2328
7 changed files with 76 additions and 33 deletions
|
|
@ -3698,6 +3698,19 @@ sorflush(struct socket *so)
|
|||
|
||||
}
|
||||
|
||||
int
|
||||
sosetfib(struct socket *so, int fibnum)
|
||||
{
|
||||
if (fibnum < 0 || fibnum >= rt_numfibs)
|
||||
return (EINVAL);
|
||||
|
||||
SOCK_LOCK(so);
|
||||
so->so_fibnum = fibnum;
|
||||
SOCK_UNLOCK(so);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for Socket established helper hook.
|
||||
* Parameters: socket, context of the hook point, hook id.
|
||||
|
|
@ -3844,21 +3857,7 @@ sosetopt(struct socket *so, struct sockopt *sopt)
|
|||
break;
|
||||
|
||||
case SO_SETFIB:
|
||||
error = sooptcopyin(sopt, &optval, sizeof optval,
|
||||
sizeof optval);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
if (optval < 0 || optval >= rt_numfibs) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
if (((so->so_proto->pr_domain->dom_family == PF_INET) ||
|
||||
(so->so_proto->pr_domain->dom_family == PF_INET6) ||
|
||||
(so->so_proto->pr_domain->dom_family == PF_ROUTE)))
|
||||
so->so_fibnum = optval;
|
||||
else
|
||||
so->so_fibnum = 0;
|
||||
error = so->so_proto->pr_ctloutput(so, sopt);
|
||||
break;
|
||||
|
||||
case SO_USER_COOKIE:
|
||||
|
|
|
|||
|
|
@ -425,6 +425,30 @@ rts_attach(struct socket *so, int proto, struct thread *td)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rts_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
{
|
||||
int error, optval;
|
||||
|
||||
error = ENOPROTOOPT;
|
||||
if (sopt->sopt_dir == SOPT_SET) {
|
||||
switch (sopt->sopt_level) {
|
||||
case SOL_SOCKET:
|
||||
switch (sopt->sopt_name) {
|
||||
case SO_SETFIB:
|
||||
error = sooptcopyin(sopt, &optval,
|
||||
sizeof(optval), sizeof(optval));
|
||||
if (error != 0)
|
||||
break;
|
||||
error = sosetfib(so, optval);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
rts_detach(struct socket *so)
|
||||
{
|
||||
|
|
@ -2687,6 +2711,7 @@ static struct protosw routesw = {
|
|||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_abort = rts_close,
|
||||
.pr_attach = rts_attach,
|
||||
.pr_ctloutput = rts_ctloutput,
|
||||
.pr_detach = rts_detach,
|
||||
.pr_send = rts_send,
|
||||
.pr_shutdown = rts_shutdown,
|
||||
|
|
|
|||
|
|
@ -1100,10 +1100,22 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||
sopt->sopt_dir == SOPT_SET) {
|
||||
switch (sopt->sopt_name) {
|
||||
case SO_SETFIB:
|
||||
error = sooptcopyin(sopt, &optval,
|
||||
sizeof(optval), sizeof(optval));
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
INP_WLOCK(inp);
|
||||
inp->inp_inc.inc_fibnum = so->so_fibnum;
|
||||
if ((inp->inp_flags & INP_BOUNDFIB) != 0 &&
|
||||
optval != so->so_fibnum) {
|
||||
INP_WUNLOCK(inp);
|
||||
error = EISCONN;
|
||||
break;
|
||||
}
|
||||
error = sosetfib(inp->inp_socket, optval);
|
||||
if (error == 0)
|
||||
inp->inp_inc.inc_fibnum = optval;
|
||||
INP_WUNLOCK(inp);
|
||||
error = 0;
|
||||
break;
|
||||
case SO_MAX_PACING_RATE:
|
||||
#ifdef RATELIMIT
|
||||
|
|
|
|||
|
|
@ -635,13 +635,10 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||
int error, optval;
|
||||
|
||||
if (sopt->sopt_level != IPPROTO_IP) {
|
||||
if ((sopt->sopt_level == SOL_SOCKET) &&
|
||||
(sopt->sopt_name == SO_SETFIB)) {
|
||||
INP_WLOCK(inp);
|
||||
inp->inp_inc.inc_fibnum = so->so_fibnum;
|
||||
INP_WUNLOCK(inp);
|
||||
return (0);
|
||||
}
|
||||
if (sopt->sopt_dir == SOPT_SET &&
|
||||
sopt->sopt_level == SOL_SOCKET &&
|
||||
sopt->sopt_name == SO_SETFIB)
|
||||
return (ip_ctloutput(so, sopt));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1658,10 +1658,22 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||
sopt->sopt_dir == SOPT_SET) {
|
||||
switch (sopt->sopt_name) {
|
||||
case SO_SETFIB:
|
||||
error = sooptcopyin(sopt, &optval,
|
||||
sizeof(optval), sizeof(optval));
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
INP_WLOCK(inp);
|
||||
inp->inp_inc.inc_fibnum = so->so_fibnum;
|
||||
if ((inp->inp_flags & INP_BOUNDFIB) != 0 &&
|
||||
optval != so->so_fibnum) {
|
||||
INP_WUNLOCK(inp);
|
||||
error = EISCONN;
|
||||
break;
|
||||
}
|
||||
error = sosetfib(inp->inp_socket, optval);
|
||||
if (error == 0)
|
||||
inp->inp_inc.inc_fibnum = optval;
|
||||
INP_WUNLOCK(inp);
|
||||
error = 0;
|
||||
break;
|
||||
case SO_MAX_PACING_RATE:
|
||||
#ifdef RATELIMIT
|
||||
|
|
|
|||
|
|
@ -578,13 +578,10 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||
*/
|
||||
return (icmp6_ctloutput(so, sopt));
|
||||
else if (sopt->sopt_level != IPPROTO_IPV6) {
|
||||
if (sopt->sopt_level == SOL_SOCKET &&
|
||||
sopt->sopt_name == SO_SETFIB) {
|
||||
INP_WLOCK(inp);
|
||||
inp->inp_inc.inc_fibnum = so->so_fibnum;
|
||||
INP_WUNLOCK(inp);
|
||||
return (0);
|
||||
}
|
||||
if (sopt->sopt_dir == SOPT_SET &&
|
||||
sopt->sopt_level == SOL_SOCKET &&
|
||||
sopt->sopt_name == SO_SETFIB)
|
||||
return (ip6_ctloutput(so, sopt));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -555,6 +555,7 @@ int sosend_dgram(struct socket *so, struct sockaddr *addr,
|
|||
int sosend_generic(struct socket *so, struct sockaddr *addr,
|
||||
struct uio *uio, struct mbuf *top, struct mbuf *control,
|
||||
int flags, struct thread *td);
|
||||
int sosetfib(struct socket *so, int fibnum);
|
||||
int soshutdown(struct socket *so, int how);
|
||||
void soupcall_clear(struct socket *, sb_which);
|
||||
void soupcall_set(struct socket *, sb_which, so_upcall_t, void *);
|
||||
|
|
|
|||
Loading…
Reference in a new issue