in6_ifattach.c revision 197138
1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $
3053541Sshin */
3153541Sshin
32174510Sobrien#include <sys/cdefs.h>
33174510Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/in6_ifattach.c 197138 2009-09-12 22:08:20Z hrs $");
34174510Sobrien
3553541Sshin#include <sys/param.h>
3653541Sshin#include <sys/systm.h>
3753541Sshin#include <sys/malloc.h>
3853541Sshin#include <sys/socket.h>
3953541Sshin#include <sys/sockio.h>
40193066Sjamie#include <sys/jail.h>
4153541Sshin#include <sys/kernel.h>
42196019Srwatson#include <sys/proc.h>
4378064Sume#include <sys/syslog.h>
4453541Sshin#include <sys/md5.h>
4553541Sshin
4653541Sshin#include <net/if.h>
4753541Sshin#include <net/if_dl.h>
4853541Sshin#include <net/if_types.h>
4953541Sshin#include <net/route.h>
50185571Sbz#include <net/vnet.h>
5153541Sshin
5253541Sshin#include <netinet/in.h>
5353541Sshin#include <netinet/in_var.h>
5453541Sshin#include <netinet/if_ether.h>
5581127Sume#include <netinet/in_pcb.h>
56195699Srwatson#include <netinet/ip_var.h>
57195699Srwatson#include <netinet/udp.h>
58195699Srwatson#include <netinet/udp_var.h>
5953541Sshin
6062587Sitojun#include <netinet/ip6.h>
6153541Sshin#include <netinet6/ip6_var.h>
6278064Sume#include <netinet6/in6_var.h>
6381127Sume#include <netinet6/in6_pcb.h>
6453541Sshin#include <netinet6/in6_ifattach.h>
6553541Sshin#include <netinet6/ip6_var.h>
6653541Sshin#include <netinet6/nd6.h>
67191672Sbms#include <netinet6/mld6_var.h>
6862587Sitojun#include <netinet6/scope6_var.h>
6953541Sshin
70195699SrwatsonVNET_DEFINE(unsigned long, in6_maxmtu);
71195699SrwatsonVNET_DEFINE(int, ip6_auto_linklocal);
72195699SrwatsonVNET_DEFINE(struct callout, in6_tmpaddrtimer_ch);
7381127Sume
74195727Srwatson#define	V_in6_tmpaddrtimer_ch		VNET(in6_tmpaddrtimer_ch)
75195699Srwatson
76195699SrwatsonVNET_DECLARE(struct inpcbinfo, ripcbinfo);
77195727Srwatson#define	V_ripcbinfo			VNET(ripcbinfo)
78195699Srwatson
79175162Sobrienstatic int get_rand_ifid(struct ifnet *, struct in6_addr *);
80175162Sobrienstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
81175162Sobrienstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
82175162Sobrienstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
83175162Sobrienstatic int in6_ifattach_loopback(struct ifnet *);
84175162Sobrienstatic void in6_purgemaddrs(struct ifnet *);
8553541Sshin
8662587Sitojun#define EUI64_GBIT	0x01
8762587Sitojun#define EUI64_UBIT	0x02
8862587Sitojun#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
8962587Sitojun#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
9062587Sitojun#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
9162587Sitojun#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
9262587Sitojun#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
9353541Sshin
9462587Sitojun#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
9562587Sitojun#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
9653541Sshin
9753541Sshin/*
9853541Sshin * Generate a last-resort interface identifier, when the machine has no
9953541Sshin * IEEE802/EUI64 address sources.
10062587Sitojun * The goal here is to get an interface identifier that is
10162587Sitojun * (1) random enough and (2) does not change across reboot.
10262587Sitojun * We currently use MD5(hostname) for it.
103171259Sdelphij *
104171259Sdelphij * in6 - upper 64bits are preserved
10553541Sshin */
10653541Sshinstatic int
107171259Sdelphijget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
10853541Sshin{
10953541Sshin	MD5_CTX ctxt;
110193066Sjamie	struct prison *pr;
11153541Sshin	u_int8_t digest[16];
112180291Srwatson	int hostnamelen;
11353541Sshin
114193066Sjamie	pr = curthread->td_ucred->cr_prison;
115193066Sjamie	mtx_lock(&pr->pr_mtx);
116194118Sjamie	hostnamelen = strlen(pr->pr_hostname);
11762587Sitojun#if 0
11862587Sitojun	/* we need at least several letters as seed for ifid */
119193066Sjamie	if (hostnamelen < 3) {
120193066Sjamie		mtx_unlock(&pr->pr_mtx);
12162587Sitojun		return -1;
122193066Sjamie	}
12362587Sitojun#endif
12462587Sitojun
12562587Sitojun	/* generate 8 bytes of pseudo-random value. */
12653541Sshin	bzero(&ctxt, sizeof(ctxt));
12753541Sshin	MD5Init(&ctxt);
128194118Sjamie	MD5Update(&ctxt, pr->pr_hostname, hostnamelen);
129193066Sjamie	mtx_unlock(&pr->pr_mtx);
13053541Sshin	MD5Final(digest, &ctxt);
13153541Sshin
13262587Sitojun	/* assumes sizeof(digest) > sizeof(ifid) */
13362587Sitojun	bcopy(digest, &in6->s6_addr[8], 8);
13453541Sshin
13553541Sshin	/* make sure to set "u" bit to local, and "g" bit to individual. */
13662587Sitojun	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
13762587Sitojun	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
13853541Sshin
13962587Sitojun	/* convert EUI64 into IPv6 interface identifier */
14062587Sitojun	EUI64_TO_IFID(in6);
14162587Sitojun
14253541Sshin	return 0;
14353541Sshin}
14453541Sshin
14578064Sumestatic int
146171259Sdelphijgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret)
14778064Sume{
14878064Sume	MD5_CTX ctxt;
14978064Sume	u_int8_t seed[16], digest[16], nullbuf[8];
15078064Sume	u_int32_t val32;
15178064Sume
152171259Sdelphij	/* If there's no history, start with a random seed. */
15378064Sume	bzero(nullbuf, sizeof(nullbuf));
15478064Sume	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
15578064Sume		int i;
15678064Sume
15778064Sume		for (i = 0; i < 2; i++) {
158121807Sume			val32 = arc4random();
15978064Sume			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
16078064Sume		}
161120913Sume	} else
16278064Sume		bcopy(seed0, seed, 8);
16378064Sume
16478064Sume	/* copy the right-most 64-bits of the given address */
16578064Sume	/* XXX assumption on the size of IFID */
16678064Sume	bcopy(seed1, &seed[8], 8);
16778064Sume
16878064Sume	if (0) {		/* for debugging purposes only */
16978064Sume		int i;
17078064Sume
17178064Sume		printf("generate_tmp_ifid: new randomized ID from: ");
17278064Sume		for (i = 0; i < 16; i++)
17378064Sume			printf("%02x", seed[i]);
17478064Sume		printf(" ");
17578064Sume	}
17678064Sume
17778064Sume	/* generate 16 bytes of pseudo-random value. */
17878064Sume	bzero(&ctxt, sizeof(ctxt));
17978064Sume	MD5Init(&ctxt);
18078064Sume	MD5Update(&ctxt, seed, sizeof(seed));
18178064Sume	MD5Final(digest, &ctxt);
18278064Sume
18378064Sume	/*
18478064Sume	 * RFC 3041 3.2.1. (3)
18578064Sume	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
18678064Sume	 * left-most bit is numbered 0) to zero.
18778064Sume	 */
18878064Sume	bcopy(digest, ret, 8);
18978064Sume	ret[0] &= ~EUI64_UBIT;
19078064Sume
19178064Sume	/*
19278064Sume	 * XXX: we'd like to ensure that the generated value is not zero
19378064Sume	 * for simplicity.  If the caclculated digest happens to be zero,
19478064Sume	 * use a random non-zero value as the last resort.
19578064Sume	 */
19678064Sume	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
197151465Ssuz		nd6log((LOG_INFO,
198151465Ssuz		    "generate_tmp_ifid: computed MD5 value is zero.\n"));
19978064Sume
200121807Sume		val32 = arc4random();
20178064Sume		val32 = 1 + (val32 % (0xffffffff - 1));
20278064Sume	}
20378064Sume
20478064Sume	/*
20578064Sume	 * RFC 3041 3.2.1. (4)
20678064Sume	 * Take the rightmost 64-bits of the MD5 digest and save them in
20778064Sume	 * stable storage as the history value to be used in the next
208120913Sume	 * iteration of the algorithm.
20978064Sume	 */
21078064Sume	bcopy(&digest[8], seed0, 8);
21178064Sume
21278064Sume	if (0) {		/* for debugging purposes only */
21378064Sume		int i;
21478064Sume
21578064Sume		printf("to: ");
21678064Sume		for (i = 0; i < 16; i++)
21778064Sume			printf("%02x", digest[i]);
21878064Sume		printf("\n");
21978064Sume	}
22078064Sume
22178064Sume	return 0;
22278064Sume}
22378064Sume
22453541Sshin/*
22562587Sitojun * Get interface identifier for the specified interface.
22662587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
227171259Sdelphij *
228171259Sdelphij * in6 - upper 64bits are preserved
22953541Sshin */
230151477Ssuzint
231171259Sdelphijin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
23253541Sshin{
23353541Sshin	struct ifaddr *ifa;
23453541Sshin	struct sockaddr_dl *sdl;
23562587Sitojun	u_int8_t *addr;
23662587Sitojun	size_t addrlen;
23762587Sitojun	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
23862587Sitojun	static u_int8_t allone[8] =
23962587Sitojun		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
24053541Sshin
241191337Srwatson	IF_ADDR_LOCK(ifp);
242191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
24362587Sitojun		if (ifa->ifa_addr->sa_family != AF_LINK)
24453541Sshin			continue;
24562587Sitojun		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
24662587Sitojun		if (sdl == NULL)
24762587Sitojun			continue;
24862587Sitojun		if (sdl->sdl_alen == 0)
24962587Sitojun			continue;
25062587Sitojun
25162587Sitojun		goto found;
25253541Sshin	}
253191337Srwatson	IF_ADDR_UNLOCK(ifp);
25453541Sshin
25562587Sitojun	return -1;
25662587Sitojun
25753541Sshinfound:
258194760Srwatson	IF_ADDR_LOCK_ASSERT(ifp);
25962587Sitojun	addr = LLADDR(sdl);
26062587Sitojun	addrlen = sdl->sdl_alen;
26153541Sshin
26262587Sitojun	/* get EUI64 */
26362587Sitojun	switch (ifp->if_type) {
26462587Sitojun	case IFT_ETHER:
26562587Sitojun	case IFT_FDDI:
266120049Smdodd	case IFT_ISO88025:
26762587Sitojun	case IFT_ATM:
26878064Sume	case IFT_IEEE1394:
26978064Sume#ifdef IFT_IEEE80211
27078064Sume	case IFT_IEEE80211:
27178064Sume#endif
27262587Sitojun		/* IEEE802/EUI64 cases - what others? */
27378064Sume		/* IEEE1394 uses 16byte length address starting with EUI64 */
27478064Sume		if (addrlen > 8)
27578064Sume			addrlen = 8;
27653541Sshin
27762587Sitojun		/* look at IEEE802/EUI64 only */
278191337Srwatson		if (addrlen != 8 && addrlen != 6) {
279191337Srwatson			IF_ADDR_UNLOCK(ifp);
28062587Sitojun			return -1;
281191337Srwatson		}
28253541Sshin
28362587Sitojun		/*
28462587Sitojun		 * check for invalid MAC address - on bsdi, we see it a lot
28562587Sitojun		 * since wildboar configures all-zero MAC on pccard before
28662587Sitojun		 * card insertion.
28762587Sitojun		 */
288191337Srwatson		if (bcmp(addr, allzero, addrlen) == 0) {
289191337Srwatson			IF_ADDR_UNLOCK(ifp);
29062587Sitojun			return -1;
291191337Srwatson		}
292191337Srwatson		if (bcmp(addr, allone, addrlen) == 0) {
293191337Srwatson			IF_ADDR_UNLOCK(ifp);
29462587Sitojun			return -1;
295191337Srwatson		}
29662587Sitojun
29762587Sitojun		/* make EUI64 address */
29862587Sitojun		if (addrlen == 8)
29962587Sitojun			bcopy(addr, &in6->s6_addr[8], 8);
30062587Sitojun		else if (addrlen == 6) {
30162587Sitojun			in6->s6_addr[8] = addr[0];
30262587Sitojun			in6->s6_addr[9] = addr[1];
30362587Sitojun			in6->s6_addr[10] = addr[2];
30462587Sitojun			in6->s6_addr[11] = 0xff;
30562587Sitojun			in6->s6_addr[12] = 0xfe;
30662587Sitojun			in6->s6_addr[13] = addr[3];
30762587Sitojun			in6->s6_addr[14] = addr[4];
30862587Sitojun			in6->s6_addr[15] = addr[5];
30962587Sitojun		}
31062587Sitojun		break;
31162587Sitojun
31262587Sitojun	case IFT_ARCNET:
313191337Srwatson		if (addrlen != 1) {
314191337Srwatson			IF_ADDR_UNLOCK(ifp);
31562587Sitojun			return -1;
316191337Srwatson		}
317191337Srwatson		if (!addr[0]) {
318191337Srwatson			IF_ADDR_UNLOCK(ifp);
31962587Sitojun			return -1;
320191337Srwatson		}
32162587Sitojun
32262587Sitojun		bzero(&in6->s6_addr[8], 8);
32362587Sitojun		in6->s6_addr[15] = addr[0];
32462587Sitojun
32562587Sitojun		/*
32662587Sitojun		 * due to insufficient bitwidth, we mark it local.
32762587Sitojun		 */
32862587Sitojun		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
32962587Sitojun		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
33062587Sitojun		break;
33162587Sitojun
33262587Sitojun	case IFT_GIF:
33362587Sitojun#ifdef IFT_STF
33462587Sitojun	case IFT_STF:
33553541Sshin#endif
33662587Sitojun		/*
33778064Sume		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
33862587Sitojun		 * however, IPv4 address is not very suitable as unique
33962587Sitojun		 * identifier source (can be renumbered).
34062587Sitojun		 * we don't do this.
34162587Sitojun		 */
342191337Srwatson		IF_ADDR_UNLOCK(ifp);
34362587Sitojun		return -1;
34462587Sitojun
34562587Sitojun	default:
346191337Srwatson		IF_ADDR_UNLOCK(ifp);
34762587Sitojun		return -1;
34853541Sshin	}
34962587Sitojun
35062587Sitojun	/* sanity check: g bit must not indicate "group" */
351191337Srwatson	if (EUI64_GROUP(in6)) {
352191337Srwatson		IF_ADDR_UNLOCK(ifp);
35362587Sitojun		return -1;
354191337Srwatson	}
35562587Sitojun
35662587Sitojun	/* convert EUI64 into IPv6 interface identifier */
35762587Sitojun	EUI64_TO_IFID(in6);
35862587Sitojun
35962587Sitojun	/*
36062587Sitojun	 * sanity check: ifid must not be all zero, avoid conflict with
36162587Sitojun	 * subnet router anycast
36262587Sitojun	 */
36362587Sitojun	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
36462587Sitojun	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
365191337Srwatson		IF_ADDR_UNLOCK(ifp);
36662587Sitojun		return -1;
36762587Sitojun	}
36862587Sitojun
369191337Srwatson	IF_ADDR_UNLOCK(ifp);
37062587Sitojun	return 0;
37153541Sshin}
37253541Sshin
37353541Sshin/*
37462587Sitojun * Get interface identifier for the specified interface.  If it is not
37562587Sitojun * available on ifp0, borrow interface identifier from other information
37662587Sitojun * sources.
377171259Sdelphij *
378171259Sdelphij * altifp - secondary EUI64 source
37953541Sshin */
38062587Sitojunstatic int
381171259Sdelphijget_ifid(struct ifnet *ifp0, struct ifnet *altifp,
382171259Sdelphij    struct in6_addr *in6)
38353541Sshin{
38453541Sshin	struct ifnet *ifp;
38553541Sshin
38662587Sitojun	/* first, try to get it from the interface itself */
387151477Ssuz	if (in6_get_hw_ifid(ifp0, in6) == 0) {
38878064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
38978064Sume		    if_name(ifp0)));
39062587Sitojun		goto success;
39162587Sitojun	}
39253541Sshin
39362587Sitojun	/* try secondary EUI64 source. this basically is for ATM PVC */
394151477Ssuz	if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
39578064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
39678064Sume		    if_name(ifp0), if_name(altifp)));
39762587Sitojun		goto success;
39862587Sitojun	}
39962587Sitojun
40062587Sitojun	/* next, try to get it from some other hardware interface */
401196481Srwatson	IFNET_RLOCK_NOSLEEP();
402181803Sbz	for (ifp = V_ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
40362587Sitojun		if (ifp == ifp0)
40462587Sitojun			continue;
405151477Ssuz		if (in6_get_hw_ifid(ifp, in6) != 0)
40662587Sitojun			continue;
40762587Sitojun
40862587Sitojun		/*
40962587Sitojun		 * to borrow ifid from other interface, ifid needs to be
41062587Sitojun		 * globally unique
41162587Sitojun		 */
41262587Sitojun		if (IFID_UNIVERSAL(in6)) {
41378064Sume			nd6log((LOG_DEBUG,
41478064Sume			    "%s: borrow interface identifier from %s\n",
41578064Sume			    if_name(ifp0), if_name(ifp)));
416196481Srwatson			IFNET_RUNLOCK_NOSLEEP();
41762587Sitojun			goto success;
41862587Sitojun		}
41962587Sitojun	}
420196481Srwatson	IFNET_RUNLOCK_NOSLEEP();
42162587Sitojun
42262587Sitojun	/* last resort: get from random number source */
42362587Sitojun	if (get_rand_ifid(ifp, in6) == 0) {
42478064Sume		nd6log((LOG_DEBUG,
42578064Sume		    "%s: interface identifier generated by random number\n",
42678064Sume		    if_name(ifp0)));
42762587Sitojun		goto success;
42862587Sitojun	}
42962587Sitojun
43066504Sitojun	printf("%s: failed to get interface identifier\n", if_name(ifp0));
43162587Sitojun	return -1;
43262587Sitojun
43362587Sitojunsuccess:
434120913Sume	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
435120913Sume	    if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
436120913Sume	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
437120913Sume	    in6->s6_addr[14], in6->s6_addr[15]));
43862587Sitojun	return 0;
43962587Sitojun}
44062587Sitojun
441171259Sdelphij/*
442171259Sdelphij * altifp - secondary EUI64 source
443171259Sdelphij */
44462587Sitojunstatic int
445171259Sdelphijin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
44678064Sume{
44762587Sitojun	struct in6_ifaddr *ia;
44878064Sume	struct in6_aliasreq ifra;
449151539Ssuz	struct nd_prefixctl pr0;
45078064Sume	int i, error;
45162587Sitojun
45262587Sitojun	/*
45378064Sume	 * configure link-local address.
45462587Sitojun	 */
45578064Sume	bzero(&ifra, sizeof(ifra));
45662587Sitojun
45762587Sitojun	/*
45878064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
45978064Sume	 * for safety.
46062587Sitojun	 */
46178064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
46262587Sitojun
46378064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
46478064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
465148385Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
46678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
46778064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
46878064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
46978064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
47078064Sume	} else {
47178064Sume		if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
47278064Sume			nd6log((LOG_ERR,
47378064Sume			    "%s: no ifid available\n", if_name(ifp)));
474120913Sume			return (-1);
47562587Sitojun		}
47662587Sitojun	}
477148385Sume	if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
478148385Sume		return (-1);
47962587Sitojun
48078064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
48178064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
48278064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask64;
48378064Sume	/* link-local addresses should NEVER expire. */
48478064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
48578064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
48662587Sitojun
48778064Sume	/*
48878064Sume	 * Now call in6_update_ifa() to do a bunch of procedures to configure
489151465Ssuz	 * a link-local address. We can set the 3rd argument to NULL, because
49095023Ssuz	 * we know there's no other link-local address on the interface
49195023Ssuz	 * and therefore we are adding one (instead of updating one).
49278064Sume	 */
493151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL,
494151539Ssuz				    IN6_IFAUPDATE_DADDELAY)) != 0) {
49562587Sitojun		/*
49678064Sume		 * XXX: When the interface does not support IPv6, this call
49778064Sume		 * would fail in the SIOCSIFADDR ioctl.  I believe the
49878064Sume		 * notification is rather confusing in this case, so just
499120913Sume		 * suppress it.  (jinmei@kame.net 20010130)
50062587Sitojun		 */
50178064Sume		if (error != EAFNOSUPPORT)
502151465Ssuz			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
50378064Sume			    "configure a link-local address on %s "
50478064Sume			    "(errno=%d)\n",
505151465Ssuz			    if_name(ifp), error));
506120856Sume		return (-1);
50762587Sitojun	}
50862587Sitojun
50978064Sume	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
51078064Sume#ifdef DIAGNOSTIC
51178064Sume	if (!ia) {
51278064Sume		panic("ia == NULL in in6_ifattach_linklocal");
51395023Ssuz		/* NOTREACHED */
51478064Sume	}
51562587Sitojun#endif
516194760Srwatson	ifa_free(&ia->ia_ifa);
51753541Sshin
51878064Sume	/*
519120913Sume	 * Make the link-local prefix (fe80::%link/64) as on-link.
52078064Sume	 * Since we'd like to manage prefixes separately from addresses,
52178064Sume	 * we make an ND6 prefix structure for the link-local prefix,
52278064Sume	 * and add it to the prefix list as a never-expire prefix.
52378064Sume	 * XXX: this change might affect some existing code base...
52478064Sume	 */
52578064Sume	bzero(&pr0, sizeof(pr0));
52678064Sume	pr0.ndpr_ifp = ifp;
52778064Sume	/* this should be 64 at this moment. */
52878064Sume	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
52978064Sume	pr0.ndpr_prefix = ifra.ifra_addr;
53078064Sume	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
53178064Sume	for (i = 0; i < 4; i++) {
53278064Sume		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
533120913Sume		    in6mask64.s6_addr32[i];
53462587Sitojun	}
53578064Sume	/*
53678064Sume	 * Initialize parameters.  The link-local prefix must always be
53778064Sume	 * on-link, and its lifetimes never expire.
53878064Sume	 */
53978064Sume	pr0.ndpr_raf_onlink = 1;
54078064Sume	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
54178064Sume	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
54278064Sume	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
54378064Sume	/*
54478064Sume	 * Since there is no other link-local addresses, nd6_prefix_lookup()
54578064Sume	 * probably returns NULL.  However, we cannot always expect the result.
54678064Sume	 * For example, if we first remove the (only) existing link-local
54778064Sume	 * address, and then reconfigure another one, the prefix is still
54878064Sume	 * valid with referring to the old link-local address.
54978064Sume	 */
55078064Sume	if (nd6_prefix_lookup(&pr0) == NULL) {
55178064Sume		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
552120856Sume			return (error);
55378064Sume	}
55462587Sitojun
55562587Sitojun	return 0;
55662587Sitojun}
55762587Sitojun
558171259Sdelphij/*
559171259Sdelphij * ifp - must be IFT_LOOP
560171259Sdelphij */
56162587Sitojunstatic int
562171259Sdelphijin6_ifattach_loopback(struct ifnet *ifp)
56362587Sitojun{
56478064Sume	struct in6_aliasreq ifra;
56578064Sume	int error;
56662587Sitojun
56778064Sume	bzero(&ifra, sizeof(ifra));
56878064Sume
56962587Sitojun	/*
57078064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
57178064Sume	 * for safety.
57262587Sitojun	 */
57378064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
57462587Sitojun
57578064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
57678064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
57778064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask128;
57862587Sitojun
57962587Sitojun	/*
58062587Sitojun	 * Always initialize ia_dstaddr (= broadcast address) to loopback
58178064Sume	 * address.  Follows IPv4 practice - see in_ifinit().
58262587Sitojun	 */
58378064Sume	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
58478064Sume	ifra.ifra_dstaddr.sin6_family = AF_INET6;
58578064Sume	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
58662587Sitojun
58778064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
58878064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
58978064Sume	ifra.ifra_addr.sin6_addr = in6addr_loopback;
59062587Sitojun
59178064Sume	/* the loopback  address should NEVER expire. */
59278064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
59378064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
59462587Sitojun
59595023Ssuz	/* we don't need to perform DAD on loopback interfaces. */
59678064Sume	ifra.ifra_flags |= IN6_IFF_NODAD;
59778064Sume
59878064Sume	/* skip registration to the prefix list. XXX should be temporary. */
59978064Sume	ifra.ifra_flags |= IN6_IFF_NOPFX;
60078064Sume
60178064Sume	/*
60295023Ssuz	 * We are sure that this is a newly assigned address, so we can set
60395023Ssuz	 * NULL to the 3rd arg.
60478064Sume	 */
605151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
606151465Ssuz		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
60778064Sume		    "the loopback address on %s (errno=%d)\n",
608151465Ssuz		    if_name(ifp), error));
609120856Sume		return (-1);
61062587Sitojun	}
61162587Sitojun
61262587Sitojun	return 0;
61362587Sitojun}
61462587Sitojun
61562587Sitojun/*
61662587Sitojun * compute NI group address, based on the current hostname setting.
61762587Sitojun * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
61862587Sitojun *
61962587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid.
62062587Sitojun */
62178064Sumeint
622171259Sdelphijin6_nigroup(struct ifnet *ifp, const char *name, int namelen,
623171259Sdelphij    struct in6_addr *in6)
62462587Sitojun{
625193066Sjamie	struct prison *pr;
62662587Sitojun	const char *p;
62778064Sume	u_char *q;
62862587Sitojun	MD5_CTX ctxt;
62962587Sitojun	u_int8_t digest[16];
63062587Sitojun	char l;
63178064Sume	char n[64];	/* a single label must not exceed 63 chars */
63262587Sitojun
633192895Sjamie	/*
634192895Sjamie	 * If no name is given and namelen is -1,
635192895Sjamie	 * we try to do the hostname lookup ourselves.
636192895Sjamie	 */
637192895Sjamie	if (!name && namelen == -1) {
638193066Sjamie		pr = curthread->td_ucred->cr_prison;
639193066Sjamie		mtx_lock(&pr->pr_mtx);
640194118Sjamie		name = pr->pr_hostname;
641192895Sjamie		namelen = strlen(name);
642192895Sjamie	} else
643193066Sjamie		pr = NULL;
644192895Sjamie	if (!name || !namelen) {
645193066Sjamie		if (pr != NULL)
646193066Sjamie			mtx_unlock(&pr->pr_mtx);
64762587Sitojun		return -1;
648192895Sjamie	}
64962587Sitojun
65062587Sitojun	p = name;
65162587Sitojun	while (p && *p && *p != '.' && p - name < namelen)
65262587Sitojun		p++;
653192895Sjamie	if (p == name || p - name > sizeof(n) - 1) {
654193066Sjamie		if (pr != NULL)
655193066Sjamie			mtx_unlock(&pr->pr_mtx);
65695023Ssuz		return -1;	/* label too long */
657192895Sjamie	}
65862587Sitojun	l = p - name;
65978064Sume	strncpy(n, name, l);
660193066Sjamie	if (pr != NULL)
661193066Sjamie		mtx_unlock(&pr->pr_mtx);
66278064Sume	n[(int)l] = '\0';
66378064Sume	for (q = n; *q; q++) {
66478064Sume		if ('A' <= *q && *q <= 'Z')
66578064Sume			*q = *q - 'A' + 'a';
66678064Sume	}
66762587Sitojun
66862587Sitojun	/* generate 8 bytes of pseudo-random value. */
66962587Sitojun	bzero(&ctxt, sizeof(ctxt));
67062587Sitojun	MD5Init(&ctxt);
67162587Sitojun	MD5Update(&ctxt, &l, sizeof(l));
67278064Sume	MD5Update(&ctxt, n, l);
67362587Sitojun	MD5Final(digest, &ctxt);
67462587Sitojun
67562587Sitojun	bzero(in6, sizeof(*in6));
676151465Ssuz	in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
67762587Sitojun	in6->s6_addr8[11] = 2;
67862587Sitojun	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
679148385Sume	if (in6_setscope(in6, ifp, NULL))
680148385Sume		return (-1); /* XXX: should not fail */
68162587Sitojun
68262587Sitojun	return 0;
68362587Sitojun}
68462587Sitojun
68562587Sitojun/*
68662587Sitojun * XXX multiple loopback interface needs more care.  for instance,
68762587Sitojun * nodelocal address needs to be configured onto only one of them.
68862587Sitojun * XXX multiple link-local address case
689171259Sdelphij *
690171259Sdelphij * altifp - secondary EUI64 source
69162587Sitojun */
69262587Sitojunvoid
693171259Sdelphijin6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
69462587Sitojun{
69562587Sitojun	struct in6_ifaddr *ia;
69662587Sitojun	struct in6_addr in6;
69762587Sitojun
69878064Sume	/* some of the interfaces are inherently not IPv6 capable */
69978064Sume	switch (ifp->if_type) {
700126263Smlaier	case IFT_PFLOG:
701126263Smlaier	case IFT_PFSYNC:
702142215Sglebius	case IFT_CARP:
70378064Sume		return;
70478064Sume	}
70578064Sume
70653541Sshin	/*
70762587Sitojun	 * quirks based on interface type
70853541Sshin	 */
70962587Sitojun	switch (ifp->if_type) {
71062587Sitojun#ifdef IFT_STF
71162587Sitojun	case IFT_STF:
71262587Sitojun		/*
71395023Ssuz		 * 6to4 interface is a very special kind of beast.
71495023Ssuz		 * no multicast, no linklocal.  RFC2529 specifies how to make
71595023Ssuz		 * linklocals for 6to4 interface, but there's no use and
71695023Ssuz		 * it is rather harmful to have one.
71762587Sitojun		 */
71862587Sitojun		goto statinit;
71962587Sitojun#endif
72062587Sitojun	default:
72162587Sitojun		break;
72253541Sshin	}
72353541Sshin
72453541Sshin	/*
72562587Sitojun	 * usually, we require multicast capability to the interface
72653541Sshin	 */
72762587Sitojun	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
728151465Ssuz		nd6log((LOG_INFO, "in6_ifattach: "
72978064Sume		    "%s is not multicast capable, IPv6 not enabled\n",
730151465Ssuz		    if_name(ifp)));
73162587Sitojun		return;
73262587Sitojun	}
73362587Sitojun
73453541Sshin	/*
73578064Sume	 * assign loopback address for loopback interface.
73678064Sume	 * XXX multiple loopback interface case.
73753541Sshin	 */
73878064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
739194760Srwatson		struct ifaddr *ifa;
740194760Srwatson
74178064Sume		in6 = in6addr_loopback;
742194760Srwatson		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6);
743194760Srwatson		if (ifa == NULL) {
74462587Sitojun			if (in6_ifattach_loopback(ifp) != 0)
74562587Sitojun				return;
746194760Srwatson		} else
747194760Srwatson			ifa_free(ifa);
74862587Sitojun	}
74953541Sshin
75053541Sshin	/*
751120913Sume	 * assign a link-local address, if there's none.
75253541Sshin	 */
753197138Shrs	if (ifp->if_type != IFT_BRIDGE &&
754197138Shrs	    !(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
755197138Shrs	    ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
756197138Shrs		int error;
757197138Shrs
75878064Sume		ia = in6ifa_ifpforlinklocal(ifp, 0);
75978064Sume		if (ia == NULL) {
760197138Shrs			error = in6_ifattach_linklocal(ifp, altifp);
761197138Shrs			if (error)
762197138Shrs				log(LOG_NOTICE, "in6_ifattach_linklocal: "
763197138Shrs				    "failed to add a link-local addr to %s\n",
764197138Shrs				    if_name(ifp));
765194760Srwatson		} else
766194760Srwatson			ifa_free(&ia->ia_ifa);
76753541Sshin	}
76853541Sshin
76978064Sume#ifdef IFT_STF			/* XXX */
770120913Sumestatinit:
77178064Sume#endif
77262587Sitojun
77353541Sshin	/* update dynamically. */
774181803Sbz	if (V_in6_maxmtu < ifp->if_mtu)
775181803Sbz		V_in6_maxmtu = ifp->if_mtu;
77653541Sshin}
77753541Sshin
77862587Sitojun/*
77962587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment.
78078064Sume * We don't need this function in bsdi, because interfaces are never removed
78178064Sume * from the ifnet list in bsdi.
78262587Sitojun */
78353541Sshinvoid
784171259Sdelphijin6_ifdetach(struct ifnet *ifp)
78553541Sshin{
786194907Srwatson	struct in6_ifaddr *ia;
78762587Sitojun	struct ifaddr *ifa, *next;
788193232Sbz	struct radix_node_head *rnh;
78953541Sshin	struct rtentry *rt;
79053541Sshin	short rtflags;
79162587Sitojun	struct sockaddr_in6 sin6;
792170202Sjinmei	struct in6_multi_mship *imm;
79353541Sshin
79462587Sitojun	/* remove neighbor management table */
79562587Sitojun	nd6_purge(ifp);
79662587Sitojun
79762587Sitojun	/* nuke any of IPv6 addresses we have */
798191340Srwatson	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
79962587Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
80062587Sitojun			continue;
80178064Sume		in6_purgeaddr(ifa);
80262587Sitojun	}
80362587Sitojun
80462587Sitojun	/* undo everything done by in6_ifattach(), just in case */
805191340Srwatson	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
80653541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6
80753541Sshin		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
80853541Sshin			continue;
80953541Sshin		}
81053541Sshin
81153541Sshin		ia = (struct in6_ifaddr *)ifa;
81253541Sshin
813170202Sjinmei		/*
814170202Sjinmei		 * leave from multicast groups we have joined for the interface
815170202Sjinmei		 */
816170202Sjinmei		while ((imm = ia->ia6_memberships.lh_first) != NULL) {
817170202Sjinmei			LIST_REMOVE(imm, i6mm_chain);
818170202Sjinmei			in6_leavegroup(imm);
819170202Sjinmei		}
820170202Sjinmei
82153541Sshin		/* remove from the routing table */
822120913Sume		if ((ia->ia_flags & IFA_ROUTE) &&
823120913Sume		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
82453541Sshin			rtflags = rt->rt_flags;
825187946Sbz			RTFREE_LOCKED(rt);
826120913Sume			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
827120913Sume			    (struct sockaddr *)&ia->ia_addr,
828120913Sume			    (struct sockaddr *)&ia->ia_prefixmask,
829120913Sume			    rtflags, (struct rtentry **)0);
83053541Sshin		}
83153541Sshin
83253541Sshin		/* remove from the linked list */
833191337Srwatson		IF_ADDR_LOCK(ifp);
834194907Srwatson		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
835191337Srwatson		IF_ADDR_UNLOCK(ifp);
836194907Srwatson		ifa_free(ifa);				/* if_addrhead */
83753541Sshin
838194971Srwatson		IN6_IFADDR_WLOCK();
839194907Srwatson		TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
840194971Srwatson		IN6_IFADDR_WUNLOCK();
841194907Srwatson		ifa_free(ifa);
84253541Sshin	}
84362587Sitojun
844181803Sbz	in6_pcbpurgeif0(&V_udbinfo, ifp);
845181803Sbz	in6_pcbpurgeif0(&V_ripcbinfo, ifp);
846170613Sbms	/* leave from all multicast groups joined */
847170613Sbms	in6_purgemaddrs(ifp);
848120913Sume
84978064Sume	/*
85078064Sume	 * remove neighbor management table.  we call it twice just to make
85178064Sume	 * sure we nuke everything.  maybe we need just one call.
85278064Sume	 * XXX: since the first call did not release addresses, some prefixes
85378064Sume	 * might remain.  We should call nd6_purge() again to release the
85478064Sume	 * prefixes after removing all addresses above.
85578064Sume	 * (Or can we just delay calling nd6_purge until at this point?)
85678064Sume	 */
85762587Sitojun	nd6_purge(ifp);
85862587Sitojun
85962587Sitojun	/* remove route to link-local allnodes multicast (ff02::1) */
86062587Sitojun	bzero(&sin6, sizeof(sin6));
86162587Sitojun	sin6.sin6_len = sizeof(struct sockaddr_in6);
86262587Sitojun	sin6.sin6_family = AF_INET6;
86362587Sitojun	sin6.sin6_addr = in6addr_linklocal_allnodes;
864148385Sume	if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
865148385Sume		/* XXX: should not fail */
866148385Sume		return;
867121770Ssam	/* XXX grab lock first to avoid LOR */
868193232Sbz	rnh = rt_tables_get_rnh(0, AF_INET6);
869193232Sbz	if (rnh != NULL) {
870193232Sbz		RADIX_NODE_HEAD_LOCK(rnh);
871185965Skmacy		rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED);
872124333Struckman		if (rt) {
873124333Struckman			if (rt->rt_ifp == ifp)
874124333Struckman				rtexpunge(rt);
875124333Struckman			RTFREE_LOCKED(rt);
876124333Struckman		}
877193232Sbz		RADIX_NODE_HEAD_UNLOCK(rnh);
87862587Sitojun	}
87953541Sshin}
88078064Sume
881151539Ssuzint
882171259Sdelphijin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf,
883171259Sdelphij    const u_int8_t *baseid, int generate)
88478064Sume{
88578064Sume	u_int8_t nullbuf[8];
886121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
88778064Sume
88878064Sume	bzero(nullbuf, sizeof(nullbuf));
88978064Sume	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
89078064Sume		/* we've never created a random ID.  Create a new one. */
89178064Sume		generate = 1;
89278064Sume	}
89378064Sume
89478064Sume	if (generate) {
89578064Sume		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
89678064Sume
89778064Sume		/* generate_tmp_ifid will update seedn and buf */
89878064Sume		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
899120913Sume		    ndi->randomid);
90078064Sume	}
90178064Sume	bcopy(ndi->randomid, retbuf, 8);
902151539Ssuz
903151539Ssuz	return (0);
90478064Sume}
90578064Sume
90678064Sumevoid
907191688Szecin6_tmpaddrtimer(void *arg)
90878064Sume{
909191688Szec	CURVNET_SET((struct vnet *) arg);
91078064Sume	struct nd_ifinfo *ndi;
91178064Sume	u_int8_t nullbuf[8];
912121161Sume	struct ifnet *ifp;
91378064Sume
914181803Sbz	callout_reset(&V_in6_tmpaddrtimer_ch,
915181803Sbz	    (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
916191688Szec	    V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet);
91778064Sume
91878064Sume	bzero(nullbuf, sizeof(nullbuf));
919181887Sjulian	for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
920181888Sjulian	    ifp = TAILQ_NEXT(ifp, if_list)) {
921121161Sume		ndi = ND_IFINFO(ifp);
92278064Sume		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
92378064Sume			/*
92478064Sume			 * We've been generating a random ID on this interface.
92578064Sume			 * Create a new one.
92678064Sume			 */
92778064Sume			(void)generate_tmp_ifid(ndi->randomseed0,
928120913Sume			    ndi->randomseed1, ndi->randomid);
92978064Sume		}
93078064Sume	}
93178064Sume
932191688Szec	CURVNET_RESTORE();
93378064Sume}
934170613Sbms
935170613Sbmsstatic void
936171259Sdelphijin6_purgemaddrs(struct ifnet *ifp)
937170613Sbms{
938191672Sbms	LIST_HEAD(,in6_multi)	 purgeinms;
939191672Sbms	struct in6_multi	*inm, *tinm;
940191672Sbms	struct ifmultiaddr	*ifma;
941170613Sbms
942191672Sbms	LIST_INIT(&purgeinms);
943191672Sbms	IN6_MULTI_LOCK();
944191672Sbms
945191672Sbms	/*
946191672Sbms	 * Extract list of in6_multi associated with the detaching ifp
947191672Sbms	 * which the PF_INET6 layer is about to release.
948191672Sbms	 * We need to do this as IF_ADDR_LOCK() may be re-acquired
949191672Sbms	 * by code further down.
950191672Sbms	 */
951191672Sbms	IF_ADDR_LOCK(ifp);
952191672Sbms	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
953191672Sbms		if (ifma->ifma_addr->sa_family != AF_INET6 ||
954191672Sbms		    ifma->ifma_protospec == NULL)
955191672Sbms			continue;
956191672Sbms		inm = (struct in6_multi *)ifma->ifma_protospec;
957191672Sbms		LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry);
958170613Sbms	}
959191672Sbms	IF_ADDR_UNLOCK(ifp);
960191672Sbms
961191672Sbms	LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) {
962191672Sbms		LIST_REMOVE(inm, in6m_entry);
963191672Sbms		in6m_release_locked(inm);
964191672Sbms	}
965191672Sbms	mld_ifdetach(ifp);
966191672Sbms
967191672Sbms	IN6_MULTI_UNLOCK();
968170613Sbms}
969