Annotation of src/sys/netinet6/in6_ifattach.c, Revision 1.30
1.30 ! itojun 1: /* $NetBSD: in6_ifattach.c,v 1.29 2000/04/27 15:39:05 itojun Exp $ */
! 2: /* $KAME: in6_ifattach.c,v 1.56 2000/05/05 06:54:33 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.24 itojun 7: *
1.2 itojun 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.
1.24 itojun 19: *
1.2 itojun 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>
1.13 itojun 38: #include <sys/kernel.h>
39: #include <sys/md5.h>
1.2 itojun 40:
41: #include <net/if.h>
42: #include <net/if_dl.h>
43: #include <net/if_types.h>
44: #include <net/route.h>
45:
46: #include <netinet/in.h>
47: #include <netinet/in_var.h>
48:
1.19 itojun 49: #include <netinet/ip6.h>
1.2 itojun 50: #include <netinet6/ip6_var.h>
51: #include <netinet6/in6_ifattach.h>
52: #include <netinet6/ip6_var.h>
53: #include <netinet6/nd6.h>
54:
1.13 itojun 55: #include <net/net_osdep.h>
56:
57: struct in6_ifstat **in6_ifstat = NULL;
58: struct icmp6_ifstat **icmp6_ifstat = NULL;
59: size_t in6_ifstatmax = 0;
60: size_t icmp6_ifstatmax = 0;
1.2 itojun 61: unsigned long in6_maxmtu = 0;
62:
1.25 itojun 63: static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
64: static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
65: static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
66: static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
67: static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
68: static int in6_ifattach_loopback __P((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);
1.2 itojun 110:
1.25 itojun 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: }
1.2 itojun 120:
1.25 itojun 121: /*
122: * Get interface identifier for the specified interface.
123: * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
124: */
1.7 itojun 125: static int
1.25 itojun 126: get_hw_ifid(ifp, in6)
127: struct ifnet *ifp;
128: struct in6_addr *in6; /*upper 64bits are preserved */
1.2 itojun 129: {
1.25 itojun 130: struct ifaddr *ifa;
131: struct sockaddr_dl *sdl;
132: u_int8_t *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: for (ifa = ifp->if_addrlist.tqh_first;
139: ifa;
140: ifa = ifa->ifa_list.tqe_next)
141: {
142: if (ifa->ifa_addr->sa_family != AF_LINK)
143: continue;
144: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
145: if (sdl == NULL)
146: continue;
147: if (sdl->sdl_alen == 0)
148: continue;
149:
150: goto found;
151: }
152:
153: return -1;
154:
155: found:
156: addr = LLADDR(sdl);
157: addrlen = sdl->sdl_alen;
158:
159: /* get EUI64 */
160: switch (ifp->if_type) {
161: case IFT_ETHER:
162: case IFT_FDDI:
163: case IFT_ATM:
164: /* IEEE802/EUI64 cases - what others? */
1.13 itojun 165:
1.25 itojun 166: /* look at IEEE802/EUI64 only */
167: if (addrlen != 8 && addrlen != 6)
168: return -1;
1.13 itojun 169:
1.25 itojun 170: /*
171: * check for invalid MAC address - on bsdi, we see it a lot
172: * since wildboar configures all-zero MAC on pccard before
173: * card insertion.
174: */
175: if (bcmp(addr, allzero, addrlen) == 0)
176: return -1;
177: if (bcmp(addr, allone, addrlen) == 0)
178: return -1;
179:
180: /* make EUI64 address */
181: if (addrlen == 8)
182: bcopy(addr, &in6->s6_addr[8], 8);
183: else if (addrlen == 6) {
184: in6->s6_addr[8] = addr[0];
185: in6->s6_addr[9] = addr[1];
186: in6->s6_addr[10] = addr[2];
187: in6->s6_addr[11] = 0xff;
1.26 itojun 188: in6->s6_addr[12] = 0xfe;
1.25 itojun 189: in6->s6_addr[13] = addr[3];
190: in6->s6_addr[14] = addr[4];
191: in6->s6_addr[15] = addr[5];
192: }
1.7 itojun 193: break;
1.25 itojun 194:
195: case IFT_ARCNET:
196: if (addrlen != 1)
197: return -1;
198: if (!addr[0])
199: return -1;
200:
201: bzero(&in6->s6_addr[8], 8);
202: in6->s6_addr[15] = addr[0];
203:
1.27 itojun 204: /*
205: * due to insufficient bitwidth, we mark it local.
206: */
1.25 itojun 207: in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
208: in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
1.7 itojun 209: break;
1.25 itojun 210:
211: case IFT_GIF:
212: #ifdef IFT_STF
213: case IFT_STF:
214: #endif
215: /*
1.27 itojun 216: * mech-06 says: "SHOULD use IPv4 address as ifid source".
217: * however, IPv4 address is not very suitable as unique
218: * identifier source (can be renumbered).
219: * we don't do this.
1.25 itojun 220: */
221: return -1;
222:
1.7 itojun 223: default:
1.25 itojun 224: return -1;
225: }
226:
227: /* sanity check: g bit must not indicate "group" */
228: if (EUI64_GROUP(in6))
229: return -1;
230:
231: /* convert EUI64 into IPv6 interface identifier */
232: EUI64_TO_IFID(in6);
233:
234: /*
235: * sanity check: ifid must not be all zero, avoid conflict with
236: * subnet router anycast
237: */
238: if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
239: bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
240: return -1;
1.7 itojun 241: }
242:
243: return 0;
1.2 itojun 244: }
245:
246: /*
1.25 itojun 247: * Get interface identifier for the specified interface. If it is not
248: * available on ifp0, borrow interface identifier from other information
249: * sources.
1.13 itojun 250: */
251: static int
1.25 itojun 252: get_ifid(ifp0, altifp, in6)
253: struct ifnet *ifp0;
254: struct ifnet *altifp; /*secondary EUI64 source*/
255: struct in6_addr *in6;
1.13 itojun 256: {
1.25 itojun 257: struct ifnet *ifp;
258:
259: /* first, try to get it from the interface itself */
260: if (get_hw_ifid(ifp0, in6) == 0) {
261: #ifdef ND6_DEBUG
262: printf("%s: got interface identifier from itself\n",
263: if_name(ifp0));
264: #endif
265: goto success;
266: }
267:
268: /* try secondary EUI64 source. this basically is for ATM PVC */
269: if (altifp && get_hw_ifid(altifp, in6) == 0) {
270: #ifdef ND6_DEBUG
271: printf("%s: got interface identifier from %s\n",
272: if_name(ifp0), ifname(altifp));
273: #endif
274: goto success;
275: }
276:
277: /* next, try to get it from some other hardware interface */
278: for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
279: {
280: if (ifp == ifp0)
281: continue;
282: if (get_hw_ifid(ifp, in6) != 0)
283: continue;
1.27 itojun 284:
1.25 itojun 285: /*
286: * to borrow ifid from other interface, ifid needs to be
287: * globally unique
288: */
289: if (IFID_UNIVERSAL(in6)) {
1.13 itojun 290:
1.25 itojun 291: #ifdef ND6_DEBUG
292: printf("%s: borrow interface identifier from %s\n",
293: if_name(ifp0), if_name(ifp));
294: #endif
295: goto success;
296: }
297: }
1.13 itojun 298:
1.25 itojun 299: /* last resort: get from random number source */
300: if (get_rand_ifid(ifp, in6) == 0) {
301: #ifdef ND6_DEBUG
302: printf("%s: interface identifier generated by random number\n",
303: if_name(ifp0));
304: #endif
305: goto success;
306: }
1.13 itojun 307:
1.25 itojun 308: printf("%s: failed to get interface identifier", if_name(ifp0));
309: return -1;
1.13 itojun 310:
1.25 itojun 311: success:
312: #ifdef ND6_DEBUG
313: printf("%s: ifid: "
314: "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
315: if_name(ifp0),
316: in6->s6_addr[8], in6->s6_addr[9],
317: in6->s6_addr[10], in6->s6_addr[11],
318: in6->s6_addr[12], in6->s6_addr[13],
319: in6->s6_addr[14], in6->s6_addr[15]);
320: #endif
1.13 itojun 321: return 0;
322: }
323:
324: /*
1.25 itojun 325: * configure IPv6 interface address. XXX code duplicated with in.c
1.2 itojun 326: */
1.25 itojun 327: static int
328: in6_ifattach_addaddr(ifp, ia)
329: struct ifnet *ifp;
330: struct in6_ifaddr *ia;
1.2 itojun 331: {
1.25 itojun 332: struct in6_ifaddr *oia;
1.2 itojun 333: struct ifaddr *ifa;
1.25 itojun 334: int error;
335: int rtflag;
336: struct in6_addr llsol;
337:
338: /*
339: * initialize if_addrlist, if we are the very first one
340: */
341: ifa = TAILQ_FIRST(&ifp->if_addrlist);
342: if (ifa == NULL) {
343: TAILQ_INIT(&ifp->if_addrlist);
344: }
1.2 itojun 345:
1.25 itojun 346: /*
347: * link the interface address to global list
348: */
349: TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.27 itojun 350: IFAREF(&ia->ia_ifa);
1.2 itojun 351:
1.25 itojun 352: /*
353: * Also link into the IPv6 address chain beginning with in6_ifaddr.
354: * kazu opposed it, but itojun & jinmei wanted.
355: */
356: if ((oia = in6_ifaddr) != NULL) {
357: for (; oia->ia_next; oia = oia->ia_next)
1.2 itojun 358: continue;
1.25 itojun 359: oia->ia_next = ia;
360: } else
361: in6_ifaddr = ia;
1.27 itojun 362: IFAREF(&ia->ia_ifa);
1.25 itojun 363:
364: /*
365: * give the interface a chance to initialize, in case this
366: * is the first address to be added.
367: */
368: if (ifp->if_ioctl != NULL) {
369: int s;
370: s = splimp();
371: error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
372: splx(s);
373: } else
374: error = 0;
375: if (error) {
376: switch (error) {
377: case EAFNOSUPPORT:
378: printf("%s: IPv6 not supported\n", if_name(ifp));
379: break;
380: default:
381: printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
382: error);
383: break;
384: }
385:
386: /* undo changes */
387: TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
388: IFAFREE(&ia->ia_ifa);
389: if (oia)
390: oia->ia_next = ia->ia_next;
391: else
392: in6_ifaddr = ia->ia_next;
393: IFAFREE(&ia->ia_ifa);
394: return -1;
395: }
396:
397: /* configure link-layer address resolution */
1.27 itojun 398: rtflag = 0;
1.25 itojun 399: if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
400: rtflag = RTF_HOST;
401: else {
402: switch (ifp->if_type) {
403: case IFT_LOOP:
404: #ifdef IFT_STF
405: case IFT_STF:
406: #endif
407: rtflag = 0;
408: break;
409: default:
410: ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
411: ia->ia_ifa.ifa_flags |= RTF_CLONING;
412: rtflag = RTF_CLONING;
413: break;
1.2 itojun 414: }
415: }
1.25 itojun 416:
417: /* add route to the interface. */
418: rtrequest(RTM_ADD,
419: (struct sockaddr *)&ia->ia_addr,
420: (struct sockaddr *)&ia->ia_addr,
421: (struct sockaddr *)&ia->ia_prefixmask,
422: RTF_UP | rtflag,
423: (struct rtentry **)0);
424: ia->ia_flags |= IFA_ROUTE;
425:
426: if ((rtflag & RTF_CLONING) != 0 &&
427: (ifp->if_flags & IFF_MULTICAST) != 0) {
428: /* Restore saved multicast addresses (if any). */
429: in6_restoremkludge(ia, ifp);
430:
431: /*
432: * join solicited multicast address
433: */
434: bzero(&llsol, sizeof(llsol));
435: llsol.s6_addr16[0] = htons(0xff02);
436: llsol.s6_addr16[1] = htons(ifp->if_index);
437: llsol.s6_addr32[1] = 0;
438: llsol.s6_addr32[2] = htonl(1);
439: llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
440: llsol.s6_addr8[12] = 0xff;
441: (void)in6_addmulti(&llsol, ifp, &error);
442:
443: /* XXX should we run DAD on other interface types? */
444: switch (ifp->if_type) {
445: #if 1
446: case IFT_ARCNET:
447: case IFT_ETHER:
448: case IFT_FDDI:
449: #else
450: default:
1.4 thorpej 451: #endif
1.25 itojun 452: /* mark the address TENTATIVE, if needed. */
453: ia->ia6_flags |= IN6_IFF_TENTATIVE;
454: /* nd6_dad_start() will be called in in6_if_up */
455: }
456: }
457:
458: return 0;
459: }
460:
461: static int
462: in6_ifattach_linklocal(ifp, altifp)
463: struct ifnet *ifp;
464: struct ifnet *altifp; /*secondary EUI64 source*/
465: {
466: struct in6_ifaddr *ia;
1.2 itojun 467:
1.25 itojun 468: /*
469: * configure link-local address
470: */
471: ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
472: bzero((caddr_t)ia, sizeof(*ia));
473: ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
474: if (ifp->if_flags & IFF_POINTOPOINT)
475: ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
476: else
477: ia->ia_ifa.ifa_dstaddr = NULL;
478: ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
479: ia->ia_ifp = ifp;
1.2 itojun 480:
1.25 itojun 481: bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
482: ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
483: ia->ia_prefixmask.sin6_family = AF_INET6;
484: ia->ia_prefixmask.sin6_addr = in6mask64;
1.5 itojun 485:
1.25 itojun 486: /* just in case */
487: bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
488: ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
489: ia->ia_dstaddr.sin6_family = AF_INET6;
1.5 itojun 490:
1.25 itojun 491: bzero(&ia->ia_addr, sizeof(ia->ia_addr));
492: ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
493: ia->ia_addr.sin6_family = AF_INET6;
494: ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
495: ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
496: ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
497: if (ifp->if_flags & IFF_LOOPBACK) {
498: ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
499: ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
1.2 itojun 500: } else {
1.25 itojun 501: if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
502: #ifdef ND6_DEBUG
503: printf("%s: no ifid available\n", if_name(ifp));
1.4 thorpej 504: #endif
1.25 itojun 505: free(ia, M_IFADDR);
506: return -1;
507: }
508: }
509:
510: ia->ia_ifa.ifa_metric = ifp->if_metric;
511:
512: if (in6_ifattach_addaddr(ifp, ia) != 0) {
513: /* ia will be freed on failure */
514: return -1;
515: }
516:
517: return 0;
518: }
519:
520: static int
521: in6_ifattach_loopback(ifp)
522: struct ifnet *ifp; /* must be IFT_LOOP */
523: {
524: struct in6_ifaddr *ia;
525:
526: /*
527: * configure link-local address
528: */
529: ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
530: bzero((caddr_t)ia, sizeof(*ia));
531: ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
532: ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
533: ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
534: ia->ia_ifp = ifp;
535:
536: bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
537: ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
538: ia->ia_prefixmask.sin6_family = AF_INET6;
539: ia->ia_prefixmask.sin6_addr = in6mask128;
540:
541: /*
542: * Always initialize ia_dstaddr (= broadcast address) to loopback
543: * address, to make getifaddr happier.
544: *
545: * For BSDI, it is mandatory. The BSDI version of
546: * ifa_ifwithroute() rejects to add a route to the loopback
547: * interface. Even for other systems, loopback looks somewhat
548: * special.
549: */
550: bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
551: ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
552: ia->ia_dstaddr.sin6_family = AF_INET6;
553: ia->ia_dstaddr.sin6_addr = in6addr_loopback;
554:
555: bzero(&ia->ia_addr, sizeof(ia->ia_addr));
556: ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
557: ia->ia_addr.sin6_family = AF_INET6;
558: ia->ia_addr.sin6_addr = in6addr_loopback;
559:
560: ia->ia_ifa.ifa_metric = ifp->if_metric;
561:
562: if (in6_ifattach_addaddr(ifp, ia) != 0) {
563: /* ia will be freed on failure */
564: return -1;
1.2 itojun 565: }
1.25 itojun 566:
567: return 0;
1.2 itojun 568: }
569:
1.17 itojun 570: /*
571: * XXX multiple loopback interface needs more care. for instance,
572: * nodelocal address needs to be configured onto only one of them.
1.25 itojun 573: * XXX multiple link-local address case
1.17 itojun 574: */
1.2 itojun 575: void
1.25 itojun 576: in6_ifattach(ifp, altifp)
1.2 itojun 577: struct ifnet *ifp;
1.25 itojun 578: struct ifnet *altifp; /* secondary EUI64 source */
1.2 itojun 579: {
580: static size_t if_indexlim = 8;
581: struct sockaddr_in6 mltaddr;
582: struct sockaddr_in6 mltmask;
583: struct sockaddr_in6 gate;
584: struct sockaddr_in6 mask;
1.25 itojun 585: struct in6_ifaddr *ia;
586: struct in6_addr in6;
1.13 itojun 587:
1.2 itojun 588: /*
589: * We have some arrays that should be indexed by if_index.
590: * since if_index will grow dynamically, they should grow too.
1.13 itojun 591: * struct in6_ifstat **in6_ifstat
592: * struct icmp6_ifstat **icmp6_ifstat
1.2 itojun 593: */
1.25 itojun 594: if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
595: if_index >= if_indexlim) {
1.2 itojun 596: size_t n;
597: caddr_t q;
1.7 itojun 598: size_t olim;
1.2 itojun 599:
1.7 itojun 600: olim = if_indexlim;
601: while (if_index >= if_indexlim)
1.2 itojun 602: if_indexlim <<= 1;
603:
1.13 itojun 604: /* grow in6_ifstat */
605: n = if_indexlim * sizeof(struct in6_ifstat *);
606: q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
607: bzero(q, n);
608: if (in6_ifstat) {
609: bcopy((caddr_t)in6_ifstat, q,
610: olim * sizeof(struct in6_ifstat *));
611: free((caddr_t)in6_ifstat, M_IFADDR);
612: }
613: in6_ifstat = (struct in6_ifstat **)q;
614: in6_ifstatmax = if_indexlim;
615:
616: /* grow icmp6_ifstat */
617: n = if_indexlim * sizeof(struct icmp6_ifstat *);
1.2 itojun 618: q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
619: bzero(q, n);
1.13 itojun 620: if (icmp6_ifstat) {
621: bcopy((caddr_t)icmp6_ifstat, q,
622: olim * sizeof(struct icmp6_ifstat *));
623: free((caddr_t)icmp6_ifstat, M_IFADDR);
1.2 itojun 624: }
1.13 itojun 625: icmp6_ifstat = (struct icmp6_ifstat **)q;
626: icmp6_ifstatmax = if_indexlim;
1.2 itojun 627: }
628:
629: /*
1.25 itojun 630: * quirks based on interface type
1.2 itojun 631: */
1.25 itojun 632: switch (ifp->if_type) {
633: #ifdef IFT_STF
634: case IFT_STF:
635: /*
636: * 6to4 interface is a very speical kind of beast.
637: * no multicast, no linklocal (based on 03 draft).
638: */
639: goto statinit;
640: #endif
641: default:
642: break;
1.7 itojun 643: }
1.2 itojun 644:
645: /*
1.25 itojun 646: * usually, we require multicast capability to the interface
1.2 itojun 647: */
1.25 itojun 648: if ((ifp->if_flags & IFF_MULTICAST) == 0) {
649: printf("%s: not multicast capable, IPv6 not enabled\n",
650: if_name(ifp));
651: return;
652: }
1.15 thorpej 653:
1.2 itojun 654: /*
1.25 itojun 655: * assign link-local address, if there's none
1.2 itojun 656: */
1.25 itojun 657: ia = in6ifa_ifpforlinklocal(ifp, 0);
658: if (ia == NULL) {
659: if (in6_ifattach_linklocal(ifp, altifp) != 0)
660: return;
661: ia = in6ifa_ifpforlinklocal(ifp, 0);
1.2 itojun 662:
1.25 itojun 663: if (ia == NULL) {
664: printf("%s: failed to add link-local address",
665: if_name(ifp));
1.2 itojun 666:
1.25 itojun 667: /* we can't initialize multicasts without link-local */
668: goto statinit;
1.2 itojun 669: }
670: }
671:
1.25 itojun 672: if (ifp->if_flags & IFF_POINTOPOINT) {
1.2 itojun 673: /*
674: * route local address to loopback
675: */
676: bzero(&gate, sizeof(gate));
677: gate.sin6_len = sizeof(struct sockaddr_in6);
678: gate.sin6_family = AF_INET6;
679: gate.sin6_addr = in6addr_loopback;
680: bzero(&mask, sizeof(mask));
681: mask.sin6_len = sizeof(struct sockaddr_in6);
682: mask.sin6_family = AF_INET6;
683: mask.sin6_addr = in6mask64;
684: rtrequest(RTM_ADD,
685: (struct sockaddr *)&ia->ia_addr,
686: (struct sockaddr *)&gate,
687: (struct sockaddr *)&mask,
688: RTF_UP|RTF_HOST,
689: (struct rtentry **)0);
690: }
691:
692: /*
1.25 itojun 693: * assign loopback address for loopback interface
694: * XXX multiple loopback interface case
1.2 itojun 695: */
1.25 itojun 696: in6 = in6addr_loopback;
697: if (ifp->if_flags & IFF_LOOPBACK) {
698: if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
699: if (in6_ifattach_loopback(ifp) != 0)
700: return;
701: }
702: }
1.2 itojun 703:
1.25 itojun 704: #ifdef DIAGNOSTIC
705: if (!ia) {
706: panic("ia == NULL in in6_ifattach");
707: /*NOTREACHED*/
1.2 itojun 708: }
1.25 itojun 709: #endif
1.2 itojun 710:
711: /*
712: * join multicast
713: */
714: if (ifp->if_flags & IFF_MULTICAST) {
715: int error; /* not used */
1.25 itojun 716: struct in6_multi *in6m;
1.2 itojun 717:
1.25 itojun 718: /* Restore saved multicast addresses (if any). */
1.2 itojun 719: in6_restoremkludge(ia, ifp);
720:
721: bzero(&mltmask, sizeof(mltmask));
722: mltmask.sin6_len = sizeof(struct sockaddr_in6);
723: mltmask.sin6_family = AF_INET6;
724: mltmask.sin6_addr = in6mask32;
725:
726: /*
727: * join link-local all-nodes address
728: */
729: bzero(&mltaddr, sizeof(mltaddr));
730: mltaddr.sin6_len = sizeof(struct sockaddr_in6);
731: mltaddr.sin6_family = AF_INET6;
732: mltaddr.sin6_addr = in6addr_linklocal_allnodes;
733: mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
734:
1.25 itojun 735: IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
736: if (in6m == NULL) {
1.2 itojun 737: rtrequest(RTM_ADD,
738: (struct sockaddr *)&mltaddr,
1.25 itojun 739: (struct sockaddr *)&ia->ia_addr,
1.2 itojun 740: (struct sockaddr *)&mltmask,
1.25 itojun 741: RTF_UP|RTF_CLONING, /* xxx */
1.2 itojun 742: (struct rtentry **)0);
743: (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
1.25 itojun 744: }
745:
746: if (ifp->if_flags & IFF_LOOPBACK) {
747: in6 = in6addr_loopback;
748: ia = in6ifa_ifpwithaddr(ifp, &in6);
1.2 itojun 749: /*
1.25 itojun 750: * join node-local all-nodes address, on loopback
1.2 itojun 751: */
1.25 itojun 752: mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
753:
754: IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
755: if (in6m == NULL && ia != NULL) {
756: rtrequest(RTM_ADD,
757: (struct sockaddr *)&mltaddr,
758: (struct sockaddr *)&ia->ia_addr,
759: (struct sockaddr *)&mltmask,
760: RTF_UP,
761: (struct rtentry **)0);
762: (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
763: }
1.2 itojun 764: }
765: }
766:
1.25 itojun 767: statinit:;
768:
1.2 itojun 769: /* update dynamically. */
770: if (in6_maxmtu < ifp->if_mtu)
771: in6_maxmtu = ifp->if_mtu;
772:
1.13 itojun 773: if (in6_ifstat[ifp->if_index] == NULL) {
774: in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
775: malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
776: bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
777: }
778: if (icmp6_ifstat[ifp->if_index] == NULL) {
779: icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
780: malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
781: bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
782: }
783:
1.2 itojun 784: /* initialize NDP variables */
785: nd6_ifattach(ifp);
786: }
787:
1.17 itojun 788: /*
789: * NOTE: in6_ifdetach() does not support loopback if at this moment.
790: */
1.2 itojun 791: void
792: in6_ifdetach(ifp)
793: struct ifnet *ifp;
794: {
795: struct in6_ifaddr *ia, *oia;
1.30 ! itojun 796: struct ifaddr *ifa, *next;
1.2 itojun 797: struct rtentry *rt;
798: short rtflags;
1.16 itojun 799: struct sockaddr_in6 sin6;
1.2 itojun 800:
1.18 itojun 801: /* nuke prefix list. this may try to remove some of ifaddrs as well */
802: in6_purgeprefix(ifp);
803:
804: /* remove neighbor management table */
805: nd6_purge(ifp);
806:
1.30 ! itojun 807: /* nuke any of IPv6 addresses we have */
! 808: for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
! 809: {
! 810: next = ifa->ifa_list.tqe_next;
! 811: if (ifa->ifa_addr->sa_family != AF_INET6)
! 812: continue;
! 813: in6_purgeaddr(ifa, ifp);
! 814: }
! 815:
! 816: /* undo everything done by in6_ifattach(), just in case */
! 817: for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
1.13 itojun 818: {
1.30 ! itojun 819: next = ifa->ifa_list.tqe_next;
! 820:
! 821:
1.2 itojun 822: if (ifa->ifa_addr->sa_family != AF_INET6
823: || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
824: continue;
825: }
826:
827: ia = (struct in6_ifaddr *)ifa;
828:
829: /* remove from the routing table */
830: if ((ia->ia_flags & IFA_ROUTE)
1.14 itojun 831: && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
1.2 itojun 832: rtflags = rt->rt_flags;
833: rtfree(rt);
834: rtrequest(RTM_DELETE,
835: (struct sockaddr *)&ia->ia_addr,
1.24 itojun 836: (struct sockaddr *)&ia->ia_addr,
1.2 itojun 837: (struct sockaddr *)&ia->ia_prefixmask,
838: rtflags, (struct rtentry **)0);
839: }
840:
841: /* remove from the linked list */
842: TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.30 ! itojun 843: IFAFREE(&ia->ia_ifa);
1.2 itojun 844:
845: /* also remove from the IPv6 address chain(itojun&jinmei) */
846: oia = ia;
847: if (oia == (ia = in6_ifaddr))
848: in6_ifaddr = ia->ia_next;
849: else {
850: while (ia->ia_next && (ia->ia_next != oia))
851: ia = ia->ia_next;
852: if (ia->ia_next)
853: ia->ia_next = oia->ia_next;
1.25 itojun 854: #ifdef ND6_DEBUG
1.2 itojun 855: else
1.4 thorpej 856: printf("%s: didn't unlink in6ifaddr from "
1.13 itojun 857: "list\n", if_name(ifp));
1.4 thorpej 858: #endif
1.2 itojun 859: }
860:
1.30 ! itojun 861: IFAFREE(&oia->ia_ifa);
1.16 itojun 862: }
863:
1.17 itojun 864: /* cleanup multicast address kludge table, if there is any */
865: in6_purgemkludge(ifp);
1.30 ! itojun 866:
! 867: /* remove neighbor management table */
! 868: nd6_purge(ifp);
1.18 itojun 869:
1.16 itojun 870: /* remove route to link-local allnodes multicast (ff02::1) */
871: bzero(&sin6, sizeof(sin6));
872: sin6.sin6_len = sizeof(struct sockaddr_in6);
873: sin6.sin6_family = AF_INET6;
874: sin6.sin6_addr = in6addr_linklocal_allnodes;
875: sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
876: if ((rt = rtalloc1((struct sockaddr *)&sin6, 0)) != NULL) {
877: rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
878: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
879: rtfree(rt);
1.2 itojun 880: }
881: }
CVSweb <webmaster@jp.NetBSD.org>