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