sys/{net,netinet,netinet6}: add in6_domifattach()/in6_domiddetach() and ifp->ifdata

Hiroki Sato hrs at allbsd.org
Sat Jan 8 12:07:16 PST 2005


Hi,

 Here are patches to add in6_domifattach(), in6_domifdetach(), and
 ifp->if_afdata from KAME.  I am working on merging IPv6 API
 transition (RFC2292 -> RFC3542) and implementation of source
 address selection in RFC 3484.  These are preparation for them.

-- 
| Hiroki SATO
- Nuke #ifdef SCOPEDROUTING.  It was never enabled and is useless now[1].
- Add in6_domifattach(), in6_domifdetach(), and ifp->if_afdata[2].
- ANSIfy.

Obtained from:	KAME via FreeBSD
References (FreeBSD):

	net/
        if.c		1.168[2]
        if_var.h	1.59[2]

	netinet/
	icmp6.h		1.12[2]
	tcp_input.c	1.209[2]

	netinet6/
        icmp6.c		1.38[1], 1.39[2]
        in6.c		1.30[1], 1.31[2]
        ip6_forward.c	1.20[1]
        in6_gif.c	1.15[1]
        in6_proto.c	1.25[2]
        in6_ifattach.c	1.17[1], 1.18[2]
        ip6_input.c	1.53[1], 1.57[2]
        ip6_output.c	1.58[1], 1.59[2]
        in6_src.c	1.14[2]
        in6_var.h	1.14[2]
        nd6.c		1.30[1], 1.32[2]
        nd6.h		1.13[2]
        nd6_nbr.c	1.19[2]
        nd6_rtr.c	1.20[2]
        scope6.c	1.8[2]
        scope6_var.h	1.3[2]

	sys/
	domain.h	1.18[2]
	kernel.h	1.113[2]
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.24
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.24 if.c
--- net/if.c	6 Jan 2005 09:14:13 -0000	1.24
+++ net/if.c	8 Jan 2005 16:18:10 -0000
@@ -53,6 +53,7 @@
 #include <sys/sockio.h>
 #include <sys/syslog.h>
 #include <sys/sysctl.h>
+#include <sys/domain.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -83,6 +84,8 @@
  * System initialization
  */
 
+static void	if_attachdomain(void *);
+static void	if_attachdomain1(struct ifnet *);
 static int ifconf (u_long, caddr_t, struct thread *);
 static void ifinit (void *);
 static void if_qflush (struct ifqueue *);
@@ -237,10 +240,45 @@
 
 	EVENTHANDLER_INVOKE(ifnet_attach_event, ifp);
 
+	if (domains)
+		if_attachdomain1(ifp);
+
 	/* Announce the interface. */
 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
 }
 
+static void
+if_attachdomain(void *dummy)
+{
+	struct ifnet *ifp;
+	int s;
+
+	s = splnet();
+	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
+		if_attachdomain1(ifp);
+	splx(s);
+}
+SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST,
+	if_attachdomain, NULL);
+
+static void
+if_attachdomain1(struct ifnet *ifp)
+{
+	struct domain *dp;
+	int s;
+
+	s = splnet();
+
+	/* address family dependent data region */
+	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
+	for (dp = domains; dp; dp = dp->dom_next) {
+		if (dp->dom_ifattach)
+			ifp->if_afdata[dp->dom_family] =
+				(*dp->dom_ifattach)(ifp);
+	}
+	splx(s);
+}
+
 /*
  * Detach an interface, removing it from the
  * list of "active" interfaces.
@@ -252,6 +290,7 @@
 	struct radix_node_head	*rnh;
 	int s;
 	int i;
+	struct domain *dp;
 
 	EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
 
@@ -321,6 +360,12 @@
 	/* Announce that the interface is gone. */
 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
 
+	for (dp = domains; dp; dp = dp->dom_next) {
+		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
+			(*dp->dom_ifdetach)(ifp,
+				ifp->if_afdata[dp->dom_family]);
+	}
+
 	ifindex2ifnet[ifp->if_index] = NULL;
 
 	TAILQ_REMOVE(&ifnet, ifp, if_link);
Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.20
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.20 if_var.h
--- net/if_var.h	28 Dec 2004 08:09:59 -0000	1.20
+++ net/if_var.h	8 Jan 2005 16:51:56 -0000
@@ -174,6 +174,7 @@
 	struct	ifqueue if_snd;		/* output queue */
 	struct	ifprefixhead if_prefixhead; /* list of prefixes per if */
 	const uint8_t	*if_broadcastaddr;
+	void	*if_afdata[AF_MAX];
 };
 typedef void if_init_f_t (void *);
 
Index: netinet/icmp6.h
===================================================================
RCS file: /cvs/src/sys/netinet/icmp6.h,v
retrieving revision 1.5
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.5 icmp6.h
--- netinet/icmp6.h	21 Dec 2004 02:54:15 -0000	1.5
+++ netinet/icmp6.h	8 Jan 2005 15:40:31 -0000
@@ -684,11 +684,8 @@
 /* XXX: is this the right place for these macros? */
 #define icmp6_ifstat_inc(ifp, tag) \
 do {								\
-	if ((ifp) && (ifp)->if_index <= if_index			\
-	 && (ifp)->if_index < icmp6_ifstatmax			\
-	 && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) {	\
-		icmp6_ifstat[(ifp)->if_index]->tag++;		\
-	}							\
+	if (ifp)						\
+		((struct in6_ifextra *)((ifp)->if_afdata[AF_INET6]))->icmp6_ifstat->tag++; \
 } while (0)
 
 #define icmp6_ifoutstat_inc(ifp, type, code) \
@@ -696,7 +693,7 @@
 		icmp6_ifstat_inc(ifp, ifs6_out_msg); \
 		if (type < ICMP6_INFOMSG_MASK) \
 			icmp6_ifstat_inc(ifp, ifs6_out_error); \
-		switch(type) { \
+		switch (type) { \
 		 case ICMP6_DST_UNREACH: \
 			 icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \
 			 if (code == ICMP6_DST_UNREACH_ADMIN) \
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.50
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.50 tcp_input.c
--- netinet/tcp_input.c	8 Jan 2005 09:26:32 -0000	1.50
+++ netinet/tcp_input.c	8 Jan 2005 19:09:58 -0000
@@ -2920,8 +2920,7 @@
 		mss = rt->rt_rmx.rmx_mtu - min_protoh;
 	else {
 		if (isipv6) {
-			mss = nd_ifinfo[rt->rt_ifp->if_index].linkmtu -
-				min_protoh;
+			mss = ND_IFINFO(rt->rt_ifp)->linkmtu - min_protoh;
 			if (!in6_localaddr(&inp->in6p_faddr))
 				mss = min(mss, tcp_v6mssdflt);
 		} else {
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.16
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.16 icmp6.c
--- netinet6/icmp6.c	6 Jan 2005 17:59:32 -0000	1.16
+++ netinet6/icmp6.c	8 Jan 2005 19:09:58 -0000
@@ -1055,7 +1055,6 @@
 			icmp6dst.sin6_addr = *finaldst;
 		icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
 							  &icmp6dst.sin6_addr);
-#ifndef SCOPEDROUTING
 		if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
 				   NULL, NULL)) {
 			/* should be impossbile */
@@ -1063,7 +1062,6 @@
 			    "icmp6_notify_error: in6_embedscope failed\n"));
 			goto freeit;
 		}
-#endif
 
 		/*
 		 * retrieve parameters from the inner IPv6 header, and convert
@@ -1075,7 +1073,6 @@
 		icmp6src.sin6_addr = eip6->ip6_src;
 		icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
 							  &icmp6src.sin6_addr);
-#ifndef SCOPEDROUTING
 		if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
 				   NULL, NULL)) {
 			/* should be impossbile */
@@ -1083,7 +1080,6 @@
 			    "icmp6_notify_error: in6_embedscope failed\n"));
 			goto freeit;
 		}
-#endif
 		icmp6src.sin6_flowinfo =
 			(eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
 
@@ -1277,18 +1273,14 @@
 			    subjlen, (caddr_t)&sin6.sin6_addr);
 			sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
 							      &sin6.sin6_addr);
-#ifndef SCOPEDROUTING
 			in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL);
-#endif
 			bzero(&sin6_d, sizeof(sin6_d));
 			sin6_d.sin6_family = AF_INET6; /* not used, actually */
 			sin6_d.sin6_len = sizeof(sin6_d); /* ditto */
 			sin6_d.sin6_addr = ip6->ip6_dst;
 			sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
 								&ip6->ip6_dst);
-#ifndef SCOPEDROUTING
 			in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL);
-#endif
 			subj = (char *)&sin6;
 			if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d))
 				break;
@@ -2139,7 +2131,7 @@
 	ip6->ip6_nxt = IPPROTO_ICMPV6;
 	if (m->m_pkthdr.rcvif) {
 		/* XXX: This may not be the outgoing interface */
-		ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
+		ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
 	} else
 		ip6->ip6_hlim = ip6_defhlim;
 
Index: netinet6/in6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.12
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.12 in6.c
--- netinet6/in6.c	6 Jan 2005 17:59:32 -0000	1.12
+++ netinet6/in6.c	8 Jan 2005 19:09:58 -0000
@@ -89,11 +89,9 @@
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/if_ether.h>
-#ifndef SCOPEDROUTING
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
-#endif
 
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
@@ -102,9 +100,7 @@
 #include <netinet6/ip6_mroute.h>
 #include <netinet6/in6_ifattach.h>
 #include <netinet6/scope6_var.h>
-#ifndef SCOPEDROUTING
 #include <netinet6/in6_pcb.h>
-#endif
 
 #include <net/net_osdep.h>
 
@@ -415,13 +411,16 @@
 	case SIOCSSCOPE6:
 		if (!privileged)
 			return(EPERM);
-		return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id));
+		return(scope6_set(ifp,
+			(struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
 		break;
 	case SIOCGSCOPE6:
-		return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id));
+		return(scope6_get(ifp,
+			(struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
 		break;
 	case SIOCGSCOPE6DEF:
-		return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id));
+		return(scope6_get_default((struct scope6_id *)
+			ifr->ifr_ifru.ifru_scope_id));
 		break;
 	}
 
@@ -557,26 +556,17 @@
 	case SIOCGIFSTAT_IN6:
 		if (ifp == NULL)
 			return EINVAL;
-		if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax
-		 || in6_ifstat[ifp->if_index] == NULL) {
-			/* return EAFNOSUPPORT? */
-			bzero(&ifr->ifr_ifru.ifru_stat,
-				sizeof(ifr->ifr_ifru.ifru_stat));
-		} else
-			ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];
+		bzero(&ifr->ifr_ifru.ifru_stat,
+			sizeof(ifr->ifr_ifru.ifru_stat));
+		ifr->ifr_ifru.ifru_stat =
+			*((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
 		break;
 
 	case SIOCGIFSTAT_ICMP6:
-		if (ifp == NULL)
-			return EINVAL;
-		if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||
-		    icmp6_ifstat[ifp->if_index] == NULL) {
-			/* return EAFNOSUPPORT? */
-			bzero(&ifr->ifr_ifru.ifru_stat,
-				sizeof(ifr->ifr_ifru.ifru_icmp6stat));
-		} else
-			ifr->ifr_ifru.ifru_icmp6stat =
-				*icmp6_ifstat[ifp->if_index];
+		bzero(&ifr->ifr_ifru.ifru_stat,
+			sizeof(ifr->ifr_ifru.ifru_icmp6stat));
+		ifr->ifr_ifru.ifru_icmp6stat =
+			*((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
 		break;
 
 	case SIOCGIFALIFETIME_IN6:
@@ -824,23 +814,19 @@
 	    (dst6.sin6_family == AF_INET6)) {
 		int scopeid;
 
-#ifndef SCOPEDROUTING
 		if ((error = in6_recoverscope(&dst6,
 					      &ifra->ifra_dstaddr.sin6_addr,
 					      ifp)) != 0)
 			return(error);
-#endif
 		scopeid = in6_addr2scopeid(ifp, &dst6.sin6_addr);
 		if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */
 			dst6.sin6_scope_id = scopeid;
 		else if (dst6.sin6_scope_id != scopeid)
 			return(EINVAL); /* scope ID mismatch. */
-#ifndef SCOPEDROUTING
 		if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL))
 		    != 0)
 			return(error);
 		dst6.sin6_scope_id = 0; /* XXX */
-#endif
 	}
 	/*
 	 * The destination address can be specified only for a p2p or a
@@ -1129,13 +1115,6 @@
 		ia->ia6_lifetime.ia6t_preferred = 0;
 
 	/*
-	 * make sure to initialize ND6 information.  this is to workaround
-	 * issues with interfaces with IPv6 addresses, which have never brought
-	 * up.  We are assuming that it is safe to nd6_ifattach multiple times.
-	 */
-	nd6_ifattach(ifp);
-
-	/*
 	 * Perform DAD, if needed.
 	 * XXX It may be of use, if we can administratively
 	 * disable DAD.
@@ -1467,7 +1446,6 @@
 				break;
 
 			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
-#ifndef SCOPEDROUTING
 			/*
 			 * XXX: this is adhoc, but is necessary to allow
 			 * a user to specify fe80::/64 (not /10) for a
@@ -1475,7 +1453,6 @@
 			 */
 			if (IN6_IS_ADDR_LINKLOCAL(&candidate))
 				candidate.s6_addr16[1] = 0;
-#endif
 			candidate.s6_addr32[0] &= mask.s6_addr32[0];
 			candidate.s6_addr32[1] &= mask.s6_addr32[1];
 			candidate.s6_addr32[2] &= mask.s6_addr32[2];
@@ -1488,24 +1465,19 @@
 		ia = ifa2ia6(ifa);
 
 		if (cmd == SIOCGLIFADDR) {
-#ifndef SCOPEDROUTING
 			struct sockaddr_in6 *s6;
-#endif
 
 			/* fill in the if_laddrreq structure */
 			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
-#ifndef SCOPEDROUTING		/* XXX see above */
 			s6 = (struct sockaddr_in6 *)&iflr->addr;
 			if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
 				s6->sin6_addr.s6_addr16[1] = 0;
 				s6->sin6_scope_id =
 					in6_addr2scopeid(ifp, &s6->sin6_addr);
 			}
-#endif
 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
 				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
 					ia->ia_dstaddr.sin6_len);
-#ifndef SCOPEDROUTING		/* XXX see above */
 				s6 = (struct sockaddr_in6 *)&iflr->dstaddr;
 				if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
 					s6->sin6_addr.s6_addr16[1] = 0;
@@ -1513,7 +1485,6 @@
 						in6_addr2scopeid(ifp,
 								 &s6->sin6_addr);
 				}
-#endif
 			} else
 				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
 
@@ -1832,9 +1803,6 @@
 	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
 		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
 				       &sa6->sin6_addr) &&
-#ifdef SCOPEDROUTING
-		    ia->ia_addr.sin6_scope_id == sa6->sin6_scope_id &&
-#endif
 		    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
 			return(1); /* true */
 
@@ -2349,13 +2317,46 @@
 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
 	{
 		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
-		    nd_ifinfo[ifp->if_index].linkmtu > maxmtu)
-			maxmtu =  nd_ifinfo[ifp->if_index].linkmtu;
+		    ND_IFINFO(ifp)->linkmtu > maxmtu)
+			maxmtu =  ND_IFINFO(ifp)->linkmtu;
 	}
 	if (maxmtu)	/* update only when maxmtu is positive */
 		in6_maxmtu = maxmtu;
 }
 
+void *
+in6_domifattach(struct ifnet *ifp)
+{
+	struct in6_ifextra *ext;
+
+	ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
+	bzero(ext, sizeof(*ext));
+
+	ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
+		M_IFADDR, M_WAITOK);
+	bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
+
+	ext->icmp6_ifstat =
+		(struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
+			M_IFADDR, M_WAITOK);
+	bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
+
+	ext->nd_ifinfo = nd6_ifattach(ifp);
+	ext->scope6_id = scope6_ifattach(ifp);
+	return ext;
+}
+
+void
+in6_domifdetach(struct ifnet *ifp, void *aux)
+{
+	struct in6_ifextra *ext = (struct in6_ifextra *)aux;
+	scope6_ifdetach(ext->scope6_id);
+	nd6_ifdetach(ext->nd_ifinfo);
+	free(ext->in6_ifstat, M_IFADDR);
+	free(ext->icmp6_ifstat, M_IFADDR);
+	free(ext, M_IFADDR);
+}
+
 /*
  * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
  * v4 mapped addr or v4 compat addr
Index: netinet6/in6_gif.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_gif.c,v
retrieving revision 1.11
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.11 in6_gif.c
--- netinet6/in6_gif.c	6 Jan 2005 17:59:32 -0000	1.11
+++ netinet6/in6_gif.c	8 Jan 2005 19:09:58 -0000
@@ -323,9 +323,7 @@
 		sin6.sin6_family = AF_INET6;
 		sin6.sin6_len = sizeof(struct sockaddr_in6);
 		sin6.sin6_addr = ip6->ip6_src;
-#ifndef SCOPEDROUTING
 		sin6.sin6_scope_id = 0; /* XXX */
-#endif
 
 		rt = rtpurelookup((struct sockaddr *)&sin6);
 		if (rt == NULL || rt->rt_ifp != ifp) {
Index: netinet6/in6_ifattach.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.11
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.11 in6_ifattach.c
--- netinet6/in6_ifattach.c	6 Jan 2005 17:59:32 -0000	1.11
+++ netinet6/in6_ifattach.c	8 Jan 2005 19:09:58 -0000
@@ -61,10 +61,6 @@
 
 #include <net/net_osdep.h>
 
-struct in6_ifstat **in6_ifstat = NULL;
-struct icmp6_ifstat **icmp6_ifstat = NULL;
-size_t in6_ifstatmax = 0;
-size_t icmp6_ifstatmax = 0;
 unsigned long in6_maxmtu = 0;
 
 #ifdef IP6_AUTO_LINKLOCAL
@@ -437,11 +433,7 @@
 	ifra.ifra_addr.sin6_family = AF_INET6;
 	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
 	ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
-#ifdef SCOPEDROUTING
-	ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
-#else
 	ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */
-#endif
 	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
 	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
 		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
@@ -453,18 +445,11 @@
 			return -1;
 		}
 	}
-#ifdef SCOPEDROUTING
-	ifra.ifra_addr.sin6_scope_id =
-		in6_addr2scopeid(ifp,  &ifra.ifra_addr.sin6_addr);
-#endif
 
 	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
 	ifra.ifra_prefixmask.sin6_family = AF_INET6;
 	ifra.ifra_prefixmask.sin6_addr = in6mask64;
-#ifdef SCOPEDROUTING
-	/* take into accound the sin6_scope_id field for routing */
-	ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
-#endif
+
 	/* link-local addresses should NEVER expire. */
 	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
 	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
@@ -717,7 +702,6 @@
 in6_ifattach(struct ifnet *ifp,
 	     struct ifnet *altifp)	/* secondary EUI64 source */
 {
-	static size_t if_indexlim = 8;
 	struct in6_ifaddr *ia;
 	struct in6_addr in6;
 
@@ -733,50 +717,6 @@
 	}
 
 	/*
-	 * We have some arrays that should be indexed by if_index.
-	 * since if_index will grow dynamically, they should grow too.
-	 *	struct in6_ifstat **in6_ifstat
-	 *	struct icmp6_ifstat **icmp6_ifstat
-	 */
-	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
-	    if_index >= if_indexlim) {
-		size_t n;
-		caddr_t q;
-		size_t olim;
-
-		olim = if_indexlim;
-		while (if_index >= if_indexlim)
-			if_indexlim <<= 1;
-
-		/* grow in6_ifstat */
-		n = if_indexlim * sizeof(struct in6_ifstat *);
-		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
-		bzero(q, n);
-		if (in6_ifstat) {
-			bcopy((caddr_t)in6_ifstat, q,
-				olim * sizeof(struct in6_ifstat *));
-			free((caddr_t)in6_ifstat, M_IFADDR);
-		}
-		in6_ifstat = (struct in6_ifstat **)q;
-		in6_ifstatmax = if_indexlim;
-
-		/* grow icmp6_ifstat */
-		n = if_indexlim * sizeof(struct icmp6_ifstat *);
-		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
-		bzero(q, n);
-		if (icmp6_ifstat) {
-			bcopy((caddr_t)icmp6_ifstat, q,
-				olim * sizeof(struct icmp6_ifstat *));
-			free((caddr_t)icmp6_ifstat, M_IFADDR);
-		}
-		icmp6_ifstat = (struct icmp6_ifstat **)q;
-		icmp6_ifstatmax = if_indexlim;
-	}
-
-	/* initialize scope identifiers */
-	scope6_ifattach(ifp);
-
-	/*
 	 * quirks based on interface type
 	 */
 	switch (ifp->if_type) {
@@ -837,20 +777,6 @@
 	/* update dynamically. */
 	if (in6_maxmtu < ifp->if_mtu)
 		in6_maxmtu = ifp->if_mtu;
-
-	if (in6_ifstat[ifp->if_index] == NULL) {
-		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
-			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
-		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
-	}
-	if (icmp6_ifstat[ifp->if_index] == NULL) {
-		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
-			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
-		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
-	}
-
-	/* initialize NDP variables */
-	nd6_ifattach(ifp);
 }
 
 /*
@@ -967,7 +893,7 @@
 		int generate)
 {
 	u_int8_t nullbuf[8];
-	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
 
 	bzero(nullbuf, sizeof(nullbuf));
 	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
@@ -988,9 +914,9 @@
 void
 in6_tmpaddrtimer(void *ignored_arg)
 {
-	int i;
 	struct nd_ifinfo *ndi;
 	u_int8_t nullbuf[8];
+	struct ifnet *ifp;
 	int s = splnet();
 
 	callout_reset(&in6_tmpaddrtimer_ch,
@@ -999,8 +925,8 @@
 		      in6_tmpaddrtimer, NULL);
 
 	bzero(nullbuf, sizeof(nullbuf));
-	for (i = 1; i < if_index + 1; i++) {
-		ndi = &nd_ifinfo[i];
+	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+		ndi = ND_IFINFO(ifp);
 		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
 			/*
 			 * We've been generating a random ID on this interface.
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.21
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.21 in6_pcb.c
--- netinet6/in6_pcb.c	6 Jan 2005 17:59:32 -0000	1.21
+++ netinet6/in6_pcb.c	8 Jan 2005 19:09:58 -0000
@@ -569,7 +569,7 @@
 	if (in6p && in6p->in6p_hops >= 0)
 		return(in6p->in6p_hops);
 	else if (ifp)
-		return(nd_ifinfo[ifp->if_index].chlim);
+		return(ND_IFINFO(ifp)->chlim);
 	else
 		return(ip6_defhlim);
 }
Index: netinet6/in6_proto.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_proto.c,v
retrieving revision 1.7
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.7 in6_proto.c
--- netinet6/in6_proto.c	3 Jan 2005 22:11:51 -0000	1.7
+++ netinet6/in6_proto.c	8 Jan 2005 14:41:23 -0000
@@ -264,7 +264,8 @@
       (struct protosw *)&inet6sw[sizeof(inet6sw)/sizeof(inet6sw[0])], 0,
       in6_inithead,
       offsetof(struct sockaddr_in6, sin6_addr) << 3,
-      sizeof(struct sockaddr_in6) };
+      sizeof(struct sockaddr_in6),
+      in6_domifattach, in6_domifdetach, };
 
 DOMAIN_SET(inet6);
 
Index: netinet6/in6_src.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.9
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.9 in6_src.c
--- netinet6/in6_src.c	6 Jan 2005 17:59:32 -0000	1.9
+++ netinet6/in6_src.c	8 Jan 2005 19:09:58 -0000
@@ -316,7 +316,7 @@
 	if (in6p && in6p->in6p_hops >= 0)
 		return(in6p->in6p_hops);
 	else if (ifp)
-		return(nd_ifinfo[ifp->if_index].chlim);
+		return(ND_IFINFO(ifp)->chlim);
 	else
 		return(ip6_defhlim);
 }
Index: netinet6/in6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_var.h,v
retrieving revision 1.5
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.5 in6_var.h
--- netinet6/in6_var.h	2 Aug 2004 13:22:33 -0000	1.5
+++ netinet6/in6_var.h	8 Jan 2005 14:43:43 -0000
@@ -91,6 +91,15 @@
 	u_int32_t ia6t_pltime;	/* prefix lifetime */
 };
 
+struct nd_ifinfo;
+struct scope6_id;
+struct in6_ifextra {
+	struct in6_ifstat *in6_ifstat;
+	struct icmp6_ifstat *icmp6_ifstat;
+	struct nd_ifinfo *nd_ifinfo;
+	struct scope6_id *scope6_id;
+};
+
 struct	in6_ifaddr {
 	struct	ifaddr ia_ifa;		/* protocol-independent info */
 #define	ia_ifp		ia_ifa.ifa_ifp
@@ -447,18 +456,11 @@
 #ifdef _KERNEL
 extern struct in6_ifaddr *in6_ifaddr;
 
-extern struct in6_ifstat **in6_ifstat;
-extern size_t in6_ifstatmax;
 extern struct icmp6stat icmp6stat;
-extern struct icmp6_ifstat **icmp6_ifstat;
-extern size_t icmp6_ifstatmax;
 #define in6_ifstat_inc(ifp, tag) \
 do {								\
-	if ((ifp) && (ifp)->if_index <= if_index		\
-	 && (ifp)->if_index < in6_ifstatmax			\
-	 && in6_ifstat && in6_ifstat[(ifp)->if_index]) {	\
-		in6_ifstat[(ifp)->if_index]->tag++;		\
-	}							\
+	if (ifp)						\
+		((struct in6_ifextra *)((ifp)->if_afdata[AF_INET6]))->in6_ifstat->tag++; \
 } while (0)
 
 extern struct ifqueue ip6intrq;		/* IP6 packet input queue */
@@ -580,6 +582,8 @@
 int	in6if_do_dad (struct ifnet *);
 void	in6_purgeif (struct ifnet *);
 void	in6_savemkludge (struct in6_ifaddr *);
+void	*in6_domifattach (struct ifnet *);
+void	in6_domifdetach (struct ifnet *, void *);
 void	in6_setmaxmtu   (void);
 void	in6_restoremkludge (struct in6_ifaddr *, struct ifnet *);
 void	in6_purgemkludge (struct ifnet *);
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.10
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.10 ip6_forward.c
--- netinet6/ip6_forward.c	15 Oct 2004 22:59:10 -0000	1.10
+++ netinet6/ip6_forward.c	6 Jan 2005 20:55:09 -0000
@@ -503,14 +503,12 @@
 	}
 	else
 		origifp = rt->rt_ifp;
-#ifndef SCOPEDROUTING
 	/*
 	 * clear embedded scope identifiers if necessary.
 	 * in6_clearscope will touch the addresses only when necessary.
 	 */
 	in6_clearscope(&ip6->ip6_src);
 	in6_clearscope(&ip6->ip6_dst);
-#endif
 
 	/*
 	 * Run through list of hooks for output packets.
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.23
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.23 ip6_input.c
--- netinet6/ip6_input.c	3 Jan 2005 22:03:26 -0000	1.23
+++ netinet6/ip6_input.c	8 Jan 2005 14:44:49 -0000
@@ -106,6 +106,7 @@
 #include <netinet6/ip6_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet/icmp6.h>
+#include <netinet6/scope6_var.h>
 #include <netinet6/in6_ifattach.h>
 #include <netinet6/nd6.h>
 #include <netinet6/in6_prefix.h>
@@ -197,6 +198,7 @@
 	}
 
 	netisr_register(NETISR_IPV6, cpu0_portfn, ip6_input);
+	scope6_init();
 	nd6_init();
 	frag6_init();
 	/*
@@ -212,13 +214,6 @@
 static void
 ip6_init2(void *dummy)
 {
-
-	/*
-	 * to route local address of p2p link to loopback,
-	 * assign loopback address first.
-	 */
-	in6_ifattach(&loif[0], NULL);
-
 	/* nd6_timer_init */
 	callout_init(&nd6_timer_ch);
 	callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL);
@@ -534,10 +529,6 @@
 		dst6->sin6_len = sizeof(struct sockaddr_in6);
 		dst6->sin6_family = AF_INET6;
 		dst6->sin6_addr = ip6->ip6_dst;
-#ifdef SCOPEDROUTING
-		ip6_forward_rt.ro_dst.sin6_scope_id =
-			in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_dst);
-#endif
 
 		rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
 	}
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.16
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.16 ip6_output.c
--- netinet6/ip6_output.c	6 Jan 2005 17:59:32 -0000	1.16
+++ netinet6/ip6_output.c	8 Jan 2005 19:09:58 -0000
@@ -521,11 +521,6 @@
 		dst->sin6_family = AF_INET6;
 		dst->sin6_len = sizeof(struct sockaddr_in6);
 		dst->sin6_addr = ip6->ip6_dst;
-#ifdef SCOPEDROUTING
-		/* XXX: sin6_scope_id should already be fixed at this point */
-		if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
-			dst->sin6_scope_id = ntohs(dst->sin6_addr.s6_addr16[1]);
-#endif
 	}
 #if defined(IPSEC) || defined(FAST_IPSEC)
 	if (needipsec && needipsectun) {
@@ -788,7 +783,7 @@
 		}
 	}
 	if (ro_pmtu->ro_rt != NULL) {
-		u_int32_t ifmtu = nd_ifinfo[ifp->if_index].linkmtu;
+		u_int32_t ifmtu = ND_IFINFO(ifp)->linkmtu;
 
 		mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
 		if (mtu > ifmtu || mtu == 0) {
@@ -808,7 +803,7 @@
 				 ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
 		}
 	} else {
-		mtu = nd_ifinfo[ifp->if_index].linkmtu;
+		mtu = ND_IFINFO(ifp)->linkmtu;
 	}
 
 	/*
@@ -855,14 +850,12 @@
 	}
 	else
 		origifp = ifp;
-#ifndef SCOPEDROUTING
 	/*
 	 * clear embedded scope identifiers if necessary.
 	 * in6_clearscope will touch the addresses only when necessary.
 	 */
 	in6_clearscope(&ip6->ip6_src);
 	in6_clearscope(&ip6->ip6_dst);
-#endif
 
 	/*
 	 * Check with the firewall...
@@ -2496,14 +2489,12 @@
 #endif
 
 	ip6 = mtod(copym, struct ip6_hdr *);
-#ifndef SCOPEDROUTING
 	/*
 	 * clear embedded scope identifiers if necessary.
 	 * in6_clearscope will touch the addresses only when necessary.
 	 */
 	in6_clearscope(&ip6->ip6_src);
 	in6_clearscope(&ip6->ip6_dst);
-#endif
 
 	(void)if_simloop(ifp, copym, dst->sin6_family, NULL);
 }
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.14
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.14 nd6.c
--- netinet6/nd6.c	6 Jan 2005 17:59:32 -0000	1.14
+++ netinet6/nd6.c	8 Jan 2005 19:12:28 -0000
@@ -106,14 +106,13 @@
 static int nd6_inuse, nd6_allocated;
 
 struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6};
-static size_t nd_ifinfo_indexlim = 8;
-struct nd_ifinfo *nd_ifinfo = NULL;
 struct nd_drhead nd_defrouter;
 struct nd_prhead nd_prefix = { 0 };
 
 int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
 static struct sockaddr_in6 all1_sa;
 
+static void nd6_setmtu0 (struct ifnet *, struct nd_ifinfo *);
 static void nd6_slowtimo (void *);
 static int regen_tmpaddr (struct in6_ifaddr *);
 
@@ -148,58 +147,39 @@
 	    nd6_slowtimo, NULL);
 }
 
-void
+struct nd_ifinfo *
 {
+	struct nd_ifinfo *nd;
 
-	/*
-	 * We have some arrays that should be indexed by if_index.
-	 * since if_index will grow dynamically, they should grow too.
-	 */
-	if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) {
-		size_t n;
-		caddr_t q;
-
-		while (if_index >= nd_ifinfo_indexlim)
-			nd_ifinfo_indexlim <<= 1;
-
-		/* grow nd_ifinfo */
-		n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo);
-		q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK);
-		bzero(q, n);
-		if (nd_ifinfo) {
-			bcopy((caddr_t)nd_ifinfo, q, n/2);
-			free((caddr_t)nd_ifinfo, M_IP6NDP);
-		}
-		nd_ifinfo = (struct nd_ifinfo *)q;
-	}
+	nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK);
+	bzero(nd, sizeof(*nd));
 
-#define ND nd_ifinfo[ifp->if_index]
+	nd->initialized = 1;
 
-	/*
-	 * Don't initialize if called twice.
-	 * XXX: to detect this, we should choose a member that is never set
-	 * before initialization of the ND structure itself.  We formaly used
-	 * the linkmtu member, which was not suitable because it could be 
-	 * initialized via "ifconfig mtu".
-	 */
-	if (ND.basereachable)
-		return;
+	nd->linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu;
+	nd->chlim = IPV6_DEFHLIM;
+	nd->basereachable = REACHABLE_TIME;
+	nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
+	nd->retrans = RETRANS_TIMER;
+	nd->receivedra = 0;
 
-	ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu;
-	ND.chlim = IPV6_DEFHLIM;
-	ND.basereachable = REACHABLE_TIME;
-	ND.reachable = ND_COMPUTE_RTIME(ND.basereachable);
-	ND.retrans = RETRANS_TIMER;
-	ND.receivedra = 0;
 	/*
 	 * Note that the default value of ip6_accept_rtadv is 0, which means
 	 * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
 	 * here.
 	 */
-	ND.flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
-	nd6_setmtu(ifp);
-#undef ND
+	nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
+
+	/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
+	nd6_setmtu0(ifp, nd);
+	return nd;
+}
+
+void
+nd6_ifdetach(struct nd_ifinfo *nd)
+{
+	free(nd, M_IP6NDP);
 }
 
 /*
@@ -209,9 +189,18 @@
 void
 nd6_setmtu(struct ifnet *ifp)
 {
-	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
-	u_long oldmaxmtu = ndi->maxmtu;
-	u_long oldlinkmtu = ndi->linkmtu;
+	nd6_setmtu0(ifp, ND_IFINFO(ifp));
+}
+
+/* XXX todo: do not maintain copy of ifp->if_mtu in ndi->maxmtu */
+void
+nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi)
+{
+	u_long oldmaxmtu;
+	u_long oldlinkmtu;
+
+	oldmaxmtu = ndi->maxmtu;
+	oldlinkmtu = ndi->linkmtu;
 
 	switch (ifp->if_type) {
 	case IFT_ARCNET:	/* XXX MTU handling needs more work */
@@ -443,7 +432,7 @@
 			ln = next;
 			continue;
 		}
-		ndi = &nd_ifinfo[ifp->if_index];
+		ndi = ND_IFINFO(ifp);
 		dst = (struct sockaddr_in6 *)rt_key(rt);
 
 		if (ln->ln_expire > time_second) {
@@ -465,7 +454,7 @@
 			if (ln->ln_asked < nd6_mmaxtries) {
 				ln->ln_asked++;
 				ln->ln_expire = time_second +
-					nd_ifinfo[ifp->if_index].retrans / 1000;
+					ND_IFINFO(ifp)->retrans / 1000;
 				nd6_ns_output(ifp, NULL, &dst->sin6_addr,
 					ln, 0);
 			} else {
@@ -520,7 +509,7 @@
 			if (ln->ln_asked < nd6_umaxtries) {
 				ln->ln_asked++;
 				ln->ln_expire = time_second +
-					nd_ifinfo[ifp->if_index].retrans / 1000;
+					ND_IFINFO(ifp)->retrans / 1000;
 				nd6_ns_output(ifp, &dst->sin6_addr,
 					       &dst->sin6_addr, ln, 0);
 			} else {
@@ -791,9 +780,7 @@
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	sin6.sin6_family = AF_INET6;
 	sin6.sin6_addr = *addr6;
-#ifdef SCOPEDROUTING
-	sin6.sin6_scope_id = in6_addr2scopeid(ifp, addr6);
-#endif
+
 	if (create)
 		rt = rtlookup((struct sockaddr *)&sin6);
 	else
@@ -1066,7 +1053,7 @@
 	ln->ln_state = ND6_LLINFO_REACHABLE;
 	if (ln->ln_expire)
 		ln->ln_expire = time_second +
-			nd_ifinfo[rt->rt_ifp->if_index].reachable;
+			ND_IFINFO(rt->rt_ifp)->reachable;
 }
 
 void
@@ -1439,35 +1426,23 @@
 
 		break;
 	case OSIOCGIFINFO_IN6:
-		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
-			error = EINVAL;
-			break;
-		}
-		ndi->ndi.linkmtu = nd_ifinfo[ifp->if_index].linkmtu;
-		ndi->ndi.maxmtu = nd_ifinfo[ifp->if_index].maxmtu;
-		ndi->ndi.basereachable =
-		    nd_ifinfo[ifp->if_index].basereachable;
-		ndi->ndi.reachable = nd_ifinfo[ifp->if_index].reachable;
-		ndi->ndi.retrans = nd_ifinfo[ifp->if_index].retrans;
-		ndi->ndi.flags = nd_ifinfo[ifp->if_index].flags;
-		ndi->ndi.recalctm = nd_ifinfo[ifp->if_index].recalctm;
-		ndi->ndi.chlim = nd_ifinfo[ifp->if_index].chlim;
-		ndi->ndi.receivedra = nd_ifinfo[ifp->if_index].receivedra;
+		/* XXX: old ndp(8) assumes a positive value for linkmtu. */
+		bzero(&ndi->ndi, sizeof(ndi->ndi));
+		ndi->ndi.linkmtu = ND_IFINFO(ifp)->linkmtu;
+		ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu;
+		ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable;
+		ndi->ndi.reachable = ND_IFINFO(ifp)->reachable;
+		ndi->ndi.retrans = ND_IFINFO(ifp)->retrans;
+		ndi->ndi.flags = ND_IFINFO(ifp)->flags;
+		ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm;
+		ndi->ndi.chlim = ND_IFINFO(ifp)->chlim;
+		ndi->ndi.receivedra = ND_IFINFO(ifp)->receivedra;
 		break;
 	case SIOCGIFINFO_IN6:
-		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
-			error = EINVAL;
-			break;
-		}
-		ndi->ndi = nd_ifinfo[ifp->if_index];
+		ndi->ndi = *ND_IFINFO(ifp);
 		break;
 	case SIOCSIFINFO_FLAGS:
-		/* XXX: almost all other fields of ndi->ndi is unused */
-		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {
-			error = EINVAL;
-			break;
-		}
-		nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags;
+		ND_IFINFO(ifp)->flags = ndi->ndi.flags;
 		break;
 	case SIOCSNDFLUSH_IN6:	/* XXX: the ioctl name is confusing... */
 		/* flush default router list */
@@ -1808,15 +1783,13 @@
 nd6_slowtimo(void *ignored_arg)
 {
 	int s = splnet();
-	int i;
 	struct nd_ifinfo *nd6if;
+	struct ifnet *ifp;
 
 	callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
 	    nd6_slowtimo, NULL);
-	for (i = 1; i < if_index + 1; i++) {
-		if (!nd_ifinfo || i >= nd_ifinfo_indexlim)
-			continue;
-		nd6if = &nd_ifinfo[i];
+	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+		nd6if = ND_IFINFO(ifp);
 		if (nd6if->basereachable && /* already initialized */
 		    (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {
 			/*
@@ -1922,7 +1895,7 @@
 	}
 	if (!ln || !rt) {
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
-		    !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) {
+		    !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
 			log(LOG_DEBUG,
 			    "nd6_output: can't allocate llinfo for %s "
 			    "(ln=%p, rt=%p)\n",
@@ -1980,7 +1953,7 @@
 		    ln->ln_expire < time_second) {
 			ln->ln_asked++;
 			ln->ln_expire = time_second +
-				nd_ifinfo[ifp->if_index].retrans / 1000;
+				ND_IFINFO(ifp)->retrans / 1000;
 			nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
 		}
 	}
Index: netinet6/nd6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.5
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.5 nd6.h
--- netinet6/nd6.h	30 Dec 2004 02:26:12 -0000	1.5
+++ netinet6/nd6.h	8 Jan 2005 14:58:54 -0000
@@ -81,6 +81,7 @@
 	int recalctm;			/* BaseReacable re-calculation timer */
 	u_int8_t chlim;			/* CurHopLimit */
 	u_int8_t receivedra;
+	u_int8_t initialized;		/* Flag to see the entry is initialized */
 	/* the following 3 members are for privacy extension for addrconf */
 	u_int8_t randomseed0[8]; /* upper 64 bits of MD5 digest */
 	u_int8_t randomseed1[8]; /* lower 64 bits (usually the EUI64 IFID) */
@@ -90,6 +91,16 @@
 #define ND6_IFF_PERFORMNUD	0x1
 #define ND6_IFF_ACCEPT_RTADV	0x2
 
+#ifdef _KERNEL
+#define ND_IFINFO(ifp) \
+	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo)
+#define IN6_LINKMTU(ifp) \
+	((ND_IFINFO(ifp)->linkmtu && ND_IFINFO(ifp)->linkmtu < (ifp)->if_mtu) \
+		? ND_IFINFO(ifp)->linkmtu \
+		: ((ND_IFINFO(ifp)->maxmtu && ND_IFINFO(ifp)->maxmtu < (ifp)->if_mtu) \
+			? ND_IFINFO(ifp)->maxmtu : (ifp)->if_mtu))
+#endif
+
 struct in6_nbrinfo {
 	char ifname[IFNAMSIZ];	/* if name, e.g. "en0" */
 	struct in6_addr addr;	/* IPv6 address of the neighbor */
@@ -342,7 +353,8 @@
 /* XXX: need nd6_var.h?? */
 /* nd6.c */
 void nd6_init (void);
-void nd6_ifattach (struct ifnet *);
+struct nd_ifinfo *nd6_ifattach (struct ifnet *);
+void nd6_ifdetach (struct nd_ifinfo *);
 int nd6_is_addr_neighbor (struct sockaddr_in6 *, struct ifnet *);
 void nd6_option_init (void *, int, union nd_opts *);
 struct nd_opt_hdr *nd6_option (union nd_opts *);
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.9
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.9 nd6_nbr.c
--- netinet6/nd6_nbr.c	6 Jan 2005 17:59:32 -0000	1.9
+++ netinet6/nd6_nbr.c	8 Jan 2005 19:09:59 -0000
@@ -657,7 +657,7 @@
 			ln->ln_byhint = 0;
 			if (ln->ln_expire)
 				ln->ln_expire = time_second +
-				    nd_ifinfo[rt->rt_ifp->if_index].reachable;
+				    ND_IFINFO(rt->rt_ifp)->reachable;
 		} else {
 			ln->ln_state = ND6_LLINFO_STALE;
 			ln->ln_expire = time_second + nd6_gctimer;
@@ -738,7 +738,7 @@
 				ln->ln_byhint = 0;
 				if (ln->ln_expire) {
 					ln->ln_expire = time_second +
-					    nd_ifinfo[ifp->if_index].reachable;
+					    ND_IFINFO(ifp)->reachable;
 				}
 			} else {
 				if (lladdr && llchange) {
@@ -1088,8 +1088,8 @@
 	dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
 	if (tick == NULL) {
 		nd6_dad_ns_output(dp, ifa);
-		nd6_dad_starttimer(dp, 
-		    nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
+		nd6_dad_starttimer(dp,
+		    ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
 	} else {
 		int ntick;
 
@@ -1178,8 +1178,8 @@
 		 * We have more NS to go.  Send NS packet for DAD.
 		 */
 		nd6_dad_ns_output(dp, ifa);
-		nd6_dad_starttimer(dp, 
-		    nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
+		nd6_dad_starttimer(dp,
+			ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
 	} else {
 		/*
 		 * We have transmitted sufficient number of DAD packets.
Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.7
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.7 nd6_rtr.c
--- netinet6/nd6_rtr.c	30 Dec 2004 02:26:12 -0000	1.7
+++ netinet6/nd6_rtr.c	8 Jan 2005 15:00:51 -0000
@@ -205,7 +205,7 @@
 	int off, icmp6len;
 {
 	struct ifnet *ifp = m->m_pkthdr.rcvif;
-	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 	struct nd_router_advert *nd_ra;
 	struct in6_addr saddr6 = ip6->ip6_src;
Index: netinet6/scope6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/scope6.c,v
retrieving revision 1.3
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.3 scope6.c
--- netinet6/scope6.c	20 May 2004 18:30:36 -0000	1.3
+++ netinet6/scope6.c	8 Jan 2005 17:25:59 -0000
@@ -46,74 +46,55 @@
 #include <netinet6/in6_var.h>
 #include <netinet6/scope6_var.h>
 
-struct scope6_id {
-	/*
-	 * 16 is correspondent to 4bit multicast scope field.
-	 * i.e. from node-local to global with some reserved/unassigned types.
-	 */
-	u_int32_t s6id_list[16];
-};
-static size_t if_indexlim = 8;
-struct scope6_id *scope6_ids = NULL;
+static struct scope6_id sid_default;
+#define SID(ifp) \
+	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id)
 
 void
+scope6_init()
+{
+	bzero(&sid_default, sizeof(sid_default));
+}
+
+struct scope6_id *
 scope6_ifattach(struct ifnet *ifp)
 {
 	int s = splnet();
+	struct scope6_id *sid;
 
-	/*
-	 * We have some arrays that should be indexed by if_index.
-	 * since if_index will grow dynamically, they should grow too.
-	 */
-	if (scope6_ids == NULL || if_index >= if_indexlim) {
-		size_t n;
-		caddr_t q;
-
-		while (if_index >= if_indexlim)
-			if_indexlim <<= 1;
-
-		/* grow scope index array */
-		n = if_indexlim * sizeof(struct scope6_id);
-		/* XXX: need new malloc type? */
-		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
-		bzero(q, n);
-		if (scope6_ids) {
-			bcopy((caddr_t)scope6_ids, q, n/2);
-			free((caddr_t)scope6_ids, M_IFADDR);
-		}
-		scope6_ids = (struct scope6_id *)q;
-	}
-
-#define SID scope6_ids[ifp->if_index]
-
-	/* don't initialize if called twice */
-	if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) {
-		splx(s);
-		return;
-	}
+	sid = (struct scope6_id *)malloc(sizeof(*sid), M_IFADDR, M_WAITOK);
+	bzero(sid, sizeof(*sid));
 
 	/*
 	 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
 	 * Should we rather hardcode here?
 	 */
-	SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
+	sid->s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = ifp->if_index;
+	sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
 #ifdef MULTI_SCOPE
 	/* by default, we don't care about scope boundary for these scopes. */
-	SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
-	SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
+	sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
+	sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
 #endif
-#undef SID
 
 	splx(s);
+	return sid;
+}
+
+void
+scope6_ifdetach(struct scope6_id *sid)
+{
+	free(sid, M_IFADDR);
 }
 
 int
-scope6_set(struct ifnet *ifp, u_int32_t *idlist)
+scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
 {
 	int i, s;
 	int error = 0;
+	struct scope6_id *sid = SID(ifp);
 
-	if (scope6_ids == NULL)	/* paranoid? */
+	if (!sid)	/* paranoid? */
 		return(EINVAL);
 
 	/*
@@ -129,10 +110,10 @@
 	s = splnet();
 
 	for (i = 0; i < 16; i++) {
-		if (idlist[i] &&
-		    idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) {
+		if (idlist->s6id_list[i] &&
+		    idlist->s6id_list[i] != sid->s6id_list[i]) {
 			if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
-			    idlist[i] > if_index) {
+			    idlist->s6id_list[i] > if_index) {
 				/*
 				 * XXX: theoretically, there should be no
 				 * relationship between link IDs and interface
@@ -148,7 +129,7 @@
 			 * but we simply set the new value in this initial
 			 * implementation.
 			 */
-			scope6_ids[ifp->if_index].s6id_list[i] = idlist[i];
+			sid->s6id_list[i] = idlist->s6id_list[i];
 		}
 	}
 	splx(s);
@@ -157,13 +138,14 @@
 }
 
 int
-scope6_get(struct ifnet *ifp, u_int32_t *idlist)
+scope6_get(struct ifnet *ifp, struct scope6_id *idlist)
 {
-	if (scope6_ids == NULL)	/* paranoid? */
+	struct scope6_id *sid = SID(ifp);
+
+	if (sid == NULL)	/* paranoid? */
 		return(EINVAL);
 
-	bcopy(scope6_ids[ifp->if_index].s6id_list, idlist,
-	      sizeof(scope6_ids[ifp->if_index].s6id_list));
+	*idlist = *sid;
 
 	return(0);
 }
@@ -231,58 +213,71 @@
 in6_addr2scopeid(struct ifnet *ifp,	/* must not be NULL */
 		 struct in6_addr *addr)	/* must not be NULL */
 {
-	int scope = in6_addrscope(addr);
+	int scope;
+	struct scope6_id *sid = SID(ifp);
 
-	if (scope6_ids == NULL)	/* paranoid? */
-		return(0);	/* XXX */
-	if (ifp->if_index >= if_indexlim)
-		return(0);	/* XXX */
+#ifdef DIAGNOSTIC
+	if (sid == NULL) { /* should not happen */
+		panic("in6_addr2zoneid: scope array is NULL");
+		/* NOTREACHED */
+	}
+#endif
+
+	/*
+	 * special case: the loopback address can only belong to a loopback
+	 * interface.
+	 */
+	if (IN6_IS_ADDR_LOOPBACK(addr)) {
+		if (!(ifp->if_flags & IFF_LOOPBACK))
+			return (-1);
+		else
+			return (0); /* there's no ambiguity */
+	}
+
+	scope = in6_addrscope(addr);
 
-#define SID scope6_ids[ifp->if_index]
 	switch(scope) {
 	case IPV6_ADDR_SCOPE_NODELOCAL:
 		return(-1);	/* XXX: is this an appropriate value? */
 
 	case IPV6_ADDR_SCOPE_LINKLOCAL:
-		return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
+		return (sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
 
 	case IPV6_ADDR_SCOPE_SITELOCAL:
-		return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
+		return (sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
 
 	case IPV6_ADDR_SCOPE_ORGLOCAL:
-		return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
+		return (sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
 
 	default:
 		return(0);	/* XXX: treat as global. */
 	}
-#undef SID
 }
 
 void
 scope6_setdefault(struct ifnet *ifp)	/* note that this might be NULL */
 {
 	/*
-	 * Currently, this function just set the default "link" according to
-	 * the given interface.
+	 * Currently, this function just set the default "interfaces"
+	 * and "links" according to the given interface.
 	 * We might eventually have to separate the notion of "link" from
 	 * "interface" and provide a user interface to set the default.
 	 */
 	if (ifp) {
-		scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
+		sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] =
 			ifp->if_index;
+		sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
+			ifp->if_index;
+	} else {
+		sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = 0;
+		sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
 	}
-	else
-		scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
 }
 
 int
-scope6_get_default(u_int32_t *idlist)
+scope6_get_default(struct scope6_id *idlist)
 {
-	if (scope6_ids == NULL)	/* paranoid? */
-		return(EINVAL);
-
-	bcopy(scope6_ids[0].s6id_list, idlist,
-	      sizeof(scope6_ids[0].s6id_list));
+	*idlist = sid_default;
 
 	return(0);
 }
@@ -290,5 +285,12 @@
 u_int32_t
 scope6_addr2default(struct in6_addr *addr)
 {
-	return(scope6_ids[0].s6id_list[in6_addrscope(addr)]);
+	/*
+	 * special case: The loopback address should be considered as
+	 * link-local, but there's no ambiguity in the syntax.
+	 */
+	if (IN6_IS_ADDR_LOOPBACK(addr))
+		return (0);
+
+	return (sid_default.s6id_list[in6_addrscope(addr)]);
 }
Index: netinet6/scope6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/scope6_var.h,v
retrieving revision 1.3
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.3 scope6_var.h
--- netinet6/scope6_var.h	23 Aug 2003 11:02:46 -0000	1.3
+++ netinet6/scope6_var.h	8 Jan 2005 15:12:40 -0000
@@ -35,11 +35,21 @@
 #define _NETINET6_SCOPE6_VAR_H_
 
 #ifdef _KERNEL
-void	scope6_ifattach (struct ifnet *);
-int	scope6_set (struct ifnet *, u_int32_t *);
-int	scope6_get (struct ifnet *, u_int32_t *);
+struct scope6_id {
+	/*
+	 * 16 is correspondent to 4bit multicast scope field.
+	 * i.e. from node-local to global with some reserved/unassigned types.
+	 */
+	u_int32_t s6id_list[16];
+};
+
+void	scope6_init (void);
+struct scope6_id *scope6_ifattach (struct ifnet *);
+void	scope6_ifdetach (struct scope6_id *);
+int	scope6_set (struct ifnet *, struct scope6_id *);
+int	scope6_get (struct ifnet *, struct scope6_id *);
 void	scope6_setdefault (struct ifnet *);
-int	scope6_get_default (u_int32_t *);
+int	scope6_get_default (struct scope6_id *);
 u_int32_t scope6_in6_addrscope (struct in6_addr *);
 u_int32_t scope6_addr2default (struct in6_addr *);
 #endif /* _KERNEL */
Index: sys/domain.h
===================================================================
RCS file: /cvs/src/sys/sys/domain.h,v
retrieving revision 1.4
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.4 domain.h
--- sys/domain.h	14 Dec 2004 18:46:08 -0000	1.4
+++ sys/domain.h	8 Jan 2005 15:57:52 -0000
@@ -46,6 +46,7 @@
  * Forward structure declarations for function prototypes [sic].
  */
 struct	mbuf;
+struct	ifnet;
 
 struct	domain {
 	int	dom_family;		/* AF_xxx */
@@ -61,6 +62,9 @@
 	int	(*dom_rtattach)(void **, int);	/* initialize routing table */
 	int	dom_rtoffset;		/* an arg to rtattach, in bits */
 	int	dom_maxrtkey;		/* for routing layer */
+	void	*(*dom_ifattach)(struct ifnet *);
+	void	(*dom_ifdetach)(struct ifnet *, void *);
+					/* af-dependent data on ifnet */
 };
 
 #ifdef _KERNEL
Index: sys/kernel.h
===================================================================
RCS file: /cvs/src/sys/sys/kernel.h,v
retrieving revision 1.11
diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$DragonFly:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.11 kernel.h
--- sys/kernel.h	30 Mar 2004 17:18:58 -0000	1.11
+++ sys/kernel.h	8 Jan 2005 15:58:48 -0000
@@ -140,6 +140,7 @@
 	SI_SUB_PROTO_BEGIN	= 0x8000000,	/* XXX: set splimp (kludge)*/
 	SI_SUB_PROTO_IF		= 0x8400000,	/* interfaces*/
 	SI_SUB_PROTO_DOMAIN	= 0x8800000,	/* domains (address families?)*/
+	SI_SUB_PROTO_IFATTACHDOMAIN	= 0x8800001,	/* domain dependent data init */
 	SI_SUB_PROTO_END	= 0x8ffffff,	/* XXX: set splx (kludge)*/
 	SI_SUB_KPROF		= 0x9000000,	/* kernel profiling*/
 	SI_SUB_KICK_SCHEDULER	= 0xa000000,	/* start the timeout events*/
Attachment:
pgp00013.pgp
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pgp00013.pgp
Type: application/octet-stream
Size: 187 bytes
Desc: "Description: PGP signature"
URL: <http://lists.dragonflybsd.org/pipermail/submit/attachments/20050108/a05ac7ab/attachment-0014.obj>


More information about the Submit mailing list