in6_ifattach.c revision 1.23
1/*	$OpenBSD: in6_ifattach.c,v 1.23 2002/05/23 06:56:16 itojun Exp $	*/
2/*	$KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 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(struct ifnet *, struct in6_addr *);
64static int get_hw_ifid(struct ifnet *, struct in6_addr *);
65static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
66static int in6_ifattach_addaddr(struct ifnet *, struct in6_ifaddr *);
67static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
68static int in6_ifattach_loopback(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		if (in6if_do_dad(ifp)) {
437			/* mark the address TENTATIVE, if needed. */
438			ia->ia6_flags |= IN6_IFF_TENTATIVE;
439			/* nd6_dad_start() will be called in in6_if_up */
440		}
441	}
442
443	return 0;
444}
445
446static int
447in6_ifattach_linklocal(ifp, altifp)
448	struct ifnet *ifp;
449	struct ifnet *altifp;	/*secondary EUI64 source*/
450{
451	struct in6_ifaddr *ia;
452
453	/*
454	 * configure link-local address
455	 */
456	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
457	bzero((caddr_t)ia, sizeof(*ia));
458	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
459	if (ifp->if_flags & IFF_POINTOPOINT)
460		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
461	else
462		ia->ia_ifa.ifa_dstaddr = NULL;
463	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
464	ia->ia_ifp = ifp;
465
466	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
467	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
468	ia->ia_prefixmask.sin6_family = AF_INET6;
469	ia->ia_prefixmask.sin6_addr = in6mask64;
470
471	/* just in case */
472	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
473	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
474	ia->ia_dstaddr.sin6_family = AF_INET6;
475
476	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
477	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
478	ia->ia_addr.sin6_family = AF_INET6;
479	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
480	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
481	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
482	if (ifp->if_flags & IFF_LOOPBACK) {
483		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
484		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
485	} else {
486		if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
487			nd6log((LOG_ERR,
488			    "%s: no ifid available\n", ifp->if_xname));
489			free(ia, M_IFADDR);
490			return -1;
491		}
492	}
493
494	ia->ia_ifa.ifa_metric = ifp->if_metric;
495
496	if (in6_ifattach_addaddr(ifp, ia) != 0) {
497		/* ia will be freed on failure */
498		return -1;
499	}
500
501	return 0;
502}
503
504static int
505in6_ifattach_loopback(ifp)
506	struct ifnet *ifp;	/* must be IFT_LOOP */
507{
508	struct in6_ifaddr *ia;
509
510	/*
511	 * configure link-local address
512	 */
513	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
514	bzero((caddr_t)ia, sizeof(*ia));
515	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
516	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
517	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
518	ia->ia_ifp = ifp;
519
520	bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
521	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
522	ia->ia_prefixmask.sin6_family = AF_INET6;
523	ia->ia_prefixmask.sin6_addr = in6mask128;
524
525	/*
526	 * Always initialize ia_dstaddr (= broadcast address) to loopback
527	 * address, to make getifaddr happier.
528	 *
529	 * For BSDI, it is mandatory.  The BSDI version of
530	 * ifa_ifwithroute() rejects to add a route to the loopback
531	 * interface.  Even for other systems, loopback looks somewhat
532	 * special.
533	 */
534	bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
535	ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
536	ia->ia_dstaddr.sin6_family = AF_INET6;
537	ia->ia_dstaddr.sin6_addr = in6addr_loopback;
538
539	bzero(&ia->ia_addr, sizeof(ia->ia_addr));
540	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
541	ia->ia_addr.sin6_family = AF_INET6;
542	ia->ia_addr.sin6_addr = in6addr_loopback;
543
544	ia->ia_ifa.ifa_metric = ifp->if_metric;
545
546	if (in6_ifattach_addaddr(ifp, ia) != 0) {
547		/* ia will be freed on failure */
548		return -1;
549	}
550
551	return 0;
552}
553
554/*
555 * XXX multiple loopback interface needs more care.  for instance,
556 * nodelocal address needs to be configured onto only one of them.
557 * XXX multiple link-local address case
558 */
559void
560in6_ifattach(ifp, altifp)
561	struct ifnet *ifp;
562	struct ifnet *altifp;	/* secondary EUI64 source */
563{
564	static size_t if_indexlim = 8;
565	struct sockaddr_in6 mltaddr;
566	struct sockaddr_in6 mltmask;
567	struct sockaddr_in6 gate;
568	struct sockaddr_in6 mask;
569	struct in6_ifaddr *ia;
570	struct in6_addr in6;
571
572	/* some of the interfaces are inherently not IPv6 capable */
573	switch (ifp->if_type) {
574	case IFT_BRIDGE:
575	case IFT_ENC:
576	case IFT_PFLOG:
577		return;
578	case IFT_PROPVIRTUAL:
579		if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
580		    '0' <= ifp->if_xname[sizeof("bridge")] &&
581		    ifp->if_xname[sizeof("bridge")] <= '9')
582			return;
583		break;
584	}
585
586	/*
587	 * We have some arrays that should be indexed by if_index.
588	 * since if_index will grow dynamically, they should grow too.
589	 *	struct in6_ifstat **in6_ifstat
590	 *	struct icmp6_ifstat **icmp6_ifstat
591	 */
592	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
593	    if_index >= if_indexlim) {
594		size_t n;
595		caddr_t q;
596		size_t olim;
597
598		olim = if_indexlim;
599		while (if_index >= if_indexlim)
600			if_indexlim <<= 1;
601
602		/* grow in6_ifstat */
603		n = if_indexlim * sizeof(struct in6_ifstat *);
604		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
605		bzero(q, n);
606		if (in6_ifstat) {
607			bcopy((caddr_t)in6_ifstat, q,
608				olim * sizeof(struct in6_ifstat *));
609			free((caddr_t)in6_ifstat, M_IFADDR);
610		}
611		in6_ifstat = (struct in6_ifstat **)q;
612		in6_ifstatmax = if_indexlim;
613
614		/* grow icmp6_ifstat */
615		n = if_indexlim * sizeof(struct icmp6_ifstat *);
616		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
617		bzero(q, n);
618		if (icmp6_ifstat) {
619			bcopy((caddr_t)icmp6_ifstat, q,
620				olim * sizeof(struct icmp6_ifstat *));
621			free((caddr_t)icmp6_ifstat, M_IFADDR);
622		}
623		icmp6_ifstat = (struct icmp6_ifstat **)q;
624		icmp6_ifstatmax = if_indexlim;
625	}
626
627	/* create a multicast kludge storage (if we have not had one) */
628	in6_createmkludge(ifp);
629
630	/*
631	 * quirks based on interface type
632	 */
633	switch (ifp->if_type) {
634#ifdef IFT_STF
635	case IFT_STF:
636		/*
637		 * 6to4 interface is a very special kind of beast.
638		 * no multicast, no linklocal.  RFC2529 specifies how to make
639		 * linklocals for 6to4 interface, but there's no use and
640		 * it is rather harmful to have one.
641		 */
642		goto statinit;
643#endif
644	default:
645		break;
646	}
647
648	/*
649	 * usually, we require multicast capability to the interface
650	 */
651	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
652		log(LOG_INFO, "in6_ifattach: "
653		    "%s is 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