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