Home | History | Annotate | Line # | Download | only in netinet6
in6_ifattach.c revision 1.24
      1 /*	$NetBSD: in6_ifattach.c,v 1.24 2000/04/10 15:45:24 itojun Exp $	*/
      2 /*	$KAME: in6_ifattach.c,v 1.39 2000/03/02 09:24:45 itojun Exp $	*/
      3 
      4 /*
      5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the project nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/param.h>
     34 #include <sys/systm.h>
     35 #include <sys/malloc.h>
     36 #include <sys/socket.h>
     37 #include <sys/sockio.h>
     38 #include <sys/kernel.h>
     39 #include <sys/md5.h>
     40 
     41 #include <net/if.h>
     42 #include <net/if_dl.h>
     43 #include <net/if_types.h>
     44 #include <net/route.h>
     45 
     46 #include <netinet/in.h>
     47 #include <netinet/in_var.h>
     48 
     49 #include <netinet/ip6.h>
     50 #include <netinet6/ip6_var.h>
     51 #include <netinet6/in6_ifattach.h>
     52 #include <netinet/ip6.h>
     53 #include <netinet6/ip6_var.h>
     54 #include <netinet6/nd6.h>
     55 
     56 #include <net/net_osdep.h>
     57 
     58 static	struct in6_addr llsol;
     59 
     60 struct in6_ifstat **in6_ifstat = NULL;
     61 struct icmp6_ifstat **icmp6_ifstat = NULL;
     62 size_t in6_ifstatmax = 0;
     63 size_t icmp6_ifstatmax = 0;
     64 unsigned long in6_maxmtu = 0;
     65 
     66 int found_first_ifid = 0;
     67 #define IFID_LEN 8
     68 static u_int8_t first_ifid[IFID_LEN];
     69 
     70 static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t));
     71 static int gen_rand_eui64 __P((u_int8_t *));
     72 
     73 static int
     74 laddr_to_eui64(dst, src, len)
     75 	u_int8_t *dst;
     76 	u_int8_t *src;
     77 	size_t len;
     78 {
     79 	static u_int8_t zero[8];
     80 
     81 	bzero(zero, sizeof(zero));
     82 
     83 	switch (len) {
     84 	case 6:
     85 		if (bcmp(zero, src, 6) == 0)
     86 			return EINVAL;
     87 		dst[0] = src[0];
     88 		dst[1] = src[1];
     89 		dst[2] = src[2];
     90 		dst[3] = 0xff;
     91 		dst[4] = 0xfe;
     92 		dst[5] = src[3];
     93 		dst[6] = src[4];
     94 		dst[7] = src[5];
     95 		break;
     96 	case 8:
     97 		if (bcmp(zero, src, 8) == 0)
     98 			return EINVAL;
     99 		bcopy(src, dst, len);
    100 		break;
    101 	default:
    102 		return EINVAL;
    103 	}
    104 
    105 	return 0;
    106 }
    107 
    108 /*
    109  * Generate a last-resort interface identifier, when the machine has no
    110  * IEEE802/EUI64 address sources.
    111  * The address should be random, and should not change across reboot.
    112  */
    113 static int
    114 gen_rand_eui64(dst)
    115 	u_int8_t *dst;
    116 {
    117 	MD5_CTX ctxt;
    118 	u_int8_t digest[16];
    119 
    120 	/* generate 8bytes of pseudo-random value. */
    121 	bzero(&ctxt, sizeof(ctxt));
    122 	MD5Init(&ctxt);
    123 	MD5Update(&ctxt, hostname, hostnamelen);
    124 	MD5Final(digest, &ctxt);
    125 
    126 	/* assumes sizeof(digest) > sizeof(first_ifid) */
    127 	bcopy(digest, dst, 8);
    128 
    129 	/* make sure to set "u" bit to local, and "g" bit to individual. */
    130 	dst[0] &= 0xfe;
    131 	dst[0] |= 0x02;		/* EUI64 "local" */
    132 
    133 	return 0;
    134 }
    135 
    136 /*
    137  * Find first ifid on list of interfaces.
    138  * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
    139  * is globally unique.  We may need to have a flag parameter in the future.
    140  */
    141 int
    142 in6_ifattach_getifid(ifp0)
    143 	struct ifnet *ifp0;
    144 {
    145 	struct ifnet *ifp;
    146 	struct ifaddr *ifa;
    147 	u_int8_t *addr = NULL;
    148 	int addrlen = 0;
    149 	struct sockaddr_dl *sdl;
    150 
    151 	if (found_first_ifid)
    152 		return 0;
    153 
    154 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
    155 	{
    156 		if (ifp0 != NULL && ifp0 != ifp)
    157 			continue;
    158 		for (ifa = ifp->if_addrlist.tqh_first;
    159 		     ifa;
    160 		     ifa = ifa->ifa_list.tqe_next)
    161 		{
    162 			if (ifa->ifa_addr->sa_family != AF_LINK)
    163 				continue;
    164 			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
    165 			if (sdl == NULL)
    166 				continue;
    167 			if (sdl->sdl_alen == 0)
    168 				continue;
    169 			switch (ifp->if_type) {
    170 			case IFT_ETHER:
    171 			case IFT_FDDI:
    172 			case IFT_ATM:
    173 				/* IEEE802/EUI64 cases - what others? */
    174 				addr = LLADDR(sdl);
    175 				addrlen = sdl->sdl_alen;
    176 				/*
    177 				 * to copy ifid from IEEE802/EUI64 interface,
    178 				 * u bit of the source needs to be 0.
    179 				 */
    180 				if ((addr[0] & 0x02) != 0)
    181 					break;
    182 				goto found;
    183 			case IFT_ARCNET:
    184 				/*
    185 				 * ARCnet interface token cannot be used as
    186 				 * globally unique identifier due to its
    187 				 * small bitwidth.
    188 				 */
    189 				break;
    190 			default:
    191 				break;
    192 			}
    193 		}
    194 	}
    195 #ifdef DEBUG
    196 	printf("in6_ifattach_getifid: failed to get EUI64");
    197 #endif
    198 	return EADDRNOTAVAIL;
    199 
    200 found:
    201 	if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
    202 		found_first_ifid = 1;
    203 
    204 	if (found_first_ifid) {
    205 		printf("%s: supplying EUI64: "
    206 			"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
    207 			if_name(ifp),
    208 			first_ifid[0], first_ifid[1],
    209 			first_ifid[2], first_ifid[3],
    210 			first_ifid[4], first_ifid[5],
    211 			first_ifid[6], first_ifid[7]);
    212 
    213 		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
    214 		first_ifid[0] ^= 0x02;
    215 
    216 		return 0;
    217 	} else {
    218 #ifdef DEBUG
    219 		printf("in6_ifattach_getifid: failed to get EUI64");
    220 #endif
    221 		return EADDRNOTAVAIL;
    222 	}
    223 }
    224 
    225 /*
    226  * XXX multiple loopback interface needs more care.  for instance,
    227  * nodelocal address needs to be configured onto only one of them.
    228  */
    229 void
    230 in6_ifattach(ifp, type, laddr, noloop)
    231 	struct ifnet *ifp;
    232 	u_int type;
    233 	caddr_t laddr;
    234 	/* size_t laddrlen; */
    235 	int noloop;
    236 {
    237 	static size_t if_indexlim = 8;
    238 	struct sockaddr_in6 mltaddr;
    239 	struct sockaddr_in6 mltmask;
    240 	struct sockaddr_in6 gate;
    241 	struct sockaddr_in6 mask;
    242 
    243 	struct in6_ifaddr *ia, *ib, *oia;
    244 	struct ifaddr *ifa;
    245 	int rtflag = 0;
    246 
    247 	if (type == IN6_IFT_P2P && found_first_ifid == 0) {
    248 		printf("%s: no ifid available for IPv6 link-local address\n",
    249 			if_name(ifp));
    250 #if 0
    251 		return;
    252 #else
    253 		/* last resort */
    254 		if (gen_rand_eui64(first_ifid) == 0) {
    255 			printf("%s: using random value as EUI64: "
    256 				"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
    257 				if_name(ifp),
    258 				first_ifid[0], first_ifid[1],
    259 				first_ifid[2], first_ifid[3],
    260 				first_ifid[4], first_ifid[5],
    261 				first_ifid[6], first_ifid[7]);
    262 			/*
    263 			 * invert u bit to convert EUI64 to RFC2373 interface
    264 			 * ID.
    265 			 */
    266 			first_ifid[0] ^= 0x02;
    267 
    268 			found_first_ifid = 1;
    269 		}
    270 #endif
    271 	}
    272 
    273 	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
    274 		printf("%s: not multicast capable, IPv6 not enabled\n",
    275 			if_name(ifp));
    276 		return;
    277 	}
    278 
    279 	/*
    280 	 * We have some arrays that should be indexed by if_index.
    281 	 * since if_index will grow dynamically, they should grow too.
    282 	 *	struct in6_ifstat **in6_ifstat
    283 	 *	struct icmp6_ifstat **icmp6_ifstat
    284 	 */
    285 	if (in6_ifstat == NULL || icmp6_ifstat == NULL
    286 	 || if_index >= if_indexlim) {
    287 		size_t n;
    288 		caddr_t q;
    289 		size_t olim;
    290 
    291 		olim = if_indexlim;
    292 		while (if_index >= if_indexlim)
    293 			if_indexlim <<= 1;
    294 
    295 		/* grow in6_ifstat */
    296 		n = if_indexlim * sizeof(struct in6_ifstat *);
    297 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
    298 		bzero(q, n);
    299 		if (in6_ifstat) {
    300 			bcopy((caddr_t)in6_ifstat, q,
    301 				olim * sizeof(struct in6_ifstat *));
    302 			free((caddr_t)in6_ifstat, M_IFADDR);
    303 		}
    304 		in6_ifstat = (struct in6_ifstat **)q;
    305 		in6_ifstatmax = if_indexlim;
    306 
    307 		/* grow icmp6_ifstat */
    308 		n = if_indexlim * sizeof(struct icmp6_ifstat *);
    309 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
    310 		bzero(q, n);
    311 		if (icmp6_ifstat) {
    312 			bcopy((caddr_t)icmp6_ifstat, q,
    313 				olim * sizeof(struct icmp6_ifstat *));
    314 			free((caddr_t)icmp6_ifstat, M_IFADDR);
    315 		}
    316 		icmp6_ifstat = (struct icmp6_ifstat **)q;
    317 		icmp6_ifstatmax = if_indexlim;
    318 	}
    319 
    320 	/*
    321 	 * To prevent to assign link-local address to PnP network
    322 	 * cards multiple times.
    323 	 * This is lengthy for P2P and LOOP but works.
    324 	 */
    325 	ifa = TAILQ_FIRST(&ifp->if_addrlist);
    326 	if (ifa != NULL) {
    327 		for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
    328 			if (ifa->ifa_addr->sa_family != AF_INET6)
    329 				continue;
    330 			if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
    331 				return;
    332 		}
    333 	} else {
    334 		TAILQ_INIT(&ifp->if_addrlist);
    335 	}
    336 
    337 	/*
    338 	 * link-local address
    339 	 */
    340 	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
    341 	bzero((caddr_t)ia, sizeof(*ia));
    342 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
    343 	if (ifp->if_flags & IFF_POINTOPOINT)
    344 		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
    345 	else
    346 		ia->ia_ifa.ifa_dstaddr = NULL;
    347 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
    348 	ia->ia_ifp = ifp;
    349 	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    350 	IFAREF((struct ifaddr *)ia);
    351 
    352 	/*
    353 	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
    354 	 * kazu opposed it, but itojun & jinmei wanted.
    355 	 */
    356 	if ((oia = in6_ifaddr) != NULL) {
    357 		for (; oia->ia_next; oia = oia->ia_next)
    358 			continue;
    359 		oia->ia_next = ia;
    360 	} else
    361 		in6_ifaddr = ia;
    362 	IFAREF((struct ifaddr *)ia);
    363 
    364 	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
    365 	ia->ia_prefixmask.sin6_family = AF_INET6;
    366 	ia->ia_prefixmask.sin6_addr = in6mask64;
    367 
    368 	bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
    369 	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
    370 	ia->ia_addr.sin6_family = AF_INET6;
    371 	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
    372 	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
    373 	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
    374 
    375 	switch (type) {
    376 	case IN6_IFT_LOOP:
    377 		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
    378 		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
    379 		break;
    380 	case IN6_IFT_802:
    381 		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
    382 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
    383 		rtflag = RTF_CLONING;
    384 		/* fall through */
    385 	case IN6_IFT_P2P802:
    386 		if (laddr == NULL)
    387 			break;
    388 		/* XXX use laddrlen */
    389 		if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
    390 				laddr, 6) != 0) {
    391 			break;
    392 		}
    393 		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
    394 		ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
    395 		if (found_first_ifid == 0)
    396 			in6_ifattach_getifid(ifp);
    397 		bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6));
    398 		ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
    399 		ia->ia_dstaddr.sin6_family = AF_INET6;
    400 		break;
    401 	case IN6_IFT_P2P:
    402 		bcopy((caddr_t)first_ifid,
    403 		      (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
    404 		      IFID_LEN);
    405 		bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6));
    406 		ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
    407 		ia->ia_dstaddr.sin6_family = AF_INET6;
    408 		break;
    409 	case IN6_IFT_ARCNET:
    410 		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
    411 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
    412 		rtflag = RTF_CLONING;
    413 		if (laddr == NULL)
    414 			break;
    415 
    416 		/* make non-global IF id out of link-level address */
    417 		bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7);
    418 		ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr;
    419 	}
    420 
    421 	ia->ia_ifa.ifa_metric = ifp->if_metric;
    422 
    423 	if (ifp->if_ioctl != NULL) {
    424 		int s;
    425 		int error;
    426 
    427 		/*
    428 		 * give the interface a chance to initialize, in case this
    429 		 * is the first address to be added.
    430 		 */
    431 		s = splimp();
    432 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
    433 		splx(s);
    434 
    435 		if (error) {
    436 			switch (error) {
    437 			case EAFNOSUPPORT:
    438 				printf("%s: IPv6 not supported\n",
    439 					if_name(ifp));
    440 				break;
    441 			default:
    442 				printf("%s: SIOCSIFADDR error %d\n",
    443 					if_name(ifp), error);
    444 				break;
    445 			}
    446 
    447 			/* undo changes */
    448 			TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    449 			IFAFREE(&ia->ia_ifa);
    450 			if (oia)
    451 				oia->ia_next = ia->ia_next;
    452 			else
    453 				in6_ifaddr = ia->ia_next;
    454 			IFAFREE(&ia->ia_ifa);
    455 			return;
    456 		}
    457 	}
    458 
    459 	/* add route to the interface. */
    460 	rtrequest(RTM_ADD,
    461 		  (struct sockaddr *)&ia->ia_addr,
    462 		  (struct sockaddr *)&ia->ia_addr,
    463 		  (struct sockaddr *)&ia->ia_prefixmask,
    464 		  RTF_UP|rtflag,
    465 		  (struct rtentry **)0);
    466 	ia->ia_flags |= IFA_ROUTE;
    467 
    468 	if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
    469 		/*
    470 		 * route local address to loopback
    471 		 */
    472 		bzero(&gate, sizeof(gate));
    473 		gate.sin6_len = sizeof(struct sockaddr_in6);
    474 		gate.sin6_family = AF_INET6;
    475 		gate.sin6_addr = in6addr_loopback;
    476 		bzero(&mask, sizeof(mask));
    477 		mask.sin6_len = sizeof(struct sockaddr_in6);
    478 		mask.sin6_family = AF_INET6;
    479 		mask.sin6_addr = in6mask64;
    480 		rtrequest(RTM_ADD,
    481 			  (struct sockaddr *)&ia->ia_addr,
    482 			  (struct sockaddr *)&gate,
    483 			  (struct sockaddr *)&mask,
    484 			  RTF_UP|RTF_HOST,
    485 			  (struct rtentry **)0);
    486 	}
    487 
    488 	/*
    489 	 * loopback address
    490 	 */
    491 	ib = (struct in6_ifaddr *)NULL;
    492 	if (type == IN6_IFT_LOOP) {
    493 		ib = (struct in6_ifaddr *)
    494 			malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
    495 		bzero((caddr_t)ib, sizeof(*ib));
    496 		ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
    497 		ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
    498 		ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
    499 		ib->ia_ifp = ifp;
    500 
    501 		ia->ia_next = ib;
    502 		TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
    503 			ifa_list);
    504 		IFAREF((struct ifaddr *)ib);
    505 
    506 		ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
    507 		ib->ia_prefixmask.sin6_family = AF_INET6;
    508 		ib->ia_prefixmask.sin6_addr = in6mask128;
    509 		ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
    510 		ib->ia_addr.sin6_family = AF_INET6;
    511 		ib->ia_addr.sin6_addr = in6addr_loopback;
    512 
    513 		/*
    514 		 * Always initialize ia_dstaddr (= broadcast address)
    515 		 * to loopback address, to make getifaddr happier.
    516 		 *
    517 		 * For BSDI, it is mandatory.  The BSDI version of
    518 		 * ifa_ifwithroute() rejects to add a route to the loopback
    519 		 * interface.  Even for other systems, loopback looks somewhat
    520 		 * special.
    521 		 */
    522 		ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
    523 		ib->ia_dstaddr.sin6_family = AF_INET6;
    524 		ib->ia_dstaddr.sin6_addr = in6addr_loopback;
    525 
    526 		ib->ia_ifa.ifa_metric = ifp->if_metric;
    527 
    528 		rtrequest(RTM_ADD,
    529 			  (struct sockaddr *)&ib->ia_addr,
    530 			  (struct sockaddr *)&ib->ia_addr,
    531 			  (struct sockaddr *)&ib->ia_prefixmask,
    532 			  RTF_UP|RTF_HOST,
    533 			  (struct rtentry **)0);
    534 
    535 		ib->ia_flags |= IFA_ROUTE;
    536 	}
    537 
    538 	/*
    539 	 * join multicast
    540 	 */
    541 	if (ifp->if_flags & IFF_MULTICAST) {
    542 		int error;	/* not used */
    543 
    544 		/* Restore saved multicast addresses(if any). */
    545 		in6_restoremkludge(ia, ifp);
    546 
    547 		bzero(&mltmask, sizeof(mltmask));
    548 		mltmask.sin6_len = sizeof(struct sockaddr_in6);
    549 		mltmask.sin6_family = AF_INET6;
    550 		mltmask.sin6_addr = in6mask32;
    551 
    552 		/*
    553 		 * join link-local all-nodes address
    554 		 */
    555 		bzero(&mltaddr, sizeof(mltaddr));
    556 		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
    557 		mltaddr.sin6_family = AF_INET6;
    558 		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
    559 		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
    560 		rtrequest(RTM_ADD,
    561 			  (struct sockaddr *)&mltaddr,
    562 			  (struct sockaddr *)&ia->ia_addr,
    563 			  (struct sockaddr *)&mltmask,
    564 			  RTF_UP|RTF_CLONING,  /* xxx */
    565 			  (struct rtentry **)0);
    566 		(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
    567 
    568 		if (type == IN6_IFT_LOOP) {
    569 			/*
    570 			 * join node-local all-nodes address
    571 			 */
    572 			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
    573 			rtrequest(RTM_ADD,
    574 				  (struct sockaddr *)&mltaddr,
    575 				  (struct sockaddr *)&ib->ia_addr,
    576 				  (struct sockaddr *)&mltmask,
    577 				  RTF_UP,
    578 				  (struct rtentry **)0);
    579 			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
    580 		} else {
    581 			/*
    582 			 * join solicited multicast address
    583 			 */
    584 			bzero(&llsol, sizeof(llsol));
    585 			llsol.s6_addr16[0] = htons(0xff02);
    586 			llsol.s6_addr16[1] = htons(ifp->if_index);
    587 			llsol.s6_addr32[1] = 0;
    588 			llsol.s6_addr32[2] = htonl(1);
    589 			llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
    590 			llsol.s6_addr8[12] = 0xff;
    591 			(void)in6_addmulti(&llsol, ifp, &error);
    592 		}
    593 	}
    594 
    595 	/* update dynamically. */
    596 	if (in6_maxmtu < ifp->if_mtu)
    597 		in6_maxmtu = ifp->if_mtu;
    598 
    599 	if (in6_ifstat[ifp->if_index] == NULL) {
    600 		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
    601 			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
    602 		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
    603 	}
    604 	if (icmp6_ifstat[ifp->if_index] == NULL) {
    605 		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
    606 			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
    607 		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
    608 	}
    609 
    610 	/* initialize NDP variables */
    611 	nd6_ifattach(ifp);
    612 
    613 	/* mark the address TENTATIVE, if needed. */
    614 	switch (ifp->if_type) {
    615 	case IFT_ARCNET:
    616 	case IFT_ETHER:
    617 	case IFT_FDDI:
    618 #if 0
    619 	case IFT_ATM:
    620 	case IFT_SLIP:
    621 	case IFT_PPP:
    622 #endif
    623 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
    624 		/* nd6_dad_start() will be called in in6_if_up */
    625 		break;
    626 	case IFT_GIF:	/*XXX*/
    627 	case IFT_LOOP:
    628 	case IFT_FAITH:
    629 	default:
    630 		break;
    631 	}
    632 
    633 	return;
    634 }
    635 
    636 /*
    637  * NOTE: in6_ifdetach() does not support loopback if at this moment.
    638  */
    639 void
    640 in6_ifdetach(ifp)
    641 	struct ifnet *ifp;
    642 {
    643 	struct in6_ifaddr *ia, *oia;
    644 	struct ifaddr *ifa;
    645 	struct rtentry *rt;
    646 	short rtflags;
    647 	struct sockaddr_in6 sin6;
    648 
    649 	/* nuke prefix list.  this may try to remove some of ifaddrs as well */
    650 	in6_purgeprefix(ifp);
    651 
    652 	/* remove neighbor management table */
    653 	nd6_purge(ifp);
    654 
    655 	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
    656 	{
    657 		if (ifa->ifa_addr->sa_family != AF_INET6
    658 		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
    659 			continue;
    660 		}
    661 
    662 		ia = (struct in6_ifaddr *)ifa;
    663 
    664 		/* remove from the routing table */
    665 		if ((ia->ia_flags & IFA_ROUTE)
    666 		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
    667 			rtflags = rt->rt_flags;
    668 			rtfree(rt);
    669 			rtrequest(RTM_DELETE,
    670 				(struct sockaddr *)&ia->ia_addr,
    671 				(struct sockaddr *)&ia->ia_addr,
    672 				(struct sockaddr *)&ia->ia_prefixmask,
    673 				rtflags, (struct rtentry **)0);
    674 		}
    675 
    676 		/* remove from the linked list */
    677 		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    678 
    679 		/* also remove from the IPv6 address chain(itojun&jinmei) */
    680 		oia = ia;
    681 		if (oia == (ia = in6_ifaddr))
    682 			in6_ifaddr = ia->ia_next;
    683 		else {
    684 			while (ia->ia_next && (ia->ia_next != oia))
    685 				ia = ia->ia_next;
    686 			if (ia->ia_next)
    687 				ia->ia_next = oia->ia_next;
    688 #ifdef DEBUG
    689 			else
    690 				printf("%s: didn't unlink in6ifaddr from "
    691 				    "list\n", if_name(ifp));
    692 #endif
    693 		}
    694 
    695 		free(ia, M_IFADDR);
    696 	}
    697 
    698 	/* cleanup multicast address kludge table, if there is any */
    699 	in6_purgemkludge(ifp);
    700 
    701 	/* remove route to link-local allnodes multicast (ff02::1) */
    702 	bzero(&sin6, sizeof(sin6));
    703 	sin6.sin6_len = sizeof(struct sockaddr_in6);
    704 	sin6.sin6_family = AF_INET6;
    705 	sin6.sin6_addr = in6addr_linklocal_allnodes;
    706 	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
    707 	if ((rt = rtalloc1((struct sockaddr *)&sin6, 0)) != NULL) {
    708 		rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
    709 			rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
    710 		rtfree(rt);
    711 	}
    712 }
    713