in6_ifattach.c revision 1.1
1/* $OpenBSD: in6_ifattach.c,v 1.1 1999/12/08 06:50:21 itojun Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/malloc.h> 35#include <sys/socket.h> 36#include <sys/sockio.h> 37#include <sys/kernel.h> 38#ifdef __bsdi__ 39#include <crypto/md5.h> 40#elif defined(__OpenBSD__) 41#include <sys/md5k.h> 42#else 43#include <sys/md5.h> 44#endif 45 46#include <net/if.h> 47#include <net/if_dl.h> 48#include <net/if_types.h> 49#include <net/route.h> 50 51#include <netinet/in.h> 52#include <netinet/in_var.h> 53#ifndef __NetBSD__ 54#include <netinet/if_ether.h> 55#endif 56 57#include <netinet6/ip6.h> 58#include <netinet6/ip6_var.h> 59#include <netinet6/in6_ifattach.h> 60#include <netinet6/ip6.h> 61#include <netinet6/ip6_var.h> 62#include <netinet6/nd6.h> 63 64#include <net/net_osdep.h> 65 66static struct in6_addr llsol; 67 68struct in6_ifstat **in6_ifstat = NULL; 69struct icmp6_ifstat **icmp6_ifstat = NULL; 70size_t in6_ifstatmax = 0; 71size_t icmp6_ifstatmax = 0; 72unsigned long in6_maxmtu = 0; 73 74int found_first_ifid = 0; 75#define IFID_LEN 8 76static char first_ifid[IFID_LEN]; 77 78static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t)); 79static int gen_rand_eui64 __P((u_int8_t *)); 80 81static int 82laddr_to_eui64(dst, src, len) 83 u_int8_t *dst; 84 u_int8_t *src; 85 size_t len; 86{ 87 static u_int8_t zero[8]; 88 89 bzero(zero, sizeof(zero)); 90 91 switch (len) { 92 case 6: 93 if (bcmp(zero, src, 6) == 0) 94 return EINVAL; 95 dst[0] = src[0]; 96 dst[1] = src[1]; 97 dst[2] = src[2]; 98 dst[3] = 0xff; 99 dst[4] = 0xfe; 100 dst[5] = src[3]; 101 dst[6] = src[4]; 102 dst[7] = src[5]; 103 break; 104 case 8: 105 if (bcmp(zero, src, 8) == 0) 106 return EINVAL; 107 bcopy(src, dst, len); 108 break; 109 default: 110 return EINVAL; 111 } 112 113 return 0; 114} 115 116/* 117 * Generate a last-resort interface identifier, when the machine has no 118 * IEEE802/EUI64 address sources. 119 * The address should be random, and should not change across reboot. 120 */ 121static int 122gen_rand_eui64(dst) 123 u_int8_t *dst; 124{ 125 MD5_CTX ctxt; 126 u_int8_t digest[16]; 127#ifdef __FreeBSD__ 128 int hostnamelen = strlen(hostname); 129#endif 130 131 /* generate 8bytes of pseudo-random value. */ 132 bzero(&ctxt, sizeof(ctxt)); 133 MD5Init(&ctxt); 134 MD5Update(&ctxt, hostname, hostnamelen); 135 MD5Final(digest, &ctxt); 136 137 /* assumes sizeof(digest) > sizeof(first_ifid) */ 138 bcopy(digest, dst, 8); 139 140 /* make sure to set "u" bit to local, and "g" bit to individual. */ 141 dst[0] &= 0xfe; 142 dst[0] |= 0x02; /* EUI64 "local" */ 143 144 return 0; 145} 146 147/* 148 * Find first ifid on list of interfaces. 149 * This is assumed that ifp0's interface token (for example, IEEE802 MAC) 150 * is globally unique. We may need to have a flag parameter in the future. 151 */ 152int 153in6_ifattach_getifid(ifp0) 154 struct ifnet *ifp0; 155{ 156 struct ifnet *ifp; 157 struct ifaddr *ifa; 158 u_int8_t *addr = NULL; 159 int addrlen = 0; 160 struct sockaddr_dl *sdl; 161 162 if (found_first_ifid) 163 return 0; 164 165#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 166 for (ifp = ifnet; ifp; ifp = ifp->if_next) 167#else 168 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) 169#endif 170 { 171 if (ifp0 != NULL && ifp0 != ifp) 172 continue; 173#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 174 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 175#else 176 for (ifa = ifp->if_addrlist.tqh_first; 177 ifa; 178 ifa = ifa->ifa_list.tqe_next) 179#endif 180 { 181 if (ifa->ifa_addr->sa_family != AF_LINK) 182 continue; 183 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 184 if (sdl == NULL) 185 continue; 186 if (sdl->sdl_alen == 0) 187 continue; 188 switch (ifp->if_type) { 189 case IFT_ETHER: 190 case IFT_FDDI: 191 case IFT_ATM: 192 /* IEEE802/EUI64 cases - what others? */ 193 addr = LLADDR(sdl); 194 addrlen = sdl->sdl_alen; 195 /* 196 * to copy ifid from IEEE802/EUI64 interface, 197 * u bit of the source needs to be 0. 198 */ 199 if ((addr[0] & 0x02) != 0) 200 break; 201 goto found; 202 case IFT_ARCNET: 203 /* 204 * ARCnet interface token cannot be used as 205 * globally unique identifier due to its 206 * small bitwidth. 207 */ 208 break; 209 default: 210 break; 211 } 212 } 213 } 214#ifdef DEBUG 215 printf("in6_ifattach_getifid: failed to get EUI64"); 216#endif 217 return EADDRNOTAVAIL; 218 219found: 220 if (laddr_to_eui64(first_ifid, addr, addrlen) == 0) 221 found_first_ifid = 1; 222 223 if (found_first_ifid) { 224 printf("%s: supplying EUI64: " 225 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 226 if_name(ifp), 227 first_ifid[0] & 0xff, first_ifid[1] & 0xff, 228 first_ifid[2] & 0xff, first_ifid[3] & 0xff, 229 first_ifid[4] & 0xff, first_ifid[5] & 0xff, 230 first_ifid[6] & 0xff, first_ifid[7] & 0xff); 231 232 /* invert u bit to convert EUI64 to RFC2373 interface ID. */ 233 first_ifid[0] ^= 0x02; 234 235 return 0; 236 } else { 237#ifdef DEBUG 238 printf("in6_ifattach_getifid: failed to get EUI64"); 239#endif 240 return EADDRNOTAVAIL; 241 } 242} 243 244void 245in6_ifattach(ifp, type, laddr, noloop) 246 struct ifnet *ifp; 247 u_int type; 248 caddr_t laddr; 249 /* size_t laddrlen; */ 250 int noloop; 251{ 252 static size_t if_indexlim = 8; 253 struct sockaddr_in6 mltaddr; 254 struct sockaddr_in6 mltmask; 255 struct sockaddr_in6 gate; 256 struct sockaddr_in6 mask; 257#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 258 struct ifaddr **ifap; 259#endif 260 261 struct in6_ifaddr *ia, *ib, *oia; 262 struct ifaddr *ifa; 263 int rtflag = 0; 264 265 if (type == IN6_IFT_P2P && found_first_ifid == 0) { 266 printf("%s: no ifid available for IPv6 link-local address\n", 267 if_name(ifp)); 268#if 0 269 return; 270#else 271 /* last resort */ 272 if (gen_rand_eui64(first_ifid) == 0) { 273 printf("%s: using random value as EUI64: " 274 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 275 if_name(ifp), 276 first_ifid[0] & 0xff, first_ifid[1] & 0xff, 277 first_ifid[2] & 0xff, first_ifid[3] & 0xff, 278 first_ifid[4] & 0xff, first_ifid[5] & 0xff, 279 first_ifid[6] & 0xff, first_ifid[7] & 0xff); 280 /* 281 * invert u bit to convert EUI64 to RFC2373 interface 282 * ID. 283 */ 284 first_ifid[0] ^= 0x02; 285 286 found_first_ifid = 1; 287 } 288#endif 289 } 290 291 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 292 printf("%s: not multicast capable, IPv6 not enabled\n", 293 if_name(ifp)); 294 return; 295 } 296 297 /* 298 * We have some arrays that should be indexed by if_index. 299 * since if_index will grow dynamically, they should grow too. 300 * struct in6_ifstat **in6_ifstat 301 * struct icmp6_ifstat **icmp6_ifstat 302 */ 303 if (in6_ifstat == NULL || icmp6_ifstat == NULL 304 || if_index >= if_indexlim) { 305 size_t n; 306 caddr_t q; 307 size_t olim; 308 309 olim = if_indexlim; 310 while (if_index >= if_indexlim) 311 if_indexlim <<= 1; 312 313 /* grow in6_ifstat */ 314 n = if_indexlim * sizeof(struct in6_ifstat *); 315 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 316 bzero(q, n); 317 if (in6_ifstat) { 318 bcopy((caddr_t)in6_ifstat, q, 319 olim * sizeof(struct in6_ifstat *)); 320 free((caddr_t)in6_ifstat, M_IFADDR); 321 } 322 in6_ifstat = (struct in6_ifstat **)q; 323 in6_ifstatmax = if_indexlim; 324 325 /* grow icmp6_ifstat */ 326 n = if_indexlim * sizeof(struct icmp6_ifstat *); 327 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 328 bzero(q, n); 329 if (icmp6_ifstat) { 330 bcopy((caddr_t)icmp6_ifstat, q, 331 olim * sizeof(struct icmp6_ifstat *)); 332 free((caddr_t)icmp6_ifstat, M_IFADDR); 333 } 334 icmp6_ifstat = (struct icmp6_ifstat **)q; 335 icmp6_ifstatmax = if_indexlim; 336 } 337 338 /* 339 * To prevent to assign link-local address to PnP network 340 * cards multiple times. 341 * This is lengthy for P2P and LOOP but works. 342 */ 343#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 344 ifa = ifp->if_addrlist; 345 if (ifa != NULL) { 346 for ( ; ifa; ifa = ifa->ifa_next) { 347 ifap = &ifa->ifa_next; 348 if (ifa->ifa_addr->sa_family != AF_INET6) 349 continue; 350 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) 351 return; 352 } 353 } else 354 ifap = &ifp->if_addrlist; 355#else 356 ifa = TAILQ_FIRST(&ifp->if_addrlist); 357 if (ifa != NULL) { 358 for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) { 359 if (ifa->ifa_addr->sa_family != AF_INET6) 360 continue; 361 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) 362 return; 363 } 364 } else { 365 TAILQ_INIT(&ifp->if_addrlist); 366 } 367#endif 368 369 /* 370 * link-local address 371 */ 372 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 373 bzero((caddr_t)ia, sizeof(*ia)); 374 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 375 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 376 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 377 ia->ia_ifp = ifp; 378#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 379 *ifap = (struct ifaddr *)ia; 380#else 381 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 382#endif 383 /* 384 * Also link into the IPv6 address chain beginning with in6_ifaddr. 385 * kazu opposed it, but itojun & jinmei wanted. 386 */ 387 if ((oia = in6_ifaddr) != NULL) { 388 for (; oia->ia_next; oia = oia->ia_next) 389 continue; 390 oia->ia_next = ia; 391 } else 392 in6_ifaddr = ia; 393 394 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 395 ia->ia_prefixmask.sin6_family = AF_INET6; 396 ia->ia_prefixmask.sin6_addr = in6mask64; 397 398 bzero(&ia->ia_addr, sizeof(struct sockaddr_in6)); 399 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 400 ia->ia_addr.sin6_family = AF_INET6; 401 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); 402 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 403 ia->ia_addr.sin6_addr.s6_addr32[1] = 0; 404 405 switch (type) { 406 case IN6_IFT_LOOP: 407 ia->ia_addr.sin6_addr.s6_addr32[2] = 0; 408 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1); 409 break; 410 case IN6_IFT_802: 411 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 412 ia->ia_ifa.ifa_flags |= RTF_CLONING; 413 rtflag = RTF_CLONING; 414 /* fall through */ 415 case IN6_IFT_P2P802: 416 if (laddr == NULL) 417 break; 418 /* XXX use laddrlen */ 419 if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], 420 laddr, 6) != 0) { 421 break; 422 } 423 /* invert u bit to convert EUI64 to RFC2373 interface ID. */ 424 ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02; 425 if (found_first_ifid == 0) 426 in6_ifattach_getifid(ifp); 427 bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); 428 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 429 ia->ia_dstaddr.sin6_family = AF_INET6; 430 break; 431 case IN6_IFT_P2P: 432 bcopy((caddr_t)first_ifid, 433 (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8], 434 IFID_LEN); 435 bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); 436 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 437 ia->ia_dstaddr.sin6_family = AF_INET6; 438 break; 439 case IN6_IFT_ARCNET: 440 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 441 ia->ia_ifa.ifa_flags |= RTF_CLONING; 442 rtflag = RTF_CLONING; 443 if (laddr == NULL) 444 break; 445 446 /* make non-global IF id out of link-level address */ 447 bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7); 448 ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr; 449 } 450 451 ia->ia_ifa.ifa_metric = ifp->if_metric; 452 453 if (ifp->if_ioctl != NULL) { 454 int s; 455 int error; 456 457 /* 458 * give the interface a chance to initialize, in case this 459 * is the first address to be added. 460 */ 461 s = splimp(); 462 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 463 splx(s); 464 465 if (error) { 466 switch (error) { 467 case EAFNOSUPPORT: 468 printf("%s: IPv6 not supported\n", 469 if_name(ifp)); 470 break; 471 default: 472 printf("%s: SIOCSIFADDR error %d\n", 473 if_name(ifp), error); 474 break; 475 } 476 477 /* undo changes */ 478#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 479 *ifap = NULL; 480#else 481 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 482#endif 483 if (oia) 484 oia->ia_next = ia->ia_next; 485 else 486 in6_ifaddr = ia->ia_next; 487 free(ia, M_IFADDR); 488 return; 489 } 490 } 491 492 /* add route to the interface. */ 493 rtrequest(RTM_ADD, 494 (struct sockaddr *)&ia->ia_addr, 495 (struct sockaddr *)&ia->ia_addr, 496 (struct sockaddr *)&ia->ia_prefixmask, 497 RTF_UP|rtflag, 498 (struct rtentry **)0); 499 ia->ia_flags |= IFA_ROUTE; 500 501 if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) { 502 /* 503 * route local address to loopback 504 */ 505 bzero(&gate, sizeof(gate)); 506 gate.sin6_len = sizeof(struct sockaddr_in6); 507 gate.sin6_family = AF_INET6; 508 gate.sin6_addr = in6addr_loopback; 509 bzero(&mask, sizeof(mask)); 510 mask.sin6_len = sizeof(struct sockaddr_in6); 511 mask.sin6_family = AF_INET6; 512 mask.sin6_addr = in6mask64; 513 rtrequest(RTM_ADD, 514 (struct sockaddr *)&ia->ia_addr, 515 (struct sockaddr *)&gate, 516 (struct sockaddr *)&mask, 517 RTF_UP|RTF_HOST, 518 (struct rtentry **)0); 519 } 520 521 /* 522 * loopback address 523 */ 524 ib = (struct in6_ifaddr *)NULL; 525 if (type == IN6_IFT_LOOP) { 526 ib = (struct in6_ifaddr *) 527 malloc(sizeof(*ib), M_IFADDR, M_WAITOK); 528 bzero((caddr_t)ib, sizeof(*ib)); 529 ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr; 530 ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr; 531 ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask; 532 ib->ia_ifp = ifp; 533 534 ia->ia_next = ib; 535#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 536 ia->ia_ifa.ifa_next = (struct ifaddr *)ib; 537#else 538 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib, 539 ifa_list); 540#endif 541 542 ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 543 ib->ia_prefixmask.sin6_family = AF_INET6; 544 ib->ia_prefixmask.sin6_addr = in6mask128; 545 ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 546 ib->ia_addr.sin6_family = AF_INET6; 547 ib->ia_addr.sin6_addr = in6addr_loopback; 548#ifdef __bsdi__ 549 /* 550 * It is necessary to set the loopback address to the dstaddr 551 * field at least for BSDI. Without this setting, the BSDI 552 * version of ifa_ifwithroute() rejects to add a route 553 * to the loopback interface. 554 */ 555 ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 556 ib->ia_dstaddr.sin6_family = AF_INET6; 557 ib->ia_dstaddr.sin6_addr = in6addr_loopback; 558#endif 559 560 ib->ia_ifa.ifa_metric = ifp->if_metric; 561 562 rtrequest(RTM_ADD, 563 (struct sockaddr *)&ib->ia_addr, 564 (struct sockaddr *)&ib->ia_addr, 565 (struct sockaddr *)&ib->ia_prefixmask, 566 RTF_UP|RTF_HOST, 567 (struct rtentry **)0); 568 569 ib->ia_flags |= IFA_ROUTE; 570 } 571 572 /* 573 * join multicast 574 */ 575 if (ifp->if_flags & IFF_MULTICAST) { 576 int error; /* not used */ 577 578#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) 579 /* Restore saved multicast addresses(if any). */ 580 in6_restoremkludge(ia, ifp); 581#endif 582 583 bzero(&mltmask, sizeof(mltmask)); 584 mltmask.sin6_len = sizeof(struct sockaddr_in6); 585 mltmask.sin6_family = AF_INET6; 586 mltmask.sin6_addr = in6mask32; 587 588 /* 589 * join link-local all-nodes address 590 */ 591 bzero(&mltaddr, sizeof(mltaddr)); 592 mltaddr.sin6_len = sizeof(struct sockaddr_in6); 593 mltaddr.sin6_family = AF_INET6; 594 mltaddr.sin6_addr = in6addr_linklocal_allnodes; 595 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 596 rtrequest(RTM_ADD, 597 (struct sockaddr *)&mltaddr, 598 (struct sockaddr *)&ia->ia_addr, 599 (struct sockaddr *)&mltmask, 600 RTF_UP|RTF_CLONING, /* xxx */ 601 (struct rtentry **)0); 602 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 603 604 if (type == IN6_IFT_LOOP) { 605 /* 606 * join node-local all-nodes address 607 */ 608 mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 609 rtrequest(RTM_ADD, 610 (struct sockaddr *)&mltaddr, 611 (struct sockaddr *)&ib->ia_addr, 612 (struct sockaddr *)&mltmask, 613 RTF_UP, 614 (struct rtentry **)0); 615 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 616 } else { 617 /* 618 * join solicited multicast address 619 */ 620 bzero(&llsol, sizeof(llsol)); 621 llsol.s6_addr16[0] = htons(0xff02); 622 llsol.s6_addr16[1] = htons(ifp->if_index); 623 llsol.s6_addr32[1] = 0; 624 llsol.s6_addr32[2] = htonl(1); 625 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; 626 llsol.s6_addr8[12] = 0xff; 627 (void)in6_addmulti(&llsol, ifp, &error); 628 } 629 } 630 631 /* update dynamically. */ 632 if (in6_maxmtu < ifp->if_mtu) 633 in6_maxmtu = ifp->if_mtu; 634 635 if (in6_ifstat[ifp->if_index] == NULL) { 636 in6_ifstat[ifp->if_index] = (struct in6_ifstat *) 637 malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK); 638 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat)); 639 } 640 if (icmp6_ifstat[ifp->if_index] == NULL) { 641 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *) 642 malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK); 643 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat)); 644 } 645 646 /* initialize NDP variables */ 647 nd6_ifattach(ifp); 648 649 /* mark the address TENTATIVE, if needed. */ 650 switch (ifp->if_type) { 651 case IFT_ARCNET: 652 case IFT_ETHER: 653 case IFT_FDDI: 654#if 0 655 case IFT_ATM: 656 case IFT_SLIP: 657 case IFT_PPP: 658#endif 659 ia->ia6_flags |= IN6_IFF_TENTATIVE; 660 /* nd6_dad_start() will be called in in6_if_up */ 661 break; 662 case IFT_DUMMY: 663 case IFT_GIF: /*XXX*/ 664 case IFT_LOOP: 665 case IFT_FAITH: 666 default: 667 break; 668 } 669 670 return; 671} 672 673void 674in6_ifdetach(ifp) 675 struct ifnet *ifp; 676{ 677 struct in6_ifaddr *ia, *oia; 678 struct ifaddr *ifa; 679#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 680 struct ifaddr *ifaprev = NULL; 681#endif 682 struct rtentry *rt; 683 short rtflags; 684 685#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 686 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 687#else 688 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) 689#endif 690 { 691 if (ifa->ifa_addr->sa_family != AF_INET6 692 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 693#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 694 ifaprev = ifa; 695#endif 696 continue; 697 } 698 699 ia = (struct in6_ifaddr *)ifa; 700 701 /* remove from the routing table */ 702 if ((ia->ia_flags & IFA_ROUTE) 703 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0 704#ifdef __FreeBSD__ 705 , 0UL 706#endif 707 ))) { 708 rtflags = rt->rt_flags; 709 rtfree(rt); 710 rtrequest(RTM_DELETE, 711 (struct sockaddr *)&ia->ia_addr, 712 (struct sockaddr *)&ia->ia_addr, 713 (struct sockaddr *)&ia->ia_prefixmask, 714 rtflags, (struct rtentry **)0); 715 } 716 717 /* remove from the linked list */ 718#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) 719 if (ifaprev) 720 ifaprev->ifa_next = ifa->ifa_next; 721 else 722 ifp->if_addrlist = ifa->ifa_next; 723#else 724 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 725#endif 726 727 /* also remove from the IPv6 address chain(itojun&jinmei) */ 728 oia = ia; 729 if (oia == (ia = in6_ifaddr)) 730 in6_ifaddr = ia->ia_next; 731 else { 732 while (ia->ia_next && (ia->ia_next != oia)) 733 ia = ia->ia_next; 734 if (ia->ia_next) 735 ia->ia_next = oia->ia_next; 736#ifdef DEBUG 737 else 738 printf("%s: didn't unlink in6ifaddr from " 739 "list\n", if_name(ifp)); 740#endif 741 } 742 743 free(ia, M_IFADDR); 744 } 745} 746