in6_ifattach.c revision 178888
1157114Sscottl/*-
2157114Sscottl * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3157114Sscottl * All rights reserved.
4157114Sscottl *
5157114Sscottl * Redistribution and use in source and binary forms, with or without
6157114Sscottl * modification, are permitted provided that the following conditions
7157114Sscottl * are met:
8157114Sscottl * 1. Redistributions of source code must retain the above copyright
9157114Sscottl *    notice, this list of conditions and the following disclaimer.
10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11157114Sscottl *    notice, this list of conditions and the following disclaimer in the
12157114Sscottl *    documentation and/or other materials provided with the distribution.
13157114Sscottl * 3. Neither the name of the project nor the names of its contributors
14157114Sscottl *    may be used to endorse or promote products derived from this software
15157114Sscottl *    without specific prior written permission.
16157114Sscottl *
17157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20157114Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26171980Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27171980Sscottl * SUCH DAMAGE.
28171980Sscottl *
29171980Sscottl *	$KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $
30171980Sscottl */
31171980Sscottl
32171980Sscottl#include <sys/cdefs.h>
33171980Sscottl__FBSDID("$FreeBSD: head/sys/netinet6/in6_ifattach.c 178888 2008-05-09 23:03:00Z julian $");
34171980Sscottl
35171980Sscottl#include <sys/param.h>
36171980Sscottl#include <sys/systm.h>
37171980Sscottl#include <sys/malloc.h>
38171980Sscottl#include <sys/socket.h>
39171980Sscottl#include <sys/sockio.h>
40171980Sscottl#include <sys/kernel.h>
41171980Sscottl#include <sys/syslog.h>
42171980Sscottl#include <sys/md5.h>
43171980Sscottl
44171980Sscottl#include <net/if.h>
45171980Sscottl#include <net/if_dl.h>
46171980Sscottl#include <net/if_types.h>
47171980Sscottl#include <net/route.h>
48171980Sscottl
49171980Sscottl#include <netinet/in.h>
50171980Sscottl#include <netinet/in_var.h>
51171980Sscottl#include <netinet/if_ether.h>
52157114Sscottl#include <netinet/in_pcb.h>
53157114Sscottl
54157114Sscottl#include <netinet/ip6.h>
55157114Sscottl#include <netinet6/ip6_var.h>
56157114Sscottl#include <netinet6/in6_var.h>
57157114Sscottl#include <netinet6/in6_pcb.h>
58157114Sscottl#include <netinet6/in6_ifattach.h>
59157114Sscottl#include <netinet6/ip6_var.h>
60157114Sscottl#include <netinet6/nd6.h>
61157114Sscottl#include <netinet6/scope6_var.h>
62157114Sscottl
63157114Sscottlunsigned long in6_maxmtu = 0;
64157114Sscottl
65157114Sscottl#ifdef IP6_AUTO_LINKLOCAL
66157114Sscottlint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
67233711Sambrisko#else
68157114Sscottlint ip6_auto_linklocal = 1;	/* enable by default */
69157114Sscottl#endif
70157114Sscottl
71157114Sscottlstruct callout in6_tmpaddrtimer_ch;
72157114Sscottl
73157114Sscottlextern struct inpcbinfo udbinfo;
74157114Sscottlextern struct inpcbinfo ripcbinfo;
75157114Sscottl
76157114Sscottlstatic int get_rand_ifid(struct ifnet *, struct in6_addr *);
77157114Sscottlstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
78157114Sscottlstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
79157114Sscottlstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
80157114Sscottlstatic int in6_ifattach_loopback(struct ifnet *);
81157114Sscottlstatic void in6_purgemaddrs(struct ifnet *);
82157114Sscottl
83157114Sscottl#define EUI64_GBIT	0x01
84157114Sscottl#define EUI64_UBIT	0x02
85171980Sscottl#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
86233711Sambrisko#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
87233711Sambrisko#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
88233711Sambrisko#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
89247369Ssmh#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
90233711Sambrisko
91233711Sambrisko#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
92233711Sambrisko#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
93233711Sambrisko
94233711Sambrisko/*
95171980Sscottl * Generate a last-resort interface identifier, when the machine has no
96171980Sscottl * IEEE802/EUI64 address sources.
97171980Sscottl * The goal here is to get an interface identifier that is
98171980Sscottl * (1) random enough and (2) does not change across reboot.
99171980Sscottl * We currently use MD5(hostname) for it.
100171980Sscottl *
101233711Sambrisko * in6 - upper 64bits are preserved
102171980Sscottl */
103171980Sscottlstatic int
104171980Sscottlget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
105233711Sambrisko{
106233711Sambrisko	MD5_CTX ctxt;
107233711Sambrisko	u_int8_t digest[16];
108233711Sambrisko	int hostnamelen	= strlen(hostname);
109233711Sambrisko
110184897Sambrisko#if 0
111184897Sambrisko	/* we need at least several letters as seed for ifid */
112184897Sambrisko	if (hostnamelen < 3)
113184897Sambrisko		return -1;
114184897Sambrisko#endif
115184897Sambrisko
116233711Sambrisko	/* generate 8 bytes of pseudo-random value. */
117233711Sambrisko	bzero(&ctxt, sizeof(ctxt));
118233711Sambrisko	MD5Init(&ctxt);
119233711Sambrisko	MD5Update(&ctxt, hostname, hostnamelen);
120233711Sambrisko	MD5Final(digest, &ctxt);
121233711Sambrisko
122233711Sambrisko	/* assumes sizeof(digest) > sizeof(ifid) */
123233711Sambrisko	bcopy(digest, &in6->s6_addr[8], 8);
124157114Sscottl
125157114Sscottl	/* make sure to set "u" bit to local, and "g" bit to individual. */
126157114Sscottl	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
127233711Sambrisko	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
128233711Sambrisko
129233711Sambrisko	/* convert EUI64 into IPv6 interface identifier */
130233711Sambrisko	EUI64_TO_IFID(in6);
131157114Sscottl
132157114Sscottl	return 0;
133157114Sscottl}
134157114Sscottl
135157114Sscottlstatic int
136157114Sscottlgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret)
137157114Sscottl{
138157114Sscottl	MD5_CTX ctxt;
139157114Sscottl	u_int8_t seed[16], digest[16], nullbuf[8];
140157114Sscottl	u_int32_t val32;
141224041Sjhb
142157114Sscottl	/* If there's no history, start with a random seed. */
143157114Sscottl	bzero(nullbuf, sizeof(nullbuf));
144157114Sscottl	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
145157114Sscottl		int i;
146157114Sscottl
147157114Sscottl		for (i = 0; i < 2; i++) {
148233711Sambrisko			val32 = arc4random();
149233711Sambrisko			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
150233711Sambrisko		}
151157114Sscottl	} else
152233711Sambrisko		bcopy(seed0, seed, 8);
153233711Sambrisko
154233711Sambrisko	/* copy the right-most 64-bits of the given address */
155233711Sambrisko	/* XXX assumption on the size of IFID */
156233711Sambrisko	bcopy(seed1, &seed[8], 8);
157233711Sambrisko
158233711Sambrisko	if (0) {		/* for debugging purposes only */
159157114Sscottl		int i;
160157114Sscottl
161157114Sscottl		printf("generate_tmp_ifid: new randomized ID from: ");
162157114Sscottl		for (i = 0; i < 16; i++)
163157114Sscottl			printf("%02x", seed[i]);
164157114Sscottl		printf(" ");
165157114Sscottl	}
166157114Sscottl
167224041Sjhb	/* generate 16 bytes of pseudo-random value. */
168157114Sscottl	bzero(&ctxt, sizeof(ctxt));
169233711Sambrisko	MD5Init(&ctxt);
170233711Sambrisko	MD5Update(&ctxt, seed, sizeof(seed));
171233711Sambrisko	MD5Final(digest, &ctxt);
172233711Sambrisko
173233711Sambrisko	/*
174233711Sambrisko	 * RFC 3041 3.2.1. (3)
175157114Sscottl	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
176157114Sscottl	 * left-most bit is numbered 0) to zero.
177157114Sscottl	 */
178157114Sscottl	bcopy(digest, ret, 8);
179157114Sscottl	ret[0] &= ~EUI64_UBIT;
180157114Sscottl
181157114Sscottl	/*
182157114Sscottl	 * XXX: we'd like to ensure that the generated value is not zero
183157114Sscottl	 * for simplicity.  If the caclculated digest happens to be zero,
184157114Sscottl	 * use a random non-zero value as the last resort.
185157114Sscottl	 */
186157114Sscottl	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
187157114Sscottl		nd6log((LOG_INFO,
188157114Sscottl		    "generate_tmp_ifid: computed MD5 value is zero.\n"));
189157114Sscottl
190157114Sscottl		val32 = arc4random();
191233711Sambrisko		val32 = 1 + (val32 % (0xffffffff - 1));
192163398Sscottl	}
193163398Sscottl
194157114Sscottl	/*
195255806Ssbruno	 * RFC 3041 3.2.1. (4)
196255806Ssbruno	 * Take the rightmost 64-bits of the MD5 digest and save them in
197157114Sscottl	 * stable storage as the history value to be used in the next
198157114Sscottl	 * iteration of the algorithm.
199157114Sscottl	 */
200157114Sscottl	bcopy(&digest[8], seed0, 8);
201196200Sscottl
202196200Sscottl	if (0) {		/* for debugging purposes only */
203196200Sscottl		int i;
204196200Sscottl
205196200Sscottl		printf("to: ");
206196200Sscottl		for (i = 0; i < 16; i++)
207196200Sscottl			printf("%02x", digest[i]);
208196200Sscottl		printf("\n");
209196200Sscottl	}
210196200Sscottl
211196200Sscottl	return 0;
212233711Sambrisko}
213196200Sscottl
214196200Sscottl/*
215196200Sscottl * Get interface identifier for the specified interface.
216196200Sscottl * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
217196200Sscottl *
218196200Sscottl * in6 - upper 64bits are preserved
219196200Sscottl */
220196200Sscottlint
221196200Sscottlin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
222233711Sambrisko{
223233711Sambrisko	struct ifaddr *ifa;
224159811Sps	struct sockaddr_dl *sdl;
225159811Sps	u_int8_t *addr;
226157114Sscottl	size_t addrlen;
227159811Sps	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
228196200Sscottl	static u_int8_t allone[8] =
229171821Sjhb		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
230163398Sscottl
231163398Sscottl	for (ifa = ifp->if_addrlist.tqh_first;
232163398Sscottl	     ifa;
233196200Sscottl	     ifa = ifa->ifa_list.tqe_next) {
234233711Sambrisko		if (ifa->ifa_addr->sa_family != AF_LINK)
235251516Ssbruno			continue;
236251516Ssbruno		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
237251516Ssbruno		if (sdl == NULL)
238184897Sambrisko			continue;
239251516Ssbruno		if (sdl->sdl_alen == 0)
240196200Sscottl			continue;
241196200Sscottl
242196200Sscottl		goto found;
243249257Smarkj	}
244249257Smarkj
245249257Smarkj	return -1;
246157114Sscottl
247157114Sscottlfound:
248157114Sscottl	addr = LLADDR(sdl);
249157114Sscottl	addrlen = sdl->sdl_alen;
250157114Sscottl
251157114Sscottl	/* get EUI64 */
252157114Sscottl	switch (ifp->if_type) {
253157114Sscottl	case IFT_ETHER:
254157114Sscottl	case IFT_FDDI:
255157114Sscottl	case IFT_ISO88025:
256157114Sscottl	case IFT_ATM:
257157114Sscottl	case IFT_IEEE1394:
258157114Sscottl#ifdef IFT_IEEE80211
259158737Sambrisko	case IFT_IEEE80211:
260157114Sscottl#endif
261157114Sscottl		/* IEEE802/EUI64 cases - what others? */
262157114Sscottl		/* IEEE1394 uses 16byte length address starting with EUI64 */
263157114Sscottl		if (addrlen > 8)
264157114Sscottl			addrlen = 8;
265157114Sscottl
266157114Sscottl		/* look at IEEE802/EUI64 only */
267157114Sscottl		if (addrlen != 8 && addrlen != 6)
268157114Sscottl			return -1;
269157114Sscottl
270157114Sscottl		/*
271233711Sambrisko		 * check for invalid MAC address - on bsdi, we see it a lot
272247369Ssmh		 * since wildboar configures all-zero MAC on pccard before
273247369Ssmh		 * card insertion.
274247369Ssmh		 */
275247369Ssmh		if (bcmp(addr, allzero, addrlen) == 0)
276247369Ssmh			return -1;
277247369Ssmh		if (bcmp(addr, allone, addrlen) == 0)
278247369Ssmh			return -1;
279157114Sscottl
280233711Sambrisko		/* make EUI64 address */
281233711Sambrisko		if (addrlen == 8)
282233711Sambrisko			bcopy(addr, &in6->s6_addr[8], 8);
283233711Sambrisko		else if (addrlen == 6) {
284233711Sambrisko			in6->s6_addr[8] = addr[0];
285233711Sambrisko			in6->s6_addr[9] = addr[1];
286233711Sambrisko			in6->s6_addr[10] = addr[2];
287233711Sambrisko			in6->s6_addr[11] = 0xff;
288233711Sambrisko			in6->s6_addr[12] = 0xfe;
289233711Sambrisko			in6->s6_addr[13] = addr[3];
290233711Sambrisko			in6->s6_addr[14] = addr[4];
291233711Sambrisko			in6->s6_addr[15] = addr[5];
292233711Sambrisko		}
293233711Sambrisko		break;
294233711Sambrisko
295233711Sambrisko	case IFT_ARCNET:
296233711Sambrisko		if (addrlen != 1)
297233711Sambrisko			return -1;
298233711Sambrisko		if (!addr[0])
299233711Sambrisko			return -1;
300233711Sambrisko
301233711Sambrisko		bzero(&in6->s6_addr[8], 8);
302233711Sambrisko		in6->s6_addr[15] = addr[0];
303233711Sambrisko
304233711Sambrisko		/*
305233711Sambrisko		 * due to insufficient bitwidth, we mark it local.
306233711Sambrisko		 */
307233711Sambrisko		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
308233711Sambrisko		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
309157114Sscottl		break;
310157114Sscottl
311157114Sscottl	case IFT_GIF:
312157114Sscottl#ifdef IFT_STF
313157114Sscottl	case IFT_STF:
314157114Sscottl#endif
315157114Sscottl		/*
316157114Sscottl		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
317157114Sscottl		 * however, IPv4 address is not very suitable as unique
318157114Sscottl		 * identifier source (can be renumbered).
319157114Sscottl		 * we don't do this.
320157114Sscottl		 */
321157114Sscottl		return -1;
322157114Sscottl
323157114Sscottl	default:
324157114Sscottl		return -1;
325157114Sscottl	}
326157114Sscottl
327157114Sscottl	/* sanity check: g bit must not indicate "group" */
328157114Sscottl	if (EUI64_GROUP(in6))
329157114Sscottl		return -1;
330157114Sscottl
331157114Sscottl	/* convert EUI64 into IPv6 interface identifier */
332157114Sscottl	EUI64_TO_IFID(in6);
333157114Sscottl
334157114Sscottl	/*
335157114Sscottl	 * sanity check: ifid must not be all zero, avoid conflict with
336157114Sscottl	 * subnet router anycast
337157114Sscottl	 */
338157114Sscottl	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
339157114Sscottl	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
340157114Sscottl		return -1;
341157114Sscottl	}
342157114Sscottl
343157114Sscottl	return 0;
344157114Sscottl}
345157114Sscottl
346157114Sscottl/*
347157114Sscottl * Get interface identifier for the specified interface.  If it is not
348157114Sscottl * available on ifp0, borrow interface identifier from other information
349157114Sscottl * sources.
350157114Sscottl *
351157114Sscottl * altifp - secondary EUI64 source
352157114Sscottl */
353157114Sscottlstatic int
354157114Sscottlget_ifid(struct ifnet *ifp0, struct ifnet *altifp,
355157114Sscottl    struct in6_addr *in6)
356157114Sscottl{
357157114Sscottl	struct ifnet *ifp;
358157114Sscottl
359157114Sscottl	/* first, try to get it from the interface itself */
360157114Sscottl	if (in6_get_hw_ifid(ifp0, in6) == 0) {
361157114Sscottl		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
362157114Sscottl		    if_name(ifp0)));
363157114Sscottl		goto success;
364157114Sscottl	}
365157114Sscottl
366157114Sscottl	/* try secondary EUI64 source. this basically is for ATM PVC */
367157114Sscottl	if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
368196200Sscottl		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
369196200Sscottl		    if_name(ifp0), if_name(altifp)));
370196200Sscottl		goto success;
371157114Sscottl	}
372157114Sscottl
373157114Sscottl	/* next, try to get it from some other hardware interface */
374157114Sscottl	IFNET_RLOCK();
375157114Sscottl	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
376157114Sscottl		if (ifp == ifp0)
377157114Sscottl			continue;
378157114Sscottl		if (in6_get_hw_ifid(ifp, in6) != 0)
379157114Sscottl			continue;
380157114Sscottl
381157114Sscottl		/*
382157114Sscottl		 * to borrow ifid from other interface, ifid needs to be
383157114Sscottl		 * globally unique
384157114Sscottl		 */
385157114Sscottl		if (IFID_UNIVERSAL(in6)) {
386157114Sscottl			nd6log((LOG_DEBUG,
387157114Sscottl			    "%s: borrow interface identifier from %s\n",
388157114Sscottl			    if_name(ifp0), if_name(ifp)));
389157114Sscottl			IFNET_RUNLOCK();
390157114Sscottl			goto success;
391157114Sscottl		}
392157114Sscottl	}
393157114Sscottl	IFNET_RUNLOCK();
394157114Sscottl
395157114Sscottl	/* last resort: get from random number source */
396157114Sscottl	if (get_rand_ifid(ifp, in6) == 0) {
397158737Sambrisko		nd6log((LOG_DEBUG,
398158737Sambrisko		    "%s: interface identifier generated by random number\n",
399158737Sambrisko		    if_name(ifp0)));
400158737Sambrisko		goto success;
401158737Sambrisko	}
402158737Sambrisko
403158737Sambrisko	printf("%s: failed to get interface identifier\n", if_name(ifp0));
404158737Sambrisko	return -1;
405158737Sambrisko
406158737Sambriskosuccess:
407158737Sambrisko	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
408158737Sambrisko	    if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
409158737Sambrisko	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
410158737Sambrisko	    in6->s6_addr[14], in6->s6_addr[15]));
411158737Sambrisko	return 0;
412158737Sambrisko}
413158737Sambrisko
414158737Sambrisko/*
415158737Sambrisko * altifp - secondary EUI64 source
416158737Sambrisko */
417158737Sambriskostatic int
418157114Sscottlin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
419157114Sscottl{
420233711Sambrisko	struct in6_ifaddr *ia;
421233711Sambrisko	struct in6_aliasreq ifra;
422233711Sambrisko	struct nd_prefixctl pr0;
423235014Sambrisko	int i, error;
424233711Sambrisko
425163398Sscottl	/*
426163398Sscottl	 * configure link-local address.
427163398Sscottl	 */
428163398Sscottl	bzero(&ifra, sizeof(ifra));
429163398Sscottl
430163398Sscottl	/*
431163398Sscottl	 * in6_update_ifa() does not use ifra_name, but we accurately set it
432163398Sscottl	 * for safety.
433163398Sscottl	 */
434196200Sscottl	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
435163398Sscottl
436196200Sscottl	ifra.ifra_addr.sin6_family = AF_INET6;
437196200Sscottl	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
438196200Sscottl	ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
439196200Sscottl	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
440196200Sscottl	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
441196200Sscottl		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
442196200Sscottl		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
443196200Sscottl	} else {
444196200Sscottl		if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
445196200Sscottl			nd6log((LOG_ERR,
446163398Sscottl			    "%s: no ifid available\n", if_name(ifp)));
447163398Sscottl			return (-1);
448163398Sscottl		}
449163398Sscottl	}
450163398Sscottl	if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
451163398Sscottl		return (-1);
452233711Sambrisko
453233711Sambrisko	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
454233711Sambrisko	ifra.ifra_prefixmask.sin6_family = AF_INET6;
455233711Sambrisko	ifra.ifra_prefixmask.sin6_addr = in6mask64;
456233711Sambrisko	/* link-local addresses should NEVER expire. */
457233711Sambrisko	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
458233711Sambrisko	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
459233711Sambrisko
460233711Sambrisko	/*
461157114Sscottl	 * Now call in6_update_ifa() to do a bunch of procedures to configure
462157114Sscottl	 * a link-local address. We can set the 3rd argument to NULL, because
463157114Sscottl	 * we know there's no other link-local address on the interface
464157114Sscottl	 * and therefore we are adding one (instead of updating one).
465157114Sscottl	 */
466157114Sscottl	if ((error = in6_update_ifa(ifp, &ifra, NULL,
467157114Sscottl				    IN6_IFAUPDATE_DADDELAY)) != 0) {
468157114Sscottl		/*
469157114Sscottl		 * XXX: When the interface does not support IPv6, this call
470157114Sscottl		 * would fail in the SIOCSIFADDR ioctl.  I believe the
471196200Sscottl		 * notification is rather confusing in this case, so just
472157114Sscottl		 * suppress it.  (jinmei@kame.net 20010130)
473157114Sscottl		 */
474157114Sscottl		if (error != EAFNOSUPPORT)
475157114Sscottl			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
476247369Ssmh			    "configure a link-local address on %s "
477247369Ssmh			    "(errno=%d)\n",
478157114Sscottl			    if_name(ifp), error));
479157114Sscottl		return (-1);
480157114Sscottl	}
481157114Sscottl
482157114Sscottl	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
483157114Sscottl#ifdef DIAGNOSTIC
484157114Sscottl	if (!ia) {
485157114Sscottl		panic("ia == NULL in in6_ifattach_linklocal");
486157114Sscottl		/* NOTREACHED */
487157114Sscottl	}
488157114Sscottl#endif
489157114Sscottl
490157114Sscottl	/*
491157114Sscottl	 * Make the link-local prefix (fe80::%link/64) as on-link.
492157114Sscottl	 * Since we'd like to manage prefixes separately from addresses,
493233711Sambrisko	 * we make an ND6 prefix structure for the link-local prefix,
494233711Sambrisko	 * and add it to the prefix list as a never-expire prefix.
495233711Sambrisko	 * XXX: this change might affect some existing code base...
496233711Sambrisko	 */
497233711Sambrisko	bzero(&pr0, sizeof(pr0));
498233711Sambrisko	pr0.ndpr_ifp = ifp;
499157114Sscottl	/* this should be 64 at this moment. */
500233711Sambrisko	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
501233711Sambrisko	pr0.ndpr_prefix = ifra.ifra_addr;
502233711Sambrisko	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
503157114Sscottl	for (i = 0; i < 4; i++) {
504157114Sscottl		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
505157114Sscottl		    in6mask64.s6_addr32[i];
506157114Sscottl	}
507157114Sscottl	/*
508157114Sscottl	 * Initialize parameters.  The link-local prefix must always be
509157114Sscottl	 * on-link, and its lifetimes never expire.
510157114Sscottl	 */
511157114Sscottl	pr0.ndpr_raf_onlink = 1;
512157114Sscottl	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
513157114Sscottl	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
514157114Sscottl	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
515157114Sscottl	/*
516233711Sambrisko	 * Since there is no other link-local addresses, nd6_prefix_lookup()
517233711Sambrisko	 * probably returns NULL.  However, we cannot always expect the result.
518233711Sambrisko	 * For example, if we first remove the (only) existing link-local
519233711Sambrisko	 * address, and then reconfigure another one, the prefix is still
520157114Sscottl	 * valid with referring to the old link-local address.
521157114Sscottl	 */
522175897Sambrisko	if (nd6_prefix_lookup(&pr0) == NULL) {
523175897Sambrisko		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
524157114Sscottl			return (error);
525157114Sscottl	}
526157114Sscottl
527157114Sscottl	return 0;
528157114Sscottl}
529157114Sscottl
530157114Sscottl/*
531157114Sscottl * ifp - must be IFT_LOOP
532157114Sscottl */
533157114Sscottlstatic int
534233711Sambriskoin6_ifattach_loopback(struct ifnet *ifp)
535233711Sambrisko{
536233711Sambrisko	struct in6_aliasreq ifra;
537233711Sambrisko	int error;
538233711Sambrisko
539233711Sambrisko	bzero(&ifra, sizeof(ifra));
540157114Sscottl
541157114Sscottl	/*
542233711Sambrisko	 * in6_update_ifa() does not use ifra_name, but we accurately set it
543233711Sambrisko	 * for safety.
544233711Sambrisko	 */
545233711Sambrisko	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
546233711Sambrisko
547233711Sambrisko	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
548233711Sambrisko	ifra.ifra_prefixmask.sin6_family = AF_INET6;
549233711Sambrisko	ifra.ifra_prefixmask.sin6_addr = in6mask128;
550233711Sambrisko
551233711Sambrisko	/*
552233711Sambrisko	 * Always initialize ia_dstaddr (= broadcast address) to loopback
553233711Sambrisko	 * address.  Follows IPv4 practice - see in_ifinit().
554233711Sambrisko	 */
555233711Sambrisko	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
556233711Sambrisko	ifra.ifra_dstaddr.sin6_family = AF_INET6;
557157114Sscottl	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
558157114Sscottl
559157114Sscottl	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
560157114Sscottl	ifra.ifra_addr.sin6_family = AF_INET6;
561157114Sscottl	ifra.ifra_addr.sin6_addr = in6addr_loopback;
562157114Sscottl
563157114Sscottl	/* the loopback  address should NEVER expire. */
564157114Sscottl	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
565157114Sscottl	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
566157114Sscottl
567157114Sscottl	/* we don't need to perform DAD on loopback interfaces. */
568157114Sscottl	ifra.ifra_flags |= IN6_IFF_NODAD;
569157114Sscottl
570157114Sscottl	/* skip registration to the prefix list. XXX should be temporary. */
571157114Sscottl	ifra.ifra_flags |= IN6_IFF_NOPFX;
572157114Sscottl
573157114Sscottl	/*
574157114Sscottl	 * We are sure that this is a newly assigned address, so we can set
575157114Sscottl	 * NULL to the 3rd arg.
576157114Sscottl	 */
577157114Sscottl	if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
578157114Sscottl		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
579157114Sscottl		    "the loopback address on %s (errno=%d)\n",
580157114Sscottl		    if_name(ifp), error));
581157114Sscottl		return (-1);
582157114Sscottl	}
583157114Sscottl
584157114Sscottl	return 0;
585157114Sscottl}
586157114Sscottl
587233711Sambrisko/*
588233711Sambrisko * compute NI group address, based on the current hostname setting.
589157114Sscottl * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
590157114Sscottl *
591233711Sambrisko * when ifp == NULL, the caller is responsible for filling scopeid.
592157114Sscottl */
593157114Sscottlint
594157114Sscottlin6_nigroup(struct ifnet *ifp, const char *name, int namelen,
595157114Sscottl    struct in6_addr *in6)
596157114Sscottl{
597157114Sscottl	const char *p;
598157114Sscottl	u_char *q;
599157114Sscottl	MD5_CTX ctxt;
600157114Sscottl	u_int8_t digest[16];
601157114Sscottl	char l;
602157114Sscottl	char n[64];	/* a single label must not exceed 63 chars */
603157114Sscottl
604157114Sscottl	if (!namelen || !name)
605157114Sscottl		return -1;
606157114Sscottl
607157114Sscottl	p = name;
608157114Sscottl	while (p && *p && *p != '.' && p - name < namelen)
609157114Sscottl		p++;
610157114Sscottl	if (p - name > sizeof(n) - 1)
611157114Sscottl		return -1;	/* label too long */
612157114Sscottl	l = p - name;
613157114Sscottl	strncpy(n, name, l);
614157114Sscottl	n[(int)l] = '\0';
615157114Sscottl	for (q = n; *q; q++) {
616233711Sambrisko		if ('A' <= *q && *q <= 'Z')
617157114Sscottl			*q = *q - 'A' + 'a';
618157114Sscottl	}
619157114Sscottl
620157114Sscottl	/* generate 8 bytes of pseudo-random value. */
621157114Sscottl	bzero(&ctxt, sizeof(ctxt));
622157114Sscottl	MD5Init(&ctxt);
623157114Sscottl	MD5Update(&ctxt, &l, sizeof(l));
624157114Sscottl	MD5Update(&ctxt, n, l);
625157114Sscottl	MD5Final(digest, &ctxt);
626157114Sscottl
627157114Sscottl	bzero(in6, sizeof(*in6));
628157114Sscottl	in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
629157114Sscottl	in6->s6_addr8[11] = 2;
630157114Sscottl	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
631157114Sscottl	if (in6_setscope(in6, ifp, NULL))
632157114Sscottl		return (-1); /* XXX: should not fail */
633157114Sscottl
634157114Sscottl	return 0;
635157114Sscottl}
636157114Sscottl
637157114Sscottl/*
638157114Sscottl * XXX multiple loopback interface needs more care.  for instance,
639157114Sscottl * nodelocal address needs to be configured onto only one of them.
640157114Sscottl * XXX multiple link-local address case
641157114Sscottl *
642157114Sscottl * altifp - secondary EUI64 source
643157114Sscottl */
644157114Sscottlvoid
645157114Sscottlin6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
646157114Sscottl{
647157114Sscottl	struct in6_ifaddr *ia;
648157114Sscottl	struct in6_addr in6;
649157114Sscottl
650157114Sscottl	/* some of the interfaces are inherently not IPv6 capable */
651157114Sscottl	switch (ifp->if_type) {
652157114Sscottl	case IFT_PFLOG:
653157114Sscottl	case IFT_PFSYNC:
654157114Sscottl	case IFT_CARP:
655157114Sscottl		return;
656157114Sscottl	}
657157114Sscottl
658157114Sscottl	/*
659157114Sscottl	 * quirks based on interface type
660157114Sscottl	 */
661157114Sscottl	switch (ifp->if_type) {
662157114Sscottl#ifdef IFT_STF
663157114Sscottl	case IFT_STF:
664157114Sscottl		/*
665157114Sscottl		 * 6to4 interface is a very special kind of beast.
666233711Sambrisko		 * no multicast, no linklocal.  RFC2529 specifies how to make
667233711Sambrisko		 * linklocals for 6to4 interface, but there's no use and
668233711Sambrisko		 * it is rather harmful to have one.
669233711Sambrisko		 */
670233711Sambrisko		goto statinit;
671233711Sambrisko#endif
672233711Sambrisko	default:
673233711Sambrisko		break;
674233711Sambrisko	}
675233711Sambrisko
676233711Sambrisko	/*
677233711Sambrisko	 * usually, we require multicast capability to the interface
678233711Sambrisko	 */
679233711Sambrisko	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
680233711Sambrisko		nd6log((LOG_INFO, "in6_ifattach: "
681233711Sambrisko		    "%s is not multicast capable, IPv6 not enabled\n",
682233711Sambrisko		    if_name(ifp)));
683233711Sambrisko		return;
684233711Sambrisko	}
685233711Sambrisko
686233711Sambrisko	/*
687233711Sambrisko	 * assign loopback address for loopback interface.
688233711Sambrisko	 * XXX multiple loopback interface case.
689233711Sambrisko	 */
690233711Sambrisko	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
691233711Sambrisko		in6 = in6addr_loopback;
692233711Sambrisko		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
693233711Sambrisko			if (in6_ifattach_loopback(ifp) != 0)
694233711Sambrisko				return;
695233711Sambrisko		}
696233711Sambrisko	}
697233711Sambrisko
698233711Sambrisko	/*
699233711Sambrisko	 * assign a link-local address, if there's none.
700233711Sambrisko	 */
701233711Sambrisko	if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
702233711Sambrisko		ia = in6ifa_ifpforlinklocal(ifp, 0);
703233711Sambrisko		if (ia == NULL) {
704233711Sambrisko			if (in6_ifattach_linklocal(ifp, altifp) == 0) {
705233711Sambrisko				/* linklocal address assigned */
706233711Sambrisko			} else {
707233711Sambrisko				/* failed to assign linklocal address. bark? */
708233711Sambrisko			}
709233711Sambrisko		}
710233711Sambrisko	}
711233711Sambrisko
712233711Sambrisko#ifdef IFT_STF			/* XXX */
713233711Sambriskostatinit:
714233711Sambrisko#endif
715233711Sambrisko
716233711Sambrisko	/* update dynamically. */
717233711Sambrisko	if (in6_maxmtu < ifp->if_mtu)
718233711Sambrisko		in6_maxmtu = ifp->if_mtu;
719233711Sambrisko}
720233711Sambrisko
721157114Sscottl/*
722157114Sscottl * NOTE: in6_ifdetach() does not support loopback if at this moment.
723157114Sscottl * We don't need this function in bsdi, because interfaces are never removed
724157114Sscottl * from the ifnet list in bsdi.
725157114Sscottl */
726157114Sscottlvoid
727157114Sscottlin6_ifdetach(struct ifnet *ifp)
728157114Sscottl{
729157114Sscottl	struct in6_ifaddr *ia, *oia;
730157114Sscottl	struct ifaddr *ifa, *next;
731157114Sscottl	struct rtentry *rt;
732157114Sscottl	short rtflags;
733157114Sscottl	struct sockaddr_in6 sin6;
734157114Sscottl	struct in6_multi_mship *imm;
735157114Sscottl
736157114Sscottl	/* remove neighbor management table */
737157114Sscottl	nd6_purge(ifp);
738157114Sscottl
739157114Sscottl	/* nuke any of IPv6 addresses we have */
740157114Sscottl	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
741157114Sscottl		next = ifa->ifa_list.tqe_next;
742157114Sscottl		if (ifa->ifa_addr->sa_family != AF_INET6)
743157114Sscottl			continue;
744157114Sscottl		in6_purgeaddr(ifa);
745157114Sscottl	}
746157114Sscottl
747157114Sscottl	/* undo everything done by in6_ifattach(), just in case */
748157114Sscottl	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
749157114Sscottl		next = ifa->ifa_list.tqe_next;
750157114Sscottl
751157114Sscottl		if (ifa->ifa_addr->sa_family != AF_INET6
752157114Sscottl		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
753157114Sscottl			continue;
754157114Sscottl		}
755157114Sscottl
756157114Sscottl		ia = (struct in6_ifaddr *)ifa;
757157114Sscottl
758157114Sscottl		/*
759157114Sscottl		 * leave from multicast groups we have joined for the interface
760157114Sscottl		 */
761157114Sscottl		while ((imm = ia->ia6_memberships.lh_first) != NULL) {
762157114Sscottl			LIST_REMOVE(imm, i6mm_chain);
763157114Sscottl			in6_leavegroup(imm);
764163398Sscottl		}
765163398Sscottl
766163398Sscottl		/* remove from the routing table */
767163398Sscottl		if ((ia->ia_flags & IFA_ROUTE) &&
768163398Sscottl		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
769163398Sscottl			rtflags = rt->rt_flags;
770163398Sscottl			rtfree(rt);
771163398Sscottl			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
772163398Sscottl			    (struct sockaddr *)&ia->ia_addr,
773163398Sscottl			    (struct sockaddr *)&ia->ia_prefixmask,
774163398Sscottl			    rtflags, (struct rtentry **)0);
775163398Sscottl		}
776163398Sscottl
777163398Sscottl		/* remove from the linked list */
778163398Sscottl		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
779163398Sscottl		IFAFREE(&ia->ia_ifa);
780163398Sscottl
781163398Sscottl		/* also remove from the IPv6 address chain(itojun&jinmei) */
782163398Sscottl		oia = ia;
783163398Sscottl		if (oia == (ia = in6_ifaddr))
784163398Sscottl			in6_ifaddr = ia->ia_next;
785163398Sscottl		else {
786163398Sscottl			while (ia->ia_next && (ia->ia_next != oia))
787163398Sscottl				ia = ia->ia_next;
788163398Sscottl			if (ia->ia_next)
789163398Sscottl				ia->ia_next = oia->ia_next;
790163398Sscottl			else {
791163398Sscottl				nd6log((LOG_ERR,
792163398Sscottl				    "%s: didn't unlink in6ifaddr from list\n",
793163398Sscottl				    if_name(ifp)));
794163398Sscottl			}
795163398Sscottl		}
796163398Sscottl
797157114Sscottl		IFAFREE(&oia->ia_ifa);
798163398Sscottl	}
799163398Sscottl
800163398Sscottl	in6_pcbpurgeif0(&udbinfo, ifp);
801163398Sscottl	in6_pcbpurgeif0(&ripcbinfo, ifp);
802163398Sscottl	/* leave from all multicast groups joined */
803163398Sscottl	in6_purgemaddrs(ifp);
804163398Sscottl
805163398Sscottl	/*
806163398Sscottl	 * remove neighbor management table.  we call it twice just to make
807163398Sscottl	 * sure we nuke everything.  maybe we need just one call.
808163398Sscottl	 * XXX: since the first call did not release addresses, some prefixes
809163398Sscottl	 * might remain.  We should call nd6_purge() again to release the
810157114Sscottl	 * prefixes after removing all addresses above.
811157114Sscottl	 * (Or can we just delay calling nd6_purge until at this point?)
812157114Sscottl	 */
813157114Sscottl	nd6_purge(ifp);
814157114Sscottl
815157114Sscottl	/* remove route to link-local allnodes multicast (ff02::1) */
816157114Sscottl	bzero(&sin6, sizeof(sin6));
817157114Sscottl	sin6.sin6_len = sizeof(struct sockaddr_in6);
818157114Sscottl	sin6.sin6_family = AF_INET6;
819157114Sscottl	sin6.sin6_addr = in6addr_linklocal_allnodes;
820157114Sscottl	if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
821157114Sscottl		/* XXX: should not fail */
822157114Sscottl		return;
823157114Sscottl	/* XXX grab lock first to avoid LOR */
824157114Sscottl	if (rt_tables[0][AF_INET6] != NULL) {
825157114Sscottl		RADIX_NODE_HEAD_LOCK(rt_tables[0][AF_INET6]);
826157114Sscottl		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
827157114Sscottl		if (rt) {
828157114Sscottl			if (rt->rt_ifp == ifp)
829157114Sscottl				rtexpunge(rt);
830157114Sscottl			RTFREE_LOCKED(rt);
831157114Sscottl		}
832157114Sscottl		RADIX_NODE_HEAD_UNLOCK(rt_tables[0][AF_INET6]);
833157114Sscottl	}
834157114Sscottl}
835157114Sscottl
836157114Sscottlint
837157114Sscottlin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf,
838157114Sscottl    const u_int8_t *baseid, int generate)
839157114Sscottl{
840157114Sscottl	u_int8_t nullbuf[8];
841157114Sscottl	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
842157114Sscottl
843157114Sscottl	bzero(nullbuf, sizeof(nullbuf));
844157114Sscottl	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
845157114Sscottl		/* we've never created a random ID.  Create a new one. */
846157114Sscottl		generate = 1;
847157114Sscottl	}
848157114Sscottl
849157114Sscottl	if (generate) {
850157114Sscottl		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
851157114Sscottl
852157114Sscottl		/* generate_tmp_ifid will update seedn and buf */
853157114Sscottl		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
854157114Sscottl		    ndi->randomid);
855157114Sscottl	}
856157114Sscottl	bcopy(ndi->randomid, retbuf, 8);
857157114Sscottl
858157114Sscottl	return (0);
859157114Sscottl}
860157114Sscottl
861157114Sscottlvoid
862157114Sscottlin6_tmpaddrtimer(void *ignored_arg)
863157114Sscottl{
864158737Sambrisko	struct nd_ifinfo *ndi;
865157114Sscottl	u_int8_t nullbuf[8];
866157114Sscottl	struct ifnet *ifp;
867157114Sscottl	int s = splnet();
868157114Sscottl
869157114Sscottl	callout_reset(&in6_tmpaddrtimer_ch,
870157114Sscottl	    (ip6_temp_preferred_lifetime - ip6_desync_factor -
871157114Sscottl	    ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL);
872157114Sscottl
873157114Sscottl	bzero(nullbuf, sizeof(nullbuf));
874157114Sscottl	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
875157114Sscottl		ndi = ND_IFINFO(ifp);
876157114Sscottl		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
877157114Sscottl			/*
878157114Sscottl			 * We've been generating a random ID on this interface.
879157114Sscottl			 * Create a new one.
880157114Sscottl			 */
881157114Sscottl			(void)generate_tmp_ifid(ndi->randomseed0,
882157114Sscottl			    ndi->randomseed1, ndi->randomid);
883157114Sscottl		}
884157114Sscottl	}
885157114Sscottl
886157114Sscottl	splx(s);
887157114Sscottl}
888157114Sscottl
889157114Sscottlstatic void
890157114Sscottlin6_purgemaddrs(struct ifnet *ifp)
891157114Sscottl{
892157114Sscottl	struct in6_multi *in6m;
893157114Sscottl	struct in6_multi *oin6m;
894157114Sscottl
895157114Sscottl#ifdef DIAGNOSTIC
896157114Sscottl	printf("%s: purging ifp %p\n", __func__, ifp);
897157114Sscottl#endif
898157114Sscottl
899157114Sscottl	IFF_LOCKGIANT(ifp);
900157114Sscottl	LIST_FOREACH_SAFE(in6m, &in6_multihead, in6m_entry, oin6m) {
901157114Sscottl		if (in6m->in6m_ifp == ifp)
902157114Sscottl			in6_delmulti(in6m);
903157114Sscottl	}
904157114Sscottl	IFF_UNLOCKGIANT(ifp);
905157114Sscottl}
906157114Sscottl