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