xref: /freebsd/sys/netinet6/in6_ifattach.c (revision e699b0ae537fe57a4149582e0066a8a9061ff8f2)
1686cdd19SJun-ichiro itojun Hagino /*	$FreeBSD$	*/
2de9c893eSJun-ichiro itojun Hagino /*	$KAME: in6_ifattach.c,v 1.67 2000/10/01 10:51:54 itojun Exp $	*/
3686cdd19SJun-ichiro itojun Hagino 
482cd038dSYoshinobu Inoue /*
582cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
682cd038dSYoshinobu Inoue  * All rights reserved.
782cd038dSYoshinobu Inoue  *
882cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
982cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
1082cd038dSYoshinobu Inoue  * are met:
1182cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1282cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1382cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1482cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1582cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1682cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1782cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1882cd038dSYoshinobu Inoue  *    without specific prior written permission.
1982cd038dSYoshinobu Inoue  *
2082cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2182cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2282cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2382cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2482cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2582cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2682cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2782cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2882cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2982cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3082cd038dSYoshinobu Inoue  * SUCH DAMAGE.
3182cd038dSYoshinobu Inoue  */
3282cd038dSYoshinobu Inoue 
3382cd038dSYoshinobu Inoue #include <sys/param.h>
3482cd038dSYoshinobu Inoue #include <sys/systm.h>
3582cd038dSYoshinobu Inoue #include <sys/malloc.h>
3682cd038dSYoshinobu Inoue #include <sys/socket.h>
3782cd038dSYoshinobu Inoue #include <sys/sockio.h>
3882cd038dSYoshinobu Inoue #include <sys/kernel.h>
3982cd038dSYoshinobu Inoue #include <sys/md5.h>
4082cd038dSYoshinobu Inoue 
4182cd038dSYoshinobu Inoue #include <net/if.h>
4282cd038dSYoshinobu Inoue #include <net/if_dl.h>
4382cd038dSYoshinobu Inoue #include <net/if_types.h>
4482cd038dSYoshinobu Inoue #include <net/route.h>
4582cd038dSYoshinobu Inoue 
4682cd038dSYoshinobu Inoue #include <netinet/in.h>
4782cd038dSYoshinobu Inoue #include <netinet/in_var.h>
4882cd038dSYoshinobu Inoue #include <netinet/if_ether.h>
4982cd038dSYoshinobu Inoue 
50686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
5182cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
5282cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h>
5382cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
5482cd038dSYoshinobu Inoue #include <netinet6/nd6.h>
55686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h>
5682cd038dSYoshinobu Inoue 
5782cd038dSYoshinobu Inoue #include <net/net_osdep.h>
5882cd038dSYoshinobu Inoue 
5982cd038dSYoshinobu Inoue struct in6_ifstat **in6_ifstat = NULL;
6082cd038dSYoshinobu Inoue struct icmp6_ifstat **icmp6_ifstat = NULL;
6182cd038dSYoshinobu Inoue size_t in6_ifstatmax = 0;
6282cd038dSYoshinobu Inoue size_t icmp6_ifstatmax = 0;
6382cd038dSYoshinobu Inoue unsigned long in6_maxmtu = 0;
6482cd038dSYoshinobu Inoue 
65686cdd19SJun-ichiro itojun Hagino static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
66686cdd19SJun-ichiro itojun Hagino static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
67686cdd19SJun-ichiro itojun Hagino static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
68686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
69686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
70686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_loopback __P((struct ifnet *));
71686cdd19SJun-ichiro itojun Hagino static int nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
7282cd038dSYoshinobu Inoue 
73686cdd19SJun-ichiro itojun Hagino #define EUI64_GBIT	0x01
74686cdd19SJun-ichiro itojun Hagino #define EUI64_UBIT	0x02
75686cdd19SJun-ichiro itojun Hagino #define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
76686cdd19SJun-ichiro itojun Hagino #define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
77686cdd19SJun-ichiro itojun Hagino #define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
78686cdd19SJun-ichiro itojun Hagino #define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
79686cdd19SJun-ichiro itojun Hagino #define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
8082cd038dSYoshinobu Inoue 
81686cdd19SJun-ichiro itojun Hagino #define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
82686cdd19SJun-ichiro itojun Hagino #define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
8382cd038dSYoshinobu Inoue 
8482cd038dSYoshinobu Inoue /*
8582cd038dSYoshinobu Inoue  * Generate a last-resort interface identifier, when the machine has no
8682cd038dSYoshinobu Inoue  * IEEE802/EUI64 address sources.
87686cdd19SJun-ichiro itojun Hagino  * The goal here is to get an interface identifier that is
88686cdd19SJun-ichiro itojun Hagino  * (1) random enough and (2) does not change across reboot.
89686cdd19SJun-ichiro itojun Hagino  * We currently use MD5(hostname) for it.
9082cd038dSYoshinobu Inoue  */
9182cd038dSYoshinobu Inoue static int
92686cdd19SJun-ichiro itojun Hagino get_rand_ifid(ifp, in6)
93686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
94686cdd19SJun-ichiro itojun Hagino 	struct in6_addr *in6;	/*upper 64bits are preserved */
9582cd038dSYoshinobu Inoue {
9682cd038dSYoshinobu Inoue 	MD5_CTX ctxt;
9782cd038dSYoshinobu Inoue 	u_int8_t digest[16];
9882cd038dSYoshinobu Inoue 	int hostnamelen	= strlen(hostname);
9982cd038dSYoshinobu Inoue 
100686cdd19SJun-ichiro itojun Hagino #if 0
101686cdd19SJun-ichiro itojun Hagino 	/* we need at least several letters as seed for ifid */
102686cdd19SJun-ichiro itojun Hagino 	if (hostnamelen < 3)
103686cdd19SJun-ichiro itojun Hagino 		return -1;
104686cdd19SJun-ichiro itojun Hagino #endif
105686cdd19SJun-ichiro itojun Hagino 
10682cd038dSYoshinobu Inoue 	/* generate 8 bytes of pseudo-random value. */
10782cd038dSYoshinobu Inoue 	bzero(&ctxt, sizeof(ctxt));
10882cd038dSYoshinobu Inoue 	MD5Init(&ctxt);
10982cd038dSYoshinobu Inoue 	MD5Update(&ctxt, hostname, hostnamelen);
11082cd038dSYoshinobu Inoue 	MD5Final(digest, &ctxt);
11182cd038dSYoshinobu Inoue 
112686cdd19SJun-ichiro itojun Hagino 	/* assumes sizeof(digest) > sizeof(ifid) */
113686cdd19SJun-ichiro itojun Hagino 	bcopy(digest, &in6->s6_addr[8], 8);
11482cd038dSYoshinobu Inoue 
11582cd038dSYoshinobu Inoue 	/* make sure to set "u" bit to local, and "g" bit to individual. */
116686cdd19SJun-ichiro itojun Hagino 	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
117686cdd19SJun-ichiro itojun Hagino 	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
118686cdd19SJun-ichiro itojun Hagino 
119686cdd19SJun-ichiro itojun Hagino 	/* convert EUI64 into IPv6 interface identifier */
120686cdd19SJun-ichiro itojun Hagino 	EUI64_TO_IFID(in6);
12182cd038dSYoshinobu Inoue 
12282cd038dSYoshinobu Inoue 	return 0;
12382cd038dSYoshinobu Inoue }
12482cd038dSYoshinobu Inoue 
12582cd038dSYoshinobu Inoue /*
126686cdd19SJun-ichiro itojun Hagino  * Get interface identifier for the specified interface.
127686cdd19SJun-ichiro itojun Hagino  * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
12882cd038dSYoshinobu Inoue  */
129686cdd19SJun-ichiro itojun Hagino static int
130686cdd19SJun-ichiro itojun Hagino get_hw_ifid(ifp, in6)
13182cd038dSYoshinobu Inoue 	struct ifnet *ifp;
132686cdd19SJun-ichiro itojun Hagino 	struct in6_addr *in6;	/*upper 64bits are preserved */
13382cd038dSYoshinobu Inoue {
134686cdd19SJun-ichiro itojun Hagino 	struct ifaddr *ifa;
135686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_dl *sdl;
136686cdd19SJun-ichiro itojun Hagino 	u_int8_t *addr;
137686cdd19SJun-ichiro itojun Hagino 	size_t addrlen;
138686cdd19SJun-ichiro itojun Hagino 	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
139686cdd19SJun-ichiro itojun Hagino 	static u_int8_t allone[8] =
140686cdd19SJun-ichiro itojun Hagino 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
141686cdd19SJun-ichiro itojun Hagino 
142686cdd19SJun-ichiro itojun Hagino 	for (ifa = ifp->if_addrlist.tqh_first;
143686cdd19SJun-ichiro itojun Hagino 	     ifa;
144686cdd19SJun-ichiro itojun Hagino 	     ifa = ifa->ifa_list.tqe_next)
14582cd038dSYoshinobu Inoue 	{
14682cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_LINK)
14782cd038dSYoshinobu Inoue 			continue;
14882cd038dSYoshinobu Inoue 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
14982cd038dSYoshinobu Inoue 		if (sdl == NULL)
15082cd038dSYoshinobu Inoue 			continue;
15182cd038dSYoshinobu Inoue 		if (sdl->sdl_alen == 0)
15282cd038dSYoshinobu Inoue 			continue;
153686cdd19SJun-ichiro itojun Hagino 
154686cdd19SJun-ichiro itojun Hagino 		goto found;
155686cdd19SJun-ichiro itojun Hagino 	}
156686cdd19SJun-ichiro itojun Hagino 
157686cdd19SJun-ichiro itojun Hagino 	return -1;
158686cdd19SJun-ichiro itojun Hagino 
159686cdd19SJun-ichiro itojun Hagino found:
160686cdd19SJun-ichiro itojun Hagino 	addr = LLADDR(sdl);
161686cdd19SJun-ichiro itojun Hagino 	addrlen = sdl->sdl_alen;
162686cdd19SJun-ichiro itojun Hagino 
163686cdd19SJun-ichiro itojun Hagino 	/* get EUI64 */
16482cd038dSYoshinobu Inoue 	switch (ifp->if_type) {
16582cd038dSYoshinobu Inoue 	case IFT_ETHER:
16682cd038dSYoshinobu Inoue 	case IFT_FDDI:
16782cd038dSYoshinobu Inoue 	case IFT_ATM:
16882cd038dSYoshinobu Inoue 		/* IEEE802/EUI64 cases - what others? */
169686cdd19SJun-ichiro itojun Hagino 
170686cdd19SJun-ichiro itojun Hagino 		/* look at IEEE802/EUI64 only */
171686cdd19SJun-ichiro itojun Hagino 		if (addrlen != 8 && addrlen != 6)
172686cdd19SJun-ichiro itojun Hagino 			return -1;
173686cdd19SJun-ichiro itojun Hagino 
17482cd038dSYoshinobu Inoue 		/*
175686cdd19SJun-ichiro itojun Hagino 		 * check for invalid MAC address - on bsdi, we see it a lot
176686cdd19SJun-ichiro itojun Hagino 		 * since wildboar configures all-zero MAC on pccard before
177686cdd19SJun-ichiro itojun Hagino 		 * card insertion.
17882cd038dSYoshinobu Inoue 		 */
179686cdd19SJun-ichiro itojun Hagino 		if (bcmp(addr, allzero, addrlen) == 0)
180686cdd19SJun-ichiro itojun Hagino 			return -1;
181686cdd19SJun-ichiro itojun Hagino 		if (bcmp(addr, allone, addrlen) == 0)
182686cdd19SJun-ichiro itojun Hagino 			return -1;
183686cdd19SJun-ichiro itojun Hagino 
184686cdd19SJun-ichiro itojun Hagino 		/* make EUI64 address */
185686cdd19SJun-ichiro itojun Hagino 		if (addrlen == 8)
186686cdd19SJun-ichiro itojun Hagino 			bcopy(addr, &in6->s6_addr[8], 8);
187686cdd19SJun-ichiro itojun Hagino 		else if (addrlen == 6) {
188686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[8] = addr[0];
189686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[9] = addr[1];
190686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[10] = addr[2];
191686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[11] = 0xff;
192686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[12] = 0xfe;
193686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[13] = addr[3];
194686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[14] = addr[4];
195686cdd19SJun-ichiro itojun Hagino 			in6->s6_addr[15] = addr[5];
196686cdd19SJun-ichiro itojun Hagino 		}
19782cd038dSYoshinobu Inoue 		break;
198686cdd19SJun-ichiro itojun Hagino 
19982cd038dSYoshinobu Inoue 	case IFT_ARCNET:
200686cdd19SJun-ichiro itojun Hagino 		if (addrlen != 1)
201686cdd19SJun-ichiro itojun Hagino 			return -1;
202686cdd19SJun-ichiro itojun Hagino 		if (!addr[0])
203686cdd19SJun-ichiro itojun Hagino 			return -1;
204686cdd19SJun-ichiro itojun Hagino 
205686cdd19SJun-ichiro itojun Hagino 		bzero(&in6->s6_addr[8], 8);
206686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[15] = addr[0];
207686cdd19SJun-ichiro itojun Hagino 
20882cd038dSYoshinobu Inoue 		/*
209686cdd19SJun-ichiro itojun Hagino 		 * due to insufficient bitwidth, we mark it local.
21082cd038dSYoshinobu Inoue 		 */
211686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
212686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
21382cd038dSYoshinobu Inoue 		break;
214686cdd19SJun-ichiro itojun Hagino 
215686cdd19SJun-ichiro itojun Hagino 	case IFT_GIF:
216686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF
217686cdd19SJun-ichiro itojun Hagino 	case IFT_STF:
21882cd038dSYoshinobu Inoue #endif
219686cdd19SJun-ichiro itojun Hagino 		/*
220686cdd19SJun-ichiro itojun Hagino 		 * mech-06 says: "SHOULD use IPv4 address as ifid source".
221686cdd19SJun-ichiro itojun Hagino 		 * however, IPv4 address is not very suitable as unique
222686cdd19SJun-ichiro itojun Hagino 		 * identifier source (can be renumbered).
223686cdd19SJun-ichiro itojun Hagino 		 * we don't do this.
224686cdd19SJun-ichiro itojun Hagino 		 */
225686cdd19SJun-ichiro itojun Hagino 		return -1;
22682cd038dSYoshinobu Inoue 
227686cdd19SJun-ichiro itojun Hagino 	default:
228686cdd19SJun-ichiro itojun Hagino 		return -1;
229686cdd19SJun-ichiro itojun Hagino 	}
23082cd038dSYoshinobu Inoue 
231686cdd19SJun-ichiro itojun Hagino 	/* sanity check: g bit must not indicate "group" */
232686cdd19SJun-ichiro itojun Hagino 	if (EUI64_GROUP(in6))
233686cdd19SJun-ichiro itojun Hagino 		return -1;
23482cd038dSYoshinobu Inoue 
235686cdd19SJun-ichiro itojun Hagino 	/* convert EUI64 into IPv6 interface identifier */
236686cdd19SJun-ichiro itojun Hagino 	EUI64_TO_IFID(in6);
237686cdd19SJun-ichiro itojun Hagino 
238686cdd19SJun-ichiro itojun Hagino 	/*
239686cdd19SJun-ichiro itojun Hagino 	 * sanity check: ifid must not be all zero, avoid conflict with
240686cdd19SJun-ichiro itojun Hagino 	 * subnet router anycast
241686cdd19SJun-ichiro itojun Hagino 	 */
242686cdd19SJun-ichiro itojun Hagino 	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
243686cdd19SJun-ichiro itojun Hagino 	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
244686cdd19SJun-ichiro itojun Hagino 		return -1;
245686cdd19SJun-ichiro itojun Hagino 	}
24682cd038dSYoshinobu Inoue 
24782cd038dSYoshinobu Inoue 	return 0;
248686cdd19SJun-ichiro itojun Hagino }
249686cdd19SJun-ichiro itojun Hagino 
250686cdd19SJun-ichiro itojun Hagino /*
251686cdd19SJun-ichiro itojun Hagino  * Get interface identifier for the specified interface.  If it is not
252686cdd19SJun-ichiro itojun Hagino  * available on ifp0, borrow interface identifier from other information
253686cdd19SJun-ichiro itojun Hagino  * sources.
254686cdd19SJun-ichiro itojun Hagino  */
255686cdd19SJun-ichiro itojun Hagino static int
256686cdd19SJun-ichiro itojun Hagino get_ifid(ifp0, altifp, in6)
257686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp0;
258686cdd19SJun-ichiro itojun Hagino 	struct ifnet *altifp;	/*secondary EUI64 source*/
259686cdd19SJun-ichiro itojun Hagino 	struct in6_addr *in6;
260686cdd19SJun-ichiro itojun Hagino {
261686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
262686cdd19SJun-ichiro itojun Hagino 
263686cdd19SJun-ichiro itojun Hagino 	/* first, try to get it from the interface itself */
264686cdd19SJun-ichiro itojun Hagino 	if (get_hw_ifid(ifp0, in6) == 0) {
265686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
266686cdd19SJun-ichiro itojun Hagino 		printf("%s: got interface identifier from itself\n",
267686cdd19SJun-ichiro itojun Hagino 		    if_name(ifp0));
26882cd038dSYoshinobu Inoue #endif
269686cdd19SJun-ichiro itojun Hagino 		goto success;
270686cdd19SJun-ichiro itojun Hagino 	}
271686cdd19SJun-ichiro itojun Hagino 
272686cdd19SJun-ichiro itojun Hagino 	/* try secondary EUI64 source. this basically is for ATM PVC */
273686cdd19SJun-ichiro itojun Hagino 	if (altifp && get_hw_ifid(altifp, in6) == 0) {
274686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
275686cdd19SJun-ichiro itojun Hagino 		printf("%s: got interface identifier from %s\n",
276686cdd19SJun-ichiro itojun Hagino 		    if_name(ifp0), if_name(altifp));
277686cdd19SJun-ichiro itojun Hagino #endif
278686cdd19SJun-ichiro itojun Hagino 		goto success;
279686cdd19SJun-ichiro itojun Hagino 	}
280686cdd19SJun-ichiro itojun Hagino 
281686cdd19SJun-ichiro itojun Hagino 	/* next, try to get it from some other hardware interface */
282686cdd19SJun-ichiro itojun Hagino 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
283686cdd19SJun-ichiro itojun Hagino 	{
284686cdd19SJun-ichiro itojun Hagino 		if (ifp == ifp0)
285686cdd19SJun-ichiro itojun Hagino 			continue;
286686cdd19SJun-ichiro itojun Hagino 		if (get_hw_ifid(ifp, in6) != 0)
287686cdd19SJun-ichiro itojun Hagino 			continue;
288686cdd19SJun-ichiro itojun Hagino 
289686cdd19SJun-ichiro itojun Hagino 		/*
290686cdd19SJun-ichiro itojun Hagino 		 * to borrow ifid from other interface, ifid needs to be
291686cdd19SJun-ichiro itojun Hagino 		 * globally unique
292686cdd19SJun-ichiro itojun Hagino 		 */
293686cdd19SJun-ichiro itojun Hagino 		if (IFID_UNIVERSAL(in6)) {
294686cdd19SJun-ichiro itojun Hagino 
295686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
296686cdd19SJun-ichiro itojun Hagino 			printf("%s: borrow interface identifier from %s\n",
297686cdd19SJun-ichiro itojun Hagino 			    if_name(ifp0), if_name(ifp));
298686cdd19SJun-ichiro itojun Hagino #endif
299686cdd19SJun-ichiro itojun Hagino 			goto success;
300686cdd19SJun-ichiro itojun Hagino 		}
301686cdd19SJun-ichiro itojun Hagino 	}
302686cdd19SJun-ichiro itojun Hagino 
303686cdd19SJun-ichiro itojun Hagino 	/* last resort: get from random number source */
304686cdd19SJun-ichiro itojun Hagino 	if (get_rand_ifid(ifp, in6) == 0) {
305686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
306686cdd19SJun-ichiro itojun Hagino 		printf("%s: interface identifier generated by random number\n",
307686cdd19SJun-ichiro itojun Hagino 		    if_name(ifp0));
308686cdd19SJun-ichiro itojun Hagino #endif
309686cdd19SJun-ichiro itojun Hagino 		goto success;
310686cdd19SJun-ichiro itojun Hagino 	}
311686cdd19SJun-ichiro itojun Hagino 
312de9c893eSJun-ichiro itojun Hagino 	printf("%s: failed to get interface identifier\n", if_name(ifp0));
313686cdd19SJun-ichiro itojun Hagino 	return -1;
314686cdd19SJun-ichiro itojun Hagino 
315686cdd19SJun-ichiro itojun Hagino success:
316686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
317686cdd19SJun-ichiro itojun Hagino 	printf("%s: ifid: "
318686cdd19SJun-ichiro itojun Hagino 		"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
319686cdd19SJun-ichiro itojun Hagino 		if_name(ifp0),
320686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[8], in6->s6_addr[9],
321686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[10], in6->s6_addr[11],
322686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[12], in6->s6_addr[13],
323686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr[14], in6->s6_addr[15]);
324686cdd19SJun-ichiro itojun Hagino #endif
325686cdd19SJun-ichiro itojun Hagino 	return 0;
326686cdd19SJun-ichiro itojun Hagino }
327686cdd19SJun-ichiro itojun Hagino 
328686cdd19SJun-ichiro itojun Hagino /*
329686cdd19SJun-ichiro itojun Hagino  * configure IPv6 interface address.  XXX code duplicated with in.c
330686cdd19SJun-ichiro itojun Hagino  */
331686cdd19SJun-ichiro itojun Hagino static int
332686cdd19SJun-ichiro itojun Hagino in6_ifattach_addaddr(ifp, ia)
333686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
334686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *ia;
335686cdd19SJun-ichiro itojun Hagino {
336686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *oia;
337686cdd19SJun-ichiro itojun Hagino 	struct ifaddr *ifa;
338686cdd19SJun-ichiro itojun Hagino 	int error;
339686cdd19SJun-ichiro itojun Hagino 	int rtflag;
340686cdd19SJun-ichiro itojun Hagino 	struct in6_addr llsol;
341686cdd19SJun-ichiro itojun Hagino 
342686cdd19SJun-ichiro itojun Hagino 	/*
343686cdd19SJun-ichiro itojun Hagino 	 * initialize if_addrlist, if we are the very first one
344686cdd19SJun-ichiro itojun Hagino 	 */
345686cdd19SJun-ichiro itojun Hagino 	ifa = TAILQ_FIRST(&ifp->if_addrlist);
346686cdd19SJun-ichiro itojun Hagino 	if (ifa == NULL) {
347686cdd19SJun-ichiro itojun Hagino 		TAILQ_INIT(&ifp->if_addrlist);
348686cdd19SJun-ichiro itojun Hagino 	}
349686cdd19SJun-ichiro itojun Hagino 
350686cdd19SJun-ichiro itojun Hagino 	/*
351686cdd19SJun-ichiro itojun Hagino 	 * link the interface address to global list
352686cdd19SJun-ichiro itojun Hagino 	 */
353686cdd19SJun-ichiro itojun Hagino 	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
354686cdd19SJun-ichiro itojun Hagino 	/* gain a refcnt for the link from if_addrlist */
355686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_refcnt++;
356686cdd19SJun-ichiro itojun Hagino 
357686cdd19SJun-ichiro itojun Hagino 	/*
358686cdd19SJun-ichiro itojun Hagino 	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
359686cdd19SJun-ichiro itojun Hagino 	 * kazu opposed it, but itojun & jinmei wanted.
360686cdd19SJun-ichiro itojun Hagino 	 */
361686cdd19SJun-ichiro itojun Hagino 	if ((oia = in6_ifaddr) != NULL) {
362686cdd19SJun-ichiro itojun Hagino 		for (; oia->ia_next; oia = oia->ia_next)
363686cdd19SJun-ichiro itojun Hagino 			continue;
364686cdd19SJun-ichiro itojun Hagino 		oia->ia_next = ia;
365686cdd19SJun-ichiro itojun Hagino 	} else
366686cdd19SJun-ichiro itojun Hagino 		in6_ifaddr = ia;
367686cdd19SJun-ichiro itojun Hagino 	/* gain another refcnt for the link from in6_ifaddr */
368686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_refcnt++;
369686cdd19SJun-ichiro itojun Hagino 
370686cdd19SJun-ichiro itojun Hagino 	/*
371686cdd19SJun-ichiro itojun Hagino 	 * give the interface a chance to initialize, in case this
372686cdd19SJun-ichiro itojun Hagino 	 * is the first address to be added.
373686cdd19SJun-ichiro itojun Hagino 	 */
374686cdd19SJun-ichiro itojun Hagino 	if (ifp->if_ioctl != NULL) {
375686cdd19SJun-ichiro itojun Hagino 		int s;
376686cdd19SJun-ichiro itojun Hagino 		s = splimp();
377686cdd19SJun-ichiro itojun Hagino 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
378686cdd19SJun-ichiro itojun Hagino 		splx(s);
379686cdd19SJun-ichiro itojun Hagino 	} else
380686cdd19SJun-ichiro itojun Hagino 		error = 0;
381686cdd19SJun-ichiro itojun Hagino 	if (error) {
382686cdd19SJun-ichiro itojun Hagino 		switch (error) {
383686cdd19SJun-ichiro itojun Hagino 		case EAFNOSUPPORT:
384686cdd19SJun-ichiro itojun Hagino 			printf("%s: IPv6 not supported\n", if_name(ifp));
385686cdd19SJun-ichiro itojun Hagino 			break;
386686cdd19SJun-ichiro itojun Hagino 		default:
387686cdd19SJun-ichiro itojun Hagino 			printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
388686cdd19SJun-ichiro itojun Hagino 			    error);
389686cdd19SJun-ichiro itojun Hagino 			break;
390686cdd19SJun-ichiro itojun Hagino 		}
391686cdd19SJun-ichiro itojun Hagino 
392686cdd19SJun-ichiro itojun Hagino 		/* undo changes */
393686cdd19SJun-ichiro itojun Hagino 		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
394686cdd19SJun-ichiro itojun Hagino 		IFAFREE(&ia->ia_ifa);
395686cdd19SJun-ichiro itojun Hagino 		if (oia)
396686cdd19SJun-ichiro itojun Hagino 			oia->ia_next = ia->ia_next;
397686cdd19SJun-ichiro itojun Hagino 		else
398686cdd19SJun-ichiro itojun Hagino 			in6_ifaddr = ia->ia_next;
399686cdd19SJun-ichiro itojun Hagino 		IFAFREE(&ia->ia_ifa);
400686cdd19SJun-ichiro itojun Hagino 		return -1;
401686cdd19SJun-ichiro itojun Hagino 	}
402686cdd19SJun-ichiro itojun Hagino 
403686cdd19SJun-ichiro itojun Hagino 	/* configure link-layer address resolution */
404686cdd19SJun-ichiro itojun Hagino 	rtflag = 0;
405686cdd19SJun-ichiro itojun Hagino 	if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
406686cdd19SJun-ichiro itojun Hagino 		rtflag = RTF_HOST;
407686cdd19SJun-ichiro itojun Hagino 	else {
408686cdd19SJun-ichiro itojun Hagino 		switch (ifp->if_type) {
409686cdd19SJun-ichiro itojun Hagino 		case IFT_LOOP:
410686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF
411686cdd19SJun-ichiro itojun Hagino 		case IFT_STF:
412686cdd19SJun-ichiro itojun Hagino #endif
413686cdd19SJun-ichiro itojun Hagino 			rtflag = 0;
414686cdd19SJun-ichiro itojun Hagino 			break;
415686cdd19SJun-ichiro itojun Hagino 		default:
416686cdd19SJun-ichiro itojun Hagino 			ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
417686cdd19SJun-ichiro itojun Hagino 			ia->ia_ifa.ifa_flags |= RTF_CLONING;
418686cdd19SJun-ichiro itojun Hagino 			rtflag = RTF_CLONING;
419686cdd19SJun-ichiro itojun Hagino 			break;
420686cdd19SJun-ichiro itojun Hagino 		}
421686cdd19SJun-ichiro itojun Hagino 	}
422686cdd19SJun-ichiro itojun Hagino 
423686cdd19SJun-ichiro itojun Hagino 	/* add route to the interface. */
424686cdd19SJun-ichiro itojun Hagino 	{
425686cdd19SJun-ichiro itojun Hagino 		int e;
426686cdd19SJun-ichiro itojun Hagino 
427686cdd19SJun-ichiro itojun Hagino 		e = rtrequest(RTM_ADD,
428686cdd19SJun-ichiro itojun Hagino 			      (struct sockaddr *)&ia->ia_addr,
429686cdd19SJun-ichiro itojun Hagino 			      (struct sockaddr *)&ia->ia_addr,
430686cdd19SJun-ichiro itojun Hagino 			      (struct sockaddr *)&ia->ia_prefixmask,
431686cdd19SJun-ichiro itojun Hagino 			      RTF_UP | rtflag,
432686cdd19SJun-ichiro itojun Hagino 			      (struct rtentry **)0);
433686cdd19SJun-ichiro itojun Hagino 		if (e) {
434686cdd19SJun-ichiro itojun Hagino 			printf("in6_ifattach_addaddr: rtrequest failed. errno = %d\n", e);
435686cdd19SJun-ichiro itojun Hagino 		}
436686cdd19SJun-ichiro itojun Hagino 	}
437686cdd19SJun-ichiro itojun Hagino 	ia->ia_flags |= IFA_ROUTE;
438686cdd19SJun-ichiro itojun Hagino 
439686cdd19SJun-ichiro itojun Hagino 	if ((rtflag & RTF_CLONING) != 0 &&
440686cdd19SJun-ichiro itojun Hagino 	    (ifp->if_flags & IFF_MULTICAST) != 0) {
441686cdd19SJun-ichiro itojun Hagino 		/*
442686cdd19SJun-ichiro itojun Hagino 		 * join solicited multicast address
443686cdd19SJun-ichiro itojun Hagino 		 */
444686cdd19SJun-ichiro itojun Hagino 		bzero(&llsol, sizeof(llsol));
445686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr16[0] = htons(0xff02);
446686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr16[1] = htons(ifp->if_index);
447686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr32[1] = 0;
448686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr32[2] = htonl(1);
449686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
450686cdd19SJun-ichiro itojun Hagino 		llsol.s6_addr8[12] = 0xff;
451686cdd19SJun-ichiro itojun Hagino 		(void)in6_addmulti(&llsol, ifp, &error);
452686cdd19SJun-ichiro itojun Hagino 
453686cdd19SJun-ichiro itojun Hagino 		/* XXX should we run DAD on other interface types? */
454686cdd19SJun-ichiro itojun Hagino 		switch (ifp->if_type) {
455686cdd19SJun-ichiro itojun Hagino #if 1
456686cdd19SJun-ichiro itojun Hagino 		case IFT_ARCNET:
457686cdd19SJun-ichiro itojun Hagino 		case IFT_ETHER:
458686cdd19SJun-ichiro itojun Hagino 		case IFT_FDDI:
459686cdd19SJun-ichiro itojun Hagino #else
460686cdd19SJun-ichiro itojun Hagino 		default:
461686cdd19SJun-ichiro itojun Hagino #endif
462686cdd19SJun-ichiro itojun Hagino 			/* mark the address TENTATIVE, if needed. */
463686cdd19SJun-ichiro itojun Hagino 			ia->ia6_flags |= IN6_IFF_TENTATIVE;
464686cdd19SJun-ichiro itojun Hagino 			/* nd6_dad_start() will be called in in6_if_up */
465686cdd19SJun-ichiro itojun Hagino 		}
466686cdd19SJun-ichiro itojun Hagino 	}
467686cdd19SJun-ichiro itojun Hagino 
468686cdd19SJun-ichiro itojun Hagino 	return 0;
469686cdd19SJun-ichiro itojun Hagino }
470686cdd19SJun-ichiro itojun Hagino 
471686cdd19SJun-ichiro itojun Hagino static int
472686cdd19SJun-ichiro itojun Hagino in6_ifattach_linklocal(ifp, altifp)
473686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
474686cdd19SJun-ichiro itojun Hagino 	struct ifnet *altifp;	/*secondary EUI64 source*/
475686cdd19SJun-ichiro itojun Hagino {
476686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *ia;
477686cdd19SJun-ichiro itojun Hagino 
478686cdd19SJun-ichiro itojun Hagino 	/*
479686cdd19SJun-ichiro itojun Hagino 	 * configure link-local address
480686cdd19SJun-ichiro itojun Hagino 	 */
481686cdd19SJun-ichiro itojun Hagino 	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
482686cdd19SJun-ichiro itojun Hagino 	bzero((caddr_t)ia, sizeof(*ia));
483686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
484686cdd19SJun-ichiro itojun Hagino 	if (ifp->if_flags & IFF_POINTOPOINT)
485686cdd19SJun-ichiro itojun Hagino 		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
486686cdd19SJun-ichiro itojun Hagino 	else
487686cdd19SJun-ichiro itojun Hagino 		ia->ia_ifa.ifa_dstaddr = NULL;
488686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
489686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifp = ifp;
490686cdd19SJun-ichiro itojun Hagino 
491686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
492686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
493686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_family = AF_INET6;
494686cdd19SJun-ichiro itojun Hagino #ifdef SCOPEDROUTING
495686cdd19SJun-ichiro itojun Hagino 	/* take into accound the sin6_scope_id field for routing */
496686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_scope_id = 0xffffffff;
497686cdd19SJun-ichiro itojun Hagino #endif
498686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_addr = in6mask64;
499686cdd19SJun-ichiro itojun Hagino 
500686cdd19SJun-ichiro itojun Hagino 	/* just in case */
501686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
502686cdd19SJun-ichiro itojun Hagino 	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
503686cdd19SJun-ichiro itojun Hagino 	ia->ia_dstaddr.sin6_family = AF_INET6;
504686cdd19SJun-ichiro itojun Hagino 
505686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
506686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
507686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_family = AF_INET6;
508686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
509686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
510686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
511686cdd19SJun-ichiro itojun Hagino 	if (ifp->if_flags & IFF_LOOPBACK) {
512686cdd19SJun-ichiro itojun Hagino 		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
513686cdd19SJun-ichiro itojun Hagino 		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
514686cdd19SJun-ichiro itojun Hagino 	} else {
515686cdd19SJun-ichiro itojun Hagino 		if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
516686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
517686cdd19SJun-ichiro itojun Hagino 			printf("%s: no ifid available\n", if_name(ifp));
518686cdd19SJun-ichiro itojun Hagino #endif
519686cdd19SJun-ichiro itojun Hagino 			free(ia, M_IFADDR);
520686cdd19SJun-ichiro itojun Hagino 			return -1;
521686cdd19SJun-ichiro itojun Hagino 		}
522686cdd19SJun-ichiro itojun Hagino 	}
523686cdd19SJun-ichiro itojun Hagino #ifdef SCOPEDROUTING
524686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp,
525686cdd19SJun-ichiro itojun Hagino 						     &ia->ia_addr.sin6_addr);
526686cdd19SJun-ichiro itojun Hagino #endif
527686cdd19SJun-ichiro itojun Hagino 
528686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_metric = ifp->if_metric;
529686cdd19SJun-ichiro itojun Hagino 
530686cdd19SJun-ichiro itojun Hagino 	if (in6_ifattach_addaddr(ifp, ia) != 0) {
531686cdd19SJun-ichiro itojun Hagino 		/* ia will be freed on failure */
532686cdd19SJun-ichiro itojun Hagino 		return -1;
533686cdd19SJun-ichiro itojun Hagino 	}
534686cdd19SJun-ichiro itojun Hagino 
535686cdd19SJun-ichiro itojun Hagino 	return 0;
536686cdd19SJun-ichiro itojun Hagino }
537686cdd19SJun-ichiro itojun Hagino 
538686cdd19SJun-ichiro itojun Hagino static int
539686cdd19SJun-ichiro itojun Hagino in6_ifattach_loopback(ifp)
540686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;	/* must be IFT_LOOP */
541686cdd19SJun-ichiro itojun Hagino {
542686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *ia;
543686cdd19SJun-ichiro itojun Hagino 
544686cdd19SJun-ichiro itojun Hagino 	/*
545686cdd19SJun-ichiro itojun Hagino 	 * configure link-local address
546686cdd19SJun-ichiro itojun Hagino 	 */
547686cdd19SJun-ichiro itojun Hagino 	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
548686cdd19SJun-ichiro itojun Hagino 	bzero((caddr_t)ia, sizeof(*ia));
549686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
550686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
551686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
552686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifp = ifp;
553686cdd19SJun-ichiro itojun Hagino 
554686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
555686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
556686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_family = AF_INET6;
557686cdd19SJun-ichiro itojun Hagino 	ia->ia_prefixmask.sin6_addr = in6mask128;
558686cdd19SJun-ichiro itojun Hagino 
559686cdd19SJun-ichiro itojun Hagino 	/*
560686cdd19SJun-ichiro itojun Hagino 	 * Always initialize ia_dstaddr (= broadcast address) to loopback
561686cdd19SJun-ichiro itojun Hagino 	 * address, to make getifaddr happier.
562686cdd19SJun-ichiro itojun Hagino 	 *
563686cdd19SJun-ichiro itojun Hagino 	 * For BSDI, it is mandatory.  The BSDI version of
564686cdd19SJun-ichiro itojun Hagino 	 * ifa_ifwithroute() rejects to add a route to the loopback
565686cdd19SJun-ichiro itojun Hagino 	 * interface.  Even for other systems, loopback looks somewhat
566686cdd19SJun-ichiro itojun Hagino 	 * special.
567686cdd19SJun-ichiro itojun Hagino 	 */
568686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
569686cdd19SJun-ichiro itojun Hagino 	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
570686cdd19SJun-ichiro itojun Hagino 	ia->ia_dstaddr.sin6_family = AF_INET6;
571686cdd19SJun-ichiro itojun Hagino 	ia->ia_dstaddr.sin6_addr = in6addr_loopback;
572686cdd19SJun-ichiro itojun Hagino 
573686cdd19SJun-ichiro itojun Hagino 	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
574686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
575686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_family = AF_INET6;
576686cdd19SJun-ichiro itojun Hagino 	ia->ia_addr.sin6_addr = in6addr_loopback;
577686cdd19SJun-ichiro itojun Hagino 
578686cdd19SJun-ichiro itojun Hagino 	ia->ia_ifa.ifa_metric = ifp->if_metric;
579686cdd19SJun-ichiro itojun Hagino 
580686cdd19SJun-ichiro itojun Hagino 	if (in6_ifattach_addaddr(ifp, ia) != 0) {
581686cdd19SJun-ichiro itojun Hagino 		/* ia will be freed on failure */
582686cdd19SJun-ichiro itojun Hagino 		return -1;
583686cdd19SJun-ichiro itojun Hagino 	}
584686cdd19SJun-ichiro itojun Hagino 
585686cdd19SJun-ichiro itojun Hagino 	return 0;
586686cdd19SJun-ichiro itojun Hagino }
587686cdd19SJun-ichiro itojun Hagino 
588686cdd19SJun-ichiro itojun Hagino /*
589686cdd19SJun-ichiro itojun Hagino  * compute NI group address, based on the current hostname setting.
590686cdd19SJun-ichiro itojun Hagino  * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
591686cdd19SJun-ichiro itojun Hagino  *
592686cdd19SJun-ichiro itojun Hagino  * when ifp == NULL, the caller is responsible for filling scopeid.
593686cdd19SJun-ichiro itojun Hagino  */
594686cdd19SJun-ichiro itojun Hagino static int
595686cdd19SJun-ichiro itojun Hagino nigroup(ifp, name, namelen, in6)
596686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
597686cdd19SJun-ichiro itojun Hagino 	const char *name;
598686cdd19SJun-ichiro itojun Hagino 	int namelen;
599686cdd19SJun-ichiro itojun Hagino 	struct in6_addr *in6;
600686cdd19SJun-ichiro itojun Hagino {
601686cdd19SJun-ichiro itojun Hagino 	const char *p;
602686cdd19SJun-ichiro itojun Hagino 	MD5_CTX ctxt;
603686cdd19SJun-ichiro itojun Hagino 	u_int8_t digest[16];
604686cdd19SJun-ichiro itojun Hagino 	char l;
605686cdd19SJun-ichiro itojun Hagino 
606686cdd19SJun-ichiro itojun Hagino 	if (!namelen || !name)
607686cdd19SJun-ichiro itojun Hagino 		return -1;
608686cdd19SJun-ichiro itojun Hagino 
609686cdd19SJun-ichiro itojun Hagino 	p = name;
610686cdd19SJun-ichiro itojun Hagino 	while (p && *p && *p != '.' && p - name < namelen)
611686cdd19SJun-ichiro itojun Hagino 		p++;
612686cdd19SJun-ichiro itojun Hagino 	if (p - name > 63)
613686cdd19SJun-ichiro itojun Hagino 		return -1;	/*label too long*/
614686cdd19SJun-ichiro itojun Hagino 	l = p - name;
615686cdd19SJun-ichiro itojun Hagino 
616686cdd19SJun-ichiro itojun Hagino 	/* generate 8 bytes of pseudo-random value. */
617686cdd19SJun-ichiro itojun Hagino 	bzero(&ctxt, sizeof(ctxt));
618686cdd19SJun-ichiro itojun Hagino 	MD5Init(&ctxt);
619686cdd19SJun-ichiro itojun Hagino 	MD5Update(&ctxt, &l, sizeof(l));
620686cdd19SJun-ichiro itojun Hagino 	/* LINTED const cast */
621686cdd19SJun-ichiro itojun Hagino 	MD5Update(&ctxt, (void *)name, p - name);
622686cdd19SJun-ichiro itojun Hagino 	MD5Final(digest, &ctxt);
623686cdd19SJun-ichiro itojun Hagino 
624686cdd19SJun-ichiro itojun Hagino 	bzero(in6, sizeof(*in6));
625686cdd19SJun-ichiro itojun Hagino 	in6->s6_addr16[0] = htons(0xff02);
626686cdd19SJun-ichiro itojun Hagino 	if (ifp)
627686cdd19SJun-ichiro itojun Hagino 		in6->s6_addr16[1] = htons(ifp->if_index);
628686cdd19SJun-ichiro itojun Hagino 	in6->s6_addr8[11] = 2;
629686cdd19SJun-ichiro itojun Hagino 	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
630686cdd19SJun-ichiro itojun Hagino 
631686cdd19SJun-ichiro itojun Hagino 	return 0;
632686cdd19SJun-ichiro itojun Hagino }
633686cdd19SJun-ichiro itojun Hagino 
634686cdd19SJun-ichiro itojun Hagino void
635686cdd19SJun-ichiro itojun Hagino in6_nigroup_attach(name, namelen)
636686cdd19SJun-ichiro itojun Hagino 	const char *name;
637686cdd19SJun-ichiro itojun Hagino 	int namelen;
638686cdd19SJun-ichiro itojun Hagino {
639686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
640686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_in6 mltaddr;
641686cdd19SJun-ichiro itojun Hagino 	struct in6_multi *in6m;
642686cdd19SJun-ichiro itojun Hagino 	int error;
643686cdd19SJun-ichiro itojun Hagino 
644686cdd19SJun-ichiro itojun Hagino 	bzero(&mltaddr, sizeof(mltaddr));
645686cdd19SJun-ichiro itojun Hagino 	mltaddr.sin6_family = AF_INET6;
646686cdd19SJun-ichiro itojun Hagino 	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
647686cdd19SJun-ichiro itojun Hagino 	if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
648686cdd19SJun-ichiro itojun Hagino 		return;
649686cdd19SJun-ichiro itojun Hagino 
650686cdd19SJun-ichiro itojun Hagino 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
651686cdd19SJun-ichiro itojun Hagino 	{
652686cdd19SJun-ichiro itojun Hagino 		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
653686cdd19SJun-ichiro itojun Hagino 		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
654686cdd19SJun-ichiro itojun Hagino 		if (!in6m)
655686cdd19SJun-ichiro itojun Hagino 			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
656686cdd19SJun-ichiro itojun Hagino 	}
657686cdd19SJun-ichiro itojun Hagino }
658686cdd19SJun-ichiro itojun Hagino 
659686cdd19SJun-ichiro itojun Hagino void
660686cdd19SJun-ichiro itojun Hagino in6_nigroup_detach(name, namelen)
661686cdd19SJun-ichiro itojun Hagino 	const char *name;
662686cdd19SJun-ichiro itojun Hagino 	int namelen;
663686cdd19SJun-ichiro itojun Hagino {
664686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
665686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_in6 mltaddr;
666686cdd19SJun-ichiro itojun Hagino 	struct in6_multi *in6m;
667686cdd19SJun-ichiro itojun Hagino 
668686cdd19SJun-ichiro itojun Hagino 	bzero(&mltaddr, sizeof(mltaddr));
669686cdd19SJun-ichiro itojun Hagino 	mltaddr.sin6_family = AF_INET6;
670686cdd19SJun-ichiro itojun Hagino 	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
671686cdd19SJun-ichiro itojun Hagino 	if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
672686cdd19SJun-ichiro itojun Hagino 		return;
673686cdd19SJun-ichiro itojun Hagino 
674686cdd19SJun-ichiro itojun Hagino 	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
675686cdd19SJun-ichiro itojun Hagino 	{
676686cdd19SJun-ichiro itojun Hagino 		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
677686cdd19SJun-ichiro itojun Hagino 		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
678686cdd19SJun-ichiro itojun Hagino 		if (in6m)
679686cdd19SJun-ichiro itojun Hagino 			in6_delmulti(in6m);
68082cd038dSYoshinobu Inoue 	}
68182cd038dSYoshinobu Inoue }
68282cd038dSYoshinobu Inoue 
68382cd038dSYoshinobu Inoue /*
684686cdd19SJun-ichiro itojun Hagino  * XXX multiple loopback interface needs more care.  for instance,
685686cdd19SJun-ichiro itojun Hagino  * nodelocal address needs to be configured onto only one of them.
686686cdd19SJun-ichiro itojun Hagino  * XXX multiple link-local address case
68782cd038dSYoshinobu Inoue  */
68882cd038dSYoshinobu Inoue void
689686cdd19SJun-ichiro itojun Hagino in6_ifattach(ifp, altifp)
69082cd038dSYoshinobu Inoue 	struct ifnet *ifp;
691686cdd19SJun-ichiro itojun Hagino 	struct ifnet *altifp;	/* secondary EUI64 source */
69282cd038dSYoshinobu Inoue {
69382cd038dSYoshinobu Inoue 	static size_t if_indexlim = 8;
69482cd038dSYoshinobu Inoue 	struct sockaddr_in6 mltaddr;
69582cd038dSYoshinobu Inoue 	struct sockaddr_in6 mltmask;
69682cd038dSYoshinobu Inoue 	struct sockaddr_in6 gate;
69782cd038dSYoshinobu Inoue 	struct sockaddr_in6 mask;
698686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *ia;
699686cdd19SJun-ichiro itojun Hagino 	struct in6_addr in6;
700686cdd19SJun-ichiro itojun Hagino 	int hostnamelen	= strlen(hostname);
70182cd038dSYoshinobu Inoue 
70282cd038dSYoshinobu Inoue 	/*
70382cd038dSYoshinobu Inoue 	 * We have some arrays that should be indexed by if_index.
70482cd038dSYoshinobu Inoue 	 * since if_index will grow dynamically, they should grow too.
70582cd038dSYoshinobu Inoue 	 *	struct in6_ifstat **in6_ifstat
70682cd038dSYoshinobu Inoue 	 *	struct icmp6_ifstat **icmp6_ifstat
70782cd038dSYoshinobu Inoue 	 */
708686cdd19SJun-ichiro itojun Hagino 	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
709686cdd19SJun-ichiro itojun Hagino 	    if_index >= if_indexlim) {
71082cd038dSYoshinobu Inoue 		size_t n;
71182cd038dSYoshinobu Inoue 		caddr_t q;
71282cd038dSYoshinobu Inoue 		size_t olim;
71382cd038dSYoshinobu Inoue 
71482cd038dSYoshinobu Inoue 		olim = if_indexlim;
71582cd038dSYoshinobu Inoue 		while (if_index >= if_indexlim)
71682cd038dSYoshinobu Inoue 			if_indexlim <<= 1;
71782cd038dSYoshinobu Inoue 
71882cd038dSYoshinobu Inoue 		/* grow in6_ifstat */
71982cd038dSYoshinobu Inoue 		n = if_indexlim * sizeof(struct in6_ifstat *);
72082cd038dSYoshinobu Inoue 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
72182cd038dSYoshinobu Inoue 		bzero(q, n);
72282cd038dSYoshinobu Inoue 		if (in6_ifstat) {
72382cd038dSYoshinobu Inoue 			bcopy((caddr_t)in6_ifstat, q,
72482cd038dSYoshinobu Inoue 				olim * sizeof(struct in6_ifstat *));
72582cd038dSYoshinobu Inoue 			free((caddr_t)in6_ifstat, M_IFADDR);
72682cd038dSYoshinobu Inoue 		}
72782cd038dSYoshinobu Inoue 		in6_ifstat = (struct in6_ifstat **)q;
72882cd038dSYoshinobu Inoue 		in6_ifstatmax = if_indexlim;
72982cd038dSYoshinobu Inoue 
73082cd038dSYoshinobu Inoue 		/* grow icmp6_ifstat */
73182cd038dSYoshinobu Inoue 		n = if_indexlim * sizeof(struct icmp6_ifstat *);
73282cd038dSYoshinobu Inoue 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
73382cd038dSYoshinobu Inoue 		bzero(q, n);
73482cd038dSYoshinobu Inoue 		if (icmp6_ifstat) {
73582cd038dSYoshinobu Inoue 			bcopy((caddr_t)icmp6_ifstat, q,
73682cd038dSYoshinobu Inoue 				olim * sizeof(struct icmp6_ifstat *));
73782cd038dSYoshinobu Inoue 			free((caddr_t)icmp6_ifstat, M_IFADDR);
73882cd038dSYoshinobu Inoue 		}
73982cd038dSYoshinobu Inoue 		icmp6_ifstat = (struct icmp6_ifstat **)q;
74082cd038dSYoshinobu Inoue 		icmp6_ifstatmax = if_indexlim;
74182cd038dSYoshinobu Inoue 	}
74282cd038dSYoshinobu Inoue 
743686cdd19SJun-ichiro itojun Hagino 	/* initialize scope identifiers */
744686cdd19SJun-ichiro itojun Hagino 	scope6_ifattach(ifp);
74582cd038dSYoshinobu Inoue 
74682cd038dSYoshinobu Inoue 	/*
747686cdd19SJun-ichiro itojun Hagino 	 * quirks based on interface type
74882cd038dSYoshinobu Inoue 	 */
749686cdd19SJun-ichiro itojun Hagino 	switch (ifp->if_type) {
750686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF
751686cdd19SJun-ichiro itojun Hagino 	case IFT_STF:
75282cd038dSYoshinobu Inoue 		/*
753686cdd19SJun-ichiro itojun Hagino 		 * 6to4 interface is a very speical kind of beast.
754686cdd19SJun-ichiro itojun Hagino 		 * no multicast, no linklocal (based on 03 draft).
75582cd038dSYoshinobu Inoue 		 */
756686cdd19SJun-ichiro itojun Hagino 		goto statinit;
757686cdd19SJun-ichiro itojun Hagino #endif
75882cd038dSYoshinobu Inoue 	default:
75982cd038dSYoshinobu Inoue 		break;
76082cd038dSYoshinobu Inoue 	}
76182cd038dSYoshinobu Inoue 
762686cdd19SJun-ichiro itojun Hagino 	/*
763686cdd19SJun-ichiro itojun Hagino 	 * usually, we require multicast capability to the interface
764686cdd19SJun-ichiro itojun Hagino 	 */
765686cdd19SJun-ichiro itojun Hagino 	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
766686cdd19SJun-ichiro itojun Hagino 		printf("%s: not multicast capable, IPv6 not enabled\n",
767686cdd19SJun-ichiro itojun Hagino 		    if_name(ifp));
76882cd038dSYoshinobu Inoue 		return;
76982cd038dSYoshinobu Inoue 	}
770686cdd19SJun-ichiro itojun Hagino 
771686cdd19SJun-ichiro itojun Hagino 	/*
772686cdd19SJun-ichiro itojun Hagino 	 * assign link-local address, if there's none
773686cdd19SJun-ichiro itojun Hagino 	 */
774686cdd19SJun-ichiro itojun Hagino 	ia = in6ifa_ifpforlinklocal(ifp, 0);
775686cdd19SJun-ichiro itojun Hagino 	if (ia == NULL) {
776686cdd19SJun-ichiro itojun Hagino 		if (in6_ifattach_linklocal(ifp, altifp) != 0)
777686cdd19SJun-ichiro itojun Hagino 			return;
778686cdd19SJun-ichiro itojun Hagino 		ia = in6ifa_ifpforlinklocal(ifp, 0);
779686cdd19SJun-ichiro itojun Hagino 
780686cdd19SJun-ichiro itojun Hagino 		if (ia == NULL) {
781de9c893eSJun-ichiro itojun Hagino 			printf("%s: failed to add link-local address\n",
782686cdd19SJun-ichiro itojun Hagino 			    if_name(ifp));
783686cdd19SJun-ichiro itojun Hagino 
784686cdd19SJun-ichiro itojun Hagino 			/* we can't initialize multicasts without link-local */
785686cdd19SJun-ichiro itojun Hagino 			goto statinit;
786686cdd19SJun-ichiro itojun Hagino 		}
78782cd038dSYoshinobu Inoue 	}
78882cd038dSYoshinobu Inoue 
789686cdd19SJun-ichiro itojun Hagino 	if (ifp->if_flags & IFF_POINTOPOINT) {
79082cd038dSYoshinobu Inoue 		/*
79182cd038dSYoshinobu Inoue 		 * route local address to loopback
79282cd038dSYoshinobu Inoue 		 */
79382cd038dSYoshinobu Inoue 		bzero(&gate, sizeof(gate));
79482cd038dSYoshinobu Inoue 		gate.sin6_len = sizeof(struct sockaddr_in6);
79582cd038dSYoshinobu Inoue 		gate.sin6_family = AF_INET6;
79682cd038dSYoshinobu Inoue 		gate.sin6_addr = in6addr_loopback;
79782cd038dSYoshinobu Inoue 		bzero(&mask, sizeof(mask));
79882cd038dSYoshinobu Inoue 		mask.sin6_len = sizeof(struct sockaddr_in6);
79982cd038dSYoshinobu Inoue 		mask.sin6_family = AF_INET6;
80082cd038dSYoshinobu Inoue 		mask.sin6_addr = in6mask64;
80182cd038dSYoshinobu Inoue 		rtrequest(RTM_ADD,
80282cd038dSYoshinobu Inoue 			  (struct sockaddr *)&ia->ia_addr,
80382cd038dSYoshinobu Inoue 			  (struct sockaddr *)&gate,
80482cd038dSYoshinobu Inoue 			  (struct sockaddr *)&mask,
80582cd038dSYoshinobu Inoue 			  RTF_UP|RTF_HOST,
80682cd038dSYoshinobu Inoue 			  (struct rtentry **)0);
80782cd038dSYoshinobu Inoue 	}
80882cd038dSYoshinobu Inoue 
80982cd038dSYoshinobu Inoue 	/*
810686cdd19SJun-ichiro itojun Hagino 	 * assign loopback address for loopback interface
811686cdd19SJun-ichiro itojun Hagino 	 * XXX multiple loopback interface case
81282cd038dSYoshinobu Inoue 	 */
813686cdd19SJun-ichiro itojun Hagino 	in6 = in6addr_loopback;
814686cdd19SJun-ichiro itojun Hagino 	if (ifp->if_flags & IFF_LOOPBACK) {
815686cdd19SJun-ichiro itojun Hagino 		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
816686cdd19SJun-ichiro itojun Hagino 			if (in6_ifattach_loopback(ifp) != 0)
817686cdd19SJun-ichiro itojun Hagino 				return;
81882cd038dSYoshinobu Inoue 		}
819686cdd19SJun-ichiro itojun Hagino 	}
820686cdd19SJun-ichiro itojun Hagino 
821686cdd19SJun-ichiro itojun Hagino #ifdef DIAGNOSTIC
822686cdd19SJun-ichiro itojun Hagino 	if (!ia) {
823686cdd19SJun-ichiro itojun Hagino 		panic("ia == NULL in in6_ifattach");
824686cdd19SJun-ichiro itojun Hagino 		/*NOTREACHED*/
825686cdd19SJun-ichiro itojun Hagino 	}
826686cdd19SJun-ichiro itojun Hagino #endif
82782cd038dSYoshinobu Inoue 
82882cd038dSYoshinobu Inoue 	/*
82982cd038dSYoshinobu Inoue 	 * join multicast
83082cd038dSYoshinobu Inoue 	 */
83182cd038dSYoshinobu Inoue 	if (ifp->if_flags & IFF_MULTICAST) {
83282cd038dSYoshinobu Inoue 		int error;	/* not used */
833686cdd19SJun-ichiro itojun Hagino 		struct in6_multi *in6m;
83482cd038dSYoshinobu Inoue 
83582cd038dSYoshinobu Inoue 		bzero(&mltmask, sizeof(mltmask));
83682cd038dSYoshinobu Inoue 		mltmask.sin6_len = sizeof(struct sockaddr_in6);
83782cd038dSYoshinobu Inoue 		mltmask.sin6_family = AF_INET6;
83882cd038dSYoshinobu Inoue 		mltmask.sin6_addr = in6mask32;
83982cd038dSYoshinobu Inoue 
84082cd038dSYoshinobu Inoue 		/*
84182cd038dSYoshinobu Inoue 		 * join link-local all-nodes address
84282cd038dSYoshinobu Inoue 		 */
84382cd038dSYoshinobu Inoue 		bzero(&mltaddr, sizeof(mltaddr));
84482cd038dSYoshinobu Inoue 		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
84582cd038dSYoshinobu Inoue 		mltaddr.sin6_family = AF_INET6;
84682cd038dSYoshinobu Inoue 		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
84782cd038dSYoshinobu Inoue 		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
848686cdd19SJun-ichiro itojun Hagino 
849686cdd19SJun-ichiro itojun Hagino 		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
850686cdd19SJun-ichiro itojun Hagino 		if (in6m == NULL) {
85182cd038dSYoshinobu Inoue 			rtrequest(RTM_ADD,
85282cd038dSYoshinobu Inoue 				  (struct sockaddr *)&mltaddr,
85382cd038dSYoshinobu Inoue 				  (struct sockaddr *)&ia->ia_addr,
85482cd038dSYoshinobu Inoue 				  (struct sockaddr *)&mltmask,
85582cd038dSYoshinobu Inoue 				  RTF_UP|RTF_CLONING,  /* xxx */
85682cd038dSYoshinobu Inoue 				  (struct rtentry **)0);
85782cd038dSYoshinobu Inoue 			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
858686cdd19SJun-ichiro itojun Hagino 		}
85982cd038dSYoshinobu Inoue 
86082cd038dSYoshinobu Inoue 		/*
861686cdd19SJun-ichiro itojun Hagino 		 * join node information group address
862686cdd19SJun-ichiro itojun Hagino 		 */
863686cdd19SJun-ichiro itojun Hagino 		if (nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
864686cdd19SJun-ichiro itojun Hagino 		    == 0) {
865686cdd19SJun-ichiro itojun Hagino 			IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
866686cdd19SJun-ichiro itojun Hagino 			if (in6m == NULL && ia != NULL) {
867686cdd19SJun-ichiro itojun Hagino 				(void)in6_addmulti(&mltaddr.sin6_addr,
868686cdd19SJun-ichiro itojun Hagino 				    ifp, &error);
869686cdd19SJun-ichiro itojun Hagino 			}
870686cdd19SJun-ichiro itojun Hagino 		}
871686cdd19SJun-ichiro itojun Hagino 
872686cdd19SJun-ichiro itojun Hagino 		if (ifp->if_flags & IFF_LOOPBACK) {
873686cdd19SJun-ichiro itojun Hagino 			in6 = in6addr_loopback;
874686cdd19SJun-ichiro itojun Hagino 			ia = in6ifa_ifpwithaddr(ifp, &in6);
875686cdd19SJun-ichiro itojun Hagino 			/*
876686cdd19SJun-ichiro itojun Hagino 			 * join node-local all-nodes address, on loopback
87782cd038dSYoshinobu Inoue 			 */
87882cd038dSYoshinobu Inoue 			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
879686cdd19SJun-ichiro itojun Hagino 
880686cdd19SJun-ichiro itojun Hagino 			IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
881686cdd19SJun-ichiro itojun Hagino 			if (in6m == NULL && ia != NULL) {
88282cd038dSYoshinobu Inoue 				rtrequest(RTM_ADD,
88382cd038dSYoshinobu Inoue 					  (struct sockaddr *)&mltaddr,
884686cdd19SJun-ichiro itojun Hagino 					  (struct sockaddr *)&ia->ia_addr,
88582cd038dSYoshinobu Inoue 					  (struct sockaddr *)&mltmask,
88682cd038dSYoshinobu Inoue 					  RTF_UP,
88782cd038dSYoshinobu Inoue 					  (struct rtentry **)0);
88882cd038dSYoshinobu Inoue 				(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
88982cd038dSYoshinobu Inoue 			}
89082cd038dSYoshinobu Inoue 		}
891686cdd19SJun-ichiro itojun Hagino 	}
892686cdd19SJun-ichiro itojun Hagino 
893686cdd19SJun-ichiro itojun Hagino statinit:;
89482cd038dSYoshinobu Inoue 
89582cd038dSYoshinobu Inoue 	/* update dynamically. */
89682cd038dSYoshinobu Inoue 	if (in6_maxmtu < ifp->if_mtu)
89782cd038dSYoshinobu Inoue 		in6_maxmtu = ifp->if_mtu;
89882cd038dSYoshinobu Inoue 
89982cd038dSYoshinobu Inoue 	if (in6_ifstat[ifp->if_index] == NULL) {
90082cd038dSYoshinobu Inoue 		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
90182cd038dSYoshinobu Inoue 			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
90282cd038dSYoshinobu Inoue 		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
90382cd038dSYoshinobu Inoue 	}
90482cd038dSYoshinobu Inoue 	if (icmp6_ifstat[ifp->if_index] == NULL) {
90582cd038dSYoshinobu Inoue 		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
90682cd038dSYoshinobu Inoue 			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
90782cd038dSYoshinobu Inoue 		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
90882cd038dSYoshinobu Inoue 	}
90982cd038dSYoshinobu Inoue 
91082cd038dSYoshinobu Inoue 	/* initialize NDP variables */
91182cd038dSYoshinobu Inoue 	nd6_ifattach(ifp);
91282cd038dSYoshinobu Inoue }
91382cd038dSYoshinobu Inoue 
914686cdd19SJun-ichiro itojun Hagino /*
915686cdd19SJun-ichiro itojun Hagino  * NOTE: in6_ifdetach() does not support loopback if at this moment.
916686cdd19SJun-ichiro itojun Hagino  */
91782cd038dSYoshinobu Inoue void
91882cd038dSYoshinobu Inoue in6_ifdetach(ifp)
91982cd038dSYoshinobu Inoue 	struct ifnet *ifp;
92082cd038dSYoshinobu Inoue {
92182cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia, *oia;
922686cdd19SJun-ichiro itojun Hagino 	struct ifaddr *ifa, *next;
92382cd038dSYoshinobu Inoue 	struct rtentry *rt;
92482cd038dSYoshinobu Inoue 	short rtflags;
925686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_in6 sin6;
926686cdd19SJun-ichiro itojun Hagino 	struct in6_multi *in6m;
927686cdd19SJun-ichiro itojun Hagino 	struct in6_multi *in6m_next;
92882cd038dSYoshinobu Inoue 
929686cdd19SJun-ichiro itojun Hagino 	/* nuke prefix list.  this may try to remove some of ifaddrs as well */
930686cdd19SJun-ichiro itojun Hagino 	in6_purgeprefix(ifp);
931686cdd19SJun-ichiro itojun Hagino 
932686cdd19SJun-ichiro itojun Hagino 	/* remove neighbor management table */
933686cdd19SJun-ichiro itojun Hagino 	nd6_purge(ifp);
934686cdd19SJun-ichiro itojun Hagino 
935686cdd19SJun-ichiro itojun Hagino 	/* nuke any of IPv6 addresses we have */
936686cdd19SJun-ichiro itojun Hagino 	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
93782cd038dSYoshinobu Inoue 	{
938686cdd19SJun-ichiro itojun Hagino 		next = ifa->ifa_list.tqe_next;
939686cdd19SJun-ichiro itojun Hagino 		if (ifa->ifa_addr->sa_family != AF_INET6)
940686cdd19SJun-ichiro itojun Hagino 			continue;
941686cdd19SJun-ichiro itojun Hagino 		in6_purgeaddr(ifa, ifp);
942686cdd19SJun-ichiro itojun Hagino 	}
943686cdd19SJun-ichiro itojun Hagino 
944686cdd19SJun-ichiro itojun Hagino 	/* undo everything done by in6_ifattach(), just in case */
945686cdd19SJun-ichiro itojun Hagino 	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
946686cdd19SJun-ichiro itojun Hagino 	{
947686cdd19SJun-ichiro itojun Hagino 		next = ifa->ifa_list.tqe_next;
948686cdd19SJun-ichiro itojun Hagino 
949686cdd19SJun-ichiro itojun Hagino 
95082cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6
95182cd038dSYoshinobu Inoue 		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
95282cd038dSYoshinobu Inoue 			continue;
95382cd038dSYoshinobu Inoue 		}
95482cd038dSYoshinobu Inoue 
95582cd038dSYoshinobu Inoue 		ia = (struct in6_ifaddr *)ifa;
95682cd038dSYoshinobu Inoue 
95782cd038dSYoshinobu Inoue 		/* remove from the routing table */
95882cd038dSYoshinobu Inoue 		if ((ia->ia_flags & IFA_ROUTE)
95982cd038dSYoshinobu Inoue 		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
96082cd038dSYoshinobu Inoue 			rtflags = rt->rt_flags;
96182cd038dSYoshinobu Inoue 			rtfree(rt);
96282cd038dSYoshinobu Inoue 			rtrequest(RTM_DELETE,
96382cd038dSYoshinobu Inoue 				(struct sockaddr *)&ia->ia_addr,
96482cd038dSYoshinobu Inoue 				(struct sockaddr *)&ia->ia_addr,
96582cd038dSYoshinobu Inoue 				(struct sockaddr *)&ia->ia_prefixmask,
96682cd038dSYoshinobu Inoue 				rtflags, (struct rtentry **)0);
96782cd038dSYoshinobu Inoue 		}
96882cd038dSYoshinobu Inoue 
96982cd038dSYoshinobu Inoue 		/* remove from the linked list */
97082cd038dSYoshinobu Inoue 		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
971686cdd19SJun-ichiro itojun Hagino 		IFAFREE(&ia->ia_ifa);
97282cd038dSYoshinobu Inoue 
97382cd038dSYoshinobu Inoue 		/* also remove from the IPv6 address chain(itojun&jinmei) */
97482cd038dSYoshinobu Inoue 		oia = ia;
97582cd038dSYoshinobu Inoue 		if (oia == (ia = in6_ifaddr))
97682cd038dSYoshinobu Inoue 			in6_ifaddr = ia->ia_next;
97782cd038dSYoshinobu Inoue 		else {
97882cd038dSYoshinobu Inoue 			while (ia->ia_next && (ia->ia_next != oia))
97982cd038dSYoshinobu Inoue 				ia = ia->ia_next;
98082cd038dSYoshinobu Inoue 			if (ia->ia_next)
98182cd038dSYoshinobu Inoue 				ia->ia_next = oia->ia_next;
982686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG
98382cd038dSYoshinobu Inoue 			else
98482cd038dSYoshinobu Inoue 				printf("%s: didn't unlink in6ifaddr from "
98582cd038dSYoshinobu Inoue 				    "list\n", if_name(ifp));
98682cd038dSYoshinobu Inoue #endif
98782cd038dSYoshinobu Inoue 		}
98882cd038dSYoshinobu Inoue 
989686cdd19SJun-ichiro itojun Hagino 		IFAFREE(&oia->ia_ifa);
990686cdd19SJun-ichiro itojun Hagino 	}
991686cdd19SJun-ichiro itojun Hagino 
992686cdd19SJun-ichiro itojun Hagino 	/* leave from all multicast groups joined */
993686cdd19SJun-ichiro itojun Hagino 	for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
994686cdd19SJun-ichiro itojun Hagino 		in6m_next = LIST_NEXT(in6m, in6m_entry);
995686cdd19SJun-ichiro itojun Hagino 		if (in6m->in6m_ifp != ifp)
996686cdd19SJun-ichiro itojun Hagino 			continue;
997686cdd19SJun-ichiro itojun Hagino 		in6_delmulti(in6m);
998686cdd19SJun-ichiro itojun Hagino 		in6m = NULL;
999686cdd19SJun-ichiro itojun Hagino 	}
1000686cdd19SJun-ichiro itojun Hagino 
1001686cdd19SJun-ichiro itojun Hagino 	/* remove neighbor management table */
1002686cdd19SJun-ichiro itojun Hagino 	nd6_purge(ifp);
1003686cdd19SJun-ichiro itojun Hagino 
1004686cdd19SJun-ichiro itojun Hagino 	/* remove route to link-local allnodes multicast (ff02::1) */
1005686cdd19SJun-ichiro itojun Hagino 	bzero(&sin6, sizeof(sin6));
1006686cdd19SJun-ichiro itojun Hagino 	sin6.sin6_len = sizeof(struct sockaddr_in6);
1007686cdd19SJun-ichiro itojun Hagino 	sin6.sin6_family = AF_INET6;
1008686cdd19SJun-ichiro itojun Hagino 	sin6.sin6_addr = in6addr_linklocal_allnodes;
1009686cdd19SJun-ichiro itojun Hagino 	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1010e699b0aeSHajimu UMEMOTO 	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
1011e699b0aeSHajimu UMEMOTO 	if (rt && rt->rt_ifp == ifp) {
1012686cdd19SJun-ichiro itojun Hagino 		rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1013686cdd19SJun-ichiro itojun Hagino 			rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1014686cdd19SJun-ichiro itojun Hagino 		rtfree(rt);
101582cd038dSYoshinobu Inoue 	}
101682cd038dSYoshinobu Inoue }
1017