xref: /freebsd/sys/netinet6/in6.c (revision 686cdd19b1b182f2257bc158116e78c5fef84980)
1686cdd19SJun-ichiro itojun Hagino /*	$FreeBSD$	*/
2686cdd19SJun-ichiro itojun Hagino /*	$KAME: in6.c,v 1.87 2000/07/03 15:44:21 itojun Exp $	*/
3686cdd19SJun-ichiro itojun Hagino 
482cd038dSYoshinobu Inoue /*
582cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
682cd038dSYoshinobu Inoue  * All rights reserved.
782cd038dSYoshinobu Inoue  *
882cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
982cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
1082cd038dSYoshinobu Inoue  * are met:
1182cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1282cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1382cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1482cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1582cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1682cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1782cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1882cd038dSYoshinobu Inoue  *    without specific prior written permission.
1982cd038dSYoshinobu Inoue  *
2082cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2182cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2282cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2382cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2482cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2582cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2682cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2782cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2882cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2982cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3082cd038dSYoshinobu Inoue  * SUCH DAMAGE.
3182cd038dSYoshinobu Inoue  */
3282cd038dSYoshinobu Inoue 
3382cd038dSYoshinobu Inoue /*
3482cd038dSYoshinobu Inoue  * Copyright (c) 1982, 1986, 1991, 1993
3582cd038dSYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
3682cd038dSYoshinobu Inoue  *
3782cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
3882cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
3982cd038dSYoshinobu Inoue  * are met:
4082cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
4182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
4282cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
4382cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
4482cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
4582cd038dSYoshinobu Inoue  * 3. All advertising materials mentioning features or use of this software
4682cd038dSYoshinobu Inoue  *    must display the following acknowledgement:
4782cd038dSYoshinobu Inoue  *	This product includes software developed by the University of
4882cd038dSYoshinobu Inoue  *	California, Berkeley and its contributors.
4982cd038dSYoshinobu Inoue  * 4. Neither the name of the University nor the names of its contributors
5082cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
5182cd038dSYoshinobu Inoue  *    without specific prior written permission.
5282cd038dSYoshinobu Inoue  *
5382cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5482cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5582cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5682cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5782cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5882cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5982cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6082cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6182cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6282cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6382cd038dSYoshinobu Inoue  * SUCH DAMAGE.
6482cd038dSYoshinobu Inoue  *
6582cd038dSYoshinobu Inoue  *	@(#)in.c	8.2 (Berkeley) 11/15/93
6682cd038dSYoshinobu Inoue  */
6782cd038dSYoshinobu Inoue 
68686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
69686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h"
70686cdd19SJun-ichiro itojun Hagino 
7182cd038dSYoshinobu Inoue #include <sys/param.h>
7282cd038dSYoshinobu Inoue #include <sys/errno.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>
7882cd038dSYoshinobu Inoue #include <sys/proc.h>
7982cd038dSYoshinobu Inoue #include <sys/time.h>
8082cd038dSYoshinobu Inoue #include <sys/kernel.h>
8182cd038dSYoshinobu Inoue #include <sys/syslog.h>
8282cd038dSYoshinobu Inoue 
8382cd038dSYoshinobu Inoue #include <net/if.h>
8482cd038dSYoshinobu Inoue #include <net/if_types.h>
8582cd038dSYoshinobu Inoue #include <net/route.h>
8682cd038dSYoshinobu Inoue #include <net/if_dl.h>
8782cd038dSYoshinobu Inoue 
8882cd038dSYoshinobu Inoue #include <netinet/in.h>
8982cd038dSYoshinobu Inoue #include <netinet/in_var.h>
9082cd038dSYoshinobu Inoue #include <netinet/if_ether.h>
9182cd038dSYoshinobu Inoue 
9282cd038dSYoshinobu Inoue #include <netinet6/nd6.h>
93686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
9482cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
9582cd038dSYoshinobu Inoue #include <netinet6/mld6_var.h>
96686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6_mroute.h>
9782cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h>
98686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h>
99686cdd19SJun-ichiro itojun Hagino 
100686cdd19SJun-ichiro itojun Hagino #include "gif.h"
101cfa1ca9dSYoshinobu Inoue #if NGIF > 0
102cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h>
103cfa1ca9dSYoshinobu Inoue #endif
10482cd038dSYoshinobu Inoue 
10582cd038dSYoshinobu Inoue #include <net/net_osdep.h>
10682cd038dSYoshinobu Inoue 
10782cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address");
10882cd038dSYoshinobu Inoue 
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;
12082cd038dSYoshinobu Inoue 
12182cd038dSYoshinobu Inoue const struct in6_addr in6mask0 = IN6MASK0;
12282cd038dSYoshinobu Inoue const struct in6_addr in6mask32 = IN6MASK32;
12382cd038dSYoshinobu Inoue const struct in6_addr in6mask64 = IN6MASK64;
12482cd038dSYoshinobu Inoue const struct in6_addr in6mask96 = IN6MASK96;
12582cd038dSYoshinobu Inoue const struct in6_addr in6mask128 = IN6MASK128;
12682cd038dSYoshinobu Inoue 
12782cd038dSYoshinobu Inoue static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
12882cd038dSYoshinobu Inoue 	struct ifnet *, struct proc *));
12982cd038dSYoshinobu Inoue 
130686cdd19SJun-ichiro itojun Hagino struct in6_multihead in6_multihead;	/* XXX BSS initialization */
13182cd038dSYoshinobu Inoue 
13282cd038dSYoshinobu Inoue /*
13382cd038dSYoshinobu Inoue  * Check if the loopback entry will be automatically generated.
13482cd038dSYoshinobu Inoue  *   if 0 returned, will not be automatically generated.
13582cd038dSYoshinobu Inoue  *   if 1 returned, will be automatically generated.
13682cd038dSYoshinobu Inoue  */
13782cd038dSYoshinobu Inoue static int
13882cd038dSYoshinobu Inoue in6_is_ifloop_auto(struct ifaddr *ifa)
13982cd038dSYoshinobu Inoue {
14082cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s)
14182cd038dSYoshinobu Inoue 	/*
14282cd038dSYoshinobu Inoue 	 * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT),
14382cd038dSYoshinobu Inoue 	 * or netmask is all0 or all1, then cloning will not happen,
14482cd038dSYoshinobu Inoue 	 * then we can't rely on its loopback entry generation.
14582cd038dSYoshinobu Inoue 	 */
14682cd038dSYoshinobu Inoue 	if ((ifa->ifa_flags & RTF_CLONING) == 0 ||
14782cd038dSYoshinobu Inoue 	    (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) ||
14882cd038dSYoshinobu Inoue 	    (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6)
14982cd038dSYoshinobu Inoue 	     &&
15082cd038dSYoshinobu Inoue 	     IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr,
15182cd038dSYoshinobu Inoue 				&in6mask128)) ||
15282cd038dSYoshinobu Inoue 	    ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0)
15382cd038dSYoshinobu Inoue 		return 0;
15482cd038dSYoshinobu Inoue 	else
15582cd038dSYoshinobu Inoue 		return 1;
15682cd038dSYoshinobu Inoue #undef SIN6
15782cd038dSYoshinobu Inoue }
15882cd038dSYoshinobu Inoue 
15982cd038dSYoshinobu Inoue /*
16082cd038dSYoshinobu Inoue  * Subroutine for in6_ifaddloop() and in6_ifremloop().
16182cd038dSYoshinobu Inoue  * This routine does actual work.
16282cd038dSYoshinobu Inoue  */
16382cd038dSYoshinobu Inoue static void
16482cd038dSYoshinobu Inoue in6_ifloop_request(int cmd, struct ifaddr *ifa)
16582cd038dSYoshinobu Inoue {
16682cd038dSYoshinobu Inoue 	struct sockaddr_in6 lo_sa;
16782cd038dSYoshinobu Inoue 	struct sockaddr_in6 all1_sa;
16882cd038dSYoshinobu Inoue 	struct rtentry *nrt = NULL;
16982cd038dSYoshinobu Inoue 
17082cd038dSYoshinobu Inoue 	bzero(&lo_sa, sizeof(lo_sa));
17182cd038dSYoshinobu Inoue 	bzero(&all1_sa, sizeof(all1_sa));
17282cd038dSYoshinobu Inoue 	lo_sa.sin6_family = AF_INET6;
17382cd038dSYoshinobu Inoue 	lo_sa.sin6_len = sizeof(struct sockaddr_in6);
17482cd038dSYoshinobu Inoue 	all1_sa = lo_sa;
17582cd038dSYoshinobu Inoue 	lo_sa.sin6_addr = in6addr_loopback;
17682cd038dSYoshinobu Inoue 	all1_sa.sin6_addr = in6mask128;
17782cd038dSYoshinobu Inoue 
178686cdd19SJun-ichiro itojun Hagino 	/*
179686cdd19SJun-ichiro itojun Hagino 	 * So we add or remove static loopback entry, here.
180686cdd19SJun-ichiro itojun Hagino 	 * This request for deletion could fail, e.g. when we remove
181686cdd19SJun-ichiro itojun Hagino 	 * an address right after adding it.
182686cdd19SJun-ichiro itojun Hagino 	 */
18382cd038dSYoshinobu Inoue 	rtrequest(cmd, ifa->ifa_addr,
18482cd038dSYoshinobu Inoue 		  (struct sockaddr *)&lo_sa,
18582cd038dSYoshinobu Inoue 		  (struct sockaddr *)&all1_sa,
18682cd038dSYoshinobu Inoue 		  RTF_UP|RTF_HOST, &nrt);
18782cd038dSYoshinobu Inoue 
18882cd038dSYoshinobu Inoue 	/*
18982cd038dSYoshinobu Inoue 	 * Make sure rt_ifa be equal to IFA, the second argument of the
19082cd038dSYoshinobu Inoue 	 * function.
19182cd038dSYoshinobu Inoue 	 * We need this because when we refer rt_ifa->ia6_flags in ip6_input,
19282cd038dSYoshinobu Inoue 	 * we assume that the rt_ifa points to the address instead of the
19382cd038dSYoshinobu Inoue 	 * loopback address.
19482cd038dSYoshinobu Inoue 	 */
19582cd038dSYoshinobu Inoue 	if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
196686cdd19SJun-ichiro itojun Hagino 		IFAFREE(nrt->rt_ifa);
19782cd038dSYoshinobu Inoue 		ifa->ifa_refcnt++;
19882cd038dSYoshinobu Inoue 		nrt->rt_ifa = ifa;
19982cd038dSYoshinobu Inoue 	}
20082cd038dSYoshinobu Inoue 	if (nrt)
20182cd038dSYoshinobu Inoue 		nrt->rt_refcnt--;
20282cd038dSYoshinobu Inoue }
20382cd038dSYoshinobu Inoue 
20482cd038dSYoshinobu Inoue /*
20582cd038dSYoshinobu Inoue  * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link).
20682cd038dSYoshinobu Inoue  * Because, KAME needs loopback rtentry for ownaddr check in
20782cd038dSYoshinobu Inoue  * ip6_input().
20882cd038dSYoshinobu Inoue  */
20982cd038dSYoshinobu Inoue static void
21082cd038dSYoshinobu Inoue in6_ifaddloop(struct ifaddr *ifa)
21182cd038dSYoshinobu Inoue {
21282cd038dSYoshinobu Inoue 	if (!in6_is_ifloop_auto(ifa)) {
21382cd038dSYoshinobu Inoue 		struct rtentry *rt;
21482cd038dSYoshinobu Inoue 
21582cd038dSYoshinobu Inoue 		/* If there is no loopback entry, allocate one. */
21682cd038dSYoshinobu Inoue 		rt = rtalloc1(ifa->ifa_addr, 0, 0);
21782cd038dSYoshinobu Inoue 		if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
21882cd038dSYoshinobu Inoue 			in6_ifloop_request(RTM_ADD, ifa);
21982cd038dSYoshinobu Inoue 		if (rt)
22082cd038dSYoshinobu Inoue 			rt->rt_refcnt--;
22182cd038dSYoshinobu Inoue 	}
22282cd038dSYoshinobu Inoue }
22382cd038dSYoshinobu Inoue 
22482cd038dSYoshinobu Inoue /*
22582cd038dSYoshinobu Inoue  * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
22682cd038dSYoshinobu Inoue  * if it exists.
22782cd038dSYoshinobu Inoue  */
22882cd038dSYoshinobu Inoue static void
22982cd038dSYoshinobu Inoue in6_ifremloop(struct ifaddr *ifa)
23082cd038dSYoshinobu Inoue {
23182cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
23282cd038dSYoshinobu Inoue 	int ia_count = 0;
23382cd038dSYoshinobu Inoue 
234686cdd19SJun-ichiro itojun Hagino 	/*
235686cdd19SJun-ichiro itojun Hagino 	 * All BSD variants except BSD/OS do not remove cloned routes
236686cdd19SJun-ichiro itojun Hagino 	 * from an interface direct route, when removing the direct route
237686cdd19SJun-ichiro itojun Hagino 	 * (see commens in net/net_osdep.h).
238686cdd19SJun-ichiro itojun Hagino 	 * So we should remove the route corresponding to the deleted address
239686cdd19SJun-ichiro itojun Hagino 	 * regardless of the result of in6_is_ifloop_auto().
240686cdd19SJun-ichiro itojun Hagino 	 */
241686cdd19SJun-ichiro itojun Hagino 	if (1)
242686cdd19SJun-ichiro itojun Hagino 	{
24382cd038dSYoshinobu Inoue 		/* If only one ifa for the loopback entry, delete it. */
24482cd038dSYoshinobu Inoue 		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
24582cd038dSYoshinobu Inoue 			if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa),
24682cd038dSYoshinobu Inoue 					       &ia->ia_addr.sin6_addr)) {
24782cd038dSYoshinobu Inoue 				ia_count++;
24882cd038dSYoshinobu Inoue 				if (ia_count > 1)
24982cd038dSYoshinobu Inoue 					break;
25082cd038dSYoshinobu Inoue 			}
25182cd038dSYoshinobu Inoue 		}
25282cd038dSYoshinobu Inoue 		if (ia_count == 1)
25382cd038dSYoshinobu Inoue 			in6_ifloop_request(RTM_DELETE, ifa);
25482cd038dSYoshinobu Inoue 	}
25582cd038dSYoshinobu Inoue }
25682cd038dSYoshinobu Inoue 
25782cd038dSYoshinobu Inoue int
25882cd038dSYoshinobu Inoue in6_ifindex2scopeid(idx)
25982cd038dSYoshinobu Inoue 	int idx;
26082cd038dSYoshinobu Inoue {
26182cd038dSYoshinobu Inoue 	struct ifnet *ifp;
26282cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
26382cd038dSYoshinobu Inoue 	struct sockaddr_in6 *sin6;
26482cd038dSYoshinobu Inoue 
26582cd038dSYoshinobu Inoue 	if (idx < 0 || if_index < idx)
26682cd038dSYoshinobu Inoue 		return -1;
26782cd038dSYoshinobu Inoue 	ifp = ifindex2ifnet[idx];
26882cd038dSYoshinobu Inoue 
269cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
27082cd038dSYoshinobu Inoue 	{
27182cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
27282cd038dSYoshinobu Inoue 			continue;
27382cd038dSYoshinobu Inoue 		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
27482cd038dSYoshinobu Inoue 		if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
27582cd038dSYoshinobu Inoue 			return sin6->sin6_scope_id & 0xffff;
27682cd038dSYoshinobu Inoue 	}
27782cd038dSYoshinobu Inoue 
27882cd038dSYoshinobu Inoue 	return -1;
27982cd038dSYoshinobu Inoue }
28082cd038dSYoshinobu Inoue 
28182cd038dSYoshinobu Inoue int
28282cd038dSYoshinobu Inoue in6_mask2len(mask)
28382cd038dSYoshinobu Inoue 	struct in6_addr *mask;
28482cd038dSYoshinobu Inoue {
28582cd038dSYoshinobu Inoue 	int x, y;
28682cd038dSYoshinobu Inoue 
28782cd038dSYoshinobu Inoue 	for (x = 0; x < sizeof(*mask); x++) {
28882cd038dSYoshinobu Inoue 		if (mask->s6_addr8[x] != 0xff)
28982cd038dSYoshinobu Inoue 			break;
29082cd038dSYoshinobu Inoue 	}
29182cd038dSYoshinobu Inoue 	y = 0;
29282cd038dSYoshinobu Inoue 	if (x < sizeof(*mask)) {
29382cd038dSYoshinobu Inoue 		for (y = 0; y < 8; y++) {
29482cd038dSYoshinobu Inoue 			if ((mask->s6_addr8[x] & (0x80 >> y)) == 0)
29582cd038dSYoshinobu Inoue 				break;
29682cd038dSYoshinobu Inoue 		}
29782cd038dSYoshinobu Inoue 	}
29882cd038dSYoshinobu Inoue 	return x * 8 + y;
29982cd038dSYoshinobu Inoue }
30082cd038dSYoshinobu Inoue 
30182cd038dSYoshinobu Inoue void
30282cd038dSYoshinobu Inoue in6_len2mask(mask, len)
30382cd038dSYoshinobu Inoue 	struct in6_addr *mask;
30482cd038dSYoshinobu Inoue 	int len;
30582cd038dSYoshinobu Inoue {
30682cd038dSYoshinobu Inoue 	int i;
30782cd038dSYoshinobu Inoue 
30882cd038dSYoshinobu Inoue 	bzero(mask, sizeof(*mask));
30982cd038dSYoshinobu Inoue 	for (i = 0; i < len / 8; i++)
31082cd038dSYoshinobu Inoue 		mask->s6_addr8[i] = 0xff;
31182cd038dSYoshinobu Inoue 	if (len % 8)
31282cd038dSYoshinobu Inoue 		mask->s6_addr8[i] = (0xff00 >> (len % 8)) & 0xff;
31382cd038dSYoshinobu Inoue }
31482cd038dSYoshinobu Inoue 
31582cd038dSYoshinobu Inoue #define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
316686cdd19SJun-ichiro itojun Hagino #define ia62ifa(ia6)	(&((ia6)->ia_ifa))
31782cd038dSYoshinobu Inoue 
31882cd038dSYoshinobu Inoue int
31982cd038dSYoshinobu Inoue in6_control(so, cmd, data, ifp, p)
32082cd038dSYoshinobu Inoue 	struct	socket *so;
32182cd038dSYoshinobu Inoue 	u_long cmd;
32282cd038dSYoshinobu Inoue 	caddr_t	data;
32382cd038dSYoshinobu Inoue 	struct ifnet *ifp;
32482cd038dSYoshinobu Inoue 	struct proc *p;
32582cd038dSYoshinobu Inoue {
32682cd038dSYoshinobu Inoue 	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
327686cdd19SJun-ichiro itojun Hagino 	struct	in6_ifaddr *ia = NULL, *oia;
32882cd038dSYoshinobu Inoue 	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
329686cdd19SJun-ichiro itojun Hagino 	struct	sockaddr_in6 oldaddr;
330686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL
331686cdd19SJun-ichiro itojun Hagino 	struct	sockaddr_in6 net;
332686cdd19SJun-ichiro itojun Hagino #endif
33382cd038dSYoshinobu Inoue 	int error = 0, hostIsNew, prefixIsNew;
334686cdd19SJun-ichiro itojun Hagino 	int newifaddr;
33582cd038dSYoshinobu Inoue 	int privileged;
33682cd038dSYoshinobu Inoue 
33782cd038dSYoshinobu Inoue 	privileged = 0;
3389d786e66SYoshinobu Inoue 	if (p == NULL || !suser(p))
33982cd038dSYoshinobu Inoue 		privileged++;
34082cd038dSYoshinobu Inoue 
34182cd038dSYoshinobu Inoue 	/*
34282cd038dSYoshinobu Inoue 	 * xxx should prevent processes for link-local addresses?
34382cd038dSYoshinobu Inoue 	 */
34482cd038dSYoshinobu Inoue #if NGIF > 0
34582cd038dSYoshinobu Inoue 	if (ifp && ifp->if_type == IFT_GIF) {
34682cd038dSYoshinobu Inoue 		switch (cmd) {
34782cd038dSYoshinobu Inoue 		case SIOCSIFPHYADDR_IN6:
34882cd038dSYoshinobu Inoue 			if (!privileged)
34982cd038dSYoshinobu Inoue 				return(EPERM);
35082cd038dSYoshinobu Inoue 			/*fall through*/
35182cd038dSYoshinobu Inoue 		case SIOCGIFPSRCADDR_IN6:
35282cd038dSYoshinobu Inoue 		case SIOCGIFPDSTADDR_IN6:
35382cd038dSYoshinobu Inoue 			return gif_ioctl(ifp, cmd, data);
35482cd038dSYoshinobu Inoue 		}
35582cd038dSYoshinobu Inoue 	}
35682cd038dSYoshinobu Inoue #endif
357686cdd19SJun-ichiro itojun Hagino 	switch (cmd) {
358686cdd19SJun-ichiro itojun Hagino 	case SIOCGETSGCNT_IN6:
359686cdd19SJun-ichiro itojun Hagino 	case SIOCGETMIFCNT_IN6:
360686cdd19SJun-ichiro itojun Hagino 		return (mrt6_ioctl(cmd, data));
361686cdd19SJun-ichiro itojun Hagino 	}
36282cd038dSYoshinobu Inoue 
363686cdd19SJun-ichiro itojun Hagino 	if (ifp == NULL)
36482cd038dSYoshinobu Inoue 		return(EOPNOTSUPP);
36582cd038dSYoshinobu Inoue 
36682cd038dSYoshinobu Inoue 	switch (cmd) {
36782cd038dSYoshinobu Inoue 	case SIOCSNDFLUSH_IN6:
36882cd038dSYoshinobu Inoue 	case SIOCSPFXFLUSH_IN6:
36982cd038dSYoshinobu Inoue 	case SIOCSRTRFLUSH_IN6:
370686cdd19SJun-ichiro itojun Hagino 	case SIOCSDEFIFACE_IN6:
371686cdd19SJun-ichiro itojun Hagino 	case SIOCSIFINFO_FLAGS:
37282cd038dSYoshinobu Inoue 		if (!privileged)
37382cd038dSYoshinobu Inoue 			return(EPERM);
37482cd038dSYoshinobu Inoue 		/*fall through*/
37582cd038dSYoshinobu Inoue 	case SIOCGIFINFO_IN6:
37682cd038dSYoshinobu Inoue 	case SIOCGDRLST_IN6:
37782cd038dSYoshinobu Inoue 	case SIOCGPRLST_IN6:
37882cd038dSYoshinobu Inoue 	case SIOCGNBRINFO_IN6:
379686cdd19SJun-ichiro itojun Hagino 	case SIOCGDEFIFACE_IN6:
38082cd038dSYoshinobu Inoue 		return(nd6_ioctl(cmd, data, ifp));
38182cd038dSYoshinobu Inoue 	}
38282cd038dSYoshinobu Inoue 
38382cd038dSYoshinobu Inoue 	switch (cmd) {
38482cd038dSYoshinobu Inoue 	case SIOCSIFPREFIX_IN6:
38582cd038dSYoshinobu Inoue 	case SIOCDIFPREFIX_IN6:
38682cd038dSYoshinobu Inoue 	case SIOCAIFPREFIX_IN6:
38782cd038dSYoshinobu Inoue 	case SIOCCIFPREFIX_IN6:
38882cd038dSYoshinobu Inoue 	case SIOCSGIFPREFIX_IN6:
38982cd038dSYoshinobu Inoue 		if (!privileged)
39082cd038dSYoshinobu Inoue 			return(EPERM);
39182cd038dSYoshinobu Inoue 		/*fall through*/
39282cd038dSYoshinobu Inoue 	case SIOCGIFPREFIX_IN6:
3939c275a58SYoshinobu Inoue 		if (ip6_forwarding == 0)
3949c275a58SYoshinobu Inoue 			return(EPERM);
39582cd038dSYoshinobu Inoue 		return(in6_prefix_ioctl(so, cmd, data, ifp));
39682cd038dSYoshinobu Inoue 	}
39782cd038dSYoshinobu Inoue 
39882cd038dSYoshinobu Inoue 	switch(cmd) {
399686cdd19SJun-ichiro itojun Hagino 	case SIOCSSCOPE6:
400686cdd19SJun-ichiro itojun Hagino 		if (!privileged)
401686cdd19SJun-ichiro itojun Hagino 			return(EPERM);
402686cdd19SJun-ichiro itojun Hagino 		return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id));
403686cdd19SJun-ichiro itojun Hagino 		break;
404686cdd19SJun-ichiro itojun Hagino 	case SIOCGSCOPE6:
405686cdd19SJun-ichiro itojun Hagino 		return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id));
406686cdd19SJun-ichiro itojun Hagino 		break;
407686cdd19SJun-ichiro itojun Hagino 	case SIOCGSCOPE6DEF:
408686cdd19SJun-ichiro itojun Hagino 		return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id));
409686cdd19SJun-ichiro itojun Hagino 		break;
410686cdd19SJun-ichiro itojun Hagino 	}
411686cdd19SJun-ichiro itojun Hagino 
412686cdd19SJun-ichiro itojun Hagino 	switch (cmd) {
41382cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
41482cd038dSYoshinobu Inoue 	case SIOCDLIFADDR:
41582cd038dSYoshinobu Inoue 		if (!privileged)
41682cd038dSYoshinobu Inoue 			return(EPERM);
41782cd038dSYoshinobu Inoue 		/*fall through*/
41882cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
41982cd038dSYoshinobu Inoue 		return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
42082cd038dSYoshinobu Inoue 	}
42182cd038dSYoshinobu Inoue 
42282cd038dSYoshinobu Inoue 	/*
42382cd038dSYoshinobu Inoue 	 * Find address for this interface, if it exists.
42482cd038dSYoshinobu Inoue 	 */
425686cdd19SJun-ichiro itojun Hagino 	if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */
42682cd038dSYoshinobu Inoue 		struct sockaddr_in6 *sa6 =
42782cd038dSYoshinobu Inoue 			(struct sockaddr_in6 *)&ifra->ifra_addr;
42882cd038dSYoshinobu Inoue 
42982cd038dSYoshinobu Inoue 		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
43082cd038dSYoshinobu Inoue 			if (sa6->sin6_addr.s6_addr16[1] == 0) {
43182cd038dSYoshinobu Inoue 				/* interface ID is not embedded by the user */
43282cd038dSYoshinobu Inoue 				sa6->sin6_addr.s6_addr16[1] =
43382cd038dSYoshinobu Inoue 					htons(ifp->if_index);
434686cdd19SJun-ichiro itojun Hagino 			} else if (sa6->sin6_addr.s6_addr16[1] !=
435686cdd19SJun-ichiro itojun Hagino 				    htons(ifp->if_index)) {
43682cd038dSYoshinobu Inoue 				return(EINVAL);	/* ifid is contradict */
437686cdd19SJun-ichiro itojun Hagino 			}
43882cd038dSYoshinobu Inoue 			if (sa6->sin6_scope_id) {
43982cd038dSYoshinobu Inoue 				if (sa6->sin6_scope_id !=
44082cd038dSYoshinobu Inoue 				    (u_int32_t)ifp->if_index)
44182cd038dSYoshinobu Inoue 					return(EINVAL);
44282cd038dSYoshinobu Inoue 				sa6->sin6_scope_id = 0; /* XXX: good way? */
44382cd038dSYoshinobu Inoue 			}
44482cd038dSYoshinobu Inoue 		}
44582cd038dSYoshinobu Inoue 		ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
446686cdd19SJun-ichiro itojun Hagino 	}
44782cd038dSYoshinobu Inoue 
44882cd038dSYoshinobu Inoue 	switch (cmd) {
44982cd038dSYoshinobu Inoue 
45082cd038dSYoshinobu Inoue 	case SIOCDIFADDR_IN6:
451686cdd19SJun-ichiro itojun Hagino 		/*
452686cdd19SJun-ichiro itojun Hagino 		 * for IPv4, we look for existing in6_ifaddr here to allow
453686cdd19SJun-ichiro itojun Hagino 		 * "ifconfig if0 delete" to remove first IPv4 address on the
454686cdd19SJun-ichiro itojun Hagino 		 * interface.  For IPv6, as the spec allow multiple interface
455686cdd19SJun-ichiro itojun Hagino 		 * address from the day one, we consider "remove the first one"
456686cdd19SJun-ichiro itojun Hagino 		 * semantics to be not preferrable.
457686cdd19SJun-ichiro itojun Hagino 		 */
458686cdd19SJun-ichiro itojun Hagino 		if (ia == NULL)
45982cd038dSYoshinobu Inoue 			return(EADDRNOTAVAIL);
46082cd038dSYoshinobu Inoue 		/* FALLTHROUGH */
46182cd038dSYoshinobu Inoue 	case SIOCAIFADDR_IN6:
46282cd038dSYoshinobu Inoue 	case SIOCSIFADDR_IN6:
463686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL
46482cd038dSYoshinobu Inoue 	case SIOCSIFDSTADDR_IN6:
465686cdd19SJun-ichiro itojun Hagino 	case SIOCSIFNETMASK_IN6:
466686cdd19SJun-ichiro itojun Hagino 		/*
467686cdd19SJun-ichiro itojun Hagino 		 * Since IPv6 allows a node to assign multiple addresses
468686cdd19SJun-ichiro itojun Hagino 		 * on a single interface, SIOCSIFxxx ioctls are not suitable
469686cdd19SJun-ichiro itojun Hagino 		 * and should be unused.
470686cdd19SJun-ichiro itojun Hagino 		 */
471686cdd19SJun-ichiro itojun Hagino #endif
472686cdd19SJun-ichiro itojun Hagino 		if (ifra->ifra_addr.sin6_family != AF_INET6)
473686cdd19SJun-ichiro itojun Hagino 			return(EAFNOSUPPORT);
47482cd038dSYoshinobu Inoue 		if (!privileged)
47582cd038dSYoshinobu Inoue 			return(EPERM);
476686cdd19SJun-ichiro itojun Hagino 		if (ia == NULL) {
47782cd038dSYoshinobu Inoue 			ia = (struct in6_ifaddr *)
47882cd038dSYoshinobu Inoue 				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
47982cd038dSYoshinobu Inoue 			if (ia == NULL)
48082cd038dSYoshinobu Inoue 				return (ENOBUFS);
48182cd038dSYoshinobu Inoue 			bzero((caddr_t)ia, sizeof(*ia));
482686cdd19SJun-ichiro itojun Hagino 			/* Initialize the address and masks */
48382cd038dSYoshinobu Inoue 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
484686cdd19SJun-ichiro itojun Hagino 			ia->ia_addr.sin6_family = AF_INET6;
485686cdd19SJun-ichiro itojun Hagino 			ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
486686cdd19SJun-ichiro itojun Hagino #if 1
487686cdd19SJun-ichiro itojun Hagino 			if (ifp->if_flags & IFF_POINTOPOINT) {
48882cd038dSYoshinobu Inoue 				ia->ia_ifa.ifa_dstaddr
48982cd038dSYoshinobu Inoue 					= (struct sockaddr *)&ia->ia_dstaddr;
490686cdd19SJun-ichiro itojun Hagino 				ia->ia_dstaddr.sin6_family = AF_INET6;
491686cdd19SJun-ichiro itojun Hagino 				ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr);
492686cdd19SJun-ichiro itojun Hagino 			} else {
493686cdd19SJun-ichiro itojun Hagino 				ia->ia_ifa.ifa_dstaddr = NULL;
494686cdd19SJun-ichiro itojun Hagino 				bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
495686cdd19SJun-ichiro itojun Hagino 			}
496686cdd19SJun-ichiro itojun Hagino #else  /* always initilize by NULL */
497686cdd19SJun-ichiro itojun Hagino 			ia->ia_ifa.ifa_dstaddr = NULL;
498686cdd19SJun-ichiro itojun Hagino 			bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
499686cdd19SJun-ichiro itojun Hagino #endif
50082cd038dSYoshinobu Inoue 			ia->ia_ifa.ifa_netmask
50182cd038dSYoshinobu Inoue 				= (struct sockaddr *)&ia->ia_prefixmask;
50282cd038dSYoshinobu Inoue 
50382cd038dSYoshinobu Inoue 			ia->ia_ifp = ifp;
50482cd038dSYoshinobu Inoue 			if ((oia = in6_ifaddr) != NULL) {
50582cd038dSYoshinobu Inoue 				for ( ; oia->ia_next; oia = oia->ia_next)
50682cd038dSYoshinobu Inoue 					continue;
50782cd038dSYoshinobu Inoue 				oia->ia_next = ia;
50882cd038dSYoshinobu Inoue 			} else
50982cd038dSYoshinobu Inoue 				in6_ifaddr = ia;
510686cdd19SJun-ichiro itojun Hagino 			/* gain a refcnt for the link from in6_ifaddr */
511686cdd19SJun-ichiro itojun Hagino 			ia->ia_ifa.ifa_refcnt++;
512686cdd19SJun-ichiro itojun Hagino 
513686cdd19SJun-ichiro itojun Hagino 			TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
514686cdd19SJun-ichiro itojun Hagino 			    ifa_list);
515686cdd19SJun-ichiro itojun Hagino 			/* gain another refcnt for the link from if_addrlist */
516686cdd19SJun-ichiro itojun Hagino 			ia->ia_ifa.ifa_refcnt++;
517686cdd19SJun-ichiro itojun Hagino 
518686cdd19SJun-ichiro itojun Hagino 			newifaddr = 1;
519686cdd19SJun-ichiro itojun Hagino 		} else
520686cdd19SJun-ichiro itojun Hagino 			newifaddr = 0;
52182cd038dSYoshinobu Inoue 
52282cd038dSYoshinobu Inoue 		if (cmd == SIOCAIFADDR_IN6) {
52382cd038dSYoshinobu Inoue 			/* sanity for overflow - beware unsigned */
52482cd038dSYoshinobu Inoue 			struct in6_addrlifetime *lt;
52582cd038dSYoshinobu Inoue 			lt = &ifra->ifra_lifetime;
52682cd038dSYoshinobu Inoue 			if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
52782cd038dSYoshinobu Inoue 			 && lt->ia6t_vltime + time_second < time_second) {
52882cd038dSYoshinobu Inoue 				return EINVAL;
52982cd038dSYoshinobu Inoue 			}
53082cd038dSYoshinobu Inoue 			if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
53182cd038dSYoshinobu Inoue 			 && lt->ia6t_pltime + time_second < time_second) {
53282cd038dSYoshinobu Inoue 				return EINVAL;
53382cd038dSYoshinobu Inoue 			}
53482cd038dSYoshinobu Inoue 		}
53582cd038dSYoshinobu Inoue 		break;
53682cd038dSYoshinobu Inoue 
53782cd038dSYoshinobu Inoue 	case SIOCGIFADDR_IN6:
53882cd038dSYoshinobu Inoue 		/* This interface is basically deprecated. use SIOCGIFCONF. */
53982cd038dSYoshinobu Inoue 		/* fall through */
54082cd038dSYoshinobu Inoue 	case SIOCGIFAFLAG_IN6:
54182cd038dSYoshinobu Inoue 	case SIOCGIFNETMASK_IN6:
54282cd038dSYoshinobu Inoue 	case SIOCGIFDSTADDR_IN6:
54382cd038dSYoshinobu Inoue 	case SIOCGIFALIFETIME_IN6:
54482cd038dSYoshinobu Inoue 		/* must think again about its semantics */
545686cdd19SJun-ichiro itojun Hagino 		if (ia == NULL)
54682cd038dSYoshinobu Inoue 			return(EADDRNOTAVAIL);
54782cd038dSYoshinobu Inoue 		break;
54882cd038dSYoshinobu Inoue 	case SIOCSIFALIFETIME_IN6:
54982cd038dSYoshinobu Inoue 	    {
55082cd038dSYoshinobu Inoue 		struct in6_addrlifetime *lt;
55182cd038dSYoshinobu Inoue 
55282cd038dSYoshinobu Inoue 		if (!privileged)
55382cd038dSYoshinobu Inoue 			return(EPERM);
554686cdd19SJun-ichiro itojun Hagino 		if (ia == NULL)
55582cd038dSYoshinobu Inoue 			return(EADDRNOTAVAIL);
55682cd038dSYoshinobu Inoue 		/* sanity for overflow - beware unsigned */
55782cd038dSYoshinobu Inoue 		lt = &ifr->ifr_ifru.ifru_lifetime;
55882cd038dSYoshinobu Inoue 		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
55982cd038dSYoshinobu Inoue 		 && lt->ia6t_vltime + time_second < time_second) {
56082cd038dSYoshinobu Inoue 			return EINVAL;
56182cd038dSYoshinobu Inoue 		}
56282cd038dSYoshinobu Inoue 		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
56382cd038dSYoshinobu Inoue 		 && lt->ia6t_pltime + time_second < time_second) {
56482cd038dSYoshinobu Inoue 			return EINVAL;
56582cd038dSYoshinobu Inoue 		}
56682cd038dSYoshinobu Inoue 		break;
56782cd038dSYoshinobu Inoue 	    }
56882cd038dSYoshinobu Inoue 	}
56982cd038dSYoshinobu Inoue 
57082cd038dSYoshinobu Inoue 	switch (cmd) {
57182cd038dSYoshinobu Inoue 
57282cd038dSYoshinobu Inoue 	case SIOCGIFADDR_IN6:
57382cd038dSYoshinobu Inoue 		ifr->ifr_addr = ia->ia_addr;
57482cd038dSYoshinobu Inoue 		break;
57582cd038dSYoshinobu Inoue 
57682cd038dSYoshinobu Inoue 	case SIOCGIFDSTADDR_IN6:
57782cd038dSYoshinobu Inoue 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
57882cd038dSYoshinobu Inoue 			return(EINVAL);
579686cdd19SJun-ichiro itojun Hagino 		/*
580686cdd19SJun-ichiro itojun Hagino 		 * XXX: should we check if ifa_dstaddr is NULL and return
581686cdd19SJun-ichiro itojun Hagino 		 * an error?
582686cdd19SJun-ichiro itojun Hagino 		 */
58382cd038dSYoshinobu Inoue 		ifr->ifr_dstaddr = ia->ia_dstaddr;
58482cd038dSYoshinobu Inoue 		break;
58582cd038dSYoshinobu Inoue 
58682cd038dSYoshinobu Inoue 	case SIOCGIFNETMASK_IN6:
58782cd038dSYoshinobu Inoue 		ifr->ifr_addr = ia->ia_prefixmask;
58882cd038dSYoshinobu Inoue 		break;
58982cd038dSYoshinobu Inoue 
59082cd038dSYoshinobu Inoue 	case SIOCGIFAFLAG_IN6:
59182cd038dSYoshinobu Inoue 		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
59282cd038dSYoshinobu Inoue 		break;
59382cd038dSYoshinobu Inoue 
59482cd038dSYoshinobu Inoue 	case SIOCGIFSTAT_IN6:
59582cd038dSYoshinobu Inoue 		if (ifp == NULL)
59682cd038dSYoshinobu Inoue 			return EINVAL;
59782cd038dSYoshinobu Inoue 		if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax
59882cd038dSYoshinobu Inoue 		 || in6_ifstat[ifp->if_index] == NULL) {
59982cd038dSYoshinobu Inoue 			/* return EAFNOSUPPORT? */
60082cd038dSYoshinobu Inoue 			bzero(&ifr->ifr_ifru.ifru_stat,
60182cd038dSYoshinobu Inoue 				sizeof(ifr->ifr_ifru.ifru_stat));
60282cd038dSYoshinobu Inoue 		} else
60382cd038dSYoshinobu Inoue 			ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];
60482cd038dSYoshinobu Inoue 		break;
60582cd038dSYoshinobu Inoue 
60682cd038dSYoshinobu Inoue 	case SIOCGIFSTAT_ICMP6:
60782cd038dSYoshinobu Inoue 		if (ifp == NULL)
60882cd038dSYoshinobu Inoue 			return EINVAL;
60982cd038dSYoshinobu Inoue 		if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||
61082cd038dSYoshinobu Inoue 		    icmp6_ifstat[ifp->if_index] == NULL) {
61182cd038dSYoshinobu Inoue 			/* return EAFNOSUPPORT? */
61282cd038dSYoshinobu Inoue 			bzero(&ifr->ifr_ifru.ifru_stat,
61382cd038dSYoshinobu Inoue 				sizeof(ifr->ifr_ifru.ifru_icmp6stat));
61482cd038dSYoshinobu Inoue 		} else
61582cd038dSYoshinobu Inoue 			ifr->ifr_ifru.ifru_icmp6stat =
61682cd038dSYoshinobu Inoue 				*icmp6_ifstat[ifp->if_index];
61782cd038dSYoshinobu Inoue 		break;
61882cd038dSYoshinobu Inoue 
619686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL		/* should be unused */
62082cd038dSYoshinobu Inoue 	case SIOCSIFDSTADDR_IN6:
62182cd038dSYoshinobu Inoue 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
62282cd038dSYoshinobu Inoue 			return(EINVAL);
62382cd038dSYoshinobu Inoue 		oldaddr = ia->ia_dstaddr;
62482cd038dSYoshinobu Inoue 		ia->ia_dstaddr = ifr->ifr_dstaddr;
62582cd038dSYoshinobu Inoue 
62682cd038dSYoshinobu Inoue 		/* link-local index check */
62782cd038dSYoshinobu Inoue 		if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
62882cd038dSYoshinobu Inoue 			if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
62982cd038dSYoshinobu Inoue 				/* interface ID is not embedded by the user */
63082cd038dSYoshinobu Inoue 				ia->ia_dstaddr.sin6_addr.s6_addr16[1]
63182cd038dSYoshinobu Inoue 					= htons(ifp->if_index);
632686cdd19SJun-ichiro itojun Hagino 			} else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
63382cd038dSYoshinobu Inoue 				    htons(ifp->if_index)) {
63482cd038dSYoshinobu Inoue 				ia->ia_dstaddr = oldaddr;
63582cd038dSYoshinobu Inoue 				return(EINVAL);	/* ifid is contradict */
63682cd038dSYoshinobu Inoue 			}
63782cd038dSYoshinobu Inoue 		}
63882cd038dSYoshinobu Inoue 
63982cd038dSYoshinobu Inoue 		if (ifp->if_ioctl && (error = (ifp->if_ioctl)
64082cd038dSYoshinobu Inoue 				      (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
64182cd038dSYoshinobu Inoue 			ia->ia_dstaddr = oldaddr;
64282cd038dSYoshinobu Inoue 			return(error);
64382cd038dSYoshinobu Inoue 		}
644686cdd19SJun-ichiro itojun Hagino 		ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
64582cd038dSYoshinobu Inoue 		if (ia->ia_flags & IFA_ROUTE) {
64682cd038dSYoshinobu Inoue 			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
64782cd038dSYoshinobu Inoue 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
64882cd038dSYoshinobu Inoue 			ia->ia_ifa.ifa_dstaddr =
64982cd038dSYoshinobu Inoue 				(struct sockaddr *)&ia->ia_dstaddr;
65082cd038dSYoshinobu Inoue 			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
65182cd038dSYoshinobu Inoue 		}
65282cd038dSYoshinobu Inoue 		break;
65382cd038dSYoshinobu Inoue 
654686cdd19SJun-ichiro itojun Hagino #endif
65582cd038dSYoshinobu Inoue 	case SIOCGIFALIFETIME_IN6:
65682cd038dSYoshinobu Inoue 		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
65782cd038dSYoshinobu Inoue 		break;
65882cd038dSYoshinobu Inoue 
65982cd038dSYoshinobu Inoue 	case SIOCSIFALIFETIME_IN6:
66082cd038dSYoshinobu Inoue 		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
66182cd038dSYoshinobu Inoue 		/* for sanity */
66282cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
66382cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire =
66482cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_vltime;
66582cd038dSYoshinobu Inoue 		} else
66682cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire = 0;
66782cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
66882cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred =
66982cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_pltime;
67082cd038dSYoshinobu Inoue 		} else
67182cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred = 0;
67282cd038dSYoshinobu Inoue 		break;
67382cd038dSYoshinobu Inoue 
67482cd038dSYoshinobu Inoue 	case SIOCSIFADDR_IN6:
675686cdd19SJun-ichiro itojun Hagino 		error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1);
676686cdd19SJun-ichiro itojun Hagino #if 0
677686cdd19SJun-ichiro itojun Hagino 		/*
678686cdd19SJun-ichiro itojun Hagino 		 * the code chokes if we are to assign multiple addresses with
679686cdd19SJun-ichiro itojun Hagino 		 * the same address prefix (rtinit() will return EEXIST, which
680686cdd19SJun-ichiro itojun Hagino 		 * is not fatal actually).  we will get memory leak if we
681686cdd19SJun-ichiro itojun Hagino 		 * don't do it.
682686cdd19SJun-ichiro itojun Hagino 		 * -> we may want to hide EEXIST from rtinit().
683686cdd19SJun-ichiro itojun Hagino 		 */
684686cdd19SJun-ichiro itojun Hagino   undo:
685686cdd19SJun-ichiro itojun Hagino 		if (error && newifaddr) {
686686cdd19SJun-ichiro itojun Hagino 			TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
687686cdd19SJun-ichiro itojun Hagino 			/* release a refcnt for the link from if_addrlist */
688686cdd19SJun-ichiro itojun Hagino 			IFAFREE(&ia->ia_ifa);
68982cd038dSYoshinobu Inoue 
690686cdd19SJun-ichiro itojun Hagino 			oia = ia;
691686cdd19SJun-ichiro itojun Hagino 			if (oia == (ia = in6_ifaddr))
692686cdd19SJun-ichiro itojun Hagino 				in6_ifaddr = ia->ia_next;
693686cdd19SJun-ichiro itojun Hagino 			else {
694686cdd19SJun-ichiro itojun Hagino 				while (ia->ia_next && (ia->ia_next != oia))
695686cdd19SJun-ichiro itojun Hagino 					ia = ia->ia_next;
696686cdd19SJun-ichiro itojun Hagino 				if (ia->ia_next)
697686cdd19SJun-ichiro itojun Hagino 					ia->ia_next = oia->ia_next;
698686cdd19SJun-ichiro itojun Hagino 				else {
699686cdd19SJun-ichiro itojun Hagino 					printf("Didn't unlink in6_ifaddr "
700686cdd19SJun-ichiro itojun Hagino 					    "from list\n");
701686cdd19SJun-ichiro itojun Hagino 				}
702686cdd19SJun-ichiro itojun Hagino 			}
703686cdd19SJun-ichiro itojun Hagino 			/* release another refcnt for the link from in6_ifaddr */
704686cdd19SJun-ichiro itojun Hagino 			IFAFREE(&oia->ia_ifa);
705686cdd19SJun-ichiro itojun Hagino 		}
706686cdd19SJun-ichiro itojun Hagino #endif
707686cdd19SJun-ichiro itojun Hagino 		return error;
708686cdd19SJun-ichiro itojun Hagino 
709686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL		/* XXX should be unused */
71082cd038dSYoshinobu Inoue 	case SIOCSIFNETMASK_IN6:
71182cd038dSYoshinobu Inoue 		ia->ia_prefixmask = ifr->ifr_addr;
71282cd038dSYoshinobu Inoue 		bzero(&net, sizeof(net));
71382cd038dSYoshinobu Inoue 		net.sin6_len = sizeof(struct sockaddr_in6);
71482cd038dSYoshinobu Inoue 		net.sin6_family = AF_INET6;
71582cd038dSYoshinobu Inoue 		net.sin6_port = htons(0);
71682cd038dSYoshinobu Inoue 		net.sin6_flowinfo = htonl(0);
71782cd038dSYoshinobu Inoue 		net.sin6_addr.s6_addr32[0]
71882cd038dSYoshinobu Inoue 			= ia->ia_addr.sin6_addr.s6_addr32[0] &
71982cd038dSYoshinobu Inoue 				ia->ia_prefixmask.sin6_addr.s6_addr32[0];
72082cd038dSYoshinobu Inoue 		net.sin6_addr.s6_addr32[1]
72182cd038dSYoshinobu Inoue 			= ia->ia_addr.sin6_addr.s6_addr32[1] &
72282cd038dSYoshinobu Inoue 				ia->ia_prefixmask.sin6_addr.s6_addr32[1];
72382cd038dSYoshinobu Inoue 		net.sin6_addr.s6_addr32[2]
72482cd038dSYoshinobu Inoue 			= ia->ia_addr.sin6_addr.s6_addr32[2] &
72582cd038dSYoshinobu Inoue 				ia->ia_prefixmask.sin6_addr.s6_addr32[2];
72682cd038dSYoshinobu Inoue 		net.sin6_addr.s6_addr32[3]
72782cd038dSYoshinobu Inoue 			= ia->ia_addr.sin6_addr.s6_addr32[3] &
72882cd038dSYoshinobu Inoue 				ia->ia_prefixmask.sin6_addr.s6_addr32[3];
72982cd038dSYoshinobu Inoue 		ia->ia_net = net;
73082cd038dSYoshinobu Inoue 		break;
731686cdd19SJun-ichiro itojun Hagino #endif
73282cd038dSYoshinobu Inoue 
73382cd038dSYoshinobu Inoue 	case SIOCAIFADDR_IN6:
73482cd038dSYoshinobu Inoue 		prefixIsNew = 0;
73582cd038dSYoshinobu Inoue 		hostIsNew = 1;
73682cd038dSYoshinobu Inoue 
73782cd038dSYoshinobu Inoue 		if (ifra->ifra_addr.sin6_len == 0) {
73882cd038dSYoshinobu Inoue 			ifra->ifra_addr = ia->ia_addr;
73982cd038dSYoshinobu Inoue 			hostIsNew = 0;
74082cd038dSYoshinobu Inoue 		} else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr,
74182cd038dSYoshinobu Inoue 					      &ia->ia_addr.sin6_addr))
74282cd038dSYoshinobu Inoue 			hostIsNew = 0;
74382cd038dSYoshinobu Inoue 
744686cdd19SJun-ichiro itojun Hagino 		/* Validate address families: */
745686cdd19SJun-ichiro itojun Hagino 		/*
746686cdd19SJun-ichiro itojun Hagino 		 * The destination address for a p2p link must have a family
747686cdd19SJun-ichiro itojun Hagino 		 * of AF_UNSPEC or AF_INET6.
748686cdd19SJun-ichiro itojun Hagino 		 */
749686cdd19SJun-ichiro itojun Hagino 		if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
750686cdd19SJun-ichiro itojun Hagino 		    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
751686cdd19SJun-ichiro itojun Hagino 		    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
752686cdd19SJun-ichiro itojun Hagino 			return(EAFNOSUPPORT);
753686cdd19SJun-ichiro itojun Hagino 		/*
754686cdd19SJun-ichiro itojun Hagino 		 * The prefixmask must have a family of AF_UNSPEC or AF_INET6.
755686cdd19SJun-ichiro itojun Hagino 		 */
756686cdd19SJun-ichiro itojun Hagino 		if (ifra->ifra_prefixmask.sin6_family != AF_INET6 &&
757686cdd19SJun-ichiro itojun Hagino 		    ifra->ifra_prefixmask.sin6_family != AF_UNSPEC)
758686cdd19SJun-ichiro itojun Hagino 			return(EAFNOSUPPORT);
759686cdd19SJun-ichiro itojun Hagino 
76082cd038dSYoshinobu Inoue 		if (ifra->ifra_prefixmask.sin6_len) {
76182cd038dSYoshinobu Inoue 			in6_ifscrub(ifp, ia);
76282cd038dSYoshinobu Inoue 			ia->ia_prefixmask = ifra->ifra_prefixmask;
76382cd038dSYoshinobu Inoue 			prefixIsNew = 1;
76482cd038dSYoshinobu Inoue 		}
76582cd038dSYoshinobu Inoue 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
76682cd038dSYoshinobu Inoue 		    (ifra->ifra_dstaddr.sin6_family == AF_INET6)) {
76782cd038dSYoshinobu Inoue 			in6_ifscrub(ifp, ia);
768686cdd19SJun-ichiro itojun Hagino 			oldaddr = ia->ia_dstaddr;
76982cd038dSYoshinobu Inoue 			ia->ia_dstaddr = ifra->ifra_dstaddr;
77082cd038dSYoshinobu Inoue 			/* link-local index check: should be a separate function? */
77182cd038dSYoshinobu Inoue 			if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
77282cd038dSYoshinobu Inoue 				if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
77382cd038dSYoshinobu Inoue 					/*
77482cd038dSYoshinobu Inoue 					 * interface ID is not embedded by
77582cd038dSYoshinobu Inoue 					 * the user
77682cd038dSYoshinobu Inoue 					 */
77782cd038dSYoshinobu Inoue 					ia->ia_dstaddr.sin6_addr.s6_addr16[1]
77882cd038dSYoshinobu Inoue 						= htons(ifp->if_index);
779686cdd19SJun-ichiro itojun Hagino 				} else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
78082cd038dSYoshinobu Inoue 					    htons(ifp->if_index)) {
78182cd038dSYoshinobu Inoue 					ia->ia_dstaddr = oldaddr;
78282cd038dSYoshinobu Inoue 					return(EINVAL);	/* ifid is contradict */
78382cd038dSYoshinobu Inoue 				}
78482cd038dSYoshinobu Inoue 			}
78582cd038dSYoshinobu Inoue 			prefixIsNew = 1; /* We lie; but effect's the same */
78682cd038dSYoshinobu Inoue 		}
787686cdd19SJun-ichiro itojun Hagino 		if (hostIsNew || prefixIsNew) {
78882cd038dSYoshinobu Inoue 			error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
789686cdd19SJun-ichiro itojun Hagino #if 0
790686cdd19SJun-ichiro itojun Hagino 			if (error)
791686cdd19SJun-ichiro itojun Hagino 				goto undo;
792686cdd19SJun-ichiro itojun Hagino #endif
793686cdd19SJun-ichiro itojun Hagino 		}
794686cdd19SJun-ichiro itojun Hagino 		if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
79582cd038dSYoshinobu Inoue 			int error_local = 0;
79682cd038dSYoshinobu Inoue 
79782cd038dSYoshinobu Inoue 			/*
79882cd038dSYoshinobu Inoue 			 * join solicited multicast addr for new host id
79982cd038dSYoshinobu Inoue 			 */
80082cd038dSYoshinobu Inoue 			struct in6_addr llsol;
80182cd038dSYoshinobu Inoue 			bzero(&llsol, sizeof(struct in6_addr));
80282cd038dSYoshinobu Inoue 			llsol.s6_addr16[0] = htons(0xff02);
80382cd038dSYoshinobu Inoue 			llsol.s6_addr16[1] = htons(ifp->if_index);
80482cd038dSYoshinobu Inoue 			llsol.s6_addr32[1] = 0;
80582cd038dSYoshinobu Inoue 			llsol.s6_addr32[2] = htonl(1);
80682cd038dSYoshinobu Inoue 			llsol.s6_addr32[3] =
80782cd038dSYoshinobu Inoue 				ifra->ifra_addr.sin6_addr.s6_addr32[3];
80882cd038dSYoshinobu Inoue 			llsol.s6_addr8[12] = 0xff;
80982cd038dSYoshinobu Inoue 			(void)in6_addmulti(&llsol, ifp, &error_local);
81082cd038dSYoshinobu Inoue 			if (error == 0)
81182cd038dSYoshinobu Inoue 				error = error_local;
81282cd038dSYoshinobu Inoue 		}
81382cd038dSYoshinobu Inoue 
81482cd038dSYoshinobu Inoue 		ia->ia6_flags = ifra->ifra_flags;
81582cd038dSYoshinobu Inoue 		ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/*safety*/
81682cd038dSYoshinobu Inoue 
81782cd038dSYoshinobu Inoue 		ia->ia6_lifetime = ifra->ifra_lifetime;
81882cd038dSYoshinobu Inoue 		/* for sanity */
81982cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
82082cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire =
82182cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_vltime;
82282cd038dSYoshinobu Inoue 		} else
82382cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_expire = 0;
82482cd038dSYoshinobu Inoue 		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
82582cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred =
82682cd038dSYoshinobu Inoue 				time_second + ia->ia6_lifetime.ia6t_pltime;
82782cd038dSYoshinobu Inoue 		} else
82882cd038dSYoshinobu Inoue 			ia->ia6_lifetime.ia6t_preferred = 0;
82982cd038dSYoshinobu Inoue 
83082cd038dSYoshinobu Inoue 		/*
83182cd038dSYoshinobu Inoue 		 * Perform DAD, if needed.
83282cd038dSYoshinobu Inoue 		 * XXX It may be of use, if we can administratively
83382cd038dSYoshinobu Inoue 		 * disable DAD.
83482cd038dSYoshinobu Inoue 		 */
83582cd038dSYoshinobu Inoue 		switch (ifp->if_type) {
83682cd038dSYoshinobu Inoue 		case IFT_ARCNET:
83782cd038dSYoshinobu Inoue 		case IFT_ETHER:
83882cd038dSYoshinobu Inoue 		case IFT_FDDI:
839686cdd19SJun-ichiro itojun Hagino #if 0
840686cdd19SJun-ichiro itojun Hagino 		case IFT_ATM:
841686cdd19SJun-ichiro itojun Hagino 		case IFT_SLIP:
842686cdd19SJun-ichiro itojun Hagino 		case IFT_PPP:
843686cdd19SJun-ichiro itojun Hagino #endif
844686cdd19SJun-ichiro itojun Hagino 			{
84582cd038dSYoshinobu Inoue 				ia->ia6_flags |= IN6_IFF_TENTATIVE;
84682cd038dSYoshinobu Inoue 				nd6_dad_start((struct ifaddr *)ia, NULL);
847686cdd19SJun-ichiro itojun Hagino 			}
84882cd038dSYoshinobu Inoue 			break;
84982cd038dSYoshinobu Inoue #ifdef IFT_DUMMY
85082cd038dSYoshinobu Inoue 		case IFT_DUMMY:
85182cd038dSYoshinobu Inoue #endif
85282cd038dSYoshinobu Inoue 		case IFT_FAITH:
85382cd038dSYoshinobu Inoue 		case IFT_GIF:
85482cd038dSYoshinobu Inoue 		case IFT_LOOP:
85582cd038dSYoshinobu Inoue 		default:
85682cd038dSYoshinobu Inoue 			break;
85782cd038dSYoshinobu Inoue 		}
85882cd038dSYoshinobu Inoue 
85982cd038dSYoshinobu Inoue 		if (hostIsNew) {
86082cd038dSYoshinobu Inoue 			int iilen;
86182cd038dSYoshinobu Inoue 			int error_local = 0;
86282cd038dSYoshinobu Inoue 
86382cd038dSYoshinobu Inoue 			iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) -
86482cd038dSYoshinobu Inoue 				in6_mask2len(&ia->ia_prefixmask.sin6_addr);
86582cd038dSYoshinobu Inoue 			error_local = in6_prefix_add_ifid(iilen, ia);
86682cd038dSYoshinobu Inoue 			if (error == 0)
86782cd038dSYoshinobu Inoue 				error = error_local;
86882cd038dSYoshinobu Inoue 		}
86982cd038dSYoshinobu Inoue 
87082cd038dSYoshinobu Inoue 		return(error);
87182cd038dSYoshinobu Inoue 
87282cd038dSYoshinobu Inoue 	case SIOCDIFADDR_IN6:
873686cdd19SJun-ichiro itojun Hagino 		in6_purgeaddr(&ia->ia_ifa, ifp);
874686cdd19SJun-ichiro itojun Hagino 		break;
875686cdd19SJun-ichiro itojun Hagino 
876686cdd19SJun-ichiro itojun Hagino 	default:
877686cdd19SJun-ichiro itojun Hagino 		if (ifp == NULL || ifp->if_ioctl == 0)
878686cdd19SJun-ichiro itojun Hagino 			return(EOPNOTSUPP);
879686cdd19SJun-ichiro itojun Hagino 		return((*ifp->if_ioctl)(ifp, cmd, data));
880686cdd19SJun-ichiro itojun Hagino 	}
881686cdd19SJun-ichiro itojun Hagino 	return(0);
882686cdd19SJun-ichiro itojun Hagino }
883686cdd19SJun-ichiro itojun Hagino 
884686cdd19SJun-ichiro itojun Hagino void
885686cdd19SJun-ichiro itojun Hagino in6_purgeaddr(ifa, ifp)
886686cdd19SJun-ichiro itojun Hagino 	struct ifaddr *ifa;
887686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
888686cdd19SJun-ichiro itojun Hagino {
889686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *oia, *ia = (void *) ifa;
890686cdd19SJun-ichiro itojun Hagino 	int plen;
891686cdd19SJun-ichiro itojun Hagino 
89282cd038dSYoshinobu Inoue 	in6_ifscrub(ifp, ia);
89382cd038dSYoshinobu Inoue 
89482cd038dSYoshinobu Inoue 	if (ifp->if_flags & IFF_MULTICAST) {
89582cd038dSYoshinobu Inoue 		/*
89682cd038dSYoshinobu Inoue 		 * delete solicited multicast addr for deleting host id
89782cd038dSYoshinobu Inoue 		 */
89882cd038dSYoshinobu Inoue 		struct in6_multi *in6m;
89982cd038dSYoshinobu Inoue 		struct in6_addr llsol;
90082cd038dSYoshinobu Inoue 		bzero(&llsol, sizeof(struct in6_addr));
90182cd038dSYoshinobu Inoue 		llsol.s6_addr16[0] = htons(0xff02);
90282cd038dSYoshinobu Inoue 		llsol.s6_addr16[1] = htons(ifp->if_index);
90382cd038dSYoshinobu Inoue 		llsol.s6_addr32[1] = 0;
90482cd038dSYoshinobu Inoue 		llsol.s6_addr32[2] = htonl(1);
90582cd038dSYoshinobu Inoue 		llsol.s6_addr32[3] =
90682cd038dSYoshinobu Inoue 			ia->ia_addr.sin6_addr.s6_addr32[3];
90782cd038dSYoshinobu Inoue 		llsol.s6_addr8[12] = 0xff;
90882cd038dSYoshinobu Inoue 
90982cd038dSYoshinobu Inoue 		IN6_LOOKUP_MULTI(llsol, ifp, in6m);
91082cd038dSYoshinobu Inoue 		if (in6m)
91182cd038dSYoshinobu Inoue 			in6_delmulti(in6m);
91282cd038dSYoshinobu Inoue 	}
91382cd038dSYoshinobu Inoue 
914686cdd19SJun-ichiro itojun Hagino 	TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
915686cdd19SJun-ichiro itojun Hagino 	/* release a refcnt for the link from if_addrlist */
916686cdd19SJun-ichiro itojun Hagino 	IFAFREE(&ia->ia_ifa);
917686cdd19SJun-ichiro itojun Hagino 
91882cd038dSYoshinobu Inoue 	oia = ia;
91982cd038dSYoshinobu Inoue 	if (oia == (ia = in6_ifaddr))
92082cd038dSYoshinobu Inoue 		in6_ifaddr = ia->ia_next;
92182cd038dSYoshinobu Inoue 	else {
92282cd038dSYoshinobu Inoue 		while (ia->ia_next && (ia->ia_next != oia))
92382cd038dSYoshinobu Inoue 			ia = ia->ia_next;
92482cd038dSYoshinobu Inoue 		if (ia->ia_next)
92582cd038dSYoshinobu Inoue 			ia->ia_next = oia->ia_next;
92682cd038dSYoshinobu Inoue 		else
92782cd038dSYoshinobu Inoue 			printf("Didn't unlink in6_ifaddr from list\n");
92882cd038dSYoshinobu Inoue 	}
92982cd038dSYoshinobu Inoue 	{
93082cd038dSYoshinobu Inoue 		int iilen;
93182cd038dSYoshinobu Inoue 
932686cdd19SJun-ichiro itojun Hagino 		plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr);
933686cdd19SJun-ichiro itojun Hagino 		iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen;
93482cd038dSYoshinobu Inoue 		in6_prefix_remove_ifid(iilen, oia);
93582cd038dSYoshinobu Inoue 	}
93682cd038dSYoshinobu Inoue 
937686cdd19SJun-ichiro itojun Hagino 	/*
938686cdd19SJun-ichiro itojun Hagino 	 * Check if we have another address that has the same prefix of
939686cdd19SJun-ichiro itojun Hagino 	 * the purged address. If we have one, reinstall the corresponding
940686cdd19SJun-ichiro itojun Hagino 	 * interface route.
941686cdd19SJun-ichiro itojun Hagino 	 */
942686cdd19SJun-ichiro itojun Hagino 	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
943686cdd19SJun-ichiro itojun Hagino 		int e;
944686cdd19SJun-ichiro itojun Hagino 
945686cdd19SJun-ichiro itojun Hagino 		if (in6_are_prefix_equal(&ia->ia_addr.sin6_addr,
946686cdd19SJun-ichiro itojun Hagino 					 &oia->ia_addr.sin6_addr, plen)) {
947686cdd19SJun-ichiro itojun Hagino 			if ((e = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
948686cdd19SJun-ichiro itojun Hagino 					ia->ia_flags)) == 0) {
949686cdd19SJun-ichiro itojun Hagino 				ia->ia_flags |= IFA_ROUTE;
950686cdd19SJun-ichiro itojun Hagino 				break;
95182cd038dSYoshinobu Inoue 			}
952686cdd19SJun-ichiro itojun Hagino 			else {
953686cdd19SJun-ichiro itojun Hagino 				log(LOG_NOTICE,
954686cdd19SJun-ichiro itojun Hagino 				    "in6_purgeaddr: failed to add an interface"
955686cdd19SJun-ichiro itojun Hagino 				    " route for %s/%d on %s, errno = %d\n",
956686cdd19SJun-ichiro itojun Hagino 				    ip6_sprintf(&ia->ia_addr.sin6_addr),
957686cdd19SJun-ichiro itojun Hagino 				    plen, if_name(ia->ia_ifp), e);
958686cdd19SJun-ichiro itojun Hagino 				/* still trying */
959686cdd19SJun-ichiro itojun Hagino 			}
960686cdd19SJun-ichiro itojun Hagino 		}
961686cdd19SJun-ichiro itojun Hagino 	}
962686cdd19SJun-ichiro itojun Hagino 
963686cdd19SJun-ichiro itojun Hagino 	/* release another refcnt for the link from in6_ifaddr */
964686cdd19SJun-ichiro itojun Hagino 	IFAFREE(&oia->ia_ifa);
96582cd038dSYoshinobu Inoue }
96682cd038dSYoshinobu Inoue 
96782cd038dSYoshinobu Inoue /*
96882cd038dSYoshinobu Inoue  * SIOC[GAD]LIFADDR.
969686cdd19SJun-ichiro itojun Hagino  *	SIOCGLIFADDR: get first address. (???)
97082cd038dSYoshinobu Inoue  *	SIOCGLIFADDR with IFLR_PREFIX:
97182cd038dSYoshinobu Inoue  *		get first address that matches the specified prefix.
97282cd038dSYoshinobu Inoue  *	SIOCALIFADDR: add the specified address.
97382cd038dSYoshinobu Inoue  *	SIOCALIFADDR with IFLR_PREFIX:
97482cd038dSYoshinobu Inoue  *		add the specified prefix, filling hostid part from
97582cd038dSYoshinobu Inoue  *		the first link-local address.  prefixlen must be <= 64.
97682cd038dSYoshinobu Inoue  *	SIOCDLIFADDR: delete the specified address.
97782cd038dSYoshinobu Inoue  *	SIOCDLIFADDR with IFLR_PREFIX:
97882cd038dSYoshinobu Inoue  *		delete the first address that matches the specified prefix.
97982cd038dSYoshinobu Inoue  * return values:
98082cd038dSYoshinobu Inoue  *	EINVAL on invalid parameters
98182cd038dSYoshinobu Inoue  *	EADDRNOTAVAIL on prefix match failed/specified address not found
98282cd038dSYoshinobu Inoue  *	other values may be returned from in6_ioctl()
98382cd038dSYoshinobu Inoue  *
98482cd038dSYoshinobu Inoue  * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
98582cd038dSYoshinobu Inoue  * this is to accomodate address naming scheme other than RFC2374,
98682cd038dSYoshinobu Inoue  * in the future.
98782cd038dSYoshinobu Inoue  * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
98882cd038dSYoshinobu Inoue  * address encoding scheme. (see figure on page 8)
98982cd038dSYoshinobu Inoue  */
99082cd038dSYoshinobu Inoue static int
99182cd038dSYoshinobu Inoue in6_lifaddr_ioctl(so, cmd, data, ifp, p)
99282cd038dSYoshinobu Inoue 	struct socket *so;
99382cd038dSYoshinobu Inoue 	u_long cmd;
99482cd038dSYoshinobu Inoue 	caddr_t	data;
99582cd038dSYoshinobu Inoue 	struct ifnet *ifp;
99682cd038dSYoshinobu Inoue 	struct proc *p;
99782cd038dSYoshinobu Inoue {
99882cd038dSYoshinobu Inoue 	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
99982cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
1000686cdd19SJun-ichiro itojun Hagino 	struct sockaddr *sa;
100182cd038dSYoshinobu Inoue 
100282cd038dSYoshinobu Inoue 	/* sanity checks */
100382cd038dSYoshinobu Inoue 	if (!data || !ifp) {
100482cd038dSYoshinobu Inoue 		panic("invalid argument to in6_lifaddr_ioctl");
100582cd038dSYoshinobu Inoue 		/*NOTRECHED*/
100682cd038dSYoshinobu Inoue 	}
100782cd038dSYoshinobu Inoue 
100882cd038dSYoshinobu Inoue 	switch (cmd) {
100982cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
101082cd038dSYoshinobu Inoue 		/* address must be specified on GET with IFLR_PREFIX */
101182cd038dSYoshinobu Inoue 		if ((iflr->flags & IFLR_PREFIX) == 0)
101282cd038dSYoshinobu Inoue 			break;
101382cd038dSYoshinobu Inoue 		/*FALLTHROUGH*/
101482cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
101582cd038dSYoshinobu Inoue 	case SIOCDLIFADDR:
101682cd038dSYoshinobu Inoue 		/* address must be specified on ADD and DELETE */
1017686cdd19SJun-ichiro itojun Hagino 		sa = (struct sockaddr *)&iflr->addr;
1018686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_family != AF_INET6)
101982cd038dSYoshinobu Inoue 			return EINVAL;
1020686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_len != sizeof(struct sockaddr_in6))
102182cd038dSYoshinobu Inoue 			return EINVAL;
102282cd038dSYoshinobu Inoue 		/* XXX need improvement */
1023686cdd19SJun-ichiro itojun Hagino 		sa = (struct sockaddr *)&iflr->dstaddr;
1024686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_family && sa->sa_family != AF_INET6)
102582cd038dSYoshinobu Inoue 			return EINVAL;
1026686cdd19SJun-ichiro itojun Hagino 		if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
102782cd038dSYoshinobu Inoue 			return EINVAL;
102882cd038dSYoshinobu Inoue 		break;
102982cd038dSYoshinobu Inoue 	default: /*shouldn't happen*/
1030686cdd19SJun-ichiro itojun Hagino #if 0
1031686cdd19SJun-ichiro itojun Hagino 		panic("invalid cmd to in6_lifaddr_ioctl");
1032686cdd19SJun-ichiro itojun Hagino 		/*NOTREACHED*/
1033686cdd19SJun-ichiro itojun Hagino #else
103482cd038dSYoshinobu Inoue 		return EOPNOTSUPP;
1035686cdd19SJun-ichiro itojun Hagino #endif
103682cd038dSYoshinobu Inoue 	}
103782cd038dSYoshinobu Inoue 	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
103882cd038dSYoshinobu Inoue 		return EINVAL;
103982cd038dSYoshinobu Inoue 
104082cd038dSYoshinobu Inoue 	switch (cmd) {
104182cd038dSYoshinobu Inoue 	case SIOCALIFADDR:
104282cd038dSYoshinobu Inoue 	    {
104382cd038dSYoshinobu Inoue 		struct in6_aliasreq ifra;
104482cd038dSYoshinobu Inoue 		struct in6_addr *hostid = NULL;
104582cd038dSYoshinobu Inoue 		int prefixlen;
104682cd038dSYoshinobu Inoue 
104782cd038dSYoshinobu Inoue 		if ((iflr->flags & IFLR_PREFIX) != 0) {
104882cd038dSYoshinobu Inoue 			struct sockaddr_in6 *sin6;
104982cd038dSYoshinobu Inoue 
105082cd038dSYoshinobu Inoue 			/*
105182cd038dSYoshinobu Inoue 			 * hostid is to fill in the hostid part of the
105282cd038dSYoshinobu Inoue 			 * address.  hostid points to the first link-local
105382cd038dSYoshinobu Inoue 			 * address attached to the interface.
105482cd038dSYoshinobu Inoue 			 */
1055686cdd19SJun-ichiro itojun Hagino 			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
105682cd038dSYoshinobu Inoue 			if (!ifa)
105782cd038dSYoshinobu Inoue 				return EADDRNOTAVAIL;
105882cd038dSYoshinobu Inoue 			hostid = IFA_IN6(ifa);
105982cd038dSYoshinobu Inoue 
106082cd038dSYoshinobu Inoue 		 	/* prefixlen must be <= 64. */
106182cd038dSYoshinobu Inoue 			if (64 < iflr->prefixlen)
106282cd038dSYoshinobu Inoue 				return EINVAL;
106382cd038dSYoshinobu Inoue 			prefixlen = iflr->prefixlen;
106482cd038dSYoshinobu Inoue 
106582cd038dSYoshinobu Inoue 			/* hostid part must be zero. */
106682cd038dSYoshinobu Inoue 			sin6 = (struct sockaddr_in6 *)&iflr->addr;
106782cd038dSYoshinobu Inoue 			if (sin6->sin6_addr.s6_addr32[2] != 0
106882cd038dSYoshinobu Inoue 			 || sin6->sin6_addr.s6_addr32[3] != 0) {
106982cd038dSYoshinobu Inoue 				return EINVAL;
107082cd038dSYoshinobu Inoue 			}
107182cd038dSYoshinobu Inoue 		} else
107282cd038dSYoshinobu Inoue 			prefixlen = iflr->prefixlen;
107382cd038dSYoshinobu Inoue 
107482cd038dSYoshinobu Inoue 		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
107582cd038dSYoshinobu Inoue 		bzero(&ifra, sizeof(ifra));
107682cd038dSYoshinobu Inoue 		bcopy(iflr->iflr_name, ifra.ifra_name,
107782cd038dSYoshinobu Inoue 			sizeof(ifra.ifra_name));
107882cd038dSYoshinobu Inoue 
1079686cdd19SJun-ichiro itojun Hagino 		bcopy(&iflr->addr, &ifra.ifra_addr,
1080686cdd19SJun-ichiro itojun Hagino 			((struct sockaddr *)&iflr->addr)->sa_len);
108182cd038dSYoshinobu Inoue 		if (hostid) {
108282cd038dSYoshinobu Inoue 			/* fill in hostid part */
108382cd038dSYoshinobu Inoue 			ifra.ifra_addr.sin6_addr.s6_addr32[2] =
108482cd038dSYoshinobu Inoue 				hostid->s6_addr32[2];
108582cd038dSYoshinobu Inoue 			ifra.ifra_addr.sin6_addr.s6_addr32[3] =
108682cd038dSYoshinobu Inoue 				hostid->s6_addr32[3];
108782cd038dSYoshinobu Inoue 		}
108882cd038dSYoshinobu Inoue 
1089686cdd19SJun-ichiro itojun Hagino 		if (((struct sockaddr *)&iflr->dstaddr)->sa_family) {	/*XXX*/
109082cd038dSYoshinobu Inoue 			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1091686cdd19SJun-ichiro itojun Hagino 				((struct sockaddr *)&iflr->dstaddr)->sa_len);
109282cd038dSYoshinobu Inoue 			if (hostid) {
109382cd038dSYoshinobu Inoue 				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
109482cd038dSYoshinobu Inoue 					hostid->s6_addr32[2];
109582cd038dSYoshinobu Inoue 				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
109682cd038dSYoshinobu Inoue 					hostid->s6_addr32[3];
109782cd038dSYoshinobu Inoue 			}
109882cd038dSYoshinobu Inoue 		}
109982cd038dSYoshinobu Inoue 
110082cd038dSYoshinobu Inoue 		ifra.ifra_prefixmask.sin6_family = AF_INET6;
110182cd038dSYoshinobu Inoue 		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
110282cd038dSYoshinobu Inoue 		in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
110382cd038dSYoshinobu Inoue 
110482cd038dSYoshinobu Inoue 		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
110582cd038dSYoshinobu Inoue 		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
110682cd038dSYoshinobu Inoue 	    }
110782cd038dSYoshinobu Inoue 	case SIOCGLIFADDR:
110882cd038dSYoshinobu Inoue 	case SIOCDLIFADDR:
110982cd038dSYoshinobu Inoue 	    {
111082cd038dSYoshinobu Inoue 		struct in6_ifaddr *ia;
111182cd038dSYoshinobu Inoue 		struct in6_addr mask, candidate, match;
111282cd038dSYoshinobu Inoue 		struct sockaddr_in6 *sin6;
111382cd038dSYoshinobu Inoue 		int cmp;
111482cd038dSYoshinobu Inoue 
111582cd038dSYoshinobu Inoue 		bzero(&mask, sizeof(mask));
111682cd038dSYoshinobu Inoue 		if (iflr->flags & IFLR_PREFIX) {
111782cd038dSYoshinobu Inoue 			/* lookup a prefix rather than address. */
111882cd038dSYoshinobu Inoue 			in6_len2mask(&mask, iflr->prefixlen);
111982cd038dSYoshinobu Inoue 
112082cd038dSYoshinobu Inoue 			sin6 = (struct sockaddr_in6 *)&iflr->addr;
112182cd038dSYoshinobu Inoue 			bcopy(&sin6->sin6_addr, &match, sizeof(match));
112282cd038dSYoshinobu Inoue 			match.s6_addr32[0] &= mask.s6_addr32[0];
112382cd038dSYoshinobu Inoue 			match.s6_addr32[1] &= mask.s6_addr32[1];
112482cd038dSYoshinobu Inoue 			match.s6_addr32[2] &= mask.s6_addr32[2];
112582cd038dSYoshinobu Inoue 			match.s6_addr32[3] &= mask.s6_addr32[3];
112682cd038dSYoshinobu Inoue 
112782cd038dSYoshinobu Inoue 			/* if you set extra bits, that's wrong */
112882cd038dSYoshinobu Inoue 			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
112982cd038dSYoshinobu Inoue 				return EINVAL;
113082cd038dSYoshinobu Inoue 
113182cd038dSYoshinobu Inoue 			cmp = 1;
113282cd038dSYoshinobu Inoue 		} else {
113382cd038dSYoshinobu Inoue 			if (cmd == SIOCGLIFADDR) {
113482cd038dSYoshinobu Inoue 				/* on getting an address, take the 1st match */
113582cd038dSYoshinobu Inoue 				cmp = 0;	/*XXX*/
113682cd038dSYoshinobu Inoue 			} else {
113782cd038dSYoshinobu Inoue 				/* on deleting an address, do exact match */
113882cd038dSYoshinobu Inoue 				in6_len2mask(&mask, 128);
113982cd038dSYoshinobu Inoue 				sin6 = (struct sockaddr_in6 *)&iflr->addr;
114082cd038dSYoshinobu Inoue 				bcopy(&sin6->sin6_addr, &match, sizeof(match));
114182cd038dSYoshinobu Inoue 
114282cd038dSYoshinobu Inoue 				cmp = 1;
114382cd038dSYoshinobu Inoue 			}
114482cd038dSYoshinobu Inoue 		}
114582cd038dSYoshinobu Inoue 
1146cfa1ca9dSYoshinobu Inoue 		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
114782cd038dSYoshinobu Inoue 		{
114882cd038dSYoshinobu Inoue 			if (ifa->ifa_addr->sa_family != AF_INET6)
114982cd038dSYoshinobu Inoue 				continue;
115082cd038dSYoshinobu Inoue 			if (!cmp)
115182cd038dSYoshinobu Inoue 				break;
115282cd038dSYoshinobu Inoue 			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
115382cd038dSYoshinobu Inoue 			candidate.s6_addr32[0] &= mask.s6_addr32[0];
115482cd038dSYoshinobu Inoue 			candidate.s6_addr32[1] &= mask.s6_addr32[1];
115582cd038dSYoshinobu Inoue 			candidate.s6_addr32[2] &= mask.s6_addr32[2];
115682cd038dSYoshinobu Inoue 			candidate.s6_addr32[3] &= mask.s6_addr32[3];
115782cd038dSYoshinobu Inoue 			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
115882cd038dSYoshinobu Inoue 				break;
115982cd038dSYoshinobu Inoue 		}
116082cd038dSYoshinobu Inoue 		if (!ifa)
116182cd038dSYoshinobu Inoue 			return EADDRNOTAVAIL;
116282cd038dSYoshinobu Inoue 		ia = ifa2ia6(ifa);
116382cd038dSYoshinobu Inoue 
116482cd038dSYoshinobu Inoue 		if (cmd == SIOCGLIFADDR) {
116582cd038dSYoshinobu Inoue 			/* fill in the if_laddrreq structure */
116682cd038dSYoshinobu Inoue 			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
116782cd038dSYoshinobu Inoue 
116882cd038dSYoshinobu Inoue 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
116982cd038dSYoshinobu Inoue 				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
117082cd038dSYoshinobu Inoue 					ia->ia_dstaddr.sin6_len);
117182cd038dSYoshinobu Inoue 			} else
117282cd038dSYoshinobu Inoue 				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
117382cd038dSYoshinobu Inoue 
117482cd038dSYoshinobu Inoue 			iflr->prefixlen =
117582cd038dSYoshinobu Inoue 				in6_mask2len(&ia->ia_prefixmask.sin6_addr);
117682cd038dSYoshinobu Inoue 
117782cd038dSYoshinobu Inoue 			iflr->flags = ia->ia6_flags;	/*XXX*/
117882cd038dSYoshinobu Inoue 
117982cd038dSYoshinobu Inoue 			return 0;
118082cd038dSYoshinobu Inoue 		} else {
118182cd038dSYoshinobu Inoue 			struct in6_aliasreq ifra;
118282cd038dSYoshinobu Inoue 
118382cd038dSYoshinobu Inoue 			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
118482cd038dSYoshinobu Inoue 			bzero(&ifra, sizeof(ifra));
118582cd038dSYoshinobu Inoue 			bcopy(iflr->iflr_name, ifra.ifra_name,
118682cd038dSYoshinobu Inoue 				sizeof(ifra.ifra_name));
118782cd038dSYoshinobu Inoue 
118882cd038dSYoshinobu Inoue 			bcopy(&ia->ia_addr, &ifra.ifra_addr,
118982cd038dSYoshinobu Inoue 				ia->ia_addr.sin6_len);
119082cd038dSYoshinobu Inoue 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
119182cd038dSYoshinobu Inoue 				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
119282cd038dSYoshinobu Inoue 					ia->ia_dstaddr.sin6_len);
1193686cdd19SJun-ichiro itojun Hagino 			} else {
1194686cdd19SJun-ichiro itojun Hagino 				bzero(&ifra.ifra_dstaddr,
1195686cdd19SJun-ichiro itojun Hagino 				    sizeof(ifra.ifra_dstaddr));
119682cd038dSYoshinobu Inoue 			}
119782cd038dSYoshinobu Inoue 			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
119882cd038dSYoshinobu Inoue 				ia->ia_prefixmask.sin6_len);
119982cd038dSYoshinobu Inoue 
120082cd038dSYoshinobu Inoue 			ifra.ifra_flags = ia->ia6_flags;
120182cd038dSYoshinobu Inoue 			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
120282cd038dSYoshinobu Inoue 				ifp, p);
120382cd038dSYoshinobu Inoue 		}
120482cd038dSYoshinobu Inoue 	    }
120582cd038dSYoshinobu Inoue 	}
120682cd038dSYoshinobu Inoue 
120782cd038dSYoshinobu Inoue 	return EOPNOTSUPP;	/*just for safety*/
120882cd038dSYoshinobu Inoue }
120982cd038dSYoshinobu Inoue 
121082cd038dSYoshinobu Inoue /*
121182cd038dSYoshinobu Inoue  * Delete any existing route for an interface.
121282cd038dSYoshinobu Inoue  */
121382cd038dSYoshinobu Inoue void
121482cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia)
121582cd038dSYoshinobu Inoue 	register struct ifnet *ifp;
121682cd038dSYoshinobu Inoue 	register struct in6_ifaddr *ia;
121782cd038dSYoshinobu Inoue {
121882cd038dSYoshinobu Inoue 	if ((ia->ia_flags & IFA_ROUTE) == 0)
121982cd038dSYoshinobu Inoue 		return;
122082cd038dSYoshinobu Inoue 	if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
122182cd038dSYoshinobu Inoue 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
122282cd038dSYoshinobu Inoue 	else
122382cd038dSYoshinobu Inoue 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
122482cd038dSYoshinobu Inoue 	ia->ia_flags &= ~IFA_ROUTE;
122582cd038dSYoshinobu Inoue 
122682cd038dSYoshinobu Inoue 	/* Remove ownaddr's loopback rtentry, if it exists. */
122782cd038dSYoshinobu Inoue 	in6_ifremloop(&(ia->ia_ifa));
122882cd038dSYoshinobu Inoue }
122982cd038dSYoshinobu Inoue 
123082cd038dSYoshinobu Inoue /*
123182cd038dSYoshinobu Inoue  * Initialize an interface's intetnet6 address
123282cd038dSYoshinobu Inoue  * and routing table entry.
123382cd038dSYoshinobu Inoue  */
123482cd038dSYoshinobu Inoue int
123582cd038dSYoshinobu Inoue in6_ifinit(ifp, ia, sin6, scrub)
123682cd038dSYoshinobu Inoue 	struct ifnet *ifp;
123782cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
123882cd038dSYoshinobu Inoue 	struct sockaddr_in6 *sin6;
123982cd038dSYoshinobu Inoue 	int scrub;
124082cd038dSYoshinobu Inoue {
124182cd038dSYoshinobu Inoue 	struct	sockaddr_in6 oldaddr;
124282cd038dSYoshinobu Inoue 	int	error, flags = RTF_UP;
124382cd038dSYoshinobu Inoue 	int	s = splimp();
124482cd038dSYoshinobu Inoue 
124582cd038dSYoshinobu Inoue 	oldaddr = ia->ia_addr;
124682cd038dSYoshinobu Inoue 	ia->ia_addr = *sin6;
124782cd038dSYoshinobu Inoue 	/*
124882cd038dSYoshinobu Inoue 	 * Give the interface a chance to initialize
124982cd038dSYoshinobu Inoue 	 * if this is its first address,
125082cd038dSYoshinobu Inoue 	 * and to validate the address if necessary.
125182cd038dSYoshinobu Inoue 	 */
125282cd038dSYoshinobu Inoue 	if (ifp->if_ioctl &&
125382cd038dSYoshinobu Inoue 	   (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
125482cd038dSYoshinobu Inoue 		splx(s);
125582cd038dSYoshinobu Inoue 		ia->ia_addr = oldaddr;
125682cd038dSYoshinobu Inoue 		return(error);
125782cd038dSYoshinobu Inoue 	}
125882cd038dSYoshinobu Inoue 
125982cd038dSYoshinobu Inoue 	switch (ifp->if_type) {
126082cd038dSYoshinobu Inoue 	case IFT_ARCNET:
126182cd038dSYoshinobu Inoue 	case IFT_ETHER:
126282cd038dSYoshinobu Inoue 	case IFT_FDDI:
126382cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
126482cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
126582cd038dSYoshinobu Inoue 		break;
126682cd038dSYoshinobu Inoue 	case IFT_PPP:
126782cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest;
126882cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
126982cd038dSYoshinobu Inoue 		break;
127082cd038dSYoshinobu Inoue 	}
127182cd038dSYoshinobu Inoue 
127282cd038dSYoshinobu Inoue 	splx(s);
127382cd038dSYoshinobu Inoue 	if (scrub) {
127482cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
127582cd038dSYoshinobu Inoue 		in6_ifscrub(ifp, ia);
127682cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
127782cd038dSYoshinobu Inoue 	}
127882cd038dSYoshinobu Inoue 	/* xxx
127982cd038dSYoshinobu Inoue 	 * in_socktrim
128082cd038dSYoshinobu Inoue 	 */
128182cd038dSYoshinobu Inoue 	/*
128282cd038dSYoshinobu Inoue 	 * Add route for the network.
128382cd038dSYoshinobu Inoue 	 */
128482cd038dSYoshinobu Inoue 	ia->ia_ifa.ifa_metric = ifp->if_metric;
128582cd038dSYoshinobu Inoue 	if (ifp->if_flags & IFF_LOOPBACK) {
128682cd038dSYoshinobu Inoue 		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
128782cd038dSYoshinobu Inoue 		flags |= RTF_HOST;
128882cd038dSYoshinobu Inoue 	} else if (ifp->if_flags & IFF_POINTOPOINT) {
128982cd038dSYoshinobu Inoue 		if (ia->ia_dstaddr.sin6_family != AF_INET6)
129082cd038dSYoshinobu Inoue 			return(0);
129182cd038dSYoshinobu Inoue 		flags |= RTF_HOST;
129282cd038dSYoshinobu Inoue 	}
129382cd038dSYoshinobu Inoue 	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
129482cd038dSYoshinobu Inoue 		ia->ia_flags |= IFA_ROUTE;
1295686cdd19SJun-ichiro itojun Hagino 	/* XXX check if the subnet route points to the same interface */
1296686cdd19SJun-ichiro itojun Hagino 	if (error == EEXIST)
1297686cdd19SJun-ichiro itojun Hagino 		error = 0;
129882cd038dSYoshinobu Inoue 
129982cd038dSYoshinobu Inoue 	/* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */
130082cd038dSYoshinobu Inoue 	in6_ifaddloop(&(ia->ia_ifa));
130182cd038dSYoshinobu Inoue 
130282cd038dSYoshinobu Inoue 	return(error);
130382cd038dSYoshinobu Inoue }
130482cd038dSYoshinobu Inoue 
130582cd038dSYoshinobu Inoue /*
130682cd038dSYoshinobu Inoue  * Add an address to the list of IP6 multicast addresses for a
130782cd038dSYoshinobu Inoue  * given interface.
130882cd038dSYoshinobu Inoue  */
130982cd038dSYoshinobu Inoue struct	in6_multi *
131082cd038dSYoshinobu Inoue in6_addmulti(maddr6, ifp, errorp)
131182cd038dSYoshinobu Inoue 	register struct in6_addr *maddr6;
131282cd038dSYoshinobu Inoue 	register struct ifnet *ifp;
131382cd038dSYoshinobu Inoue 	int *errorp;
131482cd038dSYoshinobu Inoue {
131582cd038dSYoshinobu Inoue 	struct	in6_multi *in6m;
131682cd038dSYoshinobu Inoue 	struct sockaddr_in6 sin6;
131782cd038dSYoshinobu Inoue 	struct ifmultiaddr *ifma;
131882cd038dSYoshinobu Inoue 	int	s = splnet();
131982cd038dSYoshinobu Inoue 
132082cd038dSYoshinobu Inoue 	*errorp = 0;
132182cd038dSYoshinobu Inoue 
132282cd038dSYoshinobu Inoue 	/*
132382cd038dSYoshinobu Inoue 	 * Call generic routine to add membership or increment
132482cd038dSYoshinobu Inoue 	 * refcount.  It wants addresses in the form of a sockaddr,
132582cd038dSYoshinobu Inoue 	 * so we build one here (being careful to zero the unused bytes).
132682cd038dSYoshinobu Inoue 	 */
132782cd038dSYoshinobu Inoue 	bzero(&sin6, sizeof sin6);
132882cd038dSYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
132982cd038dSYoshinobu Inoue 	sin6.sin6_len = sizeof sin6;
133082cd038dSYoshinobu Inoue 	sin6.sin6_addr = *maddr6;
133182cd038dSYoshinobu Inoue 	*errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma);
133282cd038dSYoshinobu Inoue 	if (*errorp) {
133382cd038dSYoshinobu Inoue 		splx(s);
133482cd038dSYoshinobu Inoue 		return 0;
133582cd038dSYoshinobu Inoue 	}
133682cd038dSYoshinobu Inoue 
133782cd038dSYoshinobu Inoue 	/*
133882cd038dSYoshinobu Inoue 	 * If ifma->ifma_protospec is null, then if_addmulti() created
133982cd038dSYoshinobu Inoue 	 * a new record.  Otherwise, we are done.
134082cd038dSYoshinobu Inoue 	 */
134182cd038dSYoshinobu Inoue 	if (ifma->ifma_protospec != 0)
134282cd038dSYoshinobu Inoue 		return ifma->ifma_protospec;
134382cd038dSYoshinobu Inoue 
134482cd038dSYoshinobu Inoue 	/* XXX - if_addmulti uses M_WAITOK.  Can this really be called
134582cd038dSYoshinobu Inoue 	   at interrupt time?  If so, need to fix if_addmulti. XXX */
134682cd038dSYoshinobu Inoue 	in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
134782cd038dSYoshinobu Inoue 	if (in6m == NULL) {
134882cd038dSYoshinobu Inoue 		splx(s);
134982cd038dSYoshinobu Inoue 		return (NULL);
135082cd038dSYoshinobu Inoue 	}
135182cd038dSYoshinobu Inoue 
135282cd038dSYoshinobu Inoue 	bzero(in6m, sizeof *in6m);
135382cd038dSYoshinobu Inoue 	in6m->in6m_addr = *maddr6;
135482cd038dSYoshinobu Inoue 	in6m->in6m_ifp = ifp;
135582cd038dSYoshinobu Inoue 	in6m->in6m_ifma = ifma;
135682cd038dSYoshinobu Inoue 	ifma->ifma_protospec = in6m;
135782cd038dSYoshinobu Inoue 	LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry);
135882cd038dSYoshinobu Inoue 
135982cd038dSYoshinobu Inoue 	/*
136082cd038dSYoshinobu Inoue 	 * Let MLD6 know that we have joined a new IP6 multicast
136182cd038dSYoshinobu Inoue 	 * group.
136282cd038dSYoshinobu Inoue 	 */
136382cd038dSYoshinobu Inoue 	mld6_start_listening(in6m);
136482cd038dSYoshinobu Inoue 	splx(s);
136582cd038dSYoshinobu Inoue 	return(in6m);
136682cd038dSYoshinobu Inoue }
136782cd038dSYoshinobu Inoue 
136882cd038dSYoshinobu Inoue /*
136982cd038dSYoshinobu Inoue  * Delete a multicast address record.
137082cd038dSYoshinobu Inoue  */
137182cd038dSYoshinobu Inoue void
137282cd038dSYoshinobu Inoue in6_delmulti(in6m)
137382cd038dSYoshinobu Inoue 	struct in6_multi *in6m;
137482cd038dSYoshinobu Inoue {
137582cd038dSYoshinobu Inoue 	struct ifmultiaddr *ifma = in6m->in6m_ifma;
137682cd038dSYoshinobu Inoue 	int	s = splnet();
137782cd038dSYoshinobu Inoue 
137882cd038dSYoshinobu Inoue 	if (ifma->ifma_refcount == 1) {
137982cd038dSYoshinobu Inoue 		/*
138082cd038dSYoshinobu Inoue 		 * No remaining claims to this record; let MLD6 know
138182cd038dSYoshinobu Inoue 		 * that we are leaving the multicast group.
138282cd038dSYoshinobu Inoue 		 */
138382cd038dSYoshinobu Inoue 		mld6_stop_listening(in6m);
138482cd038dSYoshinobu Inoue 		ifma->ifma_protospec = 0;
138582cd038dSYoshinobu Inoue 		LIST_REMOVE(in6m, in6m_entry);
138682cd038dSYoshinobu Inoue 		free(in6m, M_IPMADDR);
138782cd038dSYoshinobu Inoue 	}
138882cd038dSYoshinobu Inoue 	/* XXX - should be separate API for when we have an ifma? */
138982cd038dSYoshinobu Inoue 	if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
139082cd038dSYoshinobu Inoue 	splx(s);
139182cd038dSYoshinobu Inoue }
139282cd038dSYoshinobu Inoue 
139382cd038dSYoshinobu Inoue /*
139482cd038dSYoshinobu Inoue  * Find an IPv6 interface link-local address specific to an interface.
139582cd038dSYoshinobu Inoue  */
139682cd038dSYoshinobu Inoue struct in6_ifaddr *
1397686cdd19SJun-ichiro itojun Hagino in6ifa_ifpforlinklocal(ifp, ignoreflags)
139882cd038dSYoshinobu Inoue 	struct ifnet *ifp;
1399686cdd19SJun-ichiro itojun Hagino 	int ignoreflags;
140082cd038dSYoshinobu Inoue {
140182cd038dSYoshinobu Inoue 	register struct ifaddr *ifa;
140282cd038dSYoshinobu Inoue 
1403cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
140482cd038dSYoshinobu Inoue 	{
140582cd038dSYoshinobu Inoue 		if (ifa->ifa_addr == NULL)
140682cd038dSYoshinobu Inoue 			continue;	/* just for safety */
140782cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
140882cd038dSYoshinobu Inoue 			continue;
1409686cdd19SJun-ichiro itojun Hagino 		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
1410686cdd19SJun-ichiro itojun Hagino 			if ((((struct in6_ifaddr *)ifa)->ia6_flags &
1411686cdd19SJun-ichiro itojun Hagino 			     ignoreflags) != 0)
1412686cdd19SJun-ichiro itojun Hagino 				continue;
141382cd038dSYoshinobu Inoue 			break;
141482cd038dSYoshinobu Inoue 		}
1415686cdd19SJun-ichiro itojun Hagino 	}
141682cd038dSYoshinobu Inoue 
141782cd038dSYoshinobu Inoue 	return((struct in6_ifaddr *)ifa);
141882cd038dSYoshinobu Inoue }
141982cd038dSYoshinobu Inoue 
142082cd038dSYoshinobu Inoue 
142182cd038dSYoshinobu Inoue /*
142282cd038dSYoshinobu Inoue  * find the internet address corresponding to a given interface and address.
142382cd038dSYoshinobu Inoue  */
142482cd038dSYoshinobu Inoue struct in6_ifaddr *
142582cd038dSYoshinobu Inoue in6ifa_ifpwithaddr(ifp, addr)
142682cd038dSYoshinobu Inoue 	struct ifnet *ifp;
142782cd038dSYoshinobu Inoue 	struct in6_addr *addr;
142882cd038dSYoshinobu Inoue {
142982cd038dSYoshinobu Inoue 	register struct ifaddr *ifa;
143082cd038dSYoshinobu Inoue 
1431cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
143282cd038dSYoshinobu Inoue 	{
143382cd038dSYoshinobu Inoue 		if (ifa->ifa_addr == NULL)
143482cd038dSYoshinobu Inoue 			continue;	/* just for safety */
143582cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
143682cd038dSYoshinobu Inoue 			continue;
143782cd038dSYoshinobu Inoue 		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
143882cd038dSYoshinobu Inoue 			break;
143982cd038dSYoshinobu Inoue 	}
144082cd038dSYoshinobu Inoue 
144182cd038dSYoshinobu Inoue 	return((struct in6_ifaddr *)ifa);
144282cd038dSYoshinobu Inoue }
144382cd038dSYoshinobu Inoue 
144482cd038dSYoshinobu Inoue /*
144582cd038dSYoshinobu Inoue  * Convert IP6 address to printable (loggable) representation.
144682cd038dSYoshinobu Inoue  */
144782cd038dSYoshinobu Inoue static char digits[] = "0123456789abcdef";
144882cd038dSYoshinobu Inoue static int ip6round = 0;
144982cd038dSYoshinobu Inoue char *
145082cd038dSYoshinobu Inoue ip6_sprintf(addr)
145182cd038dSYoshinobu Inoue register struct in6_addr *addr;
145282cd038dSYoshinobu Inoue {
145382cd038dSYoshinobu Inoue 	static char ip6buf[8][48];
145482cd038dSYoshinobu Inoue 	register int i;
145582cd038dSYoshinobu Inoue 	register char *cp;
145682cd038dSYoshinobu Inoue 	register u_short *a = (u_short *)addr;
145782cd038dSYoshinobu Inoue 	register u_char *d;
145882cd038dSYoshinobu Inoue 	int dcolon = 0;
145982cd038dSYoshinobu Inoue 
146082cd038dSYoshinobu Inoue 	ip6round = (ip6round + 1) & 7;
146182cd038dSYoshinobu Inoue 	cp = ip6buf[ip6round];
146282cd038dSYoshinobu Inoue 
146382cd038dSYoshinobu Inoue 	for (i = 0; i < 8; i++) {
146482cd038dSYoshinobu Inoue 		if (dcolon == 1) {
146582cd038dSYoshinobu Inoue 			if (*a == 0) {
146682cd038dSYoshinobu Inoue 				if (i == 7)
146782cd038dSYoshinobu Inoue 					*cp++ = ':';
146882cd038dSYoshinobu Inoue 				a++;
146982cd038dSYoshinobu Inoue 				continue;
147082cd038dSYoshinobu Inoue 			} else
147182cd038dSYoshinobu Inoue 				dcolon = 2;
147282cd038dSYoshinobu Inoue 		}
147382cd038dSYoshinobu Inoue 		if (*a == 0) {
147482cd038dSYoshinobu Inoue 			if (dcolon == 0 && *(a + 1) == 0) {
147582cd038dSYoshinobu Inoue 				if (i == 0)
147682cd038dSYoshinobu Inoue 					*cp++ = ':';
147782cd038dSYoshinobu Inoue 				*cp++ = ':';
147882cd038dSYoshinobu Inoue 				dcolon = 1;
147982cd038dSYoshinobu Inoue 			} else {
148082cd038dSYoshinobu Inoue 				*cp++ = '0';
148182cd038dSYoshinobu Inoue 				*cp++ = ':';
148282cd038dSYoshinobu Inoue 			}
148382cd038dSYoshinobu Inoue 			a++;
148482cd038dSYoshinobu Inoue 			continue;
148582cd038dSYoshinobu Inoue 		}
148682cd038dSYoshinobu Inoue 		d = (u_char *)a;
148782cd038dSYoshinobu Inoue 		*cp++ = digits[*d >> 4];
148882cd038dSYoshinobu Inoue 		*cp++ = digits[*d++ & 0xf];
148982cd038dSYoshinobu Inoue 		*cp++ = digits[*d >> 4];
149082cd038dSYoshinobu Inoue 		*cp++ = digits[*d & 0xf];
149182cd038dSYoshinobu Inoue 		*cp++ = ':';
149282cd038dSYoshinobu Inoue 		a++;
149382cd038dSYoshinobu Inoue 	}
149482cd038dSYoshinobu Inoue 	*--cp = 0;
149582cd038dSYoshinobu Inoue 	return(ip6buf[ip6round]);
149682cd038dSYoshinobu Inoue }
149782cd038dSYoshinobu Inoue 
149882cd038dSYoshinobu Inoue int
149982cd038dSYoshinobu Inoue in6_localaddr(in6)
150082cd038dSYoshinobu Inoue 	struct in6_addr *in6;
150182cd038dSYoshinobu Inoue {
150282cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
150382cd038dSYoshinobu Inoue 
150482cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
150582cd038dSYoshinobu Inoue 		return 1;
150682cd038dSYoshinobu Inoue 
150782cd038dSYoshinobu Inoue 	for (ia = in6_ifaddr; ia; ia = ia->ia_next)
150882cd038dSYoshinobu Inoue 		if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
150982cd038dSYoshinobu Inoue 					      &ia->ia_prefixmask.sin6_addr))
151082cd038dSYoshinobu Inoue 			return 1;
151182cd038dSYoshinobu Inoue 
151282cd038dSYoshinobu Inoue 	return (0);
151382cd038dSYoshinobu Inoue }
151482cd038dSYoshinobu Inoue 
151582cd038dSYoshinobu Inoue /*
151682cd038dSYoshinobu Inoue  * return length of part which dst and src are equal
151782cd038dSYoshinobu Inoue  * hard coding...
151882cd038dSYoshinobu Inoue  */
151982cd038dSYoshinobu Inoue int
152082cd038dSYoshinobu Inoue in6_matchlen(src, dst)
152182cd038dSYoshinobu Inoue struct in6_addr *src, *dst;
152282cd038dSYoshinobu Inoue {
152382cd038dSYoshinobu Inoue 	int match = 0;
152482cd038dSYoshinobu Inoue 	u_char *s = (u_char *)src, *d = (u_char *)dst;
152582cd038dSYoshinobu Inoue 	u_char *lim = s + 16, r;
152682cd038dSYoshinobu Inoue 
152782cd038dSYoshinobu Inoue 	while (s < lim)
152882cd038dSYoshinobu Inoue 		if ((r = (*d++ ^ *s++)) != 0) {
152982cd038dSYoshinobu Inoue 			while (r < 128) {
153082cd038dSYoshinobu Inoue 				match++;
153182cd038dSYoshinobu Inoue 				r <<= 1;
153282cd038dSYoshinobu Inoue 			}
153382cd038dSYoshinobu Inoue 			break;
153482cd038dSYoshinobu Inoue 		} else
153582cd038dSYoshinobu Inoue 			match += 8;
153682cd038dSYoshinobu Inoue 	return match;
153782cd038dSYoshinobu Inoue }
153882cd038dSYoshinobu Inoue 
1539686cdd19SJun-ichiro itojun Hagino /* XXX: to be scope conscious */
154082cd038dSYoshinobu Inoue int
154182cd038dSYoshinobu Inoue in6_are_prefix_equal(p1, p2, len)
154282cd038dSYoshinobu Inoue 	struct in6_addr *p1, *p2;
154382cd038dSYoshinobu Inoue 	int len;
154482cd038dSYoshinobu Inoue {
154582cd038dSYoshinobu Inoue 	int bytelen, bitlen;
154682cd038dSYoshinobu Inoue 
154782cd038dSYoshinobu Inoue 	/* sanity check */
154882cd038dSYoshinobu Inoue 	if (0 > len || len > 128) {
154982cd038dSYoshinobu Inoue 		log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
155082cd038dSYoshinobu Inoue 		    len);
155182cd038dSYoshinobu Inoue 		return(0);
155282cd038dSYoshinobu Inoue 	}
155382cd038dSYoshinobu Inoue 
155482cd038dSYoshinobu Inoue 	bytelen = len / 8;
155582cd038dSYoshinobu Inoue 	bitlen = len % 8;
155682cd038dSYoshinobu Inoue 
155782cd038dSYoshinobu Inoue 	if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
155882cd038dSYoshinobu Inoue 		return(0);
155982cd038dSYoshinobu Inoue 	if (p1->s6_addr[bytelen] >> (8 - bitlen) !=
156082cd038dSYoshinobu Inoue 	    p2->s6_addr[bytelen] >> (8 - bitlen))
156182cd038dSYoshinobu Inoue 		return(0);
156282cd038dSYoshinobu Inoue 
156382cd038dSYoshinobu Inoue 	return(1);
156482cd038dSYoshinobu Inoue }
156582cd038dSYoshinobu Inoue 
156682cd038dSYoshinobu Inoue void
156782cd038dSYoshinobu Inoue in6_prefixlen2mask(maskp, len)
156882cd038dSYoshinobu Inoue 	struct in6_addr *maskp;
156982cd038dSYoshinobu Inoue 	int len;
157082cd038dSYoshinobu Inoue {
157182cd038dSYoshinobu Inoue 	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
157282cd038dSYoshinobu Inoue 	int bytelen, bitlen, i;
157382cd038dSYoshinobu Inoue 
157482cd038dSYoshinobu Inoue 	/* sanity check */
157582cd038dSYoshinobu Inoue 	if (0 > len || len > 128) {
157682cd038dSYoshinobu Inoue 		log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
157782cd038dSYoshinobu Inoue 		    len);
157882cd038dSYoshinobu Inoue 		return;
157982cd038dSYoshinobu Inoue 	}
158082cd038dSYoshinobu Inoue 
158182cd038dSYoshinobu Inoue 	bzero(maskp, sizeof(*maskp));
158282cd038dSYoshinobu Inoue 	bytelen = len / 8;
158382cd038dSYoshinobu Inoue 	bitlen = len % 8;
158482cd038dSYoshinobu Inoue 	for (i = 0; i < bytelen; i++)
158582cd038dSYoshinobu Inoue 		maskp->s6_addr[i] = 0xff;
158682cd038dSYoshinobu Inoue 	if (bitlen)
158782cd038dSYoshinobu Inoue 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
158882cd038dSYoshinobu Inoue }
158982cd038dSYoshinobu Inoue 
159082cd038dSYoshinobu Inoue /*
159182cd038dSYoshinobu Inoue  * return the best address out of the same scope
159282cd038dSYoshinobu Inoue  */
159382cd038dSYoshinobu Inoue struct in6_ifaddr *
1594686cdd19SJun-ichiro itojun Hagino in6_ifawithscope(oifp, dst)
1595686cdd19SJun-ichiro itojun Hagino 	register struct ifnet *oifp;
159682cd038dSYoshinobu Inoue 	register struct in6_addr *dst;
159782cd038dSYoshinobu Inoue {
1598686cdd19SJun-ichiro itojun Hagino 	int dst_scope =	in6_addrscope(dst), src_scope, best_scope = 0;
1599686cdd19SJun-ichiro itojun Hagino 	int blen = -1;
160082cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
1601686cdd19SJun-ichiro itojun Hagino 	struct ifnet *ifp;
1602686cdd19SJun-ichiro itojun Hagino 	struct in6_ifaddr *ifa_best = NULL;
160382cd038dSYoshinobu Inoue 
1604686cdd19SJun-ichiro itojun Hagino 	if (oifp == NULL) {
1605686cdd19SJun-ichiro itojun Hagino 		printf("in6_ifawithscope: output interface is not specified\n");
1606686cdd19SJun-ichiro itojun Hagino 		return(NULL);
1607686cdd19SJun-ichiro itojun Hagino 	}
160882cd038dSYoshinobu Inoue 
160982cd038dSYoshinobu Inoue 	/*
1610686cdd19SJun-ichiro itojun Hagino 	 * We search for all addresses on all interfaces from the beginning.
1611686cdd19SJun-ichiro itojun Hagino 	 * Comparing an interface with the outgoing interface will be done
1612686cdd19SJun-ichiro itojun Hagino 	 * only at the final stage of tiebreaking.
161382cd038dSYoshinobu Inoue 	 */
1614686cdd19SJun-ichiro itojun Hagino 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
1615686cdd19SJun-ichiro itojun Hagino 	{
1616686cdd19SJun-ichiro itojun Hagino 		/*
1617686cdd19SJun-ichiro itojun Hagino 		 * We can never take an address that breaks the scope zone
1618686cdd19SJun-ichiro itojun Hagino 		 * of the destination.
1619686cdd19SJun-ichiro itojun Hagino 		 */
1620686cdd19SJun-ichiro itojun Hagino 		if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
1621686cdd19SJun-ichiro itojun Hagino 			continue;
1622686cdd19SJun-ichiro itojun Hagino 
1623cfa1ca9dSYoshinobu Inoue 		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
162482cd038dSYoshinobu Inoue 		{
1625686cdd19SJun-ichiro itojun Hagino 			int tlen = -1, dscopecmp, bscopecmp, matchcmp;
1626686cdd19SJun-ichiro itojun Hagino 
162782cd038dSYoshinobu Inoue 			if (ifa->ifa_addr->sa_family != AF_INET6)
162882cd038dSYoshinobu Inoue 				continue;
162982cd038dSYoshinobu Inoue 
1630686cdd19SJun-ichiro itojun Hagino 			src_scope = in6_addrscope(IFA_IN6(ifa));
1631686cdd19SJun-ichiro itojun Hagino 
163282cd038dSYoshinobu Inoue 			/*
1633686cdd19SJun-ichiro itojun Hagino 			 * Don't use an address before completing DAD
1634686cdd19SJun-ichiro itojun Hagino 			 * nor a duplicated address.
163582cd038dSYoshinobu Inoue 			 */
1636686cdd19SJun-ichiro itojun Hagino 			if (((struct in6_ifaddr *)ifa)->ia6_flags &
1637686cdd19SJun-ichiro itojun Hagino 			    IN6_IFF_NOTREADY)
1638686cdd19SJun-ichiro itojun Hagino 				continue;
1639686cdd19SJun-ichiro itojun Hagino 
1640686cdd19SJun-ichiro itojun Hagino 			/* XXX: is there any case to allow anycasts? */
1641686cdd19SJun-ichiro itojun Hagino 			if (((struct in6_ifaddr *)ifa)->ia6_flags &
1642686cdd19SJun-ichiro itojun Hagino 			    IN6_IFF_ANYCAST)
1643686cdd19SJun-ichiro itojun Hagino 				continue;
1644686cdd19SJun-ichiro itojun Hagino 
1645686cdd19SJun-ichiro itojun Hagino 			if (((struct in6_ifaddr *)ifa)->ia6_flags &
1646686cdd19SJun-ichiro itojun Hagino 			    IN6_IFF_DETACHED)
1647686cdd19SJun-ichiro itojun Hagino 				continue;
1648686cdd19SJun-ichiro itojun Hagino 
1649686cdd19SJun-ichiro itojun Hagino 			/*
1650686cdd19SJun-ichiro itojun Hagino 			 * If this is the first address we find,
1651686cdd19SJun-ichiro itojun Hagino 			 * keep it anyway.
1652686cdd19SJun-ichiro itojun Hagino 			 */
1653686cdd19SJun-ichiro itojun Hagino 			if (ifa_best == NULL)
1654686cdd19SJun-ichiro itojun Hagino 				goto replace;
1655686cdd19SJun-ichiro itojun Hagino 
1656686cdd19SJun-ichiro itojun Hagino 			/*
1657686cdd19SJun-ichiro itojun Hagino 			 * ifa_best is never NULL beyond this line except
1658686cdd19SJun-ichiro itojun Hagino 			 * within the block labeled "replace".
1659686cdd19SJun-ichiro itojun Hagino 			 */
1660686cdd19SJun-ichiro itojun Hagino 
1661686cdd19SJun-ichiro itojun Hagino 			/*
1662686cdd19SJun-ichiro itojun Hagino 			 * If ifa_best has a smaller scope than dst and
1663686cdd19SJun-ichiro itojun Hagino 			 * the current address has a larger one than
1664686cdd19SJun-ichiro itojun Hagino 			 * (or equal to) dst, always replace ifa_best.
1665686cdd19SJun-ichiro itojun Hagino 			 * Also, if the current address has a smaller scope
1666686cdd19SJun-ichiro itojun Hagino 			 * than dst, ignore it unless ifa_best also has a
1667686cdd19SJun-ichiro itojun Hagino 			 * smaller scope.
1668686cdd19SJun-ichiro itojun Hagino 			 */
1669686cdd19SJun-ichiro itojun Hagino 			if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
1670686cdd19SJun-ichiro itojun Hagino 			    IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
1671686cdd19SJun-ichiro itojun Hagino 				goto replace;
1672686cdd19SJun-ichiro itojun Hagino 			if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
1673686cdd19SJun-ichiro itojun Hagino 			    IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
1674686cdd19SJun-ichiro itojun Hagino 				continue;
1675686cdd19SJun-ichiro itojun Hagino 
1676686cdd19SJun-ichiro itojun Hagino 			/*
1677686cdd19SJun-ichiro itojun Hagino 			 * A deprecated address SHOULD NOT be used in new
1678686cdd19SJun-ichiro itojun Hagino 			 * communications if an alternate (non-deprecated)
1679686cdd19SJun-ichiro itojun Hagino 			 * address is available and has sufficient scope.
1680686cdd19SJun-ichiro itojun Hagino 			 * RFC 2462, Section 5.5.4.
1681686cdd19SJun-ichiro itojun Hagino 			 */
1682686cdd19SJun-ichiro itojun Hagino 			if (((struct in6_ifaddr *)ifa)->ia6_flags &
1683686cdd19SJun-ichiro itojun Hagino 			    IN6_IFF_DEPRECATED) {
1684686cdd19SJun-ichiro itojun Hagino 				/*
1685686cdd19SJun-ichiro itojun Hagino 				 * Ignore any deprecated addresses if
1686686cdd19SJun-ichiro itojun Hagino 				 * specified by configuration.
1687686cdd19SJun-ichiro itojun Hagino 				 */
1688686cdd19SJun-ichiro itojun Hagino 				if (!ip6_use_deprecated)
1689686cdd19SJun-ichiro itojun Hagino 					continue;
1690686cdd19SJun-ichiro itojun Hagino 
1691686cdd19SJun-ichiro itojun Hagino 				/*
1692686cdd19SJun-ichiro itojun Hagino 				 * If we have already found a non-deprecated
1693686cdd19SJun-ichiro itojun Hagino 				 * candidate, just ignore deprecated addresses.
1694686cdd19SJun-ichiro itojun Hagino 				 */
1695686cdd19SJun-ichiro itojun Hagino 				if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
1696686cdd19SJun-ichiro itojun Hagino 				    == 0)
1697686cdd19SJun-ichiro itojun Hagino 					continue;
1698686cdd19SJun-ichiro itojun Hagino 			}
1699686cdd19SJun-ichiro itojun Hagino 
1700686cdd19SJun-ichiro itojun Hagino 			/*
1701686cdd19SJun-ichiro itojun Hagino 			 * A non-deprecated address is always preferred
1702686cdd19SJun-ichiro itojun Hagino 			 * to a deprecated one regardless of scopes and
1703686cdd19SJun-ichiro itojun Hagino 			 * address matching.
1704686cdd19SJun-ichiro itojun Hagino 			 */
1705686cdd19SJun-ichiro itojun Hagino 			if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
1706686cdd19SJun-ichiro itojun Hagino 			    (((struct in6_ifaddr *)ifa)->ia6_flags &
1707686cdd19SJun-ichiro itojun Hagino 			     IN6_IFF_DEPRECATED) == 0)
1708686cdd19SJun-ichiro itojun Hagino 				goto replace;
1709686cdd19SJun-ichiro itojun Hagino 
1710686cdd19SJun-ichiro itojun Hagino 			/*
1711686cdd19SJun-ichiro itojun Hagino 			 * At this point, we have two cases:
1712686cdd19SJun-ichiro itojun Hagino 			 * 1. we are looking at a non-deprecated address,
1713686cdd19SJun-ichiro itojun Hagino 			 *    and ifa_best is also non-deprecated.
1714686cdd19SJun-ichiro itojun Hagino 			 * 2. we are looking at a deprecated address,
1715686cdd19SJun-ichiro itojun Hagino 			 *    and ifa_best is also deprecated.
1716686cdd19SJun-ichiro itojun Hagino 			 * Also, we do not have to consider a case where
1717686cdd19SJun-ichiro itojun Hagino 			 * the scope of if_best is larger(smaller) than dst and
1718686cdd19SJun-ichiro itojun Hagino 			 * the scope of the current address is smaller(larger)
1719686cdd19SJun-ichiro itojun Hagino 			 * than dst. Such a case has already been covered.
1720686cdd19SJun-ichiro itojun Hagino 			 * Tiebreaking is done according to the following
1721686cdd19SJun-ichiro itojun Hagino 			 * items:
1722686cdd19SJun-ichiro itojun Hagino 			 * - the scope comparison between the address and
1723686cdd19SJun-ichiro itojun Hagino 			 *   dst (dscopecmp)
1724686cdd19SJun-ichiro itojun Hagino 			 * - the scope comparison between the address and
1725686cdd19SJun-ichiro itojun Hagino 			 *   ifa_best (bscopecmp)
1726686cdd19SJun-ichiro itojun Hagino 			 * - if the address match dst longer than ifa_best
1727686cdd19SJun-ichiro itojun Hagino 			 *   (matchcmp)
1728686cdd19SJun-ichiro itojun Hagino 			 * - if the address is on the outgoing I/F (outI/F)
1729686cdd19SJun-ichiro itojun Hagino 			 *
1730686cdd19SJun-ichiro itojun Hagino 			 * Roughly speaking, the selection policy is
1731686cdd19SJun-ichiro itojun Hagino 			 * - the most important item is scope. The same scope
1732686cdd19SJun-ichiro itojun Hagino 			 *   is best. Then search for a larger scope.
1733686cdd19SJun-ichiro itojun Hagino 			 *   Smaller scopes are the last resort.
1734686cdd19SJun-ichiro itojun Hagino 			 * - A deprecated address is chosen only when we have
1735686cdd19SJun-ichiro itojun Hagino 			 *   no address that has an enough scope, but is
1736686cdd19SJun-ichiro itojun Hagino 			 *   prefered to any addresses of smaller scopes.
1737686cdd19SJun-ichiro itojun Hagino 			 * - Longest address match against dst is considered
1738686cdd19SJun-ichiro itojun Hagino 			 *   only for addresses that has the same scope of dst.
1739686cdd19SJun-ichiro itojun Hagino 			 * - If there is no other reasons to choose one,
1740686cdd19SJun-ichiro itojun Hagino 			 *   addresses on the outgoing I/F are preferred.
1741686cdd19SJun-ichiro itojun Hagino 			 *
1742686cdd19SJun-ichiro itojun Hagino 			 * The precise decision table is as follows:
1743686cdd19SJun-ichiro itojun Hagino 			 * dscopecmp bscopecmp matchcmp outI/F | replace?
1744686cdd19SJun-ichiro itojun Hagino 			 *    !equal     equal      N/A    Yes |      Yes (1)
1745686cdd19SJun-ichiro itojun Hagino 			 *    !equal     equal      N/A     No |       No (2)
1746686cdd19SJun-ichiro itojun Hagino 			 *    larger    larger      N/A    N/A |       No (3)
1747686cdd19SJun-ichiro itojun Hagino 			 *    larger   smaller      N/A    N/A |      Yes (4)
1748686cdd19SJun-ichiro itojun Hagino 			 *   smaller    larger      N/A    N/A |      Yes (5)
1749686cdd19SJun-ichiro itojun Hagino 			 *   smaller   smaller      N/A    N/A |       No (6)
1750686cdd19SJun-ichiro itojun Hagino 			 *     equal   smaller      N/A    N/A |      Yes (7)
1751686cdd19SJun-ichiro itojun Hagino 			 *     equal    larger       (already done)
1752686cdd19SJun-ichiro itojun Hagino 			 *     equal     equal   larger    N/A |      Yes (8)
1753686cdd19SJun-ichiro itojun Hagino 			 *     equal     equal  smaller    N/A |       No (9)
1754686cdd19SJun-ichiro itojun Hagino 			 *     equal     equal    equal    Yes |      Yes (a)
1755686cdd19SJun-ichiro itojun Hagino 			 *     eaual     eqaul    equal     No |       No (b)
1756686cdd19SJun-ichiro itojun Hagino 			 */
1757686cdd19SJun-ichiro itojun Hagino 			dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
1758686cdd19SJun-ichiro itojun Hagino 			bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
1759686cdd19SJun-ichiro itojun Hagino 
1760686cdd19SJun-ichiro itojun Hagino 			if (dscopecmp && bscopecmp == 0) {
1761686cdd19SJun-ichiro itojun Hagino 				if (oifp == ifp) /* (1) */
1762686cdd19SJun-ichiro itojun Hagino 					goto replace;
1763686cdd19SJun-ichiro itojun Hagino 				continue; /* (2) */
1764686cdd19SJun-ichiro itojun Hagino 			}
1765686cdd19SJun-ichiro itojun Hagino 			if (dscopecmp > 0) {
1766686cdd19SJun-ichiro itojun Hagino 				if (bscopecmp > 0) /* (3) */
1767686cdd19SJun-ichiro itojun Hagino 					continue;
1768686cdd19SJun-ichiro itojun Hagino 				goto replace; /* (4) */
1769686cdd19SJun-ichiro itojun Hagino 			}
1770686cdd19SJun-ichiro itojun Hagino 			if (dscopecmp < 0) {
1771686cdd19SJun-ichiro itojun Hagino 				if (bscopecmp > 0) /* (5) */
1772686cdd19SJun-ichiro itojun Hagino 					goto replace;
1773686cdd19SJun-ichiro itojun Hagino 				continue; /* (6) */
1774686cdd19SJun-ichiro itojun Hagino 			}
1775686cdd19SJun-ichiro itojun Hagino 
1776686cdd19SJun-ichiro itojun Hagino 			/* now dscopecmp must be 0 */
1777686cdd19SJun-ichiro itojun Hagino 			if (bscopecmp < 0)
1778686cdd19SJun-ichiro itojun Hagino 				goto replace; /* (7) */
1779686cdd19SJun-ichiro itojun Hagino 
1780686cdd19SJun-ichiro itojun Hagino 			/*
1781686cdd19SJun-ichiro itojun Hagino 			 * At last both dscopecmp and bscopecmp must be 0.
1782686cdd19SJun-ichiro itojun Hagino 			 * We need address matching against dst for
1783686cdd19SJun-ichiro itojun Hagino 			 * tiebreaking.
1784686cdd19SJun-ichiro itojun Hagino 			 */
178582cd038dSYoshinobu Inoue 			tlen = in6_matchlen(IFA_IN6(ifa), dst);
1786686cdd19SJun-ichiro itojun Hagino 			matchcmp = tlen - blen;
1787686cdd19SJun-ichiro itojun Hagino 			if (matchcmp > 0) /* (8) */
1788686cdd19SJun-ichiro itojun Hagino 				goto replace;
1789686cdd19SJun-ichiro itojun Hagino 			if (matchcmp < 0) /* (9) */
1790686cdd19SJun-ichiro itojun Hagino 				continue;
1791686cdd19SJun-ichiro itojun Hagino 			if (oifp == ifp) /* (a) */
1792686cdd19SJun-ichiro itojun Hagino 				goto replace;
1793686cdd19SJun-ichiro itojun Hagino 			continue; /* (b) */
179482cd038dSYoshinobu Inoue 
1795686cdd19SJun-ichiro itojun Hagino 		  replace:
1796686cdd19SJun-ichiro itojun Hagino 			ifa_best = (struct in6_ifaddr *)ifa;
1797686cdd19SJun-ichiro itojun Hagino 			blen = tlen >= 0 ? tlen :
1798686cdd19SJun-ichiro itojun Hagino 				in6_matchlen(IFA_IN6(ifa), dst);
1799686cdd19SJun-ichiro itojun Hagino 			best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
180082cd038dSYoshinobu Inoue 		}
180182cd038dSYoshinobu Inoue 	}
180282cd038dSYoshinobu Inoue 
1803686cdd19SJun-ichiro itojun Hagino 	/* count statistics for future improvements */
1804686cdd19SJun-ichiro itojun Hagino 	if (ifa_best == NULL)
1805686cdd19SJun-ichiro itojun Hagino 		ip6stat.ip6s_sources_none++;
1806686cdd19SJun-ichiro itojun Hagino 	else {
1807686cdd19SJun-ichiro itojun Hagino 		if (oifp == ifa_best->ia_ifp)
1808686cdd19SJun-ichiro itojun Hagino 			ip6stat.ip6s_sources_sameif[best_scope]++;
1809686cdd19SJun-ichiro itojun Hagino 		else
1810686cdd19SJun-ichiro itojun Hagino 			ip6stat.ip6s_sources_otherif[best_scope]++;
1811686cdd19SJun-ichiro itojun Hagino 
1812686cdd19SJun-ichiro itojun Hagino 		if (best_scope == dst_scope)
1813686cdd19SJun-ichiro itojun Hagino 			ip6stat.ip6s_sources_samescope[best_scope]++;
1814686cdd19SJun-ichiro itojun Hagino 		else
1815686cdd19SJun-ichiro itojun Hagino 			ip6stat.ip6s_sources_otherscope[best_scope]++;
1816686cdd19SJun-ichiro itojun Hagino 
1817686cdd19SJun-ichiro itojun Hagino 		if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
1818686cdd19SJun-ichiro itojun Hagino 			ip6stat.ip6s_sources_deprecated[best_scope]++;
1819836b116aSYoshinobu Inoue 	}
1820836b116aSYoshinobu Inoue 
1821686cdd19SJun-ichiro itojun Hagino 	return(ifa_best);
182282cd038dSYoshinobu Inoue }
182382cd038dSYoshinobu Inoue 
182482cd038dSYoshinobu Inoue /*
182582cd038dSYoshinobu Inoue  * return the best address out of the same scope. if no address was
182682cd038dSYoshinobu Inoue  * found, return the first valid address from designated IF.
182782cd038dSYoshinobu Inoue  */
182882cd038dSYoshinobu Inoue struct in6_ifaddr *
182982cd038dSYoshinobu Inoue in6_ifawithifp(ifp, dst)
183082cd038dSYoshinobu Inoue 	register struct ifnet *ifp;
183182cd038dSYoshinobu Inoue 	register struct in6_addr *dst;
183282cd038dSYoshinobu Inoue {
183382cd038dSYoshinobu Inoue 	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
183482cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
183582cd038dSYoshinobu Inoue 	struct in6_ifaddr *besta = 0;
183682cd038dSYoshinobu Inoue 	struct in6_ifaddr *dep[2];	/*last-resort: deprecated*/
183782cd038dSYoshinobu Inoue 
183882cd038dSYoshinobu Inoue 	dep[0] = dep[1] = NULL;
183982cd038dSYoshinobu Inoue 
184082cd038dSYoshinobu Inoue 	/*
184182cd038dSYoshinobu Inoue 	 * We first look for addresses in the same scope.
184282cd038dSYoshinobu Inoue 	 * If there is one, return it.
184382cd038dSYoshinobu Inoue 	 * If two or more, return one which matches the dst longest.
184482cd038dSYoshinobu Inoue 	 * If none, return one of global addresses assigned other ifs.
184582cd038dSYoshinobu Inoue 	 */
1846cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
184782cd038dSYoshinobu Inoue 	{
184882cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
184982cd038dSYoshinobu Inoue 			continue;
185082cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
185182cd038dSYoshinobu Inoue 			continue; /* XXX: is there any case to allow anycast? */
185282cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
185382cd038dSYoshinobu Inoue 			continue; /* don't use this interface */
185482cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
185582cd038dSYoshinobu Inoue 			continue;
185682cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
185782cd038dSYoshinobu Inoue 			if (ip6_use_deprecated)
185882cd038dSYoshinobu Inoue 				dep[0] = (struct in6_ifaddr *)ifa;
185982cd038dSYoshinobu Inoue 			continue;
186082cd038dSYoshinobu Inoue 		}
186182cd038dSYoshinobu Inoue 
186282cd038dSYoshinobu Inoue 		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
186382cd038dSYoshinobu Inoue 			/*
186482cd038dSYoshinobu Inoue 			 * call in6_matchlen() as few as possible
186582cd038dSYoshinobu Inoue 			 */
186682cd038dSYoshinobu Inoue 			if (besta) {
186782cd038dSYoshinobu Inoue 				if (blen == -1)
186882cd038dSYoshinobu Inoue 					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
186982cd038dSYoshinobu Inoue 				tlen = in6_matchlen(IFA_IN6(ifa), dst);
187082cd038dSYoshinobu Inoue 				if (tlen > blen) {
187182cd038dSYoshinobu Inoue 					blen = tlen;
187282cd038dSYoshinobu Inoue 					besta = (struct in6_ifaddr *)ifa;
187382cd038dSYoshinobu Inoue 				}
187482cd038dSYoshinobu Inoue 			} else
187582cd038dSYoshinobu Inoue 				besta = (struct in6_ifaddr *)ifa;
187682cd038dSYoshinobu Inoue 		}
187782cd038dSYoshinobu Inoue 	}
187882cd038dSYoshinobu Inoue 	if (besta)
187982cd038dSYoshinobu Inoue 		return(besta);
188082cd038dSYoshinobu Inoue 
1881cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
188282cd038dSYoshinobu Inoue 	{
188382cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
188482cd038dSYoshinobu Inoue 			continue;
188582cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
188682cd038dSYoshinobu Inoue 			continue; /* XXX: is there any case to allow anycast? */
188782cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
188882cd038dSYoshinobu Inoue 			continue; /* don't use this interface */
188982cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
189082cd038dSYoshinobu Inoue 			continue;
189182cd038dSYoshinobu Inoue 		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
189282cd038dSYoshinobu Inoue 			if (ip6_use_deprecated)
189382cd038dSYoshinobu Inoue 				dep[1] = (struct in6_ifaddr *)ifa;
189482cd038dSYoshinobu Inoue 			continue;
189582cd038dSYoshinobu Inoue 		}
189682cd038dSYoshinobu Inoue 
189782cd038dSYoshinobu Inoue 		return (struct in6_ifaddr *)ifa;
189882cd038dSYoshinobu Inoue 	}
189982cd038dSYoshinobu Inoue 
190082cd038dSYoshinobu Inoue 	/* use the last-resort values, that are, deprecated addresses */
190182cd038dSYoshinobu Inoue 	if (dep[0])
190282cd038dSYoshinobu Inoue 		return dep[0];
190382cd038dSYoshinobu Inoue 	if (dep[1])
190482cd038dSYoshinobu Inoue 		return dep[1];
190582cd038dSYoshinobu Inoue 
190682cd038dSYoshinobu Inoue 	return NULL;
190782cd038dSYoshinobu Inoue }
190882cd038dSYoshinobu Inoue 
190982cd038dSYoshinobu Inoue /*
191082cd038dSYoshinobu Inoue  * perform DAD when interface becomes IFF_UP.
191182cd038dSYoshinobu Inoue  */
191282cd038dSYoshinobu Inoue void
191382cd038dSYoshinobu Inoue in6_if_up(ifp)
191482cd038dSYoshinobu Inoue 	struct ifnet *ifp;
191582cd038dSYoshinobu Inoue {
191682cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
191782cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia;
191882cd038dSYoshinobu Inoue 	int dad_delay;		/* delay ticks before DAD output */
191982cd038dSYoshinobu Inoue 
1920686cdd19SJun-ichiro itojun Hagino 	/*
1921686cdd19SJun-ichiro itojun Hagino 	 * special cases, like 6to4, are handled in in6_ifattach
1922686cdd19SJun-ichiro itojun Hagino 	 */
1923686cdd19SJun-ichiro itojun Hagino 	in6_ifattach(ifp, NULL);
192482cd038dSYoshinobu Inoue 
192582cd038dSYoshinobu Inoue 	dad_delay = 0;
1926cfa1ca9dSYoshinobu Inoue 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
192782cd038dSYoshinobu Inoue 	{
192882cd038dSYoshinobu Inoue 		if (ifa->ifa_addr->sa_family != AF_INET6)
192982cd038dSYoshinobu Inoue 			continue;
193082cd038dSYoshinobu Inoue 		ia = (struct in6_ifaddr *)ifa;
193182cd038dSYoshinobu Inoue 		if (ia->ia6_flags & IN6_IFF_TENTATIVE)
193282cd038dSYoshinobu Inoue 			nd6_dad_start(ifa, &dad_delay);
193382cd038dSYoshinobu Inoue 	}
193482cd038dSYoshinobu Inoue }
193582cd038dSYoshinobu Inoue 
193682cd038dSYoshinobu Inoue /*
193782cd038dSYoshinobu Inoue  * Calculate max IPv6 MTU through all the interfaces and store it
193882cd038dSYoshinobu Inoue  * to in6_maxmtu.
193982cd038dSYoshinobu Inoue  */
194082cd038dSYoshinobu Inoue void
194182cd038dSYoshinobu Inoue in6_setmaxmtu()
194282cd038dSYoshinobu Inoue {
194382cd038dSYoshinobu Inoue 	unsigned long maxmtu = 0;
194482cd038dSYoshinobu Inoue 	struct ifnet *ifp;
194582cd038dSYoshinobu Inoue 
194682cd038dSYoshinobu Inoue 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
194782cd038dSYoshinobu Inoue 	{
194882cd038dSYoshinobu Inoue 		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
194982cd038dSYoshinobu Inoue 		    nd_ifinfo[ifp->if_index].linkmtu > maxmtu)
195082cd038dSYoshinobu Inoue 			maxmtu =  nd_ifinfo[ifp->if_index].linkmtu;
195182cd038dSYoshinobu Inoue 	}
195282cd038dSYoshinobu Inoue 	if (maxmtu)	/* update only when maxmtu is positive */
195382cd038dSYoshinobu Inoue 		in6_maxmtu = maxmtu;
195482cd038dSYoshinobu Inoue }
195582cd038dSYoshinobu Inoue 
195682cd038dSYoshinobu Inoue /*
195782cd038dSYoshinobu Inoue  * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be
195882cd038dSYoshinobu Inoue  * v4 mapped addr or v4 compat addr
195982cd038dSYoshinobu Inoue  */
196082cd038dSYoshinobu Inoue void
196182cd038dSYoshinobu Inoue in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
196282cd038dSYoshinobu Inoue {
196382cd038dSYoshinobu Inoue 	bzero(sin, sizeof(*sin));
196482cd038dSYoshinobu Inoue 	sin->sin_len = sizeof(struct sockaddr_in);
196582cd038dSYoshinobu Inoue 	sin->sin_family = AF_INET;
196682cd038dSYoshinobu Inoue 	sin->sin_port = sin6->sin6_port;
196782cd038dSYoshinobu Inoue 	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
196882cd038dSYoshinobu Inoue }
196982cd038dSYoshinobu Inoue 
197082cd038dSYoshinobu Inoue /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
197182cd038dSYoshinobu Inoue void
197282cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
197382cd038dSYoshinobu Inoue {
197482cd038dSYoshinobu Inoue 	bzero(sin6, sizeof(*sin6));
197582cd038dSYoshinobu Inoue 	sin6->sin6_len = sizeof(struct sockaddr_in6);
197682cd038dSYoshinobu Inoue 	sin6->sin6_family = AF_INET6;
197782cd038dSYoshinobu Inoue 	sin6->sin6_port = sin->sin_port;
197882cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[0] = 0;
197982cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[1] = 0;
198082cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
198182cd038dSYoshinobu Inoue 	sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
198282cd038dSYoshinobu Inoue }
198382cd038dSYoshinobu Inoue 
198482cd038dSYoshinobu Inoue /* Convert sockaddr_in6 into sockaddr_in. */
198582cd038dSYoshinobu Inoue void
198682cd038dSYoshinobu Inoue in6_sin6_2_sin_in_sock(struct sockaddr *nam)
198782cd038dSYoshinobu Inoue {
198882cd038dSYoshinobu Inoue 	struct sockaddr_in *sin_p;
198982cd038dSYoshinobu Inoue 	struct sockaddr_in6 sin6;
199082cd038dSYoshinobu Inoue 
199182cd038dSYoshinobu Inoue 	/*
199282cd038dSYoshinobu Inoue 	 * Save original sockaddr_in6 addr and convert it
199382cd038dSYoshinobu Inoue 	 * to sockaddr_in.
199482cd038dSYoshinobu Inoue 	 */
199582cd038dSYoshinobu Inoue 	sin6 = *(struct sockaddr_in6 *)nam;
199682cd038dSYoshinobu Inoue 	sin_p = (struct sockaddr_in *)nam;
199782cd038dSYoshinobu Inoue 	in6_sin6_2_sin(sin_p, &sin6);
199882cd038dSYoshinobu Inoue }
199982cd038dSYoshinobu Inoue 
200082cd038dSYoshinobu Inoue /* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
200182cd038dSYoshinobu Inoue void
200282cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
200382cd038dSYoshinobu Inoue {
200482cd038dSYoshinobu Inoue 	struct sockaddr_in *sin_p;
200582cd038dSYoshinobu Inoue 	struct sockaddr_in6 *sin6_p;
200682cd038dSYoshinobu Inoue 
200782cd038dSYoshinobu Inoue 	MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
200882cd038dSYoshinobu Inoue 	       M_WAITOK);
200982cd038dSYoshinobu Inoue 	sin_p = (struct sockaddr_in *)*nam;
201082cd038dSYoshinobu Inoue 	in6_sin_2_v4mapsin6(sin_p, sin6_p);
201182cd038dSYoshinobu Inoue 	FREE(*nam, M_SONAME);
201282cd038dSYoshinobu Inoue 	*nam = (struct sockaddr *)sin6_p;
201382cd038dSYoshinobu Inoue }
2014