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