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