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