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