in6_ifattach.c revision 181888
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 181888 2008-08-20 01:24:55Z julian $");
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>
4053541Sshin#include <sys/kernel.h>
4178064Sume#include <sys/syslog.h>
4253541Sshin#include <sys/md5.h>
43181803Sbz#include <sys/vimage.h>
4453541Sshin
4553541Sshin#include <net/if.h>
4653541Sshin#include <net/if_dl.h>
4753541Sshin#include <net/if_types.h>
4853541Sshin#include <net/route.h>
4953541Sshin
5053541Sshin#include <netinet/in.h>
5153541Sshin#include <netinet/in_var.h>
5253541Sshin#include <netinet/if_ether.h>
5381127Sume#include <netinet/in_pcb.h>
5453541Sshin
5562587Sitojun#include <netinet/ip6.h>
5653541Sshin#include <netinet6/ip6_var.h>
5778064Sume#include <netinet6/in6_var.h>
5881127Sume#include <netinet6/in6_pcb.h>
5953541Sshin#include <netinet6/in6_ifattach.h>
6053541Sshin#include <netinet6/ip6_var.h>
6153541Sshin#include <netinet6/nd6.h>
6262587Sitojun#include <netinet6/scope6_var.h>
6353541Sshin
6462587Sitojununsigned long in6_maxmtu = 0;
6553541Sshin
6678064Sume#ifdef IP6_AUTO_LINKLOCAL
6778064Sumeint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
6878064Sume#else
69163306Sumeint ip6_auto_linklocal = 1;	/* enable by default */
7078064Sume#endif
7178064Sume
7278064Sumestruct callout in6_tmpaddrtimer_ch;
7378064Sume
7481127Sumeextern struct inpcbinfo udbinfo;
7581127Sumeextern struct inpcbinfo ripcbinfo;
7681127Sume
77175162Sobrienstatic int get_rand_ifid(struct ifnet *, struct in6_addr *);
78175162Sobrienstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
79175162Sobrienstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
80175162Sobrienstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
81175162Sobrienstatic int in6_ifattach_loopback(struct ifnet *);
82175162Sobrienstatic void in6_purgemaddrs(struct ifnet *);
8353541Sshin
8462587Sitojun#define EUI64_GBIT	0x01
8562587Sitojun#define EUI64_UBIT	0x02
8662587Sitojun#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
8762587Sitojun#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
8862587Sitojun#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
8962587Sitojun#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
9062587Sitojun#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
9153541Sshin
9262587Sitojun#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
9362587Sitojun#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
9453541Sshin
9553541Sshin/*
9653541Sshin * Generate a last-resort interface identifier, when the machine has no
9753541Sshin * IEEE802/EUI64 address sources.
9862587Sitojun * The goal here is to get an interface identifier that is
9962587Sitojun * (1) random enough and (2) does not change across reboot.
10062587Sitojun * We currently use MD5(hostname) for it.
101171259Sdelphij *
102171259Sdelphij * in6 - upper 64bits are preserved
10353541Sshin */
10453541Sshinstatic int
105171259Sdelphijget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
10653541Sshin{
10753541Sshin	MD5_CTX ctxt;
10853541Sshin	u_int8_t digest[16];
109180291Srwatson	int hostnamelen;
11053541Sshin
111180291Srwatson	mtx_lock(&hostname_mtx);
112181803Sbz	hostnamelen = strlen(V_hostname);
11362587Sitojun#if 0
11462587Sitojun	/* we need at least several letters as seed for ifid */
11562587Sitojun	if (hostnamelen < 3)
11662587Sitojun		return -1;
11762587Sitojun#endif
11862587Sitojun
11962587Sitojun	/* generate 8 bytes of pseudo-random value. */
12053541Sshin	bzero(&ctxt, sizeof(ctxt));
12153541Sshin	MD5Init(&ctxt);
122181803Sbz	MD5Update(&ctxt, V_hostname, hostnamelen);
123180291Srwatson	mtx_unlock(&hostname_mtx);
12453541Sshin	MD5Final(digest, &ctxt);
12553541Sshin
12662587Sitojun	/* assumes sizeof(digest) > sizeof(ifid) */
12762587Sitojun	bcopy(digest, &in6->s6_addr[8], 8);
12853541Sshin
12953541Sshin	/* make sure to set "u" bit to local, and "g" bit to individual. */
13062587Sitojun	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
13162587Sitojun	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
13253541Sshin
13362587Sitojun	/* convert EUI64 into IPv6 interface identifier */
13462587Sitojun	EUI64_TO_IFID(in6);
13562587Sitojun
13653541Sshin	return 0;
13753541Sshin}
13853541Sshin
13978064Sumestatic int
140171259Sdelphijgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret)
14178064Sume{
14278064Sume	MD5_CTX ctxt;
14378064Sume	u_int8_t seed[16], digest[16], nullbuf[8];
14478064Sume	u_int32_t val32;
14578064Sume
146171259Sdelphij	/* If there's no history, start with a random seed. */
14778064Sume	bzero(nullbuf, sizeof(nullbuf));
14878064Sume	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
14978064Sume		int i;
15078064Sume
15178064Sume		for (i = 0; i < 2; i++) {
152121807Sume			val32 = arc4random();
15378064Sume			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
15478064Sume		}
155120913Sume	} else
15678064Sume		bcopy(seed0, seed, 8);
15778064Sume
15878064Sume	/* copy the right-most 64-bits of the given address */
15978064Sume	/* XXX assumption on the size of IFID */
16078064Sume	bcopy(seed1, &seed[8], 8);
16178064Sume
16278064Sume	if (0) {		/* for debugging purposes only */
16378064Sume		int i;
16478064Sume
16578064Sume		printf("generate_tmp_ifid: new randomized ID from: ");
16678064Sume		for (i = 0; i < 16; i++)
16778064Sume			printf("%02x", seed[i]);
16878064Sume		printf(" ");
16978064Sume	}
17078064Sume
17178064Sume	/* generate 16 bytes of pseudo-random value. */
17278064Sume	bzero(&ctxt, sizeof(ctxt));
17378064Sume	MD5Init(&ctxt);
17478064Sume	MD5Update(&ctxt, seed, sizeof(seed));
17578064Sume	MD5Final(digest, &ctxt);
17678064Sume
17778064Sume	/*
17878064Sume	 * RFC 3041 3.2.1. (3)
17978064Sume	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
18078064Sume	 * left-most bit is numbered 0) to zero.
18178064Sume	 */
18278064Sume	bcopy(digest, ret, 8);
18378064Sume	ret[0] &= ~EUI64_UBIT;
18478064Sume
18578064Sume	/*
18678064Sume	 * XXX: we'd like to ensure that the generated value is not zero
18778064Sume	 * for simplicity.  If the caclculated digest happens to be zero,
18878064Sume	 * use a random non-zero value as the last resort.
18978064Sume	 */
19078064Sume	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
191151465Ssuz		nd6log((LOG_INFO,
192151465Ssuz		    "generate_tmp_ifid: computed MD5 value is zero.\n"));
19378064Sume
194121807Sume		val32 = arc4random();
19578064Sume		val32 = 1 + (val32 % (0xffffffff - 1));
19678064Sume	}
19778064Sume
19878064Sume	/*
19978064Sume	 * RFC 3041 3.2.1. (4)
20078064Sume	 * Take the rightmost 64-bits of the MD5 digest and save them in
20178064Sume	 * stable storage as the history value to be used in the next
202120913Sume	 * iteration of the algorithm.
20378064Sume	 */
20478064Sume	bcopy(&digest[8], seed0, 8);
20578064Sume
20678064Sume	if (0) {		/* for debugging purposes only */
20778064Sume		int i;
20878064Sume
20978064Sume		printf("to: ");
21078064Sume		for (i = 0; i < 16; i++)
21178064Sume			printf("%02x", digest[i]);
21278064Sume		printf("\n");
21378064Sume	}
21478064Sume
21578064Sume	return 0;
21678064Sume}
21778064Sume
21853541Sshin/*
21962587Sitojun * Get interface identifier for the specified interface.
22062587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
221171259Sdelphij *
222171259Sdelphij * in6 - upper 64bits are preserved
22353541Sshin */
224151477Ssuzint
225171259Sdelphijin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
22653541Sshin{
22753541Sshin	struct ifaddr *ifa;
22853541Sshin	struct sockaddr_dl *sdl;
22962587Sitojun	u_int8_t *addr;
23062587Sitojun	size_t addrlen;
23162587Sitojun	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
23262587Sitojun	static u_int8_t allone[8] =
23362587Sitojun		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
23453541Sshin
23562587Sitojun	for (ifa = ifp->if_addrlist.tqh_first;
23662587Sitojun	     ifa;
237120913Sume	     ifa = ifa->ifa_list.tqe_next) {
23862587Sitojun		if (ifa->ifa_addr->sa_family != AF_LINK)
23953541Sshin			continue;
24062587Sitojun		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
24162587Sitojun		if (sdl == NULL)
24262587Sitojun			continue;
24362587Sitojun		if (sdl->sdl_alen == 0)
24462587Sitojun			continue;
24562587Sitojun
24662587Sitojun		goto found;
24753541Sshin	}
24853541Sshin
24962587Sitojun	return -1;
25062587Sitojun
25153541Sshinfound:
25262587Sitojun	addr = LLADDR(sdl);
25362587Sitojun	addrlen = sdl->sdl_alen;
25453541Sshin
25562587Sitojun	/* get EUI64 */
25662587Sitojun	switch (ifp->if_type) {
25762587Sitojun	case IFT_ETHER:
25862587Sitojun	case IFT_FDDI:
259120049Smdodd	case IFT_ISO88025:
26062587Sitojun	case IFT_ATM:
26178064Sume	case IFT_IEEE1394:
26278064Sume#ifdef IFT_IEEE80211
26378064Sume	case IFT_IEEE80211:
26478064Sume#endif
26562587Sitojun		/* IEEE802/EUI64 cases - what others? */
26678064Sume		/* IEEE1394 uses 16byte length address starting with EUI64 */
26778064Sume		if (addrlen > 8)
26878064Sume			addrlen = 8;
26953541Sshin
27062587Sitojun		/* look at IEEE802/EUI64 only */
27162587Sitojun		if (addrlen != 8 && addrlen != 6)
27262587Sitojun			return -1;
27353541Sshin
27462587Sitojun		/*
27562587Sitojun		 * check for invalid MAC address - on bsdi, we see it a lot
27662587Sitojun		 * since wildboar configures all-zero MAC on pccard before
27762587Sitojun		 * card insertion.
27862587Sitojun		 */
27962587Sitojun		if (bcmp(addr, allzero, addrlen) == 0)
28062587Sitojun			return -1;
28162587Sitojun		if (bcmp(addr, allone, addrlen) == 0)
28262587Sitojun			return -1;
28362587Sitojun
28462587Sitojun		/* make EUI64 address */
28562587Sitojun		if (addrlen == 8)
28662587Sitojun			bcopy(addr, &in6->s6_addr[8], 8);
28762587Sitojun		else if (addrlen == 6) {
28862587Sitojun			in6->s6_addr[8] = addr[0];
28962587Sitojun			in6->s6_addr[9] = addr[1];
29062587Sitojun			in6->s6_addr[10] = addr[2];
29162587Sitojun			in6->s6_addr[11] = 0xff;
29262587Sitojun			in6->s6_addr[12] = 0xfe;
29362587Sitojun			in6->s6_addr[13] = addr[3];
29462587Sitojun			in6->s6_addr[14] = addr[4];
29562587Sitojun			in6->s6_addr[15] = addr[5];
29662587Sitojun		}
29762587Sitojun		break;
29862587Sitojun
29962587Sitojun	case IFT_ARCNET:
30062587Sitojun		if (addrlen != 1)
30162587Sitojun			return -1;
30262587Sitojun		if (!addr[0])
30362587Sitojun			return -1;
30462587Sitojun
30562587Sitojun		bzero(&in6->s6_addr[8], 8);
30662587Sitojun		in6->s6_addr[15] = addr[0];
30762587Sitojun
30862587Sitojun		/*
30962587Sitojun		 * due to insufficient bitwidth, we mark it local.
31062587Sitojun		 */
31162587Sitojun		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
31262587Sitojun		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
31362587Sitojun		break;
31462587Sitojun
31562587Sitojun	case IFT_GIF:
31662587Sitojun#ifdef IFT_STF
31762587Sitojun	case IFT_STF:
31853541Sshin#endif
31962587Sitojun		/*
32078064Sume		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
32162587Sitojun		 * however, IPv4 address is not very suitable as unique
32262587Sitojun		 * identifier source (can be renumbered).
32362587Sitojun		 * we don't do this.
32462587Sitojun		 */
32562587Sitojun		return -1;
32662587Sitojun
32762587Sitojun	default:
32862587Sitojun		return -1;
32953541Sshin	}
33062587Sitojun
33162587Sitojun	/* sanity check: g bit must not indicate "group" */
33262587Sitojun	if (EUI64_GROUP(in6))
33362587Sitojun		return -1;
33462587Sitojun
33562587Sitojun	/* convert EUI64 into IPv6 interface identifier */
33662587Sitojun	EUI64_TO_IFID(in6);
33762587Sitojun
33862587Sitojun	/*
33962587Sitojun	 * sanity check: ifid must not be all zero, avoid conflict with
34062587Sitojun	 * subnet router anycast
34162587Sitojun	 */
34262587Sitojun	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
34362587Sitojun	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
34462587Sitojun		return -1;
34562587Sitojun	}
34662587Sitojun
34762587Sitojun	return 0;
34853541Sshin}
34953541Sshin
35053541Sshin/*
35162587Sitojun * Get interface identifier for the specified interface.  If it is not
35262587Sitojun * available on ifp0, borrow interface identifier from other information
35362587Sitojun * sources.
354171259Sdelphij *
355171259Sdelphij * altifp - secondary EUI64 source
35653541Sshin */
35762587Sitojunstatic int
358171259Sdelphijget_ifid(struct ifnet *ifp0, struct ifnet *altifp,
359171259Sdelphij    struct in6_addr *in6)
36053541Sshin{
36153541Sshin	struct ifnet *ifp;
36253541Sshin
36362587Sitojun	/* first, try to get it from the interface itself */
364151477Ssuz	if (in6_get_hw_ifid(ifp0, in6) == 0) {
36578064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
36678064Sume		    if_name(ifp0)));
36762587Sitojun		goto success;
36862587Sitojun	}
36953541Sshin
37062587Sitojun	/* try secondary EUI64 source. this basically is for ATM PVC */
371151477Ssuz	if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
37278064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
37378064Sume		    if_name(ifp0), if_name(altifp)));
37462587Sitojun		goto success;
37562587Sitojun	}
37662587Sitojun
37762587Sitojun	/* next, try to get it from some other hardware interface */
378108172Shsu	IFNET_RLOCK();
379181803Sbz	for (ifp = V_ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
38062587Sitojun		if (ifp == ifp0)
38162587Sitojun			continue;
382151477Ssuz		if (in6_get_hw_ifid(ifp, in6) != 0)
38362587Sitojun			continue;
38462587Sitojun
38562587Sitojun		/*
38662587Sitojun		 * to borrow ifid from other interface, ifid needs to be
38762587Sitojun		 * globally unique
38862587Sitojun		 */
38962587Sitojun		if (IFID_UNIVERSAL(in6)) {
39078064Sume			nd6log((LOG_DEBUG,
39178064Sume			    "%s: borrow interface identifier from %s\n",
39278064Sume			    if_name(ifp0), if_name(ifp)));
393108172Shsu			IFNET_RUNLOCK();
39462587Sitojun			goto success;
39562587Sitojun		}
39662587Sitojun	}
397108172Shsu	IFNET_RUNLOCK();
39862587Sitojun
39962587Sitojun	/* last resort: get from random number source */
40062587Sitojun	if (get_rand_ifid(ifp, in6) == 0) {
40178064Sume		nd6log((LOG_DEBUG,
40278064Sume		    "%s: interface identifier generated by random number\n",
40378064Sume		    if_name(ifp0)));
40462587Sitojun		goto success;
40562587Sitojun	}
40662587Sitojun
40766504Sitojun	printf("%s: failed to get interface identifier\n", if_name(ifp0));
40862587Sitojun	return -1;
40962587Sitojun
41062587Sitojunsuccess:
411120913Sume	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
412120913Sume	    if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
413120913Sume	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
414120913Sume	    in6->s6_addr[14], in6->s6_addr[15]));
41562587Sitojun	return 0;
41662587Sitojun}
41762587Sitojun
418171259Sdelphij/*
419171259Sdelphij * altifp - secondary EUI64 source
420171259Sdelphij */
42162587Sitojunstatic int
422171259Sdelphijin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
42378064Sume{
42462587Sitojun	struct in6_ifaddr *ia;
42578064Sume	struct in6_aliasreq ifra;
426151539Ssuz	struct nd_prefixctl pr0;
42778064Sume	int i, error;
42862587Sitojun
42962587Sitojun	/*
43078064Sume	 * configure link-local address.
43162587Sitojun	 */
43278064Sume	bzero(&ifra, sizeof(ifra));
43362587Sitojun
43462587Sitojun	/*
43578064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
43678064Sume	 * for safety.
43762587Sitojun	 */
43878064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
43962587Sitojun
44078064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
44178064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
442148385Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
44378064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
44478064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
44578064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
44678064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
44778064Sume	} else {
44878064Sume		if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
44978064Sume			nd6log((LOG_ERR,
45078064Sume			    "%s: no ifid available\n", if_name(ifp)));
451120913Sume			return (-1);
45262587Sitojun		}
45362587Sitojun	}
454148385Sume	if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
455148385Sume		return (-1);
45662587Sitojun
45778064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
45878064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
45978064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask64;
46078064Sume	/* link-local addresses should NEVER expire. */
46178064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
46278064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
46362587Sitojun
46478064Sume	/*
46578064Sume	 * Now call in6_update_ifa() to do a bunch of procedures to configure
466151465Ssuz	 * a link-local address. We can set the 3rd argument to NULL, because
46795023Ssuz	 * we know there's no other link-local address on the interface
46895023Ssuz	 * and therefore we are adding one (instead of updating one).
46978064Sume	 */
470151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL,
471151539Ssuz				    IN6_IFAUPDATE_DADDELAY)) != 0) {
47262587Sitojun		/*
47378064Sume		 * XXX: When the interface does not support IPv6, this call
47478064Sume		 * would fail in the SIOCSIFADDR ioctl.  I believe the
47578064Sume		 * notification is rather confusing in this case, so just
476120913Sume		 * suppress it.  (jinmei@kame.net 20010130)
47762587Sitojun		 */
47878064Sume		if (error != EAFNOSUPPORT)
479151465Ssuz			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
48078064Sume			    "configure a link-local address on %s "
48178064Sume			    "(errno=%d)\n",
482151465Ssuz			    if_name(ifp), error));
483120856Sume		return (-1);
48462587Sitojun	}
48562587Sitojun
48678064Sume	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
48778064Sume#ifdef DIAGNOSTIC
48878064Sume	if (!ia) {
48978064Sume		panic("ia == NULL in in6_ifattach_linklocal");
49095023Ssuz		/* NOTREACHED */
49178064Sume	}
49262587Sitojun#endif
49353541Sshin
49478064Sume	/*
495120913Sume	 * Make the link-local prefix (fe80::%link/64) as on-link.
49678064Sume	 * Since we'd like to manage prefixes separately from addresses,
49778064Sume	 * we make an ND6 prefix structure for the link-local prefix,
49878064Sume	 * and add it to the prefix list as a never-expire prefix.
49978064Sume	 * XXX: this change might affect some existing code base...
50078064Sume	 */
50178064Sume	bzero(&pr0, sizeof(pr0));
50278064Sume	pr0.ndpr_ifp = ifp;
50378064Sume	/* this should be 64 at this moment. */
50478064Sume	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
50578064Sume	pr0.ndpr_prefix = ifra.ifra_addr;
50678064Sume	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
50778064Sume	for (i = 0; i < 4; i++) {
50878064Sume		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
509120913Sume		    in6mask64.s6_addr32[i];
51062587Sitojun	}
51178064Sume	/*
51278064Sume	 * Initialize parameters.  The link-local prefix must always be
51378064Sume	 * on-link, and its lifetimes never expire.
51478064Sume	 */
51578064Sume	pr0.ndpr_raf_onlink = 1;
51678064Sume	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
51778064Sume	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
51878064Sume	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
51978064Sume	/*
52078064Sume	 * Since there is no other link-local addresses, nd6_prefix_lookup()
52178064Sume	 * probably returns NULL.  However, we cannot always expect the result.
52278064Sume	 * For example, if we first remove the (only) existing link-local
52378064Sume	 * address, and then reconfigure another one, the prefix is still
52478064Sume	 * valid with referring to the old link-local address.
52578064Sume	 */
52678064Sume	if (nd6_prefix_lookup(&pr0) == NULL) {
52778064Sume		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
528120856Sume			return (error);
52978064Sume	}
53062587Sitojun
53162587Sitojun	return 0;
53262587Sitojun}
53362587Sitojun
534171259Sdelphij/*
535171259Sdelphij * ifp - must be IFT_LOOP
536171259Sdelphij */
53762587Sitojunstatic int
538171259Sdelphijin6_ifattach_loopback(struct ifnet *ifp)
53962587Sitojun{
54078064Sume	struct in6_aliasreq ifra;
54178064Sume	int error;
54262587Sitojun
54378064Sume	bzero(&ifra, sizeof(ifra));
54478064Sume
54562587Sitojun	/*
54678064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
54778064Sume	 * for safety.
54862587Sitojun	 */
54978064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
55062587Sitojun
55178064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
55278064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
55378064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask128;
55462587Sitojun
55562587Sitojun	/*
55662587Sitojun	 * Always initialize ia_dstaddr (= broadcast address) to loopback
55778064Sume	 * address.  Follows IPv4 practice - see in_ifinit().
55862587Sitojun	 */
55978064Sume	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
56078064Sume	ifra.ifra_dstaddr.sin6_family = AF_INET6;
56178064Sume	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
56262587Sitojun
56378064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
56478064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
56578064Sume	ifra.ifra_addr.sin6_addr = in6addr_loopback;
56662587Sitojun
56778064Sume	/* the loopback  address should NEVER expire. */
56878064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
56978064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
57062587Sitojun
57195023Ssuz	/* we don't need to perform DAD on loopback interfaces. */
57278064Sume	ifra.ifra_flags |= IN6_IFF_NODAD;
57378064Sume
57478064Sume	/* skip registration to the prefix list. XXX should be temporary. */
57578064Sume	ifra.ifra_flags |= IN6_IFF_NOPFX;
57678064Sume
57778064Sume	/*
57895023Ssuz	 * We are sure that this is a newly assigned address, so we can set
57995023Ssuz	 * NULL to the 3rd arg.
58078064Sume	 */
581151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
582151465Ssuz		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
58378064Sume		    "the loopback address on %s (errno=%d)\n",
584151465Ssuz		    if_name(ifp), error));
585120856Sume		return (-1);
58662587Sitojun	}
58762587Sitojun
58862587Sitojun	return 0;
58962587Sitojun}
59062587Sitojun
59162587Sitojun/*
59262587Sitojun * compute NI group address, based on the current hostname setting.
59362587Sitojun * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
59462587Sitojun *
59562587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid.
59662587Sitojun */
59778064Sumeint
598171259Sdelphijin6_nigroup(struct ifnet *ifp, const char *name, int namelen,
599171259Sdelphij    struct in6_addr *in6)
60062587Sitojun{
60162587Sitojun	const char *p;
60278064Sume	u_char *q;
60362587Sitojun	MD5_CTX ctxt;
60462587Sitojun	u_int8_t digest[16];
60562587Sitojun	char l;
60678064Sume	char n[64];	/* a single label must not exceed 63 chars */
60762587Sitojun
60862587Sitojun	if (!namelen || !name)
60962587Sitojun		return -1;
61062587Sitojun
61162587Sitojun	p = name;
61262587Sitojun	while (p && *p && *p != '.' && p - name < namelen)
61362587Sitojun		p++;
61478064Sume	if (p - name > sizeof(n) - 1)
61595023Ssuz		return -1;	/* label too long */
61662587Sitojun	l = p - name;
61778064Sume	strncpy(n, name, l);
61878064Sume	n[(int)l] = '\0';
61978064Sume	for (q = n; *q; q++) {
62078064Sume		if ('A' <= *q && *q <= 'Z')
62178064Sume			*q = *q - 'A' + 'a';
62278064Sume	}
62362587Sitojun
62462587Sitojun	/* generate 8 bytes of pseudo-random value. */
62562587Sitojun	bzero(&ctxt, sizeof(ctxt));
62662587Sitojun	MD5Init(&ctxt);
62762587Sitojun	MD5Update(&ctxt, &l, sizeof(l));
62878064Sume	MD5Update(&ctxt, n, l);
62962587Sitojun	MD5Final(digest, &ctxt);
63062587Sitojun
63162587Sitojun	bzero(in6, sizeof(*in6));
632151465Ssuz	in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
63362587Sitojun	in6->s6_addr8[11] = 2;
63462587Sitojun	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
635148385Sume	if (in6_setscope(in6, ifp, NULL))
636148385Sume		return (-1); /* XXX: should not fail */
63762587Sitojun
63862587Sitojun	return 0;
63962587Sitojun}
64062587Sitojun
64162587Sitojun/*
64262587Sitojun * XXX multiple loopback interface needs more care.  for instance,
64362587Sitojun * nodelocal address needs to be configured onto only one of them.
64462587Sitojun * XXX multiple link-local address case
645171259Sdelphij *
646171259Sdelphij * altifp - secondary EUI64 source
64762587Sitojun */
64862587Sitojunvoid
649171259Sdelphijin6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
65062587Sitojun{
65162587Sitojun	struct in6_ifaddr *ia;
65262587Sitojun	struct in6_addr in6;
65362587Sitojun
65478064Sume	/* some of the interfaces are inherently not IPv6 capable */
65578064Sume	switch (ifp->if_type) {
656126263Smlaier	case IFT_PFLOG:
657126263Smlaier	case IFT_PFSYNC:
658142215Sglebius	case IFT_CARP:
65978064Sume		return;
66078064Sume	}
66178064Sume
66253541Sshin	/*
66362587Sitojun	 * quirks based on interface type
66453541Sshin	 */
66562587Sitojun	switch (ifp->if_type) {
66662587Sitojun#ifdef IFT_STF
66762587Sitojun	case IFT_STF:
66862587Sitojun		/*
66995023Ssuz		 * 6to4 interface is a very special kind of beast.
67095023Ssuz		 * no multicast, no linklocal.  RFC2529 specifies how to make
67195023Ssuz		 * linklocals for 6to4 interface, but there's no use and
67295023Ssuz		 * it is rather harmful to have one.
67362587Sitojun		 */
67462587Sitojun		goto statinit;
67562587Sitojun#endif
67662587Sitojun	default:
67762587Sitojun		break;
67853541Sshin	}
67953541Sshin
68053541Sshin	/*
68162587Sitojun	 * usually, we require multicast capability to the interface
68253541Sshin	 */
68362587Sitojun	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
684151465Ssuz		nd6log((LOG_INFO, "in6_ifattach: "
68578064Sume		    "%s is not multicast capable, IPv6 not enabled\n",
686151465Ssuz		    if_name(ifp)));
68762587Sitojun		return;
68862587Sitojun	}
68962587Sitojun
69053541Sshin	/*
69178064Sume	 * assign loopback address for loopback interface.
69278064Sume	 * XXX multiple loopback interface case.
69353541Sshin	 */
69478064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
69578064Sume		in6 = in6addr_loopback;
69662587Sitojun		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
69762587Sitojun			if (in6_ifattach_loopback(ifp) != 0)
69862587Sitojun				return;
69962587Sitojun		}
70062587Sitojun	}
70153541Sshin
70253541Sshin	/*
703120913Sume	 * assign a link-local address, if there's none.
70453541Sshin	 */
705181803Sbz	if (V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
70678064Sume		ia = in6ifa_ifpforlinklocal(ifp, 0);
70778064Sume		if (ia == NULL) {
70878064Sume			if (in6_ifattach_linklocal(ifp, altifp) == 0) {
70978064Sume				/* linklocal address assigned */
71078064Sume			} else {
71178064Sume				/* failed to assign linklocal address. bark? */
71262587Sitojun			}
71362587Sitojun		}
71453541Sshin	}
71553541Sshin
71678064Sume#ifdef IFT_STF			/* XXX */
717120913Sumestatinit:
71878064Sume#endif
71962587Sitojun
72053541Sshin	/* update dynamically. */
721181803Sbz	if (V_in6_maxmtu < ifp->if_mtu)
722181803Sbz		V_in6_maxmtu = ifp->if_mtu;
72353541Sshin}
72453541Sshin
72562587Sitojun/*
72662587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment.
72778064Sume * We don't need this function in bsdi, because interfaces are never removed
72878064Sume * from the ifnet list in bsdi.
72962587Sitojun */
73053541Sshinvoid
731171259Sdelphijin6_ifdetach(struct ifnet *ifp)
73253541Sshin{
73353541Sshin	struct in6_ifaddr *ia, *oia;
73462587Sitojun	struct ifaddr *ifa, *next;
73553541Sshin	struct rtentry *rt;
73653541Sshin	short rtflags;
73762587Sitojun	struct sockaddr_in6 sin6;
738170202Sjinmei	struct in6_multi_mship *imm;
73953541Sshin
74062587Sitojun	/* remove neighbor management table */
74162587Sitojun	nd6_purge(ifp);
74262587Sitojun
74362587Sitojun	/* nuke any of IPv6 addresses we have */
744120913Sume	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
74562587Sitojun		next = ifa->ifa_list.tqe_next;
74662587Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
74762587Sitojun			continue;
74878064Sume		in6_purgeaddr(ifa);
74962587Sitojun	}
75062587Sitojun
75162587Sitojun	/* undo everything done by in6_ifattach(), just in case */
752120913Sume	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
75362587Sitojun		next = ifa->ifa_list.tqe_next;
75462587Sitojun
75553541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6
75653541Sshin		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
75753541Sshin			continue;
75853541Sshin		}
75953541Sshin
76053541Sshin		ia = (struct in6_ifaddr *)ifa;
76153541Sshin
762170202Sjinmei		/*
763170202Sjinmei		 * leave from multicast groups we have joined for the interface
764170202Sjinmei		 */
765170202Sjinmei		while ((imm = ia->ia6_memberships.lh_first) != NULL) {
766170202Sjinmei			LIST_REMOVE(imm, i6mm_chain);
767170202Sjinmei			in6_leavegroup(imm);
768170202Sjinmei		}
769170202Sjinmei
77053541Sshin		/* remove from the routing table */
771120913Sume		if ((ia->ia_flags & IFA_ROUTE) &&
772120913Sume		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
77353541Sshin			rtflags = rt->rt_flags;
77453541Sshin			rtfree(rt);
775120913Sume			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
776120913Sume			    (struct sockaddr *)&ia->ia_addr,
777120913Sume			    (struct sockaddr *)&ia->ia_prefixmask,
778120913Sume			    rtflags, (struct rtentry **)0);
77953541Sshin		}
78053541Sshin
78153541Sshin		/* remove from the linked list */
78253541Sshin		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
78362587Sitojun		IFAFREE(&ia->ia_ifa);
78453541Sshin
78553541Sshin		/* also remove from the IPv6 address chain(itojun&jinmei) */
78653541Sshin		oia = ia;
787181803Sbz		if (oia == (ia = V_in6_ifaddr))
788181803Sbz			V_in6_ifaddr = ia->ia_next;
78953541Sshin		else {
79053541Sshin			while (ia->ia_next && (ia->ia_next != oia))
79153541Sshin				ia = ia->ia_next;
79253541Sshin			if (ia->ia_next)
79353541Sshin				ia->ia_next = oia->ia_next;
79478064Sume			else {
795120913Sume				nd6log((LOG_ERR,
796120913Sume				    "%s: didn't unlink in6ifaddr from list\n",
797120913Sume				    if_name(ifp)));
79878064Sume			}
79953541Sshin		}
80053541Sshin
80162587Sitojun		IFAFREE(&oia->ia_ifa);
80253541Sshin	}
80362587Sitojun
804181803Sbz	in6_pcbpurgeif0(&V_udbinfo, ifp);
805181803Sbz	in6_pcbpurgeif0(&V_ripcbinfo, ifp);
806170613Sbms	/* leave from all multicast groups joined */
807170613Sbms	in6_purgemaddrs(ifp);
808120913Sume
80978064Sume	/*
81078064Sume	 * remove neighbor management table.  we call it twice just to make
81178064Sume	 * sure we nuke everything.  maybe we need just one call.
81278064Sume	 * XXX: since the first call did not release addresses, some prefixes
81378064Sume	 * might remain.  We should call nd6_purge() again to release the
81478064Sume	 * prefixes after removing all addresses above.
81578064Sume	 * (Or can we just delay calling nd6_purge until at this point?)
81678064Sume	 */
81762587Sitojun	nd6_purge(ifp);
81862587Sitojun
81962587Sitojun	/* remove route to link-local allnodes multicast (ff02::1) */
82062587Sitojun	bzero(&sin6, sizeof(sin6));
82162587Sitojun	sin6.sin6_len = sizeof(struct sockaddr_in6);
82262587Sitojun	sin6.sin6_family = AF_INET6;
82362587Sitojun	sin6.sin6_addr = in6addr_linklocal_allnodes;
824148385Sume	if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
825148385Sume		/* XXX: should not fail */
826148385Sume		return;
827121770Ssam	/* XXX grab lock first to avoid LOR */
828181803Sbz	if (V_rt_tables[0][AF_INET6] != NULL) {
829181803Sbz		RADIX_NODE_HEAD_LOCK(V_rt_tables[0][AF_INET6]);
830124333Struckman		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
831124333Struckman		if (rt) {
832124333Struckman			if (rt->rt_ifp == ifp)
833124333Struckman				rtexpunge(rt);
834124333Struckman			RTFREE_LOCKED(rt);
835124333Struckman		}
836181803Sbz		RADIX_NODE_HEAD_UNLOCK(V_rt_tables[0][AF_INET6]);
83762587Sitojun	}
83853541Sshin}
83978064Sume
840151539Ssuzint
841171259Sdelphijin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf,
842171259Sdelphij    const u_int8_t *baseid, int generate)
84378064Sume{
84478064Sume	u_int8_t nullbuf[8];
845121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
84678064Sume
84778064Sume	bzero(nullbuf, sizeof(nullbuf));
84878064Sume	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
84978064Sume		/* we've never created a random ID.  Create a new one. */
85078064Sume		generate = 1;
85178064Sume	}
85278064Sume
85378064Sume	if (generate) {
85478064Sume		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
85578064Sume
85678064Sume		/* generate_tmp_ifid will update seedn and buf */
85778064Sume		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
858120913Sume		    ndi->randomid);
85978064Sume	}
86078064Sume	bcopy(ndi->randomid, retbuf, 8);
861151539Ssuz
862151539Ssuz	return (0);
86378064Sume}
86478064Sume
86578064Sumevoid
866171259Sdelphijin6_tmpaddrtimer(void *ignored_arg)
86778064Sume{
86878064Sume	struct nd_ifinfo *ndi;
86978064Sume	u_int8_t nullbuf[8];
870121161Sume	struct ifnet *ifp;
87178064Sume
872181803Sbz	callout_reset(&V_in6_tmpaddrtimer_ch,
873181803Sbz	    (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
874181803Sbz	    V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL);
87578064Sume
87678064Sume	bzero(nullbuf, sizeof(nullbuf));
877181887Sjulian	for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
878181888Sjulian	    ifp = TAILQ_NEXT(ifp, if_list)) {
879121161Sume		ndi = ND_IFINFO(ifp);
88078064Sume		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
88178064Sume			/*
88278064Sume			 * We've been generating a random ID on this interface.
88378064Sume			 * Create a new one.
88478064Sume			 */
88578064Sume			(void)generate_tmp_ifid(ndi->randomseed0,
886120913Sume			    ndi->randomseed1, ndi->randomid);
88778064Sume		}
88878064Sume	}
88978064Sume
89078064Sume}
891170613Sbms
892170613Sbmsstatic void
893171259Sdelphijin6_purgemaddrs(struct ifnet *ifp)
894170613Sbms{
895170613Sbms	struct in6_multi *in6m;
896170613Sbms	struct in6_multi *oin6m;
897170613Sbms
898170613Sbms#ifdef DIAGNOSTIC
899170613Sbms	printf("%s: purging ifp %p\n", __func__, ifp);
900170613Sbms#endif
901170613Sbms
902170613Sbms	IFF_LOCKGIANT(ifp);
903170613Sbms	LIST_FOREACH_SAFE(in6m, &in6_multihead, in6m_entry, oin6m) {
904170613Sbms		if (in6m->in6m_ifp == ifp)
905170613Sbms			in6_delmulti(in6m);
906170613Sbms	}
907170613Sbms	IFF_UNLOCKGIANT(ifp);
908170613Sbms}
909