1 /* $KAME: in6_ifattach.c,v 1.41 2000/03/16 07:05:34 jinmei Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
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>
39 #include <crypto/md5.h>
40 #elif defined(__OpenBSD__)
47 #include <net/if_dl.h>
48 #include <net/if_types.h>
49 #include <net/route.h>
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
54 #include <netinet/if_ether.h>
57 #include <netinet/ip6.h>
58 #include <netinet6/ip6_var.h>
59 #include <netinet6/in6_ifattach.h>
60 #include <netinet6/ip6_var.h>
61 #include <netinet6/nd6.h>
63 #include <net/net_osdep.h>
65 static struct in6_addr llsol
;
67 struct in6_ifstat
**in6_ifstat
= NULL
;
68 struct icmp6_ifstat
**icmp6_ifstat
= NULL
;
69 size_t in6_ifstatmax
= 0;
70 size_t icmp6_ifstatmax
= 0;
71 unsigned long in6_maxmtu
= 0;
73 int found_first_ifid
= 0;
75 static u_int8_t first_ifid
[IFID_LEN
];
77 static int laddr_to_eui64
__P((u_int8_t
*, u_int8_t
*, size_t));
78 static int gen_rand_eui64
__P((u_int8_t
*));
83 laddr_to_eui64(dst
, src
, len
)
88 static u_int8_t zero
[8];
90 bzero(zero
, sizeof(zero
));
94 if (bcmp(zero
, src
, 6) == 0)
106 if (bcmp(zero
, src
, 8) == 0)
108 bcopy(src
, dst
, len
);
118 * Generate a last-resort interface identifier, when the machine has no
119 * IEEE802/EUI64 address sources.
120 * The address should be random, and should not change across reboot.
128 #if defined(__FreeBSD__) || defined (__APPLE__)
129 int hostnamelen
= strlen(hostname
);
132 /* generate 8bytes of pseudo-random value. */
133 bzero(&ctxt
, sizeof(ctxt
));
135 MD5Update(&ctxt
, hostname
, hostnamelen
);
136 MD5Final(digest
, &ctxt
);
138 /* assumes sizeof(digest) > sizeof(first_ifid) */
139 bcopy(digest
, dst
, 8);
141 /* make sure to set "u" bit to local, and "g" bit to individual. */
143 dst
[0] |= 0x02; /* EUI64 "local" */
149 * Find first ifid on list of interfaces.
150 * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
151 * is globally unique. We may need to have a flag parameter in the future.
154 in6_ifattach_getifid(ifp0
)
159 u_int8_t
*addr
= NULL
;
161 struct sockaddr_dl
*sdl
;
163 if (found_first_ifid
)
166 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
167 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
169 for (ifp
= ifnet
.tqh_first
; ifp
; ifp
= ifp
->if_list
.tqe_next
)
172 if (ifp0
!= NULL
&& ifp0
!= ifp
)
174 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
175 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
177 for (ifa
= ifp
->if_addrlist
.tqh_first
;
179 ifa
= ifa
->ifa_list
.tqe_next
)
182 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
184 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
187 if (sdl
->sdl_alen
== 0)
189 switch (ifp
->if_type
) {
193 /* IEEE802/EUI64 cases - what others? */
195 addrlen
= sdl
->sdl_alen
;
197 * to copy ifid from IEEE802/EUI64 interface,
198 * u bit of the source needs to be 0.
200 if ((addr
[0] & 0x02) != 0)
205 * ARCnet interface token cannot be used as
206 * globally unique identifier due to its
216 printf("in6_ifattach_getifid: failed to get EUI64");
218 return EADDRNOTAVAIL
;
221 if (laddr_to_eui64(first_ifid
, addr
, addrlen
) == 0)
222 found_first_ifid
= 1;
224 if (found_first_ifid
) {
225 printf("%s: supplying EUI64: "
226 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
228 first_ifid
[0] & 0xff, first_ifid
[1] & 0xff,
229 first_ifid
[2] & 0xff, first_ifid
[3] & 0xff,
230 first_ifid
[4] & 0xff, first_ifid
[5] & 0xff,
231 first_ifid
[6] & 0xff, first_ifid
[7] & 0xff);
233 /* invert u bit to convert EUI64 to RFC2373 interface ID. */
234 first_ifid
[0] ^= 0x02;
239 printf("in6_ifattach_getifid: failed to get EUI64");
241 return EADDRNOTAVAIL
;
246 * XXX multiple loopback interface needs more care. for instance,
247 * nodelocal address needs to be configured onto only one of them.
250 in6_ifattach(ifp
, type
, laddr
, noloop
)
254 /* size_t laddrlen; */
257 static size_t if_indexlim
= 8;
258 struct sockaddr_in6 mltaddr
;
259 struct sockaddr_in6 mltmask
;
260 struct sockaddr_in6 gate
;
261 struct sockaddr_in6 mask
;
262 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
263 struct ifaddr
**ifap
;
266 struct in6_ifaddr
*ia
, *ib
, *oia
;
272 if (type
== IN6_IFT_P2P
&& found_first_ifid
== 0) {
273 printf("%s: no ifid available for IPv6 link-local address\n",
279 if (gen_rand_eui64(first_ifid
) == 0) {
280 printf("%s: using random value as EUI64: "
281 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
283 first_ifid
[0] & 0xff, first_ifid
[1] & 0xff,
284 first_ifid
[2] & 0xff, first_ifid
[3] & 0xff,
285 first_ifid
[4] & 0xff, first_ifid
[5] & 0xff,
286 first_ifid
[6] & 0xff, first_ifid
[7] & 0xff);
288 * invert u bit to convert EUI64 to RFC2373 interface
291 first_ifid
[0] ^= 0x02;
293 found_first_ifid
= 1;
298 if ((ifp
->if_flags
& IFF_MULTICAST
) == 0) {
299 printf("%s: not multicast capable, IPv6 not enabled\n",
305 * We have some arrays that should be indexed by if_index.
306 * since if_index will grow dynamically, they should grow too.
307 * struct in6_ifstat **in6_ifstat
308 * struct icmp6_ifstat **icmp6_ifstat
310 if (in6_ifstat
== NULL
|| icmp6_ifstat
== NULL
311 || if_index
>= if_indexlim
) {
317 while (if_index
>= if_indexlim
)
320 /* grow in6_ifstat */
321 n
= if_indexlim
* sizeof(struct in6_ifstat
*);
322 q
= (caddr_t
)_MALLOC(n
, M_IFADDR
, M_WAITOK
);
325 bcopy((caddr_t
)in6_ifstat
, q
,
326 olim
* sizeof(struct in6_ifstat
*));
327 _FREE((caddr_t
)in6_ifstat
, M_IFADDR
);
329 in6_ifstat
= (struct in6_ifstat
**)q
;
330 in6_ifstatmax
= if_indexlim
;
332 /* grow icmp6_ifstat */
333 n
= if_indexlim
* sizeof(struct icmp6_ifstat
*);
334 q
= (caddr_t
)_MALLOC(n
, M_IFADDR
, M_WAITOK
);
337 bcopy((caddr_t
)icmp6_ifstat
, q
,
338 olim
* sizeof(struct icmp6_ifstat
*));
339 _FREE((caddr_t
)icmp6_ifstat
, M_IFADDR
);
341 icmp6_ifstat
= (struct icmp6_ifstat
**)q
;
342 icmp6_ifstatmax
= if_indexlim
;
346 * To prevent to assign link-local address to PnP network
347 * cards multiple times.
348 * This is lengthy for P2P and LOOP but works.
350 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
351 ifa
= ifp
->if_addrlist
;
353 for ( ; ifa
; ifa
= ifa
->ifa_next
) {
354 ifap
= &ifa
->ifa_next
;
355 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
357 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa
->ifa_addr
)->sin6_addr
))
361 ifap
= &ifp
->if_addrlist
;
363 ifa
= TAILQ_FIRST(&ifp
->if_addrlist
);
365 for ( ; ifa
; ifa
= TAILQ_NEXT(ifa
, ifa_list
)) {
366 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
368 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa
->ifa_addr
)->sin6_addr
))
372 TAILQ_INIT(&ifp
->if_addrlist
);
379 ia
= (struct in6_ifaddr
*)_MALLOC(sizeof(*ia
), M_IFADDR
, M_WAITOK
);
380 bzero((caddr_t
)ia
, sizeof(*ia
));
381 ia
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&ia
->ia_addr
;
382 if (ifp
->if_flags
& IFF_POINTOPOINT
)
383 ia
->ia_ifa
.ifa_dstaddr
= (struct sockaddr
*)&ia
->ia_dstaddr
;
385 ia
->ia_ifa
.ifa_dstaddr
= NULL
;
386 ia
->ia_ifa
.ifa_netmask
= (struct sockaddr
*)&ia
->ia_prefixmask
;
388 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
389 *ifap
= (struct ifaddr
*)ia
;
391 TAILQ_INSERT_TAIL(&ifp
->if_addrlist
, (struct ifaddr
*)ia
, ifa_list
);
393 ia
->ia_ifa
.ifa_refcnt
++;
396 * Also link into the IPv6 address chain beginning with in6_ifaddr.
397 * kazu opposed it, but itojun & jinmei wanted.
399 if ((oia
= in6_ifaddr
) != NULL
) {
400 for (; oia
->ia_next
; oia
= oia
->ia_next
)
405 ia
->ia_ifa
.ifa_refcnt
++;
407 ia
->ia_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
408 ia
->ia_prefixmask
.sin6_family
= AF_INET6
;
409 ia
->ia_prefixmask
.sin6_addr
= in6mask64
;
411 bzero(&ia
->ia_addr
, sizeof(struct sockaddr_in6
));
412 ia
->ia_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
413 ia
->ia_addr
.sin6_family
= AF_INET6
;
414 ia
->ia_addr
.sin6_addr
.s6_addr16
[0] = htons(0xfe80);
415 ia
->ia_addr
.sin6_addr
.s6_addr16
[1] = htons(ifp
->if_index
);
416 ia
->ia_addr
.sin6_addr
.s6_addr32
[1] = 0;
420 ia
->ia_addr
.sin6_addr
.s6_addr32
[2] = 0;
421 ia
->ia_addr
.sin6_addr
.s6_addr32
[3] = htonl(1);
422 if (strcmp(ifp
->if_name
, "lo") == 0) {
423 ia
->ia_ifa
.ifa_dlt
= lo_attach_inet(ifp
);
424 printf("in6_ifattach: IFT_LOOP setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n",
425 ifp
->if_name
, ifp
->if_unit
, ia
, ia
->ia_ifa
.ifa_dlt
);
429 ia
->ia_ifa
.ifa_rtrequest
= nd6_rtrequest
;
430 ia
->ia_ifa
.ifa_flags
|= RTF_CLONING
;
431 rtflag
= RTF_CLONING
;
432 if (strcmp(ifp
->if_name
, "en") == 0) {
433 ia
->ia_ifa
.ifa_dlt
= ether_attach_inet6(ifp
);
434 printf("in6_ifattach: IFT_802 setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n",
435 ifp
->if_name
, ifp
->if_unit
, ia
, ia
->ia_ifa
.ifa_dlt
);
440 ia
->ia_ifa
.ifa_rtrequest
= nd6_rtrequest
;
441 ia
->ia_ifa
.ifa_flags
|= RTF_CLONING
;
442 rtflag
= RTF_CLONING
;
445 /* XXX use laddrlen */
446 if (laddr_to_eui64(&ia
->ia_addr
.sin6_addr
.s6_addr8
[8],
450 /* invert u bit to convert EUI64 to RFC2373 interface ID. */
451 ia
->ia_addr
.sin6_addr
.s6_addr8
[8] ^= 0x02;
452 if (found_first_ifid
== 0)
453 in6_ifattach_getifid(ifp
);
454 bzero(&ia
->ia_dstaddr
, sizeof(struct sockaddr_in6
));
455 ia
->ia_dstaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
456 ia
->ia_dstaddr
.sin6_family
= AF_INET6
;
458 if (ia
->ia_ifa
.ifa_dlt
== 0) {
459 ia
->ia_ifa
.ifa_dlt
= ifp
;
461 printf("in6_ifattach: IFT_P2P802 setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n",
462 ifp
->if_name
, ifp
->if_unit
, ia
, ia
->ia_ifa
.ifa_dlt
);
467 ia
->ia_ifa
.ifa_rtrequest
= nd6_rtrequest
;
468 ia
->ia_ifa
.ifa_flags
|= RTF_CLONING
;
469 rtflag
= RTF_CLONING
;
470 bcopy((caddr_t
)first_ifid
,
471 (caddr_t
)&ia
->ia_addr
.sin6_addr
.s6_addr8
[8],
473 bzero(&ia
->ia_dstaddr
, sizeof(struct sockaddr_in6
));
474 ia
->ia_dstaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
475 ia
->ia_dstaddr
.sin6_family
= AF_INET6
;
477 if (strcmp(ifp
->if_name
, "gif") == 0) {
478 ia
->ia_ifa
.ifa_dlt
= gif_attach_inet(ifp
);
480 printf("in6_ifattach: IFT_P2P setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n",
481 ifp
->if_name
, ifp
->if_unit
, ia
, ia
->ia_ifa
.ifa_dlt
);
487 ia
->ia_ifa
.ifa_rtrequest
= nd6_rtrequest
;
488 ia
->ia_ifa
.ifa_flags
|= RTF_CLONING
;
489 rtflag
= RTF_CLONING
;
493 /* make non-global IF id out of link-level address */
494 bzero(&ia
->ia_addr
.sin6_addr
.s6_addr8
[8], 7);
495 ia
->ia_addr
.sin6_addr
.s6_addr8
[15] = *laddr
;
496 ia
->ia_ifa
.ifa_dlt
= ifp
;
498 printf("in6_ifattach: IFT_ARCNET setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n",
499 ifp
->if_name
, ifp
->if_unit
, ia
, ia
->ia_ifa
.ifa_dlt
);
503 ia
->ia_ifa
.ifa_metric
= ifp
->if_metric
;
507 * give the interface a chance to initialize, in case this
508 * is the first address to be added.
512 error
= dlil_ioctl(0, ifp
, SIOCSIFADDR
, (caddr_t
)ia
);
514 error
= (*ifp
->if_ioctl
)(ifp
, SIOCSIFADDR
, (caddr_t
)ia
);
518 printf("in6_ifattach: Calling SIOCSIFADDR for if=%s%d ia=%x error=%x\n", ifp
->if_name
, ifp
->if_unit
, ia
, error
);
520 if (error
== EOPNOTSUPP
)
526 printf("%s: IPv6 not supported\n",
530 printf("%s: SIOCSIFADDR error %d\n",
531 if_name(ifp
), error
);
536 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
539 TAILQ_REMOVE(&ifp
->if_addrlist
, (struct ifaddr
*)ia
, ifa_list
);
541 IFAFREE(&ia
->ia_ifa
);
543 oia
->ia_next
= ia
->ia_next
;
545 in6_ifaddr
= ia
->ia_next
;
546 IFAFREE(&ia
->ia_ifa
);
550 /* add route to the interface. */
552 (struct sockaddr
*)&ia
->ia_addr
,
553 (struct sockaddr
*)&ia
->ia_addr
,
554 (struct sockaddr
*)&ia
->ia_prefixmask
,
556 (struct rtentry
**)0);
557 ia
->ia_flags
|= IFA_ROUTE
;
559 if (type
== IN6_IFT_P2P
|| type
== IN6_IFT_P2P802
) {
561 * route local address to loopback
563 bzero(&gate
, sizeof(gate
));
564 gate
.sin6_len
= sizeof(struct sockaddr_in6
);
565 gate
.sin6_family
= AF_INET6
;
566 gate
.sin6_addr
= in6addr_loopback
;
567 bzero(&mask
, sizeof(mask
));
568 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
569 mask
.sin6_family
= AF_INET6
;
570 mask
.sin6_addr
= in6mask64
;
572 (struct sockaddr
*)&ia
->ia_addr
,
573 (struct sockaddr
*)&gate
,
574 (struct sockaddr
*)&mask
,
576 (struct rtentry
**)0);
582 ib
= (struct in6_ifaddr
*)NULL
;
583 if (type
== IN6_IFT_LOOP
) {
584 ib
= (struct in6_ifaddr
*)
585 _MALLOC(sizeof(*ib
), M_IFADDR
, M_WAITOK
);
586 bzero((caddr_t
)ib
, sizeof(*ib
));
587 ib
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&ib
->ia_addr
;
588 ib
->ia_ifa
.ifa_dstaddr
= (struct sockaddr
*)&ib
->ia_dstaddr
;
589 ib
->ia_ifa
.ifa_netmask
= (struct sockaddr
*)&ib
->ia_prefixmask
;
590 ib
->ia_ifa
.ifa_dlt
= lo_attach_inet(ifp
);
594 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
595 ia
->ia_ifa
.ifa_next
= (struct ifaddr
*)ib
;
597 TAILQ_INSERT_TAIL(&ifp
->if_addrlist
, (struct ifaddr
*)ib
,
600 ib
->ia_ifa
.ifa_refcnt
++;
602 ib
->ia_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
603 ib
->ia_prefixmask
.sin6_family
= AF_INET6
;
604 ib
->ia_prefixmask
.sin6_addr
= in6mask128
;
605 ib
->ia_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
606 ib
->ia_addr
.sin6_family
= AF_INET6
;
607 ib
->ia_addr
.sin6_addr
= in6addr_loopback
;
610 * Always initialize ia_dstaddr (= broadcast address)
611 * to loopback address, to make getifaddr happier.
613 * For BSDI, it is mandatory. The BSDI version of
614 * ifa_ifwithroute() rejects to add a route to the loopback
615 * interface. Even for other systems, loopback looks somewhat
618 ib
->ia_dstaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
619 ib
->ia_dstaddr
.sin6_family
= AF_INET6
;
620 ib
->ia_dstaddr
.sin6_addr
= in6addr_loopback
;
622 ib
->ia_ifa
.ifa_metric
= ifp
->if_metric
;
625 (struct sockaddr
*)&ib
->ia_addr
,
626 (struct sockaddr
*)&ib
->ia_addr
,
627 (struct sockaddr
*)&ib
->ia_prefixmask
,
629 (struct rtentry
**)0);
631 ib
->ia_flags
|= IFA_ROUTE
;
637 if (ifp
->if_flags
& IFF_MULTICAST
) {
638 int error
; /* not used */
640 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__)
641 /* Restore saved multicast addresses(if any). */
642 in6_restoremkludge(ia
, ifp
);
645 bzero(&mltmask
, sizeof(mltmask
));
646 mltmask
.sin6_len
= sizeof(struct sockaddr_in6
);
647 mltmask
.sin6_family
= AF_INET6
;
648 mltmask
.sin6_addr
= in6mask32
;
651 * join link-local all-nodes address
653 bzero(&mltaddr
, sizeof(mltaddr
));
654 mltaddr
.sin6_len
= sizeof(struct sockaddr_in6
);
655 mltaddr
.sin6_family
= AF_INET6
;
656 mltaddr
.sin6_addr
= in6addr_linklocal_allnodes
;
657 mltaddr
.sin6_addr
.s6_addr16
[1] = htons(ifp
->if_index
);
659 (struct sockaddr
*)&mltaddr
,
660 (struct sockaddr
*)&ia
->ia_addr
,
661 (struct sockaddr
*)&mltmask
,
662 RTF_UP
|RTF_CLONING
, /* xxx */
663 (struct rtentry
**)0);
664 (void)in6_addmulti(&mltaddr
.sin6_addr
, ifp
, &error
);
666 if (type
== IN6_IFT_LOOP
) {
668 * join node-local all-nodes address
670 mltaddr
.sin6_addr
= in6addr_nodelocal_allnodes
;
672 (struct sockaddr
*)&mltaddr
,
673 (struct sockaddr
*)&ib
->ia_addr
,
674 (struct sockaddr
*)&mltmask
,
676 (struct rtentry
**)0);
677 (void)in6_addmulti(&mltaddr
.sin6_addr
, ifp
, &error
);
680 * join solicited multicast address
682 bzero(&llsol
, sizeof(llsol
));
683 llsol
.s6_addr16
[0] = htons(0xff02);
684 llsol
.s6_addr16
[1] = htons(ifp
->if_index
);
685 llsol
.s6_addr32
[1] = 0;
686 llsol
.s6_addr32
[2] = htonl(1);
687 llsol
.s6_addr32
[3] = ia
->ia_addr
.sin6_addr
.s6_addr32
[3];
688 llsol
.s6_addr8
[12] = 0xff;
689 (void)in6_addmulti(&llsol
, ifp
, &error
);
693 /* update dynamically. */
694 if (in6_maxmtu
< ifp
->if_mtu
)
695 in6_maxmtu
= ifp
->if_mtu
;
697 if (in6_ifstat
[ifp
->if_index
] == NULL
) {
698 in6_ifstat
[ifp
->if_index
] = (struct in6_ifstat
*)
699 _MALLOC(sizeof(struct in6_ifstat
), M_IFADDR
, M_WAITOK
);
700 bzero(in6_ifstat
[ifp
->if_index
], sizeof(struct in6_ifstat
));
702 if (icmp6_ifstat
[ifp
->if_index
] == NULL
) {
703 icmp6_ifstat
[ifp
->if_index
] = (struct icmp6_ifstat
*)
704 _MALLOC(sizeof(struct icmp6_ifstat
), M_IFADDR
, M_WAITOK
);
705 bzero(icmp6_ifstat
[ifp
->if_index
], sizeof(struct icmp6_ifstat
));
708 /* initialize NDP variables */
711 /* mark the address TENTATIVE, if needed. */
712 switch (ifp
->if_type
) {
721 ia
->ia6_flags
|= IN6_IFF_TENTATIVE
;
722 /* nd6_dad_start() will be called in in6_if_up */
725 case IFT_GIF
: /*XXX*/
736 * NOTE: in6_ifdetach() does not support loopback if at this moment.
742 struct in6_ifaddr
*ia
, *oia
;
744 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
745 struct ifaddr
*ifaprev
= NULL
;
749 struct sockaddr_in6 sin6
;
750 struct in6_multi
*in6m
;
751 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
752 struct in6_multi
*in6m_next
;
755 /* nuke prefix list. this may try to remove some of ifaddrs as well */
756 in6_purgeprefix(ifp
);
758 /* remove neighbor management table */
761 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
762 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
764 for (ifa
= ifp
->if_addrlist
.tqh_first
; ifa
; ifa
= ifa
->ifa_list
.tqe_next
)
767 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
768 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa
->ifa_addr
)->sin6_addr
)) {
769 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
775 ia
= (struct in6_ifaddr
*)ifa
;
777 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__)
778 /* leave from all multicast groups joined */
779 while ((in6m
= LIST_FIRST(&oia
->ia6_multiaddrs
)) != NULL
)
783 /* remove from the routing table */
784 if ((ia
->ia_flags
& IFA_ROUTE
)
785 && (rt
= rtalloc1((struct sockaddr
*)&ia
->ia_addr
, 0
786 #if defined (__FreeBSD__) || defined (__APPLE__)
790 rtflags
= rt
->rt_flags
;
792 rtrequest(RTM_DELETE
,
793 (struct sockaddr
*)&ia
->ia_addr
,
794 (struct sockaddr
*)&ia
->ia_addr
,
795 (struct sockaddr
*)&ia
->ia_prefixmask
,
796 rtflags
, (struct rtentry
**)0);
799 /* remove from the linked list */
800 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
802 ifaprev
->ifa_next
= ifa
->ifa_next
;
804 ifp
->if_addrlist
= ifa
->ifa_next
;
806 TAILQ_REMOVE(&ifp
->if_addrlist
, (struct ifaddr
*)ia
, ifa_list
);
809 /* also remove from the IPv6 address chain(itojun&jinmei) */
811 if (oia
== (ia
= in6_ifaddr
))
812 in6_ifaddr
= ia
->ia_next
;
814 while (ia
->ia_next
&& (ia
->ia_next
!= oia
))
817 ia
->ia_next
= oia
->ia_next
;
820 printf("%s: didn't unlink in6ifaddr from "
821 "list\n", if_name(ifp
));
828 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
829 /* leave from all multicast groups joined */
830 for (in6m
= LIST_FIRST(&in6_multihead
); in6m
; in6m
= in6m_next
) {
831 in6m_next
= LIST_NEXT(in6m
, in6m_entry
);
832 if (in6m
->in6m_ifp
!= ifp
)
839 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
840 /* cleanup multicast address kludge table, if there is any */
841 in6_purgemkludge(ifp
);
844 /* remove neighbor management table */
847 /* remove route to link-local allnodes multicast (ff02::1) */
848 bzero(&sin6
, sizeof(sin6
));
849 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
850 sin6
.sin6_family
= AF_INET6
;
851 sin6
.sin6_addr
= in6addr_linklocal_allnodes
;
852 sin6
.sin6_addr
.s6_addr16
[1] = htons(ifp
->if_index
);
853 #if !defined(__FreeBSD__) && !defined (__APPLE__)
854 if ((rt
= rtalloc1((struct sockaddr
*)&sin6
, 0)) != NULL
)
856 if ((rt
= rtalloc1((struct sockaddr
*)&sin6
, 0, 0UL)) != NULL
)
859 rtrequest(RTM_DELETE
, (struct sockaddr
*)rt_key(rt
),
860 rt
->rt_gateway
, rt_mask(rt
), rt
->rt_flags
, 0);