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