1 /* $NetBSD: in6_ifattach.c,v 1.122 2024/04/11 07:34:37 knakahara Exp $ */
2 /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.122 2024/04/11 07:34:37 knakahara Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kmem.h>
39 #include <sys/socket.h>
40 #include <sys/sockio.h>
41 #include <sys/kernel.h>
42 #include <sys/syslog.h>
43 #include <sys/md5.h>
44 #include <sys/socketvar.h>
45 #include <sys/cprng.h>
46
47 #include <net/if.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
50 #include <net/route.h>
51
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54
55 #include <netinet/ip6.h>
56 #include <netinet6/in6_ifattach.h>
57 #include <netinet6/ip6_var.h>
58 #include <netinet6/nd6.h>
59 #include <netinet6/ip6_mroute.h>
60 #include <netinet6/scope6_var.h>
61
62 int ip6_auto_linklocal = 1; /* enable by default */
63
64 #if 0
65 static int get_hostid_ifid(struct ifnet *, struct in6_addr *);
66 #endif
67 static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
68 static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
69 static int in6_ifattach_loopback(struct ifnet *);
70
71 #define EUI64_GBIT 0x01
72 #define EUI64_UBIT 0x02
73 #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (/*CONSTCOND*/ 0)
74 #define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
75 #define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
76 #define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
77 #define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
78
79 #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
80 #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
81
82 #if 0
83 /*
84 * Generate a last-resort interface identifier from hostid.
85 * works only for certain architectures (like sparc).
86 * also, using hostid itself may constitute a privacy threat, much worse
87 * than MAC addresses (hostids are used for software licensing).
88 * maybe we should use MD5(hostid) instead.
89 *
90 * in6 - upper 64bits are preserved
91 */
92 static int
93 get_hostid_ifid(struct ifnet *ifp, struct in6_addr *in6)
94 {
95 int off, len;
96 static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
97 static const uint8_t allone[8] =
98 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
99
100 if (!hostid)
101 return -1;
102
103 /* get up to 8 bytes from the hostid field - should we get */
104 len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid);
105 off = sizeof(*in6) - len;
106 memcpy(&in6->s6_addr[off], &hostid, len);
107
108 /* make sure we do not return anything bogus */
109 if (memcmp(&in6->s6_addr[8], allzero, sizeof(allzero)))
110 return -1;
111 if (memcmp(&in6->s6_addr[8], allone, sizeof(allone)))
112 return -1;
113
114 /* make sure to set "u" bit to local, and "g" bit to individual. */
115 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
116 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
117
118 /* convert EUI64 into IPv6 interface identifier */
119 EUI64_TO_IFID(in6);
120
121 return 0;
122 }
123 #endif
124
125 /*
126 * Generate a last-resort interface identifier, when the machine has no
127 * IEEE802/EUI64 address sources.
128 * The goal here is to get an interface identifier that is
129 * (1) random enough and (2) does not change across reboot.
130 * We currently use MD5(hostname) for it.
131 */
132 static int
get_rand_ifid(struct in6_addr * in6)133 get_rand_ifid(struct in6_addr *in6) /* upper 64bits are preserved */
134 {
135 MD5_CTX ctxt;
136 u_int8_t digest[16];
137
138 #if 0
139 /* we need at least several letters as seed for ifid */
140 if (hostnamelen < 3)
141 return -1;
142 #endif
143
144 /* generate 8 bytes of pseudo-random value. */
145 memset(&ctxt, 0, sizeof(ctxt));
146 MD5Init(&ctxt);
147 MD5Update(&ctxt, (u_char *)hostname, hostnamelen);
148 MD5Final(digest, &ctxt);
149
150 /* assumes sizeof(digest) > sizeof(ifid) */
151 memcpy(&in6->s6_addr[8], digest, 8);
152
153 /* make sure to set "u" bit to local, and "g" bit to individual. */
154 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
155 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
156
157 /* convert EUI64 into IPv6 interface identifier */
158 EUI64_TO_IFID(in6);
159
160 return 0;
161 }
162
163 /*
164 * Get interface identifier for the specified interface.
165 *
166 * in6 - upper 64bits are preserved
167 */
168 int
in6_get_hw_ifid(struct ifnet * ifp,struct in6_addr * in6)169 in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
170 {
171 struct ifaddr *ifa;
172 const struct sockaddr_dl *sdl = NULL;
173 const char *addr = NULL; /* XXX gcc 4.8 -Werror=maybe-uninitialized */
174 size_t addrlen = 0; /* XXX gcc 4.8 -Werror=maybe-uninitialized */
175 static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
176 static u_int8_t allone[8] =
177 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
178 int s;
179
180 s = pserialize_read_enter();
181 IFADDR_READER_FOREACH(ifa, ifp) {
182 const struct sockaddr_dl *tsdl;
183 if (ifa->ifa_addr->sa_family != AF_LINK)
184 continue;
185 tsdl = satocsdl(ifa->ifa_addr);
186 if (tsdl == NULL || tsdl->sdl_alen == 0)
187 continue;
188 if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl) {
189 sdl = tsdl;
190 addr = CLLADDR(sdl);
191 addrlen = sdl->sdl_alen;
192 }
193 if (ifa == ifp->if_hwdl)
194 break;
195 }
196 pserialize_read_exit(s);
197
198 if (sdl == NULL)
199 return -1;
200
201 switch (ifp->if_type) {
202 case IFT_IEEE1394:
203 case IFT_IEEE80211:
204 /* IEEE1394 uses 16byte length address starting with EUI64 */
205 if (addrlen > 8)
206 addrlen = 8;
207 break;
208 default:
209 break;
210 }
211
212 /* get EUI64 */
213 switch (ifp->if_type) {
214 /* IEEE802/EUI64 cases - what others? */
215 case IFT_ETHER:
216 case IFT_ATM:
217 case IFT_IEEE1394:
218 case IFT_IEEE80211:
219 /* look at IEEE802/EUI64 only */
220 if (addrlen != 8 && addrlen != 6)
221 return -1;
222
223 /*
224 * check for invalid MAC address - on bsdi, we see it a lot
225 * since wildboar configures all-zero MAC on pccard before
226 * card insertion.
227 */
228 if (memcmp(addr, allzero, addrlen) == 0)
229 return -1;
230 if (memcmp(addr, allone, addrlen) == 0)
231 return -1;
232
233 /* make EUI64 address */
234 if (addrlen == 8)
235 memcpy(&in6->s6_addr[8], addr, 8);
236 else if (addrlen == 6) {
237 in6->s6_addr[8] = addr[0];
238 in6->s6_addr[9] = addr[1];
239 in6->s6_addr[10] = addr[2];
240 in6->s6_addr[11] = 0xff;
241 in6->s6_addr[12] = 0xfe;
242 in6->s6_addr[13] = addr[3];
243 in6->s6_addr[14] = addr[4];
244 in6->s6_addr[15] = addr[5];
245 }
246 break;
247
248 case IFT_ARCNET:
249 if (addrlen != 1)
250 return -1;
251 if (!addr[0])
252 return -1;
253
254 memset(&in6->s6_addr[8], 0, 8);
255 in6->s6_addr[15] = addr[0];
256
257 /*
258 * due to insufficient bitwidth, we mark it local.
259 */
260 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
261 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
262 break;
263
264 case IFT_GIF:
265 case IFT_IPSEC:
266 #ifdef IFT_STF
267 case IFT_STF:
268 #endif
269 /*
270 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
271 * however, IPv4 address is not very suitable as unique
272 * identifier source (can be renumbered).
273 * we don't do this.
274 */
275 return -1;
276
277 default:
278 return -1;
279 }
280
281 /* sanity check: g bit must not indicate "group" */
282 if (EUI64_GROUP(in6))
283 return -1;
284
285 /* convert EUI64 into IPv6 interface identifier */
286 EUI64_TO_IFID(in6);
287
288 /*
289 * sanity check: ifid must not be all zero, avoid conflict with
290 * subnet router anycast
291 */
292 if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
293 memcmp(&in6->s6_addr[9], allzero, 7) == 0) {
294 return -1;
295 }
296
297 return 0;
298 }
299
300 /*
301 * Get interface identifier for the specified interface. If it is not
302 * available on ifp0, borrow interface identifier from other information
303 * sources.
304 *
305 * altifp - secondary EUI64 source
306 */
307 static int
get_ifid(struct ifnet * ifp0,struct ifnet * altifp,struct in6_addr * in6)308 get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
309 struct in6_addr *in6)
310 {
311 struct ifnet *ifp;
312 int s;
313
314 /* first, try to get it from the interface itself */
315 if (in6_get_hw_ifid(ifp0, in6) == 0) {
316 nd6log(LOG_DEBUG, "%s: got interface identifier from itself\n",
317 if_name(ifp0));
318 goto success;
319 }
320
321 /* try secondary EUI64 source. this basically is for ATM PVC */
322 if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
323 nd6log(LOG_DEBUG, "%s: got interface identifier from %s\n",
324 if_name(ifp0), if_name(altifp));
325 goto success;
326 }
327
328 /* next, try to get it from some other hardware interface */
329 s = pserialize_read_enter();
330 IFNET_READER_FOREACH(ifp) {
331 if (ifp == ifp0)
332 continue;
333 if (in6_get_hw_ifid(ifp, in6) != 0)
334 continue;
335
336 /*
337 * to borrow ifid from other interface, ifid needs to be
338 * globally unique
339 */
340 if (IFID_UNIVERSAL(in6)) {
341 nd6log(LOG_DEBUG,
342 "%s: borrow interface identifier from %s\n",
343 if_name(ifp0), if_name(ifp));
344 pserialize_read_exit(s);
345 goto success;
346 }
347 }
348 pserialize_read_exit(s);
349
350 #if 0
351 /* get from hostid - only for certain architectures */
352 if (get_hostid_ifid(ifp, in6) == 0) {
353 nd6log(LOG_DEBUG,
354 "%s: interface identifier generated by hostid\n",
355 if_name(ifp0));
356 goto success;
357 }
358 #endif
359
360 /* last resort: get from random number source */
361 if (get_rand_ifid(in6) == 0) {
362 nd6log(LOG_DEBUG,
363 "%s: interface identifier generated by random number\n",
364 if_name(ifp0));
365 goto success;
366 }
367
368 printf("%s: failed to get interface identifier\n", if_name(ifp0));
369 return -1;
370
371 success:
372 nd6log(LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
373 if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
374 in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
375 in6->s6_addr[14], in6->s6_addr[15]);
376 return 0;
377 }
378
379 /*
380 * altifp - secondary EUI64 source
381 */
382
383 static int
in6_ifattach_linklocal(struct ifnet * ifp,struct ifnet * altifp)384 in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
385 {
386 struct in6_aliasreq ifra;
387 int error;
388
389 /*
390 * configure link-local address.
391 */
392 memset(&ifra, 0, sizeof(ifra));
393
394 /*
395 * in6_update_ifa() does not use ifra_name, but we accurately set it
396 * for safety.
397 */
398 strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
399
400 ifra.ifra_addr.sin6_family = AF_INET6;
401 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
402 ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
403 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
404 if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
405 ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
406 ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
407 } else {
408 if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
409 nd6log(LOG_ERR,
410 "%s: no ifid available\n", if_name(ifp));
411 return -1;
412 }
413 }
414 if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
415 return -1;
416
417 sockaddr_in6_init(&ifra.ifra_prefixmask, &in6mask64, 0, 0, 0);
418 /* link-local addresses should NEVER expire. */
419 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
420 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
421
422 /*
423 * Now call in6_update_ifa() to do a bunch of procedures to configure
424 * a link-local address. We can set the 3rd argument to NULL, because
425 * we know there's no other link-local address on the interface
426 * and therefore we are adding one (instead of updating one).
427 */
428 if ((error = in6_update_ifa(ifp, &ifra, IN6_IFAUPDATE_DADDELAY)) != 0) {
429 /*
430 * XXX: When the interface does not support IPv6, this call
431 * would fail in the SIOCINITIFADDR ioctl. I believe the
432 * notification is rather confusing in this case, so just
433 * suppress it. (jinmei@kame.net 20010130)
434 */
435 if (error != EAFNOSUPPORT)
436 nd6log(LOG_NOTICE,
437 "failed to configure a link-local address on %s "
438 "(errno=%d)\n",
439 if_name(ifp), error);
440 return -1;
441 }
442
443 return 0;
444 }
445
446 /*
447 * ifp - must be IFT_LOOP
448 */
449
450 static int
in6_ifattach_loopback(struct ifnet * ifp)451 in6_ifattach_loopback(struct ifnet *ifp)
452 {
453 struct in6_aliasreq ifra;
454 int error;
455
456 memset(&ifra, 0, sizeof(ifra));
457
458 /*
459 * in6_update_ifa() does not use ifra_name, but we accurately set it
460 * for safety.
461 */
462 strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
463
464 sockaddr_in6_init(&ifra.ifra_prefixmask, &in6mask128, 0, 0, 0);
465
466 /*
467 * Always initialize ia_dstaddr (= broadcast address) to loopback
468 * address. Follows IPv4 practice - see in_ifinit().
469 */
470 sockaddr_in6_init(&ifra.ifra_dstaddr, &in6addr_loopback, 0, 0, 0);
471
472 sockaddr_in6_init(&ifra.ifra_addr, &in6addr_loopback, 0, 0, 0);
473
474 /* the loopback address should NEVER expire. */
475 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
476 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
477
478 /* we don't need to perform DAD on loopback interfaces. */
479 ifra.ifra_flags |= IN6_IFF_NODAD;
480
481 /*
482 * We are sure that this is a newly assigned address, so we can set
483 * NULL to the 3rd arg.
484 */
485 if ((error = in6_update_ifa(ifp, &ifra, 0)) != 0) {
486 nd6log(LOG_ERR, "failed to configure "
487 "the loopback address on %s (errno=%d)\n",
488 if_name(ifp), error);
489 return -1;
490 }
491
492 return 0;
493 }
494
495 /*
496 * compute NI group address, based on the current hostname setting.
497 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
498 *
499 * when ifp == NULL, the caller is responsible for filling scopeid.
500 */
501 int
in6_nigroup(struct ifnet * ifp,const char * name,int namelen,struct sockaddr_in6 * sa6)502 in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
503 struct sockaddr_in6 *sa6)
504 {
505 const char *p;
506 u_int8_t *q;
507 MD5_CTX ctxt;
508 u_int8_t digest[16];
509 u_int8_t l;
510 u_int8_t n[64]; /* a single label must not exceed 63 chars */
511
512 if (!namelen || !name)
513 return -1;
514
515 p = name;
516 while (p && *p && *p != '.' && p - name < namelen)
517 p++;
518 if (p - name > sizeof(n) - 1)
519 return -1; /* label too long */
520 l = p - name;
521 strncpy((char *)n, name, l);
522 n[(int)l] = '\0';
523 for (q = n; *q; q++) {
524 if ('A' <= *q && *q <= 'Z')
525 *q = *q - 'A' + 'a';
526 }
527
528 /* generate 8 bytes of pseudo-random value. */
529 memset(&ctxt, 0, sizeof(ctxt));
530 MD5Init(&ctxt);
531 MD5Update(&ctxt, &l, sizeof(l));
532 MD5Update(&ctxt, n, l);
533 MD5Final(digest, &ctxt);
534
535 memset(sa6, 0, sizeof(*sa6));
536 sa6->sin6_family = AF_INET6;
537 sa6->sin6_len = sizeof(*sa6);
538 sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
539 sa6->sin6_addr.s6_addr8[11] = 2;
540 memcpy(&sa6->sin6_addr.s6_addr32[3], digest,
541 sizeof(sa6->sin6_addr.s6_addr32[3]));
542 if (in6_setscope(&sa6->sin6_addr, ifp, NULL))
543 return -1; /* XXX: should not fail */
544
545 return 0;
546 }
547
548 /*
549 * XXX multiple loopback interface needs more care. for instance,
550 * nodelocal address needs to be configured onto only one of them.
551 * XXX multiple link-local address case
552 *
553 * altifp - secondary EUI64 source
554 */
555 void
in6_ifattach(struct ifnet * ifp,struct ifnet * altifp)556 in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
557 {
558 struct in6_ifaddr *ia;
559 struct in6_addr in6;
560
561 KASSERT(IFNET_LOCKED(ifp));
562
563 /* some of the interfaces are inherently not IPv6 capable */
564 switch (ifp->if_type) {
565 case IFT_BRIDGE:
566 case IFT_L2TP:
567 case IFT_IEEE8023ADLAG:
568 #ifdef IFT_PFLOG
569 case IFT_PFLOG:
570 #endif
571 #ifdef IFT_PFSYNC
572 case IFT_PFSYNC:
573 #endif
574 ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
575 ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
576 return;
577 }
578
579 /*
580 * if link mtu is too small, don't try to configure IPv6.
581 * remember there could be some link-layer that has special
582 * fragmentation logic.
583 */
584 if (ifp->if_mtu < IPV6_MMTU) {
585 nd6log(LOG_INFO, "%s has too small MTU, IPv6 not enabled\n",
586 if_name(ifp));
587 return;
588 }
589
590 /*
591 * quirks based on interface type
592 */
593 switch (ifp->if_type) {
594 #ifdef IFT_STF
595 case IFT_STF:
596 /*
597 * 6to4 interface is a very special kind of beast.
598 * no multicast, no linklocal. RFC2529 specifies how to make
599 * linklocals for 6to4 interface, but there's no use and
600 * it is rather harmful to have one.
601 */
602 ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
603 return;
604 #endif
605 case IFT_CARP:
606 return;
607 default:
608 break;
609 }
610
611 /*
612 * usually, we require multicast capability to the interface
613 */
614 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
615 nd6log(LOG_INFO,
616 "%s is not multicast capable, IPv6 not enabled\n",
617 if_name(ifp));
618 return;
619 }
620
621 /*
622 * assign loopback address for loopback interface.
623 * XXX multiple loopback interface case.
624 */
625 if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
626 in6 = in6addr_loopback;
627 /* These are safe and atomic thanks to IFNET_LOCK */
628 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
629 if (in6_ifattach_loopback(ifp) != 0)
630 return;
631 }
632 }
633
634 /*
635 * assign a link-local address, if there's none.
636 */
637 if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
638 ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
639 int bound = curlwp_bind();
640 struct psref psref;
641 ia = in6ifa_ifpforlinklocal_psref(ifp, 0, &psref);
642 if (ia == NULL && in6_ifattach_linklocal(ifp, altifp) != 0) {
643 printf("%s: cannot assign link-local address\n",
644 ifp->if_xname);
645 }
646 ia6_release(ia, &psref);
647 curlwp_bindx(bound);
648 }
649 }
650
651 /*
652 * NOTE: in6_ifdetach() does not support loopback if at this moment.
653 * We don't need this function in bsdi, because interfaces are never removed
654 * from the ifnet list in bsdi.
655 */
656 void
in6_ifdetach(struct ifnet * ifp)657 in6_ifdetach(struct ifnet *ifp)
658 {
659
660 /* nuke any of IPv6 addresses we have */
661 if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr);
662
663 in6_purge_multi(ifp);
664
665 /* remove ip6_mrouter stuff */
666 ip6_mrouter_detach(ifp);
667
668 /* remove neighbor management table */
669 nd6_purge(ifp, NULL);
670 }
671