in6_ifattach.c revision 62587
1/*	$FreeBSD: head/sys/netinet6/in6_ifattach.c 62587 2000-07-04 16:35:15Z itojun $	*/
2/*	$KAME: in6_ifattach.c,v 1.61 2000/06/13 08:15:27 itojun Exp $	*/
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/socket.h>
37#include <sys/sockio.h>
38#include <sys/kernel.h>
39#include <sys/md5.h>
40
41#include <net/if.h>
42#include <net/if_dl.h>
43#include <net/if_types.h>
44#include <net/route.h>
45
46#include <netinet/in.h>
47#include <netinet/in_var.h>
48#include <netinet/if_ether.h>
49
50#include <netinet/ip6.h>
51#include <netinet6/ip6_var.h>
52#include <netinet6/in6_ifattach.h>
53#include <netinet6/ip6_var.h>
54#include <netinet6/nd6.h>
55#include <netinet6/scope6_var.h>
56
57#include <net/net_osdep.h>
58
59struct in6_ifstat **in6_ifstat = NULL;
60struct icmp6_ifstat **icmp6_ifstat = NULL;
61size_t in6_ifstatmax = 0;
62size_t icmp6_ifstatmax = 0;
63unsigned long in6_maxmtu = 0;
64
65static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
66static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
67static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
68static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
69static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
70static int in6_ifattach_loopback __P((struct ifnet *));
71static int nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
72
73#define EUI64_GBIT	0x01
74#define EUI64_UBIT	0x02
75#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
76#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
77#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
78#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
79#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
80
81#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
82#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
83
84/*
85 * Generate a last-resort interface identifier, when the machine has no
86 * IEEE802/EUI64 address sources.
87 * The goal here is to get an interface identifier that is
88 * (1) random enough and (2) does not change across reboot.
89 * We currently use MD5(hostname) for it.
90 */
91static int
92get_rand_ifid(ifp, in6)
93	struct ifnet *ifp;
94	struct in6_addr *in6;	/*upper 64bits are preserved */
95{
96	MD5_CTX ctxt;
97	u_int8_t digest[16];
98	int hostnamelen	= strlen(hostname);
99
100#if 0
101	/* we need at least several letters as seed for ifid */
102	if (hostnamelen < 3)
103		return -1;
104#endif
105
106	/* generate 8 bytes of pseudo-random value. */
107	bzero(&ctxt, sizeof(ctxt));
108	MD5Init(&ctxt);
109	MD5Update(&ctxt, hostname, hostnamelen);
110	MD5Final(digest, &ctxt);
111
112	/* assumes sizeof(digest) > sizeof(ifid) */
113	bcopy(digest, &in6->s6_addr[8], 8);
114
115	/* make sure to set "u" bit to local, and "g" bit to individual. */
116	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
117	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
118
119	/* convert EUI64 into IPv6 interface identifier */
120	EUI64_TO_IFID(in6);
121
122	return 0;
123}
124
125/*
126 * Get interface identifier for the specified interface.
127 * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
128 */
129static int
130get_hw_ifid(ifp, in6)
131	struct ifnet *ifp;
132	struct in6_addr *in6;	/*upper 64bits are preserved */
133{
134	struct ifaddr *ifa;
135	struct sockaddr_dl *sdl;
136	u_int8_t *addr;
137	size_t addrlen;
138	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
139	static u_int8_t allone[8] =
140		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
141
142	for (ifa = ifp->if_addrlist.tqh_first;
143	     ifa;
144	     ifa = ifa->ifa_list.tqe_next)
145	{
146		if (ifa->ifa_addr->sa_family != AF_LINK)
147			continue;
148		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
149		if (sdl == NULL)
150			continue;
151		if (sdl->sdl_alen == 0)
152			continue;
153
154		goto found;
155	}
156
157	return -1;
158
159found:
160	addr = LLADDR(sdl);
161	addrlen = sdl->sdl_alen;
162
163	/* get EUI64 */
164	switch (ifp->if_type) {
165	case IFT_ETHER:
166	case IFT_FDDI:
167	case IFT_ATM:
168		/* IEEE802/EUI64 cases - what others? */
169
170		/* look at IEEE802/EUI64 only */
171		if (addrlen != 8 && addrlen != 6)
172			return -1;
173
174		/*
175		 * check for invalid MAC address - on bsdi, we see it a lot
176		 * since wildboar configures all-zero MAC on pccard before
177		 * card insertion.
178		 */
179		if (bcmp(addr, allzero, addrlen) == 0)
180			return -1;
181		if (bcmp(addr, allone, addrlen) == 0)
182			return -1;
183
184		/* make EUI64 address */
185		if (addrlen == 8)
186			bcopy(addr, &in6->s6_addr[8], 8);
187		else if (addrlen == 6) {
188			in6->s6_addr[8] = addr[0];
189			in6->s6_addr[9] = addr[1];
190			in6->s6_addr[10] = addr[2];
191			in6->s6_addr[11] = 0xff;
192			in6->s6_addr[12] = 0xfe;
193			in6->s6_addr[13] = addr[3];
194			in6->s6_addr[14] = addr[4];
195			in6->s6_addr[15] = addr[5];
196		}
197		break;
198
199	case IFT_ARCNET:
200		if (addrlen != 1)
201			return -1;
202		if (!addr[0])
203			return -1;
204
205		bzero(&in6->s6_addr[8], 8);
206		in6->s6_addr[15] = addr[0];
207
208		/*
209		 * due to insufficient bitwidth, we mark it local.
210		 */
211		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
212		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
213		break;
214
215	case IFT_GIF:
216#ifdef IFT_STF
217	case IFT_STF:
218#endif
219		/*
220		 * mech-06 says: "SHOULD use IPv4 address as ifid source".
221		 * however, IPv4 address is not very suitable as unique
222		 * identifier source (can be renumbered).
223		 * we don't do this.
224		 */
225		return -1;
226
227	default:
228		return -1;
229	}
230
231	/* sanity check: g bit must not indicate "group" */
232	if (EUI64_GROUP(in6))
233		return -1;
234
235	/* convert EUI64 into IPv6 interface identifier */
236	EUI64_TO_IFID(in6);
237
238	/*
239	 * sanity check: ifid must not be all zero, avoid conflict with
240	 * subnet router anycast
241	 */
242	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
243	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
244		return -1;
245	}
246
247	return 0;
248}
249
250/*
251 * Get interface identifier for the specified interface.  If it is not
252 * available on ifp0, borrow interface identifier from other information
253 * sources.
254 */
255static int
256get_ifid(ifp0, altifp, in6)
257	struct ifnet *ifp0;
258	struct ifnet *altifp;	/*secondary EUI64 source*/
259	struct in6_addr *in6;
260{
261	struct ifnet *ifp;
262
263	/* first, try to get it from the interface itself */
264	if (get_hw_ifid(ifp0, in6) == 0) {
265#ifdef ND6_DEBUG
266		printf("%s: got interface identifier from itself\n",
267		    if_name(ifp0));
268#endif
269		goto success;
270	}
271
272	/* try secondary EUI64 source. this basically is for ATM PVC */
273	if (altifp && get_hw_ifid(altifp, in6) == 0) {
274#ifdef ND6_DEBUG
275		printf("%s: got interface identifier from %s\n",
276		    if_name(ifp0), if_name(altifp));
277#endif
278		goto success;
279	}
280
281	/* next, try to get it from some other hardware interface */
282	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
283	{
284		if (ifp == ifp0)
285			continue;
286		if (get_hw_ifid(ifp, in6) != 0)
287			continue;
288
289		/*
290		 * to borrow ifid from other interface, ifid needs to be
291		 * globally unique
292		 */
293		if (IFID_UNIVERSAL(in6)) {
294
295#ifdef ND6_DEBUG
296			printf("%s: borrow interface identifier from %s\n",
297			    if_name(ifp0), if_name(ifp));
298#endif
299			goto success;
300		}
301	}
302
303	/* last resort: get from random number source */
304	if (get_rand_ifid(ifp, in6) == 0) {
305#ifdef ND6_DEBUG
306		printf("%s: interface identifier generated by random number\n",
307		    if_name(ifp0));
308#endif
309		goto success;
310	}
311
312	printf("%s: failed to get interface identifier", if_name(ifp0));
313	return -1;
314
315success:
316#ifdef ND6_DEBUG
317	printf("%s: ifid: "
318		"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
319		if_name(ifp0),
320		in6->s6_addr[8], in6->s6_addr[9],
321		in6->s6_addr[10], in6->s6_addr[11],
322		in6->s6_addr[12], in6->s6_addr[13],
323		in6->s6_addr[14], in6->s6_addr[15]);
324#endif
325	return 0;
326}
327
328/*
329 * configure IPv6 interface address.  XXX code duplicated with in.c
330 */
331static int
332in6_ifattach_addaddr(ifp, ia)
333	struct ifnet *ifp;
334	struct in6_ifaddr *ia;
335{
336	struct in6_ifaddr *oia;
337	struct ifaddr *ifa;
338	int error;
339	int rtflag;
340	struct in6_addr llsol;
341
342	/*
343	 * initialize if_addrlist, if we are the very first one
344	 */
345	ifa = TAILQ_FIRST(&ifp->if_addrlist);
346	if (ifa == NULL) {
347		TAILQ_INIT(&ifp->if_addrlist);
348	}
349
350	/*
351	 * link the interface address to global list
352	 */
353	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
354	/* gain a refcnt for the link from if_addrlist */
355	ia->ia_ifa.ifa_refcnt++;
356
357	/*
358	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
359	 * kazu opposed it, but itojun & jinmei wanted.
360	 */
361	if ((oia = in6_ifaddr) != NULL) {
362		for (; oia->ia_next; oia = oia->ia_next)
363			continue;
364		oia->ia_next = ia;
365	} else
366		in6_ifaddr = ia;
367	/* gain another refcnt for the link from in6_ifaddr */
368	ia->ia_ifa.ifa_refcnt++;
369
370	/*
371	 * give the interface a chance to initialize, in case this
372	 * is the first address to be added.
373	 */
374	if (ifp->if_ioctl != NULL) {
375		int s;
376		s = splimp();
377		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
378		splx(s);
379	} else
380		error = 0;
381	if (error) {
382		switch (error) {
383		case EAFNOSUPPORT:
384			printf("%s: IPv6 not supported\n", if_name(ifp));
385			break;
386		default:
387			printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
388			    error);
389			break;
390		}
391
392		/* undo changes */
393		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
394		IFAFREE(&ia->ia_ifa);
395		if (oia)
396			oia->ia_next = ia->ia_next;
397		else
398			in6_ifaddr = ia->ia_next;
399		IFAFREE(&ia->ia_ifa);
400		return -1;
401	}
402
403	/* configure link-layer address resolution */
404	rtflag = 0;
405	if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
406		rtflag = RTF_HOST;
407	else {
408		switch (ifp->if_type) {
409		case IFT_LOOP:
410#ifdef IFT_STF
411		case IFT_STF:
412#endif
413			rtflag = 0;
414			break;
415		default:
416			ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
417			ia->ia_ifa.ifa_flags |= RTF_CLONING;
418			rtflag = RTF_CLONING;
419			break;
420		}
421	}
422
423	/* add route to the interface. */
424	{
425		int e;
426
427		e = rtrequest(RTM_ADD,
428			      (struct sockaddr *)&ia->ia_addr,
429			      (struct sockaddr *)&ia->ia_addr,
430			      (struct sockaddr *)&ia->ia_prefixmask,
431			      RTF_UP | rtflag,
432			      (struct rtentry **)0);
433		if (e) {
434			printf("in6_ifattach_addaddr: rtrequest failed. errno = %d\n", e);
435		}
436	}
437	ia->ia_flags |= IFA_ROUTE;
438
439	if ((rtflag & RTF_CLONING) != 0 &&
440	    (ifp->if_flags & IFF_MULTICAST) != 0) {
441		/*
442		 * join solicited multicast address
443		 */
444		bzero(&llsol, sizeof(llsol));
445		llsol.s6_addr16[0] = htons(0xff02);
446		llsol.s6_addr16[1] = htons(ifp->if_index);
447		llsol.s6_addr32[1] = 0;
448		llsol.s6_addr32[2] = htonl(1);
449		llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
450		llsol.s6_addr8[12] = 0xff;
451		(void)in6_addmulti(&llsol, ifp, &error);
452
453		/* XXX should we run DAD on other interface types? */
454		switch (ifp->if_type) {
455#if 1
456		case IFT_ARCNET:
457		case IFT_ETHER:
458		case IFT_FDDI:
459#else
460		default:
461#endif
462			/* mark the address TENTATIVE, if needed. */
463			ia->ia6_flags |= IN6_IFF_TENTATIVE;
464			/* nd6_dad_start() will be called in in6_if_up */
465		}
466	}
467
468	return 0;
469}
470
471static int
472in6_ifattach_linklocal(ifp, altifp)
473	struct ifnet *ifp;
474	struct ifnet *altifp;	/*secondary EUI64 source*/
475{
476	struct in6_ifaddr *ia;
477
478	/*
479	 * configure link-local address
480	 */
481	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
482	bzero((caddr_t)ia, sizeof(*ia));
483	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
484	if (ifp->if_flags & IFF_POINTOPOINT)
485		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
486	else
487		ia->ia_ifa.ifa_dstaddr = NULL;
488	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
489	ia->ia_ifp = ifp;
490
491	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
492	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
493	ia->ia_prefixmask.sin6_family = AF_INET6;
494#ifdef SCOPEDROUTING
495	/* take into accound the sin6_scope_id field for routing */
496	ia->ia_prefixmask.sin6_scope_id = 0xffffffff;
497#endif
498	ia->ia_prefixmask.sin6_addr = in6mask64;
499
500	/* just in case */
501	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
502	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
503	ia->ia_dstaddr.sin6_family = AF_INET6;
504
505	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
506	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
507	ia->ia_addr.sin6_family = AF_INET6;
508	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
509	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
510	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
511	if (ifp->if_flags & IFF_LOOPBACK) {
512		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
513		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
514	} else {
515		if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
516#ifdef ND6_DEBUG
517			printf("%s: no ifid available\n", if_name(ifp));
518#endif
519			free(ia, M_IFADDR);
520			return -1;
521		}
522	}
523#ifdef SCOPEDROUTING
524	ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp,
525						     &ia->ia_addr.sin6_addr);
526#endif
527
528	ia->ia_ifa.ifa_metric = ifp->if_metric;
529
530	if (in6_ifattach_addaddr(ifp, ia) != 0) {
531		/* ia will be freed on failure */
532		return -1;
533	}
534
535	return 0;
536}
537
538static int
539in6_ifattach_loopback(ifp)
540	struct ifnet *ifp;	/* must be IFT_LOOP */
541{
542	struct in6_ifaddr *ia;
543
544	/*
545	 * configure link-local address
546	 */
547	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
548	bzero((caddr_t)ia, sizeof(*ia));
549	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
550	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
551	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
552	ia->ia_ifp = ifp;
553
554	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
555	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
556	ia->ia_prefixmask.sin6_family = AF_INET6;
557	ia->ia_prefixmask.sin6_addr = in6mask128;
558
559	/*
560	 * Always initialize ia_dstaddr (= broadcast address) to loopback
561	 * address, to make getifaddr happier.
562	 *
563	 * For BSDI, it is mandatory.  The BSDI version of
564	 * ifa_ifwithroute() rejects to add a route to the loopback
565	 * interface.  Even for other systems, loopback looks somewhat
566	 * special.
567	 */
568	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
569	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
570	ia->ia_dstaddr.sin6_family = AF_INET6;
571	ia->ia_dstaddr.sin6_addr = in6addr_loopback;
572
573	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
574	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
575	ia->ia_addr.sin6_family = AF_INET6;
576	ia->ia_addr.sin6_addr = in6addr_loopback;
577
578	ia->ia_ifa.ifa_metric = ifp->if_metric;
579
580	if (in6_ifattach_addaddr(ifp, ia) != 0) {
581		/* ia will be freed on failure */
582		return -1;
583	}
584
585	return 0;
586}
587
588/*
589 * compute NI group address, based on the current hostname setting.
590 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
591 *
592 * when ifp == NULL, the caller is responsible for filling scopeid.
593 */
594static int
595nigroup(ifp, name, namelen, in6)
596	struct ifnet *ifp;
597	const char *name;
598	int namelen;
599	struct in6_addr *in6;
600{
601	const char *p;
602	MD5_CTX ctxt;
603	u_int8_t digest[16];
604	char l;
605
606	if (!namelen || !name)
607		return -1;
608
609	p = name;
610	while (p && *p && *p != '.' && p - name < namelen)
611		p++;
612	if (p - name > 63)
613		return -1;	/*label too long*/
614	l = p - name;
615
616	/* generate 8 bytes of pseudo-random value. */
617	bzero(&ctxt, sizeof(ctxt));
618	MD5Init(&ctxt);
619	MD5Update(&ctxt, &l, sizeof(l));
620	/* LINTED const cast */
621	MD5Update(&ctxt, (void *)name, p - name);
622	MD5Final(digest, &ctxt);
623
624	bzero(in6, sizeof(*in6));
625	in6->s6_addr16[0] = htons(0xff02);
626	if (ifp)
627		in6->s6_addr16[1] = htons(ifp->if_index);
628	in6->s6_addr8[11] = 2;
629	bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
630
631	return 0;
632}
633
634void
635in6_nigroup_attach(name, namelen)
636	const char *name;
637	int namelen;
638{
639	struct ifnet *ifp;
640	struct sockaddr_in6 mltaddr;
641	struct in6_multi *in6m;
642	int error;
643
644	bzero(&mltaddr, sizeof(mltaddr));
645	mltaddr.sin6_family = AF_INET6;
646	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
647	if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
648		return;
649
650	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
651	{
652		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
653		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
654		if (!in6m)
655			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
656	}
657}
658
659void
660in6_nigroup_detach(name, namelen)
661	const char *name;
662	int namelen;
663{
664	struct ifnet *ifp;
665	struct sockaddr_in6 mltaddr;
666	struct in6_multi *in6m;
667
668	bzero(&mltaddr, sizeof(mltaddr));
669	mltaddr.sin6_family = AF_INET6;
670	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
671	if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
672		return;
673
674	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
675	{
676		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
677		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
678		if (in6m)
679			in6_delmulti(in6m);
680	}
681}
682
683/*
684 * XXX multiple loopback interface needs more care.  for instance,
685 * nodelocal address needs to be configured onto only one of them.
686 * XXX multiple link-local address case
687 */
688void
689in6_ifattach(ifp, altifp)
690	struct ifnet *ifp;
691	struct ifnet *altifp;	/* secondary EUI64 source */
692{
693	static size_t if_indexlim = 8;
694	struct sockaddr_in6 mltaddr;
695	struct sockaddr_in6 mltmask;
696	struct sockaddr_in6 gate;
697	struct sockaddr_in6 mask;
698	struct in6_ifaddr *ia;
699	struct in6_addr in6;
700	int hostnamelen	= strlen(hostname);
701
702	/*
703	 * We have some arrays that should be indexed by if_index.
704	 * since if_index will grow dynamically, they should grow too.
705	 *	struct in6_ifstat **in6_ifstat
706	 *	struct icmp6_ifstat **icmp6_ifstat
707	 */
708	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
709	    if_index >= if_indexlim) {
710		size_t n;
711		caddr_t q;
712		size_t olim;
713
714		olim = if_indexlim;
715		while (if_index >= if_indexlim)
716			if_indexlim <<= 1;
717
718		/* grow in6_ifstat */
719		n = if_indexlim * sizeof(struct in6_ifstat *);
720		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
721		bzero(q, n);
722		if (in6_ifstat) {
723			bcopy((caddr_t)in6_ifstat, q,
724				olim * sizeof(struct in6_ifstat *));
725			free((caddr_t)in6_ifstat, M_IFADDR);
726		}
727		in6_ifstat = (struct in6_ifstat **)q;
728		in6_ifstatmax = if_indexlim;
729
730		/* grow icmp6_ifstat */
731		n = if_indexlim * sizeof(struct icmp6_ifstat *);
732		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
733		bzero(q, n);
734		if (icmp6_ifstat) {
735			bcopy((caddr_t)icmp6_ifstat, q,
736				olim * sizeof(struct icmp6_ifstat *));
737			free((caddr_t)icmp6_ifstat, M_IFADDR);
738		}
739		icmp6_ifstat = (struct icmp6_ifstat **)q;
740		icmp6_ifstatmax = if_indexlim;
741	}
742
743	/* initialize scope identifiers */
744	scope6_ifattach(ifp);
745
746	/*
747	 * quirks based on interface type
748	 */
749	switch (ifp->if_type) {
750#ifdef IFT_STF
751	case IFT_STF:
752		/*
753		 * 6to4 interface is a very speical kind of beast.
754		 * no multicast, no linklocal (based on 03 draft).
755		 */
756		goto statinit;
757#endif
758	default:
759		break;
760	}
761
762	/*
763	 * usually, we require multicast capability to the interface
764	 */
765	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
766		printf("%s: not multicast capable, IPv6 not enabled\n",
767		    if_name(ifp));
768		return;
769	}
770
771	/*
772	 * assign link-local address, if there's none
773	 */
774	ia = in6ifa_ifpforlinklocal(ifp, 0);
775	if (ia == NULL) {
776		if (in6_ifattach_linklocal(ifp, altifp) != 0)
777			return;
778		ia = in6ifa_ifpforlinklocal(ifp, 0);
779
780		if (ia == NULL) {
781			printf("%s: failed to add link-local address",
782			    if_name(ifp));
783
784			/* we can't initialize multicasts without link-local */
785			goto statinit;
786		}
787	}
788
789	if (ifp->if_flags & IFF_POINTOPOINT) {
790		/*
791		 * route local address to loopback
792		 */
793		bzero(&gate, sizeof(gate));
794		gate.sin6_len = sizeof(struct sockaddr_in6);
795		gate.sin6_family = AF_INET6;
796		gate.sin6_addr = in6addr_loopback;
797		bzero(&mask, sizeof(mask));
798		mask.sin6_len = sizeof(struct sockaddr_in6);
799		mask.sin6_family = AF_INET6;
800		mask.sin6_addr = in6mask64;
801		rtrequest(RTM_ADD,
802			  (struct sockaddr *)&ia->ia_addr,
803			  (struct sockaddr *)&gate,
804			  (struct sockaddr *)&mask,
805			  RTF_UP|RTF_HOST,
806			  (struct rtentry **)0);
807	}
808
809	/*
810	 * assign loopback address for loopback interface
811	 * XXX multiple loopback interface case
812	 */
813	in6 = in6addr_loopback;
814	if (ifp->if_flags & IFF_LOOPBACK) {
815		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
816			if (in6_ifattach_loopback(ifp) != 0)
817				return;
818		}
819	}
820
821#ifdef DIAGNOSTIC
822	if (!ia) {
823		panic("ia == NULL in in6_ifattach");
824		/*NOTREACHED*/
825	}
826#endif
827
828	/*
829	 * join multicast
830	 */
831	if (ifp->if_flags & IFF_MULTICAST) {
832		int error;	/* not used */
833		struct in6_multi *in6m;
834
835		bzero(&mltmask, sizeof(mltmask));
836		mltmask.sin6_len = sizeof(struct sockaddr_in6);
837		mltmask.sin6_family = AF_INET6;
838		mltmask.sin6_addr = in6mask32;
839
840		/*
841		 * join link-local all-nodes address
842		 */
843		bzero(&mltaddr, sizeof(mltaddr));
844		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
845		mltaddr.sin6_family = AF_INET6;
846		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
847		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
848
849		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
850		if (in6m == NULL) {
851			rtrequest(RTM_ADD,
852				  (struct sockaddr *)&mltaddr,
853				  (struct sockaddr *)&ia->ia_addr,
854				  (struct sockaddr *)&mltmask,
855				  RTF_UP|RTF_CLONING,  /* xxx */
856				  (struct rtentry **)0);
857			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
858		}
859
860		/*
861		 * join node information group address
862		 */
863		if (nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
864		    == 0) {
865			IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
866			if (in6m == NULL && ia != NULL) {
867				(void)in6_addmulti(&mltaddr.sin6_addr,
868				    ifp, &error);
869			}
870		}
871
872		if (ifp->if_flags & IFF_LOOPBACK) {
873			in6 = in6addr_loopback;
874			ia = in6ifa_ifpwithaddr(ifp, &in6);
875			/*
876			 * join node-local all-nodes address, on loopback
877			 */
878			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
879
880			IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
881			if (in6m == NULL && ia != NULL) {
882				rtrequest(RTM_ADD,
883					  (struct sockaddr *)&mltaddr,
884					  (struct sockaddr *)&ia->ia_addr,
885					  (struct sockaddr *)&mltmask,
886					  RTF_UP,
887					  (struct rtentry **)0);
888				(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
889			}
890		}
891	}
892
893statinit:;
894
895	/* update dynamically. */
896	if (in6_maxmtu < ifp->if_mtu)
897		in6_maxmtu = ifp->if_mtu;
898
899	if (in6_ifstat[ifp->if_index] == NULL) {
900		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
901			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
902		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
903	}
904	if (icmp6_ifstat[ifp->if_index] == NULL) {
905		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
906			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
907		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
908	}
909
910	/* initialize NDP variables */
911	nd6_ifattach(ifp);
912}
913
914/*
915 * NOTE: in6_ifdetach() does not support loopback if at this moment.
916 */
917void
918in6_ifdetach(ifp)
919	struct ifnet *ifp;
920{
921	struct in6_ifaddr *ia, *oia;
922	struct ifaddr *ifa, *next;
923	struct rtentry *rt;
924	short rtflags;
925	struct sockaddr_in6 sin6;
926	struct in6_multi *in6m;
927	struct in6_multi *in6m_next;
928
929	/* nuke prefix list.  this may try to remove some of ifaddrs as well */
930	in6_purgeprefix(ifp);
931
932	/* remove neighbor management table */
933	nd6_purge(ifp);
934
935	/* nuke any of IPv6 addresses we have */
936	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
937	{
938		next = ifa->ifa_list.tqe_next;
939		if (ifa->ifa_addr->sa_family != AF_INET6)
940			continue;
941		in6_purgeaddr(ifa, ifp);
942	}
943
944	/* undo everything done by in6_ifattach(), just in case */
945	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
946	{
947		next = ifa->ifa_list.tqe_next;
948
949
950		if (ifa->ifa_addr->sa_family != AF_INET6
951		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
952			continue;
953		}
954
955		ia = (struct in6_ifaddr *)ifa;
956
957		/* remove from the routing table */
958		if ((ia->ia_flags & IFA_ROUTE)
959		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
960			rtflags = rt->rt_flags;
961			rtfree(rt);
962			rtrequest(RTM_DELETE,
963				(struct sockaddr *)&ia->ia_addr,
964				(struct sockaddr *)&ia->ia_addr,
965				(struct sockaddr *)&ia->ia_prefixmask,
966				rtflags, (struct rtentry **)0);
967		}
968
969		/* remove from the linked list */
970		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
971		IFAFREE(&ia->ia_ifa);
972
973		/* also remove from the IPv6 address chain(itojun&jinmei) */
974		oia = ia;
975		if (oia == (ia = in6_ifaddr))
976			in6_ifaddr = ia->ia_next;
977		else {
978			while (ia->ia_next && (ia->ia_next != oia))
979				ia = ia->ia_next;
980			if (ia->ia_next)
981				ia->ia_next = oia->ia_next;
982#ifdef ND6_DEBUG
983			else
984				printf("%s: didn't unlink in6ifaddr from "
985				    "list\n", if_name(ifp));
986#endif
987		}
988
989		IFAFREE(&oia->ia_ifa);
990	}
991
992	/* leave from all multicast groups joined */
993	for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
994		in6m_next = LIST_NEXT(in6m, in6m_entry);
995		if (in6m->in6m_ifp != ifp)
996			continue;
997		in6_delmulti(in6m);
998		in6m = NULL;
999	}
1000
1001	/* remove neighbor management table */
1002	nd6_purge(ifp);
1003
1004	/* remove route to link-local allnodes multicast (ff02::1) */
1005	bzero(&sin6, sizeof(sin6));
1006	sin6.sin6_len = sizeof(struct sockaddr_in6);
1007	sin6.sin6_family = AF_INET6;
1008	sin6.sin6_addr = in6addr_linklocal_allnodes;
1009	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1010	if ((rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL)) != NULL)
1011	{
1012		rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1013			rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1014		rtfree(rt);
1015	}
1016}
1017