in6.c revision 240309
1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $
3053541Sshin */
3153541Sshin
32139826Simp/*-
3353541Sshin * Copyright (c) 1982, 1986, 1991, 1993
3453541Sshin *	The Regents of the University of California.  All rights reserved.
3553541Sshin *
3653541Sshin * Redistribution and use in source and binary forms, with or without
3753541Sshin * modification, are permitted provided that the following conditions
3853541Sshin * are met:
3953541Sshin * 1. Redistributions of source code must retain the above copyright
4053541Sshin *    notice, this list of conditions and the following disclaimer.
4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright
4253541Sshin *    notice, this list of conditions and the following disclaimer in the
4353541Sshin *    documentation and/or other materials provided with the distribution.
4453541Sshin * 4. Neither the name of the University nor the names of its contributors
4553541Sshin *    may be used to endorse or promote products derived from this software
4653541Sshin *    without specific prior written permission.
4753541Sshin *
4853541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4953541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5053541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5153541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5253541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5353541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5453541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5553541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5653541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5753541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5853541Sshin * SUCH DAMAGE.
5953541Sshin *
6053541Sshin *	@(#)in.c	8.2 (Berkeley) 11/15/93
6153541Sshin */
6253541Sshin
63174510Sobrien#include <sys/cdefs.h>
64174510Sobrien__FBSDID("$FreeBSD: stable/9/sys/netinet6/in6.c 240309 2012-09-10 12:02:58Z glebius $");
65174510Sobrien
66207268Skib#include "opt_compat.h"
6762587Sitojun#include "opt_inet.h"
6862587Sitojun#include "opt_inet6.h"
6962587Sitojun
7053541Sshin#include <sys/param.h>
7153541Sshin#include <sys/errno.h>
72186948Sbz#include <sys/jail.h>
7353541Sshin#include <sys/malloc.h>
7453541Sshin#include <sys/socket.h>
7553541Sshin#include <sys/socketvar.h>
7653541Sshin#include <sys/sockio.h>
7753541Sshin#include <sys/systm.h>
78164033Srwatson#include <sys/priv.h>
7953541Sshin#include <sys/proc.h>
8053541Sshin#include <sys/time.h>
8153541Sshin#include <sys/kernel.h>
8253541Sshin#include <sys/syslog.h>
8353541Sshin
8453541Sshin#include <net/if.h>
85197227Sqingli#include <net/if_var.h>
8653541Sshin#include <net/if_types.h>
8753541Sshin#include <net/route.h>
8853541Sshin#include <net/if_dl.h>
89185571Sbz#include <net/vnet.h>
9053541Sshin
9153541Sshin#include <netinet/in.h>
9253541Sshin#include <netinet/in_var.h>
93186119Sqingli#include <net/if_llatbl.h>
9453541Sshin#include <netinet/if_ether.h>
9578064Sume#include <netinet/in_systm.h>
9678064Sume#include <netinet/ip.h>
9778064Sume#include <netinet/in_pcb.h>
9853541Sshin
9962587Sitojun#include <netinet/ip6.h>
10053541Sshin#include <netinet6/ip6_var.h>
10195023Ssuz#include <netinet6/nd6.h>
10253541Sshin#include <netinet6/mld6_var.h>
10362587Sitojun#include <netinet6/ip6_mroute.h>
10453541Sshin#include <netinet6/in6_ifattach.h>
10562587Sitojun#include <netinet6/scope6_var.h>
10678064Sume#include <netinet6/in6_pcb.h>
10762587Sitojun
10853541Sshin/*
10953541Sshin * Definitions of some costant IP6 addresses.
11053541Sshin */
11162587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
11262587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
11362587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes =
11453541Sshin	IN6ADDR_NODELOCAL_ALLNODES_INIT;
11562587Sitojunconst struct in6_addr in6addr_linklocal_allnodes =
11653541Sshin	IN6ADDR_LINKLOCAL_ALLNODES_INIT;
11762587Sitojunconst struct in6_addr in6addr_linklocal_allrouters =
11853541Sshin	IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
119191672Sbmsconst struct in6_addr in6addr_linklocal_allv2routers =
120191672Sbms	IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT;
12153541Sshin
12262587Sitojunconst struct in6_addr in6mask0 = IN6MASK0;
12362587Sitojunconst struct in6_addr in6mask32 = IN6MASK32;
12462587Sitojunconst struct in6_addr in6mask64 = IN6MASK64;
12562587Sitojunconst struct in6_addr in6mask96 = IN6MASK96;
12662587Sitojunconst struct in6_addr in6mask128 = IN6MASK128;
12753541Sshin
128126552Sumeconst struct sockaddr_in6 sa6_any =
129126552Sume	{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
13078064Sume
13162587Sitojunstatic int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
13283366Sjulian	struct ifnet *, struct thread *));
13378064Sumestatic int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
134120891Sume	struct sockaddr_in6 *, int));
135175162Sobrienstatic void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
13653541Sshin
13783934Sbrooksint	(*faithprefix_p)(struct in6_addr *);
13883934Sbrooks
139226570Sglebius#define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
140226570Sglebius#define ia62ifa(ia6)	(&((ia6)->ia_ifa))
141120891Sume
142226570Sglebiusvoid
143226570Sglebiusin6_ifaddloop(struct ifaddr *ifa)
144226570Sglebius{
145226570Sglebius	struct sockaddr_dl gateway;
146226570Sglebius	struct sockaddr_in6 mask, addr;
147226570Sglebius	struct rtentry rt;
148226570Sglebius	struct in6_ifaddr *ia;
149226570Sglebius	struct ifnet *ifp;
150226570Sglebius	struct llentry *ln;
15178064Sume
152226570Sglebius	ia = ifa2ia6(ifa);
153226570Sglebius	ifp = ifa->ifa_ifp;
154226570Sglebius	IF_AFDATA_LOCK(ifp);
155230604Sqingli	ifa->ifa_rtrequest = nd6_rtrequest;
156226570Sglebius	ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
157226570Sglebius	    LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
158226570Sglebius	IF_AFDATA_UNLOCK(ifp);
159226570Sglebius	if (ln != NULL) {
160226570Sglebius		ln->la_expire = 0;  /* for IPv6 this means permanent */
161226570Sglebius		ln->ln_state = ND6_LLINFO_REACHABLE;
162226570Sglebius		/*
163226570Sglebius		 * initialize for rtmsg generation
164226570Sglebius		 */
165226570Sglebius		bzero(&gateway, sizeof(gateway));
166226570Sglebius		gateway.sdl_len = sizeof(gateway);
167226570Sglebius		gateway.sdl_family = AF_LINK;
168226570Sglebius		gateway.sdl_nlen = 0;
169226570Sglebius		gateway.sdl_alen = 6;
170226570Sglebius		memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned,
171226570Sglebius		    sizeof(ln->ll_addr));
172226570Sglebius		LLE_WUNLOCK(ln);
173226570Sglebius	}
174226570Sglebius
175226570Sglebius	bzero(&rt, sizeof(rt));
176226570Sglebius	rt.rt_gateway = (struct sockaddr *)&gateway;
177226570Sglebius	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
178226570Sglebius	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
179226570Sglebius	rt_mask(&rt) = (struct sockaddr *)&mask;
180226570Sglebius	rt_key(&rt) = (struct sockaddr *)&addr;
181226570Sglebius	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
182232292Sbz	/* Announce arrival of local address to all FIBs. */
183226570Sglebius	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
184226570Sglebius}
185226570Sglebius
186226570Sglebiusvoid
187226570Sglebiusin6_ifremloop(struct ifaddr *ifa)
188226570Sglebius{
189226570Sglebius	struct sockaddr_dl gateway;
190226570Sglebius	struct sockaddr_in6 mask, addr;
191226570Sglebius	struct rtentry rt0;
192226570Sglebius	struct in6_ifaddr *ia;
193226570Sglebius	struct ifnet *ifp;
194226570Sglebius
195226570Sglebius	ia = ifa2ia6(ifa);
196226570Sglebius	ifp = ifa->ifa_ifp;
197226570Sglebius	IF_AFDATA_LOCK(ifp);
198226570Sglebius	lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR),
199226570Sglebius	    (struct sockaddr *)&ia->ia_addr);
200226570Sglebius	IF_AFDATA_UNLOCK(ifp);
201226570Sglebius
202226570Sglebius	/*
203226570Sglebius	 * initialize for rtmsg generation
204226570Sglebius	 */
205226570Sglebius	bzero(&gateway, sizeof(gateway));
206226570Sglebius	gateway.sdl_len = sizeof(gateway);
207226570Sglebius	gateway.sdl_family = AF_LINK;
208226570Sglebius	gateway.sdl_nlen = 0;
209226570Sglebius	gateway.sdl_alen = ifp->if_addrlen;
210226570Sglebius	bzero(&rt0, sizeof(rt0));
211226570Sglebius	rt0.rt_gateway = (struct sockaddr *)&gateway;
212226570Sglebius	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
213226570Sglebius	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
214226570Sglebius	rt_mask(&rt0) = (struct sockaddr *)&mask;
215226570Sglebius	rt_key(&rt0) = (struct sockaddr *)&addr;
216226570Sglebius	rt0.rt_flags = RTF_HOST | RTF_STATIC;
217232292Sbz	/* Announce removal of local address to all FIBs. */
218226570Sglebius	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
219226570Sglebius}
220226570Sglebius
22153541Sshinint
222171259Sdelphijin6_mask2len(struct in6_addr *mask, u_char *lim0)
22353541Sshin{
22478064Sume	int x = 0, y;
22578064Sume	u_char *lim = lim0, *p;
22653541Sshin
227120891Sume	/* ignore the scope_id part */
228120891Sume	if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
22978064Sume		lim = (u_char *)mask + sizeof(*mask);
23078064Sume	for (p = (u_char *)mask; p < lim; x++, p++) {
23178064Sume		if (*p != 0xff)
23253541Sshin			break;
23353541Sshin	}
23453541Sshin	y = 0;
23578064Sume	if (p < lim) {
23653541Sshin		for (y = 0; y < 8; y++) {
23778064Sume			if ((*p & (0x80 >> y)) == 0)
23853541Sshin				break;
23953541Sshin		}
24053541Sshin	}
24178064Sume
24278064Sume	/*
24378064Sume	 * when the limit pointer is given, do a stricter check on the
24478064Sume	 * remaining bits.
24578064Sume	 */
24678064Sume	if (p < lim) {
24778064Sume		if (y != 0 && (*p & (0x00ff >> y)) != 0)
248120856Sume			return (-1);
24978064Sume		for (p = p + 1; p < lim; p++)
25078064Sume			if (*p != 0)
251120856Sume				return (-1);
25278064Sume	}
253120891Sume
25453541Sshin	return x * 8 + y;
25553541Sshin}
25653541Sshin
257207268Skib#ifdef COMPAT_FREEBSD32
258207268Skibstruct in6_ndifreq32 {
259207268Skib        char ifname[IFNAMSIZ];
260207268Skib        uint32_t ifindex;
261207268Skib};
262207268Skib#define	SIOCGDEFIFACE32_IN6     _IOWR('i', 86, struct in6_ndifreq32)
263207268Skib#endif
264207268Skib
26553541Sshinint
266171259Sdelphijin6_control(struct socket *so, u_long cmd, caddr_t data,
267171259Sdelphij    struct ifnet *ifp, struct thread *td)
26853541Sshin{
26953541Sshin	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
27078064Sume	struct	in6_ifaddr *ia = NULL;
27153541Sshin	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
272151539Ssuz	struct sockaddr_in6 *sa6;
273164033Srwatson	int error;
27453541Sshin
27562587Sitojun	switch (cmd) {
27662587Sitojun	case SIOCGETSGCNT_IN6:
27762587Sitojun	case SIOCGETMIFCNT_IN6:
278232292Sbz		/*
279232292Sbz		 * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
280232292Sbz		 * We cannot see how that would be needed, so do not adjust the
281232292Sbz		 * KPI blindly; more likely should clean up the IPv4 variant.
282232292Sbz		 */
283166938Sbms		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
28462587Sitojun	}
28553541Sshin
286121742Sume	switch(cmd) {
287121742Sume	case SIOCAADDRCTL_POLICY:
288121742Sume	case SIOCDADDRCTL_POLICY:
289164033Srwatson		if (td != NULL) {
290164033Srwatson			error = priv_check(td, PRIV_NETINET_ADDRCTRL6);
291164033Srwatson			if (error)
292164033Srwatson				return (error);
293164033Srwatson		}
294121742Sume		return (in6_src_ioctl(cmd, data));
295121742Sume	}
296121742Sume
29762587Sitojun	if (ifp == NULL)
298120856Sume		return (EOPNOTSUPP);
29953541Sshin
30053541Sshin	switch (cmd) {
30153541Sshin	case SIOCSNDFLUSH_IN6:
30253541Sshin	case SIOCSPFXFLUSH_IN6:
30353541Sshin	case SIOCSRTRFLUSH_IN6:
30462587Sitojun	case SIOCSDEFIFACE_IN6:
30562587Sitojun	case SIOCSIFINFO_FLAGS:
306193893Scperciva	case SIOCSIFINFO_IN6:
307164033Srwatson		if (td != NULL) {
308164033Srwatson			error = priv_check(td, PRIV_NETINET_ND6);
309164033Srwatson			if (error)
310164033Srwatson				return (error);
311164033Srwatson		}
312120891Sume		/* FALLTHROUGH */
31378064Sume	case OSIOCGIFINFO_IN6:
31453541Sshin	case SIOCGIFINFO_IN6:
31553541Sshin	case SIOCGDRLST_IN6:
31653541Sshin	case SIOCGPRLST_IN6:
31753541Sshin	case SIOCGNBRINFO_IN6:
31862587Sitojun	case SIOCGDEFIFACE_IN6:
319120856Sume		return (nd6_ioctl(cmd, data, ifp));
320207268Skib
321207268Skib#ifdef COMPAT_FREEBSD32
322207268Skib	case SIOCGDEFIFACE32_IN6:
323207268Skib		{
324207268Skib			struct in6_ndifreq ndif;
325207268Skib			struct in6_ndifreq32 *ndif32;
326207268Skib
327207268Skib			error = nd6_ioctl(SIOCGDEFIFACE_IN6, (caddr_t)&ndif,
328207268Skib			    ifp);
329207268Skib			if (error)
330207268Skib				return (error);
331207268Skib			ndif32 = (struct in6_ndifreq32 *)data;
332207268Skib			ndif32->ifindex = ndif.ifindex;
333207268Skib			return (0);
334207268Skib		}
335207268Skib#endif
33653541Sshin	}
33753541Sshin
33853541Sshin	switch (cmd) {
33953541Sshin	case SIOCSIFPREFIX_IN6:
34053541Sshin	case SIOCDIFPREFIX_IN6:
34153541Sshin	case SIOCAIFPREFIX_IN6:
34253541Sshin	case SIOCCIFPREFIX_IN6:
34353541Sshin	case SIOCSGIFPREFIX_IN6:
34453541Sshin	case SIOCGIFPREFIX_IN6:
34578064Sume		log(LOG_NOTICE,
34678064Sume		    "prefix ioctls are now invalidated. "
34778064Sume		    "please use ifconfig.\n");
348120856Sume		return (EOPNOTSUPP);
34953541Sshin	}
35053541Sshin
35195023Ssuz	switch (cmd) {
35262587Sitojun	case SIOCSSCOPE6:
353164033Srwatson		if (td != NULL) {
354164033Srwatson			error = priv_check(td, PRIV_NETINET_SCOPE6);
355164033Srwatson			if (error)
356164033Srwatson				return (error);
357164033Srwatson		}
358121161Sume		return (scope6_set(ifp,
359121161Sume		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
36062587Sitojun	case SIOCGSCOPE6:
361121161Sume		return (scope6_get(ifp,
362121161Sume		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
36362587Sitojun	case SIOCGSCOPE6DEF:
364121161Sume		return (scope6_get_default((struct scope6_id *)
365121161Sume		    ifr->ifr_ifru.ifru_scope_id));
36662587Sitojun	}
36762587Sitojun
36853541Sshin	switch (cmd) {
36953541Sshin	case SIOCALIFADDR:
370175630Sbz		if (td != NULL) {
371175630Sbz			error = priv_check(td, PRIV_NET_ADDIFADDR);
372175630Sbz			if (error)
373175630Sbz				return (error);
374175630Sbz		}
375175630Sbz		return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
376175630Sbz
37753541Sshin	case SIOCDLIFADDR:
378164033Srwatson		if (td != NULL) {
379175630Sbz			error = priv_check(td, PRIV_NET_DELIFADDR);
380164033Srwatson			if (error)
381164033Srwatson				return (error);
382164033Srwatson		}
383120891Sume		/* FALLTHROUGH */
38453541Sshin	case SIOCGLIFADDR:
38583366Sjulian		return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
38653541Sshin	}
38753541Sshin
38853541Sshin	/*
38953541Sshin	 * Find address for this interface, if it exists.
390151539Ssuz	 *
391151539Ssuz	 * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
392151539Ssuz	 * only, and used the first interface address as the target of other
393151539Ssuz	 * operations (without checking ifra_addr).  This was because netinet
394151539Ssuz	 * code/API assumed at most 1 interface address per interface.
395151539Ssuz	 * Since IPv6 allows a node to assign multiple addresses
396151539Ssuz	 * on a single interface, we almost always look and check the
397151539Ssuz	 * presence of ifra_addr, and reject invalid ones here.
398151539Ssuz	 * It also decreases duplicated code among SIOC*_IN6 operations.
39953541Sshin	 */
400151539Ssuz	switch (cmd) {
401151539Ssuz	case SIOCAIFADDR_IN6:
402151539Ssuz	case SIOCSIFPHYADDR_IN6:
403151539Ssuz		sa6 = &ifra->ifra_addr;
404151539Ssuz		break;
405151539Ssuz	case SIOCSIFADDR_IN6:
406151539Ssuz	case SIOCGIFADDR_IN6:
407151539Ssuz	case SIOCSIFDSTADDR_IN6:
408151539Ssuz	case SIOCSIFNETMASK_IN6:
409151539Ssuz	case SIOCGIFDSTADDR_IN6:
410151539Ssuz	case SIOCGIFNETMASK_IN6:
411151539Ssuz	case SIOCDIFADDR_IN6:
412151539Ssuz	case SIOCGIFPSRCADDR_IN6:
413151539Ssuz	case SIOCGIFPDSTADDR_IN6:
414151539Ssuz	case SIOCGIFAFLAG_IN6:
415151539Ssuz	case SIOCSNDFLUSH_IN6:
416151539Ssuz	case SIOCSPFXFLUSH_IN6:
417151539Ssuz	case SIOCSRTRFLUSH_IN6:
418151539Ssuz	case SIOCGIFALIFETIME_IN6:
419151539Ssuz	case SIOCSIFALIFETIME_IN6:
420151539Ssuz	case SIOCGIFSTAT_IN6:
421151539Ssuz	case SIOCGIFSTAT_ICMP6:
422151539Ssuz		sa6 = &ifr->ifr_addr;
423151539Ssuz		break;
424151539Ssuz	default:
425151539Ssuz		sa6 = NULL;
426151539Ssuz		break;
427151539Ssuz	}
428151539Ssuz	if (sa6 && sa6->sin6_family == AF_INET6) {
429151539Ssuz		if (sa6->sin6_scope_id != 0)
430151539Ssuz			error = sa6_embedscope(sa6, 0);
431148385Sume		else
432151539Ssuz			error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
433148385Sume		if (error != 0)
434148385Sume			return (error);
435188144Sjamie		if (td != NULL && (error = prison_check_ip6(td->td_ucred,
436188144Sjamie		    &sa6->sin6_addr)) != 0)
437188144Sjamie			return (error);
438151539Ssuz		ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
439151539Ssuz	} else
440151539Ssuz		ia = NULL;
44153541Sshin
44253541Sshin	switch (cmd) {
44378064Sume	case SIOCSIFADDR_IN6:
44478064Sume	case SIOCSIFDSTADDR_IN6:
44578064Sume	case SIOCSIFNETMASK_IN6:
44678064Sume		/*
44778064Sume		 * Since IPv6 allows a node to assign multiple addresses
448151465Ssuz		 * on a single interface, SIOCSIFxxx ioctls are deprecated.
44978064Sume		 */
45078064Sume		/* we decided to obsolete this command (20000704) */
451194760Srwatson		error = EINVAL;
452194760Srwatson		goto out;
45353541Sshin
45453541Sshin	case SIOCDIFADDR_IN6:
45562587Sitojun		/*
45678064Sume		 * for IPv4, we look for existing in_ifaddr here to allow
457151465Ssuz		 * "ifconfig if0 delete" to remove the first IPv4 address on
458151465Ssuz		 * the interface.  For IPv6, as the spec allows multiple
459151465Ssuz		 * interface address from the day one, we consider "remove the
460151465Ssuz		 * first one" semantics to be not preferable.
46162587Sitojun		 */
462194760Srwatson		if (ia == NULL) {
463194760Srwatson			error = EADDRNOTAVAIL;
464194760Srwatson			goto out;
465194760Srwatson		}
46653541Sshin		/* FALLTHROUGH */
46753541Sshin	case SIOCAIFADDR_IN6:
46862587Sitojun		/*
46978064Sume		 * We always require users to specify a valid IPv6 address for
47078064Sume		 * the corresponding operation.
47162587Sitojun		 */
47278064Sume		if (ifra->ifra_addr.sin6_family != AF_INET6 ||
473194760Srwatson		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
474194760Srwatson			error = EAFNOSUPPORT;
475194760Srwatson			goto out;
476194760Srwatson		}
47753541Sshin
478164033Srwatson		if (td != NULL) {
479175630Sbz			error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
480175630Sbz			    PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
481164033Srwatson			if (error)
482194760Srwatson				goto out;
483164033Srwatson		}
48453541Sshin		break;
48553541Sshin
48653541Sshin	case SIOCGIFADDR_IN6:
48753541Sshin		/* This interface is basically deprecated. use SIOCGIFCONF. */
488120891Sume		/* FALLTHROUGH */
48953541Sshin	case SIOCGIFAFLAG_IN6:
49053541Sshin	case SIOCGIFNETMASK_IN6:
49153541Sshin	case SIOCGIFDSTADDR_IN6:
49253541Sshin	case SIOCGIFALIFETIME_IN6:
49353541Sshin		/* must think again about its semantics */
494194760Srwatson		if (ia == NULL) {
495194760Srwatson			error = EADDRNOTAVAIL;
496194760Srwatson			goto out;
497194760Srwatson		}
49853541Sshin		break;
499194760Srwatson
50053541Sshin	case SIOCSIFALIFETIME_IN6:
50153541Sshin	    {
50253541Sshin		struct in6_addrlifetime *lt;
50353541Sshin
504164033Srwatson		if (td != NULL) {
505164033Srwatson			error = priv_check(td, PRIV_NETINET_ALIFETIME6);
506164033Srwatson			if (error)
507194760Srwatson				goto out;
508164033Srwatson		}
509194760Srwatson		if (ia == NULL) {
510194760Srwatson			error = EADDRNOTAVAIL;
511194760Srwatson			goto out;
512194760Srwatson		}
51353541Sshin		/* sanity for overflow - beware unsigned */
51453541Sshin		lt = &ifr->ifr_ifru.ifru_lifetime;
515126552Sume		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME &&
516126552Sume		    lt->ia6t_vltime + time_second < time_second) {
517194760Srwatson			error = EINVAL;
518194760Srwatson			goto out;
51953541Sshin		}
520126552Sume		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME &&
521126552Sume		    lt->ia6t_pltime + time_second < time_second) {
522194760Srwatson			error = EINVAL;
523194760Srwatson			goto out;
52453541Sshin		}
52553541Sshin		break;
52653541Sshin	    }
52753541Sshin	}
52853541Sshin
52953541Sshin	switch (cmd) {
53053541Sshin	case SIOCGIFADDR_IN6:
53153541Sshin		ifr->ifr_addr = ia->ia_addr;
532148385Sume		if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
533194760Srwatson			goto out;
53453541Sshin		break;
53553541Sshin
53653541Sshin	case SIOCGIFDSTADDR_IN6:
537194760Srwatson		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
538194760Srwatson			error = EINVAL;
539194760Srwatson			goto out;
540194760Srwatson		}
54162587Sitojun		/*
54262587Sitojun		 * XXX: should we check if ifa_dstaddr is NULL and return
54362587Sitojun		 * an error?
54462587Sitojun		 */
54553541Sshin		ifr->ifr_dstaddr = ia->ia_dstaddr;
546148385Sume		if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0)
547194760Srwatson			goto out;
54853541Sshin		break;
54953541Sshin
55053541Sshin	case SIOCGIFNETMASK_IN6:
55153541Sshin		ifr->ifr_addr = ia->ia_prefixmask;
55253541Sshin		break;
55353541Sshin
55453541Sshin	case SIOCGIFAFLAG_IN6:
55553541Sshin		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
55653541Sshin		break;
55753541Sshin
55853541Sshin	case SIOCGIFSTAT_IN6:
559194760Srwatson		if (ifp == NULL) {
560194760Srwatson			error = EINVAL;
561194760Srwatson			goto out;
562194760Srwatson		}
563121161Sume		bzero(&ifr->ifr_ifru.ifru_stat,
564121161Sume		    sizeof(ifr->ifr_ifru.ifru_stat));
565121161Sume		ifr->ifr_ifru.ifru_stat =
566121161Sume		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
56753541Sshin		break;
56853541Sshin
56953541Sshin	case SIOCGIFSTAT_ICMP6:
570194760Srwatson		if (ifp == NULL) {
571194760Srwatson			error = EINVAL;
572194760Srwatson			goto out;
573194760Srwatson		}
574155454Sgnn		bzero(&ifr->ifr_ifru.ifru_icmp6stat,
575121161Sume		    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
576121161Sume		ifr->ifr_ifru.ifru_icmp6stat =
577121161Sume		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
57853541Sshin		break;
57953541Sshin
58053541Sshin	case SIOCGIFALIFETIME_IN6:
58153541Sshin		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
582151539Ssuz		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
583151539Ssuz			time_t maxexpire;
584151539Ssuz			struct in6_addrlifetime *retlt =
585151539Ssuz			    &ifr->ifr_ifru.ifru_lifetime;
586151539Ssuz
587151539Ssuz			/*
588151539Ssuz			 * XXX: adjust expiration time assuming time_t is
589151539Ssuz			 * signed.
590151539Ssuz			 */
591151539Ssuz			maxexpire = (-1) &
592151546Ssuz			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
593151539Ssuz			if (ia->ia6_lifetime.ia6t_vltime <
594151539Ssuz			    maxexpire - ia->ia6_updatetime) {
595151539Ssuz				retlt->ia6t_expire = ia->ia6_updatetime +
596151539Ssuz				    ia->ia6_lifetime.ia6t_vltime;
597151539Ssuz			} else
598151539Ssuz				retlt->ia6t_expire = maxexpire;
599151539Ssuz		}
600151539Ssuz		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
601151539Ssuz			time_t maxexpire;
602151539Ssuz			struct in6_addrlifetime *retlt =
603151539Ssuz			    &ifr->ifr_ifru.ifru_lifetime;
604151539Ssuz
605151539Ssuz			/*
606151539Ssuz			 * XXX: adjust expiration time assuming time_t is
607151539Ssuz			 * signed.
608151539Ssuz			 */
609151539Ssuz			maxexpire = (-1) &
610151546Ssuz			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
611151539Ssuz			if (ia->ia6_lifetime.ia6t_pltime <
612151539Ssuz			    maxexpire - ia->ia6_updatetime) {
613151539Ssuz				retlt->ia6t_preferred = ia->ia6_updatetime +
614151539Ssuz				    ia->ia6_lifetime.ia6t_pltime;
615151539Ssuz			} else
616151539Ssuz				retlt->ia6t_preferred = maxexpire;
617151539Ssuz		}
61853541Sshin		break;
61953541Sshin
62053541Sshin	case SIOCSIFALIFETIME_IN6:
62153541Sshin		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
62253541Sshin		/* for sanity */
62353541Sshin		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
62453541Sshin			ia->ia6_lifetime.ia6t_expire =
62553541Sshin				time_second + ia->ia6_lifetime.ia6t_vltime;
62653541Sshin		} else
62753541Sshin			ia->ia6_lifetime.ia6t_expire = 0;
62853541Sshin		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
62953541Sshin			ia->ia6_lifetime.ia6t_preferred =
63053541Sshin				time_second + ia->ia6_lifetime.ia6t_pltime;
63153541Sshin		} else
63253541Sshin			ia->ia6_lifetime.ia6t_preferred = 0;
63353541Sshin		break;
63453541Sshin
63578064Sume	case SIOCAIFADDR_IN6:
63678064Sume	{
637194760Srwatson		int i;
638151539Ssuz		struct nd_prefixctl pr0;
639151539Ssuz		struct nd_prefix *pr;
64078064Sume
64162587Sitojun		/*
64278064Sume		 * first, make or update the interface address structure,
64378064Sume		 * and link it to the list.
64462587Sitojun		 */
645151539Ssuz		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
646194760Srwatson			goto out;
647194760Srwatson		if (ia != NULL)
648194760Srwatson			ifa_free(&ia->ia_ifa);
649151915Ssuz		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
650151915Ssuz		    == NULL) {
651171260Sdelphij			/*
652151915Ssuz			 * this can happen when the user specify the 0 valid
653151915Ssuz			 * lifetime.
654151915Ssuz			 */
655151915Ssuz			break;
656151915Ssuz		}
65753541Sshin
65878064Sume		/*
65978064Sume		 * then, make the prefix on-link on the interface.
66078064Sume		 * XXX: we'd rather create the prefix before the address, but
66178064Sume		 * we need at least one address to install the corresponding
66278064Sume		 * interface route, so we configure the address first.
66378064Sume		 */
66478064Sume
66578064Sume		/*
66678064Sume		 * convert mask to prefix length (prefixmask has already
66778064Sume		 * been validated in in6_update_ifa().
66878064Sume		 */
66978064Sume		bzero(&pr0, sizeof(pr0));
67078064Sume		pr0.ndpr_ifp = ifp;
67178064Sume		pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
672120891Sume		    NULL);
673120891Sume		if (pr0.ndpr_plen == 128) {
67478064Sume			break;	/* we don't need to install a host route. */
675120891Sume		}
67678064Sume		pr0.ndpr_prefix = ifra->ifra_addr;
67778064Sume		/* apply the mask for safety. */
67878064Sume		for (i = 0; i < 4; i++) {
67978064Sume			pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
680120891Sume			    ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
68178064Sume		}
68278064Sume		/*
68395023Ssuz		 * XXX: since we don't have an API to set prefix (not address)
68495023Ssuz		 * lifetimes, we just use the same lifetimes as addresses.
68595023Ssuz		 * The (temporarily) installed lifetimes can be overridden by
68695023Ssuz		 * later advertised RAs (when accept_rtadv is non 0), which is
68795023Ssuz		 * an intended behavior.
68878064Sume		 */
68978064Sume		pr0.ndpr_raf_onlink = 1; /* should be configurable? */
69078064Sume		pr0.ndpr_raf_auto =
691120891Sume		    ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
69278064Sume		pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
69378064Sume		pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
69478064Sume
695120891Sume		/* add the prefix if not yet. */
69678064Sume		if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
69778064Sume			/*
69878064Sume			 * nd6_prelist_add will install the corresponding
69978064Sume			 * interface route.
70078064Sume			 */
70178064Sume			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
702194760Srwatson				goto out;
70378064Sume			if (pr == NULL) {
704120891Sume				log(LOG_ERR, "nd6_prelist_add succeeded but "
70578064Sume				    "no prefix\n");
706194760Srwatson				error = EINVAL;
707194760Srwatson				goto out;
70878064Sume			}
70978064Sume		}
71078064Sume
711151915Ssuz		/* relate the address to the prefix */
712151915Ssuz		if (ia->ia6_ndpr == NULL) {
713151915Ssuz			ia->ia6_ndpr = pr;
714151915Ssuz			pr->ndpr_refcnt++;
71578064Sume
71678064Sume			/*
717151915Ssuz			 * If this is the first autoconf address from the
718151915Ssuz			 * prefix, create a temporary address as well
719151915Ssuz			 * (when required).
72078064Sume			 */
721151915Ssuz			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
722181803Sbz			    V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) {
723151915Ssuz				int e;
724151915Ssuz				if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
725151915Ssuz					log(LOG_NOTICE, "in6_control: failed "
726151915Ssuz					    "to create a temporary address, "
727151915Ssuz					    "errno=%d\n", e);
728151915Ssuz				}
729151915Ssuz			}
73062587Sitojun		}
731151915Ssuz
732151915Ssuz		/*
733151915Ssuz		 * this might affect the status of autoconfigured addresses,
734151915Ssuz		 * that is, this address might make other addresses detached.
735151915Ssuz		 */
736151915Ssuz		pfxlist_onlink_check();
737222730Shrs		if (error == 0 && ia) {
738222730Shrs			if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
739222730Shrs				/*
740222730Shrs				 * Try to clear the flag when a new
741222730Shrs				 * IPv6 address is added onto an
742222730Shrs				 * IFDISABLED interface and it
743222730Shrs				 * succeeds.
744222730Shrs				 */
745222730Shrs				struct in6_ndireq nd;
746222730Shrs
747222730Shrs				memset(&nd, 0, sizeof(nd));
748222730Shrs				nd.ndi.flags = ND_IFINFO(ifp)->flags;
749222730Shrs				nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
750222730Shrs				if (nd6_ioctl(SIOCSIFINFO_FLAGS,
751222730Shrs				    (caddr_t)&nd, ifp) < 0)
752222730Shrs					log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
753222730Shrs					    "SIOCSIFINFO_FLAGS for -ifdisabled "
754222730Shrs					    "failed.");
755222730Shrs				/*
756222730Shrs				 * Ignore failure of clearing the flag
757222730Shrs				 * intentionally.  The failure means
758222730Shrs				 * address duplication was detected.
759222730Shrs				 */
760222730Shrs			}
761126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
762222730Shrs		}
76378064Sume		break;
76478064Sume	}
76562587Sitojun
76678064Sume	case SIOCDIFADDR_IN6:
76778064Sume	{
768151539Ssuz		struct nd_prefix *pr;
76978064Sume
77078064Sume		/*
77178064Sume		 * If the address being deleted is the only one that owns
77278064Sume		 * the corresponding prefix, expire the prefix as well.
773120891Sume		 * XXX: theoretically, we don't have to worry about such
77478064Sume		 * relationship, since we separate the address management
77578064Sume		 * and the prefix management.  We do this, however, to provide
77678064Sume		 * as much backward compatibility as possible in terms of
77778064Sume		 * the ioctl operation.
778151915Ssuz		 * Note that in6_purgeaddr() will decrement ndpr_refcnt.
77978064Sume		 */
780151915Ssuz		pr = ia->ia6_ndpr;
78178064Sume		in6_purgeaddr(&ia->ia_ifa);
782151915Ssuz		if (pr && pr->ndpr_refcnt == 0)
783151915Ssuz			prelist_remove(pr);
784126264Smlaier		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
78553541Sshin		break;
78678064Sume	}
78753541Sshin
78878064Sume	default:
789194760Srwatson		if (ifp == NULL || ifp->if_ioctl == 0) {
790194760Srwatson			error = EOPNOTSUPP;
791194760Srwatson			goto out;
792194760Srwatson		}
793194760Srwatson		error = (*ifp->if_ioctl)(ifp, cmd, data);
794194760Srwatson		goto out;
79578064Sume	}
79653541Sshin
797194760Srwatson	error = 0;
798194760Srwatsonout:
799194760Srwatson	if (ia != NULL)
800194760Srwatson		ifa_free(&ia->ia_ifa);
801194760Srwatson	return (error);
80278064Sume}
80353541Sshin
804232292Sbz
80578064Sume/*
806232292Sbz * Join necessary multicast groups.  Factored out from in6_update_ifa().
807232292Sbz * This entire work should only be done once, for the default FIB.
808232292Sbz */
809232292Sbzstatic int
810232292Sbzin6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
811232292Sbz    struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
812232292Sbz{
813232292Sbz	char ip6buf[INET6_ADDRSTRLEN];
814232292Sbz	struct sockaddr_in6 mltaddr, mltmask;
815232292Sbz	struct in6_addr llsol;
816232292Sbz	struct in6_multi_mship *imm;
817232292Sbz	struct rtentry *rt;
818232292Sbz	int delay, error;
819232292Sbz
820232292Sbz	KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
821232292Sbz
822232292Sbz	/* Join solicited multicast addr for new host id. */
823232292Sbz	bzero(&llsol, sizeof(struct in6_addr));
824232292Sbz	llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
825232292Sbz	llsol.s6_addr32[1] = 0;
826232292Sbz	llsol.s6_addr32[2] = htonl(1);
827232292Sbz	llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
828232292Sbz	llsol.s6_addr8[12] = 0xff;
829232292Sbz	if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
830232292Sbz		/* XXX: should not happen */
831232292Sbz		log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
832232292Sbz		goto cleanup;
833232292Sbz	}
834232292Sbz	delay = 0;
835232292Sbz	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
836232292Sbz		/*
837232292Sbz		 * We need a random delay for DAD on the address being
838232292Sbz		 * configured.  It also means delaying transmission of the
839232292Sbz		 * corresponding MLD report to avoid report collision.
840232292Sbz		 * [RFC 4861, Section 6.3.7]
841232292Sbz		 */
842232292Sbz		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
843232292Sbz	}
844232292Sbz	imm = in6_joingroup(ifp, &llsol, &error, delay);
845232292Sbz	if (imm == NULL) {
846232292Sbz		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
847232292Sbz		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
848232292Sbz		    if_name(ifp), error));
849232292Sbz		goto cleanup;
850232292Sbz	}
851232292Sbz	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
852232292Sbz	*in6m_sol = imm->i6mm_maddr;
853232292Sbz
854232292Sbz	bzero(&mltmask, sizeof(mltmask));
855232292Sbz	mltmask.sin6_len = sizeof(struct sockaddr_in6);
856232292Sbz	mltmask.sin6_family = AF_INET6;
857232292Sbz	mltmask.sin6_addr = in6mask32;
858232292Sbz#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
859232292Sbz
860232292Sbz	/*
861232292Sbz	 * Join link-local all-nodes address.
862232292Sbz	 */
863232292Sbz	bzero(&mltaddr, sizeof(mltaddr));
864232292Sbz	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
865232292Sbz	mltaddr.sin6_family = AF_INET6;
866232292Sbz	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
867232292Sbz	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
868232292Sbz		goto cleanup; /* XXX: should not fail */
869232292Sbz
870232292Sbz	/*
871232292Sbz	 * XXX: do we really need this automatic routes?  We should probably
872232292Sbz	 * reconsider this stuff.  Most applications actually do not need the
873232292Sbz	 * routes, since they usually specify the outgoing interface.
874232292Sbz	 */
875232292Sbz	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
876232292Sbz	if (rt != NULL) {
877232292Sbz		/* XXX: only works in !SCOPEDROUTING case. */
878232292Sbz		if (memcmp(&mltaddr.sin6_addr,
879232292Sbz		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
880232292Sbz		    MLTMASK_LEN)) {
881232292Sbz			RTFREE_LOCKED(rt);
882232292Sbz			rt = NULL;
883232292Sbz		}
884232292Sbz	}
885232292Sbz	if (rt == NULL) {
886232292Sbz		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
887232292Sbz		    (struct sockaddr *)&ia->ia_addr,
888232292Sbz		    (struct sockaddr *)&mltmask, RTF_UP,
889232292Sbz		    (struct rtentry **)0, RT_DEFAULT_FIB);
890232292Sbz		if (error)
891232292Sbz			goto cleanup;
892232292Sbz	} else
893232292Sbz		RTFREE_LOCKED(rt);
894232292Sbz
895232292Sbz	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
896232292Sbz	if (imm == NULL) {
897232292Sbz		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
898232292Sbz		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
899232292Sbz		    &mltaddr.sin6_addr), if_name(ifp), error));
900232292Sbz		goto cleanup;
901232292Sbz	}
902232292Sbz	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
903232292Sbz
904232292Sbz	/*
905232292Sbz	 * Join node information group address.
906232292Sbz	 */
907232292Sbz	delay = 0;
908232292Sbz	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
909232292Sbz		/*
910232292Sbz		 * The spec does not say anything about delay for this group,
911232292Sbz		 * but the same logic should apply.
912232292Sbz		 */
913232292Sbz		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
914232292Sbz	}
915232292Sbz	if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
916232292Sbz		/* XXX jinmei */
917232292Sbz		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
918232292Sbz		if (imm == NULL)
919232292Sbz			nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
920232292Sbz			    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
921232292Sbz			    &mltaddr.sin6_addr), if_name(ifp), error));
922232292Sbz			/* XXX not very fatal, go on... */
923232292Sbz		else
924232292Sbz			LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
925232292Sbz	}
926232292Sbz
927232292Sbz	/*
928232292Sbz	 * Join interface-local all-nodes address.
929232292Sbz	 * (ff01::1%ifN, and ff01::%ifN/32)
930232292Sbz	 */
931232292Sbz	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
932232292Sbz	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
933232292Sbz		goto cleanup; /* XXX: should not fail */
934232292Sbz	/* XXX: again, do we really need the route? */
935232292Sbz	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
936232292Sbz	if (rt != NULL) {
937232292Sbz		if (memcmp(&mltaddr.sin6_addr,
938232292Sbz		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
939232292Sbz		    MLTMASK_LEN)) {
940232292Sbz			RTFREE_LOCKED(rt);
941232292Sbz			rt = NULL;
942232292Sbz		}
943232292Sbz	}
944232292Sbz	if (rt == NULL) {
945232292Sbz		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
946232292Sbz		    (struct sockaddr *)&ia->ia_addr,
947232292Sbz		    (struct sockaddr *)&mltmask, RTF_UP,
948232292Sbz		    (struct rtentry **)0, RT_DEFAULT_FIB);
949232292Sbz		if (error)
950232292Sbz			goto cleanup;
951232292Sbz	} else
952232292Sbz		RTFREE_LOCKED(rt);
953232292Sbz
954232292Sbz	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
955232292Sbz	if (imm == NULL) {
956232292Sbz		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
957232292Sbz		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
958232292Sbz		    &mltaddr.sin6_addr), if_name(ifp), error));
959232292Sbz		goto cleanup;
960232292Sbz	}
961232292Sbz	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
962232292Sbz#undef	MLTMASK_LEN
963232292Sbz
964232292Sbzcleanup:
965232292Sbz	return (error);
966232292Sbz}
967232292Sbz
968232292Sbz/*
96978064Sume * Update parameters of an IPv6 interface address.
97078064Sume * If necessary, a new entry is created and linked into address chains.
97178064Sume * This function is separated from in6_control().
97278064Sume * XXX: should this be performed under splnet()?
97378064Sume */
97478064Sumeint
975171259Sdelphijin6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
976171259Sdelphij    struct in6_ifaddr *ia, int flags)
97778064Sume{
97878064Sume	int error = 0, hostIsNew = 0, plen = -1;
97978064Sume	struct sockaddr_in6 dst6;
98078064Sume	struct in6_addrlifetime *lt;
981151539Ssuz	struct in6_multi *in6m_sol;
982151539Ssuz	int delay;
983165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
98478064Sume
98578064Sume	/* Validate parameters */
98678064Sume	if (ifp == NULL || ifra == NULL) /* this maybe redundant */
987120856Sume		return (EINVAL);
98878064Sume
98978064Sume	/*
99078064Sume	 * The destination address for a p2p link must have a family
99178064Sume	 * of AF_UNSPEC or AF_INET6.
99278064Sume	 */
99378064Sume	if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
99478064Sume	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
99578064Sume	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
996120856Sume		return (EAFNOSUPPORT);
99778064Sume	/*
99878064Sume	 * validate ifra_prefixmask.  don't check sin6_family, netmask
99978064Sume	 * does not carry fields other than sin6_len.
100078064Sume	 */
100178064Sume	if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
1002120856Sume		return (EINVAL);
100378064Sume	/*
100478064Sume	 * Because the IPv6 address architecture is classless, we require
100578064Sume	 * users to specify a (non 0) prefix length (mask) for a new address.
100678064Sume	 * We also require the prefix (when specified) mask is valid, and thus
100778064Sume	 * reject a non-consecutive mask.
100878064Sume	 */
100978064Sume	if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
1010120856Sume		return (EINVAL);
101178064Sume	if (ifra->ifra_prefixmask.sin6_len != 0) {
101278064Sume		plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
1013120891Sume		    (u_char *)&ifra->ifra_prefixmask +
1014120891Sume		    ifra->ifra_prefixmask.sin6_len);
101578064Sume		if (plen <= 0)
1016120856Sume			return (EINVAL);
1017120891Sume	} else {
101862587Sitojun		/*
101995023Ssuz		 * In this case, ia must not be NULL.  We just use its prefix
102078064Sume		 * length.
102162587Sitojun		 */
102278064Sume		plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
102378064Sume	}
102478064Sume	/*
102578064Sume	 * If the destination address on a p2p interface is specified,
102678064Sume	 * and the address is a scoped one, validate/set the scope
102778064Sume	 * zone identifier.
102878064Sume	 */
102978064Sume	dst6 = ifra->ifra_dstaddr;
1030120891Sume	if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 &&
103178064Sume	    (dst6.sin6_family == AF_INET6)) {
1032148385Sume		struct in6_addr in6_tmp;
1033126552Sume		u_int32_t zoneid;
103478064Sume
1035148385Sume		in6_tmp = dst6.sin6_addr;
1036148385Sume		if (in6_setscope(&in6_tmp, ifp, &zoneid))
1037148385Sume			return (EINVAL); /* XXX: should be impossible */
1038148385Sume
1039148385Sume		if (dst6.sin6_scope_id != 0) {
1040148385Sume			if (dst6.sin6_scope_id != zoneid)
1041148385Sume				return (EINVAL);
1042148385Sume		} else		/* user omit to specify the ID. */
1043126552Sume			dst6.sin6_scope_id = zoneid;
1044148385Sume
1045148385Sume		/* convert into the internal form */
1046148385Sume		if (sa6_embedscope(&dst6, 0))
1047148385Sume			return (EINVAL); /* XXX: should be impossible */
104878064Sume	}
104978064Sume	/*
105078064Sume	 * The destination address can be specified only for a p2p or a
105178064Sume	 * loopback interface.  If specified, the corresponding prefix length
105278064Sume	 * must be 128.
105378064Sume	 */
105478064Sume	if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
105578064Sume		if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
1056126552Sume			/* XXX: noisy message */
1057122059Sume			nd6log((LOG_INFO, "in6_update_ifa: a destination can "
1058122059Sume			    "be specified for a p2p or a loopback IF only\n"));
1059120856Sume			return (EINVAL);
106078064Sume		}
106178064Sume		if (plen != 128) {
1062122059Sume			nd6log((LOG_INFO, "in6_update_ifa: prefixlen should "
1063122059Sume			    "be 128 when dstaddr is specified\n"));
1064120856Sume			return (EINVAL);
106578064Sume		}
106678064Sume	}
106778064Sume	/* lifetime consistency check */
106878064Sume	lt = &ifra->ifra_lifetime;
1069151539Ssuz	if (lt->ia6t_pltime > lt->ia6t_vltime)
1070151539Ssuz		return (EINVAL);
107178064Sume	if (lt->ia6t_vltime == 0) {
107262587Sitojun		/*
107378064Sume		 * the following log might be noisy, but this is a typical
107478064Sume		 * configuration mistake or a tool's bug.
107562587Sitojun		 */
1076122059Sume		nd6log((LOG_INFO,
107778064Sume		    "in6_update_ifa: valid lifetime is 0 for %s\n",
1078165118Sbz		    ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr)));
1079151539Ssuz
1080151539Ssuz		if (ia == NULL)
1081151539Ssuz			return (0); /* there's nothing to do */
108278064Sume	}
108362587Sitojun
108478064Sume	/*
108578064Sume	 * If this is a new address, allocate a new ifaddr and link it
108678064Sume	 * into chains.
108778064Sume	 */
108878064Sume	if (ia == NULL) {
108978064Sume		hostIsNew = 1;
109079763Sume		/*
109179763Sume		 * When in6_update_ifa() is called in a process of a received
1092120891Sume		 * RA, it is called under an interrupt context.  So, we should
1093120891Sume		 * call malloc with M_NOWAIT.
109479763Sume		 */
1095120891Sume		ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR,
1096120891Sume		    M_NOWAIT);
109778064Sume		if (ia == NULL)
109878064Sume			return (ENOBUFS);
109978064Sume		bzero((caddr_t)ia, sizeof(*ia));
1100194602Srwatson		ifa_init(&ia->ia_ifa);
1101170202Sjinmei		LIST_INIT(&ia->ia6_memberships);
1102151539Ssuz		/* Initialize the address and masks, and put time stamp */
110378064Sume		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
110478064Sume		ia->ia_addr.sin6_family = AF_INET6;
110578064Sume		ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
1106151539Ssuz		ia->ia6_createtime = time_second;
110778064Sume		if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
110878064Sume			/*
110978064Sume			 * XXX: some functions expect that ifa_dstaddr is not
111078064Sume			 * NULL for p2p interfaces.
111178064Sume			 */
1112120891Sume			ia->ia_ifa.ifa_dstaddr =
1113120891Sume			    (struct sockaddr *)&ia->ia_dstaddr;
111478064Sume		} else {
111578064Sume			ia->ia_ifa.ifa_dstaddr = NULL;
111653541Sshin		}
1117108033Shsu		ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
111878064Sume		ia->ia_ifp = ifp;
1119194760Srwatson		ifa_ref(&ia->ia_ifa);			/* if_addrhead */
1120233200Sjhb		IF_ADDR_WLOCK(ifp);
1121191340Srwatson		TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
1122233200Sjhb		IF_ADDR_WUNLOCK(ifp);
1123194907Srwatson
1124194971Srwatson		ifa_ref(&ia->ia_ifa);			/* in6_ifaddrhead */
1125194971Srwatson		IN6_IFADDR_WLOCK();
1126194907Srwatson		TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
1127194971Srwatson		IN6_IFADDR_WUNLOCK();
112878064Sume	}
112978064Sume
1130151539Ssuz	/* update timestamp */
1131151539Ssuz	ia->ia6_updatetime = time_second;
1132151539Ssuz
113378064Sume	/* set prefix mask */
113478064Sume	if (ifra->ifra_prefixmask.sin6_len) {
113578064Sume		/*
113678064Sume		 * We prohibit changing the prefix length of an existing
113778064Sume		 * address, because
113878064Sume		 * + such an operation should be rare in IPv6, and
113978064Sume		 * + the operation would confuse prefix management.
114078064Sume		 */
114178064Sume		if (ia->ia_prefixmask.sin6_len &&
114278064Sume		    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
1143122059Sume			nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an"
114478064Sume			    " existing (%s) address should not be changed\n",
1145165118Sbz			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
114678064Sume			error = EINVAL;
114778064Sume			goto unlink;
114853541Sshin		}
114978064Sume		ia->ia_prefixmask = ifra->ifra_prefixmask;
115078064Sume	}
115178064Sume
115278064Sume	/*
115378064Sume	 * If a new destination address is specified, scrub the old one and
115478064Sume	 * install the new destination.  Note that the interface must be
1155120891Sume	 * p2p or loopback (see the check above.)
115678064Sume	 */
115778064Sume	if (dst6.sin6_family == AF_INET6 &&
1158120891Sume	    !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
115978064Sume		int e;
116078064Sume
116178064Sume		if ((ia->ia_flags & IFA_ROUTE) != 0 &&
1162120891Sume		    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) {
1163122059Sume			nd6log((LOG_ERR, "in6_update_ifa: failed to remove "
116478064Sume			    "a route to the old destination: %s\n",
1165165118Sbz			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
116678064Sume			/* proceed anyway... */
1167120891Sume		} else
116878064Sume			ia->ia_flags &= ~IFA_ROUTE;
116978064Sume		ia->ia_dstaddr = dst6;
117078064Sume	}
117153541Sshin
1172148385Sume	/*
1173148385Sume	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
1174148385Sume	 * to see if the address is deprecated or invalidated, but initialize
1175148385Sume	 * these members for applications.
1176148385Sume	 */
1177148385Sume	ia->ia6_lifetime = ifra->ifra_lifetime;
1178148385Sume	if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
1179148385Sume		ia->ia6_lifetime.ia6t_expire =
1180148385Sume		    time_second + ia->ia6_lifetime.ia6t_vltime;
1181148385Sume	} else
1182148385Sume		ia->ia6_lifetime.ia6t_expire = 0;
1183148385Sume	if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
1184148385Sume		ia->ia6_lifetime.ia6t_preferred =
1185148385Sume		    time_second + ia->ia6_lifetime.ia6t_pltime;
1186148385Sume	} else
1187148385Sume		ia->ia6_lifetime.ia6t_preferred = 0;
1188148385Sume
118978064Sume	/* reset the interface and routing table appropriately. */
119078064Sume	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
119178064Sume		goto unlink;
119278064Sume
119378064Sume	/*
1194148385Sume	 * configure address flags.
1195148385Sume	 */
1196148385Sume	ia->ia6_flags = ifra->ifra_flags;
1197148385Sume	/*
1198148385Sume	 * backward compatibility - if IN6_IFF_DEPRECATED is set from the
1199148385Sume	 * userland, make it deprecated.
1200148385Sume	 */
1201148385Sume	if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
1202148385Sume		ia->ia6_lifetime.ia6t_pltime = 0;
1203148385Sume		ia->ia6_lifetime.ia6t_preferred = time_second;
1204148385Sume	}
1205148385Sume	/*
1206151539Ssuz	 * Make the address tentative before joining multicast addresses,
1207151539Ssuz	 * so that corresponding MLD responses would not have a tentative
1208151539Ssuz	 * source address.
1209148385Sume	 */
1210151539Ssuz	ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/* safety */
1211151539Ssuz	if (hostIsNew && in6if_do_dad(ifp))
1212148385Sume		ia->ia6_flags |= IN6_IFF_TENTATIVE;
1213148385Sume
1214197138Shrs	/* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */
1215197138Shrs	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
1216197138Shrs		ia->ia6_flags |= IN6_IFF_TENTATIVE;
1217197138Shrs
1218148385Sume	/*
1219148385Sume	 * We are done if we have simply modified an existing address.
1220148385Sume	 */
1221148385Sume	if (!hostIsNew)
1222148385Sume		return (error);
1223148385Sume
1224148385Sume	/*
122578064Sume	 * Beyond this point, we should call in6_purgeaddr upon an error,
1226120891Sume	 * not just go to unlink.
122778064Sume	 */
122878064Sume
1229232292Sbz	/* Join necessary multicast groups. */
1230151539Ssuz	in6m_sol = NULL;
123178064Sume	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
1232232292Sbz		error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
1233232292Sbz		if (error)
1234148385Sume			goto cleanup;
123578064Sume	}
123653541Sshin
1237151539Ssuz	/*
1238151539Ssuz	 * Perform DAD, if needed.
1239232292Sbz	 * XXX It may be of use, if we can administratively disable DAD.
1240151539Ssuz	 */
1241194760Srwatson	if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
1242151539Ssuz	    (ia->ia6_flags & IN6_IFF_TENTATIVE))
1243151539Ssuz	{
1244151539Ssuz		int mindelay, maxdelay;
1245151539Ssuz
1246151539Ssuz		delay = 0;
1247151539Ssuz		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1248151539Ssuz			/*
1249151539Ssuz			 * We need to impose a delay before sending an NS
1250151539Ssuz			 * for DAD.  Check if we also needed a delay for the
1251151539Ssuz			 * corresponding MLD message.  If we did, the delay
1252151539Ssuz			 * should be larger than the MLD delay (this could be
1253151539Ssuz			 * relaxed a bit, but this simple logic is at least
1254151539Ssuz			 * safe).
1255191672Sbms			 * XXX: Break data hiding guidelines and look at
1256191672Sbms			 * state for the solicited multicast group.
1257151539Ssuz			 */
1258151539Ssuz			mindelay = 0;
1259151539Ssuz			if (in6m_sol != NULL &&
1260191672Sbms			    in6m_sol->in6m_state == MLD_REPORTING_MEMBER) {
1261151539Ssuz				mindelay = in6m_sol->in6m_timer;
1262151539Ssuz			}
1263151539Ssuz			maxdelay = MAX_RTR_SOLICITATION_DELAY * hz;
1264151539Ssuz			if (maxdelay - mindelay == 0)
1265151539Ssuz				delay = 0;
1266151539Ssuz			else {
1267151539Ssuz				delay =
1268151539Ssuz				    (arc4random() % (maxdelay - mindelay)) +
1269151539Ssuz				    mindelay;
1270151539Ssuz			}
1271151539Ssuz		}
1272151539Ssuz		nd6_dad_start((struct ifaddr *)ia, delay);
1273151539Ssuz	}
1274151539Ssuz
1275194760Srwatson	KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew"));
1276194760Srwatson	ifa_free(&ia->ia_ifa);
1277120856Sume	return (error);
127878064Sume
127978064Sume  unlink:
128078064Sume	/*
128178064Sume	 * XXX: if a change of an existing address failed, keep the entry
128278064Sume	 * anyway.
128378064Sume	 */
1284194760Srwatson	if (hostIsNew) {
1285194943Srwatson		in6_unlink_ifa(ia, ifp);
1286194760Srwatson		ifa_free(&ia->ia_ifa);
1287194760Srwatson	}
1288120856Sume	return (error);
1289148385Sume
1290148385Sume  cleanup:
1291194760Srwatson	KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew"));
1292194760Srwatson	ifa_free(&ia->ia_ifa);
1293148385Sume	in6_purgeaddr(&ia->ia_ifa);
1294148385Sume	return error;
129553541Sshin}
129653541Sshin
1297232292Sbz/*
1298232292Sbz * Leave multicast groups.  Factored out from in6_purgeaddr().
1299232292Sbz * This entire work should only be done once, for the default FIB.
1300232292Sbz */
1301232292Sbzstatic int
1302232292Sbzin6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
130362587Sitojun{
1304232292Sbz	struct sockaddr_in6 mltaddr, mltmask;
1305170202Sjinmei	struct in6_multi_mship *imm;
1306192282Sqingli	struct rtentry *rt;
1307237945Sdelphij	struct sockaddr_in6 sin6;
1308232292Sbz	int error;
130962587Sitojun
1310192282Sqingli	/*
1311232292Sbz	 * Leave from multicast groups we have joined for the interface.
1312192282Sqingli	 */
1313233046Sjhb	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
1314170202Sjinmei		LIST_REMOVE(imm, i6mm_chain);
1315170202Sjinmei		in6_leavegroup(imm);
131662587Sitojun	}
131762587Sitojun
1318192282Sqingli	/*
1319232292Sbz	 * Remove the link-local all-nodes address.
1320192282Sqingli	 */
1321192282Sqingli	bzero(&mltmask, sizeof(mltmask));
1322192282Sqingli	mltmask.sin6_len = sizeof(struct sockaddr_in6);
1323192282Sqingli	mltmask.sin6_family = AF_INET6;
1324192282Sqingli	mltmask.sin6_addr = in6mask32;
1325192282Sqingli
1326192282Sqingli	bzero(&mltaddr, sizeof(mltaddr));
1327192282Sqingli	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
1328192282Sqingli	mltaddr.sin6_family = AF_INET6;
1329192282Sqingli	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
1330192282Sqingli
1331231319Sbz	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
1332232292Sbz		return (error);
1333192282Sqingli
1334237945Sdelphij	/*
1335237945Sdelphij	 * As for the mltaddr above, proactively prepare the sin6 to avoid
1336237945Sdelphij	 * rtentry un- and re-locking.
1337237945Sdelphij	 */
1338237945Sdelphij	if (ifa0 != NULL) {
1339237945Sdelphij		bzero(&sin6, sizeof(sin6));
1340237945Sdelphij		sin6.sin6_len = sizeof(sin6);
1341237945Sdelphij		sin6.sin6_family = AF_INET6;
1342237945Sdelphij		memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
1343237945Sdelphij		    sizeof(sin6.sin6_addr));
1344238476Sbz		error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL);
1345238476Sbz		if (error != 0)
1346238476Sbz			return (error);
1347237945Sdelphij	}
1348237945Sdelphij
1349232292Sbz	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
1350192282Sqingli	if (rt != NULL && rt->rt_gateway != NULL &&
1351192282Sqingli	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
1352192282Sqingli		    &ia->ia_addr.sin6_addr,
1353192282Sqingli		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
1354192282Sqingli		/*
1355232292Sbz		 * If no more IPv6 address exists on this interface then
1356232292Sbz		 * remove the multicast address route.
1357192282Sqingli		 */
1358192282Sqingli		if (ifa0 == NULL) {
1359192282Sqingli			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
1360192282Sqingli			       sizeof(mltaddr.sin6_addr));
1361192282Sqingli			RTFREE_LOCKED(rt);
1362232292Sbz			error = in6_rtrequest(RTM_DELETE,
1363232292Sbz			    (struct sockaddr *)&mltaddr,
1364232292Sbz			    (struct sockaddr *)&ia->ia_addr,
1365232292Sbz			    (struct sockaddr *)&mltmask, RTF_UP,
1366232292Sbz			    (struct rtentry **)0, RT_DEFAULT_FIB);
1367192282Sqingli			if (error)
1368232292Sbz				log(LOG_INFO, "%s: link-local all-nodes "
1369232292Sbz				    "multicast address deletion error\n",
1370232292Sbz				    __func__);
1371192282Sqingli		} else {
1372192282Sqingli			/*
1373232292Sbz			 * Replace the gateway of the route.
1374192282Sqingli			 */
1375237945Sdelphij			memcpy(rt->rt_gateway, &sin6, sizeof(sin6));
1376192282Sqingli			RTFREE_LOCKED(rt);
1377192282Sqingli		}
1378192282Sqingli	} else {
1379192282Sqingli		if (rt != NULL)
1380192282Sqingli			RTFREE_LOCKED(rt);
1381192282Sqingli	}
1382192282Sqingli
1383192282Sqingli	/*
1384232292Sbz	 * Remove the node-local all-nodes address.
1385192282Sqingli	 */
1386192282Sqingli	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
1387232292Sbz	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
1388232292Sbz		return (error);
1389192282Sqingli
1390232292Sbz	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
1391192282Sqingli	if (rt != NULL && rt->rt_gateway != NULL &&
1392192282Sqingli	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
1393192282Sqingli		    &ia->ia_addr.sin6_addr,
1394192282Sqingli		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
1395192282Sqingli		/*
1396232292Sbz		 * If no more IPv6 address exists on this interface then
1397232292Sbz		 * remove the multicast address route.
1398192282Sqingli		 */
1399192282Sqingli		if (ifa0 == NULL) {
1400192282Sqingli			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
1401192282Sqingli			       sizeof(mltaddr.sin6_addr));
1402192282Sqingli
1403192282Sqingli			RTFREE_LOCKED(rt);
1404232292Sbz			error = in6_rtrequest(RTM_DELETE,
1405232292Sbz			    (struct sockaddr *)&mltaddr,
1406232292Sbz			    (struct sockaddr *)&ia->ia_addr,
1407232292Sbz			    (struct sockaddr *)&mltmask, RTF_UP,
1408232292Sbz			    (struct rtentry **)0, RT_DEFAULT_FIB);
1409192282Sqingli			if (error)
1410232292Sbz				log(LOG_INFO, "%s: node-local all-nodes"
1411232292Sbz				    "multicast address deletion error\n",
1412232292Sbz				    __func__);
1413192282Sqingli		} else {
1414192282Sqingli			/*
1415232292Sbz			 * Replace the gateway of the route.
1416192282Sqingli			 */
1417237945Sdelphij			memcpy(rt->rt_gateway, &sin6, sizeof(sin6));
1418192282Sqingli			RTFREE_LOCKED(rt);
1419192282Sqingli		}
1420192282Sqingli	} else {
1421192282Sqingli		if (rt != NULL)
1422192282Sqingli			RTFREE_LOCKED(rt);
1423192282Sqingli	}
1424192282Sqingli
1425232292Sbz	return (0);
1426232292Sbz}
1427232292Sbz
1428232292Sbzvoid
1429232292Sbzin6_purgeaddr(struct ifaddr *ifa)
1430232292Sbz{
1431232292Sbz	struct ifnet *ifp = ifa->ifa_ifp;
1432232292Sbz	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
1433232292Sbz	int plen, error;
1434232292Sbz	struct ifaddr *ifa0;
1435232292Sbz
1436232292Sbz	/*
1437232292Sbz	 * find another IPv6 address as the gateway for the
1438232292Sbz	 * link-local and node-local all-nodes multicast
1439232292Sbz	 * address routes
1440232292Sbz	 */
1441233200Sjhb	IF_ADDR_RLOCK(ifp);
1442232292Sbz	TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
1443232292Sbz		if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
1444232292Sbz		    memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
1445232292Sbz			   &ia->ia_addr.sin6_addr,
1446232292Sbz			   sizeof(struct in6_addr)) == 0)
1447232292Sbz			continue;
1448232292Sbz		else
1449232292Sbz			break;
1450232292Sbz	}
1451231324Sbz	if (ifa0 != NULL)
1452232292Sbz		ifa_ref(ifa0);
1453233200Sjhb	IF_ADDR_RUNLOCK(ifp);
1454232292Sbz
1455232292Sbz	/*
1456232292Sbz	 * Remove the loopback route to the interface address.
1457232292Sbz	 * The check for the current setting of "nd6_useloopback"
1458232292Sbz	 * is not needed.
1459232292Sbz	 */
1460232292Sbz	if (ia->ia_flags & IFA_RTSELF) {
1461232292Sbz		error = ifa_del_loopback_route((struct ifaddr *)ia,
1462232292Sbz				       (struct sockaddr *)&ia->ia_addr);
1463232292Sbz		if (error == 0)
1464232292Sbz			ia->ia_flags &= ~IFA_RTSELF;
1465232292Sbz	}
1466232292Sbz
1467232292Sbz	/* stop DAD processing */
1468232292Sbz	nd6_dad_stop(ifa);
1469232292Sbz
1470232292Sbz	/* Remove local address entry from lltable. */
1471232292Sbz	in6_ifremloop(ifa);
1472232292Sbz
1473232292Sbz	/* Leave multicast groups. */
1474232292Sbz	error = in6_purgeaddr_mc(ifp, ia, ifa0);
1475232292Sbz
1476232292Sbz	if (ifa0 != NULL)
1477231324Sbz		ifa_free(ifa0);
1478192282Sqingli
1479192282Sqingli	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
1480192282Sqingli	if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
1481232292Sbz		error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
1482232292Sbz		    (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0);
1483192282Sqingli		if (error != 0)
1484232292Sbz			log(LOG_INFO, "%s: err=%d, destination address delete "
1485232292Sbz			    "failed\n", __func__, error);
1486192282Sqingli		ia->ia_flags &= ~IFA_ROUTE;
1487192282Sqingli	}
1488192282Sqingli
148978064Sume	in6_unlink_ifa(ia, ifp);
149078064Sume}
149178064Sume
149278064Sumestatic void
1493171259Sdelphijin6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
149478064Sume{
149578064Sume	int	s = splnet();
149678064Sume
1497233200Sjhb	IF_ADDR_WLOCK(ifp);
1498191340Srwatson	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
1499233200Sjhb	IF_ADDR_WUNLOCK(ifp);
1500194760Srwatson	ifa_free(&ia->ia_ifa);			/* if_addrhead */
150162587Sitojun
1502195102Srwatson	/*
1503195102Srwatson	 * Defer the release of what might be the last reference to the
1504195102Srwatson	 * in6_ifaddr so that it can't be freed before the remainder of the
1505195102Srwatson	 * cleanup.
1506195102Srwatson	 */
1507194971Srwatson	IN6_IFADDR_WLOCK();
1508194907Srwatson	TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
1509194971Srwatson	IN6_IFADDR_WUNLOCK();
151062587Sitojun
151162587Sitojun	/*
1512151915Ssuz	 * Release the reference to the base prefix.  There should be a
1513151915Ssuz	 * positive reference.
151462587Sitojun	 */
1515194907Srwatson	if (ia->ia6_ndpr == NULL) {
1516151915Ssuz		nd6log((LOG_NOTICE,
1517151915Ssuz		    "in6_unlink_ifa: autoconf'ed address "
1518194907Srwatson		    "%p has no prefix\n", ia));
1519151915Ssuz	} else {
1520194907Srwatson		ia->ia6_ndpr->ndpr_refcnt--;
1521194907Srwatson		ia->ia6_ndpr = NULL;
1522151915Ssuz	}
152362587Sitojun
1524151915Ssuz	/*
1525151915Ssuz	 * Also, if the address being removed is autoconf'ed, call
1526151915Ssuz	 * pfxlist_onlink_check() since the release might affect the status of
1527171260Sdelphij	 * other (detached) addresses.
1528151915Ssuz	 */
1529194907Srwatson	if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) {
153078064Sume		pfxlist_onlink_check();
153162587Sitojun	}
1532195102Srwatson	ifa_free(&ia->ia_ifa);			/* in6_ifaddrhead */
153378064Sume	splx(s);
153462587Sitojun}
153562587Sitojun
153678064Sumevoid
1537171259Sdelphijin6_purgeif(struct ifnet *ifp)
153878064Sume{
153978064Sume	struct ifaddr *ifa, *nifa;
154078064Sume
1541191340Srwatson	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
154278064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
154378064Sume			continue;
154478064Sume		in6_purgeaddr(ifa);
154578064Sume	}
154678064Sume
154778064Sume	in6_ifdetach(ifp);
154878064Sume}
154978064Sume
155053541Sshin/*
155153541Sshin * SIOC[GAD]LIFADDR.
155262744Sgrog *	SIOCGLIFADDR: get first address. (?)
155353541Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
155453541Sshin *		get first address that matches the specified prefix.
155553541Sshin *	SIOCALIFADDR: add the specified address.
155653541Sshin *	SIOCALIFADDR with IFLR_PREFIX:
155753541Sshin *		add the specified prefix, filling hostid part from
155853541Sshin *		the first link-local address.  prefixlen must be <= 64.
155953541Sshin *	SIOCDLIFADDR: delete the specified address.
156053541Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
156153541Sshin *		delete the first address that matches the specified prefix.
156253541Sshin * return values:
156353541Sshin *	EINVAL on invalid parameters
156453541Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
156553541Sshin *	other values may be returned from in6_ioctl()
156653541Sshin *
156753541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
156853541Sshin * this is to accomodate address naming scheme other than RFC2374,
156953541Sshin * in the future.
157053541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
157153541Sshin * address encoding scheme. (see figure on page 8)
157253541Sshin */
157353541Sshinstatic int
1574171259Sdelphijin6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
1575171259Sdelphij    struct ifnet *ifp, struct thread *td)
157653541Sshin{
157753541Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
157853541Sshin	struct ifaddr *ifa;
157962587Sitojun	struct sockaddr *sa;
158053541Sshin
158153541Sshin	/* sanity checks */
158253541Sshin	if (!data || !ifp) {
158353541Sshin		panic("invalid argument to in6_lifaddr_ioctl");
1584120891Sume		/* NOTREACHED */
158553541Sshin	}
158653541Sshin
158753541Sshin	switch (cmd) {
158853541Sshin	case SIOCGLIFADDR:
158953541Sshin		/* address must be specified on GET with IFLR_PREFIX */
159053541Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
159153541Sshin			break;
159295023Ssuz		/* FALLTHROUGH */
159353541Sshin	case SIOCALIFADDR:
159453541Sshin	case SIOCDLIFADDR:
159553541Sshin		/* address must be specified on ADD and DELETE */
159662587Sitojun		sa = (struct sockaddr *)&iflr->addr;
159762587Sitojun		if (sa->sa_family != AF_INET6)
159853541Sshin			return EINVAL;
159962587Sitojun		if (sa->sa_len != sizeof(struct sockaddr_in6))
160053541Sshin			return EINVAL;
160153541Sshin		/* XXX need improvement */
160262587Sitojun		sa = (struct sockaddr *)&iflr->dstaddr;
160362587Sitojun		if (sa->sa_family && sa->sa_family != AF_INET6)
160453541Sshin			return EINVAL;
160562587Sitojun		if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
160653541Sshin			return EINVAL;
160753541Sshin		break;
160895023Ssuz	default: /* shouldn't happen */
160962587Sitojun#if 0
161062587Sitojun		panic("invalid cmd to in6_lifaddr_ioctl");
161195023Ssuz		/* NOTREACHED */
161262587Sitojun#else
161353541Sshin		return EOPNOTSUPP;
161462587Sitojun#endif
161553541Sshin	}
161653541Sshin	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
161753541Sshin		return EINVAL;
161853541Sshin
161953541Sshin	switch (cmd) {
162053541Sshin	case SIOCALIFADDR:
162153541Sshin	    {
162253541Sshin		struct in6_aliasreq ifra;
162353541Sshin		struct in6_addr *hostid = NULL;
162453541Sshin		int prefixlen;
162553541Sshin
1626194760Srwatson		ifa = NULL;
162753541Sshin		if ((iflr->flags & IFLR_PREFIX) != 0) {
162853541Sshin			struct sockaddr_in6 *sin6;
162953541Sshin
163053541Sshin			/*
163153541Sshin			 * hostid is to fill in the hostid part of the
163253541Sshin			 * address.  hostid points to the first link-local
163353541Sshin			 * address attached to the interface.
163453541Sshin			 */
163562587Sitojun			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
163653541Sshin			if (!ifa)
163753541Sshin				return EADDRNOTAVAIL;
163853541Sshin			hostid = IFA_IN6(ifa);
163953541Sshin
1640171260Sdelphij			/* prefixlen must be <= 64. */
1641236826Sbz			if (64 < iflr->prefixlen) {
1642236826Sbz				if (ifa != NULL)
1643236826Sbz					ifa_free(ifa);
164453541Sshin				return EINVAL;
1645236826Sbz			}
164653541Sshin			prefixlen = iflr->prefixlen;
164753541Sshin
164853541Sshin			/* hostid part must be zero. */
164953541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
1650126552Sume			if (sin6->sin6_addr.s6_addr32[2] != 0 ||
1651126552Sume			    sin6->sin6_addr.s6_addr32[3] != 0) {
1652236826Sbz				if (ifa != NULL)
1653236826Sbz					ifa_free(ifa);
165453541Sshin				return EINVAL;
165553541Sshin			}
165653541Sshin		} else
165753541Sshin			prefixlen = iflr->prefixlen;
165853541Sshin
165953541Sshin		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
166053541Sshin		bzero(&ifra, sizeof(ifra));
1661120891Sume		bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name));
166253541Sshin
166362587Sitojun		bcopy(&iflr->addr, &ifra.ifra_addr,
1664120891Sume		    ((struct sockaddr *)&iflr->addr)->sa_len);
166553541Sshin		if (hostid) {
166653541Sshin			/* fill in hostid part */
166753541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[2] =
1668120891Sume			    hostid->s6_addr32[2];
166953541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[3] =
1670120891Sume			    hostid->s6_addr32[3];
167153541Sshin		}
167253541Sshin
1673120891Sume		if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */
167453541Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1675120891Sume			    ((struct sockaddr *)&iflr->dstaddr)->sa_len);
167653541Sshin			if (hostid) {
167753541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
1678120891Sume				    hostid->s6_addr32[2];
167953541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
1680120891Sume				    hostid->s6_addr32[3];
168153541Sshin			}
168253541Sshin		}
1683194760Srwatson		if (ifa != NULL)
1684194760Srwatson			ifa_free(ifa);
168553541Sshin
168653541Sshin		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1687121168Sume		in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
168853541Sshin
168953541Sshin		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
169083366Sjulian		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td);
169153541Sshin	    }
169253541Sshin	case SIOCGLIFADDR:
169353541Sshin	case SIOCDLIFADDR:
169453541Sshin	    {
169553541Sshin		struct in6_ifaddr *ia;
169653541Sshin		struct in6_addr mask, candidate, match;
169753541Sshin		struct sockaddr_in6 *sin6;
169853541Sshin		int cmp;
169953541Sshin
170053541Sshin		bzero(&mask, sizeof(mask));
170153541Sshin		if (iflr->flags & IFLR_PREFIX) {
170253541Sshin			/* lookup a prefix rather than address. */
1703121168Sume			in6_prefixlen2mask(&mask, iflr->prefixlen);
170453541Sshin
170553541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
170653541Sshin			bcopy(&sin6->sin6_addr, &match, sizeof(match));
170753541Sshin			match.s6_addr32[0] &= mask.s6_addr32[0];
170853541Sshin			match.s6_addr32[1] &= mask.s6_addr32[1];
170953541Sshin			match.s6_addr32[2] &= mask.s6_addr32[2];
171053541Sshin			match.s6_addr32[3] &= mask.s6_addr32[3];
171153541Sshin
171253541Sshin			/* if you set extra bits, that's wrong */
171353541Sshin			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
171453541Sshin				return EINVAL;
171553541Sshin
171653541Sshin			cmp = 1;
171753541Sshin		} else {
171853541Sshin			if (cmd == SIOCGLIFADDR) {
171953541Sshin				/* on getting an address, take the 1st match */
172095023Ssuz				cmp = 0;	/* XXX */
172153541Sshin			} else {
172253541Sshin				/* on deleting an address, do exact match */
1723121168Sume				in6_prefixlen2mask(&mask, 128);
172453541Sshin				sin6 = (struct sockaddr_in6 *)&iflr->addr;
172553541Sshin				bcopy(&sin6->sin6_addr, &match, sizeof(match));
172653541Sshin
172753541Sshin				cmp = 1;
172853541Sshin			}
172953541Sshin		}
173053541Sshin
1731233200Sjhb		IF_ADDR_RLOCK(ifp);
1732191340Srwatson		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
173353541Sshin			if (ifa->ifa_addr->sa_family != AF_INET6)
173453541Sshin				continue;
173553541Sshin			if (!cmp)
173653541Sshin				break;
173778064Sume
173878064Sume			/*
173978064Sume			 * XXX: this is adhoc, but is necessary to allow
174078064Sume			 * a user to specify fe80::/64 (not /10) for a
174178064Sume			 * link-local address.
174278064Sume			 */
1743148385Sume			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
1744148385Sume			in6_clearscope(&candidate);
174553541Sshin			candidate.s6_addr32[0] &= mask.s6_addr32[0];
174653541Sshin			candidate.s6_addr32[1] &= mask.s6_addr32[1];
174753541Sshin			candidate.s6_addr32[2] &= mask.s6_addr32[2];
174853541Sshin			candidate.s6_addr32[3] &= mask.s6_addr32[3];
174953541Sshin			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
175053541Sshin				break;
175153541Sshin		}
1752230074Sjhb		if (ifa != NULL)
1753230074Sjhb			ifa_ref(ifa);
1754233200Sjhb		IF_ADDR_RUNLOCK(ifp);
175553541Sshin		if (!ifa)
175653541Sshin			return EADDRNOTAVAIL;
175753541Sshin		ia = ifa2ia6(ifa);
175853541Sshin
175953541Sshin		if (cmd == SIOCGLIFADDR) {
1760148385Sume			int error;
176178064Sume
176253541Sshin			/* fill in the if_laddrreq structure */
176353541Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
1764148385Sume			error = sa6_recoverscope(
1765148385Sume			    (struct sockaddr_in6 *)&iflr->addr);
1766230074Sjhb			if (error != 0) {
1767230074Sjhb				ifa_free(ifa);
1768148385Sume				return (error);
1769230074Sjhb			}
1770148385Sume
177153541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
177253541Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
1773120891Sume				    ia->ia_dstaddr.sin6_len);
1774148385Sume				error = sa6_recoverscope(
1775148385Sume				    (struct sockaddr_in6 *)&iflr->dstaddr);
1776230074Sjhb				if (error != 0) {
1777230074Sjhb					ifa_free(ifa);
1778148385Sume					return (error);
1779230074Sjhb				}
178053541Sshin			} else
178153541Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
178253541Sshin
178353541Sshin			iflr->prefixlen =
1784120891Sume			    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
178553541Sshin
178695023Ssuz			iflr->flags = ia->ia6_flags;	/* XXX */
1787230074Sjhb			ifa_free(ifa);
178853541Sshin
178953541Sshin			return 0;
179053541Sshin		} else {
179153541Sshin			struct in6_aliasreq ifra;
179253541Sshin
179353541Sshin			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
179453541Sshin			bzero(&ifra, sizeof(ifra));
179553541Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
1796120891Sume			    sizeof(ifra.ifra_name));
179753541Sshin
179853541Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
1799120891Sume			    ia->ia_addr.sin6_len);
180053541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
180153541Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
1802120891Sume				    ia->ia_dstaddr.sin6_len);
180362587Sitojun			} else {
180462587Sitojun				bzero(&ifra.ifra_dstaddr,
180562587Sitojun				    sizeof(ifra.ifra_dstaddr));
180653541Sshin			}
180753541Sshin			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
1808120891Sume			    ia->ia_prefixmask.sin6_len);
180953541Sshin
181053541Sshin			ifra.ifra_flags = ia->ia6_flags;
1811230074Sjhb			ifa_free(ifa);
181253541Sshin			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
1813120891Sume			    ifp, td);
181453541Sshin		}
181553541Sshin	    }
181653541Sshin	}
181753541Sshin
181895023Ssuz	return EOPNOTSUPP;	/* just for safety */
181953541Sshin}
182053541Sshin
182153541Sshin/*
1822232292Sbz * Initialize an interface's IPv6 address and routing table entry.
182353541Sshin */
182478064Sumestatic int
1825171259Sdelphijin6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
1826171259Sdelphij    struct sockaddr_in6 *sin6, int newhost)
182753541Sshin{
182878064Sume	int	error = 0, plen, ifacount = 0;
182953541Sshin	int	s = splimp();
183078064Sume	struct ifaddr *ifa;
183153541Sshin
183253541Sshin	/*
183353541Sshin	 * Give the interface a chance to initialize
183453541Sshin	 * if this is its first address,
183553541Sshin	 * and to validate the address if necessary.
183653541Sshin	 */
1837233200Sjhb	IF_ADDR_RLOCK(ifp);
1838191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
183978064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
184078064Sume			continue;
184178064Sume		ifacount++;
184278064Sume	}
1843233200Sjhb	IF_ADDR_RUNLOCK(ifp);
184478064Sume
184578064Sume	ia->ia_addr = *sin6;
184678064Sume
1847146883Siedowse	if (ifacount <= 1 && ifp->if_ioctl) {
1848146883Siedowse		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
1849146883Siedowse		if (error) {
1850146883Siedowse			splx(s);
1851146883Siedowse			return (error);
1852146883Siedowse		}
185353541Sshin	}
185478064Sume	splx(s);
185553541Sshin
185678064Sume	ia->ia_ifa.ifa_metric = ifp->if_metric;
185753541Sshin
185878064Sume	/* we could do in(6)_socktrim here, but just omit it at this moment. */
185978064Sume
186053541Sshin	/*
186178064Sume	 * Special case:
1862124337Sume	 * If a new destination address is specified for a point-to-point
186378064Sume	 * interface, install a route to the destination as an interface
1864186119Sqingli	 * direct route.
1865124337Sume	 * XXX: the logic below rejects assigning multiple addresses on a p2p
1866159390Sgnn	 * interface that share the same destination.
186753541Sshin	 */
186878064Sume	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
1869196152Sqingli	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
1870196152Sqingli	    ia->ia_dstaddr.sin6_family == AF_INET6) {
1871159390Sgnn		int rtflags = RTF_UP | RTF_HOST;
1872232292Sbz		error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
1873232292Sbz		if (error)
1874120856Sume			return (error);
187578064Sume		ia->ia_flags |= IFA_ROUTE;
1876226455Sqingli		/*
1877226455Sqingli		 * Handle the case for ::1 .
1878226455Sqingli		 */
1879226455Sqingli		if (ifp->if_flags & IFF_LOOPBACK)
1880226455Sqingli			ia->ia_flags |= IFA_RTSELF;
188153541Sshin	}
188253541Sshin
1883195643Sqingli	/*
1884195643Sqingli	 * add a loopback route to self
1885195643Sqingli	 */
1886226455Sqingli	if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) {
1887197227Sqingli		error = ifa_add_loopback_route((struct ifaddr *)ia,
1888197227Sqingli				       (struct sockaddr *)&ia->ia_addr);
1889201282Sqingli		if (error == 0)
1890201282Sqingli			ia->ia_flags |= IFA_RTSELF;
1891195643Sqingli	}
1892195643Sqingli
1893232292Sbz	/* Add local address to lltable, if necessary (ex. on p2p link). */
1894226570Sglebius	if (newhost)
1895226570Sglebius		in6_ifaddloop(&(ia->ia_ifa));
189653541Sshin
1897120856Sume	return (error);
189853541Sshin}
189953541Sshin
190053541Sshin/*
190153541Sshin * Find an IPv6 interface link-local address specific to an interface.
1902194760Srwatson * ifaddr is returned referenced.
190353541Sshin */
190453541Sshinstruct in6_ifaddr *
1905171259Sdelphijin6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
190653541Sshin{
190778064Sume	struct ifaddr *ifa;
190853541Sshin
1909233200Sjhb	IF_ADDR_RLOCK(ifp);
1910191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
191153541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
191253541Sshin			continue;
191362587Sitojun		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
191462587Sitojun			if ((((struct in6_ifaddr *)ifa)->ia6_flags &
191562587Sitojun			     ignoreflags) != 0)
191662587Sitojun				continue;
1917194760Srwatson			ifa_ref(ifa);
191853541Sshin			break;
191962587Sitojun		}
192053541Sshin	}
1921233200Sjhb	IF_ADDR_RUNLOCK(ifp);
192253541Sshin
1923120856Sume	return ((struct in6_ifaddr *)ifa);
192453541Sshin}
192553541Sshin
192653541Sshin
192753541Sshin/*
192853541Sshin * find the internet address corresponding to a given interface and address.
1929194760Srwatson * ifaddr is returned referenced.
193053541Sshin */
193153541Sshinstruct in6_ifaddr *
1932171259Sdelphijin6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
193353541Sshin{
193478064Sume	struct ifaddr *ifa;
193553541Sshin
1936233200Sjhb	IF_ADDR_RLOCK(ifp);
1937191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
193853541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
193953541Sshin			continue;
1940194760Srwatson		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) {
1941194760Srwatson			ifa_ref(ifa);
194253541Sshin			break;
1943194760Srwatson		}
194453541Sshin	}
1945233200Sjhb	IF_ADDR_RUNLOCK(ifp);
194653541Sshin
1947120856Sume	return ((struct in6_ifaddr *)ifa);
194853541Sshin}
194953541Sshin
195053541Sshin/*
1951165118Sbz * Convert IP6 address to printable (loggable) representation. Caller
1952165118Sbz * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long.
195353541Sshin */
195453541Sshinstatic char digits[] = "0123456789abcdef";
195553541Sshinchar *
1956165118Sbzip6_sprintf(char *ip6buf, const struct in6_addr *addr)
195753541Sshin{
1958208284Salfred	int i, cnt = 0, maxcnt = 0, idx = 0, index = 0;
195978064Sume	char *cp;
1960126552Sume	const u_int16_t *a = (const u_int16_t *)addr;
1961126552Sume	const u_int8_t *d;
1962165287Sbz	int dcolon = 0, zero = 0;
196353541Sshin
1964165118Sbz	cp = ip6buf;
196553541Sshin
196653541Sshin	for (i = 0; i < 8; i++) {
1967208284Salfred		if (*(a + i) == 0) {
1968208284Salfred			cnt++;
1969208284Salfred			if (cnt == 1)
1970208284Salfred				idx = i;
1971208284Salfred		}
1972208284Salfred		else if (maxcnt < cnt) {
1973208284Salfred			maxcnt = cnt;
1974208284Salfred			index = idx;
1975208284Salfred			cnt = 0;
1976208284Salfred		}
1977208284Salfred	}
1978208284Salfred	if (maxcnt < cnt) {
1979208284Salfred		maxcnt = cnt;
1980208284Salfred		index = idx;
1981208284Salfred	}
1982208284Salfred
1983208284Salfred	for (i = 0; i < 8; i++) {
198453541Sshin		if (dcolon == 1) {
198553541Sshin			if (*a == 0) {
198653541Sshin				if (i == 7)
198753541Sshin					*cp++ = ':';
198853541Sshin				a++;
198953541Sshin				continue;
199053541Sshin			} else
199153541Sshin				dcolon = 2;
199253541Sshin		}
199353541Sshin		if (*a == 0) {
1994208284Salfred			if (dcolon == 0 && *(a + 1) == 0 && i == index) {
199553541Sshin				if (i == 0)
199653541Sshin					*cp++ = ':';
199753541Sshin				*cp++ = ':';
199853541Sshin				dcolon = 1;
199953541Sshin			} else {
200053541Sshin				*cp++ = '0';
200153541Sshin				*cp++ = ':';
200253541Sshin			}
200353541Sshin			a++;
200453541Sshin			continue;
200553541Sshin		}
200691346Salfred		d = (const u_char *)a;
2007165287Sbz		/* Try to eliminate leading zeros in printout like in :0001. */
2008165287Sbz		zero = 1;
2009165287Sbz		*cp = digits[*d >> 4];
2010165287Sbz		if (*cp != '0') {
2011165287Sbz			zero = 0;
2012165287Sbz			cp++;
2013165287Sbz		}
2014165287Sbz		*cp = digits[*d++ & 0xf];
2015165287Sbz		if (zero == 0 || (*cp != '0')) {
2016165287Sbz			zero = 0;
2017165287Sbz			cp++;
2018165287Sbz		}
2019165287Sbz		*cp = digits[*d >> 4];
2020165287Sbz		if (zero == 0 || (*cp != '0')) {
2021165287Sbz			zero = 0;
2022165287Sbz			cp++;
2023165287Sbz		}
202453541Sshin		*cp++ = digits[*d & 0xf];
202553541Sshin		*cp++ = ':';
202653541Sshin		a++;
202753541Sshin	}
2028165118Sbz	*--cp = '\0';
2029165118Sbz	return (ip6buf);
203053541Sshin}
203153541Sshin
203253541Sshinint
2033171259Sdelphijin6_localaddr(struct in6_addr *in6)
203453541Sshin{
203553541Sshin	struct in6_ifaddr *ia;
203653541Sshin
203753541Sshin	if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
203853541Sshin		return 1;
203953541Sshin
2040194971Srwatson	IN6_IFADDR_RLOCK();
2041194907Srwatson	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
204253541Sshin		if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
2043120891Sume		    &ia->ia_prefixmask.sin6_addr)) {
2044194971Srwatson			IN6_IFADDR_RUNLOCK();
204553541Sshin			return 1;
2046120891Sume		}
2047120891Sume	}
2048194971Srwatson	IN6_IFADDR_RUNLOCK();
204953541Sshin
205053541Sshin	return (0);
205153541Sshin}
205253541Sshin
2053225043Sbz/*
2054225043Sbz * Return 1 if an internet address is for the local host and configured
2055225043Sbz * on one of its interfaces.
2056225043Sbz */
205778064Sumeint
2058225043Sbzin6_localip(struct in6_addr *in6)
2059225043Sbz{
2060225043Sbz	struct in6_ifaddr *ia;
2061225043Sbz
2062225043Sbz	IN6_IFADDR_RLOCK();
2063225043Sbz	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
2064225043Sbz		if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) {
2065225043Sbz			IN6_IFADDR_RUNLOCK();
2066225043Sbz			return (1);
2067225043Sbz		}
2068225043Sbz	}
2069225043Sbz	IN6_IFADDR_RUNLOCK();
2070225043Sbz	return (0);
2071225043Sbz}
2072225043Sbz
2073225043Sbz
2074225043Sbzint
2075171259Sdelphijin6_is_addr_deprecated(struct sockaddr_in6 *sa6)
207678064Sume{
207778064Sume	struct in6_ifaddr *ia;
207878064Sume
2079194971Srwatson	IN6_IFADDR_RLOCK();
2080194907Srwatson	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
208178064Sume		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
208278064Sume				       &sa6->sin6_addr) &&
2083194971Srwatson		    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
2084194971Srwatson			IN6_IFADDR_RUNLOCK();
2085120856Sume			return (1); /* true */
2086194971Srwatson		}
208778064Sume
208878064Sume		/* XXX: do we still have to go thru the rest of the list? */
208978064Sume	}
2090194971Srwatson	IN6_IFADDR_RUNLOCK();
209178064Sume
2092120856Sume	return (0);		/* false */
209378064Sume}
209478064Sume
209553541Sshin/*
209653541Sshin * return length of part which dst and src are equal
209753541Sshin * hard coding...
209853541Sshin */
209953541Sshinint
2100171259Sdelphijin6_matchlen(struct in6_addr *src, struct in6_addr *dst)
210153541Sshin{
210253541Sshin	int match = 0;
210353541Sshin	u_char *s = (u_char *)src, *d = (u_char *)dst;
210453541Sshin	u_char *lim = s + 16, r;
210553541Sshin
210653541Sshin	while (s < lim)
210753541Sshin		if ((r = (*d++ ^ *s++)) != 0) {
210853541Sshin			while (r < 128) {
210953541Sshin				match++;
211053541Sshin				r <<= 1;
211153541Sshin			}
211253541Sshin			break;
211353541Sshin		} else
211453541Sshin			match += 8;
211553541Sshin	return match;
211653541Sshin}
211753541Sshin
211862587Sitojun/* XXX: to be scope conscious */
211953541Sshinint
2120171259Sdelphijin6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len)
212153541Sshin{
212253541Sshin	int bytelen, bitlen;
212353541Sshin
212453541Sshin	/* sanity check */
212553541Sshin	if (0 > len || len > 128) {
212653541Sshin		log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
212753541Sshin		    len);
2128120856Sume		return (0);
212953541Sshin	}
213053541Sshin
213153541Sshin	bytelen = len / 8;
213253541Sshin	bitlen = len % 8;
213353541Sshin
213453541Sshin	if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
2135120856Sume		return (0);
2136126184Scperciva	if (bitlen != 0 &&
2137126184Scperciva	    p1->s6_addr[bytelen] >> (8 - bitlen) !=
213853541Sshin	    p2->s6_addr[bytelen] >> (8 - bitlen))
2139120856Sume		return (0);
214053541Sshin
2141120856Sume	return (1);
214253541Sshin}
214353541Sshin
214453541Sshinvoid
2145171259Sdelphijin6_prefixlen2mask(struct in6_addr *maskp, int len)
214653541Sshin{
214753541Sshin	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
214853541Sshin	int bytelen, bitlen, i;
214953541Sshin
215053541Sshin	/* sanity check */
215153541Sshin	if (0 > len || len > 128) {
215253541Sshin		log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
215353541Sshin		    len);
215453541Sshin		return;
215553541Sshin	}
215653541Sshin
215753541Sshin	bzero(maskp, sizeof(*maskp));
215853541Sshin	bytelen = len / 8;
215953541Sshin	bitlen = len % 8;
216053541Sshin	for (i = 0; i < bytelen; i++)
216153541Sshin		maskp->s6_addr[i] = 0xff;
216253541Sshin	if (bitlen)
216353541Sshin		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
216453541Sshin}
216553541Sshin
216653541Sshin/*
216753541Sshin * return the best address out of the same scope. if no address was
216853541Sshin * found, return the first valid address from designated IF.
216953541Sshin */
217053541Sshinstruct in6_ifaddr *
2171171259Sdelphijin6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
217253541Sshin{
217353541Sshin	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
217453541Sshin	struct ifaddr *ifa;
217553541Sshin	struct in6_ifaddr *besta = 0;
217695023Ssuz	struct in6_ifaddr *dep[2];	/* last-resort: deprecated */
217753541Sshin
217853541Sshin	dep[0] = dep[1] = NULL;
217953541Sshin
218053541Sshin	/*
218153541Sshin	 * We first look for addresses in the same scope.
218253541Sshin	 * If there is one, return it.
218353541Sshin	 * If two or more, return one which matches the dst longest.
218453541Sshin	 * If none, return one of global addresses assigned other ifs.
218553541Sshin	 */
2186233200Sjhb	IF_ADDR_RLOCK(ifp);
2187191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
218853541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
218953541Sshin			continue;
219053541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
219153541Sshin			continue; /* XXX: is there any case to allow anycast? */
219253541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
219353541Sshin			continue; /* don't use this interface */
219453541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
219553541Sshin			continue;
219653541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2197181803Sbz			if (V_ip6_use_deprecated)
219853541Sshin				dep[0] = (struct in6_ifaddr *)ifa;
219953541Sshin			continue;
220053541Sshin		}
220153541Sshin
220253541Sshin		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
220353541Sshin			/*
220453541Sshin			 * call in6_matchlen() as few as possible
220553541Sshin			 */
220653541Sshin			if (besta) {
220753541Sshin				if (blen == -1)
220853541Sshin					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
220953541Sshin				tlen = in6_matchlen(IFA_IN6(ifa), dst);
221053541Sshin				if (tlen > blen) {
221153541Sshin					blen = tlen;
221253541Sshin					besta = (struct in6_ifaddr *)ifa;
221353541Sshin				}
221453541Sshin			} else
221553541Sshin				besta = (struct in6_ifaddr *)ifa;
221653541Sshin		}
221753541Sshin	}
2218191323Srwatson	if (besta) {
2219194760Srwatson		ifa_ref(&besta->ia_ifa);
2220233200Sjhb		IF_ADDR_RUNLOCK(ifp);
2221120856Sume		return (besta);
2222191323Srwatson	}
222353541Sshin
2224191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
222553541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
222653541Sshin			continue;
222753541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
222853541Sshin			continue; /* XXX: is there any case to allow anycast? */
222953541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
223053541Sshin			continue; /* don't use this interface */
223153541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
223253541Sshin			continue;
223353541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2234181803Sbz			if (V_ip6_use_deprecated)
223553541Sshin				dep[1] = (struct in6_ifaddr *)ifa;
223653541Sshin			continue;
223753541Sshin		}
223853541Sshin
2239194760Srwatson		if (ifa != NULL)
2240194760Srwatson			ifa_ref(ifa);
2241233200Sjhb		IF_ADDR_RUNLOCK(ifp);
224253541Sshin		return (struct in6_ifaddr *)ifa;
224353541Sshin	}
224453541Sshin
224553541Sshin	/* use the last-resort values, that are, deprecated addresses */
2246236606Sbz	if (dep[0]) {
2247236606Sbz		ifa_ref((struct ifaddr *)dep[0]);
2248236606Sbz		IF_ADDR_RUNLOCK(ifp);
224953541Sshin		return dep[0];
2250236606Sbz	}
2251236606Sbz	if (dep[1]) {
2252236606Sbz		ifa_ref((struct ifaddr *)dep[1]);
2253236606Sbz		IF_ADDR_RUNLOCK(ifp);
225453541Sshin		return dep[1];
2255236606Sbz	}
225653541Sshin
2257236606Sbz	IF_ADDR_RUNLOCK(ifp);
225853541Sshin	return NULL;
225953541Sshin}
226053541Sshin
226153541Sshin/*
226253541Sshin * perform DAD when interface becomes IFF_UP.
226353541Sshin */
226453541Sshinvoid
2265171259Sdelphijin6_if_up(struct ifnet *ifp)
226653541Sshin{
226753541Sshin	struct ifaddr *ifa;
226853541Sshin	struct in6_ifaddr *ia;
226953541Sshin
2270233200Sjhb	IF_ADDR_RLOCK(ifp);
2271191340Srwatson	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
227253541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
227353541Sshin			continue;
227453541Sshin		ia = (struct in6_ifaddr *)ifa;
2275151539Ssuz		if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
2276151539Ssuz			/*
2277151539Ssuz			 * The TENTATIVE flag was likely set by hand
2278151539Ssuz			 * beforehand, implicitly indicating the need for DAD.
2279151539Ssuz			 * We may be able to skip the random delay in this
2280151539Ssuz			 * case, but we impose delays just in case.
2281151539Ssuz			 */
2282151539Ssuz			nd6_dad_start(ifa,
2283151539Ssuz			    arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz));
2284151539Ssuz		}
228553541Sshin	}
2286233200Sjhb	IF_ADDR_RUNLOCK(ifp);
2287151539Ssuz
2288151539Ssuz	/*
2289151539Ssuz	 * special cases, like 6to4, are handled in in6_ifattach
2290151539Ssuz	 */
2291151539Ssuz	in6_ifattach(ifp, NULL);
229253541Sshin}
229353541Sshin
229478064Sumeint
2295171259Sdelphijin6if_do_dad(struct ifnet *ifp)
229678064Sume{
229778064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0)
2298120856Sume		return (0);
229978064Sume
2300197138Shrs	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
2301197138Shrs		return (0);
2302197138Shrs
230378064Sume	switch (ifp->if_type) {
230478064Sume#ifdef IFT_DUMMY
230578064Sume	case IFT_DUMMY:
230678064Sume#endif
230778064Sume	case IFT_FAITH:
230878064Sume		/*
230978064Sume		 * These interfaces do not have the IFF_LOOPBACK flag,
231078064Sume		 * but loop packets back.  We do not have to do DAD on such
231178064Sume		 * interfaces.  We should even omit it, because loop-backed
231278064Sume		 * NS would confuse the DAD procedure.
231378064Sume		 */
2314120856Sume		return (0);
231578064Sume	default:
231678064Sume		/*
231778064Sume		 * Our DAD routine requires the interface up and running.
231878064Sume		 * However, some interfaces can be up before the RUNNING
231978064Sume		 * status.  Additionaly, users may try to assign addresses
232078064Sume		 * before the interface becomes up (or running).
232178064Sume		 * We simply skip DAD in such a case as a work around.
232278064Sume		 * XXX: we should rather mark "tentative" on such addresses,
232378064Sume		 * and do DAD after the interface becomes ready.
232478064Sume		 */
2325148887Srwatson		if (!((ifp->if_flags & IFF_UP) &&
2326148887Srwatson		    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
2327120856Sume			return (0);
232878064Sume
2329120856Sume		return (1);
233078064Sume	}
233178064Sume}
233278064Sume
233353541Sshin/*
233453541Sshin * Calculate max IPv6 MTU through all the interfaces and store it
233553541Sshin * to in6_maxmtu.
233653541Sshin */
233753541Sshinvoid
2338171259Sdelphijin6_setmaxmtu(void)
233953541Sshin{
234053541Sshin	unsigned long maxmtu = 0;
234153541Sshin	struct ifnet *ifp;
234253541Sshin
2343196481Srwatson	IFNET_RLOCK_NOSLEEP();
2344233046Sjhb	TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
2345121283Sume		/* this function can be called during ifnet initialization */
2346121283Sume		if (!ifp->if_afdata[AF_INET6])
2347121283Sume			continue;
234853541Sshin		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
2349121283Sume		    IN6_LINKMTU(ifp) > maxmtu)
2350121283Sume			maxmtu = IN6_LINKMTU(ifp);
235153541Sshin	}
2352196481Srwatson	IFNET_RUNLOCK_NOSLEEP();
2353120891Sume	if (maxmtu)	     /* update only when maxmtu is positive */
2354181803Sbz		V_in6_maxmtu = maxmtu;
235553541Sshin}
235653541Sshin
2357151539Ssuz/*
2358151539Ssuz * Provide the length of interface identifiers to be used for the link attached
2359151539Ssuz * to the given interface.  The length should be defined in "IPv6 over
2360151539Ssuz * xxx-link" document.  Note that address architecture might also define
2361151539Ssuz * the length for a particular set of address prefixes, regardless of the
2362151539Ssuz * link type.  As clarified in rfc2462bis, those two definitions should be
2363151539Ssuz * consistent, and those really are as of August 2004.
2364151539Ssuz */
2365151539Ssuzint
2366171259Sdelphijin6_if2idlen(struct ifnet *ifp)
2367151539Ssuz{
2368151539Ssuz	switch (ifp->if_type) {
2369151539Ssuz	case IFT_ETHER:		/* RFC2464 */
2370151539Ssuz#ifdef IFT_PROPVIRTUAL
2371151539Ssuz	case IFT_PROPVIRTUAL:	/* XXX: no RFC. treat it as ether */
2372151539Ssuz#endif
2373151539Ssuz#ifdef IFT_L2VLAN
2374151539Ssuz	case IFT_L2VLAN:	/* ditto */
2375151539Ssuz#endif
2376151539Ssuz#ifdef IFT_IEEE80211
2377151539Ssuz	case IFT_IEEE80211:	/* ditto */
2378151539Ssuz#endif
2379151539Ssuz#ifdef IFT_MIP
2380151539Ssuz	case IFT_MIP:	/* ditto */
2381151539Ssuz#endif
2382219819Sjeff	case IFT_INFINIBAND:
2383151539Ssuz		return (64);
2384151539Ssuz	case IFT_FDDI:		/* RFC2467 */
2385151539Ssuz		return (64);
2386151539Ssuz	case IFT_ISO88025:	/* RFC2470 (IPv6 over Token Ring) */
2387151539Ssuz		return (64);
2388151539Ssuz	case IFT_PPP:		/* RFC2472 */
2389151539Ssuz		return (64);
2390151539Ssuz	case IFT_ARCNET:	/* RFC2497 */
2391151539Ssuz		return (64);
2392151539Ssuz	case IFT_FRELAY:	/* RFC2590 */
2393151539Ssuz		return (64);
2394151539Ssuz	case IFT_IEEE1394:	/* RFC3146 */
2395151539Ssuz		return (64);
2396151539Ssuz	case IFT_GIF:
2397151539Ssuz		return (64);	/* draft-ietf-v6ops-mech-v2-07 */
2398151539Ssuz	case IFT_LOOP:
2399151539Ssuz		return (64);	/* XXX: is this really correct? */
2400151539Ssuz	default:
2401151539Ssuz		/*
2402151539Ssuz		 * Unknown link type:
2403151539Ssuz		 * It might be controversial to use the today's common constant
2404151539Ssuz		 * of 64 for these cases unconditionally.  For full compliance,
2405151539Ssuz		 * we should return an error in this case.  On the other hand,
2406151539Ssuz		 * if we simply miss the standard for the link type or a new
2407151539Ssuz		 * standard is defined for a new link type, the IFID length
2408151539Ssuz		 * is very likely to be the common constant.  As a compromise,
2409151539Ssuz		 * we always use the constant, but make an explicit notice
2410151539Ssuz		 * indicating the "unknown" case.
2411151539Ssuz		 */
2412151539Ssuz		printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type);
2413151539Ssuz		return (64);
2414151539Ssuz	}
2415151539Ssuz}
2416151539Ssuz
2417186119Sqingli#include <sys/sysctl.h>
2418186119Sqingli
2419186119Sqinglistruct in6_llentry {
2420186119Sqingli	struct llentry		base;
2421186119Sqingli	struct sockaddr_in6	l3_addr6;
2422186119Sqingli};
2423186119Sqingli
2424240309Sglebius/*
2425240309Sglebius * Deletes an address from the address table.
2426240309Sglebius * This function is called by the timer functions
2427240309Sglebius * such as arptimer() and nd6_llinfo_timer(), and
2428240309Sglebius * the caller does the locking.
2429240309Sglebius */
2430240309Sglebiusstatic void
2431240309Sglebiusin6_lltable_free(struct lltable *llt, struct llentry *lle)
2432240309Sglebius{
2433240309Sglebius	LLE_WUNLOCK(lle);
2434240309Sglebius	LLE_LOCK_DESTROY(lle);
2435240309Sglebius	free(lle, M_LLTABLE);
2436240309Sglebius}
2437240309Sglebius
2438186119Sqinglistatic struct llentry *
2439186119Sqingliin6_lltable_new(const struct sockaddr *l3addr, u_int flags)
2440186119Sqingli{
2441186119Sqingli	struct in6_llentry *lle;
2442186119Sqingli
2443186119Sqingli	lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
2444186119Sqingli	    M_DONTWAIT | M_ZERO);
2445186119Sqingli	if (lle == NULL)		/* NB: caller generates msg */
2446186119Sqingli		return NULL;
2447186119Sqingli
2448186119Sqingli	lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
2449186119Sqingli	lle->base.lle_refcnt = 1;
2450240309Sglebius	lle->base.lle_free = in6_lltable_free;
2451186119Sqingli	LLE_LOCK_INIT(&lle->base);
2452216022Sbz	callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
2453216022Sbz	    CALLOUT_RETURNUNLOCKED);
2454216022Sbz
2455186119Sqingli	return &lle->base;
2456186119Sqingli}
2457186119Sqingli
2458186119Sqinglistatic void
2459192476Sqingliin6_lltable_prefix_free(struct lltable *llt,
2460192476Sqingli			const struct sockaddr *prefix,
2461222143Sqingli			const struct sockaddr *mask,
2462222143Sqingli			u_int flags)
2463192476Sqingli{
2464192476Sqingli	const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
2465192476Sqingli	const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
2466192476Sqingli	struct llentry *lle, *next;
2467192476Sqingli	register int i;
2468192476Sqingli
2469222143Sqingli	/*
2470222143Sqingli	 * (flags & LLE_STATIC) means deleting all entries
2471222143Sqingli	 * including static ND6 entries
2472222143Sqingli	 */
2473192476Sqingli	for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
2474192476Sqingli		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
2475192476Sqingli			if (IN6_ARE_MASKED_ADDR_EQUAL(
2476192476Sqingli				    &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr,
2477192476Sqingli				    &pfx->sin6_addr,
2478222143Sqingli				    &msk->sin6_addr) &&
2479222143Sqingli			    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) {
2480206481Sbz				int canceled;
2481206481Sbz
2482206481Sbz				canceled = callout_drain(&lle->la_timer);
2483192476Sqingli				LLE_WLOCK(lle);
2484206481Sbz				if (canceled)
2485206481Sbz					LLE_REMREF(lle);
2486192476Sqingli				llentry_free(lle);
2487192476Sqingli			}
2488192476Sqingli		}
2489192476Sqingli	}
2490192476Sqingli}
2491192476Sqingli
2492186119Sqinglistatic int
2493201282Sqingliin6_lltable_rtcheck(struct ifnet *ifp,
2494201282Sqingli		    u_int flags,
2495201282Sqingli		    const struct sockaddr *l3addr)
2496186119Sqingli{
2497186119Sqingli	struct rtentry *rt;
2498186119Sqingli	char ip6buf[INET6_ADDRSTRLEN];
2499186119Sqingli
2500186119Sqingli	KASSERT(l3addr->sa_family == AF_INET6,
2501186119Sqingli	    ("sin_family %d", l3addr->sa_family));
2502186119Sqingli
2503232292Sbz	/* Our local addresses are always only installed on the default FIB. */
2504186119Sqingli	/* XXX rtalloc1 should take a const param */
2505232292Sbz	rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0,
2506232292Sbz	    RT_DEFAULT_FIB);
2507186119Sqingli	if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
2508186119Sqingli		struct ifaddr *ifa;
2509186119Sqingli		/*
2510186119Sqingli		 * Create an ND6 cache for an IPv6 neighbor
2511186119Sqingli		 * that is not covered by our own prefix.
2512186119Sqingli		 */
2513186119Sqingli		/* XXX ifaof_ifpforaddr should take a const param */
2514186119Sqingli		ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp);
2515186119Sqingli		if (ifa != NULL) {
2516194760Srwatson			ifa_free(ifa);
2517186119Sqingli			if (rt != NULL)
2518187946Sbz				RTFREE_LOCKED(rt);
2519186119Sqingli			return 0;
2520186119Sqingli		}
2521186119Sqingli		log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
2522186119Sqingli		    ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr));
2523186119Sqingli		if (rt != NULL)
2524187946Sbz			RTFREE_LOCKED(rt);
2525186119Sqingli		return EINVAL;
2526186119Sqingli	}
2527187946Sbz	RTFREE_LOCKED(rt);
2528186119Sqingli	return 0;
2529186119Sqingli}
2530186119Sqingli
2531186119Sqinglistatic struct llentry *
2532186119Sqingliin6_lltable_lookup(struct lltable *llt, u_int flags,
2533186119Sqingli	const struct sockaddr *l3addr)
2534186119Sqingli{
2535186119Sqingli	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
2536186119Sqingli	struct ifnet *ifp = llt->llt_ifp;
2537186119Sqingli	struct llentry *lle;
2538186119Sqingli	struct llentries *lleh;
2539186119Sqingli	u_int hashkey;
2540186119Sqingli
2541186119Sqingli	IF_AFDATA_LOCK_ASSERT(ifp);
2542186119Sqingli	KASSERT(l3addr->sa_family == AF_INET6,
2543186119Sqingli	    ("sin_family %d", l3addr->sa_family));
2544186119Sqingli
2545186119Sqingli	hashkey = sin6->sin6_addr.s6_addr32[3];
2546186119Sqingli	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
2547186119Sqingli	LIST_FOREACH(lle, lleh, lle_next) {
2548186708Sqingli		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle);
2549186119Sqingli		if (lle->la_flags & LLE_DELETED)
2550186119Sqingli			continue;
2551186708Sqingli		if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
2552186708Sqingli			 sizeof(struct in6_addr)) == 0)
2553186119Sqingli			break;
2554186119Sqingli	}
2555186119Sqingli
2556186119Sqingli	if (lle == NULL) {
2557186119Sqingli		if (!(flags & LLE_CREATE))
2558186119Sqingli			return (NULL);
2559186119Sqingli		/*
2560186119Sqingli		 * A route that covers the given address must have
2561186119Sqingli		 * been installed 1st because we are doing a resolution,
2562186119Sqingli		 * verify this.
2563186119Sqingli		 */
2564186119Sqingli		if (!(flags & LLE_IFADDR) &&
2565201282Sqingli		    in6_lltable_rtcheck(ifp, flags, l3addr) != 0)
2566186119Sqingli			return NULL;
2567186119Sqingli
2568186119Sqingli		lle = in6_lltable_new(l3addr, flags);
2569186119Sqingli		if (lle == NULL) {
2570186119Sqingli			log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
2571186119Sqingli			return NULL;
2572186119Sqingli		}
2573186119Sqingli		lle->la_flags = flags & ~LLE_CREATE;
2574186119Sqingli		if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
2575186119Sqingli			bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
2576186119Sqingli			lle->la_flags |= (LLE_VALID | LLE_STATIC);
2577186119Sqingli		}
2578186119Sqingli
2579186119Sqingli		lle->lle_tbl  = llt;
2580186119Sqingli		lle->lle_head = lleh;
2581186119Sqingli		LIST_INSERT_HEAD(lleh, lle, lle_next);
2582186119Sqingli	} else if (flags & LLE_DELETE) {
2583186392Sqingli		if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
2584186392Sqingli			LLE_WLOCK(lle);
2585186392Sqingli			lle->la_flags = LLE_DELETED;
2586186392Sqingli			LLE_WUNLOCK(lle);
2587198418Sqingli#ifdef DIAGNOSTIC
2588186392Sqingli			log(LOG_INFO, "ifaddr cache = %p  is deleted\n", lle);
2589186119Sqingli#endif
2590186392Sqingli		}
2591186119Sqingli		lle = (void *)-1;
2592186119Sqingli	}
2593186119Sqingli	if (LLE_IS_VALID(lle)) {
2594186119Sqingli		if (flags & LLE_EXCLUSIVE)
2595186119Sqingli			LLE_WLOCK(lle);
2596186119Sqingli		else
2597186119Sqingli			LLE_RLOCK(lle);
2598186119Sqingli	}
2599186119Sqingli	return (lle);
2600186119Sqingli}
2601186119Sqingli
2602186119Sqinglistatic int
2603186119Sqingliin6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
2604186119Sqingli{
2605186119Sqingli	struct ifnet *ifp = llt->llt_ifp;
2606186119Sqingli	struct llentry *lle;
2607186119Sqingli	/* XXX stack use */
2608186119Sqingli	struct {
2609186119Sqingli		struct rt_msghdr	rtm;
2610186119Sqingli		struct sockaddr_in6	sin6;
2611186119Sqingli		/*
2612186119Sqingli		 * ndp.c assumes that sdl is word aligned
2613186119Sqingli		 */
2614186119Sqingli#ifdef __LP64__
2615186119Sqingli		uint32_t		pad;
2616186119Sqingli#endif
2617186119Sqingli		struct sockaddr_dl	sdl;
2618186119Sqingli	} ndpc;
2619186119Sqingli	int i, error;
2620186119Sqingli
2621196864Sqingli	if (ifp->if_flags & IFF_LOOPBACK)
2622196864Sqingli		return 0;
2623196864Sqingli
2624196535Srwatson	LLTABLE_LOCK_ASSERT();
2625186119Sqingli
2626186119Sqingli	error = 0;
2627186119Sqingli	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
2628186119Sqingli		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
2629186119Sqingli			struct sockaddr_dl *sdl;
2630186119Sqingli
2631186119Sqingli			/* skip deleted or invalid entries */
2632186119Sqingli			if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID)
2633186119Sqingli				continue;
2634186980Sbz			/* Skip if jailed and not a valid IP of the prison. */
2635188144Sjamie			if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0)
2636186980Sbz				continue;
2637186119Sqingli			/*
2638186119Sqingli			 * produce a msg made of:
2639186119Sqingli			 *  struct rt_msghdr;
2640186119Sqingli			 *  struct sockaddr_in6 (IPv6)
2641186119Sqingli			 *  struct sockaddr_dl;
2642186119Sqingli			 */
2643186119Sqingli			bzero(&ndpc, sizeof(ndpc));
2644186119Sqingli			ndpc.rtm.rtm_msglen = sizeof(ndpc);
2645187094Sqingli			ndpc.rtm.rtm_version = RTM_VERSION;
2646187094Sqingli			ndpc.rtm.rtm_type = RTM_GET;
2647187094Sqingli			ndpc.rtm.rtm_flags = RTF_UP;
2648187094Sqingli			ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
2649186119Sqingli			ndpc.sin6.sin6_family = AF_INET6;
2650186119Sqingli			ndpc.sin6.sin6_len = sizeof(ndpc.sin6);
2651186119Sqingli			bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle));
2652186119Sqingli
2653186119Sqingli			/* publish */
2654186119Sqingli			if (lle->la_flags & LLE_PUB)
2655186119Sqingli				ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
2656186119Sqingli
2657186119Sqingli			sdl = &ndpc.sdl;
2658186119Sqingli			sdl->sdl_family = AF_LINK;
2659186119Sqingli			sdl->sdl_len = sizeof(*sdl);
2660186119Sqingli			sdl->sdl_alen = ifp->if_addrlen;
2661186119Sqingli			sdl->sdl_index = ifp->if_index;
2662186119Sqingli			sdl->sdl_type = ifp->if_type;
2663186119Sqingli			bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
2664186119Sqingli			ndpc.rtm.rtm_rmx.rmx_expire =
2665186119Sqingli			    lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
2666186500Sqingli			ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
2667186119Sqingli			if (lle->la_flags & LLE_STATIC)
2668186119Sqingli				ndpc.rtm.rtm_flags |= RTF_STATIC;
2669186119Sqingli			ndpc.rtm.rtm_index = ifp->if_index;
2670186119Sqingli			error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
2671186119Sqingli			if (error)
2672186119Sqingli				break;
2673186119Sqingli		}
2674186119Sqingli	}
2675186119Sqingli	return error;
2676186119Sqingli}
2677186119Sqingli
2678121161Sumevoid *
2679171259Sdelphijin6_domifattach(struct ifnet *ifp)
2680121161Sume{
2681121161Sume	struct in6_ifextra *ext;
2682121161Sume
2683121161Sume	ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
2684121161Sume	bzero(ext, sizeof(*ext));
2685121161Sume
2686121161Sume	ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
2687121161Sume	    M_IFADDR, M_WAITOK);
2688121161Sume	bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
2689121161Sume
2690121161Sume	ext->icmp6_ifstat =
2691121161Sume	    (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
2692121161Sume	    M_IFADDR, M_WAITOK);
2693121161Sume	bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
2694121161Sume
2695121161Sume	ext->nd_ifinfo = nd6_ifattach(ifp);
2696121161Sume	ext->scope6_id = scope6_ifattach(ifp);
2697186119Sqingli	ext->lltable = lltable_init(ifp, AF_INET6);
2698186119Sqingli	if (ext->lltable != NULL) {
2699192476Sqingli		ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
2700186119Sqingli		ext->lltable->llt_lookup = in6_lltable_lookup;
2701186119Sqingli		ext->lltable->llt_dump = in6_lltable_dump;
2702186119Sqingli	}
2703191672Sbms
2704191672Sbms	ext->mld_ifinfo = mld_domifattach(ifp);
2705191672Sbms
2706121161Sume	return ext;
2707121161Sume}
2708121161Sume
2709121161Sumevoid
2710171259Sdelphijin6_domifdetach(struct ifnet *ifp, void *aux)
2711121161Sume{
2712121161Sume	struct in6_ifextra *ext = (struct in6_ifextra *)aux;
2713121161Sume
2714191672Sbms	mld_domifdetach(ifp);
2715121161Sume	scope6_ifdetach(ext->scope6_id);
2716121161Sume	nd6_ifdetach(ext->nd_ifinfo);
2717186119Sqingli	lltable_free(ext->lltable);
2718121161Sume	free(ext->in6_ifstat, M_IFADDR);
2719121161Sume	free(ext->icmp6_ifstat, M_IFADDR);
2720121161Sume	free(ext, M_IFADDR);
2721121161Sume}
2722121161Sume
272353541Sshin/*
272495023Ssuz * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
272553541Sshin * v4 mapped addr or v4 compat addr
272653541Sshin */
272753541Sshinvoid
272853541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
272953541Sshin{
2730171259Sdelphij
273153541Sshin	bzero(sin, sizeof(*sin));
273253541Sshin	sin->sin_len = sizeof(struct sockaddr_in);
273353541Sshin	sin->sin_family = AF_INET;
273453541Sshin	sin->sin_port = sin6->sin6_port;
2735120891Sume	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
273653541Sshin}
273753541Sshin
273853541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
273953541Sshinvoid
274053541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
274153541Sshin{
274253541Sshin	bzero(sin6, sizeof(*sin6));
274353541Sshin	sin6->sin6_len = sizeof(struct sockaddr_in6);
274453541Sshin	sin6->sin6_family = AF_INET6;
274553541Sshin	sin6->sin6_port = sin->sin_port;
274653541Sshin	sin6->sin6_addr.s6_addr32[0] = 0;
274753541Sshin	sin6->sin6_addr.s6_addr32[1] = 0;
274853541Sshin	sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
274953541Sshin	sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
275053541Sshin}
275153541Sshin
275253541Sshin/* Convert sockaddr_in6 into sockaddr_in. */
275353541Sshinvoid
275453541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam)
275553541Sshin{
275653541Sshin	struct sockaddr_in *sin_p;
275753541Sshin	struct sockaddr_in6 sin6;
275853541Sshin
275953541Sshin	/*
276053541Sshin	 * Save original sockaddr_in6 addr and convert it
276153541Sshin	 * to sockaddr_in.
276253541Sshin	 */
276353541Sshin	sin6 = *(struct sockaddr_in6 *)nam;
276453541Sshin	sin_p = (struct sockaddr_in *)nam;
276553541Sshin	in6_sin6_2_sin(sin_p, &sin6);
276653541Sshin}
276753541Sshin
276853541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
276953541Sshinvoid
277053541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
277153541Sshin{
277253541Sshin	struct sockaddr_in *sin_p;
277353541Sshin	struct sockaddr_in6 *sin6_p;
277453541Sshin
2775184205Sdes	sin6_p = malloc(sizeof *sin6_p, M_SONAME,
2776111119Simp	       M_WAITOK);
277753541Sshin	sin_p = (struct sockaddr_in *)*nam;
277853541Sshin	in6_sin_2_v4mapsin6(sin_p, sin6_p);
2779184205Sdes	free(*nam, M_SONAME);
278053541Sshin	*nam = (struct sockaddr *)sin6_p;
278153541Sshin}
2782