xref: /freebsd/sys/netinet6/in6.c (revision 71212473120f655524672d5fa1d6b2eb63c7196c)
1caf43b02SWarner Losh /*-
282cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
382cd038dSYoshinobu Inoue  * All rights reserved.
482cd038dSYoshinobu Inoue  *
582cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
682cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
782cd038dSYoshinobu Inoue  * are met:
882cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
982cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1082cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1282cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1382cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1482cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1582cd038dSYoshinobu Inoue  *    without specific prior written permission.
1682cd038dSYoshinobu Inoue  *
1782cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1882cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1982cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2082cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2182cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2282cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2382cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2482cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2582cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2682cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2782cd038dSYoshinobu Inoue  * SUCH DAMAGE.
28b48287a3SDavid E. O'Brien  *
29b48287a3SDavid E. O'Brien  *	$KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $
3082cd038dSYoshinobu Inoue  */
3182cd038dSYoshinobu Inoue 
32caf43b02SWarner Losh /*-
3382cd038dSYoshinobu Inoue  * Copyright (c) 1982, 1986, 1991, 1993
3482cd038dSYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
3582cd038dSYoshinobu Inoue  *
3682cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
3782cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
3882cd038dSYoshinobu Inoue  * are met:
3982cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
4082cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
4182cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
4282cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
4382cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
4482cd038dSYoshinobu Inoue  * 4. Neither the name of the University nor the names of its contributors
4582cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
4682cd038dSYoshinobu Inoue  *    without specific prior written permission.
4782cd038dSYoshinobu Inoue  *
4882cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4982cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5082cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5182cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5282cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5382cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5482cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5582cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5682cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5782cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5882cd038dSYoshinobu Inoue  * SUCH DAMAGE.
5982cd038dSYoshinobu Inoue  *
6082cd038dSYoshinobu Inoue  *	@(#)in.c	8.2 (Berkeley) 11/15/93
6182cd038dSYoshinobu Inoue  */
6282cd038dSYoshinobu Inoue 
63b48287a3SDavid E. O'Brien #include <sys/cdefs.h>
64b48287a3SDavid E. O'Brien __FBSDID("$FreeBSD$");
65b48287a3SDavid E. O'Brien 
6699c750a8SKonstantin Belousov #include "opt_compat.h"
67686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
68686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h"
69686cdd19SJun-ichiro itojun Hagino 
7082cd038dSYoshinobu Inoue #include <sys/param.h>
7182cd038dSYoshinobu Inoue #include <sys/errno.h>
725ce0eb7fSBjoern A. Zeeb #include <sys/jail.h>
7382cd038dSYoshinobu Inoue #include <sys/malloc.h>
7482cd038dSYoshinobu Inoue #include <sys/socket.h>
7582cd038dSYoshinobu Inoue #include <sys/socketvar.h>
7682cd038dSYoshinobu Inoue #include <sys/sockio.h>
7782cd038dSYoshinobu Inoue #include <sys/systm.h>
78acd3428bSRobert Watson #include <sys/priv.h>
7982cd038dSYoshinobu Inoue #include <sys/proc.h>
8082cd038dSYoshinobu Inoue #include <sys/time.h>
8182cd038dSYoshinobu Inoue #include <sys/kernel.h>
8282cd038dSYoshinobu Inoue #include <sys/syslog.h>
8382cd038dSYoshinobu Inoue 
8482cd038dSYoshinobu Inoue #include <net/if.h>
859bb7d0f4SQing Li #include <net/if_var.h>
8682cd038dSYoshinobu Inoue #include <net/if_types.h>
8782cd038dSYoshinobu Inoue #include <net/route.h>
8882cd038dSYoshinobu Inoue #include <net/if_dl.h>
894b79449eSBjoern A. Zeeb #include <net/vnet.h>
9082cd038dSYoshinobu Inoue 
9182cd038dSYoshinobu Inoue #include <netinet/in.h>
9282cd038dSYoshinobu Inoue #include <netinet/in_var.h>
936e6b3f7cSQing Li #include <net/if_llatbl.h>
9482cd038dSYoshinobu Inoue #include <netinet/if_ether.h>
9533841545SHajimu UMEMOTO #include <netinet/in_systm.h>
9633841545SHajimu UMEMOTO #include <netinet/ip.h>
9733841545SHajimu UMEMOTO #include <netinet/in_pcb.h>
9808b68b0eSGleb Smirnoff #include <netinet/ip_carp.h>
9982cd038dSYoshinobu Inoue 
100686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
10182cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
10288ff5695SSUZUKI Shinsuke #include <netinet6/nd6.h>
10382cd038dSYoshinobu Inoue #include <netinet6/mld6_var.h>
104686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6_mroute.h>
10582cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h>
106686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h>
10733841545SHajimu UMEMOTO #include <netinet6/in6_pcb.h>
108686cdd19SJun-ichiro itojun Hagino 
10982cd038dSYoshinobu Inoue /*
11082cd038dSYoshinobu Inoue  * Definitions of some costant IP6 addresses.
11182cd038dSYoshinobu Inoue  */
11282cd038dSYoshinobu Inoue const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
11382cd038dSYoshinobu Inoue const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
11482cd038dSYoshinobu Inoue const struct in6_addr in6addr_nodelocal_allnodes =
11582cd038dSYoshinobu Inoue 	IN6ADDR_NODELOCAL_ALLNODES_INIT;
11682cd038dSYoshinobu Inoue const struct in6_addr in6addr_linklocal_allnodes =
11782cd038dSYoshinobu Inoue 	IN6ADDR_LINKLOCAL_ALLNODES_INIT;
11882cd038dSYoshinobu Inoue const struct in6_addr in6addr_linklocal_allrouters =
11982cd038dSYoshinobu Inoue 	IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
12033cde130SBruce M Simpson const struct in6_addr in6addr_linklocal_allv2routers =
12133cde130SBruce M Simpson 	IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT;
12282cd038dSYoshinobu Inoue 
12382cd038dSYoshinobu Inoue const struct in6_addr in6mask0 = IN6MASK0;
12482cd038dSYoshinobu Inoue const struct in6_addr in6mask32 = IN6MASK32;
12582cd038dSYoshinobu Inoue const struct in6_addr in6mask64 = IN6MASK64;
12682cd038dSYoshinobu Inoue const struct in6_addr in6mask96 = IN6MASK96;
12782cd038dSYoshinobu Inoue const struct in6_addr in6mask128 = IN6MASK128;
12882cd038dSYoshinobu Inoue 
12959aecc96SHajimu UMEMOTO const struct sockaddr_in6 sa6_any =
13059aecc96SHajimu UMEMOTO 	{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
13133841545SHajimu UMEMOTO 
13282cd038dSYoshinobu Inoue static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
133b40ce416SJulian Elischer 	struct ifnet *, struct thread *));
13433841545SHajimu UMEMOTO static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
13533841545SHajimu UMEMOTO 	struct sockaddr_in6 *, int));
1369233d8f3SDavid E. O'Brien static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
13782cd038dSYoshinobu Inoue 
1389494d596SBrooks Davis int	(*faithprefix_p)(struct in6_addr *);
1399494d596SBrooks Davis 
140b590b6aeSGleb Smirnoff #define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
141b590b6aeSGleb Smirnoff #define ia62ifa(ia6)	(&((ia6)->ia_ifa))
14282cd038dSYoshinobu Inoue 
143b590b6aeSGleb Smirnoff void
144b590b6aeSGleb Smirnoff in6_ifaddloop(struct ifaddr *ifa)
145b590b6aeSGleb Smirnoff {
146b590b6aeSGleb Smirnoff 	struct sockaddr_dl gateway;
147b590b6aeSGleb Smirnoff 	struct sockaddr_in6 mask, addr;
148b590b6aeSGleb Smirnoff 	struct rtentry rt;
149b590b6aeSGleb Smirnoff 	struct in6_ifaddr *ia;
150b590b6aeSGleb Smirnoff 	struct ifnet *ifp;
151b590b6aeSGleb Smirnoff 	struct llentry *ln;
152b590b6aeSGleb Smirnoff 
153b590b6aeSGleb Smirnoff 	ia = ifa2ia6(ifa);
154b590b6aeSGleb Smirnoff 	ifp = ifa->ifa_ifp;
155b590b6aeSGleb Smirnoff 	IF_AFDATA_LOCK(ifp);
1560f1aca65SQing Li 	ifa->ifa_rtrequest = nd6_rtrequest;
157b590b6aeSGleb Smirnoff 
158b590b6aeSGleb Smirnoff 	/* XXX QL
159b590b6aeSGleb Smirnoff 	 * we need to report rt_newaddrmsg
160b590b6aeSGleb Smirnoff 	 */
161b590b6aeSGleb Smirnoff 	ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
162b590b6aeSGleb Smirnoff 	    LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
163b590b6aeSGleb Smirnoff 	IF_AFDATA_UNLOCK(ifp);
164b590b6aeSGleb Smirnoff 	if (ln != NULL) {
165b590b6aeSGleb Smirnoff 		ln->la_expire = 0;  /* for IPv6 this means permanent */
166b590b6aeSGleb Smirnoff 		ln->ln_state = ND6_LLINFO_REACHABLE;
167b590b6aeSGleb Smirnoff 		/*
168b590b6aeSGleb Smirnoff 		 * initialize for rtmsg generation
169b590b6aeSGleb Smirnoff 		 */
170b590b6aeSGleb Smirnoff 		bzero(&gateway, sizeof(gateway));
171b590b6aeSGleb Smirnoff 		gateway.sdl_len = sizeof(gateway);
172b590b6aeSGleb Smirnoff 		gateway.sdl_family = AF_LINK;
173b590b6aeSGleb Smirnoff 		gateway.sdl_nlen = 0;
174b590b6aeSGleb Smirnoff 		gateway.sdl_alen = 6;
175b590b6aeSGleb Smirnoff 		memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned,
176b590b6aeSGleb Smirnoff 		    sizeof(ln->ll_addr));
177b590b6aeSGleb Smirnoff 		LLE_WUNLOCK(ln);
178b590b6aeSGleb Smirnoff 	}
179b590b6aeSGleb Smirnoff 
180b590b6aeSGleb Smirnoff 	bzero(&rt, sizeof(rt));
181b590b6aeSGleb Smirnoff 	rt.rt_gateway = (struct sockaddr *)&gateway;
182b590b6aeSGleb Smirnoff 	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
183b590b6aeSGleb Smirnoff 	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
184b590b6aeSGleb Smirnoff 	rt_mask(&rt) = (struct sockaddr *)&mask;
185b590b6aeSGleb Smirnoff 	rt_key(&rt) = (struct sockaddr *)&addr;
186b590b6aeSGleb Smirnoff 	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
187b590b6aeSGleb Smirnoff 	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
188b590b6aeSGleb Smirnoff }
189b590b6aeSGleb Smirnoff 
190b590b6aeSGleb Smirnoff void
191b590b6aeSGleb Smirnoff in6_ifremloop(struct ifaddr *ifa)
192b590b6aeSGleb Smirnoff {
193b590b6aeSGleb Smirnoff 	struct sockaddr_dl gateway;
194b590b6aeSGleb Smirnoff 	struct sockaddr_in6 mask, addr;
195b590b6aeSGleb Smirnoff 	struct rtentry rt0;
196b590b6aeSGleb Smirnoff 	struct in6_ifaddr *ia;
197b590b6aeSGleb Smirnoff 	struct ifnet *ifp;
198b590b6aeSGleb Smirnoff 
199b590b6aeSGleb Smirnoff 	ia = ifa2ia6(ifa);
200b590b6aeSGleb Smirnoff 	ifp = ifa->ifa_ifp;
201b590b6aeSGleb Smirnoff 	IF_AFDATA_LOCK(ifp);
202b590b6aeSGleb Smirnoff 	lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR),
203b590b6aeSGleb Smirnoff 	    (struct sockaddr *)&ia->ia_addr);
204b590b6aeSGleb Smirnoff 	IF_AFDATA_UNLOCK(ifp);
205b590b6aeSGleb Smirnoff 
206b590b6aeSGleb Smirnoff 	/*
207b590b6aeSGleb Smirnoff 	 * initialize for rtmsg generation
208b590b6aeSGleb Smirnoff 	 */
209b590b6aeSGleb Smirnoff 	bzero(&gateway, sizeof(gateway));
210b590b6aeSGleb Smirnoff 	gateway.sdl_len = sizeof(gateway);
211b590b6aeSGleb Smirnoff 	gateway.sdl_family = AF_LINK;
212b590b6aeSGleb Smirnoff 	gateway.sdl_nlen = 0;
213b590b6aeSGleb Smirnoff 	gateway.sdl_alen = ifp->if_addrlen;
214b590b6aeSGleb Smirnoff 	bzero(&rt0, sizeof(rt0));
215b590b6aeSGleb Smirnoff 	rt0.rt_gateway = (struct sockaddr *)&gateway;
216b590b6aeSGleb Smirnoff 	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
217b590b6aeSGleb Smirnoff 	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
218b590b6aeSGleb Smirnoff 	rt_mask(&rt0) = (struct sockaddr *)&mask;
219b590b6aeSGleb Smirnoff 	rt_key(&rt0) = (struct sockaddr *)&addr;
220b590b6aeSGleb Smirnoff 	rt0.rt_flags = RTF_HOST | RTF_STATIC;
221b590b6aeSGleb Smirnoff 	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
222b590b6aeSGleb Smirnoff }
22382cd038dSYoshinobu Inoue 
22482cd038dSYoshinobu Inoue int
2251272577eSXin LI in6_mask2len(struct in6_addr *mask, u_char *lim0)
22682cd038dSYoshinobu Inoue {
22733841545SHajimu UMEMOTO 	int x = 0, y;
22833841545SHajimu UMEMOTO 	u_char *lim = lim0, *p;
22982cd038dSYoshinobu Inoue 
23006cd0a3fSHajimu UMEMOTO 	/* ignore the scope_id part */
23106cd0a3fSHajimu UMEMOTO 	if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
23233841545SHajimu UMEMOTO 		lim = (u_char *)mask + sizeof(*mask);
23333841545SHajimu UMEMOTO 	for (p = (u_char *)mask; p < lim; x++, p++) {
23433841545SHajimu UMEMOTO 		if (*p != 0xff)
23582cd038dSYoshinobu Inoue 			break;
23682cd038dSYoshinobu Inoue 	}
23782cd038dSYoshinobu Inoue 	y = 0;
23833841545SHajimu UMEMOTO 	if (p < lim) {
23982cd038dSYoshinobu Inoue 		for (y = 0; y < 8; y++) {
24033841545SHajimu UMEMOTO 			if ((*p & (0x80 >> y)) == 0)
24182cd038dSYoshinobu Inoue 				break;
24282cd038dSYoshinobu Inoue 		}
24382cd038dSYoshinobu Inoue 	}
24433841545SHajimu UMEMOTO 
24533841545SHajimu UMEMOTO 	/*
24633841545SHajimu UMEMOTO 	 * when the limit pointer is given, do a stricter check on the
24733841545SHajimu UMEMOTO 	 * remaining bits.
24833841545SHajimu UMEMOTO 	 */
24933841545SHajimu UMEMOTO 	if (p < lim) {
25033841545SHajimu UMEMOTO 		if (y != 0 && (*p & (0x00ff >> y)) != 0)
25133841545SHajimu UMEMOTO 			return (-1);
25233841545SHajimu UMEMOTO 		for (p = p + 1; p < lim; p++)
25333841545SHajimu UMEMOTO 			if (*p != 0)
25433841545SHajimu UMEMOTO 				return (-1);
25533841545SHajimu UMEMOTO 	}
25633841545SHajimu UMEMOTO 
25782cd038dSYoshinobu Inoue 	return x * 8 + y;
25882cd038dSYoshinobu Inoue }
25982cd038dSYoshinobu Inoue 
26099c750a8SKonstantin Belousov #ifdef COMPAT_FREEBSD32
26199c750a8SKonstantin Belousov struct in6_ndifreq32 {
26299c750a8SKonstantin Belousov         char ifname[IFNAMSIZ];
26399c750a8SKonstantin Belousov         uint32_t ifindex;
26499c750a8SKonstantin Belousov };
26599c750a8SKonstantin Belousov #define	SIOCGDEFIFACE32_IN6     _IOWR('i', 86, struct in6_ndifreq32)
26699c750a8SKonstantin Belousov #endif
26799c750a8SKonstantin Belousov 
26882cd038dSYoshinobu Inoue int
2691272577eSXin LI in6_control(struct socket *so, u_long cmd, caddr_t data,
2701272577eSXin LI     struct ifnet *ifp, struct thread *td)
27182cd038dSYoshinobu Inoue {
27282cd038dSYoshinobu Inoue 	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
27333841545SHajimu UMEMOTO 	struct	in6_ifaddr *ia = NULL;
27482cd038dSYoshinobu Inoue 	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
275743eee66SSUZUKI Shinsuke 	struct sockaddr_in6 *sa6;
27608b68b0eSGleb Smirnoff 	int carp_attached = 0;
277acd3428bSRobert Watson 	int error;
278*71212473SGleb Smirnoff 	u_long ocmd = cmd;
279*71212473SGleb Smirnoff 
280*71212473SGleb Smirnoff 	/*
281*71212473SGleb Smirnoff 	 * Compat to make pre-10.x ifconfig(8) operable.
282*71212473SGleb Smirnoff 	 */
283*71212473SGleb Smirnoff 	if (cmd == OSIOCAIFADDR_IN6)
284*71212473SGleb Smirnoff 		cmd = SIOCAIFADDR_IN6;
28582cd038dSYoshinobu Inoue 
286686cdd19SJun-ichiro itojun Hagino 	switch (cmd) {
287686cdd19SJun-ichiro itojun Hagino 	case SIOCGETSGCNT_IN6:
288686cdd19SJun-ichiro itojun Hagino 	case SIOCGETMIFCNT_IN6:
2896be2e366SBruce M Simpson 		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
290686cdd19SJun-ichiro itojun Hagino 	}
29182cd038dSYoshinobu Inoue 
2927fc91b3fSHajimu UMEMOTO 	switch(cmd) {
2937fc91b3fSHajimu UMEMOTO 	case SIOCAADDRCTL_POLICY:
2947fc91b3fSHajimu UMEMOTO 	case SIOCDADDRCTL_POLICY:
295acd3428bSRobert Watson 		if (td != NULL) {
296acd3428bSRobert Watson 			error = priv_check(td, PRIV_NETINET_ADDRCTRL6);
297acd3428bSRobert Watson 			if (error)
298acd3428bSRobert Watson 				return (error);
299acd3428bSRobert Watson 		}
3007fc91b3fSHajimu UMEMOTO 		return (in6_src_ioctl(cmd, data));
3017fc91b3fSHajimu UMEMOTO 	}
3027fc91b3fSHajimu UMEMOTO 
303686cdd19SJun-ichiro itojun Hagino 	if (ifp == NULL)
30482cd038dSYoshinobu Inoue 		return (EOPNOTSUPP);
30582cd038dSYoshinobu Inoue 
30682cd038dSYoshinobu Inoue 	switch (cmd) {
30782cd038dSYoshinobu Inoue 	case SIOCSNDFLUSH_IN6:
30882cd038dSYoshinobu Inoue 	case SIOCSPFXFLUSH_IN6:
30982cd038dSYoshinobu Inoue 	case SIOCSRTRFLUSH_IN6:
310686cdd19SJun-ichiro itojun Hagino 	case SIOCSDEFIFACE_IN6:
311686cdd19SJun-ichiro itojun Hagino 	case SIOCSIFINFO_FLAGS:
3129a1bde18SColin Percival 	case SIOCSIFINFO_IN6:
313acd3428bSRobert Watson 		if (td != NULL) {
314acd3428bSRobert Watson 			error = priv_check(td, PRIV_NETINET_ND6);
315acd3428bSRobert Watson 			if (error)
316acd3428bSRobert Watson 				return (error);
317acd3428bSRobert Watson 		}
31806cd0a3fSHajimu UMEMOTO 		/* FALLTHROUGH */
31933841545SHajimu UMEMOTO 	case OSIOCGIFINFO_IN6:
32082cd038dSYoshinobu Inoue 	case SIOCGIFINFO_IN6:
32182cd038dSYoshinobu Inoue 	case SIOCGDRLST_IN6:
32282cd038dSYoshinobu Inoue 	case SIOCGPRLST_IN6:
32382cd038dSYoshinobu Inoue 	case SIOCGNBRINFO_IN6:
324686cdd19SJun-ichiro itojun Hagino 	case SIOCGDEFIFACE_IN6:
32582cd038dSYoshinobu Inoue 		return (nd6_ioctl(cmd, data, ifp));
32699c750a8SKonstantin Belousov 
32799c750a8SKonstantin Belousov #ifdef COMPAT_FREEBSD32
32899c750a8SKonstantin Belousov 	case SIOCGDEFIFACE32_IN6:
32999c750a8SKonstantin Belousov 		{
33099c750a8SKonstantin Belousov 			struct in6_ndifreq ndif;
33199c750a8SKonstantin Belousov 			struct in6_ndifreq32 *ndif32;
33299c750a8SKonstantin Belousov 
33399c750a8SKonstantin Belousov 			error = nd6_ioctl(SIOCGDEFIFACE_IN6, (caddr_t)&ndif,
33499c750a8SKonstantin Belousov 			    ifp);
33599c750a8SKonstantin Belousov 			if (error)
33699c750a8SKonstantin Belousov 				return (error);
33799c750a8SKonstantin Belousov 			ndif32 = (struct in6_ndifreq32 *)data;
33899c750a8SKonstantin Belousov 			ndif32->ifindex = ndif.ifindex;
33999c750a8SKonstantin Belousov 			return (0);
34099c750a8SKonstantin Belousov 		}
34199c750a8SKonstantin Belousov #endif
34282cd038dSYoshinobu Inoue 	}
34382cd038dSYoshinobu Inoue 
34482cd038dSYoshinobu Inoue 	switch (cmd) {
34582cd038dSYoshinobu Inoue 	case SIOCSIFPREFIX_IN6:
34682cd038dSYoshinobu Inoue 	case SIOCDIFPREFIX_IN6:
34782cd038dSYoshinobu Inoue 	case SIOCAIFPREFIX_IN6:
34882cd038dSYoshinobu Inoue 	case SIOCCIFPREFIX_IN6:
34982cd038dSYoshinobu Inoue 	case SIOCSGIFPREFIX_IN6:
35082cd038dSYoshinobu Inoue 	case SIOCGIFPREFIX_IN6:
35133841545SHajimu UMEMOTO 		log(LOG_NOTICE,
35233841545SHajimu UMEMOTO 		    "prefix ioctls are now invalidated. "
35333841545SHajimu UMEMOTO 		    "please use ifconfig.\n");
35433841545SHajimu UMEMOTO 		return (EOPNOTSUPP);
35582cd038dSYoshinobu Inoue 	}
35682cd038dSYoshinobu Inoue 
35782cd038dSYoshinobu Inoue 	switch (cmd) {
358686cdd19SJun-ichiro itojun Hagino 	case SIOCSSCOPE6:
359acd3428bSRobert Watson 		if (td != NULL) {
360acd3428bSRobert Watson 			error = priv_check(td, PRIV_NETINET_SCOPE6);
361acd3428bSRobert Watson 			if (error)
362acd3428bSRobert Watson 				return (error);
363acd3428bSRobert Watson 		}
36431b1bfe1SHajimu UMEMOTO 		return (scope6_set(ifp,
36531b1bfe1SHajimu UMEMOTO 		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
366686cdd19SJun-ichiro itojun Hagino 	case SIOCGSCOPE6:
36731b1bfe1SHajimu UMEMOTO 		return (scope6_get(ifp,
36831b1bfe1SHajimu UMEMOTO 		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
369686cdd19SJun-ichiro itojun Hagino 	case SIOCGSCOPE6DEF:
37031b1bfe1SHajimu UMEMOTO 		return (scope6_get_default((struct scope6_id *)
37131b1bfe1SHajimu UMEMOTO 		    ifr->ifr_ifru.ifru_scope_id));
372686cdd19SJun-ichiro itojun Hagino 	}
373686cdd19SJun-ichiro itojun Hagino 
374686cdd19SJun-ichiro itojun Hagino 	switch (cmd) {
37582cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
376acd3428bSRobert Watson 		if (td != NULL) {
37779ba3952SBjoern A. Zeeb 			error = priv_check(td, PRIV_NET_ADDIFADDR);
37879ba3952SBjoern A. Zeeb 			if (error)
37979ba3952SBjoern A. Zeeb 				return (error);
38079ba3952SBjoern A. Zeeb 		}
38179ba3952SBjoern A. Zeeb 		return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
38279ba3952SBjoern A. Zeeb 
38379ba3952SBjoern A. Zeeb 	case SIOCDLIFADDR:
38479ba3952SBjoern A. Zeeb 		if (td != NULL) {
38579ba3952SBjoern A. Zeeb 			error = priv_check(td, PRIV_NET_DELIFADDR);
386acd3428bSRobert Watson 			if (error)
387acd3428bSRobert Watson 				return (error);
388acd3428bSRobert Watson 		}
38906cd0a3fSHajimu UMEMOTO 		/* FALLTHROUGH */
39082cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
391b40ce416SJulian Elischer 		return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
39282cd038dSYoshinobu Inoue 	}
39382cd038dSYoshinobu Inoue 
39482cd038dSYoshinobu Inoue 	/*
39582cd038dSYoshinobu Inoue 	 * Find address for this interface, if it exists.
396743eee66SSUZUKI Shinsuke 	 *
397743eee66SSUZUKI Shinsuke 	 * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
398743eee66SSUZUKI Shinsuke 	 * only, and used the first interface address as the target of other
399743eee66SSUZUKI Shinsuke 	 * operations (without checking ifra_addr).  This was because netinet
400743eee66SSUZUKI Shinsuke 	 * code/API assumed at most 1 interface address per interface.
401743eee66SSUZUKI Shinsuke 	 * Since IPv6 allows a node to assign multiple addresses
402743eee66SSUZUKI Shinsuke 	 * on a single interface, we almost always look and check the
403743eee66SSUZUKI Shinsuke 	 * presence of ifra_addr, and reject invalid ones here.
404743eee66SSUZUKI Shinsuke 	 * It also decreases duplicated code among SIOC*_IN6 operations.
40582cd038dSYoshinobu Inoue 	 */
406743eee66SSUZUKI Shinsuke 	switch (cmd) {
407743eee66SSUZUKI Shinsuke 	case SIOCAIFADDR_IN6:
408743eee66SSUZUKI Shinsuke 	case SIOCSIFPHYADDR_IN6:
409743eee66SSUZUKI Shinsuke 		sa6 = &ifra->ifra_addr;
410743eee66SSUZUKI Shinsuke 		break;
411743eee66SSUZUKI Shinsuke 	case SIOCSIFADDR_IN6:
412743eee66SSUZUKI Shinsuke 	case SIOCGIFADDR_IN6:
413743eee66SSUZUKI Shinsuke 	case SIOCSIFDSTADDR_IN6:
414743eee66SSUZUKI Shinsuke 	case SIOCSIFNETMASK_IN6:
415743eee66SSUZUKI Shinsuke 	case SIOCGIFDSTADDR_IN6:
416743eee66SSUZUKI Shinsuke 	case SIOCGIFNETMASK_IN6:
417743eee66SSUZUKI Shinsuke 	case SIOCDIFADDR_IN6:
418743eee66SSUZUKI Shinsuke 	case SIOCGIFPSRCADDR_IN6:
419743eee66SSUZUKI Shinsuke 	case SIOCGIFPDSTADDR_IN6:
420743eee66SSUZUKI Shinsuke 	case SIOCGIFAFLAG_IN6:
421743eee66SSUZUKI Shinsuke 	case SIOCSNDFLUSH_IN6:
422743eee66SSUZUKI Shinsuke 	case SIOCSPFXFLUSH_IN6:
423743eee66SSUZUKI Shinsuke 	case SIOCSRTRFLUSH_IN6:
424743eee66SSUZUKI Shinsuke 	case SIOCGIFALIFETIME_IN6:
425743eee66SSUZUKI Shinsuke 	case SIOCSIFALIFETIME_IN6:
426743eee66SSUZUKI Shinsuke 	case SIOCGIFSTAT_IN6:
427743eee66SSUZUKI Shinsuke 	case SIOCGIFSTAT_ICMP6:
428743eee66SSUZUKI Shinsuke 		sa6 = &ifr->ifr_addr;
429743eee66SSUZUKI Shinsuke 		break;
430743eee66SSUZUKI Shinsuke 	default:
431743eee66SSUZUKI Shinsuke 		sa6 = NULL;
432743eee66SSUZUKI Shinsuke 		break;
433743eee66SSUZUKI Shinsuke 	}
434743eee66SSUZUKI Shinsuke 	if (sa6 && sa6->sin6_family == AF_INET6) {
435743eee66SSUZUKI Shinsuke 		if (sa6->sin6_scope_id != 0)
436743eee66SSUZUKI Shinsuke 			error = sa6_embedscope(sa6, 0);
437a1f7e5f8SHajimu UMEMOTO 		else
438743eee66SSUZUKI Shinsuke 			error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
439a1f7e5f8SHajimu UMEMOTO 		if (error != 0)
440a1f7e5f8SHajimu UMEMOTO 			return (error);
441b89e82ddSJamie Gritton 		if (td != NULL && (error = prison_check_ip6(td->td_ucred,
442b89e82ddSJamie Gritton 		    &sa6->sin6_addr)) != 0)
443b89e82ddSJamie Gritton 			return (error);
444743eee66SSUZUKI Shinsuke 		ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
445743eee66SSUZUKI Shinsuke 	} else
446743eee66SSUZUKI Shinsuke 		ia = NULL;
44782cd038dSYoshinobu Inoue 
44882cd038dSYoshinobu Inoue 	switch (cmd) {
44982cd038dSYoshinobu Inoue 	case SIOCSIFADDR_IN6:
45082cd038dSYoshinobu Inoue 	case SIOCSIFDSTADDR_IN6:
451686cdd19SJun-ichiro itojun Hagino 	case SIOCSIFNETMASK_IN6:
452686cdd19SJun-ichiro itojun Hagino 		/*
453686cdd19SJun-ichiro itojun Hagino 		 * Since IPv6 allows a node to assign multiple addresses
4542ce62dceSSUZUKI Shinsuke 		 * on a single interface, SIOCSIFxxx ioctls are deprecated.
455686cdd19SJun-ichiro itojun Hagino 		 */
45633841545SHajimu UMEMOTO 		/* we decided to obsolete this command (20000704) */
4578c0fec80SRobert Watson 		error = EINVAL;
4588c0fec80SRobert Watson 		goto out;
45933841545SHajimu UMEMOTO 
46033841545SHajimu UMEMOTO 	case SIOCDIFADDR_IN6:
46133841545SHajimu UMEMOTO 		/*
46233841545SHajimu UMEMOTO 		 * for IPv4, we look for existing in_ifaddr here to allow
4632ce62dceSSUZUKI Shinsuke 		 * "ifconfig if0 delete" to remove the first IPv4 address on
4642ce62dceSSUZUKI Shinsuke 		 * the interface.  For IPv6, as the spec allows multiple
4652ce62dceSSUZUKI Shinsuke 		 * interface address from the day one, we consider "remove the
4662ce62dceSSUZUKI Shinsuke 		 * first one" semantics to be not preferable.
46733841545SHajimu UMEMOTO 		 */
4688c0fec80SRobert Watson 		if (ia == NULL) {
4698c0fec80SRobert Watson 			error = EADDRNOTAVAIL;
4708c0fec80SRobert Watson 			goto out;
4718c0fec80SRobert Watson 		}
47233841545SHajimu UMEMOTO 		/* FALLTHROUGH */
47333841545SHajimu UMEMOTO 	case SIOCAIFADDR_IN6:
47433841545SHajimu UMEMOTO 		/*
47533841545SHajimu UMEMOTO 		 * We always require users to specify a valid IPv6 address for
47633841545SHajimu UMEMOTO 		 * the corresponding operation.
47733841545SHajimu UMEMOTO 		 */
47833841545SHajimu UMEMOTO 		if (ifra->ifra_addr.sin6_family != AF_INET6 ||
4798c0fec80SRobert Watson 		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
4808c0fec80SRobert Watson 			error = EAFNOSUPPORT;
4818c0fec80SRobert Watson 			goto out;
4828c0fec80SRobert Watson 		}
483acd3428bSRobert Watson 
484acd3428bSRobert Watson 		if (td != NULL) {
48579ba3952SBjoern A. Zeeb 			error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
48679ba3952SBjoern A. Zeeb 			    PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
487acd3428bSRobert Watson 			if (error)
4888c0fec80SRobert Watson 				goto out;
489acd3428bSRobert Watson 		}
49082cd038dSYoshinobu Inoue 		break;
49182cd038dSYoshinobu Inoue 
49282cd038dSYoshinobu Inoue 	case SIOCGIFADDR_IN6:
49382cd038dSYoshinobu Inoue 		/* This interface is basically deprecated. use SIOCGIFCONF. */
49406cd0a3fSHajimu UMEMOTO 		/* FALLTHROUGH */
49582cd038dSYoshinobu Inoue 	case SIOCGIFAFLAG_IN6:
49682cd038dSYoshinobu Inoue 	case SIOCGIFNETMASK_IN6:
49782cd038dSYoshinobu Inoue 	case SIOCGIFDSTADDR_IN6:
49882cd038dSYoshinobu Inoue 	case SIOCGIFALIFETIME_IN6:
49982cd038dSYoshinobu Inoue 		/* must think again about its semantics */
5008c0fec80SRobert Watson 		if (ia == NULL) {
5018c0fec80SRobert Watson 			error = EADDRNOTAVAIL;
5028c0fec80SRobert Watson 			goto out;
5038c0fec80SRobert Watson 		}
50482cd038dSYoshinobu Inoue 		break;
5058c0fec80SRobert Watson 
50682cd038dSYoshinobu Inoue 	case SIOCSIFALIFETIME_IN6:
50782cd038dSYoshinobu Inoue 	    {
50882cd038dSYoshinobu Inoue 		struct in6_addrlifetime *lt;
50982cd038dSYoshinobu Inoue 
510acd3428bSRobert Watson 		if (td != NULL) {
511acd3428bSRobert Watson 			error = priv_check(td, PRIV_NETINET_ALIFETIME6);
512acd3428bSRobert Watson 			if (error)
5138c0fec80SRobert Watson 				goto out;
514acd3428bSRobert Watson 		}
5158c0fec80SRobert Watson 		if (ia == NULL) {
5168c0fec80SRobert Watson 			error = EADDRNOTAVAIL;
5178c0fec80SRobert Watson 			goto out;
5188c0fec80SRobert Watson 		}
51982cd038dSYoshinobu Inoue 		/* sanity for overflow - beware unsigned */
52082cd038dSYoshinobu Inoue 		lt = &ifr->ifr_ifru.ifru_lifetime;
52159aecc96SHajimu UMEMOTO 		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME &&
52259aecc96SHajimu UMEMOTO 		    lt->ia6t_vltime + time_second < time_second) {
5238c0fec80SRobert Watson 			error = EINVAL;
5248c0fec80SRobert Watson 			goto out;
52582cd038dSYoshinobu Inoue 		}
52659aecc96SHajimu UMEMOTO 		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME &&
52759aecc96SHajimu UMEMOTO 		    lt->ia6t_pltime + time_second < time_second) {
5288c0fec80SRobert Watson 			error = EINVAL;
5298c0fec80SRobert Watson 			goto out;
53082cd038dSYoshinobu Inoue 		}
53182cd038dSYoshinobu Inoue 		break;
53282cd038dSYoshinobu Inoue 	    }
53382cd038dSYoshinobu Inoue 	}
53482cd038dSYoshinobu Inoue 
53582cd038dSYoshinobu Inoue 	switch (cmd) {
53682cd038dSYoshinobu Inoue 	case SIOCGIFADDR_IN6:
53782cd038dSYoshinobu Inoue 		ifr->ifr_addr = ia->ia_addr;
538a1f7e5f8SHajimu UMEMOTO 		if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
5398c0fec80SRobert Watson 			goto out;
54082cd038dSYoshinobu Inoue 		break;
54182cd038dSYoshinobu Inoue 
54282cd038dSYoshinobu Inoue 	case SIOCGIFDSTADDR_IN6:
5438c0fec80SRobert Watson 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
5448c0fec80SRobert Watson 			error = EINVAL;
5458c0fec80SRobert Watson 			goto out;
5468c0fec80SRobert Watson 		}
547686cdd19SJun-ichiro itojun Hagino 		/*
548686cdd19SJun-ichiro itojun Hagino 		 * XXX: should we check if ifa_dstaddr is NULL and return
549686cdd19SJun-ichiro itojun Hagino 		 * an error?
550686cdd19SJun-ichiro itojun Hagino 		 */
55182cd038dSYoshinobu Inoue 		ifr->ifr_dstaddr = ia->ia_dstaddr;
552a1f7e5f8SHajimu UMEMOTO 		if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0)
5538c0fec80SRobert Watson 			goto out;
55482cd038dSYoshinobu Inoue 		break;
55582cd038dSYoshinobu Inoue 
55682cd038dSYoshinobu Inoue 	case SIOCGIFNETMASK_IN6:
55782cd038dSYoshinobu Inoue 		ifr->ifr_addr = ia->ia_prefixmask;
55882cd038dSYoshinobu Inoue 		break;
55982cd038dSYoshinobu Inoue 
56082cd038dSYoshinobu Inoue 	case SIOCGIFAFLAG_IN6:
56182cd038dSYoshinobu Inoue 		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
56282cd038dSYoshinobu Inoue 		break;
56382cd038dSYoshinobu Inoue 
56482cd038dSYoshinobu Inoue 	case SIOCGIFSTAT_IN6:
5658c0fec80SRobert Watson 		if (ifp == NULL) {
5668c0fec80SRobert Watson 			error = EINVAL;
5678c0fec80SRobert Watson 			goto out;
5688c0fec80SRobert Watson 		}
56982cd038dSYoshinobu Inoue 		bzero(&ifr->ifr_ifru.ifru_stat,
57082cd038dSYoshinobu Inoue 		    sizeof(ifr->ifr_ifru.ifru_stat));
57131b1bfe1SHajimu UMEMOTO 		ifr->ifr_ifru.ifru_stat =
57231b1bfe1SHajimu UMEMOTO 		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
57382cd038dSYoshinobu Inoue 		break;
57482cd038dSYoshinobu Inoue 
57582cd038dSYoshinobu Inoue 	case SIOCGIFSTAT_ICMP6:
5768c0fec80SRobert Watson 		if (ifp == NULL) {
5778c0fec80SRobert Watson 			error = EINVAL;
5788c0fec80SRobert Watson 			goto out;
5798c0fec80SRobert Watson 		}
580f2b1bd14SGeorge V. Neville-Neil 		bzero(&ifr->ifr_ifru.ifru_icmp6stat,
58182cd038dSYoshinobu Inoue 		    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
58282cd038dSYoshinobu Inoue 		ifr->ifr_ifru.ifru_icmp6stat =
58331b1bfe1SHajimu UMEMOTO 		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
58482cd038dSYoshinobu Inoue 		break;
58582cd038dSYoshinobu Inoue 
58682cd038dSYoshinobu Inoue 	case SIOCGIFALIFETIME_IN6:
58782cd038dSYoshinobu Inoue 		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
588743eee66SSUZUKI Shinsuke 		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
589743eee66SSUZUKI Shinsuke 			time_t maxexpire;
590743eee66SSUZUKI Shinsuke 			struct in6_addrlifetime *retlt =
591743eee66SSUZUKI Shinsuke 			    &ifr->ifr_ifru.ifru_lifetime;
592743eee66SSUZUKI Shinsuke 
593743eee66SSUZUKI Shinsuke 			/*
594743eee66SSUZUKI Shinsuke 			 * XXX: adjust expiration time assuming time_t is
595743eee66SSUZUKI Shinsuke 			 * signed.
596743eee66SSUZUKI Shinsuke 			 */
597743eee66SSUZUKI Shinsuke 			maxexpire = (-1) &
59836dc24e6SSUZUKI Shinsuke 			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
599743eee66SSUZUKI Shinsuke 			if (ia->ia6_lifetime.ia6t_vltime <
600743eee66SSUZUKI Shinsuke 			    maxexpire - ia->ia6_updatetime) {
601743eee66SSUZUKI Shinsuke 				retlt->ia6t_expire = ia->ia6_updatetime +
602743eee66SSUZUKI Shinsuke 				    ia->ia6_lifetime.ia6t_vltime;
603743eee66SSUZUKI Shinsuke 			} else
604743eee66SSUZUKI Shinsuke 				retlt->ia6t_expire = maxexpire;
605743eee66SSUZUKI Shinsuke 		}
606743eee66SSUZUKI Shinsuke 		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
607743eee66SSUZUKI Shinsuke 			time_t maxexpire;
608743eee66SSUZUKI Shinsuke 			struct in6_addrlifetime *retlt =
609743eee66SSUZUKI Shinsuke 			    &ifr->ifr_ifru.ifru_lifetime;
610743eee66SSUZUKI Shinsuke 
611743eee66SSUZUKI Shinsuke 			/*
612743eee66SSUZUKI Shinsuke 			 * XXX: adjust expiration time assuming time_t is
613743eee66SSUZUKI Shinsuke 			 * signed.
614743eee66SSUZUKI Shinsuke 			 */
615743eee66SSUZUKI Shinsuke 			maxexpire = (-1) &
61636dc24e6SSUZUKI Shinsuke 			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
617743eee66SSUZUKI Shinsuke 			if (ia->ia6_lifetime.ia6t_pltime <
618743eee66SSUZUKI Shinsuke 			    maxexpire - ia->ia6_updatetime) {
619743eee66SSUZUKI Shinsuke 				retlt->ia6t_preferred = ia->ia6_updatetime +
620743eee66SSUZUKI Shinsuke 				    ia->ia6_lifetime.ia6t_pltime;
621743eee66SSUZUKI Shinsuke 			} else
622743eee66SSUZUKI Shinsuke 				retlt->ia6t_preferred = maxexpire;
623743eee66SSUZUKI Shinsuke 		}
62482cd038dSYoshinobu Inoue 		break;
62582cd038dSYoshinobu Inoue 
62682cd038dSYoshinobu Inoue 	case SIOCSIFALIFETIME_IN6:
62782cd038dSYoshinobu Inoue 		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
62882cd038dSYoshinobu Inoue 		/* for sanity */
62982cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
63082cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire =
63182cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_vltime;
63282cd038dSYoshinobu Inoue 		} else
63382cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire = 0;
63482cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
63582cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred =
63682cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_pltime;
63782cd038dSYoshinobu Inoue 		} else
63882cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred = 0;
63982cd038dSYoshinobu Inoue 		break;
64082cd038dSYoshinobu Inoue 
64182cd038dSYoshinobu Inoue 	case SIOCAIFADDR_IN6:
64233841545SHajimu UMEMOTO 	{
6438c0fec80SRobert Watson 		int i;
644743eee66SSUZUKI Shinsuke 		struct nd_prefixctl pr0;
645743eee66SSUZUKI Shinsuke 		struct nd_prefix *pr;
64682cd038dSYoshinobu Inoue 
64733841545SHajimu UMEMOTO 		/*
64833841545SHajimu UMEMOTO 		 * first, make or update the interface address structure,
64933841545SHajimu UMEMOTO 		 * and link it to the list.
65033841545SHajimu UMEMOTO 		 */
651743eee66SSUZUKI Shinsuke 		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
6528c0fec80SRobert Watson 			goto out;
6538c0fec80SRobert Watson 		if (ia != NULL)
6548c0fec80SRobert Watson 			ifa_free(&ia->ia_ifa);
655797df30dSSUZUKI Shinsuke 		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
656797df30dSSUZUKI Shinsuke 		    == NULL) {
657797df30dSSUZUKI Shinsuke 			/*
658797df30dSSUZUKI Shinsuke 			 * this can happen when the user specify the 0 valid
659797df30dSSUZUKI Shinsuke 			 * lifetime.
660797df30dSSUZUKI Shinsuke 			 */
661797df30dSSUZUKI Shinsuke 			break;
662797df30dSSUZUKI Shinsuke 		}
66382cd038dSYoshinobu Inoue 
664*71212473SGleb Smirnoff 		if (cmd == ocmd && ifra->ifra_vhid > 0) {
66508b68b0eSGleb Smirnoff 			if (carp_attach_p != NULL)
66608b68b0eSGleb Smirnoff 				error = (*carp_attach_p)(&ia->ia_ifa,
66708b68b0eSGleb Smirnoff 				    ifra->ifra_vhid);
66808b68b0eSGleb Smirnoff 			else
66908b68b0eSGleb Smirnoff 				error = EPROTONOSUPPORT;
67008b68b0eSGleb Smirnoff 			if (error)
67108b68b0eSGleb Smirnoff 				goto out;
67208b68b0eSGleb Smirnoff 			else
67308b68b0eSGleb Smirnoff 				carp_attached = 1;
67408b68b0eSGleb Smirnoff 		}
67508b68b0eSGleb Smirnoff 
67633841545SHajimu UMEMOTO 		/*
67733841545SHajimu UMEMOTO 		 * then, make the prefix on-link on the interface.
67833841545SHajimu UMEMOTO 		 * XXX: we'd rather create the prefix before the address, but
67933841545SHajimu UMEMOTO 		 * we need at least one address to install the corresponding
68033841545SHajimu UMEMOTO 		 * interface route, so we configure the address first.
68133841545SHajimu UMEMOTO 		 */
68233841545SHajimu UMEMOTO 
68333841545SHajimu UMEMOTO 		/*
68433841545SHajimu UMEMOTO 		 * convert mask to prefix length (prefixmask has already
68533841545SHajimu UMEMOTO 		 * been validated in in6_update_ifa().
68633841545SHajimu UMEMOTO 		 */
68733841545SHajimu UMEMOTO 		bzero(&pr0, sizeof(pr0));
68833841545SHajimu UMEMOTO 		pr0.ndpr_ifp = ifp;
68933841545SHajimu UMEMOTO 		pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
69033841545SHajimu UMEMOTO 		    NULL);
69106cd0a3fSHajimu UMEMOTO 		if (pr0.ndpr_plen == 128) {
69233841545SHajimu UMEMOTO 			break;	/* we don't need to install a host route. */
69306cd0a3fSHajimu UMEMOTO 		}
69433841545SHajimu UMEMOTO 		pr0.ndpr_prefix = ifra->ifra_addr;
69533841545SHajimu UMEMOTO 		/* apply the mask for safety. */
69633841545SHajimu UMEMOTO 		for (i = 0; i < 4; i++) {
69733841545SHajimu UMEMOTO 			pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
69833841545SHajimu UMEMOTO 			    ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
69933841545SHajimu UMEMOTO 		}
70033841545SHajimu UMEMOTO 		/*
70188ff5695SSUZUKI Shinsuke 		 * XXX: since we don't have an API to set prefix (not address)
70288ff5695SSUZUKI Shinsuke 		 * lifetimes, we just use the same lifetimes as addresses.
70388ff5695SSUZUKI Shinsuke 		 * The (temporarily) installed lifetimes can be overridden by
70488ff5695SSUZUKI Shinsuke 		 * later advertised RAs (when accept_rtadv is non 0), which is
70588ff5695SSUZUKI Shinsuke 		 * an intended behavior.
70633841545SHajimu UMEMOTO 		 */
70733841545SHajimu UMEMOTO 		pr0.ndpr_raf_onlink = 1; /* should be configurable? */
70833841545SHajimu UMEMOTO 		pr0.ndpr_raf_auto =
70933841545SHajimu UMEMOTO 		    ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
71033841545SHajimu UMEMOTO 		pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
71133841545SHajimu UMEMOTO 		pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
71233841545SHajimu UMEMOTO 
71306cd0a3fSHajimu UMEMOTO 		/* add the prefix if not yet. */
71433841545SHajimu UMEMOTO 		if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
71533841545SHajimu UMEMOTO 			/*
71633841545SHajimu UMEMOTO 			 * nd6_prelist_add will install the corresponding
71733841545SHajimu UMEMOTO 			 * interface route.
71833841545SHajimu UMEMOTO 			 */
71908b68b0eSGleb Smirnoff 			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
72008b68b0eSGleb Smirnoff 				if (carp_attached)
72108b68b0eSGleb Smirnoff 					(*carp_detach_p)(&ia->ia_ifa);
7228c0fec80SRobert Watson 				goto out;
72308b68b0eSGleb Smirnoff 			}
72433841545SHajimu UMEMOTO 			if (pr == NULL) {
72508b68b0eSGleb Smirnoff 				if (carp_attached)
72608b68b0eSGleb Smirnoff 					(*carp_detach_p)(&ia->ia_ifa);
72706cd0a3fSHajimu UMEMOTO 				log(LOG_ERR, "nd6_prelist_add succeeded but "
72833841545SHajimu UMEMOTO 				    "no prefix\n");
7298c0fec80SRobert Watson 				error = EINVAL;
7308c0fec80SRobert Watson 				goto out;
73133841545SHajimu UMEMOTO 			}
73233841545SHajimu UMEMOTO 		}
733797df30dSSUZUKI Shinsuke 
734797df30dSSUZUKI Shinsuke 		/* relate the address to the prefix */
735797df30dSSUZUKI Shinsuke 		if (ia->ia6_ndpr == NULL) {
73633841545SHajimu UMEMOTO 			ia->ia6_ndpr = pr;
73733841545SHajimu UMEMOTO 			pr->ndpr_refcnt++;
73833841545SHajimu UMEMOTO 
73933841545SHajimu UMEMOTO 			/*
740797df30dSSUZUKI Shinsuke 			 * If this is the first autoconf address from the
741797df30dSSUZUKI Shinsuke 			 * prefix, create a temporary address as well
742797df30dSSUZUKI Shinsuke 			 * (when required).
74333841545SHajimu UMEMOTO 			 */
744797df30dSSUZUKI Shinsuke 			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
745603724d3SBjoern A. Zeeb 			    V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) {
74633841545SHajimu UMEMOTO 				int e;
747743eee66SSUZUKI Shinsuke 				if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
748797df30dSSUZUKI Shinsuke 					log(LOG_NOTICE, "in6_control: failed "
749797df30dSSUZUKI Shinsuke 					    "to create a temporary address, "
7504835e2c7SHajimu UMEMOTO 					    "errno=%d\n", e);
75133841545SHajimu UMEMOTO 				}
75233841545SHajimu UMEMOTO 			}
75333841545SHajimu UMEMOTO 		}
75433841545SHajimu UMEMOTO 
75533841545SHajimu UMEMOTO 		/*
756797df30dSSUZUKI Shinsuke 		 * this might affect the status of autoconfigured addresses,
757797df30dSSUZUKI Shinsuke 		 * that is, this address might make other addresses detached.
75833841545SHajimu UMEMOTO 		 */
75933841545SHajimu UMEMOTO 		pfxlist_onlink_check();
76077bc4985SHiroki Sato 		if (error == 0 && ia) {
76177bc4985SHiroki Sato 			if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
76277bc4985SHiroki Sato 				/*
76377bc4985SHiroki Sato 				 * Try to clear the flag when a new
76477bc4985SHiroki Sato 				 * IPv6 address is added onto an
76577bc4985SHiroki Sato 				 * IFDISABLED interface and it
76677bc4985SHiroki Sato 				 * succeeds.
76777bc4985SHiroki Sato 				 */
76877bc4985SHiroki Sato 				struct in6_ndireq nd;
76977bc4985SHiroki Sato 
77077bc4985SHiroki Sato 				memset(&nd, 0, sizeof(nd));
77177bc4985SHiroki Sato 				nd.ndi.flags = ND_IFINFO(ifp)->flags;
77277bc4985SHiroki Sato 				nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
77377bc4985SHiroki Sato 				if (nd6_ioctl(SIOCSIFINFO_FLAGS,
77477bc4985SHiroki Sato 				    (caddr_t)&nd, ifp) < 0)
77577bc4985SHiroki Sato 					log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
77677bc4985SHiroki Sato 					    "SIOCSIFINFO_FLAGS for -ifdisabled "
77777bc4985SHiroki Sato 					    "failed.");
77877bc4985SHiroki Sato 				/*
77977bc4985SHiroki Sato 				 * Ignore failure of clearing the flag
78077bc4985SHiroki Sato 				 * intentionally.  The failure means
78177bc4985SHiroki Sato 				 * address duplication was detected.
78277bc4985SHiroki Sato 				 */
78377bc4985SHiroki Sato 			}
78425a4adceSMax Laier 			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
78577bc4985SHiroki Sato 		}
78633841545SHajimu UMEMOTO 		break;
78733841545SHajimu UMEMOTO 	}
78833841545SHajimu UMEMOTO 
78933841545SHajimu UMEMOTO 	case SIOCDIFADDR_IN6:
79033841545SHajimu UMEMOTO 	{
791743eee66SSUZUKI Shinsuke 		struct nd_prefix *pr;
79233841545SHajimu UMEMOTO 
79333841545SHajimu UMEMOTO 		/*
79433841545SHajimu UMEMOTO 		 * If the address being deleted is the only one that owns
79533841545SHajimu UMEMOTO 		 * the corresponding prefix, expire the prefix as well.
79606cd0a3fSHajimu UMEMOTO 		 * XXX: theoretically, we don't have to worry about such
79733841545SHajimu UMEMOTO 		 * relationship, since we separate the address management
79833841545SHajimu UMEMOTO 		 * and the prefix management.  We do this, however, to provide
79933841545SHajimu UMEMOTO 		 * as much backward compatibility as possible in terms of
80033841545SHajimu UMEMOTO 		 * the ioctl operation.
801797df30dSSUZUKI Shinsuke 		 * Note that in6_purgeaddr() will decrement ndpr_refcnt.
80233841545SHajimu UMEMOTO 		 */
803797df30dSSUZUKI Shinsuke 		pr = ia->ia6_ndpr;
80433841545SHajimu UMEMOTO 		in6_purgeaddr(&ia->ia_ifa);
805797df30dSSUZUKI Shinsuke 		if (pr && pr->ndpr_refcnt == 0)
806797df30dSSUZUKI Shinsuke 			prelist_remove(pr);
80725a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
80833841545SHajimu UMEMOTO 		break;
80933841545SHajimu UMEMOTO 	}
81033841545SHajimu UMEMOTO 
81133841545SHajimu UMEMOTO 	default:
8128c0fec80SRobert Watson 		if (ifp == NULL || ifp->if_ioctl == 0) {
8138c0fec80SRobert Watson 			error = EOPNOTSUPP;
8148c0fec80SRobert Watson 			goto out;
8158c0fec80SRobert Watson 		}
8168c0fec80SRobert Watson 		error = (*ifp->if_ioctl)(ifp, cmd, data);
8178c0fec80SRobert Watson 		goto out;
81833841545SHajimu UMEMOTO 	}
81933841545SHajimu UMEMOTO 
8208c0fec80SRobert Watson 	error = 0;
8218c0fec80SRobert Watson out:
8228c0fec80SRobert Watson 	if (ia != NULL)
8238c0fec80SRobert Watson 		ifa_free(&ia->ia_ifa);
8248c0fec80SRobert Watson 	return (error);
82533841545SHajimu UMEMOTO }
82633841545SHajimu UMEMOTO 
82733841545SHajimu UMEMOTO /*
82833841545SHajimu UMEMOTO  * Update parameters of an IPv6 interface address.
82933841545SHajimu UMEMOTO  * If necessary, a new entry is created and linked into address chains.
83033841545SHajimu UMEMOTO  * This function is separated from in6_control().
83133841545SHajimu UMEMOTO  * XXX: should this be performed under splnet()?
83233841545SHajimu UMEMOTO  */
83333841545SHajimu UMEMOTO int
8341272577eSXin LI in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
8351272577eSXin LI     struct in6_ifaddr *ia, int flags)
83633841545SHajimu UMEMOTO {
83733841545SHajimu UMEMOTO 	int error = 0, hostIsNew = 0, plen = -1;
83833841545SHajimu UMEMOTO 	struct sockaddr_in6 dst6;
83933841545SHajimu UMEMOTO 	struct in6_addrlifetime *lt;
840743eee66SSUZUKI Shinsuke 	struct in6_multi_mship *imm;
841743eee66SSUZUKI Shinsuke 	struct in6_multi *in6m_sol;
842a1f7e5f8SHajimu UMEMOTO 	struct rtentry *rt;
843743eee66SSUZUKI Shinsuke 	int delay;
8441d54aa3bSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
84533841545SHajimu UMEMOTO 
84633841545SHajimu UMEMOTO 	/* Validate parameters */
84733841545SHajimu UMEMOTO 	if (ifp == NULL || ifra == NULL) /* this maybe redundant */
84833841545SHajimu UMEMOTO 		return (EINVAL);
84933841545SHajimu UMEMOTO 
850686cdd19SJun-ichiro itojun Hagino 	/*
851686cdd19SJun-ichiro itojun Hagino 	 * The destination address for a p2p link must have a family
852686cdd19SJun-ichiro itojun Hagino 	 * of AF_UNSPEC or AF_INET6.
853686cdd19SJun-ichiro itojun Hagino 	 */
854686cdd19SJun-ichiro itojun Hagino 	if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
855686cdd19SJun-ichiro itojun Hagino 	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
856686cdd19SJun-ichiro itojun Hagino 	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
857686cdd19SJun-ichiro itojun Hagino 		return (EAFNOSUPPORT);
858686cdd19SJun-ichiro itojun Hagino 	/*
85933841545SHajimu UMEMOTO 	 * validate ifra_prefixmask.  don't check sin6_family, netmask
86033841545SHajimu UMEMOTO 	 * does not carry fields other than sin6_len.
861686cdd19SJun-ichiro itojun Hagino 	 */
86233841545SHajimu UMEMOTO 	if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
86333841545SHajimu UMEMOTO 		return (EINVAL);
86482cd038dSYoshinobu Inoue 	/*
86533841545SHajimu UMEMOTO 	 * Because the IPv6 address architecture is classless, we require
86633841545SHajimu UMEMOTO 	 * users to specify a (non 0) prefix length (mask) for a new address.
86733841545SHajimu UMEMOTO 	 * We also require the prefix (when specified) mask is valid, and thus
86833841545SHajimu UMEMOTO 	 * reject a non-consecutive mask.
86982cd038dSYoshinobu Inoue 	 */
87033841545SHajimu UMEMOTO 	if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
87133841545SHajimu UMEMOTO 		return (EINVAL);
87233841545SHajimu UMEMOTO 	if (ifra->ifra_prefixmask.sin6_len != 0) {
87333841545SHajimu UMEMOTO 		plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
87433841545SHajimu UMEMOTO 		    (u_char *)&ifra->ifra_prefixmask +
87533841545SHajimu UMEMOTO 		    ifra->ifra_prefixmask.sin6_len);
87633841545SHajimu UMEMOTO 		if (plen <= 0)
87733841545SHajimu UMEMOTO 			return (EINVAL);
87806cd0a3fSHajimu UMEMOTO 	} else {
87933841545SHajimu UMEMOTO 		/*
88033841545SHajimu UMEMOTO 		 * In this case, ia must not be NULL.  We just use its prefix
88133841545SHajimu UMEMOTO 		 * length.
88233841545SHajimu UMEMOTO 		 */
88333841545SHajimu UMEMOTO 		plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
88482cd038dSYoshinobu Inoue 	}
88533841545SHajimu UMEMOTO 	/*
88633841545SHajimu UMEMOTO 	 * If the destination address on a p2p interface is specified,
88733841545SHajimu UMEMOTO 	 * and the address is a scoped one, validate/set the scope
88833841545SHajimu UMEMOTO 	 * zone identifier.
88933841545SHajimu UMEMOTO 	 */
89033841545SHajimu UMEMOTO 	dst6 = ifra->ifra_dstaddr;
89106cd0a3fSHajimu UMEMOTO 	if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 &&
89233841545SHajimu UMEMOTO 	    (dst6.sin6_family == AF_INET6)) {
893a1f7e5f8SHajimu UMEMOTO 		struct in6_addr in6_tmp;
89459aecc96SHajimu UMEMOTO 		u_int32_t zoneid;
89533841545SHajimu UMEMOTO 
896a1f7e5f8SHajimu UMEMOTO 		in6_tmp = dst6.sin6_addr;
897a1f7e5f8SHajimu UMEMOTO 		if (in6_setscope(&in6_tmp, ifp, &zoneid))
898a1f7e5f8SHajimu UMEMOTO 			return (EINVAL); /* XXX: should be impossible */
899a1f7e5f8SHajimu UMEMOTO 
900a1f7e5f8SHajimu UMEMOTO 		if (dst6.sin6_scope_id != 0) {
901a1f7e5f8SHajimu UMEMOTO 			if (dst6.sin6_scope_id != zoneid)
9029a4f9608SHajimu UMEMOTO 				return (EINVAL);
903a1f7e5f8SHajimu UMEMOTO 		} else		/* user omit to specify the ID. */
90459aecc96SHajimu UMEMOTO 			dst6.sin6_scope_id = zoneid;
905a1f7e5f8SHajimu UMEMOTO 
906a1f7e5f8SHajimu UMEMOTO 		/* convert into the internal form */
907a1f7e5f8SHajimu UMEMOTO 		if (sa6_embedscope(&dst6, 0))
908a1f7e5f8SHajimu UMEMOTO 			return (EINVAL); /* XXX: should be impossible */
909686cdd19SJun-ichiro itojun Hagino 	}
91033841545SHajimu UMEMOTO 	/*
91133841545SHajimu UMEMOTO 	 * The destination address can be specified only for a p2p or a
91233841545SHajimu UMEMOTO 	 * loopback interface.  If specified, the corresponding prefix length
91333841545SHajimu UMEMOTO 	 * must be 128.
91433841545SHajimu UMEMOTO 	 */
91533841545SHajimu UMEMOTO 	if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
91633841545SHajimu UMEMOTO 		if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
91759aecc96SHajimu UMEMOTO 			/* XXX: noisy message */
9184835e2c7SHajimu UMEMOTO 			nd6log((LOG_INFO, "in6_update_ifa: a destination can "
9194835e2c7SHajimu UMEMOTO 			    "be specified for a p2p or a loopback IF only\n"));
92033841545SHajimu UMEMOTO 			return (EINVAL);
92133841545SHajimu UMEMOTO 		}
92233841545SHajimu UMEMOTO 		if (plen != 128) {
9234835e2c7SHajimu UMEMOTO 			nd6log((LOG_INFO, "in6_update_ifa: prefixlen should "
9244835e2c7SHajimu UMEMOTO 			    "be 128 when dstaddr is specified\n"));
92533841545SHajimu UMEMOTO 			return (EINVAL);
92633841545SHajimu UMEMOTO 		}
92733841545SHajimu UMEMOTO 	}
92833841545SHajimu UMEMOTO 	/* lifetime consistency check */
92933841545SHajimu UMEMOTO 	lt = &ifra->ifra_lifetime;
930743eee66SSUZUKI Shinsuke 	if (lt->ia6t_pltime > lt->ia6t_vltime)
931743eee66SSUZUKI Shinsuke 		return (EINVAL);
93233841545SHajimu UMEMOTO 	if (lt->ia6t_vltime == 0) {
93333841545SHajimu UMEMOTO 		/*
93433841545SHajimu UMEMOTO 		 * the following log might be noisy, but this is a typical
93533841545SHajimu UMEMOTO 		 * configuration mistake or a tool's bug.
93633841545SHajimu UMEMOTO 		 */
9374835e2c7SHajimu UMEMOTO 		nd6log((LOG_INFO,
93833841545SHajimu UMEMOTO 		    "in6_update_ifa: valid lifetime is 0 for %s\n",
9391d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr)));
940743eee66SSUZUKI Shinsuke 
941743eee66SSUZUKI Shinsuke 		if (ia == NULL)
942743eee66SSUZUKI Shinsuke 			return (0); /* there's nothing to do */
94333841545SHajimu UMEMOTO 	}
94482cd038dSYoshinobu Inoue 
94582cd038dSYoshinobu Inoue 	/*
94633841545SHajimu UMEMOTO 	 * If this is a new address, allocate a new ifaddr and link it
94733841545SHajimu UMEMOTO 	 * into chains.
94833841545SHajimu UMEMOTO 	 */
94933841545SHajimu UMEMOTO 	if (ia == NULL) {
95033841545SHajimu UMEMOTO 		hostIsNew = 1;
95109541513SHajimu UMEMOTO 		/*
95209541513SHajimu UMEMOTO 		 * When in6_update_ifa() is called in a process of a received
95306cd0a3fSHajimu UMEMOTO 		 * RA, it is called under an interrupt context.  So, we should
95406cd0a3fSHajimu UMEMOTO 		 * call malloc with M_NOWAIT.
95509541513SHajimu UMEMOTO 		 */
95606cd0a3fSHajimu UMEMOTO 		ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR,
95706cd0a3fSHajimu UMEMOTO 		    M_NOWAIT);
95833841545SHajimu UMEMOTO 		if (ia == NULL)
95933841545SHajimu UMEMOTO 			return (ENOBUFS);
96033841545SHajimu UMEMOTO 		bzero((caddr_t)ia, sizeof(*ia));
9611099f828SRobert Watson 		ifa_init(&ia->ia_ifa);
96209a52a55SJINMEI Tatuya 		LIST_INIT(&ia->ia6_memberships);
963743eee66SSUZUKI Shinsuke 		/* Initialize the address and masks, and put time stamp */
96433841545SHajimu UMEMOTO 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
96533841545SHajimu UMEMOTO 		ia->ia_addr.sin6_family = AF_INET6;
96633841545SHajimu UMEMOTO 		ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
967743eee66SSUZUKI Shinsuke 		ia->ia6_createtime = time_second;
96833841545SHajimu UMEMOTO 		if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
96933841545SHajimu UMEMOTO 			/*
97033841545SHajimu UMEMOTO 			 * XXX: some functions expect that ifa_dstaddr is not
97133841545SHajimu UMEMOTO 			 * NULL for p2p interfaces.
97233841545SHajimu UMEMOTO 			 */
97306cd0a3fSHajimu UMEMOTO 			ia->ia_ifa.ifa_dstaddr =
97406cd0a3fSHajimu UMEMOTO 			    (struct sockaddr *)&ia->ia_dstaddr;
97533841545SHajimu UMEMOTO 		} else {
97633841545SHajimu UMEMOTO 			ia->ia_ifa.ifa_dstaddr = NULL;
97733841545SHajimu UMEMOTO 		}
97819fc74fbSJeffrey Hsu 		ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
97933841545SHajimu UMEMOTO 		ia->ia_ifp = ifp;
9808c0fec80SRobert Watson 		ifa_ref(&ia->ia_ifa);			/* if_addrhead */
981ac6ba962SRobert Watson 		IF_ADDR_LOCK(ifp);
982c4dd3fe1SRobert Watson 		TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
983ac6ba962SRobert Watson 		IF_ADDR_UNLOCK(ifp);
98480af0152SRobert Watson 
985d1da0a06SRobert Watson 		ifa_ref(&ia->ia_ifa);			/* in6_ifaddrhead */
986d1da0a06SRobert Watson 		IN6_IFADDR_WLOCK();
98780af0152SRobert Watson 		TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
988d1da0a06SRobert Watson 		IN6_IFADDR_WUNLOCK();
98933841545SHajimu UMEMOTO 	}
99033841545SHajimu UMEMOTO 
991743eee66SSUZUKI Shinsuke 	/* update timestamp */
992743eee66SSUZUKI Shinsuke 	ia->ia6_updatetime = time_second;
993743eee66SSUZUKI Shinsuke 
99433841545SHajimu UMEMOTO 	/* set prefix mask */
99533841545SHajimu UMEMOTO 	if (ifra->ifra_prefixmask.sin6_len) {
99633841545SHajimu UMEMOTO 		/*
99733841545SHajimu UMEMOTO 		 * We prohibit changing the prefix length of an existing
99833841545SHajimu UMEMOTO 		 * address, because
99933841545SHajimu UMEMOTO 		 * + such an operation should be rare in IPv6, and
100033841545SHajimu UMEMOTO 		 * + the operation would confuse prefix management.
100133841545SHajimu UMEMOTO 		 */
100233841545SHajimu UMEMOTO 		if (ia->ia_prefixmask.sin6_len &&
100333841545SHajimu UMEMOTO 		    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
10044835e2c7SHajimu UMEMOTO 			nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an"
100533841545SHajimu UMEMOTO 			    " existing (%s) address should not be changed\n",
10061d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
100733841545SHajimu UMEMOTO 			error = EINVAL;
100833841545SHajimu UMEMOTO 			goto unlink;
100933841545SHajimu UMEMOTO 		}
101033841545SHajimu UMEMOTO 		ia->ia_prefixmask = ifra->ifra_prefixmask;
101133841545SHajimu UMEMOTO 	}
101233841545SHajimu UMEMOTO 
101333841545SHajimu UMEMOTO 	/*
101433841545SHajimu UMEMOTO 	 * If a new destination address is specified, scrub the old one and
101533841545SHajimu UMEMOTO 	 * install the new destination.  Note that the interface must be
101633841545SHajimu UMEMOTO 	 * p2p or loopback (see the check above.)
101733841545SHajimu UMEMOTO 	 */
101833841545SHajimu UMEMOTO 	if (dst6.sin6_family == AF_INET6 &&
101906cd0a3fSHajimu UMEMOTO 	    !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
102033841545SHajimu UMEMOTO 		int e;
102133841545SHajimu UMEMOTO 
102233841545SHajimu UMEMOTO 		if ((ia->ia_flags & IFA_ROUTE) != 0 &&
102306cd0a3fSHajimu UMEMOTO 		    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) {
10244835e2c7SHajimu UMEMOTO 			nd6log((LOG_ERR, "in6_update_ifa: failed to remove "
102533841545SHajimu UMEMOTO 			    "a route to the old destination: %s\n",
10261d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
102733841545SHajimu UMEMOTO 			/* proceed anyway... */
102806cd0a3fSHajimu UMEMOTO 		} else
102933841545SHajimu UMEMOTO 			ia->ia_flags &= ~IFA_ROUTE;
103033841545SHajimu UMEMOTO 		ia->ia_dstaddr = dst6;
103133841545SHajimu UMEMOTO 	}
103233841545SHajimu UMEMOTO 
1033a1f7e5f8SHajimu UMEMOTO 	/*
1034a1f7e5f8SHajimu UMEMOTO 	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
1035a1f7e5f8SHajimu UMEMOTO 	 * to see if the address is deprecated or invalidated, but initialize
1036a1f7e5f8SHajimu UMEMOTO 	 * these members for applications.
1037a1f7e5f8SHajimu UMEMOTO 	 */
1038a1f7e5f8SHajimu UMEMOTO 	ia->ia6_lifetime = ifra->ifra_lifetime;
1039a1f7e5f8SHajimu UMEMOTO 	if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
1040a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_expire =
1041a1f7e5f8SHajimu UMEMOTO 		    time_second + ia->ia6_lifetime.ia6t_vltime;
1042a1f7e5f8SHajimu UMEMOTO 	} else
1043a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_expire = 0;
1044a1f7e5f8SHajimu UMEMOTO 	if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
1045a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_preferred =
1046a1f7e5f8SHajimu UMEMOTO 		    time_second + ia->ia6_lifetime.ia6t_pltime;
1047a1f7e5f8SHajimu UMEMOTO 	} else
1048a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_preferred = 0;
1049a1f7e5f8SHajimu UMEMOTO 
105033841545SHajimu UMEMOTO 	/* reset the interface and routing table appropriately. */
105133841545SHajimu UMEMOTO 	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
105233841545SHajimu UMEMOTO 		goto unlink;
105333841545SHajimu UMEMOTO 
105433841545SHajimu UMEMOTO 	/*
1055a1f7e5f8SHajimu UMEMOTO 	 * configure address flags.
1056a1f7e5f8SHajimu UMEMOTO 	 */
1057a1f7e5f8SHajimu UMEMOTO 	ia->ia6_flags = ifra->ifra_flags;
1058a1f7e5f8SHajimu UMEMOTO 	/*
1059a1f7e5f8SHajimu UMEMOTO 	 * backward compatibility - if IN6_IFF_DEPRECATED is set from the
1060a1f7e5f8SHajimu UMEMOTO 	 * userland, make it deprecated.
1061a1f7e5f8SHajimu UMEMOTO 	 */
1062a1f7e5f8SHajimu UMEMOTO 	if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
1063a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_pltime = 0;
1064a1f7e5f8SHajimu UMEMOTO 		ia->ia6_lifetime.ia6t_preferred = time_second;
1065a1f7e5f8SHajimu UMEMOTO 	}
1066a1f7e5f8SHajimu UMEMOTO 	/*
1067743eee66SSUZUKI Shinsuke 	 * Make the address tentative before joining multicast addresses,
1068743eee66SSUZUKI Shinsuke 	 * so that corresponding MLD responses would not have a tentative
1069743eee66SSUZUKI Shinsuke 	 * source address.
1070a1f7e5f8SHajimu UMEMOTO 	 */
1071743eee66SSUZUKI Shinsuke 	ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/* safety */
1072743eee66SSUZUKI Shinsuke 	if (hostIsNew && in6if_do_dad(ifp))
1073a1f7e5f8SHajimu UMEMOTO 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
1074a1f7e5f8SHajimu UMEMOTO 
1075a283298cSHiroki Sato 	/* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */
1076a283298cSHiroki Sato 	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
1077a283298cSHiroki Sato 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
1078a283298cSHiroki Sato 
1079a1f7e5f8SHajimu UMEMOTO 	/*
1080a1f7e5f8SHajimu UMEMOTO 	 * We are done if we have simply modified an existing address.
1081a1f7e5f8SHajimu UMEMOTO 	 */
1082a1f7e5f8SHajimu UMEMOTO 	if (!hostIsNew)
1083a1f7e5f8SHajimu UMEMOTO 		return (error);
1084a1f7e5f8SHajimu UMEMOTO 
1085a1f7e5f8SHajimu UMEMOTO 	/*
108633841545SHajimu UMEMOTO 	 * Beyond this point, we should call in6_purgeaddr upon an error,
108733841545SHajimu UMEMOTO 	 * not just go to unlink.
108833841545SHajimu UMEMOTO 	 */
108933841545SHajimu UMEMOTO 
10902ce62dceSSUZUKI Shinsuke 	/* Join necessary multicast groups */
1091743eee66SSUZUKI Shinsuke 	in6m_sol = NULL;
109233841545SHajimu UMEMOTO 	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
109333841545SHajimu UMEMOTO 		struct sockaddr_in6 mltaddr, mltmask;
109482cd038dSYoshinobu Inoue 		struct in6_addr llsol;
109506cd0a3fSHajimu UMEMOTO 
1096a1f7e5f8SHajimu UMEMOTO 		/* join solicited multicast addr for new host id */
109782cd038dSYoshinobu Inoue 		bzero(&llsol, sizeof(struct in6_addr));
10982ce62dceSSUZUKI Shinsuke 		llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
109982cd038dSYoshinobu Inoue 		llsol.s6_addr32[1] = 0;
110082cd038dSYoshinobu Inoue 		llsol.s6_addr32[2] = htonl(1);
1101a1f7e5f8SHajimu UMEMOTO 		llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
110282cd038dSYoshinobu Inoue 		llsol.s6_addr8[12] = 0xff;
1103a1f7e5f8SHajimu UMEMOTO 		if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
1104a1f7e5f8SHajimu UMEMOTO 			/* XXX: should not happen */
1105a1f7e5f8SHajimu UMEMOTO 			log(LOG_ERR, "in6_update_ifa: "
1106a1f7e5f8SHajimu UMEMOTO 			    "in6_setscope failed\n");
1107a1f7e5f8SHajimu UMEMOTO 			goto cleanup;
1108a1f7e5f8SHajimu UMEMOTO 		}
1109743eee66SSUZUKI Shinsuke 		delay = 0;
1110743eee66SSUZUKI Shinsuke 		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1111743eee66SSUZUKI Shinsuke 			/*
1112743eee66SSUZUKI Shinsuke 			 * We need a random delay for DAD on the address
1113743eee66SSUZUKI Shinsuke 			 * being configured.  It also means delaying
1114743eee66SSUZUKI Shinsuke 			 * transmission of the corresponding MLD report to
1115743eee66SSUZUKI Shinsuke 			 * avoid report collision.
1116a283298cSHiroki Sato 			 * [RFC 4861, Section 6.3.7]
1117743eee66SSUZUKI Shinsuke 			 */
1118743eee66SSUZUKI Shinsuke 			delay = arc4random() %
1119743eee66SSUZUKI Shinsuke 			    (MAX_RTR_SOLICITATION_DELAY * hz);
1120743eee66SSUZUKI Shinsuke 		}
1121743eee66SSUZUKI Shinsuke 		imm = in6_joingroup(ifp, &llsol, &error, delay);
112209a52a55SJINMEI Tatuya 		if (imm == NULL) {
11234835e2c7SHajimu UMEMOTO 			nd6log((LOG_WARNING,
112433841545SHajimu UMEMOTO 			    "in6_update_ifa: addmulti failed for "
112533841545SHajimu UMEMOTO 			    "%s on %s (errno=%d)\n",
11261d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &llsol), if_name(ifp),
11274835e2c7SHajimu UMEMOTO 			    error));
1128f291b9cdSRobert Watson 			goto cleanup;
112933841545SHajimu UMEMOTO 		}
113009a52a55SJINMEI Tatuya 		LIST_INSERT_HEAD(&ia->ia6_memberships,
113109a52a55SJINMEI Tatuya 		    imm, i6mm_chain);
1132743eee66SSUZUKI Shinsuke 		in6m_sol = imm->i6mm_maddr;
113333841545SHajimu UMEMOTO 
113433841545SHajimu UMEMOTO 		bzero(&mltmask, sizeof(mltmask));
113533841545SHajimu UMEMOTO 		mltmask.sin6_len = sizeof(struct sockaddr_in6);
113633841545SHajimu UMEMOTO 		mltmask.sin6_family = AF_INET6;
113733841545SHajimu UMEMOTO 		mltmask.sin6_addr = in6mask32;
11382ce62dceSSUZUKI Shinsuke #define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
113933841545SHajimu UMEMOTO 
114033841545SHajimu UMEMOTO 		/*
114133841545SHajimu UMEMOTO 		 * join link-local all-nodes address
114233841545SHajimu UMEMOTO 		 */
114333841545SHajimu UMEMOTO 		bzero(&mltaddr, sizeof(mltaddr));
114433841545SHajimu UMEMOTO 		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
114533841545SHajimu UMEMOTO 		mltaddr.sin6_family = AF_INET6;
114633841545SHajimu UMEMOTO 		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
1147a1f7e5f8SHajimu UMEMOTO 		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
1148a1f7e5f8SHajimu UMEMOTO 		    0)
1149a1f7e5f8SHajimu UMEMOTO 			goto cleanup; /* XXX: should not fail */
1150a1f7e5f8SHajimu UMEMOTO 
1151a1f7e5f8SHajimu UMEMOTO 		/*
1152a1f7e5f8SHajimu UMEMOTO 		 * XXX: do we really need this automatic routes?
1153a1f7e5f8SHajimu UMEMOTO 		 * We should probably reconsider this stuff.  Most applications
1154a1f7e5f8SHajimu UMEMOTO 		 * actually do not need the routes, since they usually specify
1155a1f7e5f8SHajimu UMEMOTO 		 * the outgoing interface.
1156a1f7e5f8SHajimu UMEMOTO 		 */
1157a1f7e5f8SHajimu UMEMOTO 		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1158a1f7e5f8SHajimu UMEMOTO 		if (rt) {
1159743eee66SSUZUKI Shinsuke 			/* XXX: only works in !SCOPEDROUTING case. */
1160743eee66SSUZUKI Shinsuke 			if (memcmp(&mltaddr.sin6_addr,
1161743eee66SSUZUKI Shinsuke 			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1162743eee66SSUZUKI Shinsuke 			    MLTMASK_LEN)) {
1163743eee66SSUZUKI Shinsuke 				RTFREE_LOCKED(rt);
1164743eee66SSUZUKI Shinsuke 				rt = NULL;
1165743eee66SSUZUKI Shinsuke 			}
1166743eee66SSUZUKI Shinsuke 		}
1167743eee66SSUZUKI Shinsuke 		if (!rt) {
1168743eee66SSUZUKI Shinsuke 			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
1169743eee66SSUZUKI Shinsuke 			    (struct sockaddr *)&ia->ia_addr,
11706e6b3f7cSQing Li 			    (struct sockaddr *)&mltmask, RTF_UP,
1171743eee66SSUZUKI Shinsuke 			    (struct rtentry **)0);
1172743eee66SSUZUKI Shinsuke 			if (error)
1173743eee66SSUZUKI Shinsuke 				goto cleanup;
1174743eee66SSUZUKI Shinsuke 		} else {
1175743eee66SSUZUKI Shinsuke 			RTFREE_LOCKED(rt);
1176743eee66SSUZUKI Shinsuke 		}
1177743eee66SSUZUKI Shinsuke 
1178743eee66SSUZUKI Shinsuke 		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
1179743eee66SSUZUKI Shinsuke 		if (!imm) {
11804835e2c7SHajimu UMEMOTO 			nd6log((LOG_WARNING,
118133841545SHajimu UMEMOTO 			    "in6_update_ifa: addmulti failed for "
118233841545SHajimu UMEMOTO 			    "%s on %s (errno=%d)\n",
11831d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
11844835e2c7SHajimu UMEMOTO 			    if_name(ifp), error));
1185a1f7e5f8SHajimu UMEMOTO 			goto cleanup;
118633841545SHajimu UMEMOTO 		}
118709a52a55SJINMEI Tatuya 		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
118833841545SHajimu UMEMOTO 
118933841545SHajimu UMEMOTO 		/*
119033841545SHajimu UMEMOTO 		 * join node information group address
119133841545SHajimu UMEMOTO 		 */
1192743eee66SSUZUKI Shinsuke 		delay = 0;
1193743eee66SSUZUKI Shinsuke 		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1194743eee66SSUZUKI Shinsuke 			/*
1195743eee66SSUZUKI Shinsuke 			 * The spec doesn't say anything about delay for this
1196743eee66SSUZUKI Shinsuke 			 * group, but the same logic should apply.
1197743eee66SSUZUKI Shinsuke 			 */
1198743eee66SSUZUKI Shinsuke 			delay = arc4random() %
1199743eee66SSUZUKI Shinsuke 			    (MAX_RTR_SOLICITATION_DELAY * hz);
1200743eee66SSUZUKI Shinsuke 		}
12010304c731SJamie Gritton 		if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
1202743eee66SSUZUKI Shinsuke 			imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
1203743eee66SSUZUKI Shinsuke 			    delay); /* XXX jinmei */
1204743eee66SSUZUKI Shinsuke 			if (!imm) {
12054835e2c7SHajimu UMEMOTO 				nd6log((LOG_WARNING, "in6_update_ifa: "
1206743eee66SSUZUKI Shinsuke 				    "addmulti failed for %s on %s "
1207743eee66SSUZUKI Shinsuke 				    "(errno=%d)\n",
12081d54aa3bSBjoern A. Zeeb 				    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
12094835e2c7SHajimu UMEMOTO 				    if_name(ifp), error));
1210743eee66SSUZUKI Shinsuke 				/* XXX not very fatal, go on... */
121109a52a55SJINMEI Tatuya 			} else {
121209a52a55SJINMEI Tatuya 				LIST_INSERT_HEAD(&ia->ia6_memberships,
121309a52a55SJINMEI Tatuya 				    imm, i6mm_chain);
121433841545SHajimu UMEMOTO 			}
12150304c731SJamie Gritton 		}
121633841545SHajimu UMEMOTO 
121733841545SHajimu UMEMOTO 		/*
1218a1f7e5f8SHajimu UMEMOTO 		 * join interface-local all-nodes address.
1219a1f7e5f8SHajimu UMEMOTO 		 * (ff01::1%ifN, and ff01::%ifN/32)
122033841545SHajimu UMEMOTO 		 */
122133841545SHajimu UMEMOTO 		mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
1222a1f7e5f8SHajimu UMEMOTO 		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
1223a1f7e5f8SHajimu UMEMOTO 		    != 0)
1224a1f7e5f8SHajimu UMEMOTO 			goto cleanup; /* XXX: should not fail */
1225a1f7e5f8SHajimu UMEMOTO 		/* XXX: again, do we really need the route? */
1226a1f7e5f8SHajimu UMEMOTO 		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1227a1f7e5f8SHajimu UMEMOTO 		if (rt) {
1228a1f7e5f8SHajimu UMEMOTO 			if (memcmp(&mltaddr.sin6_addr,
1229a1f7e5f8SHajimu UMEMOTO 			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
12302ce62dceSSUZUKI Shinsuke 			    MLTMASK_LEN)) {
1231a1f7e5f8SHajimu UMEMOTO 				RTFREE_LOCKED(rt);
1232a1f7e5f8SHajimu UMEMOTO 				rt = NULL;
1233a1f7e5f8SHajimu UMEMOTO 			}
1234a1f7e5f8SHajimu UMEMOTO 		}
1235a1f7e5f8SHajimu UMEMOTO 		if (!rt) {
1236a1f7e5f8SHajimu UMEMOTO 			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
1237a1f7e5f8SHajimu UMEMOTO 			    (struct sockaddr *)&ia->ia_addr,
12386e6b3f7cSQing Li 			    (struct sockaddr *)&mltmask, RTF_UP,
1239a1f7e5f8SHajimu UMEMOTO 			    (struct rtentry **)0);
1240a1f7e5f8SHajimu UMEMOTO 			if (error)
1241a1f7e5f8SHajimu UMEMOTO 				goto cleanup;
1242a1f7e5f8SHajimu UMEMOTO 		} else
1243a1f7e5f8SHajimu UMEMOTO 			RTFREE_LOCKED(rt);
124433841545SHajimu UMEMOTO 
1245743eee66SSUZUKI Shinsuke 		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
1246743eee66SSUZUKI Shinsuke 		if (!imm) {
12474835e2c7SHajimu UMEMOTO 			nd6log((LOG_WARNING, "in6_update_ifa: "
124833841545SHajimu UMEMOTO 			    "addmulti failed for %s on %s "
124933841545SHajimu UMEMOTO 			    "(errno=%d)\n",
12501d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
12514835e2c7SHajimu UMEMOTO 			    if_name(ifp), error));
1252a1f7e5f8SHajimu UMEMOTO 			goto cleanup;
125333841545SHajimu UMEMOTO 		}
125409a52a55SJINMEI Tatuya 		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
12552ce62dceSSUZUKI Shinsuke #undef	MLTMASK_LEN
125633841545SHajimu UMEMOTO 	}
125782cd038dSYoshinobu Inoue 
1258743eee66SSUZUKI Shinsuke 	/*
1259743eee66SSUZUKI Shinsuke 	 * Perform DAD, if needed.
1260743eee66SSUZUKI Shinsuke 	 * XXX It may be of use, if we can administratively
1261743eee66SSUZUKI Shinsuke 	 * disable DAD.
1262743eee66SSUZUKI Shinsuke 	 */
12638c0fec80SRobert Watson 	if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
1264743eee66SSUZUKI Shinsuke 	    (ia->ia6_flags & IN6_IFF_TENTATIVE))
1265743eee66SSUZUKI Shinsuke 	{
1266743eee66SSUZUKI Shinsuke 		int mindelay, maxdelay;
1267743eee66SSUZUKI Shinsuke 
1268743eee66SSUZUKI Shinsuke 		delay = 0;
1269743eee66SSUZUKI Shinsuke 		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1270743eee66SSUZUKI Shinsuke 			/*
1271743eee66SSUZUKI Shinsuke 			 * We need to impose a delay before sending an NS
1272743eee66SSUZUKI Shinsuke 			 * for DAD.  Check if we also needed a delay for the
1273743eee66SSUZUKI Shinsuke 			 * corresponding MLD message.  If we did, the delay
1274743eee66SSUZUKI Shinsuke 			 * should be larger than the MLD delay (this could be
1275743eee66SSUZUKI Shinsuke 			 * relaxed a bit, but this simple logic is at least
1276743eee66SSUZUKI Shinsuke 			 * safe).
127733cde130SBruce M Simpson 			 * XXX: Break data hiding guidelines and look at
127833cde130SBruce M Simpson 			 * state for the solicited multicast group.
1279743eee66SSUZUKI Shinsuke 			 */
1280743eee66SSUZUKI Shinsuke 			mindelay = 0;
1281743eee66SSUZUKI Shinsuke 			if (in6m_sol != NULL &&
128233cde130SBruce M Simpson 			    in6m_sol->in6m_state == MLD_REPORTING_MEMBER) {
1283743eee66SSUZUKI Shinsuke 				mindelay = in6m_sol->in6m_timer;
1284743eee66SSUZUKI Shinsuke 			}
1285743eee66SSUZUKI Shinsuke 			maxdelay = MAX_RTR_SOLICITATION_DELAY * hz;
1286743eee66SSUZUKI Shinsuke 			if (maxdelay - mindelay == 0)
1287743eee66SSUZUKI Shinsuke 				delay = 0;
1288743eee66SSUZUKI Shinsuke 			else {
1289743eee66SSUZUKI Shinsuke 				delay =
1290743eee66SSUZUKI Shinsuke 				    (arc4random() % (maxdelay - mindelay)) +
1291743eee66SSUZUKI Shinsuke 				    mindelay;
1292743eee66SSUZUKI Shinsuke 			}
1293743eee66SSUZUKI Shinsuke 		}
1294743eee66SSUZUKI Shinsuke 		nd6_dad_start((struct ifaddr *)ia, delay);
1295743eee66SSUZUKI Shinsuke 	}
1296743eee66SSUZUKI Shinsuke 
12978c0fec80SRobert Watson 	KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew"));
12988c0fec80SRobert Watson 	ifa_free(&ia->ia_ifa);
129982cd038dSYoshinobu Inoue 	return (error);
130082cd038dSYoshinobu Inoue 
130133841545SHajimu UMEMOTO   unlink:
130233841545SHajimu UMEMOTO 	/*
130333841545SHajimu UMEMOTO 	 * XXX: if a change of an existing address failed, keep the entry
130433841545SHajimu UMEMOTO 	 * anyway.
130533841545SHajimu UMEMOTO 	 */
13068c0fec80SRobert Watson 	if (hostIsNew) {
130733841545SHajimu UMEMOTO 		in6_unlink_ifa(ia, ifp);
13083cfed08dSRobert Watson 		ifa_free(&ia->ia_ifa);
13098c0fec80SRobert Watson 	}
131033841545SHajimu UMEMOTO 	return (error);
1311a1f7e5f8SHajimu UMEMOTO 
1312a1f7e5f8SHajimu UMEMOTO   cleanup:
13138c0fec80SRobert Watson 	KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew"));
13148c0fec80SRobert Watson 	ifa_free(&ia->ia_ifa);
1315a1f7e5f8SHajimu UMEMOTO 	in6_purgeaddr(&ia->ia_ifa);
1316a1f7e5f8SHajimu UMEMOTO 	return error;
1317686cdd19SJun-ichiro itojun Hagino }
1318686cdd19SJun-ichiro itojun Hagino 
1319686cdd19SJun-ichiro itojun Hagino void
13201272577eSXin LI in6_purgeaddr(struct ifaddr *ifa)
1321686cdd19SJun-ichiro itojun Hagino {
132233841545SHajimu UMEMOTO 	struct ifnet *ifp = ifa->ifa_ifp;
132333841545SHajimu UMEMOTO 	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
132409a52a55SJINMEI Tatuya 	struct in6_multi_mship *imm;
1325511e8a53SQing Li 	struct sockaddr_in6 mltaddr, mltmask;
1326511e8a53SQing Li 	int plen, error;
1327511e8a53SQing Li 	struct rtentry *rt;
1328511e8a53SQing Li 	struct ifaddr *ifa0, *nifa;
1329511e8a53SQing Li 
133008b68b0eSGleb Smirnoff 	if (ifa->ifa_carp)
133108b68b0eSGleb Smirnoff 		(*carp_detach_p)(ifa);
133208b68b0eSGleb Smirnoff 
1333511e8a53SQing Li 	/*
1334511e8a53SQing Li 	 * find another IPv6 address as the gateway for the
1335511e8a53SQing Li 	 * link-local and node-local all-nodes multicast
1336511e8a53SQing Li 	 * address routes
1337511e8a53SQing Li 	 */
13388c0fec80SRobert Watson 	IF_ADDR_LOCK(ifp);
1339511e8a53SQing Li 	TAILQ_FOREACH_SAFE(ifa0, &ifp->if_addrhead, ifa_link, nifa) {
1340511e8a53SQing Li 		if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
1341511e8a53SQing Li 		    memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
1342511e8a53SQing Li 			   &ia->ia_addr.sin6_addr,
1343511e8a53SQing Li 			   sizeof(struct in6_addr)) == 0)
1344511e8a53SQing Li 			continue;
1345511e8a53SQing Li 		else
1346511e8a53SQing Li 			break;
1347511e8a53SQing Li 	}
13488c0fec80SRobert Watson 	if (ifa0 != NULL)
13498c0fec80SRobert Watson 		ifa_ref(ifa0);
13508c0fec80SRobert Watson 	IF_ADDR_UNLOCK(ifp);
1351686cdd19SJun-ichiro itojun Hagino 
1352df813b7eSQing Li 	/*
1353df813b7eSQing Li 	 * Remove the loopback route to the interface address.
1354d134008aSQing Li 	 * The check for the current setting of "nd6_useloopback"
1355d134008aSQing Li 	 * is not needed.
1356df813b7eSQing Li 	 */
1357c7ab6602SQing Li 	if (ia->ia_flags & IFA_RTSELF) {
13589bb7d0f4SQing Li 		error = ifa_del_loopback_route((struct ifaddr *)ia,
13599bb7d0f4SQing Li 				       (struct sockaddr *)&ia->ia_addr);
1360c7ab6602SQing Li 		if (error == 0)
1361c7ab6602SQing Li 			ia->ia_flags &= ~IFA_RTSELF;
1362c7ab6602SQing Li 	}
136305b262e2SQing Li 
136433841545SHajimu UMEMOTO 	/* stop DAD processing */
136533841545SHajimu UMEMOTO 	nd6_dad_stop(ifa);
136633841545SHajimu UMEMOTO 
1367b590b6aeSGleb Smirnoff 	in6_ifremloop(ifa);
1368511e8a53SQing Li 
1369511e8a53SQing Li 	/*
137009a52a55SJINMEI Tatuya 	 * leave from multicast groups we have joined for the interface
137182cd038dSYoshinobu Inoue 	 */
137209a52a55SJINMEI Tatuya 	while ((imm = ia->ia6_memberships.lh_first) != NULL) {
137309a52a55SJINMEI Tatuya 		LIST_REMOVE(imm, i6mm_chain);
137409a52a55SJINMEI Tatuya 		in6_leavegroup(imm);
137582cd038dSYoshinobu Inoue 	}
137682cd038dSYoshinobu Inoue 
1377511e8a53SQing Li 	/*
1378511e8a53SQing Li 	 * remove the link-local all-nodes address
1379511e8a53SQing Li 	 */
1380511e8a53SQing Li 	bzero(&mltmask, sizeof(mltmask));
1381511e8a53SQing Li 	mltmask.sin6_len = sizeof(struct sockaddr_in6);
1382511e8a53SQing Li 	mltmask.sin6_family = AF_INET6;
1383511e8a53SQing Li 	mltmask.sin6_addr = in6mask32;
1384511e8a53SQing Li 
1385511e8a53SQing Li 	bzero(&mltaddr, sizeof(mltaddr));
1386511e8a53SQing Li 	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
1387511e8a53SQing Li 	mltaddr.sin6_family = AF_INET6;
1388511e8a53SQing Li 	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
1389511e8a53SQing Li 
1390511e8a53SQing Li 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
1391511e8a53SQing Li 	    0)
1392511e8a53SQing Li 		goto cleanup;
1393511e8a53SQing Li 
1394511e8a53SQing Li 	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1395511e8a53SQing Li 	if (rt != NULL && rt->rt_gateway != NULL &&
1396511e8a53SQing Li 	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
1397511e8a53SQing Li 		    &ia->ia_addr.sin6_addr,
1398511e8a53SQing Li 		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
1399511e8a53SQing Li 		/*
1400511e8a53SQing Li 		 * if no more IPv6 address exists on this interface
1401511e8a53SQing Li 		 * then remove the multicast address route
1402511e8a53SQing Li 		 */
1403511e8a53SQing Li 		if (ifa0 == NULL) {
1404511e8a53SQing Li 			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
1405511e8a53SQing Li 			       sizeof(mltaddr.sin6_addr));
1406511e8a53SQing Li 			RTFREE_LOCKED(rt);
1407511e8a53SQing Li 			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
1408511e8a53SQing Li 					  (struct sockaddr *)&ia->ia_addr,
1409511e8a53SQing Li 					  (struct sockaddr *)&mltmask, RTF_UP,
1410511e8a53SQing Li 					  (struct rtentry **)0);
1411511e8a53SQing Li 			if (error)
1412511e8a53SQing Li 				log(LOG_INFO, "in6_purgeaddr: link-local all-nodes"
1413511e8a53SQing Li 				    "multicast address deletion error\n");
1414511e8a53SQing Li 		} else {
1415511e8a53SQing Li 			/*
1416511e8a53SQing Li 			 * replace the gateway of the route
1417511e8a53SQing Li 			 */
1418511e8a53SQing Li 			struct sockaddr_in6 sa;
1419511e8a53SQing Li 
1420511e8a53SQing Li 			bzero(&sa, sizeof(sa));
1421511e8a53SQing Li 			sa.sin6_len = sizeof(struct sockaddr_in6);
1422511e8a53SQing Li 			sa.sin6_family = AF_INET6;
1423511e8a53SQing Li 			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
1424511e8a53SQing Li 			       sizeof(sa.sin6_addr));
1425511e8a53SQing Li 			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
1426511e8a53SQing Li 			memcpy(rt->rt_gateway, &sa, sizeof(sa));
1427511e8a53SQing Li 			RTFREE_LOCKED(rt);
1428511e8a53SQing Li 		}
1429511e8a53SQing Li 	} else {
1430511e8a53SQing Li 		if (rt != NULL)
1431511e8a53SQing Li 			RTFREE_LOCKED(rt);
1432511e8a53SQing Li 	}
1433511e8a53SQing Li 
1434511e8a53SQing Li 	/*
1435511e8a53SQing Li 	 * remove the node-local all-nodes address
1436511e8a53SQing Li 	 */
1437511e8a53SQing Li 	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
1438511e8a53SQing Li 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
1439511e8a53SQing Li 	    0)
1440511e8a53SQing Li 		goto cleanup;
1441511e8a53SQing Li 
1442511e8a53SQing Li 	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1443511e8a53SQing Li 	if (rt != NULL && rt->rt_gateway != NULL &&
1444511e8a53SQing Li 	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
1445511e8a53SQing Li 		    &ia->ia_addr.sin6_addr,
1446511e8a53SQing Li 		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
1447511e8a53SQing Li 		/*
1448511e8a53SQing Li 		 * if no more IPv6 address exists on this interface
1449511e8a53SQing Li 		 * then remove the multicast address route
1450511e8a53SQing Li 		 */
1451511e8a53SQing Li 		if (ifa0 == NULL) {
1452511e8a53SQing Li 			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
1453511e8a53SQing Li 			       sizeof(mltaddr.sin6_addr));
1454511e8a53SQing Li 
1455511e8a53SQing Li 			RTFREE_LOCKED(rt);
1456511e8a53SQing Li 			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
1457511e8a53SQing Li 					  (struct sockaddr *)&ia->ia_addr,
1458511e8a53SQing Li 					  (struct sockaddr *)&mltmask, RTF_UP,
1459511e8a53SQing Li 					  (struct rtentry **)0);
1460511e8a53SQing Li 
1461511e8a53SQing Li 			if (error)
1462511e8a53SQing Li 				log(LOG_INFO, "in6_purgeaddr: node-local all-nodes"
1463511e8a53SQing Li 				    "multicast address deletion error\n");
1464511e8a53SQing Li 		} else {
1465511e8a53SQing Li 			/*
1466511e8a53SQing Li 			 * replace the gateway of the route
1467511e8a53SQing Li 			 */
1468511e8a53SQing Li 			struct sockaddr_in6 sa;
1469511e8a53SQing Li 
1470511e8a53SQing Li 			bzero(&sa, sizeof(sa));
1471511e8a53SQing Li 			sa.sin6_len = sizeof(struct sockaddr_in6);
1472511e8a53SQing Li 			sa.sin6_family = AF_INET6;
1473511e8a53SQing Li 			memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
1474511e8a53SQing Li 			       sizeof(sa.sin6_addr));
1475511e8a53SQing Li 			in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
1476511e8a53SQing Li 			memcpy(rt->rt_gateway, &sa, sizeof(sa));
1477511e8a53SQing Li 			RTFREE_LOCKED(rt);
1478511e8a53SQing Li 		}
1479511e8a53SQing Li 	} else {
1480511e8a53SQing Li 		if (rt != NULL)
1481511e8a53SQing Li 			RTFREE_LOCKED(rt);
1482511e8a53SQing Li 	}
1483511e8a53SQing Li 
1484511e8a53SQing Li cleanup:
1485511e8a53SQing Li 
1486511e8a53SQing Li 	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
1487511e8a53SQing Li 	if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
1488511e8a53SQing Li 		int error;
1489511e8a53SQing Li 		struct sockaddr *dstaddr;
1490511e8a53SQing Li 
1491511e8a53SQing Li 		/*
1492511e8a53SQing Li 		 * use the interface address if configuring an
1493511e8a53SQing Li 		 * interface address with a /128 prefix len
1494511e8a53SQing Li 		 */
1495511e8a53SQing Li 		if (ia->ia_dstaddr.sin6_family == AF_INET6)
1496511e8a53SQing Li 			dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
1497511e8a53SQing Li 		else
1498511e8a53SQing Li 			dstaddr = (struct sockaddr *)&ia->ia_addr;
1499511e8a53SQing Li 
1500511e8a53SQing Li 		error = rtrequest(RTM_DELETE,
1501511e8a53SQing Li 		    (struct sockaddr *)dstaddr,
1502511e8a53SQing Li 		    (struct sockaddr *)&ia->ia_addr,
1503511e8a53SQing Li 		    (struct sockaddr *)&ia->ia_prefixmask,
1504511e8a53SQing Li 		    ia->ia_flags | RTF_HOST, NULL);
1505511e8a53SQing Li 		if (error != 0)
1506511e8a53SQing Li 			return;
1507511e8a53SQing Li 		ia->ia_flags &= ~IFA_ROUTE;
1508511e8a53SQing Li 	}
15098c0fec80SRobert Watson 	if (ifa0 != NULL)
15108c0fec80SRobert Watson 		ifa_free(ifa0);
1511511e8a53SQing Li 
151233841545SHajimu UMEMOTO 	in6_unlink_ifa(ia, ifp);
151333841545SHajimu UMEMOTO }
151433841545SHajimu UMEMOTO 
151533841545SHajimu UMEMOTO static void
15161272577eSXin LI in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
151733841545SHajimu UMEMOTO {
151833841545SHajimu UMEMOTO 	int	s = splnet();
151933841545SHajimu UMEMOTO 
1520ac6ba962SRobert Watson 	IF_ADDR_LOCK(ifp);
1521c4dd3fe1SRobert Watson 	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
1522ac6ba962SRobert Watson 	IF_ADDR_UNLOCK(ifp);
15238c0fec80SRobert Watson 	ifa_free(&ia->ia_ifa);			/* if_addrhead */
1524686cdd19SJun-ichiro itojun Hagino 
1525f291b9cdSRobert Watson 	/*
1526f291b9cdSRobert Watson 	 * Defer the release of what might be the last reference to the
1527f291b9cdSRobert Watson 	 * in6_ifaddr so that it can't be freed before the remainder of the
1528f291b9cdSRobert Watson 	 * cleanup.
1529f291b9cdSRobert Watson 	 */
1530d1da0a06SRobert Watson 	IN6_IFADDR_WLOCK();
153180af0152SRobert Watson 	TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
1532d1da0a06SRobert Watson 	IN6_IFADDR_WUNLOCK();
153382cd038dSYoshinobu Inoue 
1534686cdd19SJun-ichiro itojun Hagino 	/*
1535797df30dSSUZUKI Shinsuke 	 * Release the reference to the base prefix.  There should be a
1536797df30dSSUZUKI Shinsuke 	 * positive reference.
1537686cdd19SJun-ichiro itojun Hagino 	 */
153880af0152SRobert Watson 	if (ia->ia6_ndpr == NULL) {
1539797df30dSSUZUKI Shinsuke 		nd6log((LOG_NOTICE,
1540797df30dSSUZUKI Shinsuke 		    "in6_unlink_ifa: autoconf'ed address "
154180af0152SRobert Watson 		    "%p has no prefix\n", ia));
154233841545SHajimu UMEMOTO 	} else {
154380af0152SRobert Watson 		ia->ia6_ndpr->ndpr_refcnt--;
154480af0152SRobert Watson 		ia->ia6_ndpr = NULL;
1545686cdd19SJun-ichiro itojun Hagino 	}
1546686cdd19SJun-ichiro itojun Hagino 
1547797df30dSSUZUKI Shinsuke 	/*
1548797df30dSSUZUKI Shinsuke 	 * Also, if the address being removed is autoconf'ed, call
1549797df30dSSUZUKI Shinsuke 	 * pfxlist_onlink_check() since the release might affect the status of
1550797df30dSSUZUKI Shinsuke 	 * other (detached) addresses.
1551797df30dSSUZUKI Shinsuke 	 */
155280af0152SRobert Watson 	if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) {
155333841545SHajimu UMEMOTO 		pfxlist_onlink_check();
155433841545SHajimu UMEMOTO 	}
1555f291b9cdSRobert Watson 	ifa_free(&ia->ia_ifa);			/* in6_ifaddrhead */
155633841545SHajimu UMEMOTO 	splx(s);
155733841545SHajimu UMEMOTO }
155833841545SHajimu UMEMOTO 
155933841545SHajimu UMEMOTO void
15601272577eSXin LI in6_purgeif(struct ifnet *ifp)
156133841545SHajimu UMEMOTO {
156233841545SHajimu UMEMOTO 	struct ifaddr *ifa, *nifa;
156333841545SHajimu UMEMOTO 
1564c4dd3fe1SRobert Watson 	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
156533841545SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family != AF_INET6)
156633841545SHajimu UMEMOTO 			continue;
156733841545SHajimu UMEMOTO 		in6_purgeaddr(ifa);
156833841545SHajimu UMEMOTO 	}
156933841545SHajimu UMEMOTO 
157033841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
157182cd038dSYoshinobu Inoue }
157282cd038dSYoshinobu Inoue 
157382cd038dSYoshinobu Inoue /*
157482cd038dSYoshinobu Inoue  * SIOC[GAD]LIFADDR.
157545b65a5eSGreg Lehey  *	SIOCGLIFADDR: get first address. (?)
157682cd038dSYoshinobu Inoue  *	SIOCGLIFADDR with IFLR_PREFIX:
157782cd038dSYoshinobu Inoue  *		get first address that matches the specified prefix.
157882cd038dSYoshinobu Inoue  *	SIOCALIFADDR: add the specified address.
157982cd038dSYoshinobu Inoue  *	SIOCALIFADDR with IFLR_PREFIX:
158082cd038dSYoshinobu Inoue  *		add the specified prefix, filling hostid part from
158182cd038dSYoshinobu Inoue  *		the first link-local address.  prefixlen must be <= 64.
158282cd038dSYoshinobu Inoue  *	SIOCDLIFADDR: delete the specified address.
158382cd038dSYoshinobu Inoue  *	SIOCDLIFADDR with IFLR_PREFIX:
158482cd038dSYoshinobu Inoue  *		delete the first address that matches the specified prefix.
158582cd038dSYoshinobu Inoue  * return values:
158682cd038dSYoshinobu Inoue  *	EINVAL on invalid parameters
158782cd038dSYoshinobu Inoue  *	EADDRNOTAVAIL on prefix match failed/specified address not found
158882cd038dSYoshinobu Inoue  *	other values may be returned from in6_ioctl()
158982cd038dSYoshinobu Inoue  *
159082cd038dSYoshinobu Inoue  * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
159182cd038dSYoshinobu Inoue  * this is to accomodate address naming scheme other than RFC2374,
159282cd038dSYoshinobu Inoue  * in the future.
159382cd038dSYoshinobu Inoue  * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
159482cd038dSYoshinobu Inoue  * address encoding scheme. (see figure on page 8)
159582cd038dSYoshinobu Inoue  */
159682cd038dSYoshinobu Inoue static int
15971272577eSXin LI in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
15981272577eSXin LI     struct ifnet *ifp, struct thread *td)
159982cd038dSYoshinobu Inoue {
160082cd038dSYoshinobu Inoue 	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
160182cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
1602686cdd19SJun-ichiro itojun Hagino 	struct sockaddr *sa;
160382cd038dSYoshinobu Inoue 
160482cd038dSYoshinobu Inoue 	/* sanity checks */
160582cd038dSYoshinobu Inoue 	if (!data || !ifp) {
160682cd038dSYoshinobu Inoue 		panic("invalid argument to in6_lifaddr_ioctl");
160706cd0a3fSHajimu UMEMOTO 		/* NOTREACHED */
160882cd038dSYoshinobu Inoue 	}
160982cd038dSYoshinobu Inoue 
161082cd038dSYoshinobu Inoue 	switch (cmd) {
161182cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
161282cd038dSYoshinobu Inoue 		/* address must be specified on GET with IFLR_PREFIX */
161382cd038dSYoshinobu Inoue 		if ((iflr->flags & IFLR_PREFIX) == 0)
161482cd038dSYoshinobu Inoue 			break;
161582cd038dSYoshinobu Inoue 		/* FALLTHROUGH */
161682cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
161782cd038dSYoshinobu Inoue 	case SIOCDLIFADDR:
161882cd038dSYoshinobu Inoue 		/* address must be specified on ADD and DELETE */
1619686cdd19SJun-ichiro itojun Hagino 		sa = (struct sockaddr *)&iflr->addr;
1620686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_family != AF_INET6)
162182cd038dSYoshinobu Inoue 			return EINVAL;
1622686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_len != sizeof(struct sockaddr_in6))
162382cd038dSYoshinobu Inoue 			return EINVAL;
162482cd038dSYoshinobu Inoue 		/* XXX need improvement */
1625686cdd19SJun-ichiro itojun Hagino 		sa = (struct sockaddr *)&iflr->dstaddr;
1626686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_family && sa->sa_family != AF_INET6)
162782cd038dSYoshinobu Inoue 			return EINVAL;
1628686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
162982cd038dSYoshinobu Inoue 			return EINVAL;
163082cd038dSYoshinobu Inoue 		break;
163182cd038dSYoshinobu Inoue 	default: /* shouldn't happen */
1632686cdd19SJun-ichiro itojun Hagino #if 0
1633686cdd19SJun-ichiro itojun Hagino 		panic("invalid cmd to in6_lifaddr_ioctl");
1634686cdd19SJun-ichiro itojun Hagino 		/* NOTREACHED */
1635686cdd19SJun-ichiro itojun Hagino #else
163682cd038dSYoshinobu Inoue 		return EOPNOTSUPP;
1637686cdd19SJun-ichiro itojun Hagino #endif
163882cd038dSYoshinobu Inoue 	}
163982cd038dSYoshinobu Inoue 	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
164082cd038dSYoshinobu Inoue 		return EINVAL;
164182cd038dSYoshinobu Inoue 
164282cd038dSYoshinobu Inoue 	switch (cmd) {
164382cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
164482cd038dSYoshinobu Inoue 	    {
164582cd038dSYoshinobu Inoue 		struct in6_aliasreq ifra;
164682cd038dSYoshinobu Inoue 		struct in6_addr *hostid = NULL;
164782cd038dSYoshinobu Inoue 		int prefixlen;
164882cd038dSYoshinobu Inoue 
16498c0fec80SRobert Watson 		ifa = NULL;
165082cd038dSYoshinobu Inoue 		if ((iflr->flags & IFLR_PREFIX) != 0) {
165182cd038dSYoshinobu Inoue 			struct sockaddr_in6 *sin6;
165282cd038dSYoshinobu Inoue 
165382cd038dSYoshinobu Inoue 			/*
165482cd038dSYoshinobu Inoue 			 * hostid is to fill in the hostid part of the
165582cd038dSYoshinobu Inoue 			 * address.  hostid points to the first link-local
165682cd038dSYoshinobu Inoue 			 * address attached to the interface.
165782cd038dSYoshinobu Inoue 			 */
1658686cdd19SJun-ichiro itojun Hagino 			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
165982cd038dSYoshinobu Inoue 			if (!ifa)
166082cd038dSYoshinobu Inoue 				return EADDRNOTAVAIL;
166182cd038dSYoshinobu Inoue 			hostid = IFA_IN6(ifa);
166282cd038dSYoshinobu Inoue 
166382cd038dSYoshinobu Inoue 			/* prefixlen must be <= 64. */
166482cd038dSYoshinobu Inoue 			if (64 < iflr->prefixlen)
166582cd038dSYoshinobu Inoue 				return EINVAL;
166682cd038dSYoshinobu Inoue 			prefixlen = iflr->prefixlen;
166782cd038dSYoshinobu Inoue 
166882cd038dSYoshinobu Inoue 			/* hostid part must be zero. */
166982cd038dSYoshinobu Inoue 			sin6 = (struct sockaddr_in6 *)&iflr->addr;
167059aecc96SHajimu UMEMOTO 			if (sin6->sin6_addr.s6_addr32[2] != 0 ||
167159aecc96SHajimu UMEMOTO 			    sin6->sin6_addr.s6_addr32[3] != 0) {
167282cd038dSYoshinobu Inoue 				return EINVAL;
167382cd038dSYoshinobu Inoue 			}
167482cd038dSYoshinobu Inoue 		} else
167582cd038dSYoshinobu Inoue 			prefixlen = iflr->prefixlen;
167682cd038dSYoshinobu Inoue 
167782cd038dSYoshinobu Inoue 		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
167882cd038dSYoshinobu Inoue 		bzero(&ifra, sizeof(ifra));
167906cd0a3fSHajimu UMEMOTO 		bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name));
168082cd038dSYoshinobu Inoue 
1681686cdd19SJun-ichiro itojun Hagino 		bcopy(&iflr->addr, &ifra.ifra_addr,
1682686cdd19SJun-ichiro itojun Hagino 		    ((struct sockaddr *)&iflr->addr)->sa_len);
168382cd038dSYoshinobu Inoue 		if (hostid) {
168482cd038dSYoshinobu Inoue 			/* fill in hostid part */
168582cd038dSYoshinobu Inoue 			ifra.ifra_addr.sin6_addr.s6_addr32[2] =
168682cd038dSYoshinobu Inoue 			    hostid->s6_addr32[2];
168782cd038dSYoshinobu Inoue 			ifra.ifra_addr.sin6_addr.s6_addr32[3] =
168882cd038dSYoshinobu Inoue 			    hostid->s6_addr32[3];
168982cd038dSYoshinobu Inoue 		}
169082cd038dSYoshinobu Inoue 
1691686cdd19SJun-ichiro itojun Hagino 		if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */
169282cd038dSYoshinobu Inoue 			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1693686cdd19SJun-ichiro itojun Hagino 			    ((struct sockaddr *)&iflr->dstaddr)->sa_len);
169482cd038dSYoshinobu Inoue 			if (hostid) {
169582cd038dSYoshinobu Inoue 				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
169682cd038dSYoshinobu Inoue 				    hostid->s6_addr32[2];
169782cd038dSYoshinobu Inoue 				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
169882cd038dSYoshinobu Inoue 				    hostid->s6_addr32[3];
169982cd038dSYoshinobu Inoue 			}
170082cd038dSYoshinobu Inoue 		}
17018c0fec80SRobert Watson 		if (ifa != NULL)
17028c0fec80SRobert Watson 			ifa_free(ifa);
170382cd038dSYoshinobu Inoue 
170482cd038dSYoshinobu Inoue 		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1705ae360dddSHajimu UMEMOTO 		in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
170682cd038dSYoshinobu Inoue 
170782cd038dSYoshinobu Inoue 		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
1708b40ce416SJulian Elischer 		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td);
170982cd038dSYoshinobu Inoue 	    }
171082cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
171182cd038dSYoshinobu Inoue 	case SIOCDLIFADDR:
171282cd038dSYoshinobu Inoue 	    {
171382cd038dSYoshinobu Inoue 		struct in6_ifaddr *ia;
171482cd038dSYoshinobu Inoue 		struct in6_addr mask, candidate, match;
171582cd038dSYoshinobu Inoue 		struct sockaddr_in6 *sin6;
171682cd038dSYoshinobu Inoue 		int cmp;
171782cd038dSYoshinobu Inoue 
171882cd038dSYoshinobu Inoue 		bzero(&mask, sizeof(mask));
171982cd038dSYoshinobu Inoue 		if (iflr->flags & IFLR_PREFIX) {
172082cd038dSYoshinobu Inoue 			/* lookup a prefix rather than address. */
1721ae360dddSHajimu UMEMOTO 			in6_prefixlen2mask(&mask, iflr->prefixlen);
172282cd038dSYoshinobu Inoue 
172382cd038dSYoshinobu Inoue 			sin6 = (struct sockaddr_in6 *)&iflr->addr;
172482cd038dSYoshinobu Inoue 			bcopy(&sin6->sin6_addr, &match, sizeof(match));
172582cd038dSYoshinobu Inoue 			match.s6_addr32[0] &= mask.s6_addr32[0];
172682cd038dSYoshinobu Inoue 			match.s6_addr32[1] &= mask.s6_addr32[1];
172782cd038dSYoshinobu Inoue 			match.s6_addr32[2] &= mask.s6_addr32[2];
172882cd038dSYoshinobu Inoue 			match.s6_addr32[3] &= mask.s6_addr32[3];
172982cd038dSYoshinobu Inoue 
173082cd038dSYoshinobu Inoue 			/* if you set extra bits, that's wrong */
173182cd038dSYoshinobu Inoue 			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
173282cd038dSYoshinobu Inoue 				return EINVAL;
173382cd038dSYoshinobu Inoue 
173482cd038dSYoshinobu Inoue 			cmp = 1;
173582cd038dSYoshinobu Inoue 		} else {
173682cd038dSYoshinobu Inoue 			if (cmd == SIOCGLIFADDR) {
173782cd038dSYoshinobu Inoue 				/* on getting an address, take the 1st match */
173882cd038dSYoshinobu Inoue 				cmp = 0;	/* XXX */
173982cd038dSYoshinobu Inoue 			} else {
174082cd038dSYoshinobu Inoue 				/* on deleting an address, do exact match */
1741ae360dddSHajimu UMEMOTO 				in6_prefixlen2mask(&mask, 128);
174282cd038dSYoshinobu Inoue 				sin6 = (struct sockaddr_in6 *)&iflr->addr;
174382cd038dSYoshinobu Inoue 				bcopy(&sin6->sin6_addr, &match, sizeof(match));
174482cd038dSYoshinobu Inoue 
174582cd038dSYoshinobu Inoue 				cmp = 1;
174682cd038dSYoshinobu Inoue 			}
174782cd038dSYoshinobu Inoue 		}
174882cd038dSYoshinobu Inoue 
1749ac6ba962SRobert Watson 		IF_ADDR_LOCK(ifp);
1750c4dd3fe1SRobert Watson 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
175182cd038dSYoshinobu Inoue 			if (ifa->ifa_addr->sa_family != AF_INET6)
175282cd038dSYoshinobu Inoue 				continue;
175382cd038dSYoshinobu Inoue 			if (!cmp)
175482cd038dSYoshinobu Inoue 				break;
175533841545SHajimu UMEMOTO 
175633841545SHajimu UMEMOTO 			/*
175733841545SHajimu UMEMOTO 			 * XXX: this is adhoc, but is necessary to allow
175833841545SHajimu UMEMOTO 			 * a user to specify fe80::/64 (not /10) for a
175933841545SHajimu UMEMOTO 			 * link-local address.
176033841545SHajimu UMEMOTO 			 */
1761a1f7e5f8SHajimu UMEMOTO 			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
1762a1f7e5f8SHajimu UMEMOTO 			in6_clearscope(&candidate);
176382cd038dSYoshinobu Inoue 			candidate.s6_addr32[0] &= mask.s6_addr32[0];
176482cd038dSYoshinobu Inoue 			candidate.s6_addr32[1] &= mask.s6_addr32[1];
176582cd038dSYoshinobu Inoue 			candidate.s6_addr32[2] &= mask.s6_addr32[2];
176682cd038dSYoshinobu Inoue 			candidate.s6_addr32[3] &= mask.s6_addr32[3];
176782cd038dSYoshinobu Inoue 			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
176882cd038dSYoshinobu Inoue 				break;
176982cd038dSYoshinobu Inoue 		}
1770ac6ba962SRobert Watson 		IF_ADDR_UNLOCK(ifp);
177182cd038dSYoshinobu Inoue 		if (!ifa)
177282cd038dSYoshinobu Inoue 			return EADDRNOTAVAIL;
177382cd038dSYoshinobu Inoue 		ia = ifa2ia6(ifa);
177482cd038dSYoshinobu Inoue 
177582cd038dSYoshinobu Inoue 		if (cmd == SIOCGLIFADDR) {
1776a1f7e5f8SHajimu UMEMOTO 			int error;
177733841545SHajimu UMEMOTO 
177882cd038dSYoshinobu Inoue 			/* fill in the if_laddrreq structure */
177982cd038dSYoshinobu Inoue 			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
1780a1f7e5f8SHajimu UMEMOTO 			error = sa6_recoverscope(
1781a1f7e5f8SHajimu UMEMOTO 			    (struct sockaddr_in6 *)&iflr->addr);
1782a1f7e5f8SHajimu UMEMOTO 			if (error != 0)
1783a1f7e5f8SHajimu UMEMOTO 				return (error);
1784a1f7e5f8SHajimu UMEMOTO 
178582cd038dSYoshinobu Inoue 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
178682cd038dSYoshinobu Inoue 				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
178782cd038dSYoshinobu Inoue 				    ia->ia_dstaddr.sin6_len);
1788a1f7e5f8SHajimu UMEMOTO 				error = sa6_recoverscope(
1789a1f7e5f8SHajimu UMEMOTO 				    (struct sockaddr_in6 *)&iflr->dstaddr);
1790a1f7e5f8SHajimu UMEMOTO 				if (error != 0)
1791a1f7e5f8SHajimu UMEMOTO 					return (error);
179282cd038dSYoshinobu Inoue 			} else
179382cd038dSYoshinobu Inoue 				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
179482cd038dSYoshinobu Inoue 
179582cd038dSYoshinobu Inoue 			iflr->prefixlen =
179606cd0a3fSHajimu UMEMOTO 			    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
179782cd038dSYoshinobu Inoue 
179882cd038dSYoshinobu Inoue 			iflr->flags = ia->ia6_flags;	/* XXX */
179982cd038dSYoshinobu Inoue 
180082cd038dSYoshinobu Inoue 			return 0;
180182cd038dSYoshinobu Inoue 		} else {
180282cd038dSYoshinobu Inoue 			struct in6_aliasreq ifra;
180382cd038dSYoshinobu Inoue 
180482cd038dSYoshinobu Inoue 			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
180582cd038dSYoshinobu Inoue 			bzero(&ifra, sizeof(ifra));
180682cd038dSYoshinobu Inoue 			bcopy(iflr->iflr_name, ifra.ifra_name,
180782cd038dSYoshinobu Inoue 			    sizeof(ifra.ifra_name));
180882cd038dSYoshinobu Inoue 
180982cd038dSYoshinobu Inoue 			bcopy(&ia->ia_addr, &ifra.ifra_addr,
181082cd038dSYoshinobu Inoue 			    ia->ia_addr.sin6_len);
181182cd038dSYoshinobu Inoue 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
181282cd038dSYoshinobu Inoue 				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
181382cd038dSYoshinobu Inoue 				    ia->ia_dstaddr.sin6_len);
1814686cdd19SJun-ichiro itojun Hagino 			} else {
1815686cdd19SJun-ichiro itojun Hagino 				bzero(&ifra.ifra_dstaddr,
1816686cdd19SJun-ichiro itojun Hagino 				    sizeof(ifra.ifra_dstaddr));
181782cd038dSYoshinobu Inoue 			}
181882cd038dSYoshinobu Inoue 			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
181982cd038dSYoshinobu Inoue 			    ia->ia_prefixmask.sin6_len);
182082cd038dSYoshinobu Inoue 
182182cd038dSYoshinobu Inoue 			ifra.ifra_flags = ia->ia6_flags;
182282cd038dSYoshinobu Inoue 			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
1823b40ce416SJulian Elischer 			    ifp, td);
182482cd038dSYoshinobu Inoue 		}
182582cd038dSYoshinobu Inoue 	    }
182682cd038dSYoshinobu Inoue 	}
182782cd038dSYoshinobu Inoue 
182882cd038dSYoshinobu Inoue 	return EOPNOTSUPP;	/* just for safety */
182982cd038dSYoshinobu Inoue }
183082cd038dSYoshinobu Inoue 
183182cd038dSYoshinobu Inoue /*
183282cd038dSYoshinobu Inoue  * Initialize an interface's intetnet6 address
183382cd038dSYoshinobu Inoue  * and routing table entry.
183482cd038dSYoshinobu Inoue  */
183533841545SHajimu UMEMOTO static int
18361272577eSXin LI in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
18371272577eSXin LI     struct sockaddr_in6 *sin6, int newhost)
183882cd038dSYoshinobu Inoue {
183933841545SHajimu UMEMOTO 	int	error = 0, plen, ifacount = 0;
184082cd038dSYoshinobu Inoue 	int	s = splimp();
184133841545SHajimu UMEMOTO 	struct ifaddr *ifa;
184282cd038dSYoshinobu Inoue 
184382cd038dSYoshinobu Inoue 	/*
184482cd038dSYoshinobu Inoue 	 * Give the interface a chance to initialize
184582cd038dSYoshinobu Inoue 	 * if this is its first address,
184682cd038dSYoshinobu Inoue 	 * and to validate the address if necessary.
184782cd038dSYoshinobu Inoue 	 */
1848ac6ba962SRobert Watson 	IF_ADDR_LOCK(ifp);
1849c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
185033841545SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family != AF_INET6)
185133841545SHajimu UMEMOTO 			continue;
185233841545SHajimu UMEMOTO 		ifacount++;
185333841545SHajimu UMEMOTO 	}
1854ac6ba962SRobert Watson 	IF_ADDR_UNLOCK(ifp);
185533841545SHajimu UMEMOTO 
185633841545SHajimu UMEMOTO 	ia->ia_addr = *sin6;
185733841545SHajimu UMEMOTO 
1858ba5da2a0SIan Dowse 	if (ifacount <= 1 && ifp->if_ioctl) {
1859ba5da2a0SIan Dowse 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
1860ba5da2a0SIan Dowse 		if (error) {
186182cd038dSYoshinobu Inoue 			splx(s);
186282cd038dSYoshinobu Inoue 			return (error);
186382cd038dSYoshinobu Inoue 		}
1864ba5da2a0SIan Dowse 	}
186582cd038dSYoshinobu Inoue 	splx(s);
186633841545SHajimu UMEMOTO 
186782cd038dSYoshinobu Inoue 	ia->ia_ifa.ifa_metric = ifp->if_metric;
186833841545SHajimu UMEMOTO 
186933841545SHajimu UMEMOTO 	/* we could do in(6)_socktrim here, but just omit it at this moment. */
187033841545SHajimu UMEMOTO 
187133841545SHajimu UMEMOTO 	/*
187233841545SHajimu UMEMOTO 	 * Special case:
187380343432SHajimu UMEMOTO 	 * If a new destination address is specified for a point-to-point
187433841545SHajimu UMEMOTO 	 * interface, install a route to the destination as an interface
18756e6b3f7cSQing Li 	 * direct route.
187680343432SHajimu UMEMOTO 	 * XXX: the logic below rejects assigning multiple addresses on a p2p
1877a59af512SGeorge V. Neville-Neil 	 * interface that share the same destination.
187833841545SHajimu UMEMOTO 	 */
187933841545SHajimu UMEMOTO 	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
188009b03548SQing Li 	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
188109b03548SQing Li 	    ia->ia_dstaddr.sin6_family == AF_INET6) {
1882a59af512SGeorge V. Neville-Neil 		int rtflags = RTF_UP | RTF_HOST;
1883a59af512SGeorge V. Neville-Neil 
18848b07e49aSJulian Elischer 		error = rtrequest(RTM_ADD,
188509b03548SQing Li 		    (struct sockaddr *)&ia->ia_dstaddr,
1886a59af512SGeorge V. Neville-Neil 		    (struct sockaddr *)&ia->ia_addr,
1887a59af512SGeorge V. Neville-Neil 		    (struct sockaddr *)&ia->ia_prefixmask,
1888dc495497SQing Li 		    ia->ia_flags | rtflags, NULL);
1889a59af512SGeorge V. Neville-Neil 		if (error != 0)
189033841545SHajimu UMEMOTO 			return (error);
189182cd038dSYoshinobu Inoue 		ia->ia_flags |= IFA_ROUTE;
189214417253SQing Li 		/*
189314417253SQing Li 		 * Handle the case for ::1 .
189414417253SQing Li 		 */
189514417253SQing Li 		if (ifp->if_flags & IFF_LOOPBACK)
189614417253SQing Li 			ia->ia_flags |= IFA_RTSELF;
189733841545SHajimu UMEMOTO 	}
189882cd038dSYoshinobu Inoue 
189905b262e2SQing Li 	/*
190005b262e2SQing Li 	 * add a loopback route to self
190105b262e2SQing Li 	 */
190214417253SQing Li 	if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) {
19039bb7d0f4SQing Li 		error = ifa_add_loopback_route((struct ifaddr *)ia,
19049bb7d0f4SQing Li 				       (struct sockaddr *)&ia->ia_addr);
1905c7ab6602SQing Li 		if (error == 0)
1906c7ab6602SQing Li 			ia->ia_flags |= IFA_RTSELF;
190705b262e2SQing Li 	}
190805b262e2SQing Li 
190982cd038dSYoshinobu Inoue 	/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
1910b590b6aeSGleb Smirnoff 	if (newhost)
1911b590b6aeSGleb Smirnoff 		in6_ifaddloop(&(ia->ia_ifa));
191282cd038dSYoshinobu Inoue 
191382cd038dSYoshinobu Inoue 	return (error);
191482cd038dSYoshinobu Inoue }
191582cd038dSYoshinobu Inoue 
191682cd038dSYoshinobu Inoue /*
191782cd038dSYoshinobu Inoue  * Find an IPv6 interface link-local address specific to an interface.
19188c0fec80SRobert Watson  * ifaddr is returned referenced.
191982cd038dSYoshinobu Inoue  */
192082cd038dSYoshinobu Inoue struct in6_ifaddr *
19211272577eSXin LI in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
192282cd038dSYoshinobu Inoue {
192333841545SHajimu UMEMOTO 	struct ifaddr *ifa;
192482cd038dSYoshinobu Inoue 
1925ac6ba962SRobert Watson 	IF_ADDR_LOCK(ifp);
1926c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
192782cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
192882cd038dSYoshinobu Inoue 			continue;
1929686cdd19SJun-ichiro itojun Hagino 		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
1930686cdd19SJun-ichiro itojun Hagino 			if ((((struct in6_ifaddr *)ifa)->ia6_flags &
1931686cdd19SJun-ichiro itojun Hagino 			     ignoreflags) != 0)
1932686cdd19SJun-ichiro itojun Hagino 				continue;
19338c0fec80SRobert Watson 			ifa_ref(ifa);
193482cd038dSYoshinobu Inoue 			break;
193582cd038dSYoshinobu Inoue 		}
1936686cdd19SJun-ichiro itojun Hagino 	}
1937ac6ba962SRobert Watson 	IF_ADDR_UNLOCK(ifp);
193882cd038dSYoshinobu Inoue 
193982cd038dSYoshinobu Inoue 	return ((struct in6_ifaddr *)ifa);
194082cd038dSYoshinobu Inoue }
194182cd038dSYoshinobu Inoue 
194282cd038dSYoshinobu Inoue 
194382cd038dSYoshinobu Inoue /*
194482cd038dSYoshinobu Inoue  * find the internet address corresponding to a given interface and address.
19458c0fec80SRobert Watson  * ifaddr is returned referenced.
194682cd038dSYoshinobu Inoue  */
194782cd038dSYoshinobu Inoue struct in6_ifaddr *
19481272577eSXin LI in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
194982cd038dSYoshinobu Inoue {
195033841545SHajimu UMEMOTO 	struct ifaddr *ifa;
195182cd038dSYoshinobu Inoue 
19521e6a4139SRobert Watson 	IF_ADDR_LOCK(ifp);
1953c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
195482cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
195582cd038dSYoshinobu Inoue 			continue;
19568c0fec80SRobert Watson 		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) {
19578c0fec80SRobert Watson 			ifa_ref(ifa);
195882cd038dSYoshinobu Inoue 			break;
195982cd038dSYoshinobu Inoue 		}
19608c0fec80SRobert Watson 	}
19611e6a4139SRobert Watson 	IF_ADDR_UNLOCK(ifp);
196282cd038dSYoshinobu Inoue 
196382cd038dSYoshinobu Inoue 	return ((struct in6_ifaddr *)ifa);
196482cd038dSYoshinobu Inoue }
196582cd038dSYoshinobu Inoue 
196682cd038dSYoshinobu Inoue /*
19671d54aa3bSBjoern A. Zeeb  * Convert IP6 address to printable (loggable) representation. Caller
19681d54aa3bSBjoern A. Zeeb  * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long.
196982cd038dSYoshinobu Inoue  */
197082cd038dSYoshinobu Inoue static char digits[] = "0123456789abcdef";
197182cd038dSYoshinobu Inoue char *
19721d54aa3bSBjoern A. Zeeb ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
197382cd038dSYoshinobu Inoue {
19748e96292dSAlfred Perlstein 	int i, cnt = 0, maxcnt = 0, idx = 0, index = 0;
197533841545SHajimu UMEMOTO 	char *cp;
197659aecc96SHajimu UMEMOTO 	const u_int16_t *a = (const u_int16_t *)addr;
197759aecc96SHajimu UMEMOTO 	const u_int8_t *d;
1978e521ae0cSBjoern A. Zeeb 	int dcolon = 0, zero = 0;
197982cd038dSYoshinobu Inoue 
19801d54aa3bSBjoern A. Zeeb 	cp = ip6buf;
198182cd038dSYoshinobu Inoue 
198282cd038dSYoshinobu Inoue 	for (i = 0; i < 8; i++) {
19838e96292dSAlfred Perlstein 		if (*(a + i) == 0) {
19848e96292dSAlfred Perlstein 			cnt++;
19858e96292dSAlfred Perlstein 			if (cnt == 1)
19868e96292dSAlfred Perlstein 				idx = i;
19878e96292dSAlfred Perlstein 		}
19888e96292dSAlfred Perlstein 		else if (maxcnt < cnt) {
19898e96292dSAlfred Perlstein 			maxcnt = cnt;
19908e96292dSAlfred Perlstein 			index = idx;
19918e96292dSAlfred Perlstein 			cnt = 0;
19928e96292dSAlfred Perlstein 		}
19938e96292dSAlfred Perlstein 	}
19948e96292dSAlfred Perlstein 	if (maxcnt < cnt) {
19958e96292dSAlfred Perlstein 		maxcnt = cnt;
19968e96292dSAlfred Perlstein 		index = idx;
19978e96292dSAlfred Perlstein 	}
19988e96292dSAlfred Perlstein 
19998e96292dSAlfred Perlstein 	for (i = 0; i < 8; i++) {
200082cd038dSYoshinobu Inoue 		if (dcolon == 1) {
200182cd038dSYoshinobu Inoue 			if (*a == 0) {
200282cd038dSYoshinobu Inoue 				if (i == 7)
200382cd038dSYoshinobu Inoue 					*cp++ = ':';
200482cd038dSYoshinobu Inoue 				a++;
200582cd038dSYoshinobu Inoue 				continue;
200682cd038dSYoshinobu Inoue 			} else
200782cd038dSYoshinobu Inoue 				dcolon = 2;
200882cd038dSYoshinobu Inoue 		}
200982cd038dSYoshinobu Inoue 		if (*a == 0) {
20108e96292dSAlfred Perlstein 			if (dcolon == 0 && *(a + 1) == 0 && i == index) {
201182cd038dSYoshinobu Inoue 				if (i == 0)
201282cd038dSYoshinobu Inoue 					*cp++ = ':';
201382cd038dSYoshinobu Inoue 				*cp++ = ':';
201482cd038dSYoshinobu Inoue 				dcolon = 1;
201582cd038dSYoshinobu Inoue 			} else {
201682cd038dSYoshinobu Inoue 				*cp++ = '0';
201782cd038dSYoshinobu Inoue 				*cp++ = ':';
201882cd038dSYoshinobu Inoue 			}
201982cd038dSYoshinobu Inoue 			a++;
202082cd038dSYoshinobu Inoue 			continue;
202182cd038dSYoshinobu Inoue 		}
2022c4c0c592SAlfred Perlstein 		d = (const u_char *)a;
2023e521ae0cSBjoern A. Zeeb 		/* Try to eliminate leading zeros in printout like in :0001. */
2024e521ae0cSBjoern A. Zeeb 		zero = 1;
2025e521ae0cSBjoern A. Zeeb 		*cp = digits[*d >> 4];
2026e521ae0cSBjoern A. Zeeb 		if (*cp != '0') {
2027e521ae0cSBjoern A. Zeeb 			zero = 0;
2028e521ae0cSBjoern A. Zeeb 			cp++;
2029e521ae0cSBjoern A. Zeeb 		}
2030e521ae0cSBjoern A. Zeeb 		*cp = digits[*d++ & 0xf];
2031e521ae0cSBjoern A. Zeeb 		if (zero == 0 || (*cp != '0')) {
2032e521ae0cSBjoern A. Zeeb 			zero = 0;
2033e521ae0cSBjoern A. Zeeb 			cp++;
2034e521ae0cSBjoern A. Zeeb 		}
2035e521ae0cSBjoern A. Zeeb 		*cp = digits[*d >> 4];
2036e521ae0cSBjoern A. Zeeb 		if (zero == 0 || (*cp != '0')) {
2037e521ae0cSBjoern A. Zeeb 			zero = 0;
2038e521ae0cSBjoern A. Zeeb 			cp++;
2039e521ae0cSBjoern A. Zeeb 		}
204082cd038dSYoshinobu Inoue 		*cp++ = digits[*d & 0xf];
204182cd038dSYoshinobu Inoue 		*cp++ = ':';
204282cd038dSYoshinobu Inoue 		a++;
204382cd038dSYoshinobu Inoue 	}
20441d54aa3bSBjoern A. Zeeb 	*--cp = '\0';
20451d54aa3bSBjoern A. Zeeb 	return (ip6buf);
204682cd038dSYoshinobu Inoue }
204782cd038dSYoshinobu Inoue 
204882cd038dSYoshinobu Inoue int
20491272577eSXin LI in6_localaddr(struct in6_addr *in6)
205082cd038dSYoshinobu Inoue {
205182cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
205282cd038dSYoshinobu Inoue 
205382cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
205482cd038dSYoshinobu Inoue 		return 1;
205582cd038dSYoshinobu Inoue 
2056d1da0a06SRobert Watson 	IN6_IFADDR_RLOCK();
205780af0152SRobert Watson 	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
205882cd038dSYoshinobu Inoue 		if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
205906cd0a3fSHajimu UMEMOTO 		    &ia->ia_prefixmask.sin6_addr)) {
2060d1da0a06SRobert Watson 			IN6_IFADDR_RUNLOCK();
206182cd038dSYoshinobu Inoue 			return 1;
206206cd0a3fSHajimu UMEMOTO 		}
206306cd0a3fSHajimu UMEMOTO 	}
2064d1da0a06SRobert Watson 	IN6_IFADDR_RUNLOCK();
206582cd038dSYoshinobu Inoue 
206682cd038dSYoshinobu Inoue 	return (0);
206782cd038dSYoshinobu Inoue }
206882cd038dSYoshinobu Inoue 
206990bc35deSBjoern A. Zeeb /*
207090bc35deSBjoern A. Zeeb  * Return 1 if an internet address is for the local host and configured
207190bc35deSBjoern A. Zeeb  * on one of its interfaces.
207290bc35deSBjoern A. Zeeb  */
207390bc35deSBjoern A. Zeeb int
207490bc35deSBjoern A. Zeeb in6_localip(struct in6_addr *in6)
207590bc35deSBjoern A. Zeeb {
207690bc35deSBjoern A. Zeeb 	struct in6_ifaddr *ia;
207790bc35deSBjoern A. Zeeb 
207890bc35deSBjoern A. Zeeb 	IN6_IFADDR_RLOCK();
207990bc35deSBjoern A. Zeeb 	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
208090bc35deSBjoern A. Zeeb 		if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) {
208190bc35deSBjoern A. Zeeb 			IN6_IFADDR_RUNLOCK();
208290bc35deSBjoern A. Zeeb 			return (1);
208390bc35deSBjoern A. Zeeb 		}
208490bc35deSBjoern A. Zeeb 	}
208590bc35deSBjoern A. Zeeb 	IN6_IFADDR_RUNLOCK();
208690bc35deSBjoern A. Zeeb 	return (0);
208790bc35deSBjoern A. Zeeb }
208890bc35deSBjoern A. Zeeb 
208990bc35deSBjoern A. Zeeb 
209033841545SHajimu UMEMOTO int
20911272577eSXin LI in6_is_addr_deprecated(struct sockaddr_in6 *sa6)
209233841545SHajimu UMEMOTO {
209333841545SHajimu UMEMOTO 	struct in6_ifaddr *ia;
209433841545SHajimu UMEMOTO 
2095d1da0a06SRobert Watson 	IN6_IFADDR_RLOCK();
209680af0152SRobert Watson 	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
209733841545SHajimu UMEMOTO 		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
209833841545SHajimu UMEMOTO 				       &sa6->sin6_addr) &&
2099d1da0a06SRobert Watson 		    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
2100d1da0a06SRobert Watson 			IN6_IFADDR_RUNLOCK();
210133841545SHajimu UMEMOTO 			return (1); /* true */
2102d1da0a06SRobert Watson 		}
210333841545SHajimu UMEMOTO 
210433841545SHajimu UMEMOTO 		/* XXX: do we still have to go thru the rest of the list? */
210533841545SHajimu UMEMOTO 	}
2106d1da0a06SRobert Watson 	IN6_IFADDR_RUNLOCK();
210733841545SHajimu UMEMOTO 
210833841545SHajimu UMEMOTO 	return (0);		/* false */
210933841545SHajimu UMEMOTO }
211033841545SHajimu UMEMOTO 
211182cd038dSYoshinobu Inoue /*
211282cd038dSYoshinobu Inoue  * return length of part which dst and src are equal
211382cd038dSYoshinobu Inoue  * hard coding...
211482cd038dSYoshinobu Inoue  */
211582cd038dSYoshinobu Inoue int
21161272577eSXin LI in6_matchlen(struct in6_addr *src, struct in6_addr *dst)
211782cd038dSYoshinobu Inoue {
211882cd038dSYoshinobu Inoue 	int match = 0;
211982cd038dSYoshinobu Inoue 	u_char *s = (u_char *)src, *d = (u_char *)dst;
212082cd038dSYoshinobu Inoue 	u_char *lim = s + 16, r;
212182cd038dSYoshinobu Inoue 
212282cd038dSYoshinobu Inoue 	while (s < lim)
212382cd038dSYoshinobu Inoue 		if ((r = (*d++ ^ *s++)) != 0) {
212482cd038dSYoshinobu Inoue 			while (r < 128) {
212582cd038dSYoshinobu Inoue 				match++;
212682cd038dSYoshinobu Inoue 				r <<= 1;
212782cd038dSYoshinobu Inoue 			}
212882cd038dSYoshinobu Inoue 			break;
212982cd038dSYoshinobu Inoue 		} else
213082cd038dSYoshinobu Inoue 			match += 8;
213182cd038dSYoshinobu Inoue 	return match;
213282cd038dSYoshinobu Inoue }
213382cd038dSYoshinobu Inoue 
2134686cdd19SJun-ichiro itojun Hagino /* XXX: to be scope conscious */
213582cd038dSYoshinobu Inoue int
21361272577eSXin LI in6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len)
213782cd038dSYoshinobu Inoue {
213882cd038dSYoshinobu Inoue 	int bytelen, bitlen;
213982cd038dSYoshinobu Inoue 
214082cd038dSYoshinobu Inoue 	/* sanity check */
214182cd038dSYoshinobu Inoue 	if (0 > len || len > 128) {
214282cd038dSYoshinobu Inoue 		log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
214382cd038dSYoshinobu Inoue 		    len);
214482cd038dSYoshinobu Inoue 		return (0);
214582cd038dSYoshinobu Inoue 	}
214682cd038dSYoshinobu Inoue 
214782cd038dSYoshinobu Inoue 	bytelen = len / 8;
214882cd038dSYoshinobu Inoue 	bitlen = len % 8;
214982cd038dSYoshinobu Inoue 
215082cd038dSYoshinobu Inoue 	if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
215182cd038dSYoshinobu Inoue 		return (0);
215214135e2cSColin Percival 	if (bitlen != 0 &&
215314135e2cSColin Percival 	    p1->s6_addr[bytelen] >> (8 - bitlen) !=
215482cd038dSYoshinobu Inoue 	    p2->s6_addr[bytelen] >> (8 - bitlen))
215582cd038dSYoshinobu Inoue 		return (0);
215682cd038dSYoshinobu Inoue 
215782cd038dSYoshinobu Inoue 	return (1);
215882cd038dSYoshinobu Inoue }
215982cd038dSYoshinobu Inoue 
216082cd038dSYoshinobu Inoue void
21611272577eSXin LI in6_prefixlen2mask(struct in6_addr *maskp, int len)
216282cd038dSYoshinobu Inoue {
216382cd038dSYoshinobu Inoue 	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
216482cd038dSYoshinobu Inoue 	int bytelen, bitlen, i;
216582cd038dSYoshinobu Inoue 
216682cd038dSYoshinobu Inoue 	/* sanity check */
216782cd038dSYoshinobu Inoue 	if (0 > len || len > 128) {
216882cd038dSYoshinobu Inoue 		log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
216982cd038dSYoshinobu Inoue 		    len);
217082cd038dSYoshinobu Inoue 		return;
217182cd038dSYoshinobu Inoue 	}
217282cd038dSYoshinobu Inoue 
217382cd038dSYoshinobu Inoue 	bzero(maskp, sizeof(*maskp));
217482cd038dSYoshinobu Inoue 	bytelen = len / 8;
217582cd038dSYoshinobu Inoue 	bitlen = len % 8;
217682cd038dSYoshinobu Inoue 	for (i = 0; i < bytelen; i++)
217782cd038dSYoshinobu Inoue 		maskp->s6_addr[i] = 0xff;
217882cd038dSYoshinobu Inoue 	if (bitlen)
217982cd038dSYoshinobu Inoue 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
218082cd038dSYoshinobu Inoue }
218182cd038dSYoshinobu Inoue 
218282cd038dSYoshinobu Inoue /*
218382cd038dSYoshinobu Inoue  * return the best address out of the same scope. if no address was
218482cd038dSYoshinobu Inoue  * found, return the first valid address from designated IF.
218582cd038dSYoshinobu Inoue  */
218682cd038dSYoshinobu Inoue struct in6_ifaddr *
21871272577eSXin LI in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
218882cd038dSYoshinobu Inoue {
218982cd038dSYoshinobu Inoue 	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
219082cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
219182cd038dSYoshinobu Inoue 	struct in6_ifaddr *besta = 0;
219282cd038dSYoshinobu Inoue 	struct in6_ifaddr *dep[2];	/* last-resort: deprecated */
219382cd038dSYoshinobu Inoue 
219482cd038dSYoshinobu Inoue 	dep[0] = dep[1] = NULL;
219582cd038dSYoshinobu Inoue 
219682cd038dSYoshinobu Inoue 	/*
219782cd038dSYoshinobu Inoue 	 * We first look for addresses in the same scope.
219882cd038dSYoshinobu Inoue 	 * If there is one, return it.
219982cd038dSYoshinobu Inoue 	 * If two or more, return one which matches the dst longest.
220082cd038dSYoshinobu Inoue 	 * If none, return one of global addresses assigned other ifs.
220182cd038dSYoshinobu Inoue 	 */
2202ac6ba962SRobert Watson 	IF_ADDR_LOCK(ifp);
2203c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
220482cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
220582cd038dSYoshinobu Inoue 			continue;
220682cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
220782cd038dSYoshinobu Inoue 			continue; /* XXX: is there any case to allow anycast? */
220882cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
220982cd038dSYoshinobu Inoue 			continue; /* don't use this interface */
221082cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
221182cd038dSYoshinobu Inoue 			continue;
221282cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2213603724d3SBjoern A. Zeeb 			if (V_ip6_use_deprecated)
221482cd038dSYoshinobu Inoue 				dep[0] = (struct in6_ifaddr *)ifa;
221582cd038dSYoshinobu Inoue 			continue;
221682cd038dSYoshinobu Inoue 		}
221782cd038dSYoshinobu Inoue 
221882cd038dSYoshinobu Inoue 		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
221982cd038dSYoshinobu Inoue 			/*
222082cd038dSYoshinobu Inoue 			 * call in6_matchlen() as few as possible
222182cd038dSYoshinobu Inoue 			 */
222282cd038dSYoshinobu Inoue 			if (besta) {
222382cd038dSYoshinobu Inoue 				if (blen == -1)
222482cd038dSYoshinobu Inoue 					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
222582cd038dSYoshinobu Inoue 				tlen = in6_matchlen(IFA_IN6(ifa), dst);
222682cd038dSYoshinobu Inoue 				if (tlen > blen) {
222782cd038dSYoshinobu Inoue 					blen = tlen;
222882cd038dSYoshinobu Inoue 					besta = (struct in6_ifaddr *)ifa;
222982cd038dSYoshinobu Inoue 				}
223082cd038dSYoshinobu Inoue 			} else
223182cd038dSYoshinobu Inoue 				besta = (struct in6_ifaddr *)ifa;
223282cd038dSYoshinobu Inoue 		}
223382cd038dSYoshinobu Inoue 	}
2234ac6ba962SRobert Watson 	if (besta) {
22358c0fec80SRobert Watson 		ifa_ref(&besta->ia_ifa);
2236ac6ba962SRobert Watson 		IF_ADDR_UNLOCK(ifp);
223782cd038dSYoshinobu Inoue 		return (besta);
2238ac6ba962SRobert Watson 	}
2239d1da0a06SRobert Watson 	IF_ADDR_UNLOCK(ifp);
224082cd038dSYoshinobu Inoue 
2241d1da0a06SRobert Watson 	IN6_IFADDR_RLOCK();
2242c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
224382cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
224482cd038dSYoshinobu Inoue 			continue;
224582cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
224682cd038dSYoshinobu Inoue 			continue; /* XXX: is there any case to allow anycast? */
224782cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
224882cd038dSYoshinobu Inoue 			continue; /* don't use this interface */
224982cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
225082cd038dSYoshinobu Inoue 			continue;
225182cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2252603724d3SBjoern A. Zeeb 			if (V_ip6_use_deprecated)
225382cd038dSYoshinobu Inoue 				dep[1] = (struct in6_ifaddr *)ifa;
225482cd038dSYoshinobu Inoue 			continue;
225582cd038dSYoshinobu Inoue 		}
225682cd038dSYoshinobu Inoue 
22578c0fec80SRobert Watson 		if (ifa != NULL)
22588c0fec80SRobert Watson 			ifa_ref(ifa);
2259d1da0a06SRobert Watson 		IN6_IFADDR_RUNLOCK();
226082cd038dSYoshinobu Inoue 		return (struct in6_ifaddr *)ifa;
226182cd038dSYoshinobu Inoue 	}
2262d1da0a06SRobert Watson 	IN6_IFADDR_RUNLOCK();
226382cd038dSYoshinobu Inoue 
226482cd038dSYoshinobu Inoue 	/* use the last-resort values, that are, deprecated addresses */
226582cd038dSYoshinobu Inoue 	if (dep[0])
226682cd038dSYoshinobu Inoue 		return dep[0];
226782cd038dSYoshinobu Inoue 	if (dep[1])
226882cd038dSYoshinobu Inoue 		return dep[1];
226982cd038dSYoshinobu Inoue 
227082cd038dSYoshinobu Inoue 	return NULL;
227182cd038dSYoshinobu Inoue }
227282cd038dSYoshinobu Inoue 
227382cd038dSYoshinobu Inoue /*
227482cd038dSYoshinobu Inoue  * perform DAD when interface becomes IFF_UP.
227582cd038dSYoshinobu Inoue  */
227682cd038dSYoshinobu Inoue void
22771272577eSXin LI in6_if_up(struct ifnet *ifp)
227882cd038dSYoshinobu Inoue {
227982cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
228082cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
2281743eee66SSUZUKI Shinsuke 
2282ac6ba962SRobert Watson 	IF_ADDR_LOCK(ifp);
2283c4dd3fe1SRobert Watson 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2284743eee66SSUZUKI Shinsuke 		if (ifa->ifa_addr->sa_family != AF_INET6)
2285743eee66SSUZUKI Shinsuke 			continue;
2286743eee66SSUZUKI Shinsuke 		ia = (struct in6_ifaddr *)ifa;
2287743eee66SSUZUKI Shinsuke 		if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
2288743eee66SSUZUKI Shinsuke 			/*
2289743eee66SSUZUKI Shinsuke 			 * The TENTATIVE flag was likely set by hand
2290743eee66SSUZUKI Shinsuke 			 * beforehand, implicitly indicating the need for DAD.
2291743eee66SSUZUKI Shinsuke 			 * We may be able to skip the random delay in this
2292743eee66SSUZUKI Shinsuke 			 * case, but we impose delays just in case.
2293743eee66SSUZUKI Shinsuke 			 */
2294743eee66SSUZUKI Shinsuke 			nd6_dad_start(ifa,
2295743eee66SSUZUKI Shinsuke 			    arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz));
2296743eee66SSUZUKI Shinsuke 		}
2297743eee66SSUZUKI Shinsuke 	}
2298ac6ba962SRobert Watson 	IF_ADDR_UNLOCK(ifp);
229982cd038dSYoshinobu Inoue 
2300686cdd19SJun-ichiro itojun Hagino 	/*
2301686cdd19SJun-ichiro itojun Hagino 	 * special cases, like 6to4, are handled in in6_ifattach
2302686cdd19SJun-ichiro itojun Hagino 	 */
2303686cdd19SJun-ichiro itojun Hagino 	in6_ifattach(ifp, NULL);
230482cd038dSYoshinobu Inoue }
230582cd038dSYoshinobu Inoue 
230633841545SHajimu UMEMOTO int
23071272577eSXin LI in6if_do_dad(struct ifnet *ifp)
230833841545SHajimu UMEMOTO {
230933841545SHajimu UMEMOTO 	if ((ifp->if_flags & IFF_LOOPBACK) != 0)
231033841545SHajimu UMEMOTO 		return (0);
231133841545SHajimu UMEMOTO 
2312a283298cSHiroki Sato 	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
2313a283298cSHiroki Sato 		return (0);
2314a283298cSHiroki Sato 
231533841545SHajimu UMEMOTO 	switch (ifp->if_type) {
231633841545SHajimu UMEMOTO #ifdef IFT_DUMMY
231733841545SHajimu UMEMOTO 	case IFT_DUMMY:
231833841545SHajimu UMEMOTO #endif
231933841545SHajimu UMEMOTO 	case IFT_FAITH:
232033841545SHajimu UMEMOTO 		/*
232133841545SHajimu UMEMOTO 		 * These interfaces do not have the IFF_LOOPBACK flag,
232233841545SHajimu UMEMOTO 		 * but loop packets back.  We do not have to do DAD on such
232333841545SHajimu UMEMOTO 		 * interfaces.  We should even omit it, because loop-backed
232433841545SHajimu UMEMOTO 		 * NS would confuse the DAD procedure.
232533841545SHajimu UMEMOTO 		 */
232633841545SHajimu UMEMOTO 		return (0);
232733841545SHajimu UMEMOTO 	default:
232833841545SHajimu UMEMOTO 		/*
232933841545SHajimu UMEMOTO 		 * Our DAD routine requires the interface up and running.
233033841545SHajimu UMEMOTO 		 * However, some interfaces can be up before the RUNNING
233133841545SHajimu UMEMOTO 		 * status.  Additionaly, users may try to assign addresses
233233841545SHajimu UMEMOTO 		 * before the interface becomes up (or running).
233333841545SHajimu UMEMOTO 		 * We simply skip DAD in such a case as a work around.
233433841545SHajimu UMEMOTO 		 * XXX: we should rather mark "tentative" on such addresses,
233533841545SHajimu UMEMOTO 		 * and do DAD after the interface becomes ready.
233633841545SHajimu UMEMOTO 		 */
233713f4c340SRobert Watson 		if (!((ifp->if_flags & IFF_UP) &&
233813f4c340SRobert Watson 		    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
233933841545SHajimu UMEMOTO 			return (0);
234033841545SHajimu UMEMOTO 
234133841545SHajimu UMEMOTO 		return (1);
234233841545SHajimu UMEMOTO 	}
234333841545SHajimu UMEMOTO }
234433841545SHajimu UMEMOTO 
234582cd038dSYoshinobu Inoue /*
234682cd038dSYoshinobu Inoue  * Calculate max IPv6 MTU through all the interfaces and store it
234782cd038dSYoshinobu Inoue  * to in6_maxmtu.
234882cd038dSYoshinobu Inoue  */
234982cd038dSYoshinobu Inoue void
23501272577eSXin LI in6_setmaxmtu(void)
235182cd038dSYoshinobu Inoue {
235282cd038dSYoshinobu Inoue 	unsigned long maxmtu = 0;
235382cd038dSYoshinobu Inoue 	struct ifnet *ifp;
235482cd038dSYoshinobu Inoue 
235577dfcdc4SRobert Watson 	IFNET_RLOCK_NOSLEEP();
2356ac957cd2SJulian Elischer 	for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
2357ac957cd2SJulian Elischer 	    ifp = TAILQ_NEXT(ifp, if_list)) {
235831b3783cSHajimu UMEMOTO 		/* this function can be called during ifnet initialization */
235931b3783cSHajimu UMEMOTO 		if (!ifp->if_afdata[AF_INET6])
236031b3783cSHajimu UMEMOTO 			continue;
236182cd038dSYoshinobu Inoue 		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
236231b3783cSHajimu UMEMOTO 		    IN6_LINKMTU(ifp) > maxmtu)
236331b3783cSHajimu UMEMOTO 			maxmtu = IN6_LINKMTU(ifp);
236482cd038dSYoshinobu Inoue 	}
236577dfcdc4SRobert Watson 	IFNET_RUNLOCK_NOSLEEP();
236682cd038dSYoshinobu Inoue 	if (maxmtu)	     /* update only when maxmtu is positive */
2367603724d3SBjoern A. Zeeb 		V_in6_maxmtu = maxmtu;
236882cd038dSYoshinobu Inoue }
236982cd038dSYoshinobu Inoue 
2370743eee66SSUZUKI Shinsuke /*
2371743eee66SSUZUKI Shinsuke  * Provide the length of interface identifiers to be used for the link attached
2372743eee66SSUZUKI Shinsuke  * to the given interface.  The length should be defined in "IPv6 over
2373743eee66SSUZUKI Shinsuke  * xxx-link" document.  Note that address architecture might also define
2374743eee66SSUZUKI Shinsuke  * the length for a particular set of address prefixes, regardless of the
2375743eee66SSUZUKI Shinsuke  * link type.  As clarified in rfc2462bis, those two definitions should be
2376743eee66SSUZUKI Shinsuke  * consistent, and those really are as of August 2004.
2377743eee66SSUZUKI Shinsuke  */
2378743eee66SSUZUKI Shinsuke int
23791272577eSXin LI in6_if2idlen(struct ifnet *ifp)
2380743eee66SSUZUKI Shinsuke {
2381743eee66SSUZUKI Shinsuke 	switch (ifp->if_type) {
2382743eee66SSUZUKI Shinsuke 	case IFT_ETHER:		/* RFC2464 */
2383743eee66SSUZUKI Shinsuke #ifdef IFT_PROPVIRTUAL
2384743eee66SSUZUKI Shinsuke 	case IFT_PROPVIRTUAL:	/* XXX: no RFC. treat it as ether */
2385743eee66SSUZUKI Shinsuke #endif
2386743eee66SSUZUKI Shinsuke #ifdef IFT_L2VLAN
2387743eee66SSUZUKI Shinsuke 	case IFT_L2VLAN:	/* ditto */
2388743eee66SSUZUKI Shinsuke #endif
2389743eee66SSUZUKI Shinsuke #ifdef IFT_IEEE80211
2390743eee66SSUZUKI Shinsuke 	case IFT_IEEE80211:	/* ditto */
2391743eee66SSUZUKI Shinsuke #endif
2392743eee66SSUZUKI Shinsuke #ifdef IFT_MIP
2393743eee66SSUZUKI Shinsuke 	case IFT_MIP:	/* ditto */
2394743eee66SSUZUKI Shinsuke #endif
2395e4cd31ddSJeff Roberson 	case IFT_INFINIBAND:
2396743eee66SSUZUKI Shinsuke 		return (64);
2397743eee66SSUZUKI Shinsuke 	case IFT_FDDI:		/* RFC2467 */
2398743eee66SSUZUKI Shinsuke 		return (64);
2399743eee66SSUZUKI Shinsuke 	case IFT_ISO88025:	/* RFC2470 (IPv6 over Token Ring) */
2400743eee66SSUZUKI Shinsuke 		return (64);
2401743eee66SSUZUKI Shinsuke 	case IFT_PPP:		/* RFC2472 */
2402743eee66SSUZUKI Shinsuke 		return (64);
2403743eee66SSUZUKI Shinsuke 	case IFT_ARCNET:	/* RFC2497 */
2404743eee66SSUZUKI Shinsuke 		return (64);
2405743eee66SSUZUKI Shinsuke 	case IFT_FRELAY:	/* RFC2590 */
2406743eee66SSUZUKI Shinsuke 		return (64);
2407743eee66SSUZUKI Shinsuke 	case IFT_IEEE1394:	/* RFC3146 */
2408743eee66SSUZUKI Shinsuke 		return (64);
2409743eee66SSUZUKI Shinsuke 	case IFT_GIF:
2410743eee66SSUZUKI Shinsuke 		return (64);	/* draft-ietf-v6ops-mech-v2-07 */
2411743eee66SSUZUKI Shinsuke 	case IFT_LOOP:
2412743eee66SSUZUKI Shinsuke 		return (64);	/* XXX: is this really correct? */
2413743eee66SSUZUKI Shinsuke 	default:
2414743eee66SSUZUKI Shinsuke 		/*
2415743eee66SSUZUKI Shinsuke 		 * Unknown link type:
2416743eee66SSUZUKI Shinsuke 		 * It might be controversial to use the today's common constant
2417743eee66SSUZUKI Shinsuke 		 * of 64 for these cases unconditionally.  For full compliance,
2418743eee66SSUZUKI Shinsuke 		 * we should return an error in this case.  On the other hand,
2419743eee66SSUZUKI Shinsuke 		 * if we simply miss the standard for the link type or a new
2420743eee66SSUZUKI Shinsuke 		 * standard is defined for a new link type, the IFID length
2421743eee66SSUZUKI Shinsuke 		 * is very likely to be the common constant.  As a compromise,
2422743eee66SSUZUKI Shinsuke 		 * we always use the constant, but make an explicit notice
2423743eee66SSUZUKI Shinsuke 		 * indicating the "unknown" case.
2424743eee66SSUZUKI Shinsuke 		 */
2425743eee66SSUZUKI Shinsuke 		printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type);
2426743eee66SSUZUKI Shinsuke 		return (64);
2427743eee66SSUZUKI Shinsuke 	}
2428743eee66SSUZUKI Shinsuke }
2429743eee66SSUZUKI Shinsuke 
24306e6b3f7cSQing Li #include <sys/sysctl.h>
24316e6b3f7cSQing Li 
24326e6b3f7cSQing Li struct in6_llentry {
24336e6b3f7cSQing Li 	struct llentry		base;
24346e6b3f7cSQing Li 	struct sockaddr_in6	l3_addr6;
24356e6b3f7cSQing Li };
24366e6b3f7cSQing Li 
24376e6b3f7cSQing Li static struct llentry *
24386e6b3f7cSQing Li in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
24396e6b3f7cSQing Li {
24406e6b3f7cSQing Li 	struct in6_llentry *lle;
24416e6b3f7cSQing Li 
24426e6b3f7cSQing Li 	lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
24436e6b3f7cSQing Li 	    M_DONTWAIT | M_ZERO);
24446e6b3f7cSQing Li 	if (lle == NULL)		/* NB: caller generates msg */
24456e6b3f7cSQing Li 		return NULL;
24466e6b3f7cSQing Li 
24476e6b3f7cSQing Li 	lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
24486e6b3f7cSQing Li 	lle->base.lle_refcnt = 1;
24496e6b3f7cSQing Li 	LLE_LOCK_INIT(&lle->base);
2450e6950476SBjoern A. Zeeb 	callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
2451e6950476SBjoern A. Zeeb 	    CALLOUT_RETURNUNLOCKED);
2452e6950476SBjoern A. Zeeb 
24536e6b3f7cSQing Li 	return &lle->base;
24546e6b3f7cSQing Li }
24556e6b3f7cSQing Li 
24566e6b3f7cSQing Li /*
24576e6b3f7cSQing Li  * Deletes an address from the address table.
24586e6b3f7cSQing Li  * This function is called by the timer functions
24596e6b3f7cSQing Li  * such as arptimer() and nd6_llinfo_timer(), and
24606e6b3f7cSQing Li  * the caller does the locking.
24616e6b3f7cSQing Li  */
24626e6b3f7cSQing Li static void
24636e6b3f7cSQing Li in6_lltable_free(struct lltable *llt, struct llentry *lle)
24646e6b3f7cSQing Li {
2465fbc2ca1bSKip Macy 	LLE_WUNLOCK(lle);
2466fbc2ca1bSKip Macy 	LLE_LOCK_DESTROY(lle);
24676e6b3f7cSQing Li 	free(lle, M_LLTABLE);
24686e6b3f7cSQing Li }
24696e6b3f7cSQing Li 
2470c9d763bfSQing Li static void
2471c9d763bfSQing Li in6_lltable_prefix_free(struct lltable *llt,
2472c9d763bfSQing Li 			const struct sockaddr *prefix,
24735b84dc78SQing Li 			const struct sockaddr *mask,
24745b84dc78SQing Li 			u_int flags)
2475c9d763bfSQing Li {
2476c9d763bfSQing Li 	const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
2477c9d763bfSQing Li 	const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
2478c9d763bfSQing Li 	struct llentry *lle, *next;
2479c9d763bfSQing Li 	register int i;
2480c9d763bfSQing Li 
24815b84dc78SQing Li 	/*
24825b84dc78SQing Li 	 * (flags & LLE_STATIC) means deleting all entries
24835b84dc78SQing Li 	 * including static ND6 entries
24845b84dc78SQing Li 	 */
2485c9d763bfSQing Li 	for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
2486c9d763bfSQing Li 		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
2487c9d763bfSQing Li 			if (IN6_ARE_MASKED_ADDR_EQUAL(
2488c9d763bfSQing Li 				    &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr,
2489c9d763bfSQing Li 				    &pfx->sin6_addr,
24905b84dc78SQing Li 				    &msk->sin6_addr) &&
24915b84dc78SQing Li 			    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) {
2492becba438SBjoern A. Zeeb 				int canceled;
2493becba438SBjoern A. Zeeb 
2494becba438SBjoern A. Zeeb 				canceled = callout_drain(&lle->la_timer);
2495c9d763bfSQing Li 				LLE_WLOCK(lle);
2496becba438SBjoern A. Zeeb 				if (canceled)
2497becba438SBjoern A. Zeeb 					LLE_REMREF(lle);
2498c9d763bfSQing Li 				llentry_free(lle);
2499c9d763bfSQing Li 			}
2500c9d763bfSQing Li 		}
2501c9d763bfSQing Li 	}
2502c9d763bfSQing Li }
2503c9d763bfSQing Li 
25046e6b3f7cSQing Li static int
2505c7ab6602SQing Li in6_lltable_rtcheck(struct ifnet *ifp,
2506c7ab6602SQing Li 		    u_int flags,
2507c7ab6602SQing Li 		    const struct sockaddr *l3addr)
25086e6b3f7cSQing Li {
25096e6b3f7cSQing Li 	struct rtentry *rt;
25106e6b3f7cSQing Li 	char ip6buf[INET6_ADDRSTRLEN];
25116e6b3f7cSQing Li 
25126e6b3f7cSQing Li 	KASSERT(l3addr->sa_family == AF_INET6,
25136e6b3f7cSQing Li 	    ("sin_family %d", l3addr->sa_family));
25146e6b3f7cSQing Li 
25156e6b3f7cSQing Li 	/* XXX rtalloc1 should take a const param */
25166e6b3f7cSQing Li 	rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
25176e6b3f7cSQing Li 	if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
25186e6b3f7cSQing Li 		struct ifaddr *ifa;
25196e6b3f7cSQing Li 		/*
25206e6b3f7cSQing Li 		 * Create an ND6 cache for an IPv6 neighbor
25216e6b3f7cSQing Li 		 * that is not covered by our own prefix.
25226e6b3f7cSQing Li 		 */
25236e6b3f7cSQing Li 		/* XXX ifaof_ifpforaddr should take a const param */
25246e6b3f7cSQing Li 		ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp);
25256e6b3f7cSQing Li 		if (ifa != NULL) {
25268c0fec80SRobert Watson 			ifa_free(ifa);
25276e6b3f7cSQing Li 			if (rt != NULL)
25282e730beaSBjoern A. Zeeb 				RTFREE_LOCKED(rt);
25296e6b3f7cSQing Li 			return 0;
25306e6b3f7cSQing Li 		}
25316e6b3f7cSQing Li 		log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
25326e6b3f7cSQing Li 		    ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr));
25336e6b3f7cSQing Li 		if (rt != NULL)
25342e730beaSBjoern A. Zeeb 			RTFREE_LOCKED(rt);
25356e6b3f7cSQing Li 		return EINVAL;
25366e6b3f7cSQing Li 	}
25372e730beaSBjoern A. Zeeb 	RTFREE_LOCKED(rt);
25386e6b3f7cSQing Li 	return 0;
25396e6b3f7cSQing Li }
25406e6b3f7cSQing Li 
25416e6b3f7cSQing Li static struct llentry *
25426e6b3f7cSQing Li in6_lltable_lookup(struct lltable *llt, u_int flags,
25436e6b3f7cSQing Li 	const struct sockaddr *l3addr)
25446e6b3f7cSQing Li {
25456e6b3f7cSQing Li 	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
25466e6b3f7cSQing Li 	struct ifnet *ifp = llt->llt_ifp;
25476e6b3f7cSQing Li 	struct llentry *lle;
25486e6b3f7cSQing Li 	struct llentries *lleh;
25496e6b3f7cSQing Li 	u_int hashkey;
25506e6b3f7cSQing Li 
25516e6b3f7cSQing Li 	IF_AFDATA_LOCK_ASSERT(ifp);
25526e6b3f7cSQing Li 	KASSERT(l3addr->sa_family == AF_INET6,
25536e6b3f7cSQing Li 	    ("sin_family %d", l3addr->sa_family));
25546e6b3f7cSQing Li 
25556e6b3f7cSQing Li 	hashkey = sin6->sin6_addr.s6_addr32[3];
25566e6b3f7cSQing Li 	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
25576e6b3f7cSQing Li 	LIST_FOREACH(lle, lleh, lle_next) {
2558dc495497SQing Li 		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle);
25596e6b3f7cSQing Li 		if (lle->la_flags & LLE_DELETED)
25606e6b3f7cSQing Li 			continue;
2561dc495497SQing Li 		if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
2562dc495497SQing Li 			 sizeof(struct in6_addr)) == 0)
25636e6b3f7cSQing Li 			break;
25646e6b3f7cSQing Li 	}
25656e6b3f7cSQing Li 
25666e6b3f7cSQing Li 	if (lle == NULL) {
25676e6b3f7cSQing Li 		if (!(flags & LLE_CREATE))
25686e6b3f7cSQing Li 			return (NULL);
25696e6b3f7cSQing Li 		/*
25706e6b3f7cSQing Li 		 * A route that covers the given address must have
25716e6b3f7cSQing Li 		 * been installed 1st because we are doing a resolution,
25726e6b3f7cSQing Li 		 * verify this.
25736e6b3f7cSQing Li 		 */
25746e6b3f7cSQing Li 		if (!(flags & LLE_IFADDR) &&
2575c7ab6602SQing Li 		    in6_lltable_rtcheck(ifp, flags, l3addr) != 0)
25766e6b3f7cSQing Li 			return NULL;
25776e6b3f7cSQing Li 
25786e6b3f7cSQing Li 		lle = in6_lltable_new(l3addr, flags);
25796e6b3f7cSQing Li 		if (lle == NULL) {
25806e6b3f7cSQing Li 			log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
25816e6b3f7cSQing Li 			return NULL;
25826e6b3f7cSQing Li 		}
25836e6b3f7cSQing Li 		lle->la_flags = flags & ~LLE_CREATE;
25846e6b3f7cSQing Li 		if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
25856e6b3f7cSQing Li 			bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
25866e6b3f7cSQing Li 			lle->la_flags |= (LLE_VALID | LLE_STATIC);
25876e6b3f7cSQing Li 		}
25886e6b3f7cSQing Li 
25896e6b3f7cSQing Li 		lle->lle_tbl  = llt;
25906e6b3f7cSQing Li 		lle->lle_head = lleh;
25916e6b3f7cSQing Li 		LIST_INSERT_HEAD(lleh, lle, lle_next);
25926e6b3f7cSQing Li 	} else if (flags & LLE_DELETE) {
2593ebf1c744SQing Li 		if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
25946e6b3f7cSQing Li 			LLE_WLOCK(lle);
25956e6b3f7cSQing Li 			lle->la_flags = LLE_DELETED;
25966e6b3f7cSQing Li 			LLE_WUNLOCK(lle);
25976cb2b4e7SQing Li #ifdef DIAGNOSTIC
25986e6b3f7cSQing Li 			log(LOG_INFO, "ifaddr cache = %p  is deleted\n", lle);
25996e6b3f7cSQing Li #endif
2600ebf1c744SQing Li 		}
26016e6b3f7cSQing Li 		lle = (void *)-1;
26026e6b3f7cSQing Li 	}
26036e6b3f7cSQing Li 	if (LLE_IS_VALID(lle)) {
26046e6b3f7cSQing Li 		if (flags & LLE_EXCLUSIVE)
26056e6b3f7cSQing Li 			LLE_WLOCK(lle);
26066e6b3f7cSQing Li 		else
26076e6b3f7cSQing Li 			LLE_RLOCK(lle);
26086e6b3f7cSQing Li 	}
26096e6b3f7cSQing Li 	return (lle);
26106e6b3f7cSQing Li }
26116e6b3f7cSQing Li 
26126e6b3f7cSQing Li static int
26136e6b3f7cSQing Li in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
26146e6b3f7cSQing Li {
26156e6b3f7cSQing Li 	struct ifnet *ifp = llt->llt_ifp;
26166e6b3f7cSQing Li 	struct llentry *lle;
26176e6b3f7cSQing Li 	/* XXX stack use */
26186e6b3f7cSQing Li 	struct {
26196e6b3f7cSQing Li 		struct rt_msghdr	rtm;
26206e6b3f7cSQing Li 		struct sockaddr_in6	sin6;
26216e6b3f7cSQing Li 		/*
26226e6b3f7cSQing Li 		 * ndp.c assumes that sdl is word aligned
26236e6b3f7cSQing Li 		 */
26246e6b3f7cSQing Li #ifdef __LP64__
26256e6b3f7cSQing Li 		uint32_t		pad;
26266e6b3f7cSQing Li #endif
26276e6b3f7cSQing Li 		struct sockaddr_dl	sdl;
26286e6b3f7cSQing Li 	} ndpc;
26296e6b3f7cSQing Li 	int i, error;
26306e6b3f7cSQing Li 
26319452b0d2SQing Li 	if (ifp->if_flags & IFF_LOOPBACK)
26329452b0d2SQing Li 		return 0;
26339452b0d2SQing Li 
2634dc56e98fSRobert Watson 	LLTABLE_LOCK_ASSERT();
26356e6b3f7cSQing Li 
26366e6b3f7cSQing Li 	error = 0;
26376e6b3f7cSQing Li 	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
26386e6b3f7cSQing Li 		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
26396e6b3f7cSQing Li 			struct sockaddr_dl *sdl;
26406e6b3f7cSQing Li 
26416e6b3f7cSQing Li 			/* skip deleted or invalid entries */
26426e6b3f7cSQing Li 			if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID)
26436e6b3f7cSQing Li 				continue;
2644813dd6aeSBjoern A. Zeeb 			/* Skip if jailed and not a valid IP of the prison. */
2645b89e82ddSJamie Gritton 			if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0)
2646813dd6aeSBjoern A. Zeeb 				continue;
26476e6b3f7cSQing Li 			/*
26486e6b3f7cSQing Li 			 * produce a msg made of:
26496e6b3f7cSQing Li 			 *  struct rt_msghdr;
26506e6b3f7cSQing Li 			 *  struct sockaddr_in6 (IPv6)
26516e6b3f7cSQing Li 			 *  struct sockaddr_dl;
26526e6b3f7cSQing Li 			 */
26536e6b3f7cSQing Li 			bzero(&ndpc, sizeof(ndpc));
26546e6b3f7cSQing Li 			ndpc.rtm.rtm_msglen = sizeof(ndpc);
265514981d80SQing Li 			ndpc.rtm.rtm_version = RTM_VERSION;
265614981d80SQing Li 			ndpc.rtm.rtm_type = RTM_GET;
265714981d80SQing Li 			ndpc.rtm.rtm_flags = RTF_UP;
265814981d80SQing Li 			ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
26596e6b3f7cSQing Li 			ndpc.sin6.sin6_family = AF_INET6;
26606e6b3f7cSQing Li 			ndpc.sin6.sin6_len = sizeof(ndpc.sin6);
26616e6b3f7cSQing Li 			bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle));
26626e6b3f7cSQing Li 
26636e6b3f7cSQing Li 			/* publish */
26646e6b3f7cSQing Li 			if (lle->la_flags & LLE_PUB)
26656e6b3f7cSQing Li 				ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
26666e6b3f7cSQing Li 
26676e6b3f7cSQing Li 			sdl = &ndpc.sdl;
26686e6b3f7cSQing Li 			sdl->sdl_family = AF_LINK;
26696e6b3f7cSQing Li 			sdl->sdl_len = sizeof(*sdl);
26706e6b3f7cSQing Li 			sdl->sdl_alen = ifp->if_addrlen;
26716e6b3f7cSQing Li 			sdl->sdl_index = ifp->if_index;
26726e6b3f7cSQing Li 			sdl->sdl_type = ifp->if_type;
26736e6b3f7cSQing Li 			bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
26746e6b3f7cSQing Li 			ndpc.rtm.rtm_rmx.rmx_expire =
26756e6b3f7cSQing Li 			    lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
26768eca593cSQing Li 			ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
26776e6b3f7cSQing Li 			if (lle->la_flags & LLE_STATIC)
26786e6b3f7cSQing Li 				ndpc.rtm.rtm_flags |= RTF_STATIC;
26796e6b3f7cSQing Li 			ndpc.rtm.rtm_index = ifp->if_index;
26806e6b3f7cSQing Li 			error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
26816e6b3f7cSQing Li 			if (error)
26826e6b3f7cSQing Li 				break;
26836e6b3f7cSQing Li 		}
26846e6b3f7cSQing Li 	}
26856e6b3f7cSQing Li 	return error;
26866e6b3f7cSQing Li }
26876e6b3f7cSQing Li 
268831b1bfe1SHajimu UMEMOTO void *
26891272577eSXin LI in6_domifattach(struct ifnet *ifp)
269031b1bfe1SHajimu UMEMOTO {
269131b1bfe1SHajimu UMEMOTO 	struct in6_ifextra *ext;
269231b1bfe1SHajimu UMEMOTO 
269331b1bfe1SHajimu UMEMOTO 	ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
269431b1bfe1SHajimu UMEMOTO 	bzero(ext, sizeof(*ext));
269531b1bfe1SHajimu UMEMOTO 
269631b1bfe1SHajimu UMEMOTO 	ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
269731b1bfe1SHajimu UMEMOTO 	    M_IFADDR, M_WAITOK);
269831b1bfe1SHajimu UMEMOTO 	bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
269931b1bfe1SHajimu UMEMOTO 
270031b1bfe1SHajimu UMEMOTO 	ext->icmp6_ifstat =
270131b1bfe1SHajimu UMEMOTO 	    (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
270231b1bfe1SHajimu UMEMOTO 	    M_IFADDR, M_WAITOK);
270331b1bfe1SHajimu UMEMOTO 	bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
270431b1bfe1SHajimu UMEMOTO 
270531b1bfe1SHajimu UMEMOTO 	ext->nd_ifinfo = nd6_ifattach(ifp);
270631b1bfe1SHajimu UMEMOTO 	ext->scope6_id = scope6_ifattach(ifp);
27076e6b3f7cSQing Li 	ext->lltable = lltable_init(ifp, AF_INET6);
27086e6b3f7cSQing Li 	if (ext->lltable != NULL) {
27096e6b3f7cSQing Li 		ext->lltable->llt_free = in6_lltable_free;
2710c9d763bfSQing Li 		ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
27116e6b3f7cSQing Li 		ext->lltable->llt_lookup = in6_lltable_lookup;
27126e6b3f7cSQing Li 		ext->lltable->llt_dump = in6_lltable_dump;
27136e6b3f7cSQing Li 	}
271433cde130SBruce M Simpson 
271533cde130SBruce M Simpson 	ext->mld_ifinfo = mld_domifattach(ifp);
271633cde130SBruce M Simpson 
271731b1bfe1SHajimu UMEMOTO 	return ext;
271831b1bfe1SHajimu UMEMOTO }
271931b1bfe1SHajimu UMEMOTO 
272031b1bfe1SHajimu UMEMOTO void
27211272577eSXin LI in6_domifdetach(struct ifnet *ifp, void *aux)
272231b1bfe1SHajimu UMEMOTO {
272331b1bfe1SHajimu UMEMOTO 	struct in6_ifextra *ext = (struct in6_ifextra *)aux;
272431b1bfe1SHajimu UMEMOTO 
272533cde130SBruce M Simpson 	mld_domifdetach(ifp);
272631b1bfe1SHajimu UMEMOTO 	scope6_ifdetach(ext->scope6_id);
272731b1bfe1SHajimu UMEMOTO 	nd6_ifdetach(ext->nd_ifinfo);
27286e6b3f7cSQing Li 	lltable_free(ext->lltable);
272931b1bfe1SHajimu UMEMOTO 	free(ext->in6_ifstat, M_IFADDR);
273031b1bfe1SHajimu UMEMOTO 	free(ext->icmp6_ifstat, M_IFADDR);
273131b1bfe1SHajimu UMEMOTO 	free(ext, M_IFADDR);
273231b1bfe1SHajimu UMEMOTO }
273331b1bfe1SHajimu UMEMOTO 
273482cd038dSYoshinobu Inoue /*
273582cd038dSYoshinobu Inoue  * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
273682cd038dSYoshinobu Inoue  * v4 mapped addr or v4 compat addr
273782cd038dSYoshinobu Inoue  */
273882cd038dSYoshinobu Inoue void
273982cd038dSYoshinobu Inoue in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
274082cd038dSYoshinobu Inoue {
27411272577eSXin LI 
274282cd038dSYoshinobu Inoue 	bzero(sin, sizeof(*sin));
274382cd038dSYoshinobu Inoue 	sin->sin_len = sizeof(struct sockaddr_in);
274482cd038dSYoshinobu Inoue 	sin->sin_family = AF_INET;
274582cd038dSYoshinobu Inoue 	sin->sin_port = sin6->sin6_port;
274682cd038dSYoshinobu Inoue 	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
274782cd038dSYoshinobu Inoue }
274882cd038dSYoshinobu Inoue 
274982cd038dSYoshinobu Inoue /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
275082cd038dSYoshinobu Inoue void
275182cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
275282cd038dSYoshinobu Inoue {
275382cd038dSYoshinobu Inoue 	bzero(sin6, sizeof(*sin6));
275482cd038dSYoshinobu Inoue 	sin6->sin6_len = sizeof(struct sockaddr_in6);
275582cd038dSYoshinobu Inoue 	sin6->sin6_family = AF_INET6;
275682cd038dSYoshinobu Inoue 	sin6->sin6_port = sin->sin_port;
275782cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[0] = 0;
275882cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[1] = 0;
275982cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
276082cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
276182cd038dSYoshinobu Inoue }
276282cd038dSYoshinobu Inoue 
276382cd038dSYoshinobu Inoue /* Convert sockaddr_in6 into sockaddr_in. */
276482cd038dSYoshinobu Inoue void
276582cd038dSYoshinobu Inoue in6_sin6_2_sin_in_sock(struct sockaddr *nam)
276682cd038dSYoshinobu Inoue {
276782cd038dSYoshinobu Inoue 	struct sockaddr_in *sin_p;
276882cd038dSYoshinobu Inoue 	struct sockaddr_in6 sin6;
276982cd038dSYoshinobu Inoue 
277082cd038dSYoshinobu Inoue 	/*
277182cd038dSYoshinobu Inoue 	 * Save original sockaddr_in6 addr and convert it
277282cd038dSYoshinobu Inoue 	 * to sockaddr_in.
277382cd038dSYoshinobu Inoue 	 */
277482cd038dSYoshinobu Inoue 	sin6 = *(struct sockaddr_in6 *)nam;
277582cd038dSYoshinobu Inoue 	sin_p = (struct sockaddr_in *)nam;
277682cd038dSYoshinobu Inoue 	in6_sin6_2_sin(sin_p, &sin6);
277782cd038dSYoshinobu Inoue }
277882cd038dSYoshinobu Inoue 
277982cd038dSYoshinobu Inoue /* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
278082cd038dSYoshinobu Inoue void
278182cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
278282cd038dSYoshinobu Inoue {
278382cd038dSYoshinobu Inoue 	struct sockaddr_in *sin_p;
278482cd038dSYoshinobu Inoue 	struct sockaddr_in6 *sin6_p;
278582cd038dSYoshinobu Inoue 
27861ede983cSDag-Erling Smørgrav 	sin6_p = malloc(sizeof *sin6_p, M_SONAME,
2787a163d034SWarner Losh 	       M_WAITOK);
278882cd038dSYoshinobu Inoue 	sin_p = (struct sockaddr_in *)*nam;
278982cd038dSYoshinobu Inoue 	in6_sin_2_v4mapsin6(sin_p, sin6_p);
27901ede983cSDag-Erling Smørgrav 	free(*nam, M_SONAME);
279182cd038dSYoshinobu Inoue 	*nam = (struct sockaddr *)sin6_p;
279282cd038dSYoshinobu Inoue }
2793