[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Fri Mar 2 15:39:28 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/e8250b8e4ab7
changeset: 387:e8250b8e4ab7
user:      ray at terran.dlink.ua
date:      Fri Mar 02 17:11:55 2012 +0200
description:
Update to FreeBSD-HEAD @232391

diffstat:

 head/sys/netinet6/icmp6.c        |   20 +-
 head/sys/netinet6/in6.c          |  665 +++++++++++++++++++-------------------
 head/sys/netinet6/in6_gif.c      |    9 +-
 head/sys/netinet6/in6_ifattach.c |   26 +-
 head/sys/netinet6/in6_mcast.c    |   11 +-
 head/sys/netinet6/in6_rmx.c      |  126 +++++-
 head/sys/netinet6/in6_src.c      |   75 +++-
 head/sys/netinet6/in6_var.h      |   13 +-
 head/sys/netinet6/ip6_forward.c  |    4 +-
 head/sys/netinet6/ip6_input.c    |    6 +-
 head/sys/netinet6/ip6_output.c   |   28 +-
 head/sys/netinet6/ip6_var.h      |    5 +-
 head/sys/netinet6/nd6.c          |   17 +-
 head/sys/netinet6/nd6_nbr.c      |   47 ++-
 head/sys/netinet6/nd6_rtr.c      |  190 ++++++----
 head/sys/netinet6/raw_ip6.c      |   14 +-
 head/sys/netinet6/sctp6_usrreq.c |    4 +-
 17 files changed, 730 insertions(+), 530 deletions(-)

diffs (2169 lines):

diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/icmp6.c
--- a/head/sys/netinet6/icmp6.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/icmp6.c	Fri Mar 02 17:11:55 2012 +0200
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/icmp6.c 229621 2012-01-05 19:00:36Z jhb $");
+__FBSDID("$FreeBSD: head/sys/netinet6/icmp6.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -360,7 +360,7 @@
 		m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
 
 	preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
-	M_PREPEND(m, preplen, M_DONTWAIT);
+	M_PREPEND(m, preplen, M_DONTWAIT);	/* FIB is also copied over. */
 	if (m && m->m_len < preplen)
 		m = m_pullup(m, preplen);
 	if (m == NULL) {
@@ -584,7 +584,7 @@
 			MGETHDR(n, M_DONTWAIT, n0->m_type);
 			n0len = n0->m_pkthdr.len;	/* save for use below */
 			if (n)
-				M_MOVE_PKTHDR(n, n0);
+				M_MOVE_PKTHDR(n, n0);	/* FIB copied. */
 			if (n && maxlen >= MHLEN) {
 				MCLGET(n, M_DONTWAIT);
 				if ((n->m_flags & M_EXT) == 0) {
@@ -1502,7 +1502,7 @@
 		m_freem(m);
 		return (NULL);
 	}
-	M_MOVE_PKTHDR(n, m); /* just for recvif */
+	M_MOVE_PKTHDR(n, m); /* just for recvif and FIB */
 	if (replylen > MHLEN) {
 		if (replylen > MCLBYTES) {
 			/*
@@ -2414,7 +2414,7 @@
 	sin6.sin6_family = AF_INET6;
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
-	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt) {
 		if (rt->rt_gateway == NULL ||
 		    rt->rt_gateway->sa_family != AF_INET6) {
@@ -2501,6 +2501,7 @@
 		struct sockaddr_in6 sdst;
 		struct sockaddr_in6 sgw;
 		struct sockaddr_in6 ssrc;
+		u_int fibnum;
 
 		bzero(&sdst, sizeof(sdst));
 		bzero(&sgw, sizeof(sgw));
@@ -2511,9 +2512,11 @@
 		bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
 		bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
 		bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
-		rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
-		    (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
-		    (struct sockaddr *)&ssrc);
+		for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
+			in6_rtredirect((struct sockaddr *)&sdst,
+			    (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
+			    RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
+			    fibnum);
 	}
 	/* finally update cached route in each socket via pfctlinput */
     {
@@ -2598,6 +2601,7 @@
 		MCLGET(m, M_DONTWAIT);
 	if (!m)
 		goto fail;
+	M_SETFIB(m, rt->rt_fibnum);
 	m->m_pkthdr.rcvif = NULL;
 	m->m_len = 0;
 	maxlen = M_TRAILINGSPACE(m);
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6.c
--- a/head/sys/netinet6/in6.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6.c	Fri Mar 02 17:11:55 2012 +0200
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/in6.c 230506 2012-01-24 13:57:30Z bz $");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6.c 232054 2012-02-23 18:21:37Z kmacy $");
 
 #include "opt_compat.h"
 #include "opt_inet.h"
@@ -180,6 +180,7 @@
 	rt_mask(&rt) = (struct sockaddr *)&mask;
 	rt_key(&rt) = (struct sockaddr *)&addr;
 	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+	/* Announce arrival of local address to all FIBs. */
 	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
 }
 
@@ -214,6 +215,7 @@
 	rt_mask(&rt0) = (struct sockaddr *)&mask;
 	rt_key(&rt0) = (struct sockaddr *)&addr;
 	rt0.rt_flags = RTF_HOST | RTF_STATIC;
+	/* Announce removal of local address to all FIBs. */
 	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
 }
 
@@ -282,6 +284,11 @@
 	switch (cmd) {
 	case SIOCGETSGCNT_IN6:
 	case SIOCGETMIFCNT_IN6:
+		/*	
+		 * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
+		 * We cannot see how that would be needed, so do not adjust the
+		 * KPI blindly; more likely should clean up the IPv4 variant.
+		 */
 		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
 	}
 
@@ -820,6 +827,170 @@
 	return (error);
 }
 
+
+/*
+ * Join necessary multicast groups.  Factored out from in6_update_ifa().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
+    struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
+{
+	char ip6buf[INET6_ADDRSTRLEN];
+	struct sockaddr_in6 mltaddr, mltmask;
+	struct in6_addr llsol;
+	struct in6_multi_mship *imm;
+	struct rtentry *rt;
+	int delay, error;
+
+	KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
+
+	/* Join solicited multicast addr for new host id. */
+	bzero(&llsol, sizeof(struct in6_addr));
+	llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+	llsol.s6_addr32[1] = 0;
+	llsol.s6_addr32[2] = htonl(1);
+	llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
+	llsol.s6_addr8[12] = 0xff;
+	if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
+		/* XXX: should not happen */
+		log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
+		goto cleanup;
+	}
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * We need a random delay for DAD on the address being
+		 * configured.  It also means delaying transmission of the
+		 * corresponding MLD report to avoid report collision.
+		 * [RFC 4861, Section 6.3.7]
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	imm = in6_joingroup(ifp, &llsol, &error, delay);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
+		    if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	*in6m_sol = imm->i6mm_maddr;
+
+	bzero(&mltmask, sizeof(mltmask));
+	mltmask.sin6_len = sizeof(struct sockaddr_in6);
+	mltmask.sin6_family = AF_INET6;
+	mltmask.sin6_addr = in6mask32;
+#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
+
+	/*
+	 * Join link-local all-nodes address.
+	 */
+	bzero(&mltaddr, sizeof(mltaddr));
+	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+	mltaddr.sin6_family = AF_INET6;
+	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		goto cleanup; /* XXX: should not fail */
+
+	/*
+	 * XXX: do we really need this automatic routes?  We should probably
+	 * reconsider this stuff.  Most applications actually do not need the
+	 * routes, since they usually specify the outgoing interface.
+	 */
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+	if (rt != NULL) {
+		/* XXX: only works in !SCOPEDROUTING case. */
+		if (memcmp(&mltaddr.sin6_addr,
+		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0, RT_DEFAULT_FIB);
+		if (error)
+			goto cleanup;
+	} else
+		RTFREE_LOCKED(rt);
+
+	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+		    &mltaddr.sin6_addr), if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+
+	/*
+	 * Join node information group address.
+	 */
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * The spec does not say anything about delay for this group,
+		 * but the same logic should apply.
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
+		/* XXX jinmei */
+		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
+		if (imm == NULL)
+			nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+			    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+			    &mltaddr.sin6_addr), if_name(ifp), error));
+			/* XXX not very fatal, go on... */
+		else
+			LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	}
+
+	/*
+	 * Join interface-local all-nodes address.
+	 * (ff01::1%ifN, and ff01::%ifN/32)
+	 */
+	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		goto cleanup; /* XXX: should not fail */
+	/* XXX: again, do we really need the route? */
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+	if (rt != NULL) {
+		if (memcmp(&mltaddr.sin6_addr,
+		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0, RT_DEFAULT_FIB);
+		if (error)
+			goto cleanup;
+	} else
+		RTFREE_LOCKED(rt);
+
+	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+		    &mltaddr.sin6_addr), if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+#undef	MLTMASK_LEN
+
+cleanup:
+	return (error);
+}
+
 /*
  * Update parameters of an IPv6 interface address.
  * If necessary, a new entry is created and linked into address chains.
@@ -833,9 +1004,7 @@
 	int error = 0, hostIsNew = 0, plen = -1;
 	struct sockaddr_in6 dst6;
 	struct in6_addrlifetime *lt;
-	struct in6_multi_mship *imm;
 	struct in6_multi *in6m_sol;
-	struct rtentry *rt;
 	int delay;
 	char ip6buf[INET6_ADDRSTRLEN];
 
@@ -1083,178 +1252,17 @@
 	 * not just go to unlink.
 	 */
 
-	/* Join necessary multicast groups */
+	/* Join necessary multicast groups. */
 	in6m_sol = NULL;
 	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
-		struct sockaddr_in6 mltaddr, mltmask;
-		struct in6_addr llsol;
-
-		/* join solicited multicast addr for new host id */
-		bzero(&llsol, sizeof(struct in6_addr));
-		llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
-		llsol.s6_addr32[1] = 0;
-		llsol.s6_addr32[2] = htonl(1);
-		llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
-		llsol.s6_addr8[12] = 0xff;
-		if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
-			/* XXX: should not happen */
-			log(LOG_ERR, "in6_update_ifa: "
-			    "in6_setscope failed\n");
+		error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
+		if (error)
 			goto cleanup;
-		}
-		delay = 0;
-		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
-			/*
-			 * We need a random delay for DAD on the address
-			 * being configured.  It also means delaying
-			 * transmission of the corresponding MLD report to
-			 * avoid report collision.
-			 * [RFC 4861, Section 6.3.7]
-			 */
-			delay = arc4random() %
-			    (MAX_RTR_SOLICITATION_DELAY * hz);
-		}
-		imm = in6_joingroup(ifp, &llsol, &error, delay);
-		if (imm == NULL) {
-			nd6log((LOG_WARNING,
-			    "in6_update_ifa: addmulti failed for "
-			    "%s on %s (errno=%d)\n",
-			    ip6_sprintf(ip6buf, &llsol), if_name(ifp),
-			    error));
-			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships,
-		    imm, i6mm_chain);
-		in6m_sol = imm->i6mm_maddr;
-
-		bzero(&mltmask, sizeof(mltmask));
-		mltmask.sin6_len = sizeof(struct sockaddr_in6);
-		mltmask.sin6_family = AF_INET6;
-		mltmask.sin6_addr = in6mask32;
-#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
-
-		/*
-		 * join link-local all-nodes address
-		 */
-		bzero(&mltaddr, sizeof(mltaddr));
-		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
-		mltaddr.sin6_family = AF_INET6;
-		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
-		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
-		    0)
-			goto cleanup; /* XXX: should not fail */
-
-		/*
-		 * XXX: do we really need this automatic routes?
-		 * We should probably reconsider this stuff.  Most applications
-		 * actually do not need the routes, since they usually specify
-		 * the outgoing interface.
-		 */
-		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-		if (rt) {
-			/* XXX: only works in !SCOPEDROUTING case. */
-			if (memcmp(&mltaddr.sin6_addr,
-			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
-			    MLTMASK_LEN)) {
-				RTFREE_LOCKED(rt);
-				rt = NULL;
-			}
-		}
-		if (!rt) {
-			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
-			if (error)
-				goto cleanup;
-		} else {
-			RTFREE_LOCKED(rt);
-		}
-
-		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
-		if (!imm) {
-			nd6log((LOG_WARNING,
-			    "in6_update_ifa: addmulti failed for "
-			    "%s on %s (errno=%d)\n",
-			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-			    if_name(ifp), error));
-			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-
-		/*
-		 * join node information group address
-		 */
-		delay = 0;
-		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
-			/*
-			 * The spec doesn't say anything about delay for this
-			 * group, but the same logic should apply.
-			 */
-			delay = arc4random() %
-			    (MAX_RTR_SOLICITATION_DELAY * hz);
-		}
-		if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
-			imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
-			    delay); /* XXX jinmei */
-			if (!imm) {
-				nd6log((LOG_WARNING, "in6_update_ifa: "
-				    "addmulti failed for %s on %s "
-				    "(errno=%d)\n",
-				    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-				    if_name(ifp), error));
-				/* XXX not very fatal, go on... */
-			} else {
-				LIST_INSERT_HEAD(&ia->ia6_memberships,
-				    imm, i6mm_chain);
-			}
-		}
-
-		/*
-		 * join interface-local all-nodes address.
-		 * (ff01::1%ifN, and ff01::%ifN/32)
-		 */
-		mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
-		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
-		    != 0)
-			goto cleanup; /* XXX: should not fail */
-		/* XXX: again, do we really need the route? */
-		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-		if (rt) {
-			if (memcmp(&mltaddr.sin6_addr,
-			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
-			    MLTMASK_LEN)) {
-				RTFREE_LOCKED(rt);
-				rt = NULL;
-			}
-		}
-		if (!rt) {
-			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
-			if (error)
-				goto cleanup;
-		} else
-			RTFREE_LOCKED(rt);
-
-		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
-		if (!imm) {
-			nd6log((LOG_WARNING, "in6_update_ifa: "
-			    "addmulti failed for %s on %s "
-			    "(errno=%d)\n",
-			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-			    if_name(ifp), error));
-			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-#undef	MLTMASK_LEN
 	}
 
 	/*
 	 * Perform DAD, if needed.
-	 * XXX It may be of use, if we can administratively
-	 * disable DAD.
+	 * XXX It may be of use, if we can administratively disable DAD.
 	 */
 	if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
 	    (ia->ia6_flags & IN6_IFF_TENTATIVE))
@@ -1312,15 +1320,143 @@
 	return error;
 }
 
+/*
+ * Leave multicast groups.  Factored out from in6_purgeaddr().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
+{
+	struct sockaddr_in6 mltaddr, mltmask;
+	struct in6_multi_mship *imm;
+	struct rtentry *rt;
+	int error;
+
+	/*
+	 * Leave from multicast groups we have joined for the interface.
+	 */
+	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
+		LIST_REMOVE(imm, i6mm_chain);
+		in6_leavegroup(imm);
+	}
+
+	/*
+	 * Remove the link-local all-nodes address.
+	 */
+	bzero(&mltmask, sizeof(mltmask));
+	mltmask.sin6_len = sizeof(struct sockaddr_in6);
+	mltmask.sin6_family = AF_INET6;
+	mltmask.sin6_addr = in6mask32;
+
+	bzero(&mltaddr, sizeof(mltaddr));
+	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+	mltaddr.sin6_family = AF_INET6;
+	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		return (error);
+
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+	if (rt != NULL && rt->rt_gateway != NULL &&
+	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
+		    &ia->ia_addr.sin6_addr,
+		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
+		/* 
+		 * If no more IPv6 address exists on this interface then
+		 * remove the multicast address route.
+		 */
+		if (ifa0 == NULL) {
+			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
+			       sizeof(mltaddr.sin6_addr));
+			RTFREE_LOCKED(rt);
+			error = in6_rtrequest(RTM_DELETE,
+			    (struct sockaddr *)&mltaddr,
+			    (struct sockaddr *)&ia->ia_addr,
+			    (struct sockaddr *)&mltmask, RTF_UP,
+			    (struct rtentry **)0, RT_DEFAULT_FIB);
+			if (error)
+				log(LOG_INFO, "%s: link-local all-nodes "
+				    "multicast address deletion error\n",
+				    __func__);
+		} else {
+			/*
+			 * Replace the gateway of the route.
+			 */
+			struct sockaddr_in6 sa;
+
+			bzero(&sa, sizeof(sa));
+			sa.sin6_len = sizeof(struct sockaddr_in6);
+			sa.sin6_family = AF_INET6;
+			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 
+			       sizeof(sa.sin6_addr));
+			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
+			memcpy(rt->rt_gateway, &sa, sizeof(sa));
+			RTFREE_LOCKED(rt);
+		}
+	} else {
+		if (rt != NULL)
+			RTFREE_LOCKED(rt);
+	}
+
+	/*
+	 * Remove the node-local all-nodes address.
+	 */
+	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		return (error);
+
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+	if (rt != NULL && rt->rt_gateway != NULL &&
+	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
+		    &ia->ia_addr.sin6_addr,
+		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
+		/* 
+		 * If no more IPv6 address exists on this interface then
+		 * remove the multicast address route.
+		 */
+		if (ifa0 == NULL) {
+			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
+			       sizeof(mltaddr.sin6_addr));
+
+			RTFREE_LOCKED(rt);
+			error = in6_rtrequest(RTM_DELETE,
+			    (struct sockaddr *)&mltaddr,
+			    (struct sockaddr *)&ia->ia_addr,
+			    (struct sockaddr *)&mltmask, RTF_UP,
+			    (struct rtentry **)0, RT_DEFAULT_FIB);
+			if (error)
+				log(LOG_INFO, "%s: node-local all-nodes"
+				    "multicast address deletion error\n",
+				    __func__);
+		} else {
+			/*
+			 * Replace the gateway of the route.
+			 */
+			struct sockaddr_in6 sa;
+
+			bzero(&sa, sizeof(sa));
+			sa.sin6_len = sizeof(struct sockaddr_in6);
+			sa.sin6_family = AF_INET6;
+			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 
+			       sizeof(sa.sin6_addr));
+			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
+			memcpy(rt->rt_gateway, &sa, sizeof(sa));
+			RTFREE_LOCKED(rt);
+		}
+	} else {
+		if (rt != NULL)
+			RTFREE_LOCKED(rt);
+	}
+
+	return (0);
+}
+
 void
 in6_purgeaddr(struct ifaddr *ifa)
 {
 	struct ifnet *ifp = ifa->ifa_ifp;
 	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
-	struct in6_multi_mship *imm;
-	struct sockaddr_in6 mltaddr, mltmask;
 	int plen, error;
-	struct rtentry *rt;
 	struct ifaddr *ifa0;
 
 	if (ifa->ifa_carp)
@@ -1360,147 +1496,22 @@
 	/* stop DAD processing */
 	nd6_dad_stop(ifa);
 
+	/* Remove local address entry from lltable. */
 	in6_ifremloop(ifa);
 
-	/*
-	 * leave from multicast groups we have joined for the interface
-	 */
-	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
-		LIST_REMOVE(imm, i6mm_chain);
-		in6_leavegroup(imm);
-	}
+	/* Leave multicast groups. */
+	error = in6_purgeaddr_mc(ifp, ia, ifa0);
 
-	/*
-	 * remove the link-local all-nodes address
-	 */
-	bzero(&mltmask, sizeof(mltmask));
-	mltmask.sin6_len = sizeof(struct sockaddr_in6);
-	mltmask.sin6_family = AF_INET6;
-	mltmask.sin6_addr = in6mask32;
-
-	bzero(&mltaddr, sizeof(mltaddr));
-	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
-	mltaddr.sin6_family = AF_INET6;
-	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
-
-	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
-		goto cleanup; 
-
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-	if (rt != NULL && rt->rt_gateway != NULL &&
-	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
-		    &ia->ia_addr.sin6_addr,
-		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
-		/* 
-		 * if no more IPv6 address exists on this interface
-		 * then remove the multicast address route
-		 */
-		if (ifa0 == NULL) {
-			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
-			       sizeof(mltaddr.sin6_addr));
-			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
-					  (struct sockaddr *)&ia->ia_addr,
-					  (struct sockaddr *)&mltmask, RTF_UP,
-					  (struct rtentry **)0);
-			if (error)
-				log(LOG_INFO, "in6_purgeaddr: link-local all-nodes"
-				    "multicast address deletion error\n");
-		} else {
-			/*
-			 * replace the gateway of the route
-			 */
-			struct sockaddr_in6 sa;
-
-			bzero(&sa, sizeof(sa));
-			sa.sin6_len = sizeof(struct sockaddr_in6);
-			sa.sin6_family = AF_INET6;
-			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 
-			       sizeof(sa.sin6_addr));
-			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
-			memcpy(rt->rt_gateway, &sa, sizeof(sa));
-			RTFREE_LOCKED(rt);
-		}
-	} else {
-		if (rt != NULL)
-			RTFREE_LOCKED(rt);
-	}
-
-	/*
-	 * remove the node-local all-nodes address
-	 */
-	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
-	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
-	    0)
-		goto cleanup;
-
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-	if (rt != NULL && rt->rt_gateway != NULL &&
-	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
-		    &ia->ia_addr.sin6_addr,
-		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
-		/* 
-		 * if no more IPv6 address exists on this interface
-		 * then remove the multicast address route
-		 */
-		if (ifa0 == NULL) {
-			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
-			       sizeof(mltaddr.sin6_addr));
-
-			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
-					  (struct sockaddr *)&ia->ia_addr,
-					  (struct sockaddr *)&mltmask, RTF_UP,
-					  (struct rtentry **)0);
-
-			if (error)
-				log(LOG_INFO, "in6_purgeaddr: node-local all-nodes"
-				    "multicast address deletion error\n");
-		} else {
-			/*
-			 * replace the gateway of the route
-			 */
-			struct sockaddr_in6 sa;
-
-			bzero(&sa, sizeof(sa));
-			sa.sin6_len = sizeof(struct sockaddr_in6);
-			sa.sin6_family = AF_INET6;
-			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 
-			       sizeof(sa.sin6_addr));
-			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
-			memcpy(rt->rt_gateway, &sa, sizeof(sa));
-			RTFREE_LOCKED(rt);
-		}
-	} else {
-		if (rt != NULL)
-			RTFREE_LOCKED(rt);
-	}
-
-cleanup:
 	if (ifa0 != NULL)
 		ifa_free(ifa0);
 
 	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
 	if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
-		int error;
-		struct sockaddr *dstaddr;
-
-		/* 
-		 * use the interface address if configuring an
-		 * interface address with a /128 prefix len
-		 */
-		if (ia->ia_dstaddr.sin6_family == AF_INET6)
-			dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
-		else
-			dstaddr = (struct sockaddr *)&ia->ia_addr;
-
-		error = rtrequest(RTM_DELETE,
-		    (struct sockaddr *)dstaddr,
-		    (struct sockaddr *)&ia->ia_addr,
-		    (struct sockaddr *)&ia->ia_prefixmask,
-		    ia->ia_flags | RTF_HOST, NULL);
+		error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
+		    (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0);
 		if (error != 0)
-			return;
+			log(LOG_INFO, "%s: err=%d, destination address delete "
+			    "failed\n", __func__, error);
 		ia->ia_flags &= ~IFA_ROUTE;
 	}
 
@@ -1832,8 +1843,7 @@
 }
 
 /*
- * Initialize an interface's intetnet6 address
- * and routing table entry.
+ * Initialize an interface's IPv6 address and routing table entry.
  */
 static int
 in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
@@ -1883,13 +1893,8 @@
 	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
 	    ia->ia_dstaddr.sin6_family == AF_INET6) {
 		int rtflags = RTF_UP | RTF_HOST;
-
-		error = rtrequest(RTM_ADD,
-		    (struct sockaddr *)&ia->ia_dstaddr,
-		    (struct sockaddr *)&ia->ia_addr,
-		    (struct sockaddr *)&ia->ia_prefixmask,
-		    ia->ia_flags | rtflags, NULL);
-		if (error != 0)
+		error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
+		if (error)
 			return (error);
 		ia->ia_flags |= IFA_ROUTE;
 		/*
@@ -1909,7 +1914,7 @@
 			ia->ia_flags |= IFA_RTSELF;
 	}
 
-	/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
+	/* Add local address to lltable, if necessary (ex. on p2p link). */
 	if (newhost)
 		in6_ifaddloop(&(ia->ia_ifa));
 
@@ -2434,6 +2439,20 @@
 	struct sockaddr_in6	l3_addr6;
 };
 
+/*
+ * Deletes an address from the address table.
+ * This function is called by the timer functions
+ * such as arptimer() and nd6_llinfo_timer(), and
+ * the caller does the locking.
+ */
+static void
+in6_lltable_free(struct lltable *llt, struct llentry *lle)
+{
+	LLE_WUNLOCK(lle);
+	LLE_LOCK_DESTROY(lle);
+	free(lle, M_LLTABLE);
+}
+
 static struct llentry *
 in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
 {
@@ -2446,6 +2465,7 @@
 
 	lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
 	lle->base.lle_refcnt = 1;
+	lle->base.lle_free = in6_lltable_free;
 	LLE_LOCK_INIT(&lle->base);
 	callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
 	    CALLOUT_RETURNUNLOCKED);
@@ -2453,20 +2473,6 @@
 	return &lle->base;
 }
 
-/*
- * Deletes an address from the address table.
- * This function is called by the timer functions
- * such as arptimer() and nd6_llinfo_timer(), and
- * the caller does the locking.
- */
-static void
-in6_lltable_free(struct lltable *llt, struct llentry *lle)
-{
-	LLE_WUNLOCK(lle);
-	LLE_LOCK_DESTROY(lle);
-	free(lle, M_LLTABLE);
-}
-
 static void
 in6_lltable_prefix_free(struct lltable *llt, 
 			const struct sockaddr *prefix,
@@ -2512,8 +2518,10 @@
 	KASSERT(l3addr->sa_family == AF_INET6,
 	    ("sin_family %d", l3addr->sa_family));
 
+	/* Our local addresses are always only installed on the default FIB. */
 	/* XXX rtalloc1 should take a const param */
-	rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+	rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0,
+	    RT_DEFAULT_FIB);
 	if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
 		struct ifaddr *ifa;
 		/* 
@@ -2706,7 +2714,6 @@
 	ext->scope6_id = scope6_ifattach(ifp);
 	ext->lltable = lltable_init(ifp, AF_INET6);
 	if (ext->lltable != NULL) {
-		ext->lltable->llt_free = in6_lltable_free;
 		ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
 		ext->lltable->llt_lookup = in6_lltable_lookup;
 		ext->lltable->llt_dump = in6_lltable_dump;
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_gif.c
--- a/head/sys/netinet6/in6_gif.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_gif.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/in6_gif.c 223637 2011-06-28 11:57:25Z bz $");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6_gif.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -228,6 +228,8 @@
 	ip6->ip6_flow &= ~htonl(0xff << 20);
 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
 
+	M_SETFIB(m, sc->gif_fibnum);
+
 	if (dst->sin6_family != sin6_dst->sin6_family ||
 	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
 		/* cache route doesn't match */
@@ -245,7 +247,7 @@
 	}
 
 	if (sc->gif_ro6.ro_rt == NULL) {
-		rtalloc((struct route *)&sc->gif_ro6);
+		in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum);
 		if (sc->gif_ro6.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH;
@@ -404,7 +406,8 @@
 		sin6.sin6_addr = ip6->ip6_src;
 		sin6.sin6_scope_id = 0; /* XXX */
 
-		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL,
+		    sc->gif_fibnum);
 		if (!rt || rt->rt_ifp != ifp) {
 #if 0
 			char ip6buf[INET6_ADDRSTRLEN];
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_ifattach.c
--- a/head/sys/netinet6/in6_ifattach.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_ifattach.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/in6_ifattach.c 229621 2012-01-05 19:00:36Z jhb $");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6_ifattach.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -790,7 +790,6 @@
 	struct ifaddr *ifa, *next;
 	struct radix_node_head *rnh;
 	struct rtentry *rt;
-	short rtflags;
 	struct sockaddr_in6 sin6;
 	struct in6_multi_mship *imm;
 
@@ -821,16 +820,9 @@
 			in6_leavegroup(imm);
 		}
 
-		/* remove from the routing table */
-		if ((ia->ia_flags & IFA_ROUTE) &&
-		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
-			rtflags = rt->rt_flags;
-			RTFREE_LOCKED(rt);
-			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&ia->ia_prefixmask,
-			    rtflags, (struct rtentry **)0);
-		}
+		/* Remove link-local from the routing table. */
+		if (ia->ia_flags & IFA_ROUTE)
+			(void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
 
 		/* remove from the linked list */
 		IF_ADDR_WLOCK(ifp);
@@ -859,7 +851,10 @@
 	 */
 	nd6_purge(ifp);
 
-	/* remove route to link-local allnodes multicast (ff02::1) */
+	/*
+	 * Remove route to link-local allnodes multicast (ff02::1).
+	 * These only get automatically installed for the default FIB.
+	 */
 	bzero(&sin6, sizeof(sin6));
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	sin6.sin6_family = AF_INET6;
@@ -868,10 +863,11 @@
 		/* XXX: should not fail */
 		return;
 	/* XXX grab lock first to avoid LOR */
-	rnh = rt_tables_get_rnh(0, AF_INET6);
+	rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
 	if (rnh != NULL) {
 		RADIX_NODE_HEAD_LOCK(rnh);
-		rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED);
+		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
+		    RT_DEFAULT_FIB);
 		if (rt) {
 			if (rt->rt_ifp == ifp)
 				rtexpunge(rt);
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_mcast.c
--- a/head/sys/netinet6/in6_mcast.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_mcast.c	Fri Mar 02 17:11:55 2012 +0200
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/in6_mcast.c 229621 2012-01-05 19:00:36Z jhb $");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6_mcast.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet6.h"
 
@@ -1764,7 +1764,7 @@
  * Returns NULL if no ifp could be found.
  */
 static struct ifnet *
-in6p_lookup_mcast_ifp(const struct inpcb *in6p __unused,
+in6p_lookup_mcast_ifp(const struct inpcb *in6p,
     const struct sockaddr_in6 *gsin6)
 {
 	struct route_in6	 ro6;
@@ -1780,11 +1780,8 @@
 	ifp = NULL;
 	memset(&ro6, 0, sizeof(struct route_in6));
 	memcpy(&ro6.ro_dst, gsin6, sizeof(struct sockaddr_in6));
-#ifdef notyet
-	rtalloc_ign_fib(&ro6, 0, inp ? inp->inp_inc.inc_fibnum : 0);
-#else
-	rtalloc_ign((struct route *)&ro6, 0);
-#endif
+	rtalloc_ign_fib((struct route *)&ro6, 0,
+	    in6p ? in6p->inp_inc.inc_fibnum : RT_DEFAULT_FIB);
 	if (ro6.ro_rt != NULL) {
 		ifp = ro6.ro_rt->rt_ifp;
 		KASSERT(ifp != NULL, ("%s: null ifp", __func__));
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_rmx.c
--- a/head/sys/netinet6/in6_rmx.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_rmx.c	Fri Mar 02 17:11:55 2012 +0200
@@ -73,7 +73,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6_rmx.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -168,7 +168,8 @@
 		 *	net route entry, 3ffe:0501:: -> if0.
 		 *	This case should not raise an error.
 		 */
-		rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
+		rt2 = in6_rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED,
+		    rt->rt_fibnum);
 		if (rt2) {
 			if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
 			 && rt2->rt_gateway
@@ -255,10 +256,11 @@
 			if (rt->rt_refcnt > 0)
 				panic("rtqkill route really not free");
 
-			err = rtrequest(RTM_DELETE,
+			err = in6_rtrequest(RTM_DELETE,
 					(struct sockaddr *)rt_key(rt),
 					rt->rt_gateway, rt_mask(rt),
-					rt->rt_flags|RTF_RNH_LOCKED, 0);
+					rt->rt_flags|RTF_RNH_LOCKED, 0,
+					rt->rt_fibnum);
 			if (err) {
 				log(LOG_WARNING, "in6_rtqkill: error %d", err);
 			} else {
@@ -287,19 +289,11 @@
 #define	V_rtq_timer6			VNET(rtq_timer6)
 
 static void
-in6_rtqtimo(void *rock)
+in6_rtqtimo_one(struct radix_node_head *rnh)
 {
-	CURVNET_SET_QUIET((struct vnet *) rock);
-	struct radix_node_head *rnh;
 	struct rtqk_arg arg;
-	struct timeval atv;
 	static time_t last_adjusted_timeout = 0;
 
-	rnh = rt_tables_get_rnh(0, AF_INET6);
-	if (rnh == NULL) {
-		CURVNET_RESTORE();
-		return;
-	}
 	arg.found = arg.killed = 0;
 	arg.rnh = rnh;
 	arg.nextstop = time_uptime + V_rtq_timeout6;
@@ -335,9 +329,24 @@
 		rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
 		RADIX_NODE_HEAD_UNLOCK(rnh);
 	}
+}
+
+static void
+in6_rtqtimo(void *rock)
+{
+	CURVNET_SET_QUIET((struct vnet *) rock);
+	struct radix_node_head *rnh;
+	struct timeval atv;
+	u_int fibnum;
+
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+		if (rnh != NULL)
+			in6_rtqtimo_one(rnh);
+	}
 
 	atv.tv_usec = 0;
-	atv.tv_sec = arg.nextstop - time_uptime;
+	atv.tv_sec = V_rtq_timeout6;
 	callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
 	CURVNET_RESTORE();
 }
@@ -377,31 +386,33 @@
 #define	MTUTIMO_DEFAULT	(60*1)
 
 static void
-in6_mtutimo(void *rock)
+in6_mtutimo_one(struct radix_node_head *rnh)
 {
-	CURVNET_SET_QUIET((struct vnet *) rock);
-	struct radix_node_head *rnh;
 	struct mtuex_arg arg;
-	struct timeval atv;
 
-	rnh = rt_tables_get_rnh(0, AF_INET6);
-	if (rnh == NULL) {
-		CURVNET_RESTORE();
-		return;
-	}
 	arg.rnh = rnh;
 	arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
 	RADIX_NODE_HEAD_LOCK(rnh);
 	rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
 	RADIX_NODE_HEAD_UNLOCK(rnh);
+}
 
+static void
+in6_mtutimo(void *rock)
+{
+	CURVNET_SET_QUIET((struct vnet *) rock);
+	struct radix_node_head *rnh;
+	struct timeval atv;
+	u_int fibnum;
+
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+		if (rnh != NULL)
+			in6_mtutimo_one(rnh);
+	}
+
+	atv.tv_sec = MTUTIMO_DEFAULT;
 	atv.tv_usec = 0;
-	atv.tv_sec = arg.nextstop - time_uptime;
-	if (atv.tv_sec < 0) {
-		printf("invalid mtu expiration time on routing table\n");
-		arg.nextstop = time_uptime + 30;	/* last resort */
-		atv.tv_sec = 30;
-	}
 	callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
 	CURVNET_RESTORE();
 }
@@ -413,6 +424,9 @@
  * value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
  * see also comments in in_inithead() vfs_export.c and domain.h
  */
+static VNET_DEFINE(int, _in6_rt_was_here);
+#define	V__in6_rt_was_here	VNET(_in6_rt_was_here)
+
 int
 in6_inithead(void **head, int off)
 {
@@ -425,13 +439,17 @@
 		return 1;	/* only do the rest for the real thing */
 
 	rnh = *head;
-	KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
 	rnh->rnh_addaddr = in6_addroute;
 	rnh->rnh_matchaddr = in6_matroute;
-	callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
-	callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
-	in6_rtqtimo(curvnet);	/* kick off timeout first time */
-	in6_mtutimo(curvnet);	/* kick off timeout first time */
+
+	if (V__in6_rt_was_here == 0) {
+		callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
+		callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
+		in6_rtqtimo(curvnet);	/* kick off timeout first time */
+		in6_mtutimo(curvnet);	/* kick off timeout first time */
+		V__in6_rt_was_here = 1;
+	}
+
 	return 1;
 }
 
@@ -445,3 +463,43 @@
 	return (1);
 }
 #endif
+
+/*
+ * Extended API for IPv6 FIB support.
+ */
+void
+in6_rtredirect(struct sockaddr *dst, struct sockaddr *gw, struct sockaddr *nm,
+    int flags, struct sockaddr *src, u_int fibnum)
+{
+
+	rtredirect_fib(dst, gw, nm, flags, src, fibnum);
+}
+
+int
+in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw,
+    struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum)
+{
+
+	return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum));
+}
+
+void
+in6_rtalloc(struct route_in6 *ro, u_int fibnum)
+{
+
+	rtalloc_ign_fib((struct route *)ro, 0ul, fibnum);
+}
+
+void
+in6_rtalloc_ign(struct route_in6 *ro, u_long ignflags, u_int fibnum)
+{
+
+	rtalloc_ign_fib((struct route *)ro, ignflags, fibnum);
+}
+
+struct rtentry *
+in6_rtalloc1(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)
+{
+
+	return (rtalloc1_fib(dst, report, ignflags, fibnum));
+}
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_src.c
--- a/head/sys/netinet6/in6_src.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_src.c	Fri Mar 02 17:11:55 2012 +0200
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/in6_src.c 227309 2011-11-07 15:43:11Z ed $");
+__FBSDID("$FreeBSD: head/sys/netinet6/in6_src.c 232127 2012-02-24 20:06:04Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -129,9 +129,10 @@
 
 static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
 	struct ip6_moptions *, struct route_in6 *, struct ifnet **,
-	struct rtentry **, int));
+	struct rtentry **, int, u_int));
 static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
-	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **));
+	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **,
+	struct ifnet *, u_int));
 
 static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
 
@@ -182,7 +183,7 @@
     struct ifnet **ifpp, struct in6_addr *srcp)
 {
 	struct in6_addr dst, tmp;
-	struct ifnet *ifp = NULL;
+	struct ifnet *ifp = NULL, *oifp = NULL;
 	struct in6_ifaddr *ia = NULL, *ia_best = NULL;
 	struct in6_pktinfo *pi = NULL;
 	int dst_scope = -1, best_scope = -1, best_matchlen = -1;
@@ -195,8 +196,18 @@
 	KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
 
 	dst = dstsock->sin6_addr; /* make a copy for local operation */
-	if (ifpp)
+	if (ifpp) {
+		/*
+		 * Save a possibly passed in ifp for in6_selectsrc. Only
+		 * neighbor discovery code should use this feature, where
+		 * we may know the interface but not the FIB number holding
+		 * the connected subnet in case someone deleted it from the
+		 * default FIB and we need to check the interface.
+		 */
+		if (*ifpp != NULL)
+			oifp = *ifpp;
 		*ifpp = NULL;
+	}
 
 	if (inp != NULL) {
 		INP_LOCK_ASSERT(inp);
@@ -217,7 +228,9 @@
 		struct in6_ifaddr *ia6;
 
 		/* get the outgoing interface */
-		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
+		    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
+		    != 0)
 			return (error);
 
 		/*
@@ -281,7 +294,8 @@
 	 * the outgoing interface and the destination address.
 	 */
 	/* get the outgoing interface */
-	if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+	if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
+	    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
 		return (error);
 
 #ifdef DIAGNOSTIC
@@ -504,7 +518,7 @@
 static int
 selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     struct ip6_moptions *mopts, struct route_in6 *ro,
-    struct ifnet **retifp, struct rtentry **retrt, int norouteok)
+    struct ifnet **retifp, struct rtentry **retrt, int norouteok, u_int fibnum)
 {
 	int error = 0;
 	struct ifnet *ifp = NULL;
@@ -581,7 +595,7 @@
 
 
 		if (ron->ro_rt == NULL) {
-			rtalloc((struct route *)ron); /* multi path case? */
+			in6_rtalloc(ron, fibnum); /* multi path case? */
 			if (ron->ro_rt == NULL) {
 				if (ron->ro_rt) {
 					RTFREE(ron->ro_rt);
@@ -616,7 +630,7 @@
 			*satosin6(&ron->ro_dst) = *sin6_next;
 		}
 		if (ron->ro_rt == NULL) {
-			rtalloc((struct route *)ron); /* multi path case? */
+			in6_rtalloc(ron, fibnum); /* multi path case? */
 			if (ron->ro_rt == NULL ||
 			    !(ron->ro_rt->rt_flags & RTF_LLINFO)) {
 				if (ron->ro_rt) {
@@ -661,11 +675,11 @@
 			sa6->sin6_scope_id = 0;
 
 #ifdef RADIX_MPATH
-				rtalloc_mpath((struct route *)ro,
-				    ntohl(sa6->sin6_addr.s6_addr32[3]));
+				rtalloc_mpath_fib((struct route *)ro,
+				    ntohl(sa6->sin6_addr.s6_addr32[3]), fibnum);
 #else			
-				ro->ro_rt = rtalloc1(&((struct route *)ro)
-				    ->ro_dst, 0, 0UL);
+				ro->ro_rt = in6_rtalloc1((struct sockaddr *)
+				    &ro->ro_dst, 0, 0UL, fibnum);
 				if (ro->ro_rt)
 					RT_UNLOCK(ro->ro_rt);
 #endif
@@ -746,21 +760,29 @@
 
 static int
 in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
-    struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp)
+    struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
+    struct ifnet *oifp, u_int fibnum)
 {
 	int error;
 	struct route_in6 sro;
 	struct rtentry *rt = NULL;
 
+	KASSERT(retifp != NULL, ("%s: retifp is NULL", __func__));
+
 	if (ro == NULL) {
 		bzero(&sro, sizeof(sro));
 		ro = &sro;
 	}
 
 	if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
-				     &rt, 1)) != 0) {
+	    &rt, 1, fibnum)) != 0) {
 		if (ro == &sro && rt && rt == sro.ro_rt)
 			RTFREE(rt);
+		/* Help ND. See oifp comment in in6_selectsrc(). */
+		if (oifp != NULL && fibnum == RT_DEFAULT_FIB) {
+			*retifp = oifp;
+			error = 0;
+		}
 		return (error);
 	}
 
@@ -795,7 +817,10 @@
 }
 
 /*
- * clone - meaningful only for bsdi and freebsd
+ * Public wrapper function to selectroute().
+ *
+ * XXX-BZ in6_selectroute() should and will grow the FIB argument. The
+ * in6_selectroute_fib() function is only there for backward compat on stable.
  */
 int
 in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
@@ -804,9 +829,21 @@
 {
 
 	return (selectroute(dstsock, opts, mopts, ro, retifp,
-	    retrt, 0));
+	    retrt, 0, RT_DEFAULT_FIB));
 }
 
+#ifndef BURN_BRIDGES
+int
+in6_selectroute_fib(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
+    struct ip6_moptions *mopts, struct route_in6 *ro,
+    struct ifnet **retifp, struct rtentry **retrt, u_int fibnum)
+{
+
+	return (selectroute(dstsock, opts, mopts, ro, retifp,
+	    retrt, 0, fibnum));
+}
+#endif
+
 /*
  * Default hop limit selection. The precedence is as follows:
  * 1. Hoplimit value specified via ioctl.
@@ -830,7 +867,7 @@
 		ro6.ro_dst.sin6_family = AF_INET6;
 		ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
 		ro6.ro_dst.sin6_addr = in6p->in6p_faddr;
-		rtalloc((struct route *)&ro6);
+		in6_rtalloc(&ro6, in6p->inp_inc.inc_fibnum);
 		if (ro6.ro_rt) {
 			lifp = ro6.ro_rt->rt_ifp;
 			RTFREE(ro6.ro_rt);
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/in6_var.h
--- a/head/sys/netinet6/in6_var.h	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/in6_var.h	Fri Mar 02 17:11:55 2012 +0200
@@ -58,7 +58,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)in_var.h	8.1 (Berkeley) 6/10/93
- * $FreeBSD: head/sys/netinet6/in6_var.h 229621 2012-01-05 19:00:36Z jhb $
+ * $FreeBSD: head/sys/netinet6/in6_var.h 231852 2012-02-17 02:39:58Z bz $
  */
 
 #ifndef _NETINET6_IN6_VAR_H_
@@ -792,6 +792,17 @@
 
 int	in6_is_addr_deprecated __P((struct sockaddr_in6 *));
 int	in6_src_ioctl __P((u_long, caddr_t));
+
+/*
+ * Extended API for IPv6 FIB support.
+ */
+void	in6_rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *,
+	    int, struct sockaddr *, u_int);
+int	in6_rtrequest(int, struct sockaddr *, struct sockaddr *,
+	    struct sockaddr *, int, struct rtentry **, u_int);
+void	in6_rtalloc(struct route_in6 *, u_int);
+void	in6_rtalloc_ign(struct route_in6 *, u_long, u_int);
+struct rtentry *in6_rtalloc1(struct sockaddr *, int, u_long, u_int);
 #endif /* _KERNEL */
 
 #endif /* _NETINET6_IN6_VAR_H_ */
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/ip6_forward.c
--- a/head/sys/netinet6/ip6_forward.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/ip6_forward.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/ip6_forward.c 225044 2011-08-20 17:05:11Z bz $");
+__FBSDID("$FreeBSD: head/sys/netinet6/ip6_forward.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -362,7 +362,7 @@
 #ifdef IPFIREWALL_FORWARD
 again2:
 #endif
-	rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+	rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
 	if (rin6.ro_rt != NULL)
 		RT_UNLOCK(rin6.ro_rt);
 	else {
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/ip6_input.c
--- a/head/sys/netinet6/ip6_input.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/ip6_input.c	Fri Mar 02 17:11:55 2012 +0200
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/ip6_input.c 229621 2012-01-05 19:00:36Z jhb $");
+__FBSDID("$FreeBSD: head/sys/netinet6/ip6_input.c 232379 2012-03-02 07:23:28Z hrs $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -163,6 +163,8 @@
 
 	TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal",
 	    &V_ip6_auto_linklocal);
+	TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv);
+	TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr);
 
 	TAILQ_INIT(&V_in6_ifaddrhead);
 
@@ -666,7 +668,7 @@
 	dst->sin6_len = sizeof(struct sockaddr_in6);
 	dst->sin6_family = AF_INET6;
 	dst->sin6_addr = ip6->ip6_dst;
-	rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+	rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
 	if (rin6.ro_rt)
 		RT_UNLOCK(rin6.ro_rt);
 
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/ip6_output.c
--- a/head/sys/netinet6/ip6_output.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/ip6_output.c	Fri Mar 02 17:11:55 2012 +0200
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/ip6_output.c 227207 2011-11-06 10:47:20Z trociny $");
+__FBSDID("$FreeBSD: head/sys/netinet6/ip6_output.c 232127 2012-02-24 20:06:04Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -142,7 +142,7 @@
 static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
 static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
 static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
-	struct ifnet *, struct in6_addr *, u_long *, int *));
+	struct ifnet *, struct in6_addr *, u_long *, int *, u_int));
 static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
 
 
@@ -241,6 +241,9 @@
 		goto bad;
 	}
 
+	if (inp != NULL)
+		M_SETFIB(m, inp->inp_inc.inc_fibnum);
+
 	finaldst = ip6->ip6_dst;
 	bzero(&exthdrs, sizeof(exthdrs));
 	if (opt) {
@@ -604,8 +607,8 @@
 	if (flevalid) {
 		rt = ro->ro_rt;
 		ifp = ro->ro_rt->rt_ifp;
-	} else if ((error = in6_selectroute(&dst_sa, opt, im6o, ro,
-	    &ifp, &rt)) != 0) {
+	} else if ((error = in6_selectroute_fib(&dst_sa, opt, im6o, ro,
+	    &ifp, &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0) {
 		switch (error) {
 		case EHOSTUNREACH:
 			V_ip6stat.ip6s_noroute++;
@@ -773,7 +776,7 @@
 
 	/* Determine path MTU. */
 	if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
-	    &alwaysfrag)) != 0)
+	    &alwaysfrag, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0)
 		goto bad;
 
 	/*
@@ -1064,7 +1067,7 @@
 				goto sendorfree;
 			}
 			m->m_pkthdr.rcvif = NULL;
-			m->m_flags = m0->m_flags & M_COPYFLAGS;
+			m->m_flags = m0->m_flags & M_COPYFLAGS;	/* incl. FIB */
 			*mnext = m;
 			mnext = &m->m_nextpkt;
 			m->m_data += max_linkhdr;
@@ -1321,7 +1324,7 @@
 static int
 ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
     struct ifnet *ifp, struct in6_addr *dst, u_long *mtup,
-    int *alwaysfragp)
+    int *alwaysfragp, u_int fibnum)
 {
 	u_int32_t mtu = 0;
 	int alwaysfrag = 0;
@@ -1343,7 +1346,7 @@
 			sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
 			sa6_dst->sin6_addr = *dst;
 
-			rtalloc((struct route *)ro_pmtu);
+			in6_rtalloc(ro_pmtu, fibnum);
 		}
 	}
 	if (ro_pmtu->ro_rt) {
@@ -1448,6 +1451,12 @@
 				INP_WUNLOCK(in6p);
 				error = 0;
 				break;
+			case SO_SETFIB:
+				INP_WLOCK(in6p);
+				in6p->inp_inc.inc_fibnum = so->so_fibnum;
+				INP_WUNLOCK(in6p);
+				error = 0;
+				break;
 			default:
 				break;
 			}
@@ -1975,7 +1984,8 @@
 				 * the outgoing interface.
 				 */
 				error = ip6_getpmtu(&sro, NULL, NULL,
-				    &in6p->in6p_faddr, &pmtu, NULL);
+				    &in6p->in6p_faddr, &pmtu, NULL,
+				    so->so_fibnum);
 				if (sro.ro_rt)
 					RTFREE(sro.ro_rt);
 				if (error)
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/ip6_var.h
--- a/head/sys/netinet6/ip6_var.h	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/ip6_var.h	Fri Mar 02 17:11:55 2012 +0200
@@ -58,7 +58,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ip_var.h	8.1 (Berkeley) 6/10/93
- * $FreeBSD: head/sys/netinet6/ip6_var.h 225521 2011-09-13 00:06:11Z hrs $
+ * $FreeBSD: head/sys/netinet6/ip6_var.h 232127 2012-02-24 20:06:04Z bz $
  */
 
 #ifndef _NETINET6_IP6_VAR_H_
@@ -445,6 +445,9 @@
 int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
 	struct ip6_moptions *, struct route_in6 *, struct ifnet **,
 	struct rtentry **));
+int	in6_selectroute_fib(struct sockaddr_in6 *, struct ip6_pktopts *,
+	    struct ip6_moptions *, struct route_in6 *, struct ifnet **,
+	    struct rtentry **, u_int);
 u_int32_t ip6_randomid __P((void));
 u_int32_t ip6_randomflowlabel __P((void));
 #endif /* _KERNEL */
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/nd6.c
--- a/head/sys/netinet6/nd6.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/nd6.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/nd6.c 230531 2012-01-25 08:53:42Z pluknet $");
+__FBSDID("$FreeBSD: head/sys/netinet6/nd6.c 232378 2012-03-02 07:22:04Z hrs $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -900,7 +900,10 @@
 
 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
 			struct rtentry *rt;
-			rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0, 0);
+
+			/* Always use the default FIB here. */
+			rt = in6_rtalloc1((struct sockaddr *)&pr->ndpr_prefix,
+			    0, 0, RT_DEFAULT_FIB);
 			if (rt == NULL)
 				continue;
 			/*
@@ -1342,16 +1345,6 @@
 		struct ifaddr *ifa;
 		struct in6_ifaddr *ia;
 
-		/*
-		 * Try to clear ifdisabled flag when enabling
-		 * accept_rtadv or auto_linklocal.
-		 */
-		if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
-		    !(ND.flags & ND6_IFF_IFDISABLED) &&
-		    (ND.flags & (ND6_IFF_ACCEPT_RTADV |
-		    ND6_IFF_AUTO_LINKLOCAL)))
-			ND.flags &= ~ND6_IFF_IFDISABLED;
-
 		if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
 		    !(ND.flags & ND6_IFF_IFDISABLED)) {
 			/* ifdisabled 1->0 transision */
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/nd6_nbr.c
--- a/head/sys/netinet6/nd6_nbr.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/nd6_nbr.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/nd6_nbr.c 228571 2011-12-16 12:16:56Z glebius $");
+__FBSDID("$FreeBSD: head/sys/netinet6/nd6_nbr.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -85,6 +85,8 @@
 static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
 static void nd6_dad_ns_input(struct ifaddr *);
 static void nd6_dad_na_input(struct ifaddr *);
+static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
+    const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
 
 VNET_DEFINE(int, dad_ignore_ns) = 0;	/* ignore NS in DAD - specwise incorrect*/
 VNET_DEFINE(int, dad_maxtry) = 15;	/* max # of *tries* to transmit DAD packet */
@@ -242,13 +244,16 @@
 		tsin6.sin6_family = AF_INET6;
 		tsin6.sin6_addr = taddr6;
 
+		/* Always use the default FIB. */
 #ifdef RADIX_MPATH
 		bzero(&ro, sizeof(ro));
 		ro.ro_dst = tsin6;
-		rtalloc_mpath((struct route *)&ro, RTF_ANNOUNCE);
+		rtalloc_mpath_fib((struct route *)&ro, RTF_ANNOUNCE,
+		    RT_DEFAULT_FIB);
 		rt = ro.ro_rt;
 #else
-		rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
+		rt = in6_rtalloc1((struct sockaddr *)&tsin6, 0, 0,
+		    RT_DEFAULT_FIB);
 #endif
 		need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
 		    rt->rt_gateway->sa_family == AF_LINK);
@@ -341,19 +346,20 @@
 		in6_all = in6addr_linklocal_allnodes;
 		if (in6_setscope(&in6_all, ifp, NULL) != 0)
 			goto bad;
-		nd6_na_output(ifp, &in6_all, &taddr6,
+		nd6_na_output_fib(ifp, &in6_all, &taddr6,
 		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
-		    rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
+		    rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
+		    M_GETFIB(m));
 		goto freeit;
 	}
 
 	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
 	    ND_NEIGHBOR_SOLICIT, 0);
 
-	nd6_na_output(ifp, &saddr6, &taddr6,
+	nd6_na_output_fib(ifp, &saddr6, &taddr6,
 	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
 	    rflag | ND_NA_FLAG_SOLICITED, tlladdr,
-	    proxy ? (struct sockaddr *)&proxydl : NULL);
+	    proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
  freeit:
 	if (ifa != NULL)
 		ifa_free(ifa);
@@ -505,14 +511,16 @@
 			int error;
 			struct sockaddr_in6 dst_sa;
 			struct in6_addr src_in;
+			struct ifnet *oifp;
 
 			bzero(&dst_sa, sizeof(dst_sa));
 			dst_sa.sin6_family = AF_INET6;
 			dst_sa.sin6_len = sizeof(dst_sa);
 			dst_sa.sin6_addr = ip6->ip6_dst;
 
+			oifp = ifp;
 			error = in6_selectsrc(&dst_sa, NULL,
-			    NULL, &ro, NULL, NULL, &src_in);
+			    NULL, &ro, NULL, &oifp, &src_in);
 			if (error) {
 				char ip6buf[INET6_ADDRSTRLEN];
 				nd6log((LOG_DEBUG,
@@ -954,13 +962,14 @@
  * tlladdr - 1 if include target link-layer address
  * sdl0 - sockaddr_dl (= proxy NA) or NULL
  */
-void
-nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+static void
+nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
     const struct in6_addr *taddr6, u_long flags, int tlladdr,
-    struct sockaddr *sdl0)
+    struct sockaddr *sdl0, u_int fibnum)
 {
 	struct mbuf *m;
 	struct m_tag *mtag;
+	struct ifnet *oifp;
 	struct ip6_hdr *ip6;
 	struct nd_neighbor_advert *nd_na;
 	struct ip6_moptions im6o;
@@ -996,6 +1005,7 @@
 	if (m == NULL)
 		return;
 	m->m_pkthdr.rcvif = NULL;
+	M_SETFIB(m, fibnum);
 
 	if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
 		m->m_flags |= M_MCAST;
@@ -1037,7 +1047,8 @@
 	 * Select a source whose scope is the same as that of the dest.
 	 */
 	bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
-	error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
+	oifp = ifp;
+	error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &oifp, &src);
 	if (error) {
 		char ip6buf[INET6_ADDRSTRLEN];
 		nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
@@ -1126,6 +1137,18 @@
 	return;
 }
 
+#ifndef BURN_BRIDGES
+void
+nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+    const struct in6_addr *taddr6, u_long flags, int tlladdr,
+    struct sockaddr *sdl0)
+{
+
+	nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0,
+	    RT_DEFAULT_FIB);
+}
+#endif
+
 caddr_t
 nd6_ifptomac(struct ifnet *ifp)
 {
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/nd6_rtr.c
--- a/head/sys/netinet6/nd6_rtr.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/nd6_rtr.c	Fri Mar 02 17:11:55 2012 +0200
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 229621 2012-01-05 19:00:36Z jhb $");
+__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -463,7 +463,7 @@
 	} else
 		ifa = NULL;
 
-	rt_missmsg(cmd, &info, rt->rt_flags, 0);
+	rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum);
 	if (ifa != NULL)
 		ifa_free(ifa);
 }
@@ -486,9 +486,9 @@
 	gate.sin6_addr = new->rtaddr;
 
 	s = splnet();
-	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
+	error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
 	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
-	    RTF_GATEWAY, &newrt);
+	    RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
 	if (newrt) {
 		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
 		RTFREE(newrt);
@@ -532,9 +532,9 @@
 	def.sin6_family = gate.sin6_family = AF_INET6;
 	gate.sin6_addr = dr->rtaddr;
 
-	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
+	in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def,
 	    (struct sockaddr *)&gate,
-	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
+	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB);
 	if (oldrt) {
 		nd6_rtmsg(RTM_DELETE, oldrt);
 		RTFREE(oldrt);
@@ -1541,18 +1541,91 @@
 }
 
 static int
+nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
+{
+	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+	struct radix_node_head *rnh;
+	struct rtentry *rt;
+	struct sockaddr_in6 mask6;
+	u_long rtflags;
+	int error, a_failure, fibnum;
+
+	/*
+	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
+	 * ifa->ifa_rtrequest = nd6_rtrequest;
+	 */
+	bzero(&mask6, sizeof(mask6));
+	mask6.sin6_len = sizeof(mask6);
+	mask6.sin6_addr = pr->ndpr_mask;
+	rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
+
+	a_failure = 0;
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+
+		rt = NULL;
+		error = in6_rtrequest(RTM_ADD,
+		    (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr,
+		    (struct sockaddr *)&mask6, rtflags, &rt, fibnum);
+		if (error == 0) {
+			KASSERT(rt != NULL, ("%s: in6_rtrequest return no "
+			    "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__,
+			    error, pr, ifa));
+
+			rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6);
+			/* XXX what if rhn == NULL? */
+			RADIX_NODE_HEAD_LOCK(rnh);
+			RT_LOCK(rt);
+			if (rt_setgate(rt, rt_key(rt),
+			    (struct sockaddr *)&null_sdl) == 0) {
+				struct sockaddr_dl *dl;
+
+				dl = (struct sockaddr_dl *)rt->rt_gateway;
+				dl->sdl_type = rt->rt_ifp->if_type;
+				dl->sdl_index = rt->rt_ifp->if_index;
+			}
+			RADIX_NODE_HEAD_UNLOCK(rnh);
+			nd6_rtmsg(RTM_ADD, rt);
+			RT_UNLOCK(rt);
+			pr->ndpr_stateflags |= NDPRF_ONLINK;
+		} else {
+			char ip6buf[INET6_ADDRSTRLEN];
+			char ip6bufg[INET6_ADDRSTRLEN];
+			char ip6bufm[INET6_ADDRSTRLEN];
+			struct sockaddr_in6 *sin6;
+
+			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+			nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add "
+			    "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, "
+			    "flags=%lx errno = %d\n",
+			    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
+			    pr->ndpr_plen, if_name(pr->ndpr_ifp),
+			    ip6_sprintf(ip6bufg, &sin6->sin6_addr),
+			    ip6_sprintf(ip6bufm, &mask6.sin6_addr),
+			    rtflags, error));
+
+			/* Save last error to return, see rtinit(). */
+			a_failure = error;
+		}
+
+		if (rt != NULL) {
+			RT_LOCK(rt);
+			RT_REMREF(rt);
+			RT_UNLOCK(rt);
+		}
+	}
+
+	/* Return the last error we got. */
+	return (a_failure);
+}
+
+static int
 nd6_prefix_onlink(struct nd_prefix *pr)
 {
 	struct ifaddr *ifa;
 	struct ifnet *ifp = pr->ndpr_ifp;
-	struct sockaddr_in6 mask6;
 	struct nd_prefix *opr;
-	u_long rtflags;
 	int error = 0;
-	struct radix_node_head *rnh;
-	struct rtentry *rt = NULL;
 	char ip6buf[INET6_ADDRSTRLEN];
-	struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
 
 	/* sanity check */
 	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
@@ -1616,49 +1689,8 @@
 		return (0);
 	}
 
-	/*
-	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
-	 * ifa->ifa_rtrequest = nd6_rtrequest;
-	 */
-	bzero(&mask6, sizeof(mask6));
-	mask6.sin6_len = sizeof(mask6);
-	mask6.sin6_addr = pr->ndpr_mask;
-	rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
-	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
-	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
-	if (error == 0) {
-		if (rt != NULL) /* this should be non NULL, though */ {
-			rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6);
-			/* XXX what if rhn == NULL? */
-			RADIX_NODE_HEAD_LOCK(rnh);
-			RT_LOCK(rt);
-			if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) {
-				((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
-					rt->rt_ifp->if_type;
-				((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
-					rt->rt_ifp->if_index;
-			}
-			RADIX_NODE_HEAD_UNLOCK(rnh);
-			nd6_rtmsg(RTM_ADD, rt);
-			RT_UNLOCK(rt);
-		}
-		pr->ndpr_stateflags |= NDPRF_ONLINK;
-	} else {
-		char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
-		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
-		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
-		    "errno = %d\n",
-		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
-		    pr->ndpr_plen, if_name(ifp),
-		    ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
-		    ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
-	}
+	error = nd6_prefix_onlink_rtrequest(pr, ifa);
 
-	if (rt != NULL) {
-		RT_LOCK(rt);
-		RT_REMREF(rt);
-		RT_UNLOCK(rt);
-	}
 	if (ifa != NULL)
 		ifa_free(ifa);
 
@@ -1672,8 +1704,9 @@
 	struct ifnet *ifp = pr->ndpr_ifp;
 	struct nd_prefix *opr;
 	struct sockaddr_in6 sa6, mask6;
-	struct rtentry *rt = NULL;
+	struct rtentry *rt;
 	char ip6buf[INET6_ADDRSTRLEN];
+	int fibnum, a_failure;
 
 	/* sanity check */
 	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
@@ -1693,15 +1726,28 @@
 	mask6.sin6_family = AF_INET6;
 	mask6.sin6_len = sizeof(sa6);
 	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
-	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
-	    (struct sockaddr *)&mask6, 0, &rt);
+
+	a_failure = 0;
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rt = NULL;
+		error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
+		    (struct sockaddr *)&mask6, 0, &rt, fibnum);
+		if (error == 0) {
+			/* report the route deletion to the routing socket. */
+			if (rt != NULL)
+				nd6_rtmsg(RTM_DELETE, rt);
+		} else {
+			/* Save last error to return, see rtinit(). */
+			a_failure = error;
+		}
+		if (rt != NULL) {
+			RTFREE(rt);
+		}
+	}
+	error = a_failure;
 	if (error == 0) {
 		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
 
-		/* report the route deletion to the routing socket. */
-		if (rt != NULL)
-			nd6_rtmsg(RTM_DELETE, rt);
-
 		/*
 		 * There might be the same prefix on another interface,
 		 * the prefix which could not be on-link just because we have
@@ -1749,10 +1795,6 @@
 		    if_name(ifp), error));
 	}
 
-	if (rt != NULL) {
-		RTFREE(rt);
-	}
-
 	return (error);
 }
 
@@ -2069,6 +2111,7 @@
 rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
 {
 	struct radix_node_head *rnh;
+	u_int fibnum;
 	int s = splnet();
 
 	/* We'll care only link-local addresses */
@@ -2077,13 +2120,16 @@
 		return;
 	}
 
-	rnh = rt_tables_get_rnh(0, AF_INET6);
-	if (rnh == NULL)
-		return;
+	/* XXX Do we really need to walk any but the default FIB? */
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+		if (rnh == NULL)
+			continue;
 
-	RADIX_NODE_HEAD_LOCK(rnh);
-	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
-	RADIX_NODE_HEAD_UNLOCK(rnh);
+		RADIX_NODE_HEAD_LOCK(rnh);
+		rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
+		RADIX_NODE_HEAD_UNLOCK(rnh);
+	}
 	splx(s);
 }
 
@@ -2116,8 +2162,8 @@
 	if ((rt->rt_flags & RTF_HOST) == 0)
 		return (0);
 
-	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
-	    rt_mask(rt), rt->rt_flags, 0));
+	return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
+	    rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum));
 #undef SIN6
 }
 
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/raw_ip6.c
--- a/head/sys/netinet6/raw_ip6.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/raw_ip6.c	Fri Mar 02 17:11:55 2012 +0200
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/netinet6/raw_ip6.c 231852 2012-02-17 02:39:58Z bz $");
 
 #include "opt_ipsec.h"
 #include "opt_inet6.h"
@@ -582,6 +582,7 @@
 int
 rip6_ctloutput(struct socket *so, struct sockopt *sopt)
 {
+	struct inpcb *inp;
 	int error;
 
 	if (sopt->sopt_level == IPPROTO_ICMPV6)
@@ -590,8 +591,17 @@
 		 * from protosw?
 		 */
 		return (icmp6_ctloutput(so, sopt));
-	else if (sopt->sopt_level != IPPROTO_IPV6)
+	else if (sopt->sopt_level != IPPROTO_IPV6) {
+		if (sopt->sopt_level == SOL_SOCKET &&
+		    sopt->sopt_name == SO_SETFIB) {
+			inp = sotoinpcb(so);
+			INP_WLOCK(inp);
+			inp->inp_inc.inc_fibnum = so->so_fibnum;
+			INP_WUNLOCK(inp);
+			return (0);
+		}
 		return (EINVAL);
+	}
 
 	error = 0;
 
diff -r 73bf3c4ab253 -r e8250b8e4ab7 head/sys/netinet6/sctp6_usrreq.c
--- a/head/sys/netinet6/sctp6_usrreq.c	Fri Mar 02 17:11:48 2012 +0200
+++ b/head/sys/netinet6/sctp6_usrreq.c	Fri Mar 02 17:11:55 2012 +0200
@@ -32,7 +32,7 @@
 /*	$KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $	*/
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 229805 2012-01-08 09:56:24Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 231895 2012-02-18 16:06:15Z tuexen $");
 
 #include <netinet/sctp_os.h>
 #include <sys/proc.h>
@@ -1199,7 +1199,7 @@
 static int
 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
 {
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
+	struct sockaddr_in6 *sin6;
 	int fnd;
 	struct sockaddr_in6 *sin_a6;
 	struct sctp_inpcb *inp;


More information about the Zrouter-src-freebsd mailing list