in6.c revision 53541
153541Sshin/*
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
2853541Sshin *
2953541Sshin * $FreeBSD: head/sys/netinet6/in6.c 53541 1999-11-22 02:45:11Z shin $
3053541Sshin */
3153541Sshin
3253541Sshin/*
3353541Sshin * Copyright (c) 1982, 1986, 1991, 1993
3453541Sshin *	The Regents of the University of California.  All rights reserved.
3553541Sshin *
3653541Sshin * Redistribution and use in source and binary forms, with or without
3753541Sshin * modification, are permitted provided that the following conditions
3853541Sshin * are met:
3953541Sshin * 1. Redistributions of source code must retain the above copyright
4053541Sshin *    notice, this list of conditions and the following disclaimer.
4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright
4253541Sshin *    notice, this list of conditions and the following disclaimer in the
4353541Sshin *    documentation and/or other materials provided with the distribution.
4453541Sshin * 3. All advertising materials mentioning features or use of this software
4553541Sshin *    must display the following acknowledgement:
4653541Sshin *	This product includes software developed by the University of
4753541Sshin *	California, Berkeley and its contributors.
4853541Sshin * 4. Neither the name of the University nor the names of its contributors
4953541Sshin *    may be used to endorse or promote products derived from this software
5053541Sshin *    without specific prior written permission.
5153541Sshin *
5253541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5353541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5453541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5553541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5653541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5753541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5853541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5953541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6053541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6153541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6253541Sshin * SUCH DAMAGE.
6353541Sshin *
6453541Sshin *	@(#)in.c	8.2 (Berkeley) 11/15/93
6553541Sshin */
6653541Sshin
6753541Sshin#include "opt_inet.h"
6853541Sshin
6953541Sshin#include <sys/param.h>
7053541Sshin#include <sys/errno.h>
7153541Sshin#include <sys/malloc.h>
7253541Sshin#include <sys/socket.h>
7353541Sshin#include <sys/socketvar.h>
7453541Sshin#include <sys/sockio.h>
7553541Sshin#include <sys/systm.h>
7653541Sshin#include <sys/proc.h>
7753541Sshin#include <sys/time.h>
7853541Sshin#include <sys/kernel.h>
7953541Sshin#include <sys/syslog.h>
8053541Sshin
8153541Sshin#include <net/if.h>
8253541Sshin#include <net/if_types.h>
8353541Sshin#include <net/route.h>
8453541Sshin/* #include "gif.h" */
8553541Sshin#if NGIF > 0
8653541Sshin#include <net/if_gif.h>
8753541Sshin#endif
8853541Sshin#include <net/if_dl.h>
8953541Sshin
9053541Sshin#include <netinet/in.h>
9153541Sshin#include <netinet/in_var.h>
9253541Sshin#include <netinet/if_ether.h>
9353541Sshin
9453541Sshin#include <netinet6/nd6.h>
9553541Sshin#include <netinet6/ip6.h>
9653541Sshin#include <netinet6/ip6_var.h>
9753541Sshin#include <netinet6/mld6_var.h>
9853541Sshin#include <netinet6/in6_ifattach.h>
9953541Sshin
10053541Sshin#include <net/net_osdep.h>
10153541Sshin
10253541SshinMALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address");
10353541Sshin
10453541Sshin/*
10553541Sshin * Definitions of some costant IP6 addresses.
10653541Sshin */
10753541Sshinconst struct	in6_addr in6addr_any = IN6ADDR_ANY_INIT;
10853541Sshinconst struct	in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
10953541Sshinconst struct	in6_addr in6addr_nodelocal_allnodes =
11053541Sshin	IN6ADDR_NODELOCAL_ALLNODES_INIT;
11153541Sshinconst struct	in6_addr in6addr_linklocal_allnodes =
11253541Sshin	IN6ADDR_LINKLOCAL_ALLNODES_INIT;
11353541Sshinconst struct	in6_addr in6addr_linklocal_allrouters =
11453541Sshin	IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
11553541Sshin
11653541Sshinconst struct	in6_addr in6mask0 = IN6MASK0;
11753541Sshinconst struct	in6_addr in6mask32 = IN6MASK32;
11853541Sshinconst struct	in6_addr in6mask64 = IN6MASK64;
11953541Sshinconst struct	in6_addr in6mask96 = IN6MASK96;
12053541Sshinconst struct	in6_addr in6mask128 = IN6MASK128;
12153541Sshin
12253541Sshinstatic int	in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
12353541Sshin	struct ifnet *, struct proc *));
12453541Sshinstruct	in6_multihead in6_multihead;	/* XXX BSS initialization */
12553541Sshin
12653541Sshin/*
12753541Sshin * Determine whether an IP6 address is in a reserved set of addresses
12853541Sshin * that may not be forwarded, or whether datagrams to that destination
12953541Sshin * may be forwarded.
13053541Sshin */
13153541Sshinint
13253541Sshinin6_canforward(src, dst)
13353541Sshin	struct	in6_addr *src, *dst;
13453541Sshin{
13553541Sshin	if (IN6_IS_ADDR_LINKLOCAL(src) ||
13653541Sshin	   IN6_IS_ADDR_LINKLOCAL(dst) ||
13753541Sshin	   IN6_IS_ADDR_MULTICAST(dst))
13853541Sshin		return(0);
13953541Sshin	return(1);
14053541Sshin}
14153541Sshin
14253541Sshin/*
14353541Sshin * Check if the loopback entry will be automatically generated.
14453541Sshin *   if 0 returned, will not be automatically generated.
14553541Sshin *   if 1 returned, will be automatically generated.
14653541Sshin */
14753541Sshinstatic int
14853541Sshinin6_is_ifloop_auto(struct ifaddr *ifa)
14953541Sshin{
15053541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s)
15153541Sshin	/*
15253541Sshin	 * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT),
15353541Sshin	 * or netmask is all0 or all1, then cloning will not happen,
15453541Sshin	 * then we can't rely on its loopback entry generation.
15553541Sshin	 */
15653541Sshin	if ((ifa->ifa_flags & RTF_CLONING) == 0 ||
15753541Sshin	    (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) ||
15853541Sshin	    (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6)
15953541Sshin	     &&
16053541Sshin	     IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr,
16153541Sshin				&in6mask128)) ||
16253541Sshin	    ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0)
16353541Sshin		return 0;
16453541Sshin	else
16553541Sshin		return 1;
16653541Sshin#undef SIN6
16753541Sshin}
16853541Sshin
16953541Sshin/*
17053541Sshin * Subroutine for in6_ifaddloop() and in6_ifremloop().
17153541Sshin * This routine does actual work.
17253541Sshin */
17353541Sshinstatic void
17453541Sshinin6_ifloop_request(int cmd, struct ifaddr *ifa)
17553541Sshin{
17653541Sshin	struct sockaddr_in6 lo_sa;
17753541Sshin	struct sockaddr_in6 all1_sa;
17853541Sshin	struct rtentry *nrt = NULL;
17953541Sshin
18053541Sshin	bzero(&lo_sa, sizeof(lo_sa));
18153541Sshin	bzero(&all1_sa, sizeof(all1_sa));
18253541Sshin	lo_sa.sin6_family = AF_INET6;
18353541Sshin	lo_sa.sin6_len = sizeof(struct sockaddr_in6);
18453541Sshin	all1_sa = lo_sa;
18553541Sshin	lo_sa.sin6_addr = in6addr_loopback;
18653541Sshin	all1_sa.sin6_addr = in6mask128;
18753541Sshin
18853541Sshin	/* So we add or remove static loopback entry, here. */
18953541Sshin	rtrequest(cmd, ifa->ifa_addr,
19053541Sshin		  (struct sockaddr *)&lo_sa,
19153541Sshin		  (struct sockaddr *)&all1_sa,
19253541Sshin		  RTF_UP|RTF_HOST, &nrt);
19353541Sshin
19453541Sshin	/*
19553541Sshin	 * Make sure rt_ifa be equal to IFA, the second argument of the
19653541Sshin	 * function.
19753541Sshin	 * We need this because when we refer rt_ifa->ia6_flags in ip6_input,
19853541Sshin	 * we assume that the rt_ifa points to the address instead of the
19953541Sshin	 * loopback address.
20053541Sshin	 */
20153541Sshin	if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
20253541Sshin		nrt->rt_ifa->ifa_refcnt--;
20353541Sshin		ifa->ifa_refcnt++;
20453541Sshin		nrt->rt_ifa = ifa;
20553541Sshin	}
20653541Sshin	if (nrt)
20753541Sshin		nrt->rt_refcnt--;
20853541Sshin}
20953541Sshin
21053541Sshin/*
21153541Sshin * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link).
21253541Sshin * Because, KAME needs loopback rtentry for ownaddr check in
21353541Sshin * ip6_input().
21453541Sshin */
21553541Sshinstatic void
21653541Sshinin6_ifaddloop(struct ifaddr *ifa)
21753541Sshin{
21853541Sshin	if (!in6_is_ifloop_auto(ifa)) {
21953541Sshin		struct rtentry *rt;
22053541Sshin
22153541Sshin		/* If there is no loopback entry, allocate one. */
22253541Sshin		rt = rtalloc1(ifa->ifa_addr, 0, 0);
22353541Sshin		if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
22453541Sshin			in6_ifloop_request(RTM_ADD, ifa);
22553541Sshin		if (rt)
22653541Sshin			rt->rt_refcnt--;
22753541Sshin	}
22853541Sshin}
22953541Sshin
23053541Sshin/*
23153541Sshin * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
23253541Sshin * if it exists.
23353541Sshin */
23453541Sshinstatic void
23553541Sshinin6_ifremloop(struct ifaddr *ifa)
23653541Sshin{
23753541Sshin	if (!in6_is_ifloop_auto(ifa)) {
23853541Sshin		struct in6_ifaddr *ia;
23953541Sshin		int ia_count = 0;
24053541Sshin
24153541Sshin		/* If only one ifa for the loopback entry, delete it. */
24253541Sshin		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
24353541Sshin			if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa),
24453541Sshin					       &ia->ia_addr.sin6_addr)) {
24553541Sshin				ia_count++;
24653541Sshin				if (ia_count > 1)
24753541Sshin					break;
24853541Sshin			}
24953541Sshin		}
25053541Sshin		if (ia_count == 1)
25153541Sshin			in6_ifloop_request(RTM_DELETE, ifa);
25253541Sshin	}
25353541Sshin}
25453541Sshin
25553541Sshin/*
25653541Sshin * Subroutine for in6_ifaddproxy() and in6_ifremproxy().
25753541Sshin * This routine does actual work.
25853541Sshin * call in6_addmulti() when cmd == 1.
25953541Sshin * call in6_delmulti() when cmd == 2.
26053541Sshin */
26153541Sshinstatic int
26253541Sshinin6_ifproxy_request(int cmd, struct in6_ifaddr *ia)
26353541Sshin{
26453541Sshin	int error = 0;
26553541Sshin
26653541Sshin	/*
26753541Sshin	 * If we have an IPv6 dstaddr on adding p2p interface,
26853541Sshin	 * join dstaddr's solicited multicast on necessary interface.
26953541Sshin	 */
27053541Sshin	if ((ia->ia_ifp->if_flags & IFF_POINTOPOINT) &&
27153541Sshin	    ia->ia_dstaddr.sin6_family == AF_INET6 &&
27253541Sshin	    !IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
27353541Sshin		struct in6_ifaddr *ia_lan;
27453541Sshin
27553541Sshin		/*
27653541Sshin		 * TODO: Join only on some specified interfaces by some
27753541Sshin		 * configuration.
27853541Sshin		 * Unsolicited Neighbor Advertisements will be also necessary.
27953541Sshin		 *
28053541Sshin		 * Now, join on interfaces which meets following.
28153541Sshin		 *   -IFF_BROADCAST and IFF_MULTICAST
28253541Sshin		 *    (NBMA is out of scope)
28353541Sshin		 *   -the prefix value is same as p2p dstaddr
28453541Sshin		 */
28553541Sshin		for (ia_lan = in6_ifaddr; ia_lan; ia_lan = ia_lan->ia_next) {
28653541Sshin			struct in6_addr llsol;
28753541Sshin
28853541Sshin			if ((ia_lan->ia_ifp->if_flags &
28953541Sshin			     (IFF_BROADCAST|IFF_MULTICAST)) !=
29053541Sshin			    (IFF_BROADCAST|IFF_MULTICAST))
29153541Sshin				continue;
29253541Sshin			if (!IN6_ARE_MASKED_ADDR_EQUAL(IA6_IN6(ia),
29353541Sshin						       IA6_IN6(ia_lan),
29453541Sshin						       IA6_MASKIN6(ia_lan)))
29553541Sshin				continue;
29653541Sshin			if (ia_lan->ia_ifp == ia->ia_ifp)
29753541Sshin				continue;
29853541Sshin
29953541Sshin			/* init llsol */
30053541Sshin			bzero(&llsol, sizeof(struct in6_addr));
30153541Sshin			llsol.s6_addr16[0] = htons(0xff02);
30253541Sshin			llsol.s6_addr16[1] = htons(ia_lan->ia_ifp->if_index);
30353541Sshin			llsol.s6_addr32[1] = 0;
30453541Sshin			llsol.s6_addr32[2] = htonl(1);
30553541Sshin			llsol.s6_addr32[3] =
30653541Sshin				ia->ia_dstaddr.sin6_addr.s6_addr32[3];
30753541Sshin			llsol.s6_addr8[12] = 0xff;
30853541Sshin
30953541Sshin			if (cmd == 1)
31053541Sshin				(void)in6_addmulti(&llsol,
31153541Sshin						   ia_lan->ia_ifp,
31253541Sshin						   &error);
31353541Sshin			else if (cmd == 2) {
31453541Sshin				struct in6_multi *in6m;
31553541Sshin
31653541Sshin				IN6_LOOKUP_MULTI(llsol,
31753541Sshin						 ia_lan->ia_ifp,
31853541Sshin						 in6m);
31953541Sshin				if (in6m)
32053541Sshin					in6_delmulti(in6m);
32153541Sshin			}
32253541Sshin		}
32353541Sshin	}
32453541Sshin	return error;
32553541Sshin}
32653541Sshin
32753541Sshinstatic int
32853541Sshinin6_ifaddproxy(struct in6_ifaddr *ia)
32953541Sshin{
33053541Sshin	return(in6_ifproxy_request(1, ia));
33153541Sshin}
33253541Sshin
33353541Sshinstatic void
33453541Sshinin6_ifremproxy(struct in6_ifaddr *ia)
33553541Sshin{
33653541Sshin	in6_ifproxy_request(2, ia);
33753541Sshin}
33853541Sshin
33953541Sshinint
34053541Sshinin6_ifindex2scopeid(idx)
34153541Sshin	int idx;
34253541Sshin{
34353541Sshin	struct ifnet *ifp;
34453541Sshin	struct ifaddr *ifa;
34553541Sshin	struct sockaddr_in6 *sin6;
34653541Sshin
34753541Sshin	if (idx < 0 || if_index < idx)
34853541Sshin		return -1;
34953541Sshin	ifp = ifindex2ifnet[idx];
35053541Sshin
35153541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
35253541Sshin	{
35353541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
35453541Sshin			continue;
35553541Sshin		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
35653541Sshin		if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
35753541Sshin			return sin6->sin6_scope_id & 0xffff;
35853541Sshin	}
35953541Sshin
36053541Sshin	return -1;
36153541Sshin}
36253541Sshin
36353541Sshinint
36453541Sshinin6_mask2len(mask)
36553541Sshin	struct in6_addr *mask;
36653541Sshin{
36753541Sshin	int x, y;
36853541Sshin
36953541Sshin	for (x = 0; x < sizeof(*mask); x++) {
37053541Sshin		if (mask->s6_addr8[x] != 0xff)
37153541Sshin			break;
37253541Sshin	}
37353541Sshin	y = 0;
37453541Sshin	if (x < sizeof(*mask)) {
37553541Sshin		for (y = 0; y < 8; y++) {
37653541Sshin			if ((mask->s6_addr8[x] & (0x80 >> y)) == 0)
37753541Sshin				break;
37853541Sshin		}
37953541Sshin	}
38053541Sshin	return x * 8 + y;
38153541Sshin}
38253541Sshin
38353541Sshinvoid
38453541Sshinin6_len2mask(mask, len)
38553541Sshin	struct in6_addr *mask;
38653541Sshin	int len;
38753541Sshin{
38853541Sshin	int i;
38953541Sshin
39053541Sshin	bzero(mask, sizeof(*mask));
39153541Sshin	for (i = 0; i < len / 8; i++)
39253541Sshin		mask->s6_addr8[i] = 0xff;
39353541Sshin	if (len % 8)
39453541Sshin		mask->s6_addr8[i] = (0xff00 >> (len % 8)) & 0xff;
39553541Sshin}
39653541Sshin
39753541Sshinint	in6_interfaces;		/* number of external internet interfaces */
39853541Sshin
39953541Sshin#define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
40053541Sshin#define ia62ifa(ia6)	((struct ifaddr *)(ia6))
40153541Sshin
40253541Sshinint
40353541Sshinin6_control(so, cmd, data, ifp, p)
40453541Sshin	struct	socket *so;
40553541Sshin	u_long cmd;
40653541Sshin	caddr_t	data;
40753541Sshin	struct ifnet *ifp;
40853541Sshin	struct proc *p;
40953541Sshin{
41053541Sshin	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
41153541Sshin	struct	in6_ifaddr *ia, *oia;
41253541Sshin	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
41353541Sshin	struct	sockaddr_in6 oldaddr, net;
41453541Sshin	int	error = 0, hostIsNew, prefixIsNew;
41553541Sshin	int privileged;
41653541Sshin
41753541Sshin	privileged = 0;
41853541Sshin	if (p && !suser(p))
41953541Sshin		privileged++;
42053541Sshin
42153541Sshin	/*
42253541Sshin	 * xxx should prevent processes for link-local addresses?
42353541Sshin	 */
42453541Sshin#if NGIF > 0
42553541Sshin	if (ifp && ifp->if_type == IFT_GIF) {
42653541Sshin		switch (cmd) {
42753541Sshin		case SIOCSIFPHYADDR_IN6:
42853541Sshin			if (!privileged)
42953541Sshin				return(EPERM);
43053541Sshin			/*fall through*/
43153541Sshin		case SIOCGIFPSRCADDR_IN6:
43253541Sshin		case SIOCGIFPDSTADDR_IN6:
43353541Sshin			return gif_ioctl(ifp, cmd, data);
43453541Sshin		}
43553541Sshin	}
43653541Sshin#endif
43753541Sshin
43853541Sshin	if (ifp == 0)
43953541Sshin		return(EOPNOTSUPP);
44053541Sshin
44153541Sshin	switch (cmd) {
44253541Sshin	case SIOCSNDFLUSH_IN6:
44353541Sshin	case SIOCSPFXFLUSH_IN6:
44453541Sshin	case SIOCSRTRFLUSH_IN6:
44553541Sshin		if (!privileged)
44653541Sshin			return(EPERM);
44753541Sshin		/*fall through*/
44853541Sshin	case SIOCGIFINFO_IN6:
44953541Sshin	case SIOCGDRLST_IN6:
45053541Sshin	case SIOCGPRLST_IN6:
45153541Sshin	case SIOCGNBRINFO_IN6:
45253541Sshin		return(nd6_ioctl(cmd, data, ifp));
45353541Sshin	}
45453541Sshin
45553541Sshin	switch (cmd) {
45653541Sshin	case SIOCSIFPREFIX_IN6:
45753541Sshin	case SIOCDIFPREFIX_IN6:
45853541Sshin	case SIOCAIFPREFIX_IN6:
45953541Sshin	case SIOCCIFPREFIX_IN6:
46053541Sshin	case SIOCSGIFPREFIX_IN6:
46153541Sshin		if (!privileged)
46253541Sshin			return(EPERM);
46353541Sshin		/*fall through*/
46453541Sshin	case SIOCGIFPREFIX_IN6:
46553541Sshin		return(in6_prefix_ioctl(so, cmd, data, ifp));
46653541Sshin	}
46753541Sshin
46853541Sshin	switch (cmd) {
46953541Sshin	case SIOCALIFADDR:
47053541Sshin	case SIOCDLIFADDR:
47153541Sshin		if (!privileged)
47253541Sshin			return(EPERM);
47353541Sshin		/*fall through*/
47453541Sshin	case SIOCGLIFADDR:
47553541Sshin		return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
47653541Sshin	}
47753541Sshin
47853541Sshin	/*
47953541Sshin	 * Find address for this interface, if it exists.
48053541Sshin	 */
48153541Sshin	{
48253541Sshin
48353541Sshin		struct sockaddr_in6 *sa6 =
48453541Sshin			(struct sockaddr_in6 *)&ifra->ifra_addr;
48553541Sshin
48653541Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
48753541Sshin			if (sa6->sin6_addr.s6_addr16[1] == 0) {
48853541Sshin				/* interface ID is not embedded by the user */
48953541Sshin				sa6->sin6_addr.s6_addr16[1] =
49053541Sshin					htons(ifp->if_index);
49153541Sshin			} else
49253541Sshin				if (sa6->sin6_addr.s6_addr16[1] !=
49353541Sshin				    htons(ifp->if_index))
49453541Sshin					return(EINVAL);	/* ifid is contradict */
49553541Sshin			if (sa6->sin6_scope_id) {
49653541Sshin				if (sa6->sin6_scope_id !=
49753541Sshin				    (u_int32_t)ifp->if_index)
49853541Sshin					return(EINVAL);
49953541Sshin				sa6->sin6_scope_id = 0; /* XXX: good way? */
50053541Sshin			}
50153541Sshin		}
50253541Sshin	}
50353541Sshin 	ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
50453541Sshin
50553541Sshin	switch (cmd) {
50653541Sshin
50753541Sshin	case SIOCDIFADDR_IN6:
50853541Sshin		if (ia == 0)
50953541Sshin			return(EADDRNOTAVAIL);
51053541Sshin		/* FALLTHROUGH */
51153541Sshin	case SIOCAIFADDR_IN6:
51253541Sshin	case SIOCSIFADDR_IN6:
51353541Sshin	case SIOCSIFNETMASK_IN6:
51453541Sshin	case SIOCSIFDSTADDR_IN6:
51553541Sshin		if (!privileged)
51653541Sshin			return(EPERM);
51753541Sshin		if (ia == 0) {
51853541Sshin			ia = (struct in6_ifaddr *)
51953541Sshin				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
52053541Sshin			if (ia == NULL)
52153541Sshin				return (ENOBUFS);
52253541Sshin			bzero((caddr_t)ia, sizeof(*ia));
52353541Sshin			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
52453541Sshin			ia->ia_ifa.ifa_dstaddr
52553541Sshin				= (struct sockaddr *)&ia->ia_dstaddr;
52653541Sshin			ia->ia_ifa.ifa_netmask
52753541Sshin				= (struct sockaddr *)&ia->ia_prefixmask;
52853541Sshin
52953541Sshin			ia->ia_ifp = ifp;
53053541Sshin			if ((oia = in6_ifaddr) != NULL) {
53153541Sshin				for ( ; oia->ia_next; oia = oia->ia_next)
53253541Sshin					continue;
53353541Sshin				oia->ia_next = ia;
53453541Sshin			} else
53553541Sshin				in6_ifaddr = ia;
53653541Sshin			TAILQ_INSERT_TAIL(&ifp->if_addrlist,
53753541Sshin				(struct ifaddr *)ia, ifa_list);
53853541Sshin			if ((ifp->if_flags & IFF_LOOPBACK) == 0)
53953541Sshin				in6_interfaces++;	/*XXX*/
54053541Sshin		}
54153541Sshin
54253541Sshin		if (cmd == SIOCAIFADDR_IN6) {
54353541Sshin			/* sanity for overflow - beware unsigned */
54453541Sshin			struct in6_addrlifetime *lt;
54553541Sshin			lt = &ifra->ifra_lifetime;
54653541Sshin			if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
54753541Sshin			 && lt->ia6t_vltime + time_second < time_second) {
54853541Sshin				return EINVAL;
54953541Sshin			}
55053541Sshin			if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
55153541Sshin			 && lt->ia6t_pltime + time_second < time_second) {
55253541Sshin				return EINVAL;
55353541Sshin			}
55453541Sshin		}
55553541Sshin		break;
55653541Sshin
55753541Sshin	case SIOCGIFADDR_IN6:
55853541Sshin		/* This interface is basically deprecated. use SIOCGIFCONF. */
55953541Sshin		/* fall through */
56053541Sshin	case SIOCGIFAFLAG_IN6:
56153541Sshin	case SIOCGIFNETMASK_IN6:
56253541Sshin	case SIOCGIFDSTADDR_IN6:
56353541Sshin	case SIOCGIFALIFETIME_IN6:
56453541Sshin		/* must think again about its semantics */
56553541Sshin		if (ia == 0)
56653541Sshin			return(EADDRNOTAVAIL);
56753541Sshin		break;
56853541Sshin	case SIOCSIFALIFETIME_IN6:
56953541Sshin	    {
57053541Sshin		struct in6_addrlifetime *lt;
57153541Sshin
57253541Sshin		if (!privileged)
57353541Sshin			return(EPERM);
57453541Sshin		if (ia == 0)
57553541Sshin			return(EADDRNOTAVAIL);
57653541Sshin		/* sanity for overflow - beware unsigned */
57753541Sshin		lt = &ifr->ifr_ifru.ifru_lifetime;
57853541Sshin		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
57953541Sshin		 && lt->ia6t_vltime + time_second < time_second) {
58053541Sshin			return EINVAL;
58153541Sshin		}
58253541Sshin		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
58353541Sshin		 && lt->ia6t_pltime + time_second < time_second) {
58453541Sshin			return EINVAL;
58553541Sshin		}
58653541Sshin		break;
58753541Sshin	    }
58853541Sshin	}
58953541Sshin
59053541Sshin	switch (cmd) {
59153541Sshin
59253541Sshin	case SIOCGIFADDR_IN6:
59353541Sshin		ifr->ifr_addr = ia->ia_addr;
59453541Sshin		break;
59553541Sshin
59653541Sshin	case SIOCGIFDSTADDR_IN6:
59753541Sshin		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
59853541Sshin			return(EINVAL);
59953541Sshin		ifr->ifr_dstaddr = ia->ia_dstaddr;
60053541Sshin		break;
60153541Sshin
60253541Sshin	case SIOCGIFNETMASK_IN6:
60353541Sshin		ifr->ifr_addr = ia->ia_prefixmask;
60453541Sshin		break;
60553541Sshin
60653541Sshin	case SIOCGIFAFLAG_IN6:
60753541Sshin		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
60853541Sshin		break;
60953541Sshin
61053541Sshin	case SIOCGIFSTAT_IN6:
61153541Sshin		if (ifp == NULL)
61253541Sshin			return EINVAL;
61353541Sshin		if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax
61453541Sshin		 || in6_ifstat[ifp->if_index] == NULL) {
61553541Sshin			/* return EAFNOSUPPORT? */
61653541Sshin			bzero(&ifr->ifr_ifru.ifru_stat,
61753541Sshin				sizeof(ifr->ifr_ifru.ifru_stat));
61853541Sshin		} else
61953541Sshin			ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];
62053541Sshin		break;
62153541Sshin
62253541Sshin	case SIOCGIFSTAT_ICMP6:
62353541Sshin		if (ifp == NULL)
62453541Sshin			return EINVAL;
62553541Sshin		if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||
62653541Sshin		    icmp6_ifstat[ifp->if_index] == NULL) {
62753541Sshin			/* return EAFNOSUPPORT? */
62853541Sshin			bzero(&ifr->ifr_ifru.ifru_stat,
62953541Sshin				sizeof(ifr->ifr_ifru.ifru_icmp6stat));
63053541Sshin		} else
63153541Sshin			ifr->ifr_ifru.ifru_icmp6stat =
63253541Sshin				*icmp6_ifstat[ifp->if_index];
63353541Sshin		break;
63453541Sshin
63553541Sshin	case SIOCSIFDSTADDR_IN6:
63653541Sshin		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
63753541Sshin			return(EINVAL);
63853541Sshin		oldaddr = ia->ia_dstaddr;
63953541Sshin		ia->ia_dstaddr = ifr->ifr_dstaddr;
64053541Sshin
64153541Sshin		/* link-local index check */
64253541Sshin		if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
64353541Sshin			if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
64453541Sshin				/* interface ID is not embedded by the user */
64553541Sshin				ia->ia_dstaddr.sin6_addr.s6_addr16[1]
64653541Sshin					= htons(ifp->if_index);
64753541Sshin			} else
64853541Sshin				if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
64953541Sshin				    htons(ifp->if_index)) {
65053541Sshin					ia->ia_dstaddr = oldaddr;
65153541Sshin					return(EINVAL);	/* ifid is contradict */
65253541Sshin				}
65353541Sshin		}
65453541Sshin
65553541Sshin		if (ifp->if_ioctl && (error = (ifp->if_ioctl)
65653541Sshin				      (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
65753541Sshin			ia->ia_dstaddr = oldaddr;
65853541Sshin			return(error);
65953541Sshin		}
66053541Sshin		if (ia->ia_flags & IFA_ROUTE) {
66153541Sshin			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
66253541Sshin			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
66353541Sshin			ia->ia_ifa.ifa_dstaddr =
66453541Sshin				(struct sockaddr *)&ia->ia_dstaddr;
66553541Sshin			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
66653541Sshin		}
66753541Sshin		break;
66853541Sshin
66953541Sshin	case SIOCGIFALIFETIME_IN6:
67053541Sshin		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
67153541Sshin		break;
67253541Sshin
67353541Sshin	case SIOCSIFALIFETIME_IN6:
67453541Sshin		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
67553541Sshin		/* for sanity */
67653541Sshin		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
67753541Sshin			ia->ia6_lifetime.ia6t_expire =
67853541Sshin				time_second + ia->ia6_lifetime.ia6t_vltime;
67953541Sshin		} else
68053541Sshin			ia->ia6_lifetime.ia6t_expire = 0;
68153541Sshin		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
68253541Sshin			ia->ia6_lifetime.ia6t_preferred =
68353541Sshin				time_second + ia->ia6_lifetime.ia6t_pltime;
68453541Sshin		} else
68553541Sshin			ia->ia6_lifetime.ia6t_preferred = 0;
68653541Sshin		break;
68753541Sshin
68853541Sshin	case SIOCSIFADDR_IN6:
68953541Sshin		return(in6_ifinit(ifp, ia, &ifr->ifr_addr, 1));
69053541Sshin
69153541Sshin	case SIOCSIFNETMASK_IN6:
69253541Sshin		ia->ia_prefixmask = ifr->ifr_addr;
69353541Sshin		bzero(&net, sizeof(net));
69453541Sshin		net.sin6_len = sizeof(struct sockaddr_in6);
69553541Sshin		net.sin6_family = AF_INET6;
69653541Sshin		net.sin6_port = htons(0);
69753541Sshin		net.sin6_flowinfo = htonl(0);
69853541Sshin		net.sin6_addr.s6_addr32[0]
69953541Sshin			= ia->ia_addr.sin6_addr.s6_addr32[0] &
70053541Sshin				ia->ia_prefixmask.sin6_addr.s6_addr32[0];
70153541Sshin		net.sin6_addr.s6_addr32[1]
70253541Sshin			= ia->ia_addr.sin6_addr.s6_addr32[1] &
70353541Sshin				ia->ia_prefixmask.sin6_addr.s6_addr32[1];
70453541Sshin		net.sin6_addr.s6_addr32[2]
70553541Sshin			= ia->ia_addr.sin6_addr.s6_addr32[2] &
70653541Sshin				ia->ia_prefixmask.sin6_addr.s6_addr32[2];
70753541Sshin		net.sin6_addr.s6_addr32[3]
70853541Sshin			= ia->ia_addr.sin6_addr.s6_addr32[3] &
70953541Sshin				ia->ia_prefixmask.sin6_addr.s6_addr32[3];
71053541Sshin		ia->ia_net = net;
71153541Sshin		break;
71253541Sshin
71353541Sshin	case SIOCAIFADDR_IN6:
71453541Sshin		prefixIsNew = 0;
71553541Sshin		hostIsNew = 1;
71653541Sshin
71753541Sshin		if (ifra->ifra_addr.sin6_len == 0) {
71853541Sshin			ifra->ifra_addr = ia->ia_addr;
71953541Sshin			hostIsNew = 0;
72053541Sshin		} else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr,
72153541Sshin					      &ia->ia_addr.sin6_addr))
72253541Sshin			hostIsNew = 0;
72353541Sshin
72453541Sshin		if (ifra->ifra_prefixmask.sin6_len) {
72553541Sshin			in6_ifscrub(ifp, ia);
72653541Sshin			ia->ia_prefixmask = ifra->ifra_prefixmask;
72753541Sshin			prefixIsNew = 1;
72853541Sshin		}
72953541Sshin		if ((ifp->if_flags & IFF_POINTOPOINT) &&
73053541Sshin		    (ifra->ifra_dstaddr.sin6_family == AF_INET6)) {
73153541Sshin			in6_ifscrub(ifp, ia);
73253541Sshin			ia->ia_dstaddr = ifra->ifra_dstaddr;
73353541Sshin			/* link-local index check: should be a separate function? */
73453541Sshin			if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
73553541Sshin				if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
73653541Sshin					/*
73753541Sshin					 * interface ID is not embedded by
73853541Sshin					 * the user
73953541Sshin					 */
74053541Sshin					ia->ia_dstaddr.sin6_addr.s6_addr16[1]
74153541Sshin						= htons(ifp->if_index);
74253541Sshin				} else
74353541Sshin					if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
74453541Sshin					    htons(ifp->if_index)) {
74553541Sshin						ia->ia_dstaddr = oldaddr;
74653541Sshin						return(EINVAL);	/* ifid is contradict */
74753541Sshin					}
74853541Sshin			}
74953541Sshin			prefixIsNew = 1; /* We lie; but effect's the same */
75053541Sshin		}
75153541Sshin		if (ifra->ifra_addr.sin6_family == AF_INET6 &&
75253541Sshin		    (hostIsNew || prefixIsNew))
75353541Sshin			error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
75453541Sshin		if (ifra->ifra_addr.sin6_family == AF_INET6
75553541Sshin		    && hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
75653541Sshin			int error_local = 0;
75753541Sshin
75853541Sshin			/*
75953541Sshin			 * join solicited multicast addr for new host id
76053541Sshin			 */
76153541Sshin			struct in6_addr llsol;
76253541Sshin			bzero(&llsol, sizeof(struct in6_addr));
76353541Sshin			llsol.s6_addr16[0] = htons(0xff02);
76453541Sshin			llsol.s6_addr16[1] = htons(ifp->if_index);
76553541Sshin			llsol.s6_addr32[1] = 0;
76653541Sshin			llsol.s6_addr32[2] = htonl(1);
76753541Sshin			llsol.s6_addr32[3] =
76853541Sshin				ifra->ifra_addr.sin6_addr.s6_addr32[3];
76953541Sshin			llsol.s6_addr8[12] = 0xff;
77053541Sshin			(void)in6_addmulti(&llsol, ifp, &error_local);
77153541Sshin			if (error == 0)
77253541Sshin				error = error_local;
77353541Sshin		}
77453541Sshin		/* Join dstaddr's solicited multicast if necessary. */
77553541Sshin		if (nd6_proxyall && hostIsNew) {
77653541Sshin			int error_local;
77753541Sshin
77853541Sshin			error_local = in6_ifaddproxy(ia);
77953541Sshin			if (error == 0)
78053541Sshin				error = error_local;
78153541Sshin		}
78253541Sshin
78353541Sshin		ia->ia6_flags = ifra->ifra_flags;
78453541Sshin		ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/*safety*/
78553541Sshin
78653541Sshin		ia->ia6_lifetime = ifra->ifra_lifetime;
78753541Sshin		/* for sanity */
78853541Sshin		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
78953541Sshin			ia->ia6_lifetime.ia6t_expire =
79053541Sshin				time_second + ia->ia6_lifetime.ia6t_vltime;
79153541Sshin		} else
79253541Sshin			ia->ia6_lifetime.ia6t_expire = 0;
79353541Sshin		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
79453541Sshin			ia->ia6_lifetime.ia6t_preferred =
79553541Sshin				time_second + ia->ia6_lifetime.ia6t_pltime;
79653541Sshin		} else
79753541Sshin			ia->ia6_lifetime.ia6t_preferred = 0;
79853541Sshin
79953541Sshin		/*
80053541Sshin		 * Perform DAD, if needed.
80153541Sshin		 * XXX It may be of use, if we can administratively
80253541Sshin		 * disable DAD.
80353541Sshin		 */
80453541Sshin		switch (ifp->if_type) {
80553541Sshin		case IFT_ARCNET:
80653541Sshin		case IFT_ETHER:
80753541Sshin		case IFT_FDDI:
80853541Sshin			ia->ia6_flags |= IN6_IFF_TENTATIVE;
80953541Sshin			nd6_dad_start((struct ifaddr *)ia, NULL);
81053541Sshin			break;
81153541Sshin#ifdef IFT_DUMMY
81253541Sshin		case IFT_DUMMY:
81353541Sshin#endif
81453541Sshin		case IFT_FAITH:
81553541Sshin		case IFT_GIF:
81653541Sshin		case IFT_LOOP:
81753541Sshin		default:
81853541Sshin			break;
81953541Sshin		}
82053541Sshin
82153541Sshin		if (hostIsNew) {
82253541Sshin			int iilen;
82353541Sshin			int error_local = 0;
82453541Sshin
82553541Sshin			iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) -
82653541Sshin				in6_mask2len(&ia->ia_prefixmask.sin6_addr);
82753541Sshin			error_local = in6_prefix_add_ifid(iilen, ia);
82853541Sshin			if (error == 0)
82953541Sshin				error = error_local;
83053541Sshin		}
83153541Sshin
83253541Sshin		return(error);
83353541Sshin
83453541Sshin	case SIOCDIFADDR_IN6:
83553541Sshin		in6_ifscrub(ifp, ia);
83653541Sshin
83753541Sshin		if (ifp->if_flags & IFF_MULTICAST) {
83853541Sshin			/*
83953541Sshin			 * delete solicited multicast addr for deleting host id
84053541Sshin			 */
84153541Sshin			struct in6_multi *in6m;
84253541Sshin			struct in6_addr llsol;
84353541Sshin			bzero(&llsol, sizeof(struct in6_addr));
84453541Sshin			llsol.s6_addr16[0] = htons(0xff02);
84553541Sshin			llsol.s6_addr16[1] = htons(ifp->if_index);
84653541Sshin			llsol.s6_addr32[1] = 0;
84753541Sshin			llsol.s6_addr32[2] = htonl(1);
84853541Sshin			llsol.s6_addr32[3] =
84953541Sshin				ia->ia_addr.sin6_addr.s6_addr32[3];
85053541Sshin			llsol.s6_addr8[12] = 0xff;
85153541Sshin
85253541Sshin			IN6_LOOKUP_MULTI(llsol, ifp, in6m);
85353541Sshin			if (in6m)
85453541Sshin				in6_delmulti(in6m);
85553541Sshin		}
85653541Sshin		/* Leave dstaddr's solicited multicast if necessary. */
85753541Sshin		if (nd6_proxyall)
85853541Sshin			in6_ifremproxy(ia);
85953541Sshin
86053541Sshin		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
86153541Sshin		oia = ia;
86253541Sshin		if (oia == (ia = in6_ifaddr))
86353541Sshin			in6_ifaddr = ia->ia_next;
86453541Sshin		else {
86553541Sshin			while (ia->ia_next && (ia->ia_next != oia))
86653541Sshin				ia = ia->ia_next;
86753541Sshin			if (ia->ia_next)
86853541Sshin				ia->ia_next = oia->ia_next;
86953541Sshin			else
87053541Sshin				printf("Didn't unlink in6_ifaddr from list\n");
87153541Sshin		}
87253541Sshin		{
87353541Sshin			int iilen;
87453541Sshin
87553541Sshin			iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) -
87653541Sshin				in6_mask2len(&oia->ia_prefixmask.sin6_addr);
87753541Sshin			in6_prefix_remove_ifid(iilen, oia);
87853541Sshin		}
87953541Sshin		IFAFREE((&oia->ia_ifa));
88053541Sshin		break;
88153541Sshin
88253541Sshin	default:
88353541Sshin		if (ifp == 0 || ifp->if_ioctl == 0)
88453541Sshin			return(EOPNOTSUPP);
88553541Sshin		return((*ifp->if_ioctl)(ifp, cmd, data));
88653541Sshin	}
88753541Sshin	return(0);
88853541Sshin}
88953541Sshin
89053541Sshin/*
89153541Sshin * SIOC[GAD]LIFADDR.
89253541Sshin *	SIOCGLIFADDR: get first address. (???)
89353541Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
89453541Sshin *		get first address that matches the specified prefix.
89553541Sshin *	SIOCALIFADDR: add the specified address.
89653541Sshin *	SIOCALIFADDR with IFLR_PREFIX:
89753541Sshin *		add the specified prefix, filling hostid part from
89853541Sshin *		the first link-local address.  prefixlen must be <= 64.
89953541Sshin *	SIOCDLIFADDR: delete the specified address.
90053541Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
90153541Sshin *		delete the first address that matches the specified prefix.
90253541Sshin * return values:
90353541Sshin *	EINVAL on invalid parameters
90453541Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
90553541Sshin *	other values may be returned from in6_ioctl()
90653541Sshin *
90753541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
90853541Sshin * this is to accomodate address naming scheme other than RFC2374,
90953541Sshin * in the future.
91053541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
91153541Sshin * address encoding scheme. (see figure on page 8)
91253541Sshin */
91353541Sshinstatic int
91453541Sshinin6_lifaddr_ioctl(so, cmd, data, ifp, p)
91553541Sshin	struct socket *so;
91653541Sshin	u_long cmd;
91753541Sshin	caddr_t	data;
91853541Sshin	struct ifnet *ifp;
91953541Sshin	struct proc *p;
92053541Sshin{
92153541Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
92253541Sshin	struct ifaddr *ifa;
92353541Sshin
92453541Sshin	/* sanity checks */
92553541Sshin	if (!data || !ifp) {
92653541Sshin		panic("invalid argument to in6_lifaddr_ioctl");
92753541Sshin		/*NOTRECHED*/
92853541Sshin	}
92953541Sshin
93053541Sshin	switch (cmd) {
93153541Sshin	case SIOCGLIFADDR:
93253541Sshin		/* address must be specified on GET with IFLR_PREFIX */
93353541Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
93453541Sshin			break;
93553541Sshin		/*FALLTHROUGH*/
93653541Sshin	case SIOCALIFADDR:
93753541Sshin	case SIOCDLIFADDR:
93853541Sshin		/* address must be specified on ADD and DELETE */
93953541Sshin		if (iflr->addr.__ss_family != AF_INET6)
94053541Sshin			return EINVAL;
94153541Sshin		if (iflr->addr.__ss_len != sizeof(struct sockaddr_in6))
94253541Sshin			return EINVAL;
94353541Sshin		/* XXX need improvement */
94453541Sshin		if (iflr->dstaddr.__ss_family
94553541Sshin		 && iflr->dstaddr.__ss_family != AF_INET6)
94653541Sshin			return EINVAL;
94753541Sshin		if (iflr->dstaddr.__ss_family
94853541Sshin		 && iflr->dstaddr.__ss_len != sizeof(struct sockaddr_in6))
94953541Sshin			return EINVAL;
95053541Sshin		break;
95153541Sshin	default: /*shouldn't happen*/
95253541Sshin		return EOPNOTSUPP;
95353541Sshin	}
95453541Sshin	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
95553541Sshin		return EINVAL;
95653541Sshin
95753541Sshin	switch (cmd) {
95853541Sshin	case SIOCALIFADDR:
95953541Sshin	    {
96053541Sshin		struct in6_aliasreq ifra;
96153541Sshin		struct in6_addr *hostid = NULL;
96253541Sshin		int prefixlen;
96353541Sshin
96453541Sshin		if ((iflr->flags & IFLR_PREFIX) != 0) {
96553541Sshin			struct sockaddr_in6 *sin6;
96653541Sshin
96753541Sshin			/*
96853541Sshin			 * hostid is to fill in the hostid part of the
96953541Sshin			 * address.  hostid points to the first link-local
97053541Sshin			 * address attached to the interface.
97153541Sshin			 */
97253541Sshin			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
97353541Sshin			if (!ifa)
97453541Sshin				return EADDRNOTAVAIL;
97553541Sshin			hostid = IFA_IN6(ifa);
97653541Sshin
97753541Sshin		 	/* prefixlen must be <= 64. */
97853541Sshin			if (64 < iflr->prefixlen)
97953541Sshin				return EINVAL;
98053541Sshin			prefixlen = iflr->prefixlen;
98153541Sshin
98253541Sshin			/* hostid part must be zero. */
98353541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
98453541Sshin			if (sin6->sin6_addr.s6_addr32[2] != 0
98553541Sshin			 || sin6->sin6_addr.s6_addr32[3] != 0) {
98653541Sshin				return EINVAL;
98753541Sshin			}
98853541Sshin		} else
98953541Sshin			prefixlen = iflr->prefixlen;
99053541Sshin
99153541Sshin		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
99253541Sshin		bzero(&ifra, sizeof(ifra));
99353541Sshin		bcopy(iflr->iflr_name, ifra.ifra_name,
99453541Sshin			sizeof(ifra.ifra_name));
99553541Sshin
99653541Sshin		bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.__ss_len);
99753541Sshin		if (hostid) {
99853541Sshin			/* fill in hostid part */
99953541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[2] =
100053541Sshin				hostid->s6_addr32[2];
100153541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[3] =
100253541Sshin				hostid->s6_addr32[3];
100353541Sshin		}
100453541Sshin
100553541Sshin		if (iflr->dstaddr.__ss_family) {	/*XXX*/
100653541Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
100753541Sshin				iflr->dstaddr.__ss_len);
100853541Sshin			if (hostid) {
100953541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
101053541Sshin					hostid->s6_addr32[2];
101153541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
101253541Sshin					hostid->s6_addr32[3];
101353541Sshin			}
101453541Sshin		}
101553541Sshin
101653541Sshin		ifra.ifra_prefixmask.sin6_family = AF_INET6;
101753541Sshin		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
101853541Sshin		in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
101953541Sshin
102053541Sshin		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
102153541Sshin		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
102253541Sshin	    }
102353541Sshin	case SIOCGLIFADDR:
102453541Sshin	case SIOCDLIFADDR:
102553541Sshin	    {
102653541Sshin		struct in6_ifaddr *ia;
102753541Sshin		struct in6_addr mask, candidate, match;
102853541Sshin		struct sockaddr_in6 *sin6;
102953541Sshin		int cmp;
103053541Sshin
103153541Sshin		bzero(&mask, sizeof(mask));
103253541Sshin		if (iflr->flags & IFLR_PREFIX) {
103353541Sshin			/* lookup a prefix rather than address. */
103453541Sshin			in6_len2mask(&mask, iflr->prefixlen);
103553541Sshin
103653541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
103753541Sshin			bcopy(&sin6->sin6_addr, &match, sizeof(match));
103853541Sshin			match.s6_addr32[0] &= mask.s6_addr32[0];
103953541Sshin			match.s6_addr32[1] &= mask.s6_addr32[1];
104053541Sshin			match.s6_addr32[2] &= mask.s6_addr32[2];
104153541Sshin			match.s6_addr32[3] &= mask.s6_addr32[3];
104253541Sshin
104353541Sshin			/* if you set extra bits, that's wrong */
104453541Sshin			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
104553541Sshin				return EINVAL;
104653541Sshin
104753541Sshin			cmp = 1;
104853541Sshin		} else {
104953541Sshin			if (cmd == SIOCGLIFADDR) {
105053541Sshin				/* on getting an address, take the 1st match */
105153541Sshin				cmp = 0;	/*XXX*/
105253541Sshin			} else {
105353541Sshin				/* on deleting an address, do exact match */
105453541Sshin				in6_len2mask(&mask, 128);
105553541Sshin				sin6 = (struct sockaddr_in6 *)&iflr->addr;
105653541Sshin				bcopy(&sin6->sin6_addr, &match, sizeof(match));
105753541Sshin
105853541Sshin				cmp = 1;
105953541Sshin			}
106053541Sshin		}
106153541Sshin
106253541Sshin		for (ifa = ifp->if_addrlist.tqh_first;
106353541Sshin		     ifa;
106453541Sshin		     ifa = ifa->ifa_list.tqe_next)
106553541Sshin		{
106653541Sshin			if (ifa->ifa_addr->sa_family != AF_INET6)
106753541Sshin				continue;
106853541Sshin			if (!cmp)
106953541Sshin				break;
107053541Sshin			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
107153541Sshin			candidate.s6_addr32[0] &= mask.s6_addr32[0];
107253541Sshin			candidate.s6_addr32[1] &= mask.s6_addr32[1];
107353541Sshin			candidate.s6_addr32[2] &= mask.s6_addr32[2];
107453541Sshin			candidate.s6_addr32[3] &= mask.s6_addr32[3];
107553541Sshin			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
107653541Sshin				break;
107753541Sshin		}
107853541Sshin		if (!ifa)
107953541Sshin			return EADDRNOTAVAIL;
108053541Sshin		ia = ifa2ia6(ifa);
108153541Sshin
108253541Sshin		if (cmd == SIOCGLIFADDR) {
108353541Sshin			/* fill in the if_laddrreq structure */
108453541Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
108553541Sshin
108653541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
108753541Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
108853541Sshin					ia->ia_dstaddr.sin6_len);
108953541Sshin			} else
109053541Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
109153541Sshin
109253541Sshin			iflr->prefixlen =
109353541Sshin				in6_mask2len(&ia->ia_prefixmask.sin6_addr);
109453541Sshin
109553541Sshin			iflr->flags = ia->ia6_flags;	/*XXX*/
109653541Sshin
109753541Sshin			return 0;
109853541Sshin		} else {
109953541Sshin			struct in6_aliasreq ifra;
110053541Sshin
110153541Sshin			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
110253541Sshin			bzero(&ifra, sizeof(ifra));
110353541Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
110453541Sshin				sizeof(ifra.ifra_name));
110553541Sshin
110653541Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
110753541Sshin				ia->ia_addr.sin6_len);
110853541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
110953541Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
111053541Sshin					ia->ia_dstaddr.sin6_len);
111153541Sshin			}
111253541Sshin			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
111353541Sshin				ia->ia_prefixmask.sin6_len);
111453541Sshin
111553541Sshin			ifra.ifra_flags = ia->ia6_flags;
111653541Sshin			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
111753541Sshin				ifp, p);
111853541Sshin		}
111953541Sshin	    }
112053541Sshin	}
112153541Sshin
112253541Sshin	return EOPNOTSUPP;	/*just for safety*/
112353541Sshin}
112453541Sshin
112553541Sshin/*
112653541Sshin * Delete any existing route for an interface.
112753541Sshin */
112853541Sshinvoid
112953541Sshinin6_ifscrub(ifp, ia)
113053541Sshin	register struct ifnet *ifp;
113153541Sshin	register struct in6_ifaddr *ia;
113253541Sshin{
113353541Sshin	if ((ia->ia_flags & IFA_ROUTE) == 0)
113453541Sshin		return;
113553541Sshin	if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
113653541Sshin		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
113753541Sshin	else
113853541Sshin		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
113953541Sshin	ia->ia_flags &= ~IFA_ROUTE;
114053541Sshin
114153541Sshin	/* Remove ownaddr's loopback rtentry, if it exists. */
114253541Sshin	in6_ifremloop(&(ia->ia_ifa));
114353541Sshin}
114453541Sshin
114553541Sshin/*
114653541Sshin * Initialize an interface's intetnet6 address
114753541Sshin * and routing table entry.
114853541Sshin */
114953541Sshinint
115053541Sshinin6_ifinit(ifp, ia, sin6, scrub)
115153541Sshin	struct ifnet *ifp;
115253541Sshin	struct in6_ifaddr *ia;
115353541Sshin	struct sockaddr_in6 *sin6;
115453541Sshin	int scrub;
115553541Sshin{
115653541Sshin	struct	sockaddr_in6 oldaddr;
115753541Sshin	int	error, flags = RTF_UP;
115853541Sshin	int	s = splimp();
115953541Sshin
116053541Sshin	oldaddr = ia->ia_addr;
116153541Sshin	ia->ia_addr = *sin6;
116253541Sshin	/*
116353541Sshin	 * Give the interface a chance to initialize
116453541Sshin	 * if this is its first address,
116553541Sshin	 * and to validate the address if necessary.
116653541Sshin	 */
116753541Sshin	if (ifp->if_ioctl &&
116853541Sshin	   (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
116953541Sshin		splx(s);
117053541Sshin		ia->ia_addr = oldaddr;
117153541Sshin		return(error);
117253541Sshin	}
117353541Sshin
117453541Sshin	switch (ifp->if_type) {
117553541Sshin	case IFT_ARCNET:
117653541Sshin	case IFT_ETHER:
117753541Sshin	case IFT_FDDI:
117853541Sshin		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
117953541Sshin		ia->ia_ifa.ifa_flags |= RTF_CLONING;
118053541Sshin		break;
118153541Sshin	case IFT_PPP:
118253541Sshin		ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest;
118353541Sshin		ia->ia_ifa.ifa_flags |= RTF_CLONING;
118453541Sshin		break;
118553541Sshin	}
118653541Sshin
118753541Sshin	splx(s);
118853541Sshin	if (scrub) {
118953541Sshin		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
119053541Sshin		in6_ifscrub(ifp, ia);
119153541Sshin		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
119253541Sshin	}
119353541Sshin	/* xxx
119453541Sshin	 * in_socktrim
119553541Sshin	 */
119653541Sshin	/*
119753541Sshin	 * Add route for the network.
119853541Sshin	 */
119953541Sshin	ia->ia_ifa.ifa_metric = ifp->if_metric;
120053541Sshin	if (ifp->if_flags & IFF_LOOPBACK) {
120153541Sshin		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
120253541Sshin		flags |= RTF_HOST;
120353541Sshin	} else if (ifp->if_flags & IFF_POINTOPOINT) {
120453541Sshin		if (ia->ia_dstaddr.sin6_family != AF_INET6)
120553541Sshin			return(0);
120653541Sshin		flags |= RTF_HOST;
120753541Sshin	}
120853541Sshin	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
120953541Sshin		ia->ia_flags |= IFA_ROUTE;
121053541Sshin
121153541Sshin	/* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */
121253541Sshin	in6_ifaddloop(&(ia->ia_ifa));
121353541Sshin
121453541Sshin	return(error);
121553541Sshin}
121653541Sshin
121753541Sshin/*
121853541Sshin * Add an address to the list of IP6 multicast addresses for a
121953541Sshin * given interface.
122053541Sshin */
122153541Sshinstruct	in6_multi *
122253541Sshinin6_addmulti(maddr6, ifp, errorp)
122353541Sshin	register struct in6_addr *maddr6;
122453541Sshin	register struct ifnet *ifp;
122553541Sshin	int *errorp;
122653541Sshin{
122753541Sshin	struct	in6_multi *in6m;
122853541Sshin	struct sockaddr_in6 sin6;
122953541Sshin	struct ifmultiaddr *ifma;
123053541Sshin	int	s = splnet();
123153541Sshin
123253541Sshin	*errorp = 0;
123353541Sshin
123453541Sshin	/*
123553541Sshin	 * Call generic routine to add membership or increment
123653541Sshin	 * refcount.  It wants addresses in the form of a sockaddr,
123753541Sshin	 * so we build one here (being careful to zero the unused bytes).
123853541Sshin	 */
123953541Sshin	bzero(&sin6, sizeof sin6);
124053541Sshin	sin6.sin6_family = AF_INET6;
124153541Sshin	sin6.sin6_len = sizeof sin6;
124253541Sshin	sin6.sin6_addr = *maddr6;
124353541Sshin	*errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma);
124453541Sshin	if (*errorp) {
124553541Sshin		splx(s);
124653541Sshin		return 0;
124753541Sshin	}
124853541Sshin
124953541Sshin	/*
125053541Sshin	 * If ifma->ifma_protospec is null, then if_addmulti() created
125153541Sshin	 * a new record.  Otherwise, we are done.
125253541Sshin	 */
125353541Sshin	if (ifma->ifma_protospec != 0)
125453541Sshin		return ifma->ifma_protospec;
125553541Sshin
125653541Sshin	/* XXX - if_addmulti uses M_WAITOK.  Can this really be called
125753541Sshin	   at interrupt time?  If so, need to fix if_addmulti. XXX */
125853541Sshin	in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
125953541Sshin	if (in6m == NULL) {
126053541Sshin		splx(s);
126153541Sshin		return (NULL);
126253541Sshin	}
126353541Sshin
126453541Sshin	bzero(in6m, sizeof *in6m);
126553541Sshin	in6m->in6m_addr = *maddr6;
126653541Sshin	in6m->in6m_ifp = ifp;
126753541Sshin	in6m->in6m_ifma = ifma;
126853541Sshin	ifma->ifma_protospec = in6m;
126953541Sshin	LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry);
127053541Sshin
127153541Sshin	/*
127253541Sshin	 * Let MLD6 know that we have joined a new IP6 multicast
127353541Sshin	 * group.
127453541Sshin	 */
127553541Sshin	mld6_start_listening(in6m);
127653541Sshin	splx(s);
127753541Sshin	return(in6m);
127853541Sshin}
127953541Sshin
128053541Sshin/*
128153541Sshin * Delete a multicast address record.
128253541Sshin */
128353541Sshinvoid
128453541Sshinin6_delmulti(in6m)
128553541Sshin	struct in6_multi *in6m;
128653541Sshin{
128753541Sshin	struct ifmultiaddr *ifma = in6m->in6m_ifma;
128853541Sshin	int	s = splnet();
128953541Sshin
129053541Sshin	if (ifma->ifma_refcount == 1) {
129153541Sshin		/*
129253541Sshin		 * No remaining claims to this record; let MLD6 know
129353541Sshin		 * that we are leaving the multicast group.
129453541Sshin		 */
129553541Sshin		mld6_stop_listening(in6m);
129653541Sshin		ifma->ifma_protospec = 0;
129753541Sshin		LIST_REMOVE(in6m, in6m_entry);
129853541Sshin		free(in6m, M_IPMADDR);
129953541Sshin	}
130053541Sshin	/* XXX - should be separate API for when we have an ifma? */
130153541Sshin	if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
130253541Sshin	splx(s);
130353541Sshin}
130453541Sshin
130553541Sshin/*
130653541Sshin * Find an IPv6 interface link-local address specific to an interface.
130753541Sshin */
130853541Sshinstruct in6_ifaddr *
130953541Sshinin6ifa_ifpforlinklocal(ifp)
131053541Sshin	struct ifnet *ifp;
131153541Sshin{
131253541Sshin	register struct ifaddr *ifa;
131353541Sshin
131453541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
131553541Sshin	{
131653541Sshin		if (ifa->ifa_addr == NULL)
131753541Sshin			continue;	/* just for safety */
131853541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
131953541Sshin			continue;
132053541Sshin		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)))
132153541Sshin			break;
132253541Sshin	}
132353541Sshin
132453541Sshin	return((struct in6_ifaddr *)ifa);
132553541Sshin}
132653541Sshin
132753541Sshin
132853541Sshin/*
132953541Sshin * find the internet address corresponding to a given interface and address.
133053541Sshin */
133153541Sshinstruct in6_ifaddr *
133253541Sshinin6ifa_ifpwithaddr(ifp, addr)
133353541Sshin	struct ifnet *ifp;
133453541Sshin	struct in6_addr *addr;
133553541Sshin{
133653541Sshin	register struct ifaddr *ifa;
133753541Sshin
133853541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
133953541Sshin	{
134053541Sshin		if (ifa->ifa_addr == NULL)
134153541Sshin			continue;	/* just for safety */
134253541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
134353541Sshin			continue;
134453541Sshin		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
134553541Sshin			break;
134653541Sshin	}
134753541Sshin
134853541Sshin	return((struct in6_ifaddr *)ifa);
134953541Sshin}
135053541Sshin
135153541Sshin/*
135253541Sshin * Convert IP6 address to printable (loggable) representation.
135353541Sshin */
135453541Sshinstatic char digits[] = "0123456789abcdef";
135553541Sshinstatic int ip6round = 0;
135653541Sshinchar *
135753541Sshinip6_sprintf(addr)
135853541Sshinregister struct in6_addr *addr;
135953541Sshin{
136053541Sshin	static char ip6buf[8][48];
136153541Sshin	register int i;
136253541Sshin	register char *cp;
136353541Sshin	register u_short *a = (u_short *)addr;
136453541Sshin	register u_char *d;
136553541Sshin	int dcolon = 0;
136653541Sshin
136753541Sshin	ip6round = (ip6round + 1) & 7;
136853541Sshin	cp = ip6buf[ip6round];
136953541Sshin
137053541Sshin	for (i = 0; i < 8; i++) {
137153541Sshin		if (dcolon == 1) {
137253541Sshin			if (*a == 0) {
137353541Sshin				if (i == 7)
137453541Sshin					*cp++ = ':';
137553541Sshin				a++;
137653541Sshin				continue;
137753541Sshin			} else
137853541Sshin				dcolon = 2;
137953541Sshin		}
138053541Sshin		if (*a == 0) {
138153541Sshin			if (dcolon == 0 && *(a + 1) == 0) {
138253541Sshin				if (i == 0)
138353541Sshin					*cp++ = ':';
138453541Sshin				*cp++ = ':';
138553541Sshin				dcolon = 1;
138653541Sshin			} else {
138753541Sshin				*cp++ = '0';
138853541Sshin				*cp++ = ':';
138953541Sshin			}
139053541Sshin			a++;
139153541Sshin			continue;
139253541Sshin		}
139353541Sshin		d = (u_char *)a;
139453541Sshin		*cp++ = digits[*d >> 4];
139553541Sshin		*cp++ = digits[*d++ & 0xf];
139653541Sshin		*cp++ = digits[*d >> 4];
139753541Sshin		*cp++ = digits[*d & 0xf];
139853541Sshin		*cp++ = ':';
139953541Sshin		a++;
140053541Sshin	}
140153541Sshin	*--cp = 0;
140253541Sshin	return(ip6buf[ip6round]);
140353541Sshin}
140453541Sshin
140553541Sshinint
140653541Sshinin6_localaddr(in6)
140753541Sshin	struct in6_addr *in6;
140853541Sshin{
140953541Sshin	struct in6_ifaddr *ia;
141053541Sshin
141153541Sshin	if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
141253541Sshin		return 1;
141353541Sshin
141453541Sshin	for (ia = in6_ifaddr; ia; ia = ia->ia_next)
141553541Sshin		if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
141653541Sshin					      &ia->ia_prefixmask.sin6_addr))
141753541Sshin			return 1;
141853541Sshin
141953541Sshin	return (0);
142053541Sshin}
142153541Sshin
142253541Sshin/*
142353541Sshin * Get a scope of the address. Node-local, link-local, site-local or global.
142453541Sshin */
142553541Sshinint
142653541Sshinin6_addrscope (addr)
142753541Sshinstruct in6_addr *addr;
142853541Sshin{
142953541Sshin	int scope;
143053541Sshin
143153541Sshin	if (addr->s6_addr8[0] == 0xfe) {
143253541Sshin		scope = addr->s6_addr8[1] & 0xc0;
143353541Sshin
143453541Sshin		switch (scope) {
143553541Sshin		case 0x80:
143653541Sshin			return IPV6_ADDR_SCOPE_LINKLOCAL;
143753541Sshin			break;
143853541Sshin		case 0xc0:
143953541Sshin			return IPV6_ADDR_SCOPE_SITELOCAL;
144053541Sshin			break;
144153541Sshin		default:
144253541Sshin			return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
144353541Sshin			break;
144453541Sshin		}
144553541Sshin	}
144653541Sshin
144753541Sshin
144853541Sshin	if (addr->s6_addr8[0] == 0xff) {
144953541Sshin		scope = addr->s6_addr8[1] & 0x0f;
145053541Sshin
145153541Sshin		/*
145253541Sshin		 * due to other scope such as reserved,
145353541Sshin		 * return scope doesn't work.
145453541Sshin		 */
145553541Sshin		switch (scope) {
145653541Sshin		case IPV6_ADDR_SCOPE_NODELOCAL:
145753541Sshin			return IPV6_ADDR_SCOPE_NODELOCAL;
145853541Sshin			break;
145953541Sshin		case IPV6_ADDR_SCOPE_LINKLOCAL:
146053541Sshin			return IPV6_ADDR_SCOPE_LINKLOCAL;
146153541Sshin			break;
146253541Sshin		case IPV6_ADDR_SCOPE_SITELOCAL:
146353541Sshin			return IPV6_ADDR_SCOPE_SITELOCAL;
146453541Sshin			break;
146553541Sshin		default:
146653541Sshin			return IPV6_ADDR_SCOPE_GLOBAL;
146753541Sshin			break;
146853541Sshin		}
146953541Sshin	}
147053541Sshin
147153541Sshin	if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
147253541Sshin		if (addr->s6_addr8[15] == 1) /* loopback */
147353541Sshin			return IPV6_ADDR_SCOPE_NODELOCAL;
147453541Sshin		if (addr->s6_addr8[15] == 0) /* unspecified */
147553541Sshin			return IPV6_ADDR_SCOPE_LINKLOCAL;
147653541Sshin	}
147753541Sshin
147853541Sshin	return IPV6_ADDR_SCOPE_GLOBAL;
147953541Sshin}
148053541Sshin
148153541Sshin/*
148253541Sshin * return length of part which dst and src are equal
148353541Sshin * hard coding...
148453541Sshin */
148553541Sshin
148653541Sshinint
148753541Sshinin6_matchlen(src, dst)
148853541Sshinstruct in6_addr *src, *dst;
148953541Sshin{
149053541Sshin	int match = 0;
149153541Sshin	u_char *s = (u_char *)src, *d = (u_char *)dst;
149253541Sshin	u_char *lim = s + 16, r;
149353541Sshin
149453541Sshin	while (s < lim)
149553541Sshin		if ((r = (*d++ ^ *s++)) != 0) {
149653541Sshin			while (r < 128) {
149753541Sshin				match++;
149853541Sshin				r <<= 1;
149953541Sshin			}
150053541Sshin			break;
150153541Sshin		} else
150253541Sshin			match += 8;
150353541Sshin	return match;
150453541Sshin}
150553541Sshin
150653541Sshinint
150753541Sshinin6_are_prefix_equal(p1, p2, len)
150853541Sshin	struct in6_addr *p1, *p2;
150953541Sshin	int len;
151053541Sshin{
151153541Sshin	int bytelen, bitlen;
151253541Sshin
151353541Sshin	/* sanity check */
151453541Sshin	if (0 > len || len > 128) {
151553541Sshin		log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
151653541Sshin		    len);
151753541Sshin		return(0);
151853541Sshin	}
151953541Sshin
152053541Sshin	bytelen = len / 8;
152153541Sshin	bitlen = len % 8;
152253541Sshin
152353541Sshin	if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
152453541Sshin		return(0);
152553541Sshin	if (p1->s6_addr[bytelen] >> (8 - bitlen) !=
152653541Sshin	    p2->s6_addr[bytelen] >> (8 - bitlen))
152753541Sshin		return(0);
152853541Sshin
152953541Sshin	return(1);
153053541Sshin}
153153541Sshin
153253541Sshinvoid
153353541Sshinin6_prefixlen2mask(maskp, len)
153453541Sshin	struct in6_addr *maskp;
153553541Sshin	int len;
153653541Sshin{
153753541Sshin	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
153853541Sshin	int bytelen, bitlen, i;
153953541Sshin
154053541Sshin	/* sanity check */
154153541Sshin	if (0 > len || len > 128) {
154253541Sshin		log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
154353541Sshin		    len);
154453541Sshin		return;
154553541Sshin	}
154653541Sshin
154753541Sshin	bzero(maskp, sizeof(*maskp));
154853541Sshin	bytelen = len / 8;
154953541Sshin	bitlen = len % 8;
155053541Sshin	for (i = 0; i < bytelen; i++)
155153541Sshin		maskp->s6_addr[i] = 0xff;
155253541Sshin	if (bitlen)
155353541Sshin		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
155453541Sshin}
155553541Sshin
155653541Sshin/*
155753541Sshin * return the best address out of the same scope
155853541Sshin */
155953541Sshin
156053541Sshinstruct in6_ifaddr *
156153541Sshinin6_ifawithscope(ifp, dst)
156253541Sshin	register struct ifnet *ifp;
156353541Sshin	register struct in6_addr *dst;
156453541Sshin{
156553541Sshin	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
156653541Sshin	struct ifaddr *ifa;
156753541Sshin	struct in6_ifaddr *besta = NULL, *ia;
156853541Sshin	struct in6_ifaddr *dep[2];	/*last-resort: deprecated*/
156953541Sshin
157053541Sshin	dep[0] = dep[1] = NULL;
157153541Sshin
157253541Sshin	/*
157353541Sshin	 * We first look for addresses in the same scope.
157453541Sshin	 * If there is one, return it.
157553541Sshin	 * If two or more, return one which matches the dst longest.
157653541Sshin	 * If none, return one of global addresses assigned other ifs.
157753541Sshin	 */
157853541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
157953541Sshin	{
158053541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
158153541Sshin			continue;
158253541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
158353541Sshin			continue; /* XXX: is there any case to allow anycast? */
158453541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
158553541Sshin			continue; /* don't use this interface */
158653541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
158753541Sshin			continue;
158853541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
158953541Sshin			if (ip6_use_deprecated)
159053541Sshin				dep[0] = (struct in6_ifaddr *)ifa;
159153541Sshin			continue;
159253541Sshin		}
159353541Sshin
159453541Sshin		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
159553541Sshin			/*
159653541Sshin			 * call in6_matchlen() as few as possible
159753541Sshin			 */
159853541Sshin			if (besta) {
159953541Sshin				if (blen == -1)
160053541Sshin					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
160153541Sshin				tlen = in6_matchlen(IFA_IN6(ifa), dst);
160253541Sshin				if (tlen > blen) {
160353541Sshin					blen = tlen;
160453541Sshin					besta = (struct in6_ifaddr *)ifa;
160553541Sshin				}
160653541Sshin			} else
160753541Sshin				besta = (struct in6_ifaddr *)ifa;
160853541Sshin		}
160953541Sshin	}
161053541Sshin	if (besta)
161153541Sshin		return besta;
161253541Sshin
161353541Sshin	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
161453541Sshin		if (IPV6_ADDR_SCOPE_GLOBAL !=
161553541Sshin		    in6_addrscope(&(ia->ia_addr.sin6_addr)))
161653541Sshin			continue;
161753541Sshin		/* XXX: is there any case to allow anycast? */
161853541Sshin		if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0)
161953541Sshin			continue;
162053541Sshin		if ((ia->ia6_flags & IN6_IFF_NOTREADY) != 0)
162153541Sshin			continue;
162253541Sshin		if ((ia->ia6_flags & IN6_IFF_DETACHED) != 0)
162353541Sshin			continue;
162453541Sshin		if ((ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
162553541Sshin			if (ip6_use_deprecated)
162653541Sshin				dep[1] = (struct in6_ifaddr *)ifa;
162753541Sshin			continue;
162853541Sshin		}
162953541Sshin		return ia;
163053541Sshin	}
163153541Sshin
163253541Sshin	/* use the last-resort values, that are, deprecated addresses */
163353541Sshin	if (dep[0])
163453541Sshin		return dep[0];
163553541Sshin	if (dep[1])
163653541Sshin		return dep[1];
163753541Sshin
163853541Sshin	return NULL;
163953541Sshin}
164053541Sshin
164153541Sshin/*
164253541Sshin * return the best address out of the same scope. if no address was
164353541Sshin * found, return the first valid address from designated IF.
164453541Sshin */
164553541Sshin
164653541Sshinstruct in6_ifaddr *
164753541Sshinin6_ifawithifp(ifp, dst)
164853541Sshin	register struct ifnet *ifp;
164953541Sshin	register struct in6_addr *dst;
165053541Sshin{
165153541Sshin	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
165253541Sshin	struct ifaddr *ifa;
165353541Sshin	struct in6_ifaddr *besta = 0;
165453541Sshin	struct in6_ifaddr *dep[2];	/*last-resort: deprecated*/
165553541Sshin
165653541Sshin	dep[0] = dep[1] = NULL;
165753541Sshin
165853541Sshin	/*
165953541Sshin	 * We first look for addresses in the same scope.
166053541Sshin	 * If there is one, return it.
166153541Sshin	 * If two or more, return one which matches the dst longest.
166253541Sshin	 * If none, return one of global addresses assigned other ifs.
166353541Sshin	 */
166453541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
166553541Sshin	{
166653541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
166753541Sshin			continue;
166853541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
166953541Sshin			continue; /* XXX: is there any case to allow anycast? */
167053541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
167153541Sshin			continue; /* don't use this interface */
167253541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
167353541Sshin			continue;
167453541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
167553541Sshin			if (ip6_use_deprecated)
167653541Sshin				dep[0] = (struct in6_ifaddr *)ifa;
167753541Sshin			continue;
167853541Sshin		}
167953541Sshin
168053541Sshin		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
168153541Sshin			/*
168253541Sshin			 * call in6_matchlen() as few as possible
168353541Sshin			 */
168453541Sshin			if (besta) {
168553541Sshin				if (blen == -1)
168653541Sshin					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
168753541Sshin				tlen = in6_matchlen(IFA_IN6(ifa), dst);
168853541Sshin				if (tlen > blen) {
168953541Sshin					blen = tlen;
169053541Sshin					besta = (struct in6_ifaddr *)ifa;
169153541Sshin				}
169253541Sshin			} else
169353541Sshin				besta = (struct in6_ifaddr *)ifa;
169453541Sshin		}
169553541Sshin	}
169653541Sshin	if (besta)
169753541Sshin		return(besta);
169853541Sshin
169953541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
170053541Sshin	{
170153541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
170253541Sshin			continue;
170353541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
170453541Sshin			continue; /* XXX: is there any case to allow anycast? */
170553541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
170653541Sshin			continue; /* don't use this interface */
170753541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
170853541Sshin			continue;
170953541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
171053541Sshin			if (ip6_use_deprecated)
171153541Sshin				dep[1] = (struct in6_ifaddr *)ifa;
171253541Sshin			continue;
171353541Sshin		}
171453541Sshin
171553541Sshin		return (struct in6_ifaddr *)ifa;
171653541Sshin	}
171753541Sshin
171853541Sshin	/* use the last-resort values, that are, deprecated addresses */
171953541Sshin	if (dep[0])
172053541Sshin		return dep[0];
172153541Sshin	if (dep[1])
172253541Sshin		return dep[1];
172353541Sshin
172453541Sshin	return NULL;
172553541Sshin}
172653541Sshin
172753541Sshin/*
172853541Sshin * perform DAD when interface becomes IFF_UP.
172953541Sshin */
173053541Sshinvoid
173153541Sshinin6_if_up(ifp)
173253541Sshin	struct ifnet *ifp;
173353541Sshin{
173453541Sshin	struct ifaddr *ifa;
173553541Sshin	struct in6_ifaddr *ia;
173653541Sshin	struct sockaddr_dl *sdl;
173753541Sshin	int type;
173853541Sshin	struct ether_addr ea;
173953541Sshin	int off;
174053541Sshin	int dad_delay;		/* delay ticks before DAD output */
174153541Sshin
174253541Sshin	bzero(&ea, sizeof(ea));
174353541Sshin	sdl = NULL;
174453541Sshin
174553541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
174653541Sshin	{
174753541Sshin		if (ifa->ifa_addr->sa_family == AF_INET6
174853541Sshin		 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
174953541Sshin			goto dad;
175053541Sshin		}
175153541Sshin		if (ifa->ifa_addr->sa_family != AF_LINK)
175253541Sshin			continue;
175353541Sshin		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
175453541Sshin		break;
175553541Sshin	}
175653541Sshin
175753541Sshin	switch (ifp->if_type) {
175853541Sshin	case IFT_SLIP:
175953541Sshin	case IFT_PPP:
176053541Sshin#ifdef IFT_DUMMY
176153541Sshin	case IFT_DUMMY:
176253541Sshin#endif
176353541Sshin	case IFT_GIF:
176453541Sshin	case IFT_FAITH:
176553541Sshin		type = IN6_IFT_P2P;
176653541Sshin		in6_ifattach(ifp, type, 0, 1);
176753541Sshin		break;
176853541Sshin	case IFT_ETHER:
176953541Sshin	case IFT_FDDI:
177053541Sshin	case IFT_ATM:
177153541Sshin		type = IN6_IFT_802;
177253541Sshin		if (sdl == NULL)
177353541Sshin			break;
177453541Sshin		off = sdl->sdl_nlen;
177553541Sshin		if (bcmp(&sdl->sdl_data[off], &ea, sizeof(ea)) != 0)
177653541Sshin			in6_ifattach(ifp, type, LLADDR(sdl), 0);
177753541Sshin		break;
177853541Sshin	case IFT_ARCNET:
177953541Sshin		type = IN6_IFT_ARCNET;
178053541Sshin		if (sdl == NULL)
178153541Sshin			break;
178253541Sshin		off = sdl->sdl_nlen;
178353541Sshin		if (sdl->sdl_data[off] != 0)	/* XXX ?: */
178453541Sshin			in6_ifattach(ifp, type, LLADDR(sdl), 0);
178553541Sshin		break;
178653541Sshin	default:
178753541Sshin		break;
178853541Sshin	}
178953541Sshin
179053541Sshindad:
179153541Sshin	dad_delay = 0;
179253541Sshin	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
179353541Sshin	{
179453541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
179553541Sshin			continue;
179653541Sshin		ia = (struct in6_ifaddr *)ifa;
179753541Sshin		if (ia->ia6_flags & IN6_IFF_TENTATIVE)
179853541Sshin			nd6_dad_start(ifa, &dad_delay);
179953541Sshin	}
180053541Sshin}
180153541Sshin
180253541Sshin/*
180353541Sshin * Calculate max IPv6 MTU through all the interfaces and store it
180453541Sshin * to in6_maxmtu.
180553541Sshin */
180653541Sshinvoid
180753541Sshinin6_setmaxmtu()
180853541Sshin{
180953541Sshin	unsigned long maxmtu = 0;
181053541Sshin	struct ifnet *ifp;
181153541Sshin
181253541Sshin	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
181353541Sshin	{
181453541Sshin		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
181553541Sshin		    nd_ifinfo[ifp->if_index].linkmtu > maxmtu)
181653541Sshin			maxmtu =  nd_ifinfo[ifp->if_index].linkmtu;
181753541Sshin	}
181853541Sshin	if (maxmtu)	/* update only when maxmtu is positive */
181953541Sshin		in6_maxmtu = maxmtu;
182053541Sshin}
182153541Sshin
182253541Sshin/*
182353541Sshin * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be
182453541Sshin * v4 mapped addr or v4 compat addr
182553541Sshin */
182653541Sshinvoid
182753541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
182853541Sshin{
182953541Sshin	bzero(sin, sizeof(*sin));
183053541Sshin	sin->sin_len = sizeof(struct sockaddr_in);
183153541Sshin	sin->sin_family = AF_INET;
183253541Sshin	sin->sin_port = sin6->sin6_port;
183353541Sshin	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
183453541Sshin}
183553541Sshin
183653541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
183753541Sshinvoid
183853541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
183953541Sshin{
184053541Sshin	bzero(sin6, sizeof(*sin6));
184153541Sshin	sin6->sin6_len = sizeof(struct sockaddr_in6);
184253541Sshin	sin6->sin6_family = AF_INET6;
184353541Sshin	sin6->sin6_port = sin->sin_port;
184453541Sshin	sin6->sin6_addr.s6_addr32[0] = 0;
184553541Sshin	sin6->sin6_addr.s6_addr32[1] = 0;
184653541Sshin	sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
184753541Sshin	sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
184853541Sshin}
184953541Sshin
185053541Sshin/* Convert sockaddr_in6 into sockaddr_in. */
185153541Sshinvoid
185253541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam)
185353541Sshin{
185453541Sshin	struct sockaddr_in *sin_p;
185553541Sshin	struct sockaddr_in6 sin6;
185653541Sshin
185753541Sshin	/*
185853541Sshin	 * Save original sockaddr_in6 addr and convert it
185953541Sshin	 * to sockaddr_in.
186053541Sshin	 */
186153541Sshin	sin6 = *(struct sockaddr_in6 *)nam;
186253541Sshin	sin_p = (struct sockaddr_in *)nam;
186353541Sshin	in6_sin6_2_sin(sin_p, &sin6);
186453541Sshin}
186553541Sshin
186653541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
186753541Sshinvoid
186853541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
186953541Sshin{
187053541Sshin	struct sockaddr_in *sin_p;
187153541Sshin	struct sockaddr_in6 *sin6_p;
187253541Sshin
187353541Sshin	MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
187453541Sshin	       M_WAITOK);
187553541Sshin	sin_p = (struct sockaddr_in *)*nam;
187653541Sshin	in6_sin_2_v4mapsin6(sin_p, sin6_p);
187753541Sshin	FREE(*nam, M_SONAME);
187853541Sshin	*nam = (struct sockaddr *)sin6_p;
187953541Sshin}
1880