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$");
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
70207369SbzVNET_DEFINE(unsigned long, in6_maxmtu) = 0;
71207369Sbz
72207369Sbz#ifdef IP6_AUTO_LINKLOCAL
73207369SbzVNET_DEFINE(int, ip6_auto_linklocal) = IP6_AUTO_LINKLOCAL;
74207369Sbz#else
75207369SbzVNET_DEFINE(int, ip6_auto_linklocal) = 1;	/* enabled by default */
76207369Sbz#endif
77207369Sbz
78195699SrwatsonVNET_DEFINE(struct callout, in6_tmpaddrtimer_ch);
79195727Srwatson#define	V_in6_tmpaddrtimer_ch		VNET(in6_tmpaddrtimer_ch)
80195699Srwatson
81195699SrwatsonVNET_DECLARE(struct inpcbinfo, ripcbinfo);
82195727Srwatson#define	V_ripcbinfo			VNET(ripcbinfo)
83195699Srwatson
84175162Sobrienstatic int get_rand_ifid(struct ifnet *, struct in6_addr *);
85175162Sobrienstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
86175162Sobrienstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
87175162Sobrienstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
88175162Sobrienstatic int in6_ifattach_loopback(struct ifnet *);
89175162Sobrienstatic void in6_purgemaddrs(struct ifnet *);
9053541Sshin
9162587Sitojun#define EUI64_GBIT	0x01
9262587Sitojun#define EUI64_UBIT	0x02
9362587Sitojun#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
9462587Sitojun#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
9562587Sitojun#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
9662587Sitojun#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
9762587Sitojun#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
9853541Sshin
9962587Sitojun#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
10062587Sitojun#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
10153541Sshin
10253541Sshin/*
10353541Sshin * Generate a last-resort interface identifier, when the machine has no
10453541Sshin * IEEE802/EUI64 address sources.
10562587Sitojun * The goal here is to get an interface identifier that is
10662587Sitojun * (1) random enough and (2) does not change across reboot.
10762587Sitojun * We currently use MD5(hostname) for it.
108171259Sdelphij *
109171259Sdelphij * in6 - upper 64bits are preserved
11053541Sshin */
11153541Sshinstatic int
112171259Sdelphijget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
11353541Sshin{
11453541Sshin	MD5_CTX ctxt;
115193066Sjamie	struct prison *pr;
11653541Sshin	u_int8_t digest[16];
117180291Srwatson	int hostnamelen;
11853541Sshin
119193066Sjamie	pr = curthread->td_ucred->cr_prison;
120193066Sjamie	mtx_lock(&pr->pr_mtx);
121194118Sjamie	hostnamelen = strlen(pr->pr_hostname);
12262587Sitojun#if 0
12362587Sitojun	/* we need at least several letters as seed for ifid */
124193066Sjamie	if (hostnamelen < 3) {
125193066Sjamie		mtx_unlock(&pr->pr_mtx);
12662587Sitojun		return -1;
127193066Sjamie	}
12862587Sitojun#endif
12962587Sitojun
13062587Sitojun	/* generate 8 bytes of pseudo-random value. */
13153541Sshin	bzero(&ctxt, sizeof(ctxt));
13253541Sshin	MD5Init(&ctxt);
133194118Sjamie	MD5Update(&ctxt, pr->pr_hostname, hostnamelen);
134193066Sjamie	mtx_unlock(&pr->pr_mtx);
13553541Sshin	MD5Final(digest, &ctxt);
13653541Sshin
13762587Sitojun	/* assumes sizeof(digest) > sizeof(ifid) */
13862587Sitojun	bcopy(digest, &in6->s6_addr[8], 8);
13953541Sshin
14053541Sshin	/* make sure to set "u" bit to local, and "g" bit to individual. */
14162587Sitojun	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
14262587Sitojun	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
14353541Sshin
14462587Sitojun	/* convert EUI64 into IPv6 interface identifier */
14562587Sitojun	EUI64_TO_IFID(in6);
14662587Sitojun
14753541Sshin	return 0;
14853541Sshin}
14953541Sshin
15078064Sumestatic int
151171259Sdelphijgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret)
15278064Sume{
15378064Sume	MD5_CTX ctxt;
15478064Sume	u_int8_t seed[16], digest[16], nullbuf[8];
15578064Sume	u_int32_t val32;
15678064Sume
157171259Sdelphij	/* If there's no history, start with a random seed. */
15878064Sume	bzero(nullbuf, sizeof(nullbuf));
15978064Sume	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
16078064Sume		int i;
16178064Sume
16278064Sume		for (i = 0; i < 2; i++) {
163121807Sume			val32 = arc4random();
16478064Sume			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
16578064Sume		}
166120913Sume	} else
16778064Sume		bcopy(seed0, seed, 8);
16878064Sume
16978064Sume	/* copy the right-most 64-bits of the given address */
17078064Sume	/* XXX assumption on the size of IFID */
17178064Sume	bcopy(seed1, &seed[8], 8);
17278064Sume
17378064Sume	if (0) {		/* for debugging purposes only */
17478064Sume		int i;
17578064Sume
17678064Sume		printf("generate_tmp_ifid: new randomized ID from: ");
17778064Sume		for (i = 0; i < 16; i++)
17878064Sume			printf("%02x", seed[i]);
17978064Sume		printf(" ");
18078064Sume	}
18178064Sume
18278064Sume	/* generate 16 bytes of pseudo-random value. */
18378064Sume	bzero(&ctxt, sizeof(ctxt));
18478064Sume	MD5Init(&ctxt);
18578064Sume	MD5Update(&ctxt, seed, sizeof(seed));
18678064Sume	MD5Final(digest, &ctxt);
18778064Sume
18878064Sume	/*
18978064Sume	 * RFC 3041 3.2.1. (3)
19078064Sume	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
19178064Sume	 * left-most bit is numbered 0) to zero.
19278064Sume	 */
19378064Sume	bcopy(digest, ret, 8);
19478064Sume	ret[0] &= ~EUI64_UBIT;
19578064Sume
19678064Sume	/*
19778064Sume	 * XXX: we'd like to ensure that the generated value is not zero
19878064Sume	 * for simplicity.  If the caclculated digest happens to be zero,
19978064Sume	 * use a random non-zero value as the last resort.
20078064Sume	 */
20178064Sume	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
202151465Ssuz		nd6log((LOG_INFO,
203151465Ssuz		    "generate_tmp_ifid: computed MD5 value is zero.\n"));
20478064Sume
205121807Sume		val32 = arc4random();
20678064Sume		val32 = 1 + (val32 % (0xffffffff - 1));
20778064Sume	}
20878064Sume
20978064Sume	/*
21078064Sume	 * RFC 3041 3.2.1. (4)
21178064Sume	 * Take the rightmost 64-bits of the MD5 digest and save them in
21278064Sume	 * stable storage as the history value to be used in the next
213120913Sume	 * iteration of the algorithm.
21478064Sume	 */
21578064Sume	bcopy(&digest[8], seed0, 8);
21678064Sume
21778064Sume	if (0) {		/* for debugging purposes only */
21878064Sume		int i;
21978064Sume
22078064Sume		printf("to: ");
22178064Sume		for (i = 0; i < 16; i++)
22278064Sume			printf("%02x", digest[i]);
22378064Sume		printf("\n");
22478064Sume	}
22578064Sume
22678064Sume	return 0;
22778064Sume}
22878064Sume
22953541Sshin/*
23062587Sitojun * Get interface identifier for the specified interface.
23162587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
232171259Sdelphij *
233171259Sdelphij * in6 - upper 64bits are preserved
23453541Sshin */
235151477Ssuzint
236171259Sdelphijin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
23753541Sshin{
23853541Sshin	struct ifaddr *ifa;
23953541Sshin	struct sockaddr_dl *sdl;
24062587Sitojun	u_int8_t *addr;
24162587Sitojun	size_t addrlen;
24262587Sitojun	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
24362587Sitojun	static u_int8_t allone[8] =
24462587Sitojun		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
24553541Sshin
246229621Sjhb	IF_ADDR_RLOCK(ifp);
247191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
24862587Sitojun		if (ifa->ifa_addr->sa_family != AF_LINK)
24953541Sshin			continue;
25062587Sitojun		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
25162587Sitojun		if (sdl == NULL)
25262587Sitojun			continue;
25362587Sitojun		if (sdl->sdl_alen == 0)
25462587Sitojun			continue;
25562587Sitojun
25662587Sitojun		goto found;
25753541Sshin	}
258229621Sjhb	IF_ADDR_RUNLOCK(ifp);
25953541Sshin
26062587Sitojun	return -1;
26162587Sitojun
26253541Sshinfound:
263194760Srwatson	IF_ADDR_LOCK_ASSERT(ifp);
26462587Sitojun	addr = LLADDR(sdl);
26562587Sitojun	addrlen = sdl->sdl_alen;
26653541Sshin
26762587Sitojun	/* get EUI64 */
26862587Sitojun	switch (ifp->if_type) {
269252511Shrs	case IFT_BRIDGE:
27062587Sitojun	case IFT_ETHER:
271216650Sjhay	case IFT_L2VLAN:
27262587Sitojun	case IFT_FDDI:
273120049Smdodd	case IFT_ISO88025:
27462587Sitojun	case IFT_ATM:
27578064Sume	case IFT_IEEE1394:
27678064Sume#ifdef IFT_IEEE80211
27778064Sume	case IFT_IEEE80211:
27878064Sume#endif
27962587Sitojun		/* IEEE802/EUI64 cases - what others? */
28078064Sume		/* IEEE1394 uses 16byte length address starting with EUI64 */
28178064Sume		if (addrlen > 8)
28278064Sume			addrlen = 8;
28353541Sshin
28462587Sitojun		/* look at IEEE802/EUI64 only */
285191337Srwatson		if (addrlen != 8 && addrlen != 6) {
286229621Sjhb			IF_ADDR_RUNLOCK(ifp);
28762587Sitojun			return -1;
288191337Srwatson		}
28953541Sshin
29062587Sitojun		/*
29162587Sitojun		 * check for invalid MAC address - on bsdi, we see it a lot
29262587Sitojun		 * since wildboar configures all-zero MAC on pccard before
29362587Sitojun		 * card insertion.
29462587Sitojun		 */
295191337Srwatson		if (bcmp(addr, allzero, addrlen) == 0) {
296229621Sjhb			IF_ADDR_RUNLOCK(ifp);
29762587Sitojun			return -1;
298191337Srwatson		}
299191337Srwatson		if (bcmp(addr, allone, addrlen) == 0) {
300229621Sjhb			IF_ADDR_RUNLOCK(ifp);
30162587Sitojun			return -1;
302191337Srwatson		}
30362587Sitojun
30462587Sitojun		/* make EUI64 address */
30562587Sitojun		if (addrlen == 8)
30662587Sitojun			bcopy(addr, &in6->s6_addr[8], 8);
30762587Sitojun		else if (addrlen == 6) {
30862587Sitojun			in6->s6_addr[8] = addr[0];
30962587Sitojun			in6->s6_addr[9] = addr[1];
31062587Sitojun			in6->s6_addr[10] = addr[2];
31162587Sitojun			in6->s6_addr[11] = 0xff;
31262587Sitojun			in6->s6_addr[12] = 0xfe;
31362587Sitojun			in6->s6_addr[13] = addr[3];
31462587Sitojun			in6->s6_addr[14] = addr[4];
31562587Sitojun			in6->s6_addr[15] = addr[5];
31662587Sitojun		}
31762587Sitojun		break;
31862587Sitojun
31962587Sitojun	case IFT_ARCNET:
320191337Srwatson		if (addrlen != 1) {
321229621Sjhb			IF_ADDR_RUNLOCK(ifp);
32262587Sitojun			return -1;
323191337Srwatson		}
324191337Srwatson		if (!addr[0]) {
325229621Sjhb			IF_ADDR_RUNLOCK(ifp);
32662587Sitojun			return -1;
327191337Srwatson		}
32862587Sitojun
32962587Sitojun		bzero(&in6->s6_addr[8], 8);
33062587Sitojun		in6->s6_addr[15] = addr[0];
33162587Sitojun
33262587Sitojun		/*
33362587Sitojun		 * due to insufficient bitwidth, we mark it local.
33462587Sitojun		 */
33562587Sitojun		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
33662587Sitojun		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
33762587Sitojun		break;
33862587Sitojun
33962587Sitojun	case IFT_GIF:
34062587Sitojun#ifdef IFT_STF
34162587Sitojun	case IFT_STF:
34253541Sshin#endif
34362587Sitojun		/*
34478064Sume		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
34562587Sitojun		 * however, IPv4 address is not very suitable as unique
34662587Sitojun		 * identifier source (can be renumbered).
34762587Sitojun		 * we don't do this.
34862587Sitojun		 */
349229621Sjhb		IF_ADDR_RUNLOCK(ifp);
35062587Sitojun		return -1;
35162587Sitojun
35262587Sitojun	default:
353229621Sjhb		IF_ADDR_RUNLOCK(ifp);
35462587Sitojun		return -1;
35553541Sshin	}
35662587Sitojun
35762587Sitojun	/* sanity check: g bit must not indicate "group" */
358191337Srwatson	if (EUI64_GROUP(in6)) {
359229621Sjhb		IF_ADDR_RUNLOCK(ifp);
36062587Sitojun		return -1;
361191337Srwatson	}
36262587Sitojun
36362587Sitojun	/* convert EUI64 into IPv6 interface identifier */
36462587Sitojun	EUI64_TO_IFID(in6);
36562587Sitojun
36662587Sitojun	/*
36762587Sitojun	 * sanity check: ifid must not be all zero, avoid conflict with
36862587Sitojun	 * subnet router anycast
36962587Sitojun	 */
37062587Sitojun	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
37162587Sitojun	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
372229621Sjhb		IF_ADDR_RUNLOCK(ifp);
37362587Sitojun		return -1;
37462587Sitojun	}
37562587Sitojun
376229621Sjhb	IF_ADDR_RUNLOCK(ifp);
37762587Sitojun	return 0;
37853541Sshin}
37953541Sshin
38053541Sshin/*
38162587Sitojun * Get interface identifier for the specified interface.  If it is not
38262587Sitojun * available on ifp0, borrow interface identifier from other information
38362587Sitojun * sources.
384171259Sdelphij *
385171259Sdelphij * altifp - secondary EUI64 source
38653541Sshin */
38762587Sitojunstatic int
388171259Sdelphijget_ifid(struct ifnet *ifp0, struct ifnet *altifp,
389171259Sdelphij    struct in6_addr *in6)
39053541Sshin{
39153541Sshin	struct ifnet *ifp;
39253541Sshin
39362587Sitojun	/* first, try to get it from the interface itself */
394151477Ssuz	if (in6_get_hw_ifid(ifp0, in6) == 0) {
39578064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
39678064Sume		    if_name(ifp0)));
39762587Sitojun		goto success;
39862587Sitojun	}
39953541Sshin
40062587Sitojun	/* try secondary EUI64 source. this basically is for ATM PVC */
401151477Ssuz	if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
40278064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
40378064Sume		    if_name(ifp0), if_name(altifp)));
40462587Sitojun		goto success;
40562587Sitojun	}
40662587Sitojun
40762587Sitojun	/* next, try to get it from some other hardware interface */
408196481Srwatson	IFNET_RLOCK_NOSLEEP();
409228966Sjhb	TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
41062587Sitojun		if (ifp == ifp0)
41162587Sitojun			continue;
412151477Ssuz		if (in6_get_hw_ifid(ifp, in6) != 0)
41362587Sitojun			continue;
41462587Sitojun
41562587Sitojun		/*
41662587Sitojun		 * to borrow ifid from other interface, ifid needs to be
41762587Sitojun		 * globally unique
41862587Sitojun		 */
41962587Sitojun		if (IFID_UNIVERSAL(in6)) {
42078064Sume			nd6log((LOG_DEBUG,
42178064Sume			    "%s: borrow interface identifier from %s\n",
42278064Sume			    if_name(ifp0), if_name(ifp)));
423196481Srwatson			IFNET_RUNLOCK_NOSLEEP();
42462587Sitojun			goto success;
42562587Sitojun		}
42662587Sitojun	}
427196481Srwatson	IFNET_RUNLOCK_NOSLEEP();
42862587Sitojun
42962587Sitojun	/* last resort: get from random number source */
43062587Sitojun	if (get_rand_ifid(ifp, in6) == 0) {
43178064Sume		nd6log((LOG_DEBUG,
43278064Sume		    "%s: interface identifier generated by random number\n",
43378064Sume		    if_name(ifp0)));
43462587Sitojun		goto success;
43562587Sitojun	}
43662587Sitojun
43766504Sitojun	printf("%s: failed to get interface identifier\n", if_name(ifp0));
43862587Sitojun	return -1;
43962587Sitojun
44062587Sitojunsuccess:
441120913Sume	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
442120913Sume	    if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
443120913Sume	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
444120913Sume	    in6->s6_addr[14], in6->s6_addr[15]));
44562587Sitojun	return 0;
44662587Sitojun}
44762587Sitojun
448171259Sdelphij/*
449171259Sdelphij * altifp - secondary EUI64 source
450171259Sdelphij */
45162587Sitojunstatic int
452171259Sdelphijin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
45378064Sume{
45462587Sitojun	struct in6_ifaddr *ia;
45578064Sume	struct in6_aliasreq ifra;
456151539Ssuz	struct nd_prefixctl pr0;
45778064Sume	int i, error;
45862587Sitojun
45962587Sitojun	/*
46078064Sume	 * configure link-local address.
46162587Sitojun	 */
46278064Sume	bzero(&ifra, sizeof(ifra));
46362587Sitojun
46462587Sitojun	/*
46578064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
46678064Sume	 * for safety.
46762587Sitojun	 */
46878064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
46962587Sitojun
47078064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
47178064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
472148385Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
47378064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
47478064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
47578064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
47678064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
47778064Sume	} else {
47878064Sume		if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
47978064Sume			nd6log((LOG_ERR,
48078064Sume			    "%s: no ifid available\n", if_name(ifp)));
481120913Sume			return (-1);
48262587Sitojun		}
48362587Sitojun	}
484148385Sume	if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
485148385Sume		return (-1);
48662587Sitojun
48778064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
48878064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
48978064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask64;
49078064Sume	/* link-local addresses should NEVER expire. */
49178064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
49278064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
49362587Sitojun
49478064Sume	/*
49578064Sume	 * Now call in6_update_ifa() to do a bunch of procedures to configure
496151465Ssuz	 * a link-local address. We can set the 3rd argument to NULL, because
49795023Ssuz	 * we know there's no other link-local address on the interface
49895023Ssuz	 * and therefore we are adding one (instead of updating one).
49978064Sume	 */
500151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL,
501151539Ssuz				    IN6_IFAUPDATE_DADDELAY)) != 0) {
50262587Sitojun		/*
50378064Sume		 * XXX: When the interface does not support IPv6, this call
50478064Sume		 * would fail in the SIOCSIFADDR ioctl.  I believe the
50578064Sume		 * notification is rather confusing in this case, so just
506120913Sume		 * suppress it.  (jinmei@kame.net 20010130)
50762587Sitojun		 */
50878064Sume		if (error != EAFNOSUPPORT)
509151465Ssuz			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
51078064Sume			    "configure a link-local address on %s "
51178064Sume			    "(errno=%d)\n",
512151465Ssuz			    if_name(ifp), error));
513120856Sume		return (-1);
51462587Sitojun	}
51562587Sitojun
51678064Sume	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
517229546Sbz	KASSERT(ia != NULL, ("%s: ia == NULL, ifp=%p", __func__, ifp));
518229546Sbz
519194760Srwatson	ifa_free(&ia->ia_ifa);
52053541Sshin
52178064Sume	/*
522120913Sume	 * Make the link-local prefix (fe80::%link/64) as on-link.
52378064Sume	 * Since we'd like to manage prefixes separately from addresses,
52478064Sume	 * we make an ND6 prefix structure for the link-local prefix,
52578064Sume	 * and add it to the prefix list as a never-expire prefix.
52678064Sume	 * XXX: this change might affect some existing code base...
52778064Sume	 */
52878064Sume	bzero(&pr0, sizeof(pr0));
52978064Sume	pr0.ndpr_ifp = ifp;
53078064Sume	/* this should be 64 at this moment. */
53178064Sume	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
53278064Sume	pr0.ndpr_prefix = ifra.ifra_addr;
53378064Sume	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
53478064Sume	for (i = 0; i < 4; i++) {
53578064Sume		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
536120913Sume		    in6mask64.s6_addr32[i];
53762587Sitojun	}
53878064Sume	/*
53978064Sume	 * Initialize parameters.  The link-local prefix must always be
54078064Sume	 * on-link, and its lifetimes never expire.
54178064Sume	 */
54278064Sume	pr0.ndpr_raf_onlink = 1;
54378064Sume	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
54478064Sume	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
54578064Sume	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
54678064Sume	/*
54778064Sume	 * Since there is no other link-local addresses, nd6_prefix_lookup()
54878064Sume	 * probably returns NULL.  However, we cannot always expect the result.
54978064Sume	 * For example, if we first remove the (only) existing link-local
55078064Sume	 * address, and then reconfigure another one, the prefix is still
55178064Sume	 * valid with referring to the old link-local address.
55278064Sume	 */
55378064Sume	if (nd6_prefix_lookup(&pr0) == NULL) {
55478064Sume		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
555120856Sume			return (error);
55678064Sume	}
55762587Sitojun
55862587Sitojun	return 0;
55962587Sitojun}
56062587Sitojun
561171259Sdelphij/*
562171259Sdelphij * ifp - must be IFT_LOOP
563171259Sdelphij */
56462587Sitojunstatic int
565171259Sdelphijin6_ifattach_loopback(struct ifnet *ifp)
56662587Sitojun{
56778064Sume	struct in6_aliasreq ifra;
56878064Sume	int error;
56962587Sitojun
57078064Sume	bzero(&ifra, sizeof(ifra));
57178064Sume
57262587Sitojun	/*
57378064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
57478064Sume	 * for safety.
57562587Sitojun	 */
57678064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
57762587Sitojun
57878064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
57978064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
58078064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask128;
58162587Sitojun
58262587Sitojun	/*
58362587Sitojun	 * Always initialize ia_dstaddr (= broadcast address) to loopback
58478064Sume	 * address.  Follows IPv4 practice - see in_ifinit().
58562587Sitojun	 */
58678064Sume	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
58778064Sume	ifra.ifra_dstaddr.sin6_family = AF_INET6;
58878064Sume	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
58962587Sitojun
59078064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
59178064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
59278064Sume	ifra.ifra_addr.sin6_addr = in6addr_loopback;
59362587Sitojun
59478064Sume	/* the loopback  address should NEVER expire. */
59578064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
59678064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
59762587Sitojun
59878064Sume	/*
59995023Ssuz	 * We are sure that this is a newly assigned address, so we can set
60095023Ssuz	 * NULL to the 3rd arg.
60178064Sume	 */
602151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
603151465Ssuz		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
60478064Sume		    "the loopback address on %s (errno=%d)\n",
605151465Ssuz		    if_name(ifp), error));
606120856Sume		return (-1);
60762587Sitojun	}
60862587Sitojun
60962587Sitojun	return 0;
61062587Sitojun}
61162587Sitojun
61262587Sitojun/*
61362587Sitojun * compute NI group address, based on the current hostname setting.
614250251Shrs * see RFC 4620.
61562587Sitojun *
61662587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid.
617250251Shrs *
618250251Shrs * If oldmcprefix == 1, FF02:0:0:0:0:2::/96 is used for NI group address
619250251Shrs * while it is FF02:0:0:0:0:2:FF00::/104 in RFC 4620.
62062587Sitojun */
621250251Shrsstatic int
622250251Shrsin6_nigroup0(struct ifnet *ifp, const char *name, int namelen,
623250251Shrs    struct in6_addr *in6, int oldmcprefix)
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
668250251Shrs	/* generate 16 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;
678250251Shrs	if (oldmcprefix == 0) {
679250251Shrs		in6->s6_addr8[12] = 0xff;
680250251Shrs	 	/* Copy the first 24 bits of 128-bit hash into the address. */
681250251Shrs		bcopy(digest, &in6->s6_addr8[13], 3);
682250251Shrs	} else {
683250251Shrs	 	/* Copy the first 32 bits of 128-bit hash into the address. */
684250251Shrs		bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
685250251Shrs	}
686148385Sume	if (in6_setscope(in6, ifp, NULL))
687148385Sume		return (-1); /* XXX: should not fail */
68862587Sitojun
68962587Sitojun	return 0;
69062587Sitojun}
69162587Sitojun
692250251Shrsint
693250251Shrsin6_nigroup(struct ifnet *ifp, const char *name, int namelen,
694250251Shrs    struct in6_addr *in6)
695250251Shrs{
696250251Shrs
697250251Shrs	return (in6_nigroup0(ifp, name, namelen, in6, 0));
698250251Shrs}
699250251Shrs
700250251Shrsint
701250251Shrsin6_nigroup_oldmcprefix(struct ifnet *ifp, const char *name, int namelen,
702250251Shrs    struct in6_addr *in6)
703250251Shrs{
704250251Shrs
705250251Shrs	return (in6_nigroup0(ifp, name, namelen, in6, 1));
706250251Shrs}
707250251Shrs
70862587Sitojun/*
70962587Sitojun * XXX multiple loopback interface needs more care.  for instance,
71062587Sitojun * nodelocal address needs to be configured onto only one of them.
71162587Sitojun * XXX multiple link-local address case
712171259Sdelphij *
713171259Sdelphij * altifp - secondary EUI64 source
71462587Sitojun */
71562587Sitojunvoid
716171259Sdelphijin6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
71762587Sitojun{
71862587Sitojun	struct in6_ifaddr *ia;
71962587Sitojun	struct in6_addr in6;
72062587Sitojun
721253841Shrs	if (ifp->if_afdata[AF_INET6] == NULL)
72278064Sume		return;
72353541Sshin	/*
72462587Sitojun	 * quirks based on interface type
72553541Sshin	 */
72662587Sitojun	switch (ifp->if_type) {
72762587Sitojun	case IFT_STF:
72862587Sitojun		/*
72995023Ssuz		 * 6to4 interface is a very special kind of beast.
73095023Ssuz		 * no multicast, no linklocal.  RFC2529 specifies how to make
73195023Ssuz		 * linklocals for 6to4 interface, but there's no use and
73295023Ssuz		 * it is rather harmful to have one.
73362587Sitojun		 */
734252511Shrs		ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
735252511Shrs		break;
73662587Sitojun	default:
73762587Sitojun		break;
73853541Sshin	}
73953541Sshin
74053541Sshin	/*
74162587Sitojun	 * usually, we require multicast capability to the interface
74253541Sshin	 */
74362587Sitojun	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
744151465Ssuz		nd6log((LOG_INFO, "in6_ifattach: "
74578064Sume		    "%s is not multicast capable, IPv6 not enabled\n",
746151465Ssuz		    if_name(ifp)));
74762587Sitojun		return;
74862587Sitojun	}
74962587Sitojun
75053541Sshin	/*
75178064Sume	 * assign loopback address for loopback interface.
75278064Sume	 * XXX multiple loopback interface case.
75353541Sshin	 */
75478064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
755194760Srwatson		struct ifaddr *ifa;
756194760Srwatson
75778064Sume		in6 = in6addr_loopback;
758194760Srwatson		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6);
759194760Srwatson		if (ifa == NULL) {
76062587Sitojun			if (in6_ifattach_loopback(ifp) != 0)
76162587Sitojun				return;
762194760Srwatson		} else
763194760Srwatson			ifa_free(ifa);
76462587Sitojun	}
76553541Sshin
76653541Sshin	/*
767120913Sume	 * assign a link-local address, if there's none.
76853541Sshin	 */
769252511Shrs	if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
770197138Shrs	    ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
771197138Shrs		int error;
772197138Shrs
77378064Sume		ia = in6ifa_ifpforlinklocal(ifp, 0);
77478064Sume		if (ia == NULL) {
775197138Shrs			error = in6_ifattach_linklocal(ifp, altifp);
776197996Shrs#if 0
777197138Shrs			if (error)
778197138Shrs				log(LOG_NOTICE, "in6_ifattach_linklocal: "
779197138Shrs				    "failed to add a link-local addr to %s\n",
780197138Shrs				    if_name(ifp));
781197996Shrs#endif
782194760Srwatson		} else
783194760Srwatson			ifa_free(&ia->ia_ifa);
78453541Sshin	}
78553541Sshin
78653541Sshin	/* update dynamically. */
787181803Sbz	if (V_in6_maxmtu < ifp->if_mtu)
788181803Sbz		V_in6_maxmtu = ifp->if_mtu;
78953541Sshin}
79053541Sshin
79162587Sitojun/*
79262587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment.
79378064Sume * We don't need this function in bsdi, because interfaces are never removed
79478064Sume * from the ifnet list in bsdi.
79562587Sitojun */
79653541Sshinvoid
797171259Sdelphijin6_ifdetach(struct ifnet *ifp)
79853541Sshin{
799194907Srwatson	struct in6_ifaddr *ia;
80062587Sitojun	struct ifaddr *ifa, *next;
801193232Sbz	struct radix_node_head *rnh;
80253541Sshin	struct rtentry *rt;
80362587Sitojun	struct sockaddr_in6 sin6;
804170202Sjinmei	struct in6_multi_mship *imm;
80553541Sshin
806256258Shrs	if (ifp->if_afdata[AF_INET6] == NULL)
807256258Shrs		return;
808256258Shrs
80962587Sitojun	/* remove neighbor management table */
81062587Sitojun	nd6_purge(ifp);
81162587Sitojun
81262587Sitojun	/* nuke any of IPv6 addresses we have */
813191340Srwatson	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
81462587Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
81562587Sitojun			continue;
81678064Sume		in6_purgeaddr(ifa);
81762587Sitojun	}
81862587Sitojun
81962587Sitojun	/* undo everything done by in6_ifattach(), just in case */
820191340Srwatson	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
82153541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6
82253541Sshin		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
82353541Sshin			continue;
82453541Sshin		}
82553541Sshin
82653541Sshin		ia = (struct in6_ifaddr *)ifa;
82753541Sshin
828170202Sjinmei		/*
829170202Sjinmei		 * leave from multicast groups we have joined for the interface
830170202Sjinmei		 */
831228966Sjhb		while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
832170202Sjinmei			LIST_REMOVE(imm, i6mm_chain);
833170202Sjinmei			in6_leavegroup(imm);
834170202Sjinmei		}
835170202Sjinmei
836231852Sbz		/* Remove link-local from the routing table. */
837231852Sbz		if (ia->ia_flags & IFA_ROUTE)
838231852Sbz			(void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
83953541Sshin
84053541Sshin		/* remove from the linked list */
841229621Sjhb		IF_ADDR_WLOCK(ifp);
842194907Srwatson		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
843229621Sjhb		IF_ADDR_WUNLOCK(ifp);
844194907Srwatson		ifa_free(ifa);				/* if_addrhead */
84553541Sshin
846194971Srwatson		IN6_IFADDR_WLOCK();
847194907Srwatson		TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
848194971Srwatson		IN6_IFADDR_WUNLOCK();
849194907Srwatson		ifa_free(ifa);
85053541Sshin	}
85162587Sitojun
852181803Sbz	in6_pcbpurgeif0(&V_udbinfo, ifp);
853265946Skevlo	in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
854181803Sbz	in6_pcbpurgeif0(&V_ripcbinfo, ifp);
855170613Sbms	/* leave from all multicast groups joined */
856170613Sbms	in6_purgemaddrs(ifp);
857120913Sume
85878064Sume	/*
85978064Sume	 * remove neighbor management table.  we call it twice just to make
86078064Sume	 * sure we nuke everything.  maybe we need just one call.
86178064Sume	 * XXX: since the first call did not release addresses, some prefixes
86278064Sume	 * might remain.  We should call nd6_purge() again to release the
86378064Sume	 * prefixes after removing all addresses above.
86478064Sume	 * (Or can we just delay calling nd6_purge until at this point?)
86578064Sume	 */
86662587Sitojun	nd6_purge(ifp);
86762587Sitojun
868231852Sbz	/*
869231852Sbz	 * Remove route to link-local allnodes multicast (ff02::1).
870231852Sbz	 * These only get automatically installed for the default FIB.
871231852Sbz	 */
87262587Sitojun	bzero(&sin6, sizeof(sin6));
87362587Sitojun	sin6.sin6_len = sizeof(struct sockaddr_in6);
87462587Sitojun	sin6.sin6_family = AF_INET6;
87562587Sitojun	sin6.sin6_addr = in6addr_linklocal_allnodes;
876148385Sume	if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
877148385Sume		/* XXX: should not fail */
878148385Sume		return;
879121770Ssam	/* XXX grab lock first to avoid LOR */
880231852Sbz	rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
881193232Sbz	if (rnh != NULL) {
882193232Sbz		RADIX_NODE_HEAD_LOCK(rnh);
883231852Sbz		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
884231852Sbz		    RT_DEFAULT_FIB);
885124333Struckman		if (rt) {
886124333Struckman			if (rt->rt_ifp == ifp)
887124333Struckman				rtexpunge(rt);
888124333Struckman			RTFREE_LOCKED(rt);
889124333Struckman		}
890193232Sbz		RADIX_NODE_HEAD_UNLOCK(rnh);
89162587Sitojun	}
89253541Sshin}
89378064Sume
894151539Ssuzint
895171259Sdelphijin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf,
896171259Sdelphij    const u_int8_t *baseid, int generate)
89778064Sume{
89878064Sume	u_int8_t nullbuf[8];
899121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
90078064Sume
90178064Sume	bzero(nullbuf, sizeof(nullbuf));
90278064Sume	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
90378064Sume		/* we've never created a random ID.  Create a new one. */
90478064Sume		generate = 1;
90578064Sume	}
90678064Sume
90778064Sume	if (generate) {
90878064Sume		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
90978064Sume
91078064Sume		/* generate_tmp_ifid will update seedn and buf */
91178064Sume		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
912120913Sume		    ndi->randomid);
91378064Sume	}
91478064Sume	bcopy(ndi->randomid, retbuf, 8);
915151539Ssuz
916151539Ssuz	return (0);
91778064Sume}
91878064Sume
91978064Sumevoid
920191688Szecin6_tmpaddrtimer(void *arg)
92178064Sume{
922191688Szec	CURVNET_SET((struct vnet *) arg);
92378064Sume	struct nd_ifinfo *ndi;
92478064Sume	u_int8_t nullbuf[8];
925121161Sume	struct ifnet *ifp;
92678064Sume
927181803Sbz	callout_reset(&V_in6_tmpaddrtimer_ch,
928181803Sbz	    (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
929191688Szec	    V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet);
93078064Sume
93178064Sume	bzero(nullbuf, sizeof(nullbuf));
932228966Sjhb	TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
933253950Shrs		if (ifp->if_afdata[AF_INET6] == NULL)
934253950Shrs			continue;
935121161Sume		ndi = ND_IFINFO(ifp);
93678064Sume		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
93778064Sume			/*
93878064Sume			 * We've been generating a random ID on this interface.
93978064Sume			 * Create a new one.
94078064Sume			 */
94178064Sume			(void)generate_tmp_ifid(ndi->randomseed0,
942120913Sume			    ndi->randomseed1, ndi->randomid);
94378064Sume		}
94478064Sume	}
94578064Sume
946191688Szec	CURVNET_RESTORE();
94778064Sume}
948170613Sbms
949170613Sbmsstatic void
950171259Sdelphijin6_purgemaddrs(struct ifnet *ifp)
951170613Sbms{
952191672Sbms	LIST_HEAD(,in6_multi)	 purgeinms;
953191672Sbms	struct in6_multi	*inm, *tinm;
954191672Sbms	struct ifmultiaddr	*ifma;
955170613Sbms
956191672Sbms	LIST_INIT(&purgeinms);
957191672Sbms	IN6_MULTI_LOCK();
958191672Sbms
959191672Sbms	/*
960191672Sbms	 * Extract list of in6_multi associated with the detaching ifp
961191672Sbms	 * which the PF_INET6 layer is about to release.
962191672Sbms	 * We need to do this as IF_ADDR_LOCK() may be re-acquired
963191672Sbms	 * by code further down.
964191672Sbms	 */
965229621Sjhb	IF_ADDR_RLOCK(ifp);
966191672Sbms	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
967191672Sbms		if (ifma->ifma_addr->sa_family != AF_INET6 ||
968191672Sbms		    ifma->ifma_protospec == NULL)
969191672Sbms			continue;
970191672Sbms		inm = (struct in6_multi *)ifma->ifma_protospec;
971191672Sbms		LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry);
972170613Sbms	}
973229621Sjhb	IF_ADDR_RUNLOCK(ifp);
974191672Sbms
975191672Sbms	LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) {
976191672Sbms		LIST_REMOVE(inm, in6m_entry);
977191672Sbms		in6m_release_locked(inm);
978191672Sbms	}
979191672Sbms	mld_ifdetach(ifp);
980191672Sbms
981191672Sbms	IN6_MULTI_UNLOCK();
982170613Sbms}
983