in6_ifattach.c revision 1.16
1/*	$OpenBSD: in6_ifattach.c,v 1.16 2001/02/16 15:59:38 itojun Exp $	*/
2/*	$KAME: in6_ifattach.c,v 1.112 2001/02/10 15:44:59 jinmei 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/syslog.h>
40#include <sys/md5k.h>
41
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <net/if_types.h>
45#include <net/route.h>
46
47#include <netinet/in.h>
48#include <netinet/in_var.h>
49#include <netinet/if_ether.h>
50
51#include <netinet/ip6.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/in6_ifattach.h>
54#include <netinet6/ip6_var.h>
55#include <netinet6/nd6.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 *));
71
72#define EUI64_GBIT	0x01
73#define EUI64_UBIT	0x02
74#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
75#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
76#define EUI64_INDIVIDUAL(in6)	(!EUI64_GROUP(in6))
77#define EUI64_LOCAL(in6)	((in6)->s6_addr[8] & EUI64_UBIT)
78#define EUI64_UNIVERSAL(in6)	(!EUI64_LOCAL(in6))
79
80#define IFID_LOCAL(in6)		(!EUI64_LOCAL(in6))
81#define IFID_UNIVERSAL(in6)	(!EUI64_UNIVERSAL(in6))
82
83/*
84 * Generate a last-resort interface identifier, when the machine has no
85 * IEEE802/EUI64 address sources.
86 * The goal here is to get an interface identifier that is
87 * (1) random enough and (2) does not change across reboot.
88 * We currently use MD5(hostname) for it.
89 */
90static int
91get_rand_ifid(ifp, in6)
92	struct ifnet *ifp;
93	struct in6_addr *in6;	/*upper 64bits are preserved */
94{
95	MD5_CTX ctxt;
96	u_int8_t digest[16];
97
98#if 0
99	/* we need at least several letters as seed for ifid */
100	if (hostnamelen < 3)
101		return -1;
102#endif
103
104	/* generate 8 bytes of pseudo-random value. */
105	bzero(&ctxt, sizeof(ctxt));
106	MD5Init(&ctxt);
107	MD5Update(&ctxt, hostname, hostnamelen);
108	MD5Final(digest, &ctxt);
109
110	/* assumes sizeof(digest) > sizeof(ifid) */
111	bcopy(digest, &in6->s6_addr[8], 8);
112
113	/* make sure to set "u" bit to local, and "g" bit to individual. */
114	in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
115	in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
116
117	/* convert EUI64 into IPv6 interface identifier */
118	EUI64_TO_IFID(in6);
119
120	return 0;
121}
122
123/*
124 * Get interface identifier for the specified interface.
125 * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
126 */
127static int
128get_hw_ifid(ifp, in6)
129	struct ifnet *ifp;
130	struct in6_addr *in6;	/*upper 64bits are preserved */
131{
132	struct ifaddr *ifa;
133	struct sockaddr_dl *sdl;
134	u_int8_t *addr;
135	size_t addrlen;
136	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
137	static u_int8_t allone[8] =
138		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
139
140	for (ifa = ifp->if_addrlist.tqh_first;
141	     ifa;
142	     ifa = ifa->ifa_list.tqe_next)
143	{
144		if (ifa->ifa_addr->sa_family != AF_LINK)
145			continue;
146		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
147		if (sdl == NULL)
148			continue;
149		if (sdl->sdl_alen == 0)
150			continue;
151
152		goto found;
153	}
154
155	return -1;
156
157found:
158	addr = LLADDR(sdl);
159	addrlen = sdl->sdl_alen;
160
161	/* get EUI64 */
162	switch (ifp->if_type) {
163	case IFT_ETHER:
164	case IFT_FDDI:
165	case IFT_ATM:
166		/* IEEE802/EUI64 cases - what others? */
167
168		/* look at IEEE802/EUI64 only */
169		if (addrlen != 8 && addrlen != 6)
170			return -1;
171
172		/*
173		 * check for invalid MAC address - on bsdi, we see it a lot
174		 * since wildboar configures all-zero MAC on pccard before
175		 * card insertion.
176		 */
177		if (bcmp(addr, allzero, addrlen) == 0)
178			return -1;
179		if (bcmp(addr, allone, addrlen) == 0)
180			return -1;
181
182		/* make EUI64 address */
183		if (addrlen == 8)
184			bcopy(addr, &in6->s6_addr[8], 8);
185		else if (addrlen == 6) {
186			in6->s6_addr[8] = addr[0];
187			in6->s6_addr[9] = addr[1];
188			in6->s6_addr[10] = addr[2];
189			in6->s6_addr[11] = 0xff;
190			in6->s6_addr[12] = 0xfe;
191			in6->s6_addr[13] = addr[3];
192			in6->s6_addr[14] = addr[4];
193			in6->s6_addr[15] = addr[5];
194		}
195		break;
196
197	case IFT_ARCNET:
198		if (addrlen != 1)
199			return -1;
200		if (!addr[0])
201			return -1;
202
203		bzero(&in6->s6_addr[8], 8);
204		in6->s6_addr[15] = addr[0];
205
206		/*
207		 * due to insufficient bitwidth, we mark it local.
208		 */
209		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
210		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
211		break;
212
213	case IFT_GIF:
214#ifdef IFT_STF
215	case IFT_STF:
216#endif
217		/*
218		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
219		 * however, IPv4 address is not very suitable as unique
220		 * identifier source (can be renumbered).
221		 * we don't do this.
222		 */
223		return -1;
224
225	default:
226		return -1;
227	}
228
229	/* sanity check: g bit must not indicate "group" */
230	if (EUI64_GROUP(in6))
231		return -1;
232
233	/* convert EUI64 into IPv6 interface identifier */
234	EUI64_TO_IFID(in6);
235
236	/*
237	 * sanity check: ifid must not be all zero, avoid conflict with
238	 * subnet router anycast
239	 */
240	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
241	    bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
242		return -1;
243	}
244
245	return 0;
246}
247
248/*
249 * Get interface identifier for the specified interface.  If it is not
250 * available on ifp0, borrow interface identifier from other information
251 * sources.
252 */
253static int
254get_ifid(ifp0, altifp, in6)
255	struct ifnet *ifp0;
256	struct ifnet *altifp;	/*secondary EUI64 source*/
257	struct in6_addr *in6;
258{
259	struct ifnet *ifp;
260
261	/* first, try to get it from the interface itself */
262	if (get_hw_ifid(ifp0, in6) == 0) {
263		nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
264		    if_name(ifp0)));
265		goto success;
266	}
267
268	/* try secondary EUI64 source. this basically is for ATM PVC */
269	if (altifp && get_hw_ifid(altifp, in6) == 0) {
270		nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
271		    if_name(ifp0), if_name(altifp)));
272		goto success;
273	}
274
275	/* next, try to get it from some other hardware interface */
276	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
277	{
278		if (ifp == ifp0)
279			continue;
280		if (get_hw_ifid(ifp, in6) != 0)
281			continue;
282
283		/*
284		 * to borrow ifid from other interface, ifid needs to be
285		 * globally unique
286		 */
287		if (IFID_UNIVERSAL(in6)) {
288			nd6log((LOG_DEBUG,
289			    "%s: borrow interface identifier from %s\n",
290			    if_name(ifp0), if_name(ifp)));
291			goto success;
292		}
293	}
294
295	/* last resort: get from random number source */
296	if (get_rand_ifid(ifp, in6) == 0) {
297		nd6log((LOG_DEBUG,
298		    "%s: interface identifier generated by random number\n",
299		    if_name(ifp0)));
300		goto success;
301	}
302
303	printf("%s: failed to get interface identifier\n", if_name(ifp0));
304	return -1;
305
306success:
307	nd6log((LOG_INFO, "%s: ifid: "
308		"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
309		if_name(ifp0),
310		in6->s6_addr[8], in6->s6_addr[9],
311		in6->s6_addr[10], in6->s6_addr[11],
312		in6->s6_addr[12], in6->s6_addr[13],
313		in6->s6_addr[14], in6->s6_addr[15]));
314	return 0;
315}
316
317/*
318 * configure IPv6 interface address.  XXX code duplicated with in.c
319 */
320static int
321in6_ifattach_addaddr(ifp, ia)
322	struct ifnet *ifp;
323	struct in6_ifaddr *ia;
324{
325	struct in6_ifaddr *oia;
326	struct ifaddr *ifa;
327	int error;
328	int rtflag;
329	struct in6_addr llsol;
330
331	/*
332	 * initialize if_addrlist, if we are the very first one
333	 */
334	ifa = TAILQ_FIRST(&ifp->if_addrlist);
335	if (ifa == NULL) {
336		TAILQ_INIT(&ifp->if_addrlist);
337	}
338
339	/*
340	 * link the interface address to global list
341	 */
342	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
343	ia->ia_ifa.ifa_refcnt++;
344
345	/*
346	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
347	 * kazu opposed it, but itojun & jinmei wanted.
348	 */
349	if ((oia = in6_ifaddr) != NULL) {
350		for (; oia->ia_next; oia = oia->ia_next)
351			continue;
352		oia->ia_next = ia;
353	} else
354		in6_ifaddr = ia;
355	ia->ia_ifa.ifa_refcnt++;
356
357	/*
358	 * give the interface a chance to initialize, in case this
359	 * is the first address to be added.
360	 */
361	if (ifp->if_ioctl != NULL) {
362		int s;
363		s = splimp();
364		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
365		splx(s);
366	} else
367		error = 0;
368	if (error) {
369		switch (error) {
370		case EAFNOSUPPORT:
371			printf("%s: IPv6 not supported\n", if_name(ifp));
372			break;
373		default:
374			printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
375			    error);
376			break;
377		}
378
379		/* undo changes */
380		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
381		IFAFREE(&ia->ia_ifa);
382		if (oia)
383			oia->ia_next = ia->ia_next;
384		else
385			in6_ifaddr = ia->ia_next;
386		IFAFREE(&ia->ia_ifa);
387		return -1;
388	}
389
390	/* configure link-layer address resolution */
391	rtflag = 0;
392	if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
393		rtflag = RTF_HOST;
394	else {
395		switch (ifp->if_type) {
396		case IFT_LOOP:
397#ifdef IFT_STF
398		case IFT_STF:
399#endif
400			rtflag = 0;
401			break;
402		default:
403			ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
404			ia->ia_ifa.ifa_flags |= RTF_CLONING;
405			rtflag = RTF_CLONING;
406			break;
407		}
408	}
409
410	/* add route to the interface. */
411	rtrequest(RTM_ADD,
412		  (struct sockaddr *)&ia->ia_addr,
413		  (struct sockaddr *)&ia->ia_addr,
414		  (struct sockaddr *)&ia->ia_prefixmask,
415		  RTF_UP | rtflag,
416		  (struct rtentry **)0);
417	ia->ia_flags |= IFA_ROUTE;
418
419	if ((rtflag & RTF_CLONING) != 0 &&
420	    (ifp->if_flags & IFF_MULTICAST) != 0) {
421		/* Restore saved multicast addresses (if any). */
422		in6_restoremkludge(ia, ifp);
423
424		/*
425		 * join solicited multicast address
426		 */
427		bzero(&llsol, sizeof(llsol));
428		llsol.s6_addr16[0] = htons(0xff02);
429		llsol.s6_addr16[1] = htons(ifp->if_index);
430		llsol.s6_addr32[1] = 0;
431		llsol.s6_addr32[2] = htonl(1);
432		llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
433		llsol.s6_addr8[12] = 0xff;
434		(void)in6_addmulti(&llsol, ifp, &error);
435
436		/* XXX should we run DAD on other interface types? */
437		switch (ifp->if_type) {
438#if 1
439		case IFT_ARCNET:
440		case IFT_ETHER:
441		case IFT_FDDI:
442#else
443		default:
444#endif
445			/* mark the address TENTATIVE, if needed. */
446			ia->ia6_flags |= IN6_IFF_TENTATIVE;
447			/* nd6_dad_start() will be called in in6_if_up */
448		}
449	}
450
451	return 0;
452}
453
454static int
455in6_ifattach_linklocal(ifp, altifp)
456	struct ifnet *ifp;
457	struct ifnet *altifp;	/*secondary EUI64 source*/
458{
459	struct in6_ifaddr *ia;
460
461	/*
462	 * configure link-local address
463	 */
464	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
465	bzero((caddr_t)ia, sizeof(*ia));
466	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
467	if (ifp->if_flags & IFF_POINTOPOINT)
468		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
469	else
470		ia->ia_ifa.ifa_dstaddr = NULL;
471	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
472	ia->ia_ifp = ifp;
473
474	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
475	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
476	ia->ia_prefixmask.sin6_family = AF_INET6;
477	ia->ia_prefixmask.sin6_addr = in6mask64;
478
479	/* just in case */
480	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
481	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
482	ia->ia_dstaddr.sin6_family = AF_INET6;
483
484	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
485	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
486	ia->ia_addr.sin6_family = AF_INET6;
487	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
488	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
489	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
490	if (ifp->if_flags & IFF_LOOPBACK) {
491		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
492		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
493	} else {
494		if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
495			nd6log((LOG_ERR,
496			    "%s: no ifid available\n", if_name(ifp)));
497			free(ia, M_IFADDR);
498			return -1;
499		}
500	}
501
502	ia->ia_ifa.ifa_metric = ifp->if_metric;
503
504	if (in6_ifattach_addaddr(ifp, ia) != 0) {
505		/* ia will be freed on failure */
506		return -1;
507	}
508
509	return 0;
510}
511
512static int
513in6_ifattach_loopback(ifp)
514	struct ifnet *ifp;	/* must be IFT_LOOP */
515{
516	struct in6_ifaddr *ia;
517
518	/*
519	 * configure link-local address
520	 */
521	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
522	bzero((caddr_t)ia, sizeof(*ia));
523	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
524	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
525	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
526	ia->ia_ifp = ifp;
527
528	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
529	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
530	ia->ia_prefixmask.sin6_family = AF_INET6;
531	ia->ia_prefixmask.sin6_addr = in6mask128;
532
533	/*
534	 * Always initialize ia_dstaddr (= broadcast address) to loopback
535	 * address, to make getifaddr happier.
536	 *
537	 * For BSDI, it is mandatory.  The BSDI version of
538	 * ifa_ifwithroute() rejects to add a route to the loopback
539	 * interface.  Even for other systems, loopback looks somewhat
540	 * special.
541	 */
542	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
543	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
544	ia->ia_dstaddr.sin6_family = AF_INET6;
545	ia->ia_dstaddr.sin6_addr = in6addr_loopback;
546
547	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
548	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
549	ia->ia_addr.sin6_family = AF_INET6;
550	ia->ia_addr.sin6_addr = in6addr_loopback;
551
552	ia->ia_ifa.ifa_metric = ifp->if_metric;
553
554	if (in6_ifattach_addaddr(ifp, ia) != 0) {
555		/* ia will be freed on failure */
556		return -1;
557	}
558
559	return 0;
560}
561
562/*
563 * XXX multiple loopback interface needs more care.  for instance,
564 * nodelocal address needs to be configured onto only one of them.
565 * XXX multiple link-local address case
566 */
567void
568in6_ifattach(ifp, altifp)
569	struct ifnet *ifp;
570	struct ifnet *altifp;	/* secondary EUI64 source */
571{
572	static size_t if_indexlim = 8;
573	struct sockaddr_in6 mltaddr;
574	struct sockaddr_in6 mltmask;
575	struct sockaddr_in6 gate;
576	struct sockaddr_in6 mask;
577	struct in6_ifaddr *ia;
578	struct in6_addr in6;
579
580	/* some of the interfaces are inherently not IPv6 capable */
581	switch (ifp->if_type) {
582	case IFT_BRIDGE:
583	case IFT_ENC:
584		return;
585	case IFT_PROPVIRTUAL:
586		if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
587		    '0' <= ifp->if_xname[sizeof("bridge")] &&
588		    ifp->if_xname[sizeof("bridge")] <= '9')
589			return;
590		break;
591	}
592
593	/*
594	 * We have some arrays that should be indexed by if_index.
595	 * since if_index will grow dynamically, they should grow too.
596	 *	struct in6_ifstat **in6_ifstat
597	 *	struct icmp6_ifstat **icmp6_ifstat
598	 */
599	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
600	    if_index >= if_indexlim) {
601		size_t n;
602		caddr_t q;
603		size_t olim;
604
605		olim = if_indexlim;
606		while (if_index >= if_indexlim)
607			if_indexlim <<= 1;
608
609		/* grow in6_ifstat */
610		n = if_indexlim * sizeof(struct in6_ifstat *);
611		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
612		bzero(q, n);
613		if (in6_ifstat) {
614			bcopy((caddr_t)in6_ifstat, q,
615				olim * sizeof(struct in6_ifstat *));
616			free((caddr_t)in6_ifstat, M_IFADDR);
617		}
618		in6_ifstat = (struct in6_ifstat **)q;
619		in6_ifstatmax = if_indexlim;
620
621		/* grow icmp6_ifstat */
622		n = if_indexlim * sizeof(struct icmp6_ifstat *);
623		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
624		bzero(q, n);
625		if (icmp6_ifstat) {
626			bcopy((caddr_t)icmp6_ifstat, q,
627				olim * sizeof(struct icmp6_ifstat *));
628			free((caddr_t)icmp6_ifstat, M_IFADDR);
629		}
630		icmp6_ifstat = (struct icmp6_ifstat **)q;
631		icmp6_ifstatmax = if_indexlim;
632	}
633
634	/*
635	 * quirks based on interface type
636	 */
637	switch (ifp->if_type) {
638#ifdef IFT_STF
639	case IFT_STF:
640		/*
641		 * 6to4 interface is a very speical kind of beast.
642		 * no multicast, no linklocal (based on 03 draft).
643		 */
644		goto statinit;
645#endif
646	default:
647		break;
648	}
649
650	/*
651	 * usually, we require multicast capability to the interface
652	 */
653	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
654		printf("%s: not multicast capable, IPv6 not enabled\n",
655		    if_name(ifp));
656		return;
657	}
658
659	/*
660	 * assign link-local address, if there's none
661	 */
662	ia = in6ifa_ifpforlinklocal(ifp, 0);
663	if (ia == NULL) {
664		if (in6_ifattach_linklocal(ifp, altifp) != 0)
665			return;
666		ia = in6ifa_ifpforlinklocal(ifp, 0);
667
668		if (ia == NULL) {
669			printf("%s: failed to add link-local address\n",
670			    if_name(ifp));
671
672			/* we can't initialize multicasts without link-local */
673			goto statinit;
674		}
675	}
676
677	if (ifp->if_flags & IFF_POINTOPOINT) {
678		/*
679		 * route local address to loopback
680		 */
681		bzero(&gate, sizeof(gate));
682		gate.sin6_len = sizeof(struct sockaddr_in6);
683		gate.sin6_family = AF_INET6;
684		gate.sin6_addr = in6addr_loopback;
685		bzero(&mask, sizeof(mask));
686		mask.sin6_len = sizeof(struct sockaddr_in6);
687		mask.sin6_family = AF_INET6;
688		mask.sin6_addr = in6mask64;
689		rtrequest(RTM_ADD,
690			  (struct sockaddr *)&ia->ia_addr,
691			  (struct sockaddr *)&gate,
692			  (struct sockaddr *)&mask,
693			  RTF_UP|RTF_HOST,
694			  (struct rtentry **)0);
695	}
696
697	/*
698	 * assign loopback address for loopback interface
699	 * XXX multiple loopback interface case
700	 */
701	in6 = in6addr_loopback;
702	if (ifp->if_flags & IFF_LOOPBACK) {
703		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
704			if (in6_ifattach_loopback(ifp) != 0)
705				return;
706		}
707	}
708
709#ifdef DIAGNOSTIC
710	if (!ia) {
711		panic("ia == NULL in in6_ifattach");
712		/*NOTREACHED*/
713	}
714#endif
715
716	/*
717	 * join multicast
718	 */
719	if (ifp->if_flags & IFF_MULTICAST) {
720		int error;	/* not used */
721		struct in6_multi *in6m;
722
723		/* Restore saved multicast addresses(if any). */
724		in6_restoremkludge(ia, ifp);
725
726		bzero(&mltmask, sizeof(mltmask));
727		mltmask.sin6_len = sizeof(struct sockaddr_in6);
728		mltmask.sin6_family = AF_INET6;
729		mltmask.sin6_addr = in6mask32;
730
731		/*
732		 * join link-local all-nodes address
733		 */
734		bzero(&mltaddr, sizeof(mltaddr));
735		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
736		mltaddr.sin6_family = AF_INET6;
737		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
738		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
739
740		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
741		if (in6m == NULL) {
742			rtrequest(RTM_ADD,
743				  (struct sockaddr *)&mltaddr,
744				  (struct sockaddr *)&ia->ia_addr,
745				  (struct sockaddr *)&mltmask,
746				  RTF_UP|RTF_CLONING,  /* xxx */
747				  (struct rtentry **)0);
748			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
749		}
750
751		if (ifp->if_flags & IFF_LOOPBACK) {
752			in6 = in6addr_loopback;
753			ia = in6ifa_ifpwithaddr(ifp, &in6);
754			/*
755			 * join node-local all-nodes address, on loopback
756			 */
757			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
758
759			IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
760			if (in6m == NULL && ia != NULL) {
761				rtrequest(RTM_ADD,
762					  (struct sockaddr *)&mltaddr,
763					  (struct sockaddr *)&ia->ia_addr,
764					  (struct sockaddr *)&mltmask,
765					  RTF_UP,
766					  (struct rtentry **)0);
767				(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
768			}
769		}
770	}
771
772statinit:;
773
774	/* update dynamically. */
775	if (in6_maxmtu < ifp->if_mtu)
776		in6_maxmtu = ifp->if_mtu;
777
778	if (in6_ifstat[ifp->if_index] == NULL) {
779		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
780			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
781		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
782	}
783	if (icmp6_ifstat[ifp->if_index] == NULL) {
784		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
785			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
786		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
787	}
788
789	/* initialize NDP variables */
790	nd6_ifattach(ifp);
791}
792
793/*
794 * NOTE: in6_ifdetach() does not support loopback if at this moment.
795 */
796void
797in6_ifdetach(ifp)
798	struct ifnet *ifp;
799{
800	struct in6_ifaddr *ia, *oia;
801	struct ifaddr *ifa, *next;
802	struct rtentry *rt;
803	short rtflags;
804	struct sockaddr_in6 sin6;
805	struct in6_multi *in6m;
806
807	/* nuke prefix list.  this may try to remove some of ifaddrs as well */
808	in6_purgeprefix(ifp);
809
810	/* remove neighbor management table */
811	nd6_purge(ifp);
812
813	/* nuke any of IPv6 addresses we have */
814	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
815	{
816		next = ifa->ifa_list.tqe_next;
817		if (ifa->ifa_addr->sa_family != AF_INET6)
818			continue;
819		in6_purgeaddr(ifa, ifp);
820	}
821
822	/* undo everything done by in6_ifattach(), just in case */
823	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
824	{
825		if (ifa->ifa_addr->sa_family != AF_INET6
826		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
827			continue;
828		}
829
830		ia = (struct in6_ifaddr *)ifa;
831
832		/* leave from all multicast groups joined */
833		while ((in6m = LIST_FIRST(&ia->ia6_multiaddrs)) != NULL)
834			in6_delmulti(in6m);
835
836		/* remove from the routing table */
837		if ((ia->ia_flags & IFA_ROUTE)
838		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
839			rtflags = rt->rt_flags;
840			rtfree(rt);
841			rtrequest(RTM_DELETE,
842				(struct sockaddr *)&ia->ia_addr,
843				(struct sockaddr *)&ia->ia_addr,
844				(struct sockaddr *)&ia->ia_prefixmask,
845				rtflags, (struct rtentry **)0);
846		}
847
848		/* remove from the linked list */
849		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
850		IFAFREE(&ia->ia_ifa);
851
852		/* also remove from the IPv6 address chain(itojun&jinmei) */
853		oia = ia;
854		if (oia == (ia = in6_ifaddr))
855			in6_ifaddr = ia->ia_next;
856		else {
857			while (ia->ia_next && (ia->ia_next != oia))
858				ia = ia->ia_next;
859			if (ia->ia_next)
860				ia->ia_next = oia->ia_next;
861			else {
862				nd6log((LOG_ERR,
863				    "%s: didn't unlink in6ifaddr from "
864				    "list\n", if_name(ifp)));
865			}
866		}
867
868		IFAFREE(&oia->ia_ifa);
869	}
870
871	/* cleanup multicast address kludge table, if there is any */
872	in6_purgemkludge(ifp);
873
874	/*
875	 * remove neighbor management table.  we call it twice just to make
876	 * sure we nuke everything.  maybe we need just one call.
877	 * XXX: since the first call did not release addresses, some prefixes
878	 * might remain.  We should call nd6_purge() again to release the
879	 * prefixes after removing all addresses above.
880	 * (Or can we just delay calling nd6_purge until at this point?)
881	 */
882	nd6_purge(ifp);
883
884	/* remove route to link-local allnodes multicast (ff02::1) */
885	bzero(&sin6, sizeof(sin6));
886	sin6.sin6_len = sizeof(struct sockaddr_in6);
887	sin6.sin6_family = AF_INET6;
888	sin6.sin6_addr = in6addr_linklocal_allnodes;
889	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
890	rt = rtalloc1((struct sockaddr *)&sin6, 0);
891	if (rt && rt->rt_ifp == ifp) {
892		rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
893			rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
894		rtfree(rt);
895	}
896}
897