diff options
author | Peter Hessler <phessler@cvs.openbsd.org> | 2013-10-21 08:44:14 +0000 |
---|---|---|
committer | Peter Hessler <phessler@cvs.openbsd.org> | 2013-10-21 08:44:14 +0000 |
commit | 810ae1b744042fbfe474c2d431fac6f7ec5e7693 (patch) | |
tree | a5fe96798220ebb2ce30ffba2b526e7af0f3202a | |
parent | 71f6cd32c67cb5bd9cc54e8a8a308c895a4d7eaf (diff) |
Enable IPv6 routing domain support
Started by claudio@ for IPv4, lots of heavy work by sperreault@
My part started at s2k11, continued at n2k12, g2k12, c2k12 and n2k13.
Lots of help and hints from claudio and bluhm
OK claudio@, bluhm@
-rw-r--r-- | sys/net/if.c | 20 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 34 |
2 files changed, 50 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 23014af5566..b773e41cb86 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.272 2013/10/20 13:21:56 claudio Exp $ */ +/* $OpenBSD: if.c,v 1.273 2013/10/21 08:44:13 phessler Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -1213,6 +1213,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) size_t bytesdone; short oif_flags; const char *label; + short up = 0; switch (cmd) { @@ -1495,6 +1496,16 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) /* XXX hell this is ugly */ if (ifr->ifr_rdomainid != ifp->if_rdomain) { s = splnet(); + if (ifp->if_flags & IFF_UP) + up = 1; + /* + * We are tearing down the world. + * Take down the IF so: + * 1. everything that cares gets a message + * 2. the automagic IPv6 bits are recreated + */ + if (up) + if_down(ifp); rt_if_remove(ifp); #ifdef INET rti_delete(ifp); @@ -1504,7 +1515,6 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) #endif #ifdef INET6 in6_ifdetach(ifp); - ifp->if_xflags |= IFXF_NOINET6; #endif #ifdef INET in_ifdetach(ifp); @@ -1652,6 +1662,12 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) } #endif } + /* If we took down the IF, bring it back */ + if (up) { + s = splnet(); + if_up(ifp); + splx(s); + } return (error); } diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 6d5b5c04152..27da19e581b 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.145 2013/10/20 13:44:24 henning Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.146 2013/10/21 08:44:13 phessler Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -70,6 +70,7 @@ #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/proc.h> #include <sys/systm.h> #include <net/if.h> @@ -539,6 +540,7 @@ reroute: dstsock.sin6_family = AF_INET6; dstsock.sin6_addr = ip6->ip6_dst; dstsock.sin6_len = sizeof(dstsock); + ro->ro_tableid = m->m_pkthdr.rdomain; if ((error = in6_selectroute(&dstsock, opt, im6o, ro, &ifp, &rt, m->m_pkthdr.rdomain)) != 0) { switch (error) { @@ -1216,6 +1218,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro, } if (ro_pmtu->ro_rt == 0) { bzero(ro_pmtu, sizeof(*ro_pmtu)); + ro_pmtu->ro_tableid = ifp->if_rdomain; sa6_dst->sin6_family = AF_INET6; sa6_dst->sin6_len = sizeof(struct sockaddr_in6); sa6_dst->sin6_addr = *dst; @@ -1279,12 +1282,13 @@ ip6_ctloutput(int op, struct socket *so, int level, int optname, struct inpcb *inp = sotoinpcb(so); struct mbuf *m = *mp; int error, optval; + struct proc *p = curproc; /* For IPSec and rdomain */ #ifdef IPSEC - struct proc *p = curproc; /* XXX */ struct tdb *tdb; struct tdb_ident *tdbip, tdbi; int s; #endif + u_int rtid = 0; error = optval = 0; @@ -1697,6 +1701,26 @@ do { \ inp->inp_secrequire = get_sa_require(inp); #endif break; + case SO_RTABLE: + if (m == NULL || m->m_len < sizeof(u_int)) { + error = EINVAL; + break; + } + rtid = *mtod(m, u_int *); + if (inp->inp_rtableid == rtid) + break; + /* needs privileges to switch when already set */ + if (p->p_p->ps_rtableid != rtid && + p->p_p->ps_rtableid != 0 && + (error = suser(p, 0)) != 0) + break; + /* table must exist */ + if (!rtable_exists(rtid)) { + error = EINVAL; + break; + } + inp->inp_rtableid = rtid; + break; case IPV6_PIPEX: if (m != NULL && m->m_len == sizeof(int)) inp->inp_pipex = *mtod(m, int *); @@ -1948,6 +1972,11 @@ do { \ *mtod(m, int *) = optval; #endif break; + case SO_RTABLE: + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(u_int); + *mtod(m, u_int *) = optval; + break; case IPV6_PIPEX: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); @@ -2444,6 +2473,7 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m) * XXX: is it a good approach? */ bzero(&ro, sizeof(ro)); + ro.ro_tableid = m->m_pkthdr.rdomain; dst = &ro.ro_dst; dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_family = AF_INET6; |