summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hessler <phessler@cvs.openbsd.org>2013-10-21 08:44:14 +0000
committerPeter Hessler <phessler@cvs.openbsd.org>2013-10-21 08:44:14 +0000
commit810ae1b744042fbfe474c2d431fac6f7ec5e7693 (patch)
treea5fe96798220ebb2ce30ffba2b526e7af0f3202a
parent71f6cd32c67cb5bd9cc54e8a8a308c895a4d7eaf (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.c20
-rw-r--r--sys/netinet6/ip6_output.c34
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;