in6_ifattach.c revision 1.1
1/*	$OpenBSD: in6_ifattach.c,v 1.1 1999/12/08 06:50:21 itojun Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/socket.h>
36#include <sys/sockio.h>
37#include <sys/kernel.h>
38#ifdef __bsdi__
39#include <crypto/md5.h>
40#elif defined(__OpenBSD__)
41#include <sys/md5k.h>
42#else
43#include <sys/md5.h>
44#endif
45
46#include <net/if.h>
47#include <net/if_dl.h>
48#include <net/if_types.h>
49#include <net/route.h>
50
51#include <netinet/in.h>
52#include <netinet/in_var.h>
53#ifndef __NetBSD__
54#include <netinet/if_ether.h>
55#endif
56
57#include <netinet6/ip6.h>
58#include <netinet6/ip6_var.h>
59#include <netinet6/in6_ifattach.h>
60#include <netinet6/ip6.h>
61#include <netinet6/ip6_var.h>
62#include <netinet6/nd6.h>
63
64#include <net/net_osdep.h>
65
66static	struct in6_addr llsol;
67
68struct in6_ifstat **in6_ifstat = NULL;
69struct icmp6_ifstat **icmp6_ifstat = NULL;
70size_t in6_ifstatmax = 0;
71size_t icmp6_ifstatmax = 0;
72unsigned long in6_maxmtu = 0;
73
74int found_first_ifid = 0;
75#define IFID_LEN 8
76static char first_ifid[IFID_LEN];
77
78static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t));
79static int gen_rand_eui64 __P((u_int8_t *));
80
81static int
82laddr_to_eui64(dst, src, len)
83	u_int8_t *dst;
84	u_int8_t *src;
85	size_t len;
86{
87	static u_int8_t zero[8];
88
89	bzero(zero, sizeof(zero));
90
91	switch (len) {
92	case 6:
93		if (bcmp(zero, src, 6) == 0)
94			return EINVAL;
95		dst[0] = src[0];
96		dst[1] = src[1];
97		dst[2] = src[2];
98		dst[3] = 0xff;
99		dst[4] = 0xfe;
100		dst[5] = src[3];
101		dst[6] = src[4];
102		dst[7] = src[5];
103		break;
104	case 8:
105		if (bcmp(zero, src, 8) == 0)
106			return EINVAL;
107		bcopy(src, dst, len);
108		break;
109	default:
110		return EINVAL;
111	}
112
113	return 0;
114}
115
116/*
117 * Generate a last-resort interface identifier, when the machine has no
118 * IEEE802/EUI64 address sources.
119 * The address should be random, and should not change across reboot.
120 */
121static int
122gen_rand_eui64(dst)
123	u_int8_t *dst;
124{
125	MD5_CTX ctxt;
126	u_int8_t digest[16];
127#ifdef __FreeBSD__
128	int hostnamelen	= strlen(hostname);
129#endif
130
131	/* generate 8bytes of pseudo-random value. */
132	bzero(&ctxt, sizeof(ctxt));
133	MD5Init(&ctxt);
134	MD5Update(&ctxt, hostname, hostnamelen);
135	MD5Final(digest, &ctxt);
136
137	/* assumes sizeof(digest) > sizeof(first_ifid) */
138	bcopy(digest, dst, 8);
139
140	/* make sure to set "u" bit to local, and "g" bit to individual. */
141	dst[0] &= 0xfe;
142	dst[0] |= 0x02;		/* EUI64 "local" */
143
144	return 0;
145}
146
147/*
148 * Find first ifid on list of interfaces.
149 * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
150 * is globally unique.  We may need to have a flag parameter in the future.
151 */
152int
153in6_ifattach_getifid(ifp0)
154	struct ifnet *ifp0;
155{
156	struct ifnet *ifp;
157	struct ifaddr *ifa;
158	u_int8_t *addr = NULL;
159	int addrlen = 0;
160	struct sockaddr_dl *sdl;
161
162	if (found_first_ifid)
163		return 0;
164
165#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
166	for (ifp = ifnet; ifp; ifp = ifp->if_next)
167#else
168	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
169#endif
170	{
171		if (ifp0 != NULL && ifp0 != ifp)
172			continue;
173#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
174		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
175#else
176		for (ifa = ifp->if_addrlist.tqh_first;
177		     ifa;
178		     ifa = ifa->ifa_list.tqe_next)
179#endif
180		{
181			if (ifa->ifa_addr->sa_family != AF_LINK)
182				continue;
183			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
184			if (sdl == NULL)
185				continue;
186			if (sdl->sdl_alen == 0)
187				continue;
188			switch (ifp->if_type) {
189			case IFT_ETHER:
190			case IFT_FDDI:
191			case IFT_ATM:
192				/* IEEE802/EUI64 cases - what others? */
193				addr = LLADDR(sdl);
194				addrlen = sdl->sdl_alen;
195				/*
196				 * to copy ifid from IEEE802/EUI64 interface,
197				 * u bit of the source needs to be 0.
198				 */
199				if ((addr[0] & 0x02) != 0)
200					break;
201				goto found;
202			case IFT_ARCNET:
203				/*
204				 * ARCnet interface token cannot be used as
205				 * globally unique identifier due to its
206				 * small bitwidth.
207				 */
208				break;
209			default:
210				break;
211			}
212		}
213	}
214#ifdef DEBUG
215	printf("in6_ifattach_getifid: failed to get EUI64");
216#endif
217	return EADDRNOTAVAIL;
218
219found:
220	if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
221		found_first_ifid = 1;
222
223	if (found_first_ifid) {
224		printf("%s: supplying EUI64: "
225			"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
226			if_name(ifp),
227			first_ifid[0] & 0xff, first_ifid[1] & 0xff,
228			first_ifid[2] & 0xff, first_ifid[3] & 0xff,
229			first_ifid[4] & 0xff, first_ifid[5] & 0xff,
230			first_ifid[6] & 0xff, first_ifid[7] & 0xff);
231
232		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
233		first_ifid[0] ^= 0x02;
234
235		return 0;
236	} else {
237#ifdef DEBUG
238		printf("in6_ifattach_getifid: failed to get EUI64");
239#endif
240		return EADDRNOTAVAIL;
241	}
242}
243
244void
245in6_ifattach(ifp, type, laddr, noloop)
246	struct ifnet *ifp;
247	u_int type;
248	caddr_t laddr;
249	/* size_t laddrlen; */
250	int noloop;
251{
252	static size_t if_indexlim = 8;
253	struct sockaddr_in6 mltaddr;
254	struct sockaddr_in6 mltmask;
255	struct sockaddr_in6 gate;
256	struct sockaddr_in6 mask;
257#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
258	struct ifaddr **ifap;
259#endif
260
261	struct in6_ifaddr *ia, *ib, *oia;
262	struct ifaddr *ifa;
263	int rtflag = 0;
264
265	if (type == IN6_IFT_P2P && found_first_ifid == 0) {
266		printf("%s: no ifid available for IPv6 link-local address\n",
267			if_name(ifp));
268#if 0
269		return;
270#else
271		/* last resort */
272		if (gen_rand_eui64(first_ifid) == 0) {
273			printf("%s: using random value as EUI64: "
274				"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
275				if_name(ifp),
276				first_ifid[0] & 0xff, first_ifid[1] & 0xff,
277				first_ifid[2] & 0xff, first_ifid[3] & 0xff,
278				first_ifid[4] & 0xff, first_ifid[5] & 0xff,
279				first_ifid[6] & 0xff, first_ifid[7] & 0xff);
280			/*
281			 * invert u bit to convert EUI64 to RFC2373 interface
282			 * ID.
283			 */
284			first_ifid[0] ^= 0x02;
285
286			found_first_ifid = 1;
287		}
288#endif
289	}
290
291	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
292		printf("%s: not multicast capable, IPv6 not enabled\n",
293			if_name(ifp));
294		return;
295	}
296
297	/*
298	 * We have some arrays that should be indexed by if_index.
299	 * since if_index will grow dynamically, they should grow too.
300	 *	struct in6_ifstat **in6_ifstat
301	 *	struct icmp6_ifstat **icmp6_ifstat
302	 */
303	if (in6_ifstat == NULL || icmp6_ifstat == NULL
304	 || if_index >= if_indexlim) {
305		size_t n;
306		caddr_t q;
307		size_t olim;
308
309		olim = if_indexlim;
310		while (if_index >= if_indexlim)
311			if_indexlim <<= 1;
312
313		/* grow in6_ifstat */
314		n = if_indexlim * sizeof(struct in6_ifstat *);
315		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
316		bzero(q, n);
317		if (in6_ifstat) {
318			bcopy((caddr_t)in6_ifstat, q,
319				olim * sizeof(struct in6_ifstat *));
320			free((caddr_t)in6_ifstat, M_IFADDR);
321		}
322		in6_ifstat = (struct in6_ifstat **)q;
323		in6_ifstatmax = if_indexlim;
324
325		/* grow icmp6_ifstat */
326		n = if_indexlim * sizeof(struct icmp6_ifstat *);
327		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
328		bzero(q, n);
329		if (icmp6_ifstat) {
330			bcopy((caddr_t)icmp6_ifstat, q,
331				olim * sizeof(struct icmp6_ifstat *));
332			free((caddr_t)icmp6_ifstat, M_IFADDR);
333		}
334		icmp6_ifstat = (struct icmp6_ifstat **)q;
335		icmp6_ifstatmax = if_indexlim;
336	}
337
338	/*
339	 * To prevent to assign link-local address to PnP network
340	 * cards multiple times.
341	 * This is lengthy for P2P and LOOP but works.
342	 */
343#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
344	ifa = ifp->if_addrlist;
345	if (ifa != NULL) {
346		for ( ; ifa; ifa = ifa->ifa_next) {
347			ifap = &ifa->ifa_next;
348			if (ifa->ifa_addr->sa_family != AF_INET6)
349				continue;
350			if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
351				return;
352		}
353	} else
354		ifap = &ifp->if_addrlist;
355#else
356	ifa = TAILQ_FIRST(&ifp->if_addrlist);
357	if (ifa != NULL) {
358		for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
359			if (ifa->ifa_addr->sa_family != AF_INET6)
360				continue;
361			if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
362				return;
363		}
364	} else {
365		TAILQ_INIT(&ifp->if_addrlist);
366	}
367#endif
368
369	/*
370	 * link-local address
371	 */
372	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
373	bzero((caddr_t)ia, sizeof(*ia));
374	ia->ia_ifa.ifa_addr =    (struct sockaddr *)&ia->ia_addr;
375	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
376	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
377	ia->ia_ifp = ifp;
378#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
379	*ifap = (struct ifaddr *)ia;
380#else
381	TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
382#endif
383	/*
384	 * Also link into the IPv6 address chain beginning with in6_ifaddr.
385	 * kazu opposed it, but itojun & jinmei wanted.
386	 */
387	if ((oia = in6_ifaddr) != NULL) {
388		for (; oia->ia_next; oia = oia->ia_next)
389			continue;
390		oia->ia_next = ia;
391	} else
392		in6_ifaddr = ia;
393
394	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
395	ia->ia_prefixmask.sin6_family = AF_INET6;
396	ia->ia_prefixmask.sin6_addr = in6mask64;
397
398	bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
399	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
400	ia->ia_addr.sin6_family = AF_INET6;
401	ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
402	ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
403	ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
404
405	switch (type) {
406	case IN6_IFT_LOOP:
407		ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
408		ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
409		break;
410	case IN6_IFT_802:
411		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
412		ia->ia_ifa.ifa_flags |= RTF_CLONING;
413		rtflag = RTF_CLONING;
414		/* fall through */
415	case IN6_IFT_P2P802:
416		if (laddr == NULL)
417			break;
418		/* XXX use laddrlen */
419		if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
420				laddr, 6) != 0) {
421			break;
422		}
423		/* invert u bit to convert EUI64 to RFC2373 interface ID. */
424		ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
425		if (found_first_ifid == 0)
426			in6_ifattach_getifid(ifp);
427		bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6));
428		ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
429		ia->ia_dstaddr.sin6_family = AF_INET6;
430		break;
431	case IN6_IFT_P2P:
432		bcopy((caddr_t)first_ifid,
433		      (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
434		      IFID_LEN);
435		bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6));
436		ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
437		ia->ia_dstaddr.sin6_family = AF_INET6;
438		break;
439	case IN6_IFT_ARCNET:
440		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
441		ia->ia_ifa.ifa_flags |= RTF_CLONING;
442		rtflag = RTF_CLONING;
443		if (laddr == NULL)
444			break;
445
446		/* make non-global IF id out of link-level address */
447		bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7);
448		ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr;
449	}
450
451	ia->ia_ifa.ifa_metric = ifp->if_metric;
452
453	if (ifp->if_ioctl != NULL) {
454		int s;
455		int error;
456
457		/*
458		 * give the interface a chance to initialize, in case this
459		 * is the first address to be added.
460		 */
461		s = splimp();
462		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
463		splx(s);
464
465		if (error) {
466			switch (error) {
467			case EAFNOSUPPORT:
468				printf("%s: IPv6 not supported\n",
469					if_name(ifp));
470				break;
471			default:
472				printf("%s: SIOCSIFADDR error %d\n",
473					if_name(ifp), error);
474				break;
475			}
476
477			/* undo changes */
478#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
479			*ifap = NULL;
480#else
481			TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
482#endif
483			if (oia)
484				oia->ia_next = ia->ia_next;
485			else
486				in6_ifaddr = ia->ia_next;
487			free(ia, M_IFADDR);
488			return;
489		}
490	}
491
492	/* add route to the interface. */
493	rtrequest(RTM_ADD,
494		  (struct sockaddr *)&ia->ia_addr,
495		  (struct sockaddr *)&ia->ia_addr,
496		  (struct sockaddr *)&ia->ia_prefixmask,
497		  RTF_UP|rtflag,
498		  (struct rtentry **)0);
499	ia->ia_flags |= IFA_ROUTE;
500
501	if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
502		/*
503		 * route local address to loopback
504		 */
505		bzero(&gate, sizeof(gate));
506		gate.sin6_len = sizeof(struct sockaddr_in6);
507		gate.sin6_family = AF_INET6;
508		gate.sin6_addr = in6addr_loopback;
509		bzero(&mask, sizeof(mask));
510		mask.sin6_len = sizeof(struct sockaddr_in6);
511		mask.sin6_family = AF_INET6;
512		mask.sin6_addr = in6mask64;
513		rtrequest(RTM_ADD,
514			  (struct sockaddr *)&ia->ia_addr,
515			  (struct sockaddr *)&gate,
516			  (struct sockaddr *)&mask,
517			  RTF_UP|RTF_HOST,
518			  (struct rtentry **)0);
519	}
520
521	/*
522	 * loopback address
523	 */
524	ib = (struct in6_ifaddr *)NULL;
525	if (type == IN6_IFT_LOOP) {
526		ib = (struct in6_ifaddr *)
527			malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
528		bzero((caddr_t)ib, sizeof(*ib));
529		ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
530		ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
531		ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
532		ib->ia_ifp = ifp;
533
534		ia->ia_next = ib;
535#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
536		ia->ia_ifa.ifa_next = (struct ifaddr *)ib;
537#else
538		TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
539			ifa_list);
540#endif
541
542		ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
543		ib->ia_prefixmask.sin6_family = AF_INET6;
544		ib->ia_prefixmask.sin6_addr = in6mask128;
545		ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
546		ib->ia_addr.sin6_family = AF_INET6;
547		ib->ia_addr.sin6_addr = in6addr_loopback;
548#ifdef __bsdi__
549		/*
550		 * It is necessary to set the loopback address to the dstaddr
551		 * field at least for BSDI. Without this setting, the BSDI
552		 * version of ifa_ifwithroute() rejects to add a route
553		 * to the loopback interface.
554		 */
555		ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
556		ib->ia_dstaddr.sin6_family = AF_INET6;
557		ib->ia_dstaddr.sin6_addr = in6addr_loopback;
558#endif
559
560		ib->ia_ifa.ifa_metric = ifp->if_metric;
561
562		rtrequest(RTM_ADD,
563			  (struct sockaddr *)&ib->ia_addr,
564			  (struct sockaddr *)&ib->ia_addr,
565			  (struct sockaddr *)&ib->ia_prefixmask,
566			  RTF_UP|RTF_HOST,
567			  (struct rtentry **)0);
568
569		ib->ia_flags |= IFA_ROUTE;
570	}
571
572	/*
573	 * join multicast
574	 */
575	if (ifp->if_flags & IFF_MULTICAST) {
576		int error;	/* not used */
577
578#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
579		/* Restore saved multicast addresses(if any). */
580		in6_restoremkludge(ia, ifp);
581#endif
582
583		bzero(&mltmask, sizeof(mltmask));
584		mltmask.sin6_len = sizeof(struct sockaddr_in6);
585		mltmask.sin6_family = AF_INET6;
586		mltmask.sin6_addr = in6mask32;
587
588		/*
589		 * join link-local all-nodes address
590		 */
591		bzero(&mltaddr, sizeof(mltaddr));
592		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
593		mltaddr.sin6_family = AF_INET6;
594		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
595		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
596		rtrequest(RTM_ADD,
597			  (struct sockaddr *)&mltaddr,
598			  (struct sockaddr *)&ia->ia_addr,
599			  (struct sockaddr *)&mltmask,
600			  RTF_UP|RTF_CLONING,  /* xxx */
601			  (struct rtentry **)0);
602		(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
603
604		if (type == IN6_IFT_LOOP) {
605			/*
606			 * join node-local all-nodes address
607			 */
608			mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
609			rtrequest(RTM_ADD,
610				  (struct sockaddr *)&mltaddr,
611				  (struct sockaddr *)&ib->ia_addr,
612				  (struct sockaddr *)&mltmask,
613				  RTF_UP,
614				  (struct rtentry **)0);
615			(void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
616		} else {
617			/*
618			 * join solicited multicast address
619			 */
620			bzero(&llsol, sizeof(llsol));
621			llsol.s6_addr16[0] = htons(0xff02);
622			llsol.s6_addr16[1] = htons(ifp->if_index);
623			llsol.s6_addr32[1] = 0;
624			llsol.s6_addr32[2] = htonl(1);
625			llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
626			llsol.s6_addr8[12] = 0xff;
627			(void)in6_addmulti(&llsol, ifp, &error);
628		}
629	}
630
631	/* update dynamically. */
632	if (in6_maxmtu < ifp->if_mtu)
633		in6_maxmtu = ifp->if_mtu;
634
635	if (in6_ifstat[ifp->if_index] == NULL) {
636		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
637			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
638		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
639	}
640	if (icmp6_ifstat[ifp->if_index] == NULL) {
641		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
642			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
643		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
644	}
645
646	/* initialize NDP variables */
647	nd6_ifattach(ifp);
648
649	/* mark the address TENTATIVE, if needed. */
650	switch (ifp->if_type) {
651	case IFT_ARCNET:
652	case IFT_ETHER:
653	case IFT_FDDI:
654#if 0
655	case IFT_ATM:
656	case IFT_SLIP:
657	case IFT_PPP:
658#endif
659		ia->ia6_flags |= IN6_IFF_TENTATIVE;
660		/* nd6_dad_start() will be called in in6_if_up */
661		break;
662	case IFT_DUMMY:
663	case IFT_GIF:	/*XXX*/
664	case IFT_LOOP:
665	case IFT_FAITH:
666	default:
667		break;
668	}
669
670	return;
671}
672
673void
674in6_ifdetach(ifp)
675	struct ifnet *ifp;
676{
677	struct in6_ifaddr *ia, *oia;
678	struct ifaddr *ifa;
679#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
680	struct ifaddr *ifaprev = NULL;
681#endif
682	struct rtentry *rt;
683	short rtflags;
684
685#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
686	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
687#else
688	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
689#endif
690	{
691		if (ifa->ifa_addr->sa_family != AF_INET6
692		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
693#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
694			ifaprev = ifa;
695#endif
696			continue;
697		}
698
699		ia = (struct in6_ifaddr *)ifa;
700
701		/* remove from the routing table */
702		if ((ia->ia_flags & IFA_ROUTE)
703		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0
704#ifdef __FreeBSD__
705				, 0UL
706#endif
707				))) {
708			rtflags = rt->rt_flags;
709			rtfree(rt);
710			rtrequest(RTM_DELETE,
711				(struct sockaddr *)&ia->ia_addr,
712				(struct sockaddr *)&ia->ia_addr,
713				(struct sockaddr *)&ia->ia_prefixmask,
714				rtflags, (struct rtentry **)0);
715		}
716
717		/* remove from the linked list */
718#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
719		if (ifaprev)
720			ifaprev->ifa_next = ifa->ifa_next;
721		else
722			ifp->if_addrlist = ifa->ifa_next;
723#else
724		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
725#endif
726
727		/* also remove from the IPv6 address chain(itojun&jinmei) */
728		oia = ia;
729		if (oia == (ia = in6_ifaddr))
730			in6_ifaddr = ia->ia_next;
731		else {
732			while (ia->ia_next && (ia->ia_next != oia))
733				ia = ia->ia_next;
734			if (ia->ia_next)
735				ia->ia_next = oia->ia_next;
736#ifdef DEBUG
737			else
738				printf("%s: didn't unlink in6ifaddr from "
739				    "list\n", if_name(ifp));
740#endif
741		}
742
743		free(ia, M_IFADDR);
744	}
745}
746