mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 01:30:30 -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
This commit is contained in:
parent
7034563f8e
commit
caccbaef8e
7 changed files with 76 additions and 33 deletions
|
|
@ -3699,6 +3699,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);
|
||||
}
|
||||
|
||||
#ifdef SOCKET_HHOOK
|
||||
/*
|
||||
* Wrapper for Socket established helper hook.
|
||||
|
|
@ -3847,21 +3860,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:
|
||||
|
|
|
|||
|
|
@ -423,6 +423,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)
|
||||
{
|
||||
|
|
@ -2702,6 +2726,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,
|
||||
|
|
|
|||
|
|
@ -1094,10 +1094,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
|
||||
|
|
|
|||
|
|
@ -633,13 +633,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1648,10 +1648,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
|
||||
|
|
|
|||
|
|
@ -576,13 +576,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -552,6 +552,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, enum shutdown_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