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