Annotation of sys/netinet6/in6_ifattach.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: in6_ifattach.c,v 1.45 2007/06/08 09:31:38 henning 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/param.h>
34: #include <sys/systm.h>
35: #include <sys/malloc.h>
36: #include <sys/socket.h>
37: #include <sys/sockio.h>
38: #include <sys/kernel.h>
39: #include <sys/syslog.h>
40:
41: #include <crypto/md5.h>
42:
43: #include <net/if.h>
44: #include <net/if_dl.h>
45: #include <net/if_types.h>
46: #include <net/route.h>
47:
48: #include <netinet/in.h>
49: #include <netinet/in_var.h>
50: #include <netinet/if_ether.h>
51:
52: #include <netinet/ip6.h>
53: #include <netinet6/ip6_var.h>
54: #include <netinet6/in6_ifattach.h>
55: #include <netinet6/ip6_var.h>
56: #include <netinet6/nd6.h>
57: #ifdef MROUTING
58: #include <netinet6/ip6_mroute.h>
59: #endif
60:
61: unsigned long in6_maxmtu = 0;
62:
63: int ip6_auto_linklocal = 1; /* enable by default */
64:
65: static int get_rand_ifid(struct ifnet *, struct in6_addr *);
66: static int get_hw_ifid(struct ifnet *, struct in6_addr *);
67: static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
68: static int in6_ifattach_loopback(struct ifnet *);
69:
70: #define EUI64_GBIT 0x01
71: #define EUI64_UBIT 0x02
72: #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
73: #define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
74: #define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
75: #define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
76: #define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
77:
78: #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
79: #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
80:
81: /*
82: * Generate a last-resort interface identifier, when the machine has no
83: * IEEE802/EUI64 address sources.
84: * The goal here is to get an interface identifier that is
85: * (1) random enough and (2) does not change across reboot.
86: * We currently use MD5(hostname) for it.
87: */
88: static int
89: get_rand_ifid(ifp, in6)
90: struct ifnet *ifp;
91: struct in6_addr *in6; /* upper 64bits are preserved */
92: {
93: MD5_CTX ctxt;
94: u_int8_t digest[16];
95:
96: #if 0
97: /* we need at least several letters as seed for ifid */
98: if (hostnamelen < 3)
99: return -1;
100: #endif
101:
102: /* generate 8 bytes of pseudo-random value. */
103: bzero(&ctxt, sizeof(ctxt));
104: MD5Init(&ctxt);
105: MD5Update(&ctxt, hostname, hostnamelen);
106: MD5Final(digest, &ctxt);
107:
108: /* assumes sizeof(digest) > sizeof(ifid) */
109: bcopy(digest, &in6->s6_addr[8], 8);
110:
111: /* make sure to set "u" bit to local, and "g" bit to individual. */
112: in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
113: in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
114:
115: /* convert EUI64 into IPv6 interface identifier */
116: EUI64_TO_IFID(in6);
117:
118: return 0;
119: }
120:
121: /*
122: * Get interface identifier for the specified interface.
123: * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
124: */
125: static int
126: get_hw_ifid(ifp, in6)
127: struct ifnet *ifp;
128: struct in6_addr *in6; /* upper 64bits are preserved */
129: {
130: struct ifaddr *ifa;
131: struct sockaddr_dl *sdl;
132: char *addr;
133: size_t addrlen;
134: static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
135: static u_int8_t allone[8] =
136: { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
137:
138: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
139: if (ifa->ifa_addr->sa_family != AF_LINK)
140: continue;
141: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
142: if (sdl == NULL)
143: continue;
144: if (sdl->sdl_alen == 0)
145: continue;
146:
147: goto found;
148: }
149:
150: return -1;
151:
152: found:
153: addr = LLADDR(sdl);
154: addrlen = sdl->sdl_alen;
155:
156: switch (ifp->if_type) {
157: case IFT_IEEE1394:
158: case IFT_IEEE80211:
159: /* IEEE1394 uses 16byte length address starting with EUI64 */
160: if (addrlen > 8)
161: addrlen = 8;
162: break;
163: default:
164: break;
165: }
166:
167: /* get EUI64 */
168: switch (ifp->if_type) {
169: /* IEEE802/EUI64 cases - what others? */
170: case IFT_ETHER:
171: case IFT_CARP:
172: case IFT_FDDI:
173: case IFT_ATM:
174: case IFT_IEEE1394:
175: case IFT_IEEE80211:
176: /* look at IEEE802/EUI64 only */
177: if (addrlen != 8 && addrlen != 6)
178: return -1;
179:
180: /*
181: * check for invalid MAC address - on bsdi, we see it a lot
182: * since wildboar configures all-zero MAC on pccard before
183: * card insertion.
184: */
185: if (bcmp(addr, allzero, addrlen) == 0)
186: return -1;
187: if (bcmp(addr, allone, addrlen) == 0)
188: return -1;
189:
190: /* make EUI64 address */
191: if (addrlen == 8)
192: bcopy(addr, &in6->s6_addr[8], 8);
193: else if (addrlen == 6) {
194: in6->s6_addr[8] = addr[0];
195: in6->s6_addr[9] = addr[1];
196: in6->s6_addr[10] = addr[2];
197: in6->s6_addr[11] = 0xff;
198: in6->s6_addr[12] = 0xfe;
199: in6->s6_addr[13] = addr[3];
200: in6->s6_addr[14] = addr[4];
201: in6->s6_addr[15] = addr[5];
202: }
203: break;
204:
205: case IFT_GIF:
206: /*
207: * RFC2893 says: "SHOULD use IPv4 address as ifid source".
208: * however, IPv4 address is not very suitable as unique
209: * identifier source (can be renumbered).
210: * we don't do this.
211: */
212: return -1;
213:
214: default:
215: return -1;
216: }
217:
218: /* sanity check: g bit must not indicate "group" */
219: if (EUI64_GROUP(in6))
220: return -1;
221:
222: /* convert EUI64 into IPv6 interface identifier */
223: EUI64_TO_IFID(in6);
224:
225: /*
226: * sanity check: ifid must not be all zero, avoid conflict with
227: * subnet router anycast
228: */
229: if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
230: bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
231: return -1;
232: }
233:
234: return 0;
235: }
236:
237: /*
238: * Get interface identifier for the specified interface. If it is not
239: * available on ifp0, borrow interface identifier from other information
240: * sources.
241: */
242: static int
243: get_ifid(ifp0, altifp, in6)
244: struct ifnet *ifp0;
245: struct ifnet *altifp; /* secondary EUI64 source */
246: struct in6_addr *in6;
247: {
248: struct ifnet *ifp;
249:
250: /* first, try to get it from the interface itself */
251: if (get_hw_ifid(ifp0, in6) == 0) {
252: nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
253: ifp0->if_xname));
254: goto success;
255: }
256:
257: /* try secondary EUI64 source. this basically is for ATM PVC */
258: if (altifp && get_hw_ifid(altifp, in6) == 0) {
259: nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
260: ifp0->if_xname, altifp->if_xname));
261: goto success;
262: }
263:
264: /* next, try to get it from some other hardware interface */
265: TAILQ_FOREACH(ifp, &ifnet, if_list) {
266: if (ifp == ifp0)
267: continue;
268: if (get_hw_ifid(ifp, in6) != 0)
269: continue;
270:
271: /*
272: * to borrow ifid from other interface, ifid needs to be
273: * globally unique
274: */
275: if (IFID_UNIVERSAL(in6)) {
276: nd6log((LOG_DEBUG,
277: "%s: borrow interface identifier from %s\n",
278: ifp0->if_xname, ifp->if_xname));
279: goto success;
280: }
281: }
282:
283: /* last resort: get from random number source */
284: if (get_rand_ifid(ifp, in6) == 0) {
285: nd6log((LOG_DEBUG,
286: "%s: interface identifier generated by random number\n",
287: ifp0->if_xname));
288: goto success;
289: }
290:
291: printf("%s: failed to get interface identifier\n", ifp0->if_xname);
292: return -1;
293:
294: success:
295: nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
296: ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
297: in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
298: in6->s6_addr[14], in6->s6_addr[15]));
299: return 0;
300: }
301:
302: int
303: in6_ifattach_linklocal(ifp, altifp)
304: struct ifnet *ifp;
305: struct ifnet *altifp; /*secondary EUI64 source*/
306: {
307: struct in6_ifaddr *ia;
308: struct in6_aliasreq ifra;
309: struct nd_prefix pr0;
310: int i, error;
311:
312: /*
313: * configure link-local address.
314: */
315: bzero(&ifra, sizeof(ifra));
316:
317: /*
318: * in6_update_ifa() does not use ifra_name, but we accurately set it
319: * for safety.
320: */
321: strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
322:
323: ifra.ifra_addr.sin6_family = AF_INET6;
324: ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
325: ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
326: ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
327: ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
328: if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
329: ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
330: ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
331: } else {
332: if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
333: nd6log((LOG_ERR,
334: "%s: no ifid available\n", ifp->if_xname));
335: return (-1);
336: }
337: }
338:
339: ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
340: ifra.ifra_prefixmask.sin6_family = AF_INET6;
341: ifra.ifra_prefixmask.sin6_addr = in6mask64;
342: /* link-local addresses should NEVER expire. */
343: ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
344: ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
345:
346: /*
347: * Do not let in6_update_ifa() do DAD, since we need a random delay
348: * before sending an NS at the first time the interface becomes up.
349: * Instead, in6_if_up() will start DAD with a proper random delay.
350: */
351: ifra.ifra_flags |= IN6_IFF_NODAD;
352:
353: /*
354: * Now call in6_update_ifa() to do a bunch of procedures to configure
355: * a link-local address. In the case of CARP, we may be called after
356: * one has already been configured, so check if it's already there
357: * with in6ifa_ifpforlinklocal() and clobber it if it exists.
358: */
359: if ((error = in6_update_ifa(ifp, &ifra,
360: in6ifa_ifpforlinklocal(ifp, 0))) != 0) {
361: /*
362: * XXX: When the interface does not support IPv6, this call
363: * would fail in the SIOCSIFADDR ioctl. I believe the
364: * notification is rather confusing in this case, so just
365: * suppress it. (jinmei@kame.net 20010130)
366: */
367: if (error != EAFNOSUPPORT)
368: nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
369: "configure a link-local address on %s "
370: "(errno=%d)\n",
371: ifp->if_xname, error));
372: return (-1);
373: }
374:
375: /*
376: * Adjust ia6_flags so that in6_if_up will perform DAD.
377: * XXX: Some P2P interfaces seem not to send packets just after
378: * becoming up, so we skip p2p interfaces for safety.
379: */
380: ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
381: #ifdef DIAGNOSTIC
382: if (!ia) {
383: panic("ia == NULL in in6_ifattach_linklocal");
384: /* NOTREACHED */
385: }
386: #endif
387: if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
388: (ifp->if_type == IFT_CARP)) == 0) {
389: ia->ia6_flags &= ~IN6_IFF_NODAD;
390: ia->ia6_flags |= IN6_IFF_TENTATIVE;
391: }
392:
393: /*
394: * Make the link-local prefix (fe80::/64%link) as on-link.
395: * Since we'd like to manage prefixes separately from addresses,
396: * we make an ND6 prefix structure for the link-local prefix,
397: * and add it to the prefix list as a never-expire prefix.
398: * XXX: this change might affect some existing code base...
399: */
400: bzero(&pr0, sizeof(pr0));
401: pr0.ndpr_ifp = ifp;
402: /* this should be 64 at this moment. */
403: pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
404: pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
405: pr0.ndpr_prefix = ifra.ifra_addr;
406: /* apply the mask for safety. (nd6_prelist_add will apply it again) */
407: for (i = 0; i < 4; i++) {
408: pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
409: in6mask64.s6_addr32[i];
410: }
411: /*
412: * Initialize parameters. The link-local prefix must always be
413: * on-link, and its lifetimes never expire.
414: */
415: pr0.ndpr_raf_onlink = 1;
416: pr0.ndpr_raf_auto = 1; /* probably meaningless */
417: pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
418: pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
419: /*
420: * Since there is no other link-local addresses, nd6_prefix_lookup()
421: * probably returns NULL. However, we cannot always expect the result.
422: * For example, if we first remove the (only) existing link-local
423: * address, and then reconfigure another one, the prefix is still
424: * valid with referring to the old link-local address.
425: */
426: if (nd6_prefix_lookup(&pr0) == NULL) {
427: if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
428: return (error);
429: }
430:
431: return 0;
432: }
433:
434: static int
435: in6_ifattach_loopback(ifp)
436: struct ifnet *ifp; /* must be IFT_LOOP */
437: {
438: struct in6_aliasreq ifra;
439: int error;
440:
441: bzero(&ifra, sizeof(ifra));
442:
443: /*
444: * in6_update_ifa() does not use ifra_name, but we accurately set it
445: * for safety.
446: */
447: strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
448:
449: ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
450: ifra.ifra_prefixmask.sin6_family = AF_INET6;
451: ifra.ifra_prefixmask.sin6_addr = in6mask128;
452:
453: /*
454: * Always initialize ia_dstaddr (= broadcast address) to loopback
455: * address. Follows IPv4 practice - see in_ifinit().
456: */
457: ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
458: ifra.ifra_dstaddr.sin6_family = AF_INET6;
459: ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
460:
461: ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
462: ifra.ifra_addr.sin6_family = AF_INET6;
463: ifra.ifra_addr.sin6_addr = in6addr_loopback;
464:
465: /* the loopback address should NEVER expire. */
466: ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
467: ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
468:
469: /* we don't need to perform DAD on loopback interfaces. */
470: ifra.ifra_flags |= IN6_IFF_NODAD;
471:
472: /*
473: * We are sure that this is a newly assigned address, so we can set
474: * NULL to the 3rd arg.
475: */
476: if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
477: nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
478: "the loopback address on %s (errno=%d)\n",
479: ifp->if_xname, error));
480: return (-1);
481: }
482:
483: return 0;
484: }
485:
486: /*
487: * compute NI group address, based on the current hostname setting.
488: * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
489: *
490: * when ifp == NULL, the caller is responsible for filling scopeid.
491: */
492: int
493: in6_nigroup(ifp, name, namelen, sa6)
494: struct ifnet *ifp;
495: const char *name;
496: int namelen;
497: struct sockaddr_in6 *sa6;
498: {
499: const char *p;
500: u_int8_t *q;
501: MD5_CTX ctxt;
502: u_int8_t digest[16];
503: u_int8_t l;
504: u_int8_t n[64]; /* a single label must not exceed 63 chars */
505:
506: if (!namelen || !name)
507: return -1;
508:
509: p = name;
510: while (p && *p && *p != '.' && p - name < namelen)
511: p++;
512: if (p - name > sizeof(n) - 1)
513: return -1; /* label too long */
514: l = p - name;
515: strncpy((char *)n, name, l);
516: n[(int)l] = '\0';
517: for (q = n; *q; q++) {
518: if ('A' <= *q && *q <= 'Z')
519: *q = *q - 'A' + 'a';
520: }
521:
522: /* generate 8 bytes of pseudo-random value. */
523: bzero(&ctxt, sizeof(ctxt));
524: MD5Init(&ctxt);
525: MD5Update(&ctxt, &l, sizeof(l));
526: MD5Update(&ctxt, n, l);
527: MD5Final(digest, &ctxt);
528:
529: bzero(sa6, sizeof(*sa6));
530: sa6->sin6_family = AF_INET6;
531: sa6->sin6_len = sizeof(*sa6);
532: sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
533: sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
534: sa6->sin6_addr.s6_addr8[11] = 2;
535: bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
536: sizeof(sa6->sin6_addr.s6_addr32[3]));
537:
538: return 0;
539: }
540:
541: /*
542: * XXX multiple loopback interface needs more care. for instance,
543: * nodelocal address needs to be configured onto only one of them.
544: * XXX multiple link-local address case
545: */
546: void
547: in6_ifattach(ifp, altifp)
548: struct ifnet *ifp;
549: struct ifnet *altifp; /* secondary EUI64 source */
550: {
551: struct in6_ifaddr *ia;
552: struct in6_addr in6;
553:
554: /* some of the interfaces are inherently not IPv6 capable */
555: switch (ifp->if_type) {
556: case IFT_BRIDGE:
557: case IFT_ENC:
558: case IFT_PFLOG:
559: case IFT_PFSYNC:
560: return;
561: }
562:
563: /*
564: * if link mtu is too small, don't try to configure IPv6.
565: * remember there could be some link-layer that has special
566: * fragmentation logic.
567: */
568: if (ifp->if_mtu < IPV6_MMTU) {
569: nd6log((LOG_INFO, "in6_ifattach: "
570: "%s has too small MTU, IPv6 not enabled\n",
571: ifp->if_xname));
572: return;
573: }
574:
575: /* create a multicast kludge storage (if we have not had one) */
576: in6_createmkludge(ifp);
577:
578: /*
579: * quirks based on interface type
580: */
581: switch (ifp->if_type) {
582: /* we attach a link-local address when a vhid is assigned */
583: case IFT_CARP:
584: return;
585: default:
586: break;
587: }
588:
589: /*
590: * usually, we require multicast capability to the interface
591: */
592: if ((ifp->if_flags & IFF_MULTICAST) == 0) {
593: nd6log((LOG_INFO, "in6_ifattach: "
594: "%s is not multicast capable, IPv6 not enabled\n",
595: ifp->if_xname));
596: return;
597: }
598:
599: /*
600: * assign loopback address for loopback interface.
601: * XXX multiple loopback interface case.
602: */
603: if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
604: in6 = in6addr_loopback;
605: if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
606: if (in6_ifattach_loopback(ifp) != 0)
607: return;
608: }
609: }
610:
611: /*
612: * assign a link-local address, if there's none.
613: */
614: if (ip6_auto_linklocal) {
615: ia = in6ifa_ifpforlinklocal(ifp, 0);
616: if (ia == NULL) {
617: if (in6_ifattach_linklocal(ifp, altifp) == 0) {
618: /* linklocal address assigned */
619: } else {
620: /* failed to assign linklocal address. bark? */
621: }
622: }
623: }
624: }
625:
626: /*
627: * NOTE: in6_ifdetach() does not support loopback if at this moment.
628: */
629: void
630: in6_ifdetach(ifp)
631: struct ifnet *ifp;
632: {
633: struct in6_ifaddr *ia, *oia;
634: struct ifaddr *ifa, *next;
635: struct rtentry *rt;
636: short rtflags;
637: struct sockaddr_in6 sin6;
638: struct in6_multi_mship *imm;
639:
640: #ifdef MROUTING
641: /* remove ip6_mrouter stuff */
642: ip6_mrouter_detach(ifp);
643: #endif
644:
645: /* remove neighbor management table */
646: nd6_purge(ifp);
647:
648: /* nuke any of IPv6 addresses we have */
649: for (ifa = TAILQ_FIRST(&ifp->if_addrlist);
650: ifa != TAILQ_END(&ifp->if_addrlist); ifa = next) {
651: next = TAILQ_NEXT(ifa, ifa_list);
652: if (ifa->ifa_addr->sa_family != AF_INET6)
653: continue;
654: in6_purgeaddr(ifa);
655: }
656:
657: /* undo everything done by in6_ifattach(), just in case */
658: for (ifa = TAILQ_FIRST(&ifp->if_addrlist);
659: ifa != TAILQ_END(&ifp->if_addrlist); ifa = next) {
660: next = TAILQ_NEXT(ifa, ifa_list);
661:
662: if (ifa->ifa_addr->sa_family != AF_INET6
663: || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
664: continue;
665: }
666:
667: ia = (struct in6_ifaddr *)ifa;
668:
669: /*
670: * leave from multicast groups we have joined for the interface
671: */
672: while (!LIST_EMPTY(&ia->ia6_memberships)) {
673: imm = LIST_FIRST(&ia->ia6_memberships);
674: LIST_REMOVE(imm, i6mm_chain);
675: in6_leavegroup(imm);
676: }
677:
678: /* remove from the routing table */
679: if ((ia->ia_flags & IFA_ROUTE) &&
680: (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0))) {
681: rtflags = rt->rt_flags;
682: rtfree(rt);
683: rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
684: (struct sockaddr *)&ia->ia_addr,
685: (struct sockaddr *)&ia->ia_prefixmask,
686: rtflags, (struct rtentry **)0, 0);
687: }
688:
689: /* remove from the linked list */
690: TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
691: IFAFREE(&ia->ia_ifa);
692:
693: /* also remove from the IPv6 address chain(itojun&jinmei) */
694: oia = ia;
695: if (oia == (ia = in6_ifaddr))
696: in6_ifaddr = ia->ia_next;
697: else {
698: while (ia->ia_next && (ia->ia_next != oia))
699: ia = ia->ia_next;
700: if (ia->ia_next)
701: ia->ia_next = oia->ia_next;
702: else {
703: nd6log((LOG_ERR,
704: "%s: didn't unlink in6ifaddr from list\n",
705: ifp->if_xname));
706: }
707: }
708:
709: IFAFREE(&oia->ia_ifa);
710: }
711:
712: /* cleanup multicast address kludge table, if there is any */
713: in6_purgemkludge(ifp);
714:
715: /*
716: * remove neighbor management table. we call it twice just to make
717: * sure we nuke everything. maybe we need just one call.
718: * XXX: since the first call did not release addresses, some prefixes
719: * might remain. We should call nd6_purge() again to release the
720: * prefixes after removing all addresses above.
721: * (Or can we just delay calling nd6_purge until at this point?)
722: */
723: nd6_purge(ifp);
724:
725: /* remove route to link-local allnodes multicast (ff02::1) */
726: bzero(&sin6, sizeof(sin6));
727: sin6.sin6_len = sizeof(struct sockaddr_in6);
728: sin6.sin6_family = AF_INET6;
729: sin6.sin6_addr = in6addr_linklocal_allnodes;
730: sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
731: rt = rtalloc1((struct sockaddr *)&sin6, 0, 0);
732: if (rt && rt->rt_ifp == ifp) {
733: rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
734: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
735: rtfree(rt);
736: }
737: }
CVSweb