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