in6_ifattach.c revision 157978
162587Sitojun/*	$FreeBSD: head/sys/netinet6/in6_ifattach.c 157978 2006-04-23 15:06:16Z rwatson $	*/
278064Sume/*	$KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $	*/
362587Sitojun
4139826Simp/*-
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
3353541Sshin#include <sys/param.h>
3453541Sshin#include <sys/systm.h>
3553541Sshin#include <sys/malloc.h>
3653541Sshin#include <sys/socket.h>
3753541Sshin#include <sys/sockio.h>
3853541Sshin#include <sys/kernel.h>
3978064Sume#include <sys/syslog.h>
4053541Sshin#include <sys/md5.h>
4153541Sshin
4253541Sshin#include <net/if.h>
4353541Sshin#include <net/if_dl.h>
4453541Sshin#include <net/if_types.h>
4553541Sshin#include <net/route.h>
4653541Sshin
4753541Sshin#include <netinet/in.h>
4853541Sshin#include <netinet/in_var.h>
4953541Sshin#include <netinet/if_ether.h>
5081127Sume#include <netinet/in_pcb.h>
5153541Sshin
5262587Sitojun#include <netinet/ip6.h>
5353541Sshin#include <netinet6/ip6_var.h>
5478064Sume#include <netinet6/in6_var.h>
5581127Sume#include <netinet6/in6_pcb.h>
5653541Sshin#include <netinet6/in6_ifattach.h>
5753541Sshin#include <netinet6/ip6_var.h>
5853541Sshin#include <netinet6/nd6.h>
5962587Sitojun#include <netinet6/scope6_var.h>
6053541Sshin
6153541Sshin#include <net/net_osdep.h>
6253541Sshin
6362587Sitojununsigned long in6_maxmtu = 0;
6453541Sshin
6578064Sume#ifdef IP6_AUTO_LINKLOCAL
6678064Sumeint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
6778064Sume#else
6878064Sumeint ip6_auto_linklocal = 1;	/* enable by default */
6978064Sume#endif
7078064Sume
7178064Sumestruct callout in6_tmpaddrtimer_ch;
7278064Sume
7381127Sumeextern struct inpcbinfo udbinfo;
7481127Sumeextern struct inpcbinfo ripcbinfo;
7581127Sume
7662587Sitojunstatic int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
7778064Sumestatic int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
7862587Sitojunstatic int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
7962587Sitojunstatic int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
8062587Sitojunstatic int in6_ifattach_loopback __P((struct ifnet *));
8153541Sshin
8262587Sitojun#define EUI64_GBIT	0x01
8362587Sitojun#define EUI64_UBIT	0x02
8462587Sitojun#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
8562587Sitojun#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
8662587Sitojun#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
8762587Sitojun#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
8862587Sitojun#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
8953541Sshin
9062587Sitojun#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
9162587Sitojun#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
9253541Sshin
9353541Sshin/*
9453541Sshin * Generate a last-resort interface identifier, when the machine has no
9553541Sshin * IEEE802/EUI64 address sources.
9662587Sitojun * The goal here is to get an interface identifier that is
9762587Sitojun * (1) random enough and (2) does not change across reboot.
9862587Sitojun * We currently use MD5(hostname) for it.
9953541Sshin */
10053541Sshinstatic int
10162587Sitojunget_rand_ifid(ifp, in6)
10262587Sitojun	struct ifnet *ifp;
10395023Ssuz	struct in6_addr *in6;	/* upper 64bits are preserved */
10453541Sshin{
10553541Sshin	MD5_CTX ctxt;
10653541Sshin	u_int8_t digest[16];
10753541Sshin	int hostnamelen	= strlen(hostname);
10853541Sshin
10962587Sitojun#if 0
11062587Sitojun	/* we need at least several letters as seed for ifid */
11162587Sitojun	if (hostnamelen < 3)
11262587Sitojun		return -1;
11362587Sitojun#endif
11462587Sitojun
11562587Sitojun	/* generate 8 bytes of pseudo-random value. */
11653541Sshin	bzero(&ctxt, sizeof(ctxt));
11753541Sshin	MD5Init(&ctxt);
11853541Sshin	MD5Update(&ctxt, hostname, hostnamelen);
11953541Sshin	MD5Final(digest, &ctxt);
12053541Sshin
12162587Sitojun	/* assumes sizeof(digest) > sizeof(ifid) */
12262587Sitojun	bcopy(digest, &in6->s6_addr[8], 8);
12353541Sshin
12453541Sshin	/* make sure to set "u" bit to local, and "g" bit to individual. */
12562587Sitojun	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
12662587Sitojun	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
12753541Sshin
12862587Sitojun	/* convert EUI64 into IPv6 interface identifier */
12962587Sitojun	EUI64_TO_IFID(in6);
13062587Sitojun
13153541Sshin	return 0;
13253541Sshin}
13353541Sshin
13478064Sumestatic int
13578064Sumegenerate_tmp_ifid(seed0, seed1, ret)
13678064Sume	u_int8_t *seed0, *ret;
13778064Sume	const u_int8_t *seed1;
13878064Sume{
13978064Sume	MD5_CTX ctxt;
14078064Sume	u_int8_t seed[16], digest[16], nullbuf[8];
14178064Sume	u_int32_t val32;
14278064Sume
14378064Sume	/* If there's no hisotry, start with a random seed. */
14478064Sume	bzero(nullbuf, sizeof(nullbuf));
14578064Sume	if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
14678064Sume		int i;
14778064Sume
14878064Sume		for (i = 0; i < 2; i++) {
149121807Sume			val32 = arc4random();
15078064Sume			bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
15178064Sume		}
152120913Sume	} else
15378064Sume		bcopy(seed0, seed, 8);
15478064Sume
15578064Sume	/* copy the right-most 64-bits of the given address */
15678064Sume	/* XXX assumption on the size of IFID */
15778064Sume	bcopy(seed1, &seed[8], 8);
15878064Sume
15978064Sume	if (0) {		/* for debugging purposes only */
16078064Sume		int i;
16178064Sume
16278064Sume		printf("generate_tmp_ifid: new randomized ID from: ");
16378064Sume		for (i = 0; i < 16; i++)
16478064Sume			printf("%02x", seed[i]);
16578064Sume		printf(" ");
16678064Sume	}
16778064Sume
16878064Sume	/* generate 16 bytes of pseudo-random value. */
16978064Sume	bzero(&ctxt, sizeof(ctxt));
17078064Sume	MD5Init(&ctxt);
17178064Sume	MD5Update(&ctxt, seed, sizeof(seed));
17278064Sume	MD5Final(digest, &ctxt);
17378064Sume
17478064Sume	/*
17578064Sume	 * RFC 3041 3.2.1. (3)
17678064Sume	 * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
17778064Sume	 * left-most bit is numbered 0) to zero.
17878064Sume	 */
17978064Sume	bcopy(digest, ret, 8);
18078064Sume	ret[0] &= ~EUI64_UBIT;
18178064Sume
18278064Sume	/*
18378064Sume	 * XXX: we'd like to ensure that the generated value is not zero
18478064Sume	 * for simplicity.  If the caclculated digest happens to be zero,
18578064Sume	 * use a random non-zero value as the last resort.
18678064Sume	 */
18778064Sume	if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
188151465Ssuz		nd6log((LOG_INFO,
189151465Ssuz		    "generate_tmp_ifid: computed MD5 value is zero.\n"));
19078064Sume
191121807Sume		val32 = arc4random();
19278064Sume		val32 = 1 + (val32 % (0xffffffff - 1));
19378064Sume	}
19478064Sume
19578064Sume	/*
19678064Sume	 * RFC 3041 3.2.1. (4)
19778064Sume	 * Take the rightmost 64-bits of the MD5 digest and save them in
19878064Sume	 * stable storage as the history value to be used in the next
199120913Sume	 * iteration of the algorithm.
20078064Sume	 */
20178064Sume	bcopy(&digest[8], seed0, 8);
20278064Sume
20378064Sume	if (0) {		/* for debugging purposes only */
20478064Sume		int i;
20578064Sume
20678064Sume		printf("to: ");
20778064Sume		for (i = 0; i < 16; i++)
20878064Sume			printf("%02x", digest[i]);
20978064Sume		printf("\n");
21078064Sume	}
21178064Sume
21278064Sume	return 0;
21378064Sume}
21478064Sume
21553541Sshin/*
21662587Sitojun * Get interface identifier for the specified interface.
21762587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
21853541Sshin */
219151477Ssuzint
220151477Ssuzin6_get_hw_ifid(ifp, in6)
22162587Sitojun	struct ifnet *ifp;
22295023Ssuz	struct in6_addr *in6;	/* upper 64bits are preserved */
22353541Sshin{
22453541Sshin	struct ifaddr *ifa;
22553541Sshin	struct sockaddr_dl *sdl;
22662587Sitojun	u_int8_t *addr;
22762587Sitojun	size_t addrlen;
22862587Sitojun	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
22962587Sitojun	static u_int8_t allone[8] =
23062587Sitojun		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
23153541Sshin
23262587Sitojun	for (ifa = ifp->if_addrlist.tqh_first;
23362587Sitojun	     ifa;
234120913Sume	     ifa = ifa->ifa_list.tqe_next) {
23562587Sitojun		if (ifa->ifa_addr->sa_family != AF_LINK)
23653541Sshin			continue;
23762587Sitojun		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
23862587Sitojun		if (sdl == NULL)
23962587Sitojun			continue;
24062587Sitojun		if (sdl->sdl_alen == 0)
24162587Sitojun			continue;
24262587Sitojun
24362587Sitojun		goto found;
24453541Sshin	}
24553541Sshin
24662587Sitojun	return -1;
24762587Sitojun
24853541Sshinfound:
24962587Sitojun	addr = LLADDR(sdl);
25062587Sitojun	addrlen = sdl->sdl_alen;
25153541Sshin
25262587Sitojun	/* get EUI64 */
25362587Sitojun	switch (ifp->if_type) {
25462587Sitojun	case IFT_ETHER:
25562587Sitojun	case IFT_FDDI:
256120049Smdodd	case IFT_ISO88025:
25762587Sitojun	case IFT_ATM:
25878064Sume	case IFT_IEEE1394:
25978064Sume#ifdef IFT_IEEE80211
26078064Sume	case IFT_IEEE80211:
26178064Sume#endif
26262587Sitojun		/* IEEE802/EUI64 cases - what others? */
26378064Sume		/* IEEE1394 uses 16byte length address starting with EUI64 */
26478064Sume		if (addrlen > 8)
26578064Sume			addrlen = 8;
26653541Sshin
26762587Sitojun		/* look at IEEE802/EUI64 only */
26862587Sitojun		if (addrlen != 8 && addrlen != 6)
26962587Sitojun			return -1;
27053541Sshin
27162587Sitojun		/*
27262587Sitojun		 * check for invalid MAC address - on bsdi, we see it a lot
27362587Sitojun		 * since wildboar configures all-zero MAC on pccard before
27462587Sitojun		 * card insertion.
27562587Sitojun		 */
27662587Sitojun		if (bcmp(addr, allzero, addrlen) == 0)
27762587Sitojun			return -1;
27862587Sitojun		if (bcmp(addr, allone, addrlen) == 0)
27962587Sitojun			return -1;
28062587Sitojun
28162587Sitojun		/* make EUI64 address */
28262587Sitojun		if (addrlen == 8)
28362587Sitojun			bcopy(addr, &in6->s6_addr[8], 8);
28462587Sitojun		else if (addrlen == 6) {
28562587Sitojun			in6->s6_addr[8] = addr[0];
28662587Sitojun			in6->s6_addr[9] = addr[1];
28762587Sitojun			in6->s6_addr[10] = addr[2];
28862587Sitojun			in6->s6_addr[11] = 0xff;
28962587Sitojun			in6->s6_addr[12] = 0xfe;
29062587Sitojun			in6->s6_addr[13] = addr[3];
29162587Sitojun			in6->s6_addr[14] = addr[4];
29262587Sitojun			in6->s6_addr[15] = addr[5];
29362587Sitojun		}
29462587Sitojun		break;
29562587Sitojun
29662587Sitojun	case IFT_ARCNET:
29762587Sitojun		if (addrlen != 1)
29862587Sitojun			return -1;
29962587Sitojun		if (!addr[0])
30062587Sitojun			return -1;
30162587Sitojun
30262587Sitojun		bzero(&in6->s6_addr[8], 8);
30362587Sitojun		in6->s6_addr[15] = addr[0];
30462587Sitojun
30562587Sitojun		/*
30662587Sitojun		 * due to insufficient bitwidth, we mark it local.
30762587Sitojun		 */
30862587Sitojun		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
30962587Sitojun		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
31062587Sitojun		break;
31162587Sitojun
31262587Sitojun	case IFT_GIF:
31362587Sitojun#ifdef IFT_STF
31462587Sitojun	case IFT_STF:
31553541Sshin#endif
31662587Sitojun		/*
31778064Sume		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
31862587Sitojun		 * however, IPv4 address is not very suitable as unique
31962587Sitojun		 * identifier source (can be renumbered).
32062587Sitojun		 * we don't do this.
32162587Sitojun		 */
32262587Sitojun		return -1;
32362587Sitojun
32462587Sitojun	default:
32562587Sitojun		return -1;
32653541Sshin	}
32762587Sitojun
32862587Sitojun	/* sanity check: g bit must not indicate "group" */
32962587Sitojun	if (EUI64_GROUP(in6))
33062587Sitojun		return -1;
33162587Sitojun
33262587Sitojun	/* convert EUI64 into IPv6 interface identifier */
33362587Sitojun	EUI64_TO_IFID(in6);
33462587Sitojun
33562587Sitojun	/*
33662587Sitojun	 * sanity check: ifid must not be all zero, avoid conflict with
33762587Sitojun	 * subnet router anycast
33862587Sitojun	 */
33962587Sitojun	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
34062587Sitojun	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
34162587Sitojun		return -1;
34262587Sitojun	}
34362587Sitojun
34462587Sitojun	return 0;
34553541Sshin}
34653541Sshin
34753541Sshin/*
34862587Sitojun * Get interface identifier for the specified interface.  If it is not
34962587Sitojun * available on ifp0, borrow interface identifier from other information
35062587Sitojun * sources.
35153541Sshin */
35262587Sitojunstatic int
35362587Sitojunget_ifid(ifp0, altifp, in6)
35462587Sitojun	struct ifnet *ifp0;
35595023Ssuz	struct ifnet *altifp;	/* secondary EUI64 source */
35662587Sitojun	struct in6_addr *in6;
35753541Sshin{
35853541Sshin	struct ifnet *ifp;
35953541Sshin
36062587Sitojun	/* first, try to get it from the interface itself */
361151477Ssuz	if (in6_get_hw_ifid(ifp0, in6) == 0) {
36278064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
36378064Sume		    if_name(ifp0)));
36462587Sitojun		goto success;
36562587Sitojun	}
36653541Sshin
36762587Sitojun	/* try secondary EUI64 source. this basically is for ATM PVC */
368151477Ssuz	if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
36978064Sume		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
37078064Sume		    if_name(ifp0), if_name(altifp)));
37162587Sitojun		goto success;
37262587Sitojun	}
37362587Sitojun
37462587Sitojun	/* next, try to get it from some other hardware interface */
375108172Shsu	IFNET_RLOCK();
376120913Sume	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
37762587Sitojun		if (ifp == ifp0)
37862587Sitojun			continue;
379151477Ssuz		if (in6_get_hw_ifid(ifp, in6) != 0)
38062587Sitojun			continue;
38162587Sitojun
38262587Sitojun		/*
38362587Sitojun		 * to borrow ifid from other interface, ifid needs to be
38462587Sitojun		 * globally unique
38562587Sitojun		 */
38662587Sitojun		if (IFID_UNIVERSAL(in6)) {
38778064Sume			nd6log((LOG_DEBUG,
38878064Sume			    "%s: borrow interface identifier from %s\n",
38978064Sume			    if_name(ifp0), if_name(ifp)));
390108172Shsu			IFNET_RUNLOCK();
39162587Sitojun			goto success;
39262587Sitojun		}
39362587Sitojun	}
394108172Shsu	IFNET_RUNLOCK();
39562587Sitojun
39662587Sitojun	/* last resort: get from random number source */
39762587Sitojun	if (get_rand_ifid(ifp, in6) == 0) {
39878064Sume		nd6log((LOG_DEBUG,
39978064Sume		    "%s: interface identifier generated by random number\n",
40078064Sume		    if_name(ifp0)));
40162587Sitojun		goto success;
40262587Sitojun	}
40362587Sitojun
40466504Sitojun	printf("%s: failed to get interface identifier\n", if_name(ifp0));
40562587Sitojun	return -1;
40662587Sitojun
40762587Sitojunsuccess:
408120913Sume	nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
409120913Sume	    if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
410120913Sume	    in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
411120913Sume	    in6->s6_addr[14], in6->s6_addr[15]));
41262587Sitojun	return 0;
41362587Sitojun}
41462587Sitojun
41562587Sitojunstatic int
41678064Sumein6_ifattach_linklocal(ifp, altifp)
41762587Sitojun	struct ifnet *ifp;
41878064Sume	struct ifnet *altifp;	/* secondary EUI64 source */
41978064Sume{
42062587Sitojun	struct in6_ifaddr *ia;
42178064Sume	struct in6_aliasreq ifra;
422151539Ssuz	struct nd_prefixctl pr0;
42378064Sume	int i, error;
42462587Sitojun
42562587Sitojun	/*
42678064Sume	 * configure link-local address.
42762587Sitojun	 */
42878064Sume	bzero(&ifra, sizeof(ifra));
42962587Sitojun
43062587Sitojun	/*
43178064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
43278064Sume	 * for safety.
43362587Sitojun	 */
43478064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
43562587Sitojun
43678064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
43778064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
438148385Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
43978064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
44078064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
44178064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
44278064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
44378064Sume	} else {
44478064Sume		if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
44578064Sume			nd6log((LOG_ERR,
44678064Sume			    "%s: no ifid available\n", if_name(ifp)));
447120913Sume			return (-1);
44862587Sitojun		}
44962587Sitojun	}
450148385Sume	if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
451148385Sume		return (-1);
45262587Sitojun
45378064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
45478064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
45578064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask64;
45678064Sume	/* link-local addresses should NEVER expire. */
45778064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
45878064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
45962587Sitojun
46078064Sume	/*
46178064Sume	 * Now call in6_update_ifa() to do a bunch of procedures to configure
462151465Ssuz	 * a link-local address. We can set the 3rd argument to NULL, because
46395023Ssuz	 * we know there's no other link-local address on the interface
46495023Ssuz	 * and therefore we are adding one (instead of updating one).
46578064Sume	 */
466151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL,
467151539Ssuz				    IN6_IFAUPDATE_DADDELAY)) != 0) {
46862587Sitojun		/*
46978064Sume		 * XXX: When the interface does not support IPv6, this call
47078064Sume		 * would fail in the SIOCSIFADDR ioctl.  I believe the
47178064Sume		 * notification is rather confusing in this case, so just
472120913Sume		 * suppress it.  (jinmei@kame.net 20010130)
47362587Sitojun		 */
47478064Sume		if (error != EAFNOSUPPORT)
475151465Ssuz			nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
47678064Sume			    "configure a link-local address on %s "
47778064Sume			    "(errno=%d)\n",
478151465Ssuz			    if_name(ifp), error));
479120856Sume		return (-1);
48062587Sitojun	}
48162587Sitojun
48278064Sume	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
48378064Sume#ifdef DIAGNOSTIC
48478064Sume	if (!ia) {
48578064Sume		panic("ia == NULL in in6_ifattach_linklocal");
48695023Ssuz		/* NOTREACHED */
48778064Sume	}
48862587Sitojun#endif
48953541Sshin
49078064Sume	/*
491120913Sume	 * Make the link-local prefix (fe80::%link/64) as on-link.
49278064Sume	 * Since we'd like to manage prefixes separately from addresses,
49378064Sume	 * we make an ND6 prefix structure for the link-local prefix,
49478064Sume	 * and add it to the prefix list as a never-expire prefix.
49578064Sume	 * XXX: this change might affect some existing code base...
49678064Sume	 */
49778064Sume	bzero(&pr0, sizeof(pr0));
49878064Sume	pr0.ndpr_ifp = ifp;
49978064Sume	/* this should be 64 at this moment. */
50078064Sume	pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
50178064Sume	pr0.ndpr_prefix = ifra.ifra_addr;
50278064Sume	/* apply the mask for safety. (nd6_prelist_add will apply it again) */
50378064Sume	for (i = 0; i < 4; i++) {
50478064Sume		pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
505120913Sume		    in6mask64.s6_addr32[i];
50662587Sitojun	}
50778064Sume	/*
50878064Sume	 * Initialize parameters.  The link-local prefix must always be
50978064Sume	 * on-link, and its lifetimes never expire.
51078064Sume	 */
51178064Sume	pr0.ndpr_raf_onlink = 1;
51278064Sume	pr0.ndpr_raf_auto = 1;	/* probably meaningless */
51378064Sume	pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
51478064Sume	pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
51578064Sume	/*
51678064Sume	 * Since there is no other link-local addresses, nd6_prefix_lookup()
51778064Sume	 * probably returns NULL.  However, we cannot always expect the result.
51878064Sume	 * For example, if we first remove the (only) existing link-local
51978064Sume	 * address, and then reconfigure another one, the prefix is still
52078064Sume	 * valid with referring to the old link-local address.
52178064Sume	 */
52278064Sume	if (nd6_prefix_lookup(&pr0) == NULL) {
52378064Sume		if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
524120856Sume			return (error);
52578064Sume	}
52662587Sitojun
52762587Sitojun	return 0;
52862587Sitojun}
52962587Sitojun
53062587Sitojunstatic int
53162587Sitojunin6_ifattach_loopback(ifp)
53262587Sitojun	struct ifnet *ifp;	/* must be IFT_LOOP */
53362587Sitojun{
53478064Sume	struct in6_aliasreq ifra;
53578064Sume	int error;
53662587Sitojun
53778064Sume	bzero(&ifra, sizeof(ifra));
53878064Sume
53962587Sitojun	/*
54078064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
54178064Sume	 * for safety.
54262587Sitojun	 */
54378064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
54462587Sitojun
54578064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
54678064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
54778064Sume	ifra.ifra_prefixmask.sin6_addr = in6mask128;
54862587Sitojun
54962587Sitojun	/*
55062587Sitojun	 * Always initialize ia_dstaddr (= broadcast address) to loopback
55178064Sume	 * address.  Follows IPv4 practice - see in_ifinit().
55262587Sitojun	 */
55378064Sume	ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
55478064Sume	ifra.ifra_dstaddr.sin6_family = AF_INET6;
55578064Sume	ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
55662587Sitojun
55778064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
55878064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
55978064Sume	ifra.ifra_addr.sin6_addr = in6addr_loopback;
56062587Sitojun
56178064Sume	/* the loopback  address should NEVER expire. */
56278064Sume	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
56378064Sume	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
56462587Sitojun
56595023Ssuz	/* we don't need to perform DAD on loopback interfaces. */
56678064Sume	ifra.ifra_flags |= IN6_IFF_NODAD;
56778064Sume
56878064Sume	/* skip registration to the prefix list. XXX should be temporary. */
56978064Sume	ifra.ifra_flags |= IN6_IFF_NOPFX;
57078064Sume
57178064Sume	/*
57295023Ssuz	 * We are sure that this is a newly assigned address, so we can set
57395023Ssuz	 * NULL to the 3rd arg.
57478064Sume	 */
575151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
576151465Ssuz		nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
57778064Sume		    "the loopback address on %s (errno=%d)\n",
578151465Ssuz		    if_name(ifp), error));
579120856Sume		return (-1);
58062587Sitojun	}
58162587Sitojun
58262587Sitojun	return 0;
58362587Sitojun}
58462587Sitojun
58562587Sitojun/*
58662587Sitojun * compute NI group address, based on the current hostname setting.
58762587Sitojun * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
58862587Sitojun *
58962587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid.
59062587Sitojun */
59178064Sumeint
59278064Sumein6_nigroup(ifp, name, namelen, in6)
59362587Sitojun	struct ifnet *ifp;
59462587Sitojun	const char *name;
59562587Sitojun	int namelen;
59662587Sitojun	struct in6_addr *in6;
59762587Sitojun{
59862587Sitojun	const char *p;
59978064Sume	u_char *q;
60062587Sitojun	MD5_CTX ctxt;
60162587Sitojun	u_int8_t digest[16];
60262587Sitojun	char l;
60378064Sume	char n[64];	/* a single label must not exceed 63 chars */
60462587Sitojun
60562587Sitojun	if (!namelen || !name)
60662587Sitojun		return -1;
60762587Sitojun
60862587Sitojun	p = name;
60962587Sitojun	while (p && *p && *p != '.' && p - name < namelen)
61062587Sitojun		p++;
61178064Sume	if (p - name > sizeof(n) - 1)
61295023Ssuz		return -1;	/* label too long */
61362587Sitojun	l = p - name;
61478064Sume	strncpy(n, name, l);
61578064Sume	n[(int)l] = '\0';
61678064Sume	for (q = n; *q; q++) {
61778064Sume		if ('A' <= *q && *q <= 'Z')
61878064Sume			*q = *q - 'A' + 'a';
61978064Sume	}
62062587Sitojun
62162587Sitojun	/* generate 8 bytes of pseudo-random value. */
62262587Sitojun	bzero(&ctxt, sizeof(ctxt));
62362587Sitojun	MD5Init(&ctxt);
62462587Sitojun	MD5Update(&ctxt, &l, sizeof(l));
62578064Sume	MD5Update(&ctxt, n, l);
62662587Sitojun	MD5Final(digest, &ctxt);
62762587Sitojun
62862587Sitojun	bzero(in6, sizeof(*in6));
629151465Ssuz	in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
63062587Sitojun	in6->s6_addr8[11] = 2;
63162587Sitojun	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
632148385Sume	if (in6_setscope(in6, ifp, NULL))
633148385Sume		return (-1); /* XXX: should not fail */
63462587Sitojun
63562587Sitojun	return 0;
63662587Sitojun}
63762587Sitojun
63862587Sitojun/*
63962587Sitojun * XXX multiple loopback interface needs more care.  for instance,
64062587Sitojun * nodelocal address needs to be configured onto only one of them.
64162587Sitojun * XXX multiple link-local address case
64262587Sitojun */
64362587Sitojunvoid
64462587Sitojunin6_ifattach(ifp, altifp)
64562587Sitojun	struct ifnet *ifp;
64662587Sitojun	struct ifnet *altifp;	/* secondary EUI64 source */
64762587Sitojun{
64862587Sitojun	struct in6_ifaddr *ia;
64962587Sitojun	struct in6_addr in6;
65062587Sitojun
65178064Sume	/* some of the interfaces are inherently not IPv6 capable */
65278064Sume	switch (ifp->if_type) {
653126263Smlaier	case IFT_PFLOG:
654126263Smlaier	case IFT_PFSYNC:
655142215Sglebius	case IFT_CARP:
65678064Sume		return;
65778064Sume	}
65878064Sume
65953541Sshin	/*
66062587Sitojun	 * quirks based on interface type
66153541Sshin	 */
66262587Sitojun	switch (ifp->if_type) {
66362587Sitojun#ifdef IFT_STF
66462587Sitojun	case IFT_STF:
66562587Sitojun		/*
66695023Ssuz		 * 6to4 interface is a very special kind of beast.
66795023Ssuz		 * no multicast, no linklocal.  RFC2529 specifies how to make
66895023Ssuz		 * linklocals for 6to4 interface, but there's no use and
66995023Ssuz		 * it is rather harmful to have one.
67062587Sitojun		 */
67162587Sitojun		goto statinit;
67262587Sitojun#endif
67362587Sitojun	default:
67462587Sitojun		break;
67553541Sshin	}
67653541Sshin
67753541Sshin	/*
67862587Sitojun	 * usually, we require multicast capability to the interface
67953541Sshin	 */
68062587Sitojun	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
681151465Ssuz		nd6log((LOG_INFO, "in6_ifattach: "
68278064Sume		    "%s is not multicast capable, IPv6 not enabled\n",
683151465Ssuz		    if_name(ifp)));
68462587Sitojun		return;
68562587Sitojun	}
68662587Sitojun
68753541Sshin	/*
68878064Sume	 * assign loopback address for loopback interface.
68978064Sume	 * XXX multiple loopback interface case.
69053541Sshin	 */
69178064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
69278064Sume		in6 = in6addr_loopback;
69362587Sitojun		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
69462587Sitojun			if (in6_ifattach_loopback(ifp) != 0)
69562587Sitojun				return;
69662587Sitojun		}
69762587Sitojun	}
69853541Sshin
69953541Sshin	/*
700120913Sume	 * assign a link-local address, if there's none.
70153541Sshin	 */
702149829Sthompsa	if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
70378064Sume		ia = in6ifa_ifpforlinklocal(ifp, 0);
70478064Sume		if (ia == NULL) {
70578064Sume			if (in6_ifattach_linklocal(ifp, altifp) == 0) {
70678064Sume				/* linklocal address assigned */
70778064Sume			} else {
70878064Sume				/* failed to assign linklocal address. bark? */
70962587Sitojun			}
71062587Sitojun		}
71153541Sshin	}
71253541Sshin
71378064Sume#ifdef IFT_STF			/* XXX */
714120913Sumestatinit:
71578064Sume#endif
71662587Sitojun
71753541Sshin	/* update dynamically. */
71853541Sshin	if (in6_maxmtu < ifp->if_mtu)
71953541Sshin		in6_maxmtu = ifp->if_mtu;
72053541Sshin}
72153541Sshin
72262587Sitojun/*
72362587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment.
72478064Sume * We don't need this function in bsdi, because interfaces are never removed
72578064Sume * from the ifnet list in bsdi.
72662587Sitojun */
72753541Sshinvoid
72853541Sshinin6_ifdetach(ifp)
72953541Sshin	struct ifnet *ifp;
73053541Sshin{
73153541Sshin	struct in6_ifaddr *ia, *oia;
73262587Sitojun	struct ifaddr *ifa, *next;
73353541Sshin	struct rtentry *rt;
73453541Sshin	short rtflags;
73562587Sitojun	struct sockaddr_in6 sin6;
73662587Sitojun	struct in6_multi *in6m;
73762587Sitojun	struct in6_multi *in6m_next;
73853541Sshin
73962587Sitojun	/* remove neighbor management table */
74062587Sitojun	nd6_purge(ifp);
74162587Sitojun
74262587Sitojun	/* nuke any of IPv6 addresses we have */
743120913Sume	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
74462587Sitojun		next = ifa->ifa_list.tqe_next;
74562587Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
74662587Sitojun			continue;
74778064Sume		in6_purgeaddr(ifa);
74862587Sitojun	}
74962587Sitojun
75062587Sitojun	/* undo everything done by in6_ifattach(), just in case */
751120913Sume	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
75262587Sitojun		next = ifa->ifa_list.tqe_next;
75362587Sitojun
75453541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6
75553541Sshin		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
75653541Sshin			continue;
75753541Sshin		}
75853541Sshin
75953541Sshin		ia = (struct in6_ifaddr *)ifa;
76053541Sshin
76153541Sshin		/* remove from the routing table */
762120913Sume		if ((ia->ia_flags & IFA_ROUTE) &&
763120913Sume		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
76453541Sshin			rtflags = rt->rt_flags;
76553541Sshin			rtfree(rt);
766120913Sume			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
767120913Sume			    (struct sockaddr *)&ia->ia_addr,
768120913Sume			    (struct sockaddr *)&ia->ia_prefixmask,
769120913Sume			    rtflags, (struct rtentry **)0);
77053541Sshin		}
77153541Sshin
77253541Sshin		/* remove from the linked list */
77353541Sshin		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
77462587Sitojun		IFAFREE(&ia->ia_ifa);
77553541Sshin
77653541Sshin		/* also remove from the IPv6 address chain(itojun&jinmei) */
77753541Sshin		oia = ia;
77853541Sshin		if (oia == (ia = in6_ifaddr))
77953541Sshin			in6_ifaddr = ia->ia_next;
78053541Sshin		else {
78153541Sshin			while (ia->ia_next && (ia->ia_next != oia))
78253541Sshin				ia = ia->ia_next;
78353541Sshin			if (ia->ia_next)
78453541Sshin				ia->ia_next = oia->ia_next;
78578064Sume			else {
786120913Sume				nd6log((LOG_ERR,
787120913Sume				    "%s: didn't unlink in6ifaddr from list\n",
788120913Sume				    if_name(ifp)));
78978064Sume			}
79053541Sshin		}
79153541Sshin
79262587Sitojun		IFAFREE(&oia->ia_ifa);
79353541Sshin	}
79462587Sitojun
79562587Sitojun	/* leave from all multicast groups joined */
796120913Sume
797157978Srwatson	in6_pcbpurgeif0(&udbinfo, ifp);
798157978Srwatson	in6_pcbpurgeif0(&ripcbinfo, ifp);
799120913Sume
80062587Sitojun	for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
80162587Sitojun		in6m_next = LIST_NEXT(in6m, in6m_entry);
80262587Sitojun		if (in6m->in6m_ifp != ifp)
80362587Sitojun			continue;
80462587Sitojun		in6_delmulti(in6m);
80562587Sitojun		in6m = NULL;
80662587Sitojun	}
80762587Sitojun
80878064Sume	/*
80978064Sume	 * remove neighbor management table.  we call it twice just to make
81078064Sume	 * sure we nuke everything.  maybe we need just one call.
81178064Sume	 * XXX: since the first call did not release addresses, some prefixes
81278064Sume	 * might remain.  We should call nd6_purge() again to release the
81378064Sume	 * prefixes after removing all addresses above.
81478064Sume	 * (Or can we just delay calling nd6_purge until at this point?)
81578064Sume	 */
81662587Sitojun	nd6_purge(ifp);
81762587Sitojun
81862587Sitojun	/* remove route to link-local allnodes multicast (ff02::1) */
81962587Sitojun	bzero(&sin6, sizeof(sin6));
82062587Sitojun	sin6.sin6_len = sizeof(struct sockaddr_in6);
82162587Sitojun	sin6.sin6_family = AF_INET6;
82262587Sitojun	sin6.sin6_addr = in6addr_linklocal_allnodes;
823148385Sume	if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
824148385Sume		/* XXX: should not fail */
825148385Sume		return;
826121770Ssam	/* XXX grab lock first to avoid LOR */
827124333Struckman	if (rt_tables[AF_INET6] != NULL) {
828124333Struckman		RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET6]);
829124333Struckman		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
830124333Struckman		if (rt) {
831124333Struckman			if (rt->rt_ifp == ifp)
832124333Struckman				rtexpunge(rt);
833124333Struckman			RTFREE_LOCKED(rt);
834124333Struckman		}
835124333Struckman		RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET6]);
83662587Sitojun	}
83753541Sshin}
83878064Sume
839151539Ssuzint
84078064Sumein6_get_tmpifid(ifp, retbuf, baseid, generate)
84178064Sume	struct ifnet *ifp;
84278064Sume	u_int8_t *retbuf;
84378064Sume	const u_int8_t *baseid;
84478064Sume	int generate;
84578064Sume{
84678064Sume	u_int8_t nullbuf[8];
847121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
84878064Sume
84978064Sume	bzero(nullbuf, sizeof(nullbuf));
85078064Sume	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
85178064Sume		/* we've never created a random ID.  Create a new one. */
85278064Sume		generate = 1;
85378064Sume	}
85478064Sume
85578064Sume	if (generate) {
85678064Sume		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
85778064Sume
85878064Sume		/* generate_tmp_ifid will update seedn and buf */
85978064Sume		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
860120913Sume		    ndi->randomid);
86178064Sume	}
86278064Sume	bcopy(ndi->randomid, retbuf, 8);
863151539Ssuz
864151539Ssuz	return (0);
86578064Sume}
86678064Sume
86778064Sumevoid
86878064Sumein6_tmpaddrtimer(ignored_arg)
86978064Sume	void *ignored_arg;
87078064Sume{
87178064Sume	struct nd_ifinfo *ndi;
87278064Sume	u_int8_t nullbuf[8];
873121161Sume	struct ifnet *ifp;
87478064Sume	int s = splnet();
87578064Sume
87678064Sume	callout_reset(&in6_tmpaddrtimer_ch,
877120913Sume	    (ip6_temp_preferred_lifetime - ip6_desync_factor -
878120913Sume	    ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL);
87978064Sume
88078064Sume	bzero(nullbuf, sizeof(nullbuf));
881121161Sume	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
882121161Sume		ndi = ND_IFINFO(ifp);
88378064Sume		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
88478064Sume			/*
88578064Sume			 * We've been generating a random ID on this interface.
88678064Sume			 * Create a new one.
88778064Sume			 */
88878064Sume			(void)generate_tmp_ifid(ndi->randomseed0,
889120913Sume			    ndi->randomseed1, ndi->randomid);
89078064Sume		}
89178064Sume	}
89278064Sume
89378064Sume	splx(s);
89478064Sume}
895