Home | History | Annotate | Line # | Download | only in netinet6
in6_ifattach.c revision 1.9
      1 /*	$NetBSD: in6_ifattach.c,v 1.9 1999/09/19 21:42:23 is 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 		break;
     79 	case 6:
     80 		dst[0] = src[0];
     81 		dst[1] = src[1];
     82 		dst[2] = src[2];
     83 		dst[3] = 0xff;
     84 		dst[4] = 0xfe;
     85 		dst[5] = src[3];
     86 		dst[6] = src[4];
     87 		dst[7] = src[5];
     88 		break;
     89 	case 8:
     90 		bcopy(src, dst, len);
     91 		break;
     92 	default:
     93 		return EINVAL;
     94 	}
     95 
     96 	return 0;
     97 }
     98 
     99 /*
    100  * Find first ifid on list of interfaces.
    101  * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
    102  * is globally unique.  We may need to have a flag parameter in the future.
    103  */
    104 int
    105 in6_ifattach_getifid(ifp0)
    106 	struct ifnet *ifp0;
    107 {
    108 	struct ifnet *ifp;
    109 	struct ifaddr *ifa;
    110 	u_int8_t *addr = NULL;
    111 	int addrlen = 0;
    112 	struct sockaddr_dl *sdl;
    113 
    114 	if (found_first_ifid)
    115 		return 0;
    116 
    117 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
    118 		if (ifp0 != NULL && ifp0 != ifp)
    119 			continue;
    120 		for (ifa = ifp->if_addrlist.tqh_first;
    121 		     ifa;
    122 		     ifa = ifa->ifa_list.tqe_next) {
    123 			if (ifa->ifa_addr->sa_family != AF_LINK)
    124 				continue;
    125 			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
    126 			if (sdl == NULL)
    127 				continue;
    128 			if (sdl->sdl_alen == 0)
    129 				continue;
    130 			switch (ifp->if_type) {
    131 			case IFT_ETHER:
    132 			case IFT_FDDI:
    133 			case IFT_ATM:
    134 			case IFT_ARCNET:
    135 			/* what others? */
    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 			default:
    147 				break;
    148 			}
    149 		}
    150 	}
    151 #ifdef DEBUG
    152 	printf("in6_ifattach_getifid: failed to get EUI64");
    153 #endif
    154 	return EADDRNOTAVAIL;
    155 
    156 found:
    157 	if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
    158 		found_first_ifid = 1;
    159 
    160 	if (found_first_ifid) {
    161 		printf("%s: supplying EUI64: "
    162 			"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
    163 			ifp->if_xname,
    164 			first_ifid[0] & 0xff, first_ifid[1] & 0xff,
    165 			first_ifid[2] & 0xff, first_ifid[3] & 0xff,
    166 			first_ifid[4] & 0xff, first_ifid[5] & 0xff,
    167 			first_ifid[6] & 0xff, first_ifid[7] & 0xff);
    168 
    169 		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
    170 		first_ifid[0] ^= 0x02;
    171 
    172 		return 0;
    173 	} else {
    174 #ifdef DEBUG
    175 		printf("in6_ifattach_getifid: failed to get EUI64");
    176 #endif
    177 		return EADDRNOTAVAIL;
    178 	}
    179 }
    180 
    181 /*
    182  * add link-local address to *pseudo* p2p interfaces.
    183  * get called when the first MAC address is made available in in6_ifattach().
    184  *
    185  * XXX I start feeling this as a bad idea. (itojun)
    186  */
    187 void
    188 in6_ifattach_p2p()
    189 {
    190 	struct ifnet *ifp;
    191 
    192 	/* prevent infinite loop. just in case. */
    193 	if (found_first_ifid == 0)
    194 		return;
    195 
    196 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
    197 		switch (ifp->if_type) {
    198 		case IFT_GIF:
    199 			/* pseudo interfaces - safe to initialize here */
    200 			in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
    201 			break;
    202 		case IFT_FAITH:
    203 			/* this mistakingly becomes IFF_UP */
    204 			break;
    205 		case IFT_SLIP:
    206 			/* IPv6 is not supported */
    207 			break;
    208 		case IFT_PPP:
    209 			/* this is not a pseudo interface, skip it */
    210 			break;
    211 		default:
    212 			break;
    213 		}
    214 	}
    215 }
    216 
    217 void
    218 in6_ifattach(ifp, type, laddr, noloop)
    219 	struct ifnet *ifp;
    220 	u_int type;
    221 	caddr_t laddr;
    222 	/* size_t laddrlen; */
    223 	int noloop;
    224 {
    225 	static size_t if_indexlim = 8;
    226 	struct sockaddr_in6 mltaddr;
    227 	struct sockaddr_in6 mltmask;
    228 	struct sockaddr_in6 gate;
    229 	struct sockaddr_in6 mask;
    230 
    231 	struct in6_ifaddr *ia, *ib, *oia;
    232 	struct ifaddr *ifa;
    233 	int rtflag = 0;
    234 
    235 	if (type == IN6_IFT_P2P && found_first_ifid == 0) {
    236 		printf("%s: no ifid available for IPv6 link-local address\n",
    237 			ifp->if_xname);
    238 		return;
    239 	}
    240 
    241 	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
    242 		printf("%s: not multicast capable, IPv6 not enabled\n",
    243 			ifp->if_xname);
    244 		return;
    245 	}
    246 
    247 	/*
    248 	 * We have some arrays that should be indexed by if_index.
    249 	 * since if_index will grow dynamically, they should grow too.
    250 	 *	struct in6_addr **in6_iflladdr
    251 	 */
    252 	if (in6_iflladdr == NULL || if_index >= if_indexlim) {
    253 		size_t n;
    254 		caddr_t q;
    255 		size_t olim;
    256 
    257 		olim = if_indexlim;
    258 		while (if_index >= if_indexlim)
    259 			if_indexlim <<= 1;
    260 
    261 		/* grow in6_iflladdr */
    262 		n = if_indexlim * sizeof(struct in6_addr *);
    263 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
    264 		bzero(q, n);
    265 		if (in6_iflladdr) {
    266 			bcopy((caddr_t)in6_iflladdr, q,
    267 				olim * sizeof(struct in6_addr *));
    268 			free((caddr_t)in6_iflladdr, M_IFADDR);
    269 		}
    270 		in6_iflladdr = (struct in6_addr **)q;
    271 	}
    272 
    273 	/*
    274 	 * To prevent to assign link-local address to PnP network
    275 	 * cards multiple times.
    276 	 * This is lengthy for P2P and LOOP but works.
    277 	 */
    278 	ifa = TAILQ_FIRST(&ifp->if_addrlist);
    279 	if (ifa != NULL) {
    280 		for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
    281 			if (ifa->ifa_addr->sa_family != AF_INET6)
    282 				continue;
    283 			if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
    284 				return;
    285 		}
    286 	} else {
    287 		TAILQ_INIT(&ifp->if_addrlist);
    288 	}
    289 
    290 	/*
    291 	 * link-local address
    292 	 */
    293 	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
    294 	bzero((caddr_t)ia, sizeof(*ia));
    295 	ia->ia_ifa.ifa_addr =    (struct sockaddr *)&ia->ia_addr;
    296 	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
    297 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
    298 	ia->ia_ifp = ifp;
    299 	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    300 	/*
    301 	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
    302 	 * kazu opposed it, but itojun & jinmei wanted.
    303 	 */
    304 	if ((oia = in6_ifaddr) != NULL) {
    305 		for (; oia->ia_next; oia = oia->ia_next)
    306 			continue;
    307 		oia->ia_next = ia;
    308 	} else
    309 		in6_ifaddr = ia;
    310 
    311 	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
    312 	ia->ia_prefixmask.sin6_family = AF_INET6;
    313 	ia->ia_prefixmask.sin6_addr = in6mask64;
    314 
    315 	bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
    316 	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
    317 	ia->ia_addr.sin6_family = AF_INET6;
    318 	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
    319 	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
    320 	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
    321 
    322 	switch (type) {
    323 	case IN6_IFT_LOOP:
    324 		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
    325 		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
    326 		break;
    327 	case IN6_IFT_802:
    328 		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
    329 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
    330 		rtflag = RTF_CLONING;
    331 		/* fall through */
    332 	case IN6_IFT_P2P802:
    333 		if (laddr == NULL)
    334 			break;
    335 		/* XXX use laddrlen */
    336 		if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
    337 				laddr, 6) != 0) {
    338 			break;
    339 		}
    340 		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
    341 		ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
    342 		if (found_first_ifid == 0) {
    343 			if (in6_ifattach_getifid(ifp) == 0)
    344 				in6_ifattach_p2p();
    345 		}
    346 		break;
    347 	case IN6_IFT_P2P:
    348 		bcopy((caddr_t)first_ifid,
    349 		      (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
    350 		      IFID_LEN);
    351 		break;
    352 	case IN6_IFT_ARCNET:
    353 		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
    354 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
    355 		rtflag = RTF_CLONING;
    356 		if (laddr == NULL)
    357 			break;
    358 		if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
    359 				laddr, 1) != 0) {
    360 			break;
    361 		}
    362 	}
    363 
    364 	ia->ia_ifa.ifa_metric = ifp->if_metric;
    365 
    366 	if (ifp->if_ioctl != NULL) {
    367 		int s;
    368 		int error;
    369 
    370 		/*
    371 		 * give the interface a chance to initialize, in case this
    372 		 * is the first address to be added.
    373 		 */
    374 		s = splimp();
    375 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
    376 		splx(s);
    377 
    378 		if (error) {
    379 			switch (error) {
    380 			case EAFNOSUPPORT:
    381 				printf("%s: IPv6 not supported\n",
    382 					ifp->if_xname);
    383 				break;
    384 			default:
    385 				printf("%s: SIOCSIFADDR error %d\n",
    386 					ifp->if_xname, error);
    387 				break;
    388 			}
    389 
    390 			/* undo changes */
    391 			TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    392 			if (oia)
    393 				oia->ia_next = ia->ia_next;
    394 			else
    395 				in6_ifaddr = ia->ia_next;
    396 			free(ia, M_IFADDR);
    397 			return;
    398 		}
    399 	}
    400 
    401 	/* add route to the interface. */
    402 	rtrequest(RTM_ADD,
    403 		  (struct sockaddr *)&ia->ia_addr,
    404 		  (struct sockaddr *)&ia->ia_addr,
    405 		  (struct sockaddr *)&ia->ia_prefixmask,
    406 		  RTF_UP|rtflag,
    407 		  (struct rtentry **)0);
    408 	ia->ia_flags |= IFA_ROUTE;
    409 
    410 	if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
    411 		/*
    412 		 * route local address to loopback
    413 		 */
    414 		bzero(&gate, sizeof(gate));
    415 		gate.sin6_len = sizeof(struct sockaddr_in6);
    416 		gate.sin6_family = AF_INET6;
    417 		gate.sin6_addr = in6addr_loopback;
    418 		bzero(&mask, sizeof(mask));
    419 		mask.sin6_len = sizeof(struct sockaddr_in6);
    420 		mask.sin6_family = AF_INET6;
    421 		mask.sin6_addr = in6mask64;
    422 		rtrequest(RTM_ADD,
    423 			  (struct sockaddr *)&ia->ia_addr,
    424 			  (struct sockaddr *)&gate,
    425 			  (struct sockaddr *)&mask,
    426 			  RTF_UP|RTF_HOST,
    427 			  (struct rtentry **)0);
    428 	}
    429 
    430 	/*
    431 	 * loopback address
    432 	 */
    433 	ib = (struct in6_ifaddr *)NULL;
    434 	if (type == IN6_IFT_LOOP) {
    435 		ib = (struct in6_ifaddr *)
    436 			malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
    437 		bzero((caddr_t)ib, sizeof(*ib));
    438 		ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
    439 		ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
    440 		ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
    441 		ib->ia_ifp = ifp;
    442 
    443 		ia->ia_next = ib;
    444 		TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
    445 			ifa_list);
    446 
    447 		ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
    448 		ib->ia_prefixmask.sin6_family = AF_INET6;
    449 		ib->ia_prefixmask.sin6_addr = in6mask128;
    450 		ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
    451 		ib->ia_addr.sin6_family = AF_INET6;
    452 		ib->ia_addr.sin6_addr = in6addr_loopback;
    453 #ifdef __bsdi__
    454 		/*
    455 		 * It is necessary to set the loopback address to the dstaddr
    456 		 * field at least for BSDI. Without this setting, the BSDI
    457 		 * version of ifa_ifwithroute() rejects to add a route
    458 		 * to the loopback interface.
    459 		 */
    460 		ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
    461 		ib->ia_dstaddr.sin6_family = AF_INET6;
    462 		ib->ia_dstaddr.sin6_addr = in6addr_loopback;
    463 #endif /* __bsdi__ */
    464 
    465 		ib->ia_ifa.ifa_metric = ifp->if_metric;
    466 
    467 		rtrequest(RTM_ADD,
    468 			  (struct sockaddr *)&ib->ia_addr,
    469 			  (struct sockaddr *)&ib->ia_addr,
    470 			  (struct sockaddr *)&ib->ia_prefixmask,
    471 			  RTF_UP|RTF_HOST,
    472 			  (struct rtentry **)0);
    473 
    474 		ib->ia_flags |= IFA_ROUTE;
    475 	}
    476 
    477 	/*
    478 	 * join multicast
    479 	 */
    480 	if (ifp->if_flags & IFF_MULTICAST) {
    481 		int error;	/* not used */
    482 
    483 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
    484 		/* Restore saved multicast addresses(if any). */
    485 		in6_restoremkludge(ia, ifp);
    486 #endif
    487 
    488 		bzero(&mltmask, sizeof(mltmask));
    489 		mltmask.sin6_len = sizeof(struct sockaddr_in6);
    490 		mltmask.sin6_family = AF_INET6;
    491 		mltmask.sin6_addr = in6mask32;
    492 
    493 		/*
    494 		 * join link-local all-nodes address
    495 		 */
    496 		bzero(&mltaddr, sizeof(mltaddr));
    497 		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
    498 		mltaddr.sin6_family = AF_INET6;
    499 		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
    500 		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
    501 		rtrequest(RTM_ADD,
    502 			  (struct sockaddr *)&mltaddr,
    503 			  (struct sockaddr *)&ia->ia_addr,
    504 			  (struct sockaddr *)&mltmask,
    505 			  RTF_UP|RTF_CLONING,  /* xxx */
    506 			  (struct rtentry **)0);
    507 		(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
    508 
    509 		if (type == IN6_IFT_LOOP) {
    510 			/*
    511 			 * join node-local all-nodes address
    512 			 */
    513 			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
    514 			rtrequest(RTM_ADD,
    515 				  (struct sockaddr *)&mltaddr,
    516 				  (struct sockaddr *)&ib->ia_addr,
    517 				  (struct sockaddr *)&mltmask,
    518 				  RTF_UP,
    519 				  (struct rtentry **)0);
    520 			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
    521 		} else {
    522 			/*
    523 			 * join solicited multicast address
    524 			 */
    525 			bzero(&llsol, sizeof(llsol));
    526 			llsol.s6_addr16[0] = htons(0xff02);
    527 			llsol.s6_addr16[1] = htons(ifp->if_index);
    528 			llsol.s6_addr32[1] = 0;
    529 			llsol.s6_addr32[2] = htonl(1);
    530 			llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
    531 			llsol.s6_addr8[12] = 0xff;
    532 			(void)in6_addmulti(&llsol, ifp, &error);
    533 		}
    534 	}
    535 
    536 	/* update dynamically. */
    537 	in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr;
    538 	if (in6_maxmtu < ifp->if_mtu)
    539 		in6_maxmtu = ifp->if_mtu;
    540 
    541 	/* initialize NDP variables */
    542 	nd6_ifattach(ifp);
    543 
    544 	/* mark the address TENTATIVE, if needed. */
    545 	switch (ifp->if_type) {
    546 	case IFT_ARCNET:
    547 	case IFT_ETHER:
    548 	case IFT_FDDI:
    549 #if 0
    550 	case IFT_ATM:
    551 	case IFT_SLIP:
    552 	case IFT_PPP:
    553 #endif
    554 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
    555 		/* nd6_dad_start() will be called in in6_if_up */
    556 		break;
    557 	case IFT_GIF:
    558 	case IFT_LOOP:
    559 	case IFT_FAITH:
    560 	default:
    561 		break;
    562 	}
    563 
    564 	return;
    565 }
    566 
    567 void
    568 in6_ifdetach(ifp)
    569 	struct ifnet *ifp;
    570 {
    571 	struct in6_ifaddr *ia, *oia;
    572 	struct ifaddr *ifa;
    573 	struct rtentry *rt;
    574 	short rtflags;
    575 
    576 	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
    577 		if (ifa->ifa_addr->sa_family != AF_INET6
    578 		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
    579 			continue;
    580 		}
    581 
    582 		ia = (struct in6_ifaddr *)ifa;
    583 
    584 		/* remove from the routing table */
    585 		if ((ia->ia_flags & IFA_ROUTE)
    586 		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
    587 			rtflags = rt->rt_flags;
    588 			rtfree(rt);
    589 			rtrequest(RTM_DELETE,
    590 				(struct sockaddr *)&ia->ia_addr,
    591 				(struct sockaddr *)&ia->ia_addr,
    592 				(struct sockaddr *)&ia->ia_prefixmask,
    593 				rtflags, (struct rtentry **)0);
    594 		}
    595 
    596 		/* remove from the linked list */
    597 		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
    598 
    599 		/* also remove from the IPv6 address chain(itojun&jinmei) */
    600 		oia = ia;
    601 		if (oia == (ia = in6_ifaddr))
    602 			in6_ifaddr = ia->ia_next;
    603 		else {
    604 			while (ia->ia_next && (ia->ia_next != oia))
    605 				ia = ia->ia_next;
    606 			if (ia->ia_next)
    607 				ia->ia_next = oia->ia_next;
    608 #ifdef DEBUG
    609 			else
    610 				printf("%s: didn't unlink in6ifaddr from "
    611 				    "list\n", ifp->if_xname);
    612 #endif
    613 		}
    614 
    615 		free(ia, M_IFADDR);
    616 	}
    617 }
    618