in6_ifattach.c revision 1.75
1/*	$OpenBSD: in6_ifattach.c,v 1.75 2014/11/18 02:37:31 tedu 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/socket.h>
36#include <sys/sockio.h>
37#include <sys/kernel.h>
38#include <sys/syslog.h>
39
40#include <crypto/md5.h>
41
42#include <net/if.h>
43#include <net/if_var.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/if_ether.h>
50
51#include <netinet6/in6_var.h>
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#ifdef MROUTING
58#include <netinet6/ip6_mroute.h>
59#endif
60
61unsigned long in6_maxmtu = 0;
62
63int ip6_auto_linklocal = 1;	/* enable by default */
64
65int get_last_resort_ifid(struct ifnet *, struct in6_addr *);
66int get_hw_ifid(struct ifnet *, struct in6_addr *);
67int get_ifid(struct ifnet *, struct in6_addr *);
68int in6_ifattach_loopback(struct ifnet *);
69
70#define EUI64_GBIT	0x01
71#define EUI64_UBIT	0x02
72#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
73#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
74#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
75#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
76#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
77
78#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
79#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
80
81/*
82 * Generate a last-resort interface identifier, when the machine has no
83 * IEEE802/EUI64 address sources.
84 * The goal here is to get an interface identifier that is
85 * (1) random enough and (2) does not change across reboot.
86 * We currently use MD5(hostname) for it.
87 *
88 * in6 - upper 64bits are preserved
89 */
90int
91get_last_resort_ifid(struct ifnet *ifp, struct in6_addr *in6)
92{
93	MD5_CTX ctxt;
94	u_int8_t digest[16];
95
96#if 0
97	/* we need at least several letters as seed for ifid */
98	if (hostnamelen < 3)
99		return -1;
100#endif
101
102	/* generate 8 bytes of pseudo-random value. */
103	bzero(&ctxt, sizeof(ctxt));
104	MD5Init(&ctxt);
105	MD5Update(&ctxt, hostname, hostnamelen);
106	MD5Final(digest, &ctxt);
107
108	/* assumes sizeof(digest) > sizeof(ifid) */
109	bcopy(digest, &in6->s6_addr[8], 8);
110
111	/* make sure to set "u" bit to local, and "g" bit to individual. */
112	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
113	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
114
115	/* convert EUI64 into IPv6 interface identifier */
116	EUI64_TO_IFID(in6);
117
118	return 0;
119}
120
121/*
122 * Generate a random interface identifier.
123 *
124 * in6 - upper 64bits are preserved
125 */
126void
127in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
128{
129	arc4random_buf(&in6->s6_addr32[2], 8);
130
131	/* make sure to set "u" bit to local, and "g" bit to individual. */
132	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
133	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
134
135	/* convert EUI64 into IPv6 interface identifier */
136	EUI64_TO_IFID(in6);
137}
138
139/*
140 * Get interface identifier for the specified interface.
141 *
142 * in6 - upper 64bits are preserved
143 */
144int
145get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
146{
147	struct sockaddr_dl *sdl;
148	char *addr;
149	size_t addrlen;
150	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
151	static u_int8_t allone[8] =
152		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
153
154	sdl = (struct sockaddr_dl *)ifp->if_sadl;
155	if (sdl == NULL || sdl->sdl_alen == 0)
156		return -1;
157
158	addr = LLADDR(sdl);
159	addrlen = sdl->sdl_alen;
160
161	switch (ifp->if_type) {
162	case IFT_IEEE1394:
163	case IFT_IEEE80211:
164		/* IEEE1394 uses 16byte length address starting with EUI64 */
165		if (addrlen > 8)
166			addrlen = 8;
167		break;
168	default:
169		break;
170	}
171
172	/* get EUI64 */
173	switch (ifp->if_type) {
174	/* IEEE802/EUI64 cases - what others? */
175	case IFT_ETHER:
176	case IFT_CARP:
177	case IFT_IEEE1394:
178	case IFT_IEEE80211:
179		/* look at IEEE802/EUI64 only */
180		if (addrlen != 8 && addrlen != 6)
181			return -1;
182
183		/*
184		 * check for invalid MAC address - on bsdi, we see it a lot
185		 * since wildboar configures all-zero MAC on pccard before
186		 * card insertion.
187		 */
188		if (bcmp(addr, allzero, addrlen) == 0)
189			return -1;
190		if (bcmp(addr, allone, addrlen) == 0)
191			return -1;
192
193		/* make EUI64 address */
194		if (addrlen == 8)
195			bcopy(addr, &in6->s6_addr[8], 8);
196		else if (addrlen == 6) {
197			in6->s6_addr[8] = addr[0];
198			in6->s6_addr[9] = addr[1];
199			in6->s6_addr[10] = addr[2];
200			in6->s6_addr[11] = 0xff;
201			in6->s6_addr[12] = 0xfe;
202			in6->s6_addr[13] = addr[3];
203			in6->s6_addr[14] = addr[4];
204			in6->s6_addr[15] = addr[5];
205		}
206		break;
207
208	case IFT_GIF:
209		/*
210		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
211		 * however, IPv4 address is not very suitable as unique
212		 * identifier source (can be renumbered).
213		 * we don't do this.
214		 */
215		return -1;
216
217	default:
218		return -1;
219	}
220
221	/* sanity check: g bit must not indicate "group" */
222	if (EUI64_GROUP(in6))
223		return -1;
224
225	/* convert EUI64 into IPv6 interface identifier */
226	EUI64_TO_IFID(in6);
227
228	/*
229	 * sanity check: ifid must not be all zero, avoid conflict with
230	 * subnet router anycast
231	 */
232	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
233	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
234		return -1;
235	}
236
237	return 0;
238}
239
240/*
241 * Get interface identifier for the specified interface.  If it is not
242 * available on ifp0, borrow interface identifier from other information
243 * sources.
244 */
245int
246get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
247{
248	struct ifnet *ifp;
249
250	/* first, try to get it from the interface itself */
251	if (get_hw_ifid(ifp0, in6) == 0) {
252		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
253		    ifp0->if_xname));
254		goto success;
255	}
256
257	/* next, try to get it from some other hardware interface */
258	TAILQ_FOREACH(ifp, &ifnet, if_list) {
259		if (ifp == ifp0)
260			continue;
261		if (get_hw_ifid(ifp, in6) != 0)
262			continue;
263
264		/*
265		 * to borrow ifid from other interface, ifid needs to be
266		 * globally unique
267		 */
268		if (IFID_UNIVERSAL(in6)) {
269			nd6log((LOG_DEBUG,
270			    "%s: borrow interface identifier from %s\n",
271			    ifp0->if_xname, ifp->if_xname));
272			goto success;
273		}
274	}
275
276	/* last resort: get from random number source */
277	if (get_last_resort_ifid(ifp, in6) == 0) {
278		nd6log((LOG_DEBUG,
279		    "%s: interface identifier generated by random number\n",
280		    ifp0->if_xname));
281		goto success;
282	}
283
284	printf("%s: failed to get interface identifier\n", ifp0->if_xname);
285	return -1;
286
287success:
288	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
289	    ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
290	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
291	    in6->s6_addr[14], in6->s6_addr[15]));
292	return 0;
293}
294
295/*
296 * ifid - used as EUI64 if not NULL, overrides other EUI64 sources
297 */
298
299int
300in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
301{
302	struct in6_ifaddr *ia6;
303	struct in6_aliasreq ifra;
304	struct nd_prefix pr0;
305	int i, s, error;
306
307	/*
308	 * configure link-local address.
309	 */
310	bzero(&ifra, sizeof(ifra));
311
312	/*
313	 * in6_update_ifa() does not use ifra_name, but we accurately set it
314	 * for safety.
315	 */
316	strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
317
318	ifra.ifra_addr.sin6_family = AF_INET6;
319	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
320	ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
321	ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
322	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
323	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
324		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
325		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
326	} else if (ifid) {
327		ifra.ifra_addr.sin6_addr = *ifid;
328		ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
329		ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
330		ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
331		ifra.ifra_addr.sin6_addr.s6_addr[8] &= ~EUI64_GBIT;
332		ifra.ifra_addr.sin6_addr.s6_addr[8] |= EUI64_UBIT;
333	} else {
334		if (get_ifid(ifp, &ifra.ifra_addr.sin6_addr) != 0) {
335			nd6log((LOG_ERR,
336			    "%s: no ifid available\n", ifp->if_xname));
337			return (-1);
338		}
339	}
340
341	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
342	ifra.ifra_prefixmask.sin6_family = AF_INET6;
343	ifra.ifra_prefixmask.sin6_addr = in6mask64;
344	/* link-local addresses should NEVER expire. */
345	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
346	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
347
348	/*
349	 * Do not let in6_update_ifa() do DAD, since we need a random delay
350	 * before sending an NS at the first time the interface becomes up.
351	 * Instead, in6_if_up() will start DAD with a proper random delay.
352	 */
353	ifra.ifra_flags |= IN6_IFF_NODAD;
354
355	/*
356	 * Now call in6_update_ifa() to do a bunch of procedures to configure
357	 * a link-local address. In the case of CARP, we may be called after
358	 * one has already been configured, so check if it's already there
359	 * with in6ifa_ifpforlinklocal() and clobber it if it exists.
360	 */
361	s = splsoftnet();
362	error = in6_update_ifa(ifp, &ifra, in6ifa_ifpforlinklocal(ifp, 0));
363	splx(s);
364
365	if (error != 0) {
366		/*
367		 * XXX: When the interface does not support IPv6, this call
368		 * would fail in the SIOCSIFADDR ioctl.  I believe the
369		 * notification is rather confusing in this case, so just
370		 * suppress it.  (jinmei@kame.net 20010130)
371		 */
372		if (error != EAFNOSUPPORT)
373			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
374			    "configure a link-local address on %s "
375			    "(errno=%d)\n",
376			    ifp->if_xname, error));
377		return (-1);
378	}
379
380	/*
381	 * Adjust ia6_flags so that in6_if_up will perform DAD.
382	 * XXX: Some P2P interfaces seem not to send packets just after
383	 * becoming up, so we skip p2p interfaces for safety.
384	 */
385	ia6 = in6ifa_ifpforlinklocal(ifp, 0); /* ia6 must not be NULL */
386#ifdef DIAGNOSTIC
387	if (!ia6) {
388		panic("ia6 == NULL in in6_ifattach_linklocal");
389		/* NOTREACHED */
390	}
391#endif
392	if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
393	    (ifp->if_type == IFT_CARP)) == 0) {
394		ia6->ia6_flags &= ~IN6_IFF_NODAD;
395		ia6->ia6_flags |= IN6_IFF_TENTATIVE;
396	}
397
398	/*
399	 * Make the link-local prefix (fe80::/64%link) as on-link.
400	 * Since we'd like to manage prefixes separately from addresses,
401	 * we make an ND6 prefix structure for the link-local prefix,
402	 * and add it to the prefix list as a never-expire prefix.
403	 * XXX: this change might affect some existing code base...
404	 */
405	bzero(&pr0, sizeof(pr0));
406	pr0.ndpr_ifp = ifp;
407	/* this should be 64 at this moment. */
408	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
409	pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
410	pr0.ndpr_prefix = ifra.ifra_addr;
411	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
412	for (i = 0; i < 4; i++) {
413		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
414		    in6mask64.s6_addr32[i];
415	}
416	/*
417	 * Initialize parameters.  The link-local prefix must always be
418	 * on-link, and its lifetimes never expire.
419	 */
420	pr0.ndpr_raf_onlink = 1;
421	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
422	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
423	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
424	/*
425	 * Since there is no other link-local addresses, nd6_prefix_lookup()
426	 * probably returns NULL.  However, we cannot always expect the result.
427	 * For example, if we first remove the (only) existing link-local
428	 * address, and then reconfigure another one, the prefix is still
429	 * valid with referring to the old link-local address.
430	 */
431	if (nd6_prefix_lookup(&pr0) == NULL) {
432		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
433			return (error);
434	}
435
436	return 0;
437}
438
439/*
440 * ifp - must be IFT_LOOP
441 */
442
443int
444in6_ifattach_loopback(struct ifnet *ifp)
445{
446	struct in6_aliasreq ifra;
447	int error;
448
449	bzero(&ifra, sizeof(ifra));
450
451	/*
452	 * in6_update_ifa() does not use ifra_name, but we accurately set it
453	 * for safety.
454	 */
455	strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
456
457	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
458	ifra.ifra_prefixmask.sin6_family = AF_INET6;
459	ifra.ifra_prefixmask.sin6_addr = in6mask128;
460
461	/*
462	 * Always initialize ia_dstaddr (= broadcast address) to loopback
463	 * address.  Follows IPv4 practice - see in_ifinit().
464	 */
465	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
466	ifra.ifra_dstaddr.sin6_family = AF_INET6;
467	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
468
469	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
470	ifra.ifra_addr.sin6_family = AF_INET6;
471	ifra.ifra_addr.sin6_addr = in6addr_loopback;
472
473	/* the loopback  address should NEVER expire. */
474	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
475	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
476
477	/* we don't need to perform DAD on loopback interfaces. */
478	ifra.ifra_flags |= IN6_IFF_NODAD;
479
480	/*
481	 * We are sure that this is a newly assigned address, so we can set
482	 * NULL to the 3rd arg.
483	 */
484	if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
485		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
486		    "the loopback address on %s (errno=%d)\n",
487		    ifp->if_xname, error));
488		return (-1);
489	}
490
491	return 0;
492}
493
494/*
495 * compute NI group address, based on the current hostname setting.
496 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
497 *
498 * when ifp == NULL, the caller is responsible for filling scopeid.
499 */
500int
501in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
502    struct sockaddr_in6 *sa6)
503{
504	const char *p;
505	u_int8_t *q;
506	MD5_CTX ctxt;
507	u_int8_t digest[16];
508	u_int8_t l;
509	u_int8_t n[64];	/* a single label must not exceed 63 chars */
510
511	if (!namelen || !name)
512		return -1;
513
514	p = name;
515	while (p && *p && *p != '.' && p - name < namelen)
516		p++;
517	if (p - name > sizeof(n) - 1)
518		return -1;	/* label too long */
519	l = p - name;
520	strncpy((char *)n, name, l);
521	n[(int)l] = '\0';
522	for (q = n; *q; q++) {
523		if ('A' <= *q && *q <= 'Z')
524			*q = *q - 'A' + 'a';
525	}
526
527	/* generate 8 bytes of pseudo-random value. */
528	bzero(&ctxt, sizeof(ctxt));
529	MD5Init(&ctxt);
530	MD5Update(&ctxt, &l, sizeof(l));
531	MD5Update(&ctxt, n, l);
532	MD5Final(digest, &ctxt);
533
534	bzero(sa6, sizeof(*sa6));
535	sa6->sin6_family = AF_INET6;
536	sa6->sin6_len = sizeof(*sa6);
537	sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
538	sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
539	sa6->sin6_addr.s6_addr8[11] = 2;
540	bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
541	    sizeof(sa6->sin6_addr.s6_addr32[3]));
542
543	return 0;
544}
545
546/*
547 * XXX multiple loopback interface needs more care.  for instance,
548 * nodelocal address needs to be configured onto only one of them.
549 * XXX multiple link-local address case
550 */
551void
552in6_ifattach(struct ifnet *ifp)
553{
554	struct in6_ifaddr *ia6;
555	struct in6_addr in6;
556
557	/* some of the interfaces are inherently not IPv6 capable */
558	switch (ifp->if_type) {
559	case IFT_BRIDGE:
560	case IFT_ENC:
561	case IFT_PFLOG:
562	case IFT_PFSYNC:
563		return;
564	}
565
566	/*
567	 * if link mtu is too small, don't try to configure IPv6.
568	 * remember there could be some link-layer that has special
569	 * fragmentation logic.
570	 */
571	if (ifp->if_mtu < IPV6_MMTU) {
572		nd6log((LOG_INFO, "in6_ifattach: "
573		    "%s has too small MTU, IPv6 not enabled\n",
574		    ifp->if_xname));
575		return;
576	}
577
578	/*
579	 * usually, we require multicast capability to the interface
580	 */
581	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
582		nd6log((LOG_INFO, "in6_ifattach: "
583		    "%s is not multicast capable, IPv6 not enabled\n",
584		    ifp->if_xname));
585		return;
586	}
587
588	/*
589	 * assign loopback address for loopback interface.
590	 * XXX multiple loopback interface case.
591	 */
592	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
593		in6 = in6addr_loopback;
594		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
595			if (in6_ifattach_loopback(ifp) != 0)
596				return;
597		}
598	}
599
600	/*
601	 * assign a link-local address, if there's none.
602	 */
603	if (ip6_auto_linklocal) {
604		ia6 = in6ifa_ifpforlinklocal(ifp, 0);
605		if (ia6 == NULL) {
606			if (in6_ifattach_linklocal(ifp, NULL) == 0) {
607				/* linklocal address assigned */
608			} else {
609				/* failed to assign linklocal address. bark? */
610			}
611		}
612	}
613}
614
615/*
616 * NOTE: in6_ifdetach() does not support loopback if at this moment.
617 */
618void
619in6_ifdetach(struct ifnet *ifp)
620{
621	struct ifaddr *ifa, *next;
622	struct rtentry *rt;
623	struct sockaddr_in6 sin6;
624
625#ifdef MROUTING
626	/* remove ip6_mrouter stuff */
627	ip6_mrouter_detach(ifp);
628#endif
629
630	/* remove neighbor management table */
631	nd6_purge(ifp);
632
633	/* nuke any of IPv6 addresses we have */
634	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
635		if (ifa->ifa_addr->sa_family != AF_INET6)
636			continue;
637		in6_purgeaddr(ifa);
638		dohooks(ifp->if_addrhooks, 0);
639	}
640
641	/*
642	 * remove neighbor management table.  we call it twice just to make
643	 * sure we nuke everything.  maybe we need just one call.
644	 * XXX: since the first call did not release addresses, some prefixes
645	 * might remain.  We should call nd6_purge() again to release the
646	 * prefixes after removing all addresses above.
647	 * (Or can we just delay calling nd6_purge until at this point?)
648	 */
649	nd6_purge(ifp);
650
651	/* remove route to interface local allnodes multicast (ff01::1) */
652	bzero(&sin6, sizeof(sin6));
653	sin6.sin6_len = sizeof(struct sockaddr_in6);
654	sin6.sin6_family = AF_INET6;
655	sin6.sin6_addr = in6addr_intfacelocal_allnodes;
656	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
657	rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
658	if (rt && rt->rt_ifp == ifp) {
659		struct rt_addrinfo info;
660
661		bzero(&info, sizeof(info));
662		info.rti_flags = rt->rt_flags;
663		info.rti_info[RTAX_DST] = rt_key(rt);
664		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
665		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
666		rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL,
667		    ifp->if_rdomain);
668		rtfree(rt);
669	}
670
671	/* remove route to link-local allnodes multicast (ff02::1) */
672	bzero(&sin6, sizeof(sin6));
673	sin6.sin6_len = sizeof(struct sockaddr_in6);
674	sin6.sin6_family = AF_INET6;
675	sin6.sin6_addr = in6addr_linklocal_allnodes;
676	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
677	rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
678	if (rt && rt->rt_ifp == ifp) {
679		struct rt_addrinfo info;
680
681		bzero(&info, sizeof(info));
682		info.rti_flags = rt->rt_flags;
683		info.rti_info[RTAX_DST] = rt_key(rt);
684		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
685		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
686		rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL,
687		    ifp->if_rdomain);
688		rtfree(rt);
689	}
690
691	if (ifp->if_xflags & IFXF_AUTOCONF6) {
692		nd6_rs_timeout_count--;
693		if (nd6_rs_timeout_count == 0)
694			timeout_del(&nd6_rs_output_timer);
695		if (RS_LHCOOKIE(ifp) != NULL)
696			hook_disestablish(ifp->if_linkstatehooks,
697			    RS_LHCOOKIE(ifp));
698	}
699}
700