in6.c revision 174375
162587Sitojun/*	$FreeBSD: head/sys/netinet6/in6.c 174375 2007-12-06 22:44:24Z julian $	*/
295023Ssuz/*	$KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $	*/
362587Sitojun
4139826Simp/*-
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
33139826Simp/*-
3453541Sshin * Copyright (c) 1982, 1986, 1991, 1993
3553541Sshin *	The Regents of the University of California.  All rights reserved.
3653541Sshin *
3753541Sshin * Redistribution and use in source and binary forms, with or without
3853541Sshin * modification, are permitted provided that the following conditions
3953541Sshin * are met:
4053541Sshin * 1. Redistributions of source code must retain the above copyright
4153541Sshin *    notice, this list of conditions and the following disclaimer.
4253541Sshin * 2. Redistributions in binary form must reproduce the above copyright
4353541Sshin *    notice, this list of conditions and the following disclaimer in the
4453541Sshin *    documentation and/or other materials provided with the distribution.
4553541Sshin * 4. Neither the name of the University nor the names of its contributors
4653541Sshin *    may be used to endorse or promote products derived from this software
4753541Sshin *    without specific prior written permission.
4853541Sshin *
4953541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5053541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5153541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5253541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5353541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5453541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5553541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5653541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5753541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5853541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5953541Sshin * SUCH DAMAGE.
6053541Sshin *
6153541Sshin *	@(#)in.c	8.2 (Berkeley) 11/15/93
6253541Sshin */
6353541Sshin
6462587Sitojun#include "opt_inet.h"
6562587Sitojun#include "opt_inet6.h"
6662587Sitojun
6753541Sshin#include <sys/param.h>
6853541Sshin#include <sys/errno.h>
6953541Sshin#include <sys/malloc.h>
7053541Sshin#include <sys/socket.h>
7153541Sshin#include <sys/socketvar.h>
7253541Sshin#include <sys/sockio.h>
7353541Sshin#include <sys/systm.h>
74164033Srwatson#include <sys/priv.h>
7553541Sshin#include <sys/proc.h>
7653541Sshin#include <sys/time.h>
7753541Sshin#include <sys/kernel.h>
7853541Sshin#include <sys/syslog.h>
7953541Sshin
8053541Sshin#include <net/if.h>
8153541Sshin#include <net/if_types.h>
8253541Sshin#include <net/route.h>
8353541Sshin#include <net/if_dl.h>
8453541Sshin
8553541Sshin#include <netinet/in.h>
8653541Sshin#include <netinet/in_var.h>
8753541Sshin#include <netinet/if_ether.h>
8878064Sume#include <netinet/in_systm.h>
8978064Sume#include <netinet/ip.h>
9078064Sume#include <netinet/in_pcb.h>
9153541Sshin
9262587Sitojun#include <netinet/ip6.h>
9353541Sshin#include <netinet6/ip6_var.h>
9495023Ssuz#include <netinet6/nd6.h>
9553541Sshin#include <netinet6/mld6_var.h>
9662587Sitojun#include <netinet6/ip6_mroute.h>
9753541Sshin#include <netinet6/in6_ifattach.h>
9862587Sitojun#include <netinet6/scope6_var.h>
9978064Sume#include <netinet6/in6_pcb.h>
10062587Sitojun
101149849SobrienMALLOC_DEFINE(M_IP6MADDR, "in6_multi", "internet multicast address");
10253541Sshin
10353541Sshin/*
10453541Sshin * Definitions of some costant IP6 addresses.
10553541Sshin */
10662587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
10762587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
10862587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes =
10953541Sshin	IN6ADDR_NODELOCAL_ALLNODES_INIT;
11062587Sitojunconst struct in6_addr in6addr_linklocal_allnodes =
11153541Sshin	IN6ADDR_LINKLOCAL_ALLNODES_INIT;
11262587Sitojunconst struct in6_addr in6addr_linklocal_allrouters =
11353541Sshin	IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
11453541Sshin
11562587Sitojunconst struct in6_addr in6mask0 = IN6MASK0;
11662587Sitojunconst struct in6_addr in6mask32 = IN6MASK32;
11762587Sitojunconst struct in6_addr in6mask64 = IN6MASK64;
11862587Sitojunconst struct in6_addr in6mask96 = IN6MASK96;
11962587Sitojunconst struct in6_addr in6mask128 = IN6MASK128;
12053541Sshin
121126552Sumeconst struct sockaddr_in6 sa6_any =
122126552Sume	{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
12378064Sume
12462587Sitojunstatic int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
12583366Sjulian	struct ifnet *, struct thread *));
12678064Sumestatic int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
127120891Sume	struct sockaddr_in6 *, int));
12878064Sumestatic void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *));
12953541Sshin
13062587Sitojunstruct in6_multihead in6_multihead;	/* XXX BSS initialization */
13183934Sbrooksint	(*faithprefix_p)(struct in6_addr *);
13283934Sbrooks
13353541Sshin/*
13453541Sshin * Subroutine for in6_ifaddloop() and in6_ifremloop().
13553541Sshin * This routine does actual work.
13653541Sshin */
13753541Sshinstatic void
13853541Sshinin6_ifloop_request(int cmd, struct ifaddr *ifa)
13953541Sshin{
14053541Sshin	struct sockaddr_in6 all1_sa;
14178064Sume	struct rtentry *nrt = NULL;
14278064Sume	int e;
143165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
144120891Sume
14553541Sshin	bzero(&all1_sa, sizeof(all1_sa));
14678064Sume	all1_sa.sin6_family = AF_INET6;
14778064Sume	all1_sa.sin6_len = sizeof(struct sockaddr_in6);
14853541Sshin	all1_sa.sin6_addr = in6mask128;
14978064Sume
15062587Sitojun	/*
15178064Sume	 * We specify the address itself as the gateway, and set the
15278064Sume	 * RTF_LLINFO flag, so that the corresponding host route would have
15378064Sume	 * the flag, and thus applications that assume traditional behavior
15478064Sume	 * would be happy.  Note that we assume the caller of the function
15578064Sume	 * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
15678064Sume	 * which changes the outgoing interface to the loopback interface.
15762587Sitojun	 */
15878064Sume	e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
159120891Sume	    (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
16078064Sume	if (e != 0) {
161120891Sume		/* XXX need more descriptive message */
162165118Sbz
16378064Sume		log(LOG_ERR, "in6_ifloop_request: "
16478064Sume		    "%s operation failed for %s (errno=%d)\n",
16578064Sume		    cmd == RTM_ADD ? "ADD" : "DELETE",
166165118Sbz		    ip6_sprintf(ip6buf,
167165118Sbz			    &((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), e);
16878064Sume	}
16953541Sshin
170151465Ssuz	/*
171151465Ssuz	 * Report the addition/removal of the address to the routing socket.
172151465Ssuz	 * XXX: since we called rtinit for a p2p interface with a destination,
173151465Ssuz	 *      we end up reporting twice in such a case.  Should we rather
174151465Ssuz	 *      omit the second report?
175151465Ssuz	 */
176120727Ssam	if (nrt) {
177120727Ssam		RT_LOCK(nrt);
178120727Ssam		/*
179120727Ssam		 * Make sure rt_ifa be equal to IFA, the second argument of
180120727Ssam		 * the function.  We need this because when we refer to
181120727Ssam		 * rt_ifa->ia6_flags in ip6_input, we assume that the rt_ifa
182120727Ssam		 * points to the address instead of the loopback address.
183120727Ssam		 */
184120727Ssam		if (cmd == RTM_ADD && ifa != nrt->rt_ifa) {
185120727Ssam			IFAFREE(nrt->rt_ifa);
186120727Ssam			IFAREF(ifa);
187120727Ssam			nrt->rt_ifa = ifa;
188120727Ssam		}
18978064Sume
19078064Sume		rt_newaddrmsg(cmd, ifa, e, nrt);
191169975Sjinmei		if (cmd == RTM_DELETE)
192169975Sjinmei			RTFREE_LOCKED(nrt);
193169975Sjinmei		else {
19478064Sume			/* the cmd must be RTM_ADD here */
195122334Ssam			RT_REMREF(nrt);
196120727Ssam			RT_UNLOCK(nrt);
19778064Sume		}
19878064Sume	}
19953541Sshin}
20053541Sshin
20153541Sshin/*
20278064Sume * Add ownaddr as loopback rtentry.  We previously add the route only if
20378064Sume * necessary (ex. on a p2p link).  However, since we now manage addresses
20478064Sume * separately from prefixes, we should always add the route.  We can't
20578064Sume * rely on the cloning mechanism from the corresponding interface route
20678064Sume * any more.
20753541Sshin */
208142215Sglebiusvoid
20953541Sshinin6_ifaddloop(struct ifaddr *ifa)
21053541Sshin{
21178064Sume	struct rtentry *rt;
212121716Ssam	int need_loop;
21353541Sshin
21478064Sume	/* If there is no loopback entry, allocate one. */
21578064Sume	rt = rtalloc1(ifa->ifa_addr, 0, 0);
216121716Ssam	need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
217121716Ssam	    (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0);
218170200Sjinmei	if (rt)
219170200Sjinmei		RTFREE_LOCKED(rt);
220121716Ssam	if (need_loop)
221121716Ssam		in6_ifloop_request(RTM_ADD, ifa);
22253541Sshin}
22353541Sshin
22453541Sshin/*
22553541Sshin * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
22653541Sshin * if it exists.
22753541Sshin */
228142215Sglebiusvoid
22953541Sshinin6_ifremloop(struct ifaddr *ifa)
23053541Sshin{
23162587Sitojun	struct in6_ifaddr *ia;
23278064Sume	struct rtentry *rt;
23362587Sitojun	int ia_count = 0;
23453541Sshin
23562587Sitojun	/*
23678064Sume	 * Some of BSD variants do not remove cloned routes
23762587Sitojun	 * from an interface direct route, when removing the direct route
23878064Sume	 * (see comments in net/net_osdep.h).  Even for variants that do remove
23978064Sume	 * cloned routes, they could fail to remove the cloned routes when
24078064Sume	 * we handle multple addresses that share a common prefix.
241151465Ssuz	 * So, we should remove the route corresponding to the deleted address.
24262587Sitojun	 */
24378064Sume
24478064Sume	/*
24595023Ssuz	 * Delete the entry only if exact one ifa exists.  More than one ifa
24678064Sume	 * can exist if we assign a same single address to multiple
24778064Sume	 * (probably p2p) interfaces.
24878064Sume	 * XXX: we should avoid such a configuration in IPv6...
24978064Sume	 */
25078064Sume	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
25178064Sume		if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) {
25278064Sume			ia_count++;
25378064Sume			if (ia_count > 1)
25478064Sume				break;
25553541Sshin		}
25678064Sume	}
25778064Sume
25878064Sume	if (ia_count == 1) {
25978064Sume		/*
26078064Sume		 * Before deleting, check if a corresponding loopbacked host
26195023Ssuz		 * route surely exists.  With this check, we can avoid to
26278064Sume		 * delete an interface direct route whose destination is same
263120891Sume		 * as the address being removed.  This can happen when removing
26478064Sume		 * a subnet-router anycast address on an interface attahced
26578064Sume		 * to a shared medium.
26678064Sume		 */
26778064Sume		rt = rtalloc1(ifa->ifa_addr, 0, 0);
268120727Ssam		if (rt != NULL) {
269120727Ssam			if ((rt->rt_flags & RTF_HOST) != 0 &&
270120727Ssam			    (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
271170200Sjinmei				RTFREE_LOCKED(rt);
272120727Ssam				in6_ifloop_request(RTM_DELETE, ifa);
273120727Ssam			} else
274120727Ssam				RT_UNLOCK(rt);
27578064Sume		}
27653541Sshin	}
27753541Sshin}
27853541Sshin
27953541Sshinint
280171259Sdelphijin6_mask2len(struct in6_addr *mask, u_char *lim0)
28153541Sshin{
28278064Sume	int x = 0, y;
28378064Sume	u_char *lim = lim0, *p;
28453541Sshin
285120891Sume	/* ignore the scope_id part */
286120891Sume	if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
28778064Sume		lim = (u_char *)mask + sizeof(*mask);
28878064Sume	for (p = (u_char *)mask; p < lim; x++, p++) {
28978064Sume		if (*p != 0xff)
29053541Sshin			break;
29153541Sshin	}
29253541Sshin	y = 0;
29378064Sume	if (p < lim) {
29453541Sshin		for (y = 0; y < 8; y++) {
29578064Sume			if ((*p & (0x80 >> y)) == 0)
29653541Sshin				break;
29753541Sshin		}
29853541Sshin	}
29978064Sume
30078064Sume	/*
30178064Sume	 * when the limit pointer is given, do a stricter check on the
30278064Sume	 * remaining bits.
30378064Sume	 */
30478064Sume	if (p < lim) {
30578064Sume		if (y != 0 && (*p & (0x00ff >> y)) != 0)
306120856Sume			return (-1);
30778064Sume		for (p = p + 1; p < lim; p++)
30878064Sume			if (*p != 0)
309120856Sume				return (-1);
31078064Sume	}
311120891Sume
31253541Sshin	return x * 8 + y;
31353541Sshin}
31453541Sshin
31553541Sshin#define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
31662587Sitojun#define ia62ifa(ia6)	(&((ia6)->ia_ifa))
31753541Sshin
31853541Sshinint
319171259Sdelphijin6_control(struct socket *so, u_long cmd, caddr_t data,
320171259Sdelphij    struct ifnet *ifp, struct thread *td)
32153541Sshin{
32253541Sshin	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
32378064Sume	struct	in6_ifaddr *ia = NULL;
32453541Sshin	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
325151539Ssuz	struct sockaddr_in6 *sa6;
326164033Srwatson	int error;
32753541Sshin
32862587Sitojun	switch (cmd) {
32962587Sitojun	case SIOCGETSGCNT_IN6:
33062587Sitojun	case SIOCGETMIFCNT_IN6:
331166938Sbms		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
33262587Sitojun	}
33353541Sshin
334121742Sume	switch(cmd) {
335121742Sume	case SIOCAADDRCTL_POLICY:
336121742Sume	case SIOCDADDRCTL_POLICY:
337164033Srwatson		if (td != NULL) {
338164033Srwatson			error = priv_check(td, PRIV_NETINET_ADDRCTRL6);
339164033Srwatson			if (error)
340164033Srwatson				return (error);
341164033Srwatson		}
342121742Sume		return (in6_src_ioctl(cmd, data));
343121742Sume	}
344121742Sume
34562587Sitojun	if (ifp == NULL)
346120856Sume		return (EOPNOTSUPP);
34753541Sshin
34853541Sshin	switch (cmd) {
34953541Sshin	case SIOCSNDFLUSH_IN6:
35053541Sshin	case SIOCSPFXFLUSH_IN6:
35153541Sshin	case SIOCSRTRFLUSH_IN6:
35262587Sitojun	case SIOCSDEFIFACE_IN6:
35362587Sitojun	case SIOCSIFINFO_FLAGS:
354164033Srwatson		if (td != NULL) {
355164033Srwatson			error = priv_check(td, PRIV_NETINET_ND6);
356164033Srwatson			if (error)
357164033Srwatson				return (error);
358164033Srwatson		}
359120891Sume		/* FALLTHROUGH */
36078064Sume	case OSIOCGIFINFO_IN6:
36153541Sshin	case SIOCGIFINFO_IN6:
362151468Ssuz	case SIOCSIFINFO_IN6:
36353541Sshin	case SIOCGDRLST_IN6:
36453541Sshin	case SIOCGPRLST_IN6:
36553541Sshin	case SIOCGNBRINFO_IN6:
36662587Sitojun	case SIOCGDEFIFACE_IN6:
367120856Sume		return (nd6_ioctl(cmd, data, ifp));
36853541Sshin	}
36953541Sshin
37053541Sshin	switch (cmd) {
37153541Sshin	case SIOCSIFPREFIX_IN6:
37253541Sshin	case SIOCDIFPREFIX_IN6:
37353541Sshin	case SIOCAIFPREFIX_IN6:
37453541Sshin	case SIOCCIFPREFIX_IN6:
37553541Sshin	case SIOCSGIFPREFIX_IN6:
37653541Sshin	case SIOCGIFPREFIX_IN6:
37778064Sume		log(LOG_NOTICE,
37878064Sume		    "prefix ioctls are now invalidated. "
37978064Sume		    "please use ifconfig.\n");
380120856Sume		return (EOPNOTSUPP);
38153541Sshin	}
38253541Sshin
38395023Ssuz	switch (cmd) {
38462587Sitojun	case SIOCSSCOPE6:
385164033Srwatson		if (td != NULL) {
386164033Srwatson			error = priv_check(td, PRIV_NETINET_SCOPE6);
387164033Srwatson			if (error)
388164033Srwatson				return (error);
389164033Srwatson		}
390121161Sume		return (scope6_set(ifp,
391121161Sume		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
39262587Sitojun	case SIOCGSCOPE6:
393121161Sume		return (scope6_get(ifp,
394121161Sume		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
39562587Sitojun	case SIOCGSCOPE6DEF:
396121161Sume		return (scope6_get_default((struct scope6_id *)
397121161Sume		    ifr->ifr_ifru.ifru_scope_id));
39862587Sitojun	}
39962587Sitojun
40053541Sshin	switch (cmd) {
40153541Sshin	case SIOCALIFADDR:
40253541Sshin	case SIOCDLIFADDR:
403164033Srwatson		/*
404164033Srwatson		 * XXXRW: Is this checked at another layer?  What priv to use
405164033Srwatson		 * here?
406164033Srwatson		 */
407164033Srwatson		if (td != NULL) {
408164033Srwatson			error = suser(td);
409164033Srwatson			if (error)
410164033Srwatson				return (error);
411164033Srwatson		}
412120891Sume		/* FALLTHROUGH */
41353541Sshin	case SIOCGLIFADDR:
41483366Sjulian		return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
41553541Sshin	}
41653541Sshin
41753541Sshin	/*
41853541Sshin	 * Find address for this interface, if it exists.
419151539Ssuz	 *
420151539Ssuz	 * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
421151539Ssuz	 * only, and used the first interface address as the target of other
422151539Ssuz	 * operations (without checking ifra_addr).  This was because netinet
423151539Ssuz	 * code/API assumed at most 1 interface address per interface.
424151539Ssuz	 * Since IPv6 allows a node to assign multiple addresses
425151539Ssuz	 * on a single interface, we almost always look and check the
426151539Ssuz	 * presence of ifra_addr, and reject invalid ones here.
427151539Ssuz	 * It also decreases duplicated code among SIOC*_IN6 operations.
42853541Sshin	 */
429151539Ssuz	switch (cmd) {
430151539Ssuz	case SIOCAIFADDR_IN6:
431151539Ssuz	case SIOCSIFPHYADDR_IN6:
432151539Ssuz		sa6 = &ifra->ifra_addr;
433151539Ssuz		break;
434151539Ssuz	case SIOCSIFADDR_IN6:
435151539Ssuz	case SIOCGIFADDR_IN6:
436151539Ssuz	case SIOCSIFDSTADDR_IN6:
437151539Ssuz	case SIOCSIFNETMASK_IN6:
438151539Ssuz	case SIOCGIFDSTADDR_IN6:
439151539Ssuz	case SIOCGIFNETMASK_IN6:
440151539Ssuz	case SIOCDIFADDR_IN6:
441151539Ssuz	case SIOCGIFPSRCADDR_IN6:
442151539Ssuz	case SIOCGIFPDSTADDR_IN6:
443151539Ssuz	case SIOCGIFAFLAG_IN6:
444151539Ssuz	case SIOCSNDFLUSH_IN6:
445151539Ssuz	case SIOCSPFXFLUSH_IN6:
446151539Ssuz	case SIOCSRTRFLUSH_IN6:
447151539Ssuz	case SIOCGIFALIFETIME_IN6:
448151539Ssuz	case SIOCSIFALIFETIME_IN6:
449151539Ssuz	case SIOCGIFSTAT_IN6:
450151539Ssuz	case SIOCGIFSTAT_ICMP6:
451151539Ssuz		sa6 = &ifr->ifr_addr;
452151539Ssuz		break;
453151539Ssuz	default:
454151539Ssuz		sa6 = NULL;
455151539Ssuz		break;
456151539Ssuz	}
457151539Ssuz	if (sa6 && sa6->sin6_family == AF_INET6) {
458148385Sume		int error = 0;
45953541Sshin
460151539Ssuz		if (sa6->sin6_scope_id != 0)
461151539Ssuz			error = sa6_embedscope(sa6, 0);
462148385Sume		else
463151539Ssuz			error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
464148385Sume		if (error != 0)
465148385Sume			return (error);
466151539Ssuz		ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
467151539Ssuz	} else
468151539Ssuz		ia = NULL;
46953541Sshin
47053541Sshin	switch (cmd) {
47178064Sume	case SIOCSIFADDR_IN6:
47278064Sume	case SIOCSIFDSTADDR_IN6:
47378064Sume	case SIOCSIFNETMASK_IN6:
47478064Sume		/*
47578064Sume		 * Since IPv6 allows a node to assign multiple addresses
476151465Ssuz		 * on a single interface, SIOCSIFxxx ioctls are deprecated.
47778064Sume		 */
47878064Sume		/* we decided to obsolete this command (20000704) */
479120856Sume		return (EINVAL);
48053541Sshin
48153541Sshin	case SIOCDIFADDR_IN6:
48262587Sitojun		/*
48378064Sume		 * for IPv4, we look for existing in_ifaddr here to allow
484151465Ssuz		 * "ifconfig if0 delete" to remove the first IPv4 address on
485151465Ssuz		 * the interface.  For IPv6, as the spec allows multiple
486151465Ssuz		 * interface address from the day one, we consider "remove the
487151465Ssuz		 * first one" semantics to be not preferable.
48862587Sitojun		 */
48962587Sitojun		if (ia == NULL)
490120856Sume			return (EADDRNOTAVAIL);
49153541Sshin		/* FALLTHROUGH */
49253541Sshin	case SIOCAIFADDR_IN6:
49362587Sitojun		/*
49478064Sume		 * We always require users to specify a valid IPv6 address for
49578064Sume		 * the corresponding operation.
49662587Sitojun		 */
49778064Sume		if (ifra->ifra_addr.sin6_family != AF_INET6 ||
49878064Sume		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
499120856Sume			return (EAFNOSUPPORT);
50053541Sshin
501164033Srwatson		/*
502164033Srwatson		 * XXXRW: Is this checked at another layer?  What priv to use
503164033Srwatson		 * here?
504164033Srwatson		 */
505164033Srwatson		if (td != NULL) {
506164033Srwatson			error = suser(td);
507164033Srwatson			if (error)
508164033Srwatson				return (error);
509164033Srwatson		}
510164033Srwatson
51153541Sshin		break;
51253541Sshin
51353541Sshin	case SIOCGIFADDR_IN6:
51453541Sshin		/* This interface is basically deprecated. use SIOCGIFCONF. */
515120891Sume		/* FALLTHROUGH */
51653541Sshin	case SIOCGIFAFLAG_IN6:
51753541Sshin	case SIOCGIFNETMASK_IN6:
51853541Sshin	case SIOCGIFDSTADDR_IN6:
51953541Sshin	case SIOCGIFALIFETIME_IN6:
52053541Sshin		/* must think again about its semantics */
52162587Sitojun		if (ia == NULL)
522120856Sume			return (EADDRNOTAVAIL);
52353541Sshin		break;
52453541Sshin	case SIOCSIFALIFETIME_IN6:
52553541Sshin	    {
52653541Sshin		struct in6_addrlifetime *lt;
52753541Sshin
528164033Srwatson		if (td != NULL) {
529164033Srwatson			error = priv_check(td, PRIV_NETINET_ALIFETIME6);
530164033Srwatson			if (error)
531164033Srwatson				return (error);
532164033Srwatson		}
53362587Sitojun		if (ia == NULL)
534120856Sume			return (EADDRNOTAVAIL);
53553541Sshin		/* sanity for overflow - beware unsigned */
53653541Sshin		lt = &ifr->ifr_ifru.ifru_lifetime;
537126552Sume		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME &&
538126552Sume		    lt->ia6t_vltime + time_second < time_second) {
53953541Sshin			return EINVAL;
54053541Sshin		}
541126552Sume		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME &&
542126552Sume		    lt->ia6t_pltime + time_second < time_second) {
54353541Sshin			return EINVAL;
54453541Sshin		}
54553541Sshin		break;
54653541Sshin	    }
54753541Sshin	}
54853541Sshin
54953541Sshin	switch (cmd) {
55053541Sshin
55153541Sshin	case SIOCGIFADDR_IN6:
55253541Sshin		ifr->ifr_addr = ia->ia_addr;
553148385Sume		if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
554148385Sume			return (error);
55553541Sshin		break;
55653541Sshin
55753541Sshin	case SIOCGIFDSTADDR_IN6:
55853541Sshin		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
559120856Sume			return (EINVAL);
56062587Sitojun		/*
56162587Sitojun		 * XXX: should we check if ifa_dstaddr is NULL and return
56262587Sitojun		 * an error?
56362587Sitojun		 */
56453541Sshin		ifr->ifr_dstaddr = ia->ia_dstaddr;
565148385Sume		if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0)
566148385Sume			return (error);
56753541Sshin		break;
56853541Sshin
56953541Sshin	case SIOCGIFNETMASK_IN6:
57053541Sshin		ifr->ifr_addr = ia->ia_prefixmask;
57153541Sshin		break;
57253541Sshin
57353541Sshin	case SIOCGIFAFLAG_IN6:
57453541Sshin		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
57553541Sshin		break;
57653541Sshin
57753541Sshin	case SIOCGIFSTAT_IN6:
578121167Sume		if (ifp == NULL)
579121167Sume			return EINVAL;
580121161Sume		bzero(&ifr->ifr_ifru.ifru_stat,
581121161Sume		    sizeof(ifr->ifr_ifru.ifru_stat));
582121161Sume		ifr->ifr_ifru.ifru_stat =
583121161Sume		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
58453541Sshin		break;
58553541Sshin
58653541Sshin	case SIOCGIFSTAT_ICMP6:
58753541Sshin		if (ifp == NULL)
58853541Sshin			return EINVAL;
589155454Sgnn		bzero(&ifr->ifr_ifru.ifru_icmp6stat,
590121161Sume		    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
591121161Sume		ifr->ifr_ifru.ifru_icmp6stat =
592121161Sume		    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
59353541Sshin		break;
59453541Sshin
59553541Sshin	case SIOCGIFALIFETIME_IN6:
59653541Sshin		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
597151539Ssuz		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
598151539Ssuz			time_t maxexpire;
599151539Ssuz			struct in6_addrlifetime *retlt =
600151539Ssuz			    &ifr->ifr_ifru.ifru_lifetime;
601151539Ssuz
602151539Ssuz			/*
603151539Ssuz			 * XXX: adjust expiration time assuming time_t is
604151539Ssuz			 * signed.
605151539Ssuz			 */
606151539Ssuz			maxexpire = (-1) &
607151546Ssuz			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
608151539Ssuz			if (ia->ia6_lifetime.ia6t_vltime <
609151539Ssuz			    maxexpire - ia->ia6_updatetime) {
610151539Ssuz				retlt->ia6t_expire = ia->ia6_updatetime +
611151539Ssuz				    ia->ia6_lifetime.ia6t_vltime;
612151539Ssuz			} else
613151539Ssuz				retlt->ia6t_expire = maxexpire;
614151539Ssuz		}
615151539Ssuz		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
616151539Ssuz			time_t maxexpire;
617151539Ssuz			struct in6_addrlifetime *retlt =
618151539Ssuz			    &ifr->ifr_ifru.ifru_lifetime;
619151539Ssuz
620151539Ssuz			/*
621151539Ssuz			 * XXX: adjust expiration time assuming time_t is
622151539Ssuz			 * signed.
623151539Ssuz			 */
624151539Ssuz			maxexpire = (-1) &
625151546Ssuz			    ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
626151539Ssuz			if (ia->ia6_lifetime.ia6t_pltime <
627151539Ssuz			    maxexpire - ia->ia6_updatetime) {
628151539Ssuz				retlt->ia6t_preferred = ia->ia6_updatetime +
629151539Ssuz				    ia->ia6_lifetime.ia6t_pltime;
630151539Ssuz			} else
631151539Ssuz				retlt->ia6t_preferred = maxexpire;
632151539Ssuz		}
63353541Sshin		break;
63453541Sshin
63553541Sshin	case SIOCSIFALIFETIME_IN6:
63653541Sshin		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
63753541Sshin		/* for sanity */
63853541Sshin		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
63953541Sshin			ia->ia6_lifetime.ia6t_expire =
64053541Sshin				time_second + ia->ia6_lifetime.ia6t_vltime;
64153541Sshin		} else
64253541Sshin			ia->ia6_lifetime.ia6t_expire = 0;
64353541Sshin		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
64453541Sshin			ia->ia6_lifetime.ia6t_preferred =
64553541Sshin				time_second + ia->ia6_lifetime.ia6t_pltime;
64653541Sshin		} else
64753541Sshin			ia->ia6_lifetime.ia6t_preferred = 0;
64853541Sshin		break;
64953541Sshin
65078064Sume	case SIOCAIFADDR_IN6:
65178064Sume	{
65278064Sume		int i, error = 0;
653151539Ssuz		struct nd_prefixctl pr0;
654151539Ssuz		struct nd_prefix *pr;
65578064Sume
65662587Sitojun		/*
65778064Sume		 * first, make or update the interface address structure,
65878064Sume		 * and link it to the list.
65962587Sitojun		 */
660151539Ssuz		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
661120856Sume			return (error);
662151915Ssuz		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
663151915Ssuz		    == NULL) {
664171260Sdelphij			/*
665151915Ssuz			 * this can happen when the user specify the 0 valid
666151915Ssuz			 * lifetime.
667151915Ssuz			 */
668151915Ssuz			break;
669151915Ssuz		}
67053541Sshin
67178064Sume		/*
67278064Sume		 * then, make the prefix on-link on the interface.
67378064Sume		 * XXX: we'd rather create the prefix before the address, but
67478064Sume		 * we need at least one address to install the corresponding
67578064Sume		 * interface route, so we configure the address first.
67678064Sume		 */
67778064Sume
67878064Sume		/*
67978064Sume		 * convert mask to prefix length (prefixmask has already
68078064Sume		 * been validated in in6_update_ifa().
68178064Sume		 */
68278064Sume		bzero(&pr0, sizeof(pr0));
68378064Sume		pr0.ndpr_ifp = ifp;
68478064Sume		pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
685120891Sume		    NULL);
686120891Sume		if (pr0.ndpr_plen == 128) {
68778064Sume			break;	/* we don't need to install a host route. */
688120891Sume		}
68978064Sume		pr0.ndpr_prefix = ifra->ifra_addr;
69078064Sume		/* apply the mask for safety. */
69178064Sume		for (i = 0; i < 4; i++) {
69278064Sume			pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
693120891Sume			    ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
69478064Sume		}
69578064Sume		/*
69695023Ssuz		 * XXX: since we don't have an API to set prefix (not address)
69795023Ssuz		 * lifetimes, we just use the same lifetimes as addresses.
69895023Ssuz		 * The (temporarily) installed lifetimes can be overridden by
69995023Ssuz		 * later advertised RAs (when accept_rtadv is non 0), which is
70095023Ssuz		 * an intended behavior.
70178064Sume		 */
70278064Sume		pr0.ndpr_raf_onlink = 1; /* should be configurable? */
70378064Sume		pr0.ndpr_raf_auto =
704120891Sume		    ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
70578064Sume		pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
70678064Sume		pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
70778064Sume
708120891Sume		/* add the prefix if not yet. */
70978064Sume		if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
71078064Sume			/*
71178064Sume			 * nd6_prelist_add will install the corresponding
71278064Sume			 * interface route.
71378064Sume			 */
71478064Sume			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
715120856Sume				return (error);
71678064Sume			if (pr == NULL) {
717120891Sume				log(LOG_ERR, "nd6_prelist_add succeeded but "
71878064Sume				    "no prefix\n");
719120856Sume				return (EINVAL); /* XXX panic here? */
72078064Sume			}
72178064Sume		}
72278064Sume
723151915Ssuz		/* relate the address to the prefix */
724151915Ssuz		if (ia->ia6_ndpr == NULL) {
725151915Ssuz			ia->ia6_ndpr = pr;
726151915Ssuz			pr->ndpr_refcnt++;
72778064Sume
72878064Sume			/*
729151915Ssuz			 * If this is the first autoconf address from the
730151915Ssuz			 * prefix, create a temporary address as well
731151915Ssuz			 * (when required).
73278064Sume			 */
733151915Ssuz			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
734151915Ssuz			    ip6_use_tempaddr && pr->ndpr_refcnt == 1) {
735151915Ssuz				int e;
736151915Ssuz				if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
737151915Ssuz					log(LOG_NOTICE, "in6_control: failed "
738151915Ssuz					    "to create a temporary address, "
739151915Ssuz					    "errno=%d\n", e);
740151915Ssuz				}
741151915Ssuz			}
74262587Sitojun		}
743151915Ssuz
744151915Ssuz		/*
745151915Ssuz		 * this might affect the status of autoconfigured addresses,
746151915Ssuz		 * that is, this address might make other addresses detached.
747151915Ssuz		 */
748151915Ssuz		pfxlist_onlink_check();
749126264Smlaier		if (error == 0 && ia)
750126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
75178064Sume		break;
75278064Sume	}
75362587Sitojun
75478064Sume	case SIOCDIFADDR_IN6:
75578064Sume	{
756151539Ssuz		struct nd_prefix *pr;
75778064Sume
75878064Sume		/*
75978064Sume		 * If the address being deleted is the only one that owns
76078064Sume		 * the corresponding prefix, expire the prefix as well.
761120891Sume		 * XXX: theoretically, we don't have to worry about such
76278064Sume		 * relationship, since we separate the address management
76378064Sume		 * and the prefix management.  We do this, however, to provide
76478064Sume		 * as much backward compatibility as possible in terms of
76578064Sume		 * the ioctl operation.
766151915Ssuz		 * Note that in6_purgeaddr() will decrement ndpr_refcnt.
76778064Sume		 */
768151915Ssuz		pr = ia->ia6_ndpr;
76978064Sume		in6_purgeaddr(&ia->ia_ifa);
770151915Ssuz		if (pr && pr->ndpr_refcnt == 0)
771151915Ssuz			prelist_remove(pr);
772126264Smlaier		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
77353541Sshin		break;
77478064Sume	}
77553541Sshin
77678064Sume	default:
77778064Sume		if (ifp == NULL || ifp->if_ioctl == 0)
778120856Sume			return (EOPNOTSUPP);
779120856Sume		return ((*ifp->if_ioctl)(ifp, cmd, data));
78078064Sume	}
78153541Sshin
782120856Sume	return (0);
78378064Sume}
78453541Sshin
78578064Sume/*
78678064Sume * Update parameters of an IPv6 interface address.
78778064Sume * If necessary, a new entry is created and linked into address chains.
78878064Sume * This function is separated from in6_control().
78978064Sume * XXX: should this be performed under splnet()?
79078064Sume */
79178064Sumeint
792171259Sdelphijin6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
793171259Sdelphij    struct in6_ifaddr *ia, int flags)
79478064Sume{
79578064Sume	int error = 0, hostIsNew = 0, plen = -1;
79678064Sume	struct in6_ifaddr *oia;
79778064Sume	struct sockaddr_in6 dst6;
79878064Sume	struct in6_addrlifetime *lt;
799151539Ssuz	struct in6_multi_mship *imm;
800151539Ssuz	struct in6_multi *in6m_sol;
801148385Sume	struct rtentry *rt;
802151539Ssuz	int delay;
803165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
80478064Sume
80578064Sume	/* Validate parameters */
80678064Sume	if (ifp == NULL || ifra == NULL) /* this maybe redundant */
807120856Sume		return (EINVAL);
80878064Sume
80978064Sume	/*
81078064Sume	 * The destination address for a p2p link must have a family
81178064Sume	 * of AF_UNSPEC or AF_INET6.
81278064Sume	 */
81378064Sume	if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
81478064Sume	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
81578064Sume	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
816120856Sume		return (EAFNOSUPPORT);
81778064Sume	/*
81878064Sume	 * validate ifra_prefixmask.  don't check sin6_family, netmask
81978064Sume	 * does not carry fields other than sin6_len.
82078064Sume	 */
82178064Sume	if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
822120856Sume		return (EINVAL);
82378064Sume	/*
82478064Sume	 * Because the IPv6 address architecture is classless, we require
82578064Sume	 * users to specify a (non 0) prefix length (mask) for a new address.
82678064Sume	 * We also require the prefix (when specified) mask is valid, and thus
82778064Sume	 * reject a non-consecutive mask.
82878064Sume	 */
82978064Sume	if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
830120856Sume		return (EINVAL);
83178064Sume	if (ifra->ifra_prefixmask.sin6_len != 0) {
83278064Sume		plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
833120891Sume		    (u_char *)&ifra->ifra_prefixmask +
834120891Sume		    ifra->ifra_prefixmask.sin6_len);
83578064Sume		if (plen <= 0)
836120856Sume			return (EINVAL);
837120891Sume	} else {
83862587Sitojun		/*
83995023Ssuz		 * In this case, ia must not be NULL.  We just use its prefix
84078064Sume		 * length.
84162587Sitojun		 */
84278064Sume		plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
84378064Sume	}
84478064Sume	/*
84578064Sume	 * If the destination address on a p2p interface is specified,
84678064Sume	 * and the address is a scoped one, validate/set the scope
84778064Sume	 * zone identifier.
84878064Sume	 */
84978064Sume	dst6 = ifra->ifra_dstaddr;
850120891Sume	if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 &&
85178064Sume	    (dst6.sin6_family == AF_INET6)) {
852148385Sume		struct in6_addr in6_tmp;
853126552Sume		u_int32_t zoneid;
85478064Sume
855148385Sume		in6_tmp = dst6.sin6_addr;
856148385Sume		if (in6_setscope(&in6_tmp, ifp, &zoneid))
857148385Sume			return (EINVAL); /* XXX: should be impossible */
858148385Sume
859148385Sume		if (dst6.sin6_scope_id != 0) {
860148385Sume			if (dst6.sin6_scope_id != zoneid)
861148385Sume				return (EINVAL);
862148385Sume		} else		/* user omit to specify the ID. */
863126552Sume			dst6.sin6_scope_id = zoneid;
864148385Sume
865148385Sume		/* convert into the internal form */
866148385Sume		if (sa6_embedscope(&dst6, 0))
867148385Sume			return (EINVAL); /* XXX: should be impossible */
86878064Sume	}
86978064Sume	/*
87078064Sume	 * The destination address can be specified only for a p2p or a
87178064Sume	 * loopback interface.  If specified, the corresponding prefix length
87278064Sume	 * must be 128.
87378064Sume	 */
87478064Sume	if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
87578064Sume		if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
876126552Sume			/* XXX: noisy message */
877122059Sume			nd6log((LOG_INFO, "in6_update_ifa: a destination can "
878122059Sume			    "be specified for a p2p or a loopback IF only\n"));
879120856Sume			return (EINVAL);
88078064Sume		}
88178064Sume		if (plen != 128) {
882122059Sume			nd6log((LOG_INFO, "in6_update_ifa: prefixlen should "
883122059Sume			    "be 128 when dstaddr is specified\n"));
884120856Sume			return (EINVAL);
88578064Sume		}
88678064Sume	}
88778064Sume	/* lifetime consistency check */
88878064Sume	lt = &ifra->ifra_lifetime;
889151539Ssuz	if (lt->ia6t_pltime > lt->ia6t_vltime)
890151539Ssuz		return (EINVAL);
89178064Sume	if (lt->ia6t_vltime == 0) {
89262587Sitojun		/*
89378064Sume		 * the following log might be noisy, but this is a typical
89478064Sume		 * configuration mistake or a tool's bug.
89562587Sitojun		 */
896122059Sume		nd6log((LOG_INFO,
89778064Sume		    "in6_update_ifa: valid lifetime is 0 for %s\n",
898165118Sbz		    ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr)));
899151539Ssuz
900151539Ssuz		if (ia == NULL)
901151539Ssuz			return (0); /* there's nothing to do */
90278064Sume	}
90362587Sitojun
90478064Sume	/*
90578064Sume	 * If this is a new address, allocate a new ifaddr and link it
90678064Sume	 * into chains.
90778064Sume	 */
90878064Sume	if (ia == NULL) {
90978064Sume		hostIsNew = 1;
91079763Sume		/*
91179763Sume		 * When in6_update_ifa() is called in a process of a received
912120891Sume		 * RA, it is called under an interrupt context.  So, we should
913120891Sume		 * call malloc with M_NOWAIT.
91479763Sume		 */
915120891Sume		ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR,
916120891Sume		    M_NOWAIT);
91778064Sume		if (ia == NULL)
91878064Sume			return (ENOBUFS);
91978064Sume		bzero((caddr_t)ia, sizeof(*ia));
920170202Sjinmei		LIST_INIT(&ia->ia6_memberships);
921151539Ssuz		/* Initialize the address and masks, and put time stamp */
922108033Shsu		IFA_LOCK_INIT(&ia->ia_ifa);
92378064Sume		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
92478064Sume		ia->ia_addr.sin6_family = AF_INET6;
92578064Sume		ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
926151539Ssuz		ia->ia6_createtime = time_second;
92778064Sume		if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
92878064Sume			/*
92978064Sume			 * XXX: some functions expect that ifa_dstaddr is not
93078064Sume			 * NULL for p2p interfaces.
93178064Sume			 */
932120891Sume			ia->ia_ifa.ifa_dstaddr =
933120891Sume			    (struct sockaddr *)&ia->ia_dstaddr;
93478064Sume		} else {
93578064Sume			ia->ia_ifa.ifa_dstaddr = NULL;
93653541Sshin		}
937108033Shsu		ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
93878064Sume
93978064Sume		ia->ia_ifp = ifp;
94078064Sume		if ((oia = in6_ifaddr) != NULL) {
94178064Sume			for ( ; oia->ia_next; oia = oia->ia_next)
94278064Sume				continue;
94378064Sume			oia->ia_next = ia;
94478064Sume		} else
94578064Sume			in6_ifaddr = ia;
94678064Sume
947108033Shsu		ia->ia_ifa.ifa_refcnt = 1;
948108033Shsu		TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
94978064Sume	}
95078064Sume
951151539Ssuz	/* update timestamp */
952151539Ssuz	ia->ia6_updatetime = time_second;
953151539Ssuz
95478064Sume	/* set prefix mask */
95578064Sume	if (ifra->ifra_prefixmask.sin6_len) {
95678064Sume		/*
95778064Sume		 * We prohibit changing the prefix length of an existing
95878064Sume		 * address, because
95978064Sume		 * + such an operation should be rare in IPv6, and
96078064Sume		 * + the operation would confuse prefix management.
96178064Sume		 */
96278064Sume		if (ia->ia_prefixmask.sin6_len &&
96378064Sume		    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
964122059Sume			nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an"
96578064Sume			    " existing (%s) address should not be changed\n",
966165118Sbz			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
96778064Sume			error = EINVAL;
96878064Sume			goto unlink;
96953541Sshin		}
97078064Sume		ia->ia_prefixmask = ifra->ifra_prefixmask;
97178064Sume	}
97278064Sume
97378064Sume	/*
97478064Sume	 * If a new destination address is specified, scrub the old one and
97578064Sume	 * install the new destination.  Note that the interface must be
976120891Sume	 * p2p or loopback (see the check above.)
97778064Sume	 */
97878064Sume	if (dst6.sin6_family == AF_INET6 &&
979120891Sume	    !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
98078064Sume		int e;
98178064Sume
98278064Sume		if ((ia->ia_flags & IFA_ROUTE) != 0 &&
983120891Sume		    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) {
984122059Sume			nd6log((LOG_ERR, "in6_update_ifa: failed to remove "
98578064Sume			    "a route to the old destination: %s\n",
986165118Sbz			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
98778064Sume			/* proceed anyway... */
988120891Sume		} else
98978064Sume			ia->ia_flags &= ~IFA_ROUTE;
99078064Sume		ia->ia_dstaddr = dst6;
99178064Sume	}
99253541Sshin
993148385Sume	/*
994148385Sume	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
995148385Sume	 * to see if the address is deprecated or invalidated, but initialize
996148385Sume	 * these members for applications.
997148385Sume	 */
998148385Sume	ia->ia6_lifetime = ifra->ifra_lifetime;
999148385Sume	if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
1000148385Sume		ia->ia6_lifetime.ia6t_expire =
1001148385Sume		    time_second + ia->ia6_lifetime.ia6t_vltime;
1002148385Sume	} else
1003148385Sume		ia->ia6_lifetime.ia6t_expire = 0;
1004148385Sume	if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
1005148385Sume		ia->ia6_lifetime.ia6t_preferred =
1006148385Sume		    time_second + ia->ia6_lifetime.ia6t_pltime;
1007148385Sume	} else
1008148385Sume		ia->ia6_lifetime.ia6t_preferred = 0;
1009148385Sume
101078064Sume	/* reset the interface and routing table appropriately. */
101178064Sume	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
101278064Sume		goto unlink;
101378064Sume
101478064Sume	/*
1015148385Sume	 * configure address flags.
1016148385Sume	 */
1017148385Sume	ia->ia6_flags = ifra->ifra_flags;
1018148385Sume	/*
1019148385Sume	 * backward compatibility - if IN6_IFF_DEPRECATED is set from the
1020148385Sume	 * userland, make it deprecated.
1021148385Sume	 */
1022148385Sume	if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
1023148385Sume		ia->ia6_lifetime.ia6t_pltime = 0;
1024148385Sume		ia->ia6_lifetime.ia6t_preferred = time_second;
1025148385Sume	}
1026148385Sume	/*
1027151539Ssuz	 * Make the address tentative before joining multicast addresses,
1028151539Ssuz	 * so that corresponding MLD responses would not have a tentative
1029151539Ssuz	 * source address.
1030148385Sume	 */
1031151539Ssuz	ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/* safety */
1032151539Ssuz	if (hostIsNew && in6if_do_dad(ifp))
1033148385Sume		ia->ia6_flags |= IN6_IFF_TENTATIVE;
1034148385Sume
1035148385Sume	/*
1036148385Sume	 * We are done if we have simply modified an existing address.
1037148385Sume	 */
1038148385Sume	if (!hostIsNew)
1039148385Sume		return (error);
1040148385Sume
1041148385Sume	/*
104278064Sume	 * Beyond this point, we should call in6_purgeaddr upon an error,
1043120891Sume	 * not just go to unlink.
104478064Sume	 */
104578064Sume
1046151465Ssuz	/* Join necessary multicast groups */
1047151539Ssuz	in6m_sol = NULL;
104878064Sume	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
104978064Sume		struct sockaddr_in6 mltaddr, mltmask;
1050148385Sume		struct in6_addr llsol;
105178064Sume
1052148385Sume		/* join solicited multicast addr for new host id */
1053148385Sume		bzero(&llsol, sizeof(struct in6_addr));
1054151465Ssuz		llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
1055148385Sume		llsol.s6_addr32[1] = 0;
1056148385Sume		llsol.s6_addr32[2] = htonl(1);
1057148385Sume		llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
1058148385Sume		llsol.s6_addr8[12] = 0xff;
1059148385Sume		if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
1060148385Sume			/* XXX: should not happen */
1061148385Sume			log(LOG_ERR, "in6_update_ifa: "
1062148385Sume			    "in6_setscope failed\n");
1063148385Sume			goto cleanup;
106453541Sshin		}
1065151539Ssuz		delay = 0;
1066151539Ssuz		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1067151539Ssuz			/*
1068151539Ssuz			 * We need a random delay for DAD on the address
1069151539Ssuz			 * being configured.  It also means delaying
1070151539Ssuz			 * transmission of the corresponding MLD report to
1071151539Ssuz			 * avoid report collision.
1072151539Ssuz			 * [draft-ietf-ipv6-rfc2462bis-02.txt]
1073151539Ssuz			 */
1074151539Ssuz			delay = arc4random() %
1075151539Ssuz			    (MAX_RTR_SOLICITATION_DELAY * hz);
1076151539Ssuz		}
1077151539Ssuz		imm = in6_joingroup(ifp, &llsol, &error, delay);
1078170202Sjinmei		if (imm == NULL) {
1079148385Sume			nd6log((LOG_WARNING,
1080148385Sume			    "in6_update_ifa: addmulti failed for "
1081148385Sume			    "%s on %s (errno=%d)\n",
1082165118Sbz			    ip6_sprintf(ip6buf, &llsol), if_name(ifp),
1083148385Sume			    error));
1084151539Ssuz			in6_purgeaddr((struct ifaddr *)ia);
1085151539Ssuz			return (error);
1086148385Sume		}
1087170202Sjinmei		LIST_INSERT_HEAD(&ia->ia6_memberships,
1088170202Sjinmei		    imm, i6mm_chain);
1089151539Ssuz		in6m_sol = imm->i6mm_maddr;
109053541Sshin
109178064Sume		bzero(&mltmask, sizeof(mltmask));
109278064Sume		mltmask.sin6_len = sizeof(struct sockaddr_in6);
109378064Sume		mltmask.sin6_family = AF_INET6;
109478064Sume		mltmask.sin6_addr = in6mask32;
1095151465Ssuz#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
109653541Sshin
109753541Sshin		/*
109878064Sume		 * join link-local all-nodes address
109971207Sitojun		 */
110078064Sume		bzero(&mltaddr, sizeof(mltaddr));
110178064Sume		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
110278064Sume		mltaddr.sin6_family = AF_INET6;
110378064Sume		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
1104148385Sume		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
1105148385Sume		    0)
1106148385Sume			goto cleanup; /* XXX: should not fail */
110771207Sitojun
1108148385Sume		/*
1109148385Sume		 * XXX: do we really need this automatic routes?
1110148385Sume		 * We should probably reconsider this stuff.  Most applications
1111148385Sume		 * actually do not need the routes, since they usually specify
1112148385Sume		 * the outgoing interface.
1113148385Sume		 */
1114148385Sume		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1115148385Sume		if (rt) {
1116174375Sjulian			/* XXX: only works in !SCOPEDROUTING case. */
1117148385Sume			if (memcmp(&mltaddr.sin6_addr,
1118148385Sume			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1119151465Ssuz			    MLTMASK_LEN)) {
1120148385Sume				RTFREE_LOCKED(rt);
1121148385Sume				rt = NULL;
1122148385Sume			}
1123148385Sume		}
1124148385Sume		if (!rt) {
1125148385Sume			/* XXX: we need RTF_CLONING to fake nd6_rtrequest */
1126148385Sume			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
1127148385Sume			    (struct sockaddr *)&ia->ia_addr,
1128148385Sume			    (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING,
1129148385Sume			    (struct rtentry **)0);
1130148385Sume			if (error)
1131148385Sume				goto cleanup;
1132151539Ssuz		} else {
1133151539Ssuz			RTFREE_LOCKED(rt);
1134151539Ssuz		}
113578064Sume
1136151539Ssuz		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
1137151539Ssuz		if (!imm) {
1138151539Ssuz			nd6log((LOG_WARNING,
1139151539Ssuz			    "in6_update_ifa: addmulti failed for "
1140151539Ssuz			    "%s on %s (errno=%d)\n",
1141165118Sbz			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
1142151539Ssuz			    if_name(ifp), error));
1143151539Ssuz			goto cleanup;
1144151539Ssuz		}
1145170202Sjinmei		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
1146151539Ssuz
114771207Sitojun		/*
114878064Sume		 * join node information group address
114953541Sshin		 */
115078064Sume#define hostnamelen	strlen(hostname)
1151151539Ssuz		delay = 0;
1152151539Ssuz		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1153151539Ssuz			/*
1154151539Ssuz			 * The spec doesn't say anything about delay for this
1155151539Ssuz			 * group, but the same logic should apply.
1156151539Ssuz			 */
1157151539Ssuz			delay = arc4random() %
1158151539Ssuz			    (MAX_RTR_SOLICITATION_DELAY * hz);
1159151539Ssuz		}
116078064Sume		if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
116178064Sume		    == 0) {
1162151539Ssuz			imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
1163151539Ssuz			    delay); /* XXX jinmei */
1164151539Ssuz			if (!imm) {
1165151539Ssuz				nd6log((LOG_WARNING, "in6_update_ifa: "
1166151539Ssuz				    "addmulti failed for %s on %s "
1167151539Ssuz				    "(errno=%d)\n",
1168165118Sbz				    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
1169151539Ssuz				    if_name(ifp), error));
1170151539Ssuz				/* XXX not very fatal, go on... */
1171170202Sjinmei			} else {
1172170202Sjinmei				LIST_INSERT_HEAD(&ia->ia6_memberships,
1173170202Sjinmei				    imm, i6mm_chain);
117462587Sitojun			}
117553541Sshin		}
117678064Sume#undef hostnamelen
117753541Sshin
117878064Sume		/*
1179148385Sume		 * join interface-local all-nodes address.
1180148385Sume		 * (ff01::1%ifN, and ff01::%ifN/32)
118178064Sume		 */
1182148385Sume		mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
1183148385Sume		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
1184148385Sume		    != 0)
1185148385Sume			goto cleanup; /* XXX: should not fail */
1186148385Sume		/* XXX: again, do we really need the route? */
1187148385Sume		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1188148385Sume		if (rt) {
1189148385Sume			if (memcmp(&mltaddr.sin6_addr,
1190148385Sume			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1191151465Ssuz			    MLTMASK_LEN)) {
1192148385Sume				RTFREE_LOCKED(rt);
1193148385Sume				rt = NULL;
1194148385Sume			}
1195148385Sume		}
1196148385Sume		if (!rt) {
1197148385Sume			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
1198148385Sume			    (struct sockaddr *)&ia->ia_addr,
1199148385Sume			    (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING,
1200148385Sume			    (struct rtentry **)0);
1201148385Sume			if (error)
1202148385Sume				goto cleanup;
1203148385Sume		} else
1204148385Sume			RTFREE_LOCKED(rt);
120581115Sume
1206151539Ssuz		/* XXX: again, do we really need the route? */
1207151539Ssuz		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1208151539Ssuz		if (rt) {
1209151539Ssuz			if (memcmp(&mltaddr.sin6_addr,
1210151539Ssuz			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1211151539Ssuz			    MLTMASK_LEN)) {
1212151539Ssuz				RTFREE_LOCKED(rt);
1213151539Ssuz				rt = NULL;
121478064Sume			}
121553541Sshin		}
1216151539Ssuz		if (!rt) {
1217151539Ssuz			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
1218151539Ssuz			    (struct sockaddr *)&ia->ia_addr,
1219151539Ssuz			    (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING,
1220151539Ssuz			    (struct rtentry **)0);
1221151539Ssuz			if (error)
1222151539Ssuz				goto cleanup;
1223151539Ssuz		} else {
1224151539Ssuz			RTFREE_LOCKED(rt);
1225151539Ssuz		}
1226151539Ssuz
1227151539Ssuz		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
1228151539Ssuz		if (!imm) {
1229151539Ssuz			nd6log((LOG_WARNING, "in6_update_ifa: "
1230151539Ssuz			    "addmulti failed for %s on %s "
1231151539Ssuz			    "(errno=%d)\n",
1232165118Sbz			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
1233151539Ssuz			    if_name(ifp), error));
1234151539Ssuz			goto cleanup;
1235151539Ssuz		}
1236170202Sjinmei		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
1237151465Ssuz#undef	MLTMASK_LEN
123878064Sume	}
123953541Sshin
1240151539Ssuz	/*
1241151539Ssuz	 * Perform DAD, if needed.
1242151539Ssuz	 * XXX It may be of use, if we can administratively
1243151539Ssuz	 * disable DAD.
1244151539Ssuz	 */
1245151539Ssuz	if (hostIsNew && in6if_do_dad(ifp) &&
1246151539Ssuz	    ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
1247151539Ssuz	    (ia->ia6_flags & IN6_IFF_TENTATIVE))
1248151539Ssuz	{
1249151539Ssuz		int mindelay, maxdelay;
1250151539Ssuz
1251151539Ssuz		delay = 0;
1252151539Ssuz		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
1253151539Ssuz			/*
1254151539Ssuz			 * We need to impose a delay before sending an NS
1255151539Ssuz			 * for DAD.  Check if we also needed a delay for the
1256151539Ssuz			 * corresponding MLD message.  If we did, the delay
1257151539Ssuz			 * should be larger than the MLD delay (this could be
1258151539Ssuz			 * relaxed a bit, but this simple logic is at least
1259151539Ssuz			 * safe).
1260151539Ssuz			 */
1261151539Ssuz			mindelay = 0;
1262151539Ssuz			if (in6m_sol != NULL &&
1263151539Ssuz			    in6m_sol->in6m_state == MLD_REPORTPENDING) {
1264151539Ssuz				mindelay = in6m_sol->in6m_timer;
1265151539Ssuz			}
1266151539Ssuz			maxdelay = MAX_RTR_SOLICITATION_DELAY * hz;
1267151539Ssuz			if (maxdelay - mindelay == 0)
1268151539Ssuz				delay = 0;
1269151539Ssuz			else {
1270151539Ssuz				delay =
1271151539Ssuz				    (arc4random() % (maxdelay - mindelay)) +
1272151539Ssuz				    mindelay;
1273151539Ssuz			}
1274151539Ssuz		}
1275151539Ssuz		nd6_dad_start((struct ifaddr *)ia, delay);
1276151539Ssuz	}
1277151539Ssuz
1278120856Sume	return (error);
127978064Sume
128078064Sume  unlink:
128178064Sume	/*
128278064Sume	 * XXX: if a change of an existing address failed, keep the entry
128378064Sume	 * anyway.
128478064Sume	 */
128578064Sume	if (hostIsNew)
128678064Sume		in6_unlink_ifa(ia, ifp);
1287120856Sume	return (error);
1288148385Sume
1289148385Sume  cleanup:
1290148385Sume	in6_purgeaddr(&ia->ia_ifa);
1291148385Sume	return error;
129253541Sshin}
129353541Sshin
129462587Sitojunvoid
1295171259Sdelphijin6_purgeaddr(struct ifaddr *ifa)
129662587Sitojun{
129778064Sume	struct ifnet *ifp = ifa->ifa_ifp;
129878064Sume	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
1299165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
1300170202Sjinmei	struct in6_multi_mship *imm;
130162587Sitojun
130278064Sume	/* stop DAD processing */
130378064Sume	nd6_dad_stop(ifa);
130462587Sitojun
130578064Sume	/*
130678064Sume	 * delete route to the destination of the address being purged.
130778064Sume	 * The interface must be p2p or loopback in this case.
130878064Sume	 */
130978064Sume	if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) {
131078064Sume		int e;
131178064Sume
131278064Sume		if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
131378064Sume		    != 0) {
131478064Sume			log(LOG_ERR, "in6_purgeaddr: failed to remove "
131578064Sume			    "a route to the p2p destination: %s on %s, "
131678064Sume			    "errno=%d\n",
1317165118Sbz			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
1318165118Sbz			    if_name(ifp), e);
131978064Sume			/* proceed anyway... */
1320120891Sume		} else
132178064Sume			ia->ia_flags &= ~IFA_ROUTE;
132278064Sume	}
132378064Sume
132478064Sume	/* Remove ownaddr's loopback rtentry, if it exists. */
132578064Sume	in6_ifremloop(&(ia->ia_ifa));
132678064Sume
1327170202Sjinmei	/*
1328170202Sjinmei	 * leave from multicast groups we have joined for the interface
1329170202Sjinmei	 */
1330170202Sjinmei	while ((imm = ia->ia6_memberships.lh_first) != NULL) {
1331170202Sjinmei		LIST_REMOVE(imm, i6mm_chain);
1332170202Sjinmei		in6_leavegroup(imm);
133362587Sitojun	}
133462587Sitojun
133578064Sume	in6_unlink_ifa(ia, ifp);
133678064Sume}
133778064Sume
133878064Sumestatic void
1339171259Sdelphijin6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
134078064Sume{
134178064Sume	struct in6_ifaddr *oia;
134278064Sume	int	s = splnet();
134378064Sume
134462587Sitojun	TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
134562587Sitojun
134662587Sitojun	oia = ia;
134762587Sitojun	if (oia == (ia = in6_ifaddr))
134862587Sitojun		in6_ifaddr = ia->ia_next;
134962587Sitojun	else {
135062587Sitojun		while (ia->ia_next && (ia->ia_next != oia))
135162587Sitojun			ia = ia->ia_next;
135262587Sitojun		if (ia->ia_next)
135362587Sitojun			ia->ia_next = oia->ia_next;
135478064Sume		else {
135578064Sume			/* search failed */
135678064Sume			printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n");
135778064Sume		}
135862587Sitojun	}
135962587Sitojun
136062587Sitojun	/*
1361151915Ssuz	 * Release the reference to the base prefix.  There should be a
1362151915Ssuz	 * positive reference.
136362587Sitojun	 */
1364151915Ssuz	if (oia->ia6_ndpr == NULL) {
1365151915Ssuz		nd6log((LOG_NOTICE,
1366151915Ssuz		    "in6_unlink_ifa: autoconf'ed address "
1367151915Ssuz		    "%p has no prefix\n", oia));
1368151915Ssuz	} else {
1369151915Ssuz		oia->ia6_ndpr->ndpr_refcnt--;
1370151915Ssuz		oia->ia6_ndpr = NULL;
1371151915Ssuz	}
137262587Sitojun
1373151915Ssuz	/*
1374151915Ssuz	 * Also, if the address being removed is autoconf'ed, call
1375151915Ssuz	 * pfxlist_onlink_check() since the release might affect the status of
1376171260Sdelphij	 * other (detached) addresses.
1377151915Ssuz	 */
1378151915Ssuz	if ((oia->ia6_flags & IN6_IFF_AUTOCONF)) {
137978064Sume		pfxlist_onlink_check();
138062587Sitojun	}
138178064Sume
138278064Sume	/*
138378064Sume	 * release another refcnt for the link from in6_ifaddr.
138478064Sume	 * Note that we should decrement the refcnt at least once for all *BSD.
138578064Sume	 */
138662587Sitojun	IFAFREE(&oia->ia_ifa);
138778064Sume
138878064Sume	splx(s);
138962587Sitojun}
139062587Sitojun
139178064Sumevoid
1392171259Sdelphijin6_purgeif(struct ifnet *ifp)
139378064Sume{
139478064Sume	struct ifaddr *ifa, *nifa;
139578064Sume
1396120891Sume	for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) {
139778064Sume		nifa = TAILQ_NEXT(ifa, ifa_list);
139878064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
139978064Sume			continue;
140078064Sume		in6_purgeaddr(ifa);
140178064Sume	}
140278064Sume
140378064Sume	in6_ifdetach(ifp);
140478064Sume}
140578064Sume
140653541Sshin/*
140753541Sshin * SIOC[GAD]LIFADDR.
140862744Sgrog *	SIOCGLIFADDR: get first address. (?)
140953541Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
141053541Sshin *		get first address that matches the specified prefix.
141153541Sshin *	SIOCALIFADDR: add the specified address.
141253541Sshin *	SIOCALIFADDR with IFLR_PREFIX:
141353541Sshin *		add the specified prefix, filling hostid part from
141453541Sshin *		the first link-local address.  prefixlen must be <= 64.
141553541Sshin *	SIOCDLIFADDR: delete the specified address.
141653541Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
141753541Sshin *		delete the first address that matches the specified prefix.
141853541Sshin * return values:
141953541Sshin *	EINVAL on invalid parameters
142053541Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
142153541Sshin *	other values may be returned from in6_ioctl()
142253541Sshin *
142353541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
142453541Sshin * this is to accomodate address naming scheme other than RFC2374,
142553541Sshin * in the future.
142653541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
142753541Sshin * address encoding scheme. (see figure on page 8)
142853541Sshin */
142953541Sshinstatic int
1430171259Sdelphijin6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
1431171259Sdelphij    struct ifnet *ifp, struct thread *td)
143253541Sshin{
143353541Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
143453541Sshin	struct ifaddr *ifa;
143562587Sitojun	struct sockaddr *sa;
143653541Sshin
143753541Sshin	/* sanity checks */
143853541Sshin	if (!data || !ifp) {
143953541Sshin		panic("invalid argument to in6_lifaddr_ioctl");
1440120891Sume		/* NOTREACHED */
144153541Sshin	}
144253541Sshin
144353541Sshin	switch (cmd) {
144453541Sshin	case SIOCGLIFADDR:
144553541Sshin		/* address must be specified on GET with IFLR_PREFIX */
144653541Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
144753541Sshin			break;
144895023Ssuz		/* FALLTHROUGH */
144953541Sshin	case SIOCALIFADDR:
145053541Sshin	case SIOCDLIFADDR:
145153541Sshin		/* address must be specified on ADD and DELETE */
145262587Sitojun		sa = (struct sockaddr *)&iflr->addr;
145362587Sitojun		if (sa->sa_family != AF_INET6)
145453541Sshin			return EINVAL;
145562587Sitojun		if (sa->sa_len != sizeof(struct sockaddr_in6))
145653541Sshin			return EINVAL;
145753541Sshin		/* XXX need improvement */
145862587Sitojun		sa = (struct sockaddr *)&iflr->dstaddr;
145962587Sitojun		if (sa->sa_family && sa->sa_family != AF_INET6)
146053541Sshin			return EINVAL;
146162587Sitojun		if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
146253541Sshin			return EINVAL;
146353541Sshin		break;
146495023Ssuz	default: /* shouldn't happen */
146562587Sitojun#if 0
146662587Sitojun		panic("invalid cmd to in6_lifaddr_ioctl");
146795023Ssuz		/* NOTREACHED */
146862587Sitojun#else
146953541Sshin		return EOPNOTSUPP;
147062587Sitojun#endif
147153541Sshin	}
147253541Sshin	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
147353541Sshin		return EINVAL;
147453541Sshin
147553541Sshin	switch (cmd) {
147653541Sshin	case SIOCALIFADDR:
147753541Sshin	    {
147853541Sshin		struct in6_aliasreq ifra;
147953541Sshin		struct in6_addr *hostid = NULL;
148053541Sshin		int prefixlen;
148153541Sshin
148253541Sshin		if ((iflr->flags & IFLR_PREFIX) != 0) {
148353541Sshin			struct sockaddr_in6 *sin6;
148453541Sshin
148553541Sshin			/*
148653541Sshin			 * hostid is to fill in the hostid part of the
148753541Sshin			 * address.  hostid points to the first link-local
148853541Sshin			 * address attached to the interface.
148953541Sshin			 */
149062587Sitojun			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
149153541Sshin			if (!ifa)
149253541Sshin				return EADDRNOTAVAIL;
149353541Sshin			hostid = IFA_IN6(ifa);
149453541Sshin
1495171260Sdelphij			/* prefixlen must be <= 64. */
149653541Sshin			if (64 < iflr->prefixlen)
149753541Sshin				return EINVAL;
149853541Sshin			prefixlen = iflr->prefixlen;
149953541Sshin
150053541Sshin			/* hostid part must be zero. */
150153541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
1502126552Sume			if (sin6->sin6_addr.s6_addr32[2] != 0 ||
1503126552Sume			    sin6->sin6_addr.s6_addr32[3] != 0) {
150453541Sshin				return EINVAL;
150553541Sshin			}
150653541Sshin		} else
150753541Sshin			prefixlen = iflr->prefixlen;
150853541Sshin
150953541Sshin		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
151053541Sshin		bzero(&ifra, sizeof(ifra));
1511120891Sume		bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name));
151253541Sshin
151362587Sitojun		bcopy(&iflr->addr, &ifra.ifra_addr,
1514120891Sume		    ((struct sockaddr *)&iflr->addr)->sa_len);
151553541Sshin		if (hostid) {
151653541Sshin			/* fill in hostid part */
151753541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[2] =
1518120891Sume			    hostid->s6_addr32[2];
151953541Sshin			ifra.ifra_addr.sin6_addr.s6_addr32[3] =
1520120891Sume			    hostid->s6_addr32[3];
152153541Sshin		}
152253541Sshin
1523120891Sume		if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */
152453541Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1525120891Sume			    ((struct sockaddr *)&iflr->dstaddr)->sa_len);
152653541Sshin			if (hostid) {
152753541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
1528120891Sume				    hostid->s6_addr32[2];
152953541Sshin				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
1530120891Sume				    hostid->s6_addr32[3];
153153541Sshin			}
153253541Sshin		}
153353541Sshin
153453541Sshin		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1535121168Sume		in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
153653541Sshin
153753541Sshin		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
153883366Sjulian		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td);
153953541Sshin	    }
154053541Sshin	case SIOCGLIFADDR:
154153541Sshin	case SIOCDLIFADDR:
154253541Sshin	    {
154353541Sshin		struct in6_ifaddr *ia;
154453541Sshin		struct in6_addr mask, candidate, match;
154553541Sshin		struct sockaddr_in6 *sin6;
154653541Sshin		int cmp;
154753541Sshin
154853541Sshin		bzero(&mask, sizeof(mask));
154953541Sshin		if (iflr->flags & IFLR_PREFIX) {
155053541Sshin			/* lookup a prefix rather than address. */
1551121168Sume			in6_prefixlen2mask(&mask, iflr->prefixlen);
155253541Sshin
155353541Sshin			sin6 = (struct sockaddr_in6 *)&iflr->addr;
155453541Sshin			bcopy(&sin6->sin6_addr, &match, sizeof(match));
155553541Sshin			match.s6_addr32[0] &= mask.s6_addr32[0];
155653541Sshin			match.s6_addr32[1] &= mask.s6_addr32[1];
155753541Sshin			match.s6_addr32[2] &= mask.s6_addr32[2];
155853541Sshin			match.s6_addr32[3] &= mask.s6_addr32[3];
155953541Sshin
156053541Sshin			/* if you set extra bits, that's wrong */
156153541Sshin			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
156253541Sshin				return EINVAL;
156353541Sshin
156453541Sshin			cmp = 1;
156553541Sshin		} else {
156653541Sshin			if (cmd == SIOCGLIFADDR) {
156753541Sshin				/* on getting an address, take the 1st match */
156895023Ssuz				cmp = 0;	/* XXX */
156953541Sshin			} else {
157053541Sshin				/* on deleting an address, do exact match */
1571121168Sume				in6_prefixlen2mask(&mask, 128);
157253541Sshin				sin6 = (struct sockaddr_in6 *)&iflr->addr;
157353541Sshin				bcopy(&sin6->sin6_addr, &match, sizeof(match));
157453541Sshin
157553541Sshin				cmp = 1;
157653541Sshin			}
157753541Sshin		}
157853541Sshin
1579120891Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
158053541Sshin			if (ifa->ifa_addr->sa_family != AF_INET6)
158153541Sshin				continue;
158253541Sshin			if (!cmp)
158353541Sshin				break;
158478064Sume
158578064Sume			/*
158678064Sume			 * XXX: this is adhoc, but is necessary to allow
158778064Sume			 * a user to specify fe80::/64 (not /10) for a
158878064Sume			 * link-local address.
158978064Sume			 */
1590148385Sume			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
1591148385Sume			in6_clearscope(&candidate);
159253541Sshin			candidate.s6_addr32[0] &= mask.s6_addr32[0];
159353541Sshin			candidate.s6_addr32[1] &= mask.s6_addr32[1];
159453541Sshin			candidate.s6_addr32[2] &= mask.s6_addr32[2];
159553541Sshin			candidate.s6_addr32[3] &= mask.s6_addr32[3];
159653541Sshin			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
159753541Sshin				break;
159853541Sshin		}
159953541Sshin		if (!ifa)
160053541Sshin			return EADDRNOTAVAIL;
160153541Sshin		ia = ifa2ia6(ifa);
160253541Sshin
160353541Sshin		if (cmd == SIOCGLIFADDR) {
1604148385Sume			int error;
160578064Sume
160653541Sshin			/* fill in the if_laddrreq structure */
160753541Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
1608148385Sume			error = sa6_recoverscope(
1609148385Sume			    (struct sockaddr_in6 *)&iflr->addr);
1610148385Sume			if (error != 0)
1611148385Sume				return (error);
1612148385Sume
161353541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
161453541Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
1615120891Sume				    ia->ia_dstaddr.sin6_len);
1616148385Sume				error = sa6_recoverscope(
1617148385Sume				    (struct sockaddr_in6 *)&iflr->dstaddr);
1618148385Sume				if (error != 0)
1619148385Sume					return (error);
162053541Sshin			} else
162153541Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
162253541Sshin
162353541Sshin			iflr->prefixlen =
1624120891Sume			    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
162553541Sshin
162695023Ssuz			iflr->flags = ia->ia6_flags;	/* XXX */
162753541Sshin
162853541Sshin			return 0;
162953541Sshin		} else {
163053541Sshin			struct in6_aliasreq ifra;
163153541Sshin
163253541Sshin			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
163353541Sshin			bzero(&ifra, sizeof(ifra));
163453541Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
1635120891Sume			    sizeof(ifra.ifra_name));
163653541Sshin
163753541Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
1638120891Sume			    ia->ia_addr.sin6_len);
163953541Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
164053541Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
1641120891Sume				    ia->ia_dstaddr.sin6_len);
164262587Sitojun			} else {
164362587Sitojun				bzero(&ifra.ifra_dstaddr,
164462587Sitojun				    sizeof(ifra.ifra_dstaddr));
164553541Sshin			}
164653541Sshin			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
1647120891Sume			    ia->ia_prefixmask.sin6_len);
164853541Sshin
164953541Sshin			ifra.ifra_flags = ia->ia6_flags;
165053541Sshin			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
1651120891Sume			    ifp, td);
165253541Sshin		}
165353541Sshin	    }
165453541Sshin	}
165553541Sshin
165695023Ssuz	return EOPNOTSUPP;	/* just for safety */
165753541Sshin}
165853541Sshin
165953541Sshin/*
166053541Sshin * Initialize an interface's intetnet6 address
166153541Sshin * and routing table entry.
166253541Sshin */
166378064Sumestatic int
1664171259Sdelphijin6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
1665171259Sdelphij    struct sockaddr_in6 *sin6, int newhost)
166653541Sshin{
166778064Sume	int	error = 0, plen, ifacount = 0;
166853541Sshin	int	s = splimp();
166978064Sume	struct ifaddr *ifa;
167053541Sshin
167153541Sshin	/*
167253541Sshin	 * Give the interface a chance to initialize
167353541Sshin	 * if this is its first address,
167453541Sshin	 * and to validate the address if necessary.
167553541Sshin	 */
1676120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
167778064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
167878064Sume			continue;
167978064Sume		ifacount++;
168078064Sume	}
168178064Sume
168278064Sume	ia->ia_addr = *sin6;
168378064Sume
1684146883Siedowse	if (ifacount <= 1 && ifp->if_ioctl) {
1685146883Siedowse		IFF_LOCKGIANT(ifp);
1686146883Siedowse		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
1687146883Siedowse		IFF_UNLOCKGIANT(ifp);
1688146883Siedowse		if (error) {
1689146883Siedowse			splx(s);
1690146883Siedowse			return (error);
1691146883Siedowse		}
169253541Sshin	}
169378064Sume	splx(s);
169453541Sshin
169578064Sume	ia->ia_ifa.ifa_metric = ifp->if_metric;
169653541Sshin
169778064Sume	/* we could do in(6)_socktrim here, but just omit it at this moment. */
169878064Sume
1699162540Ssuz	if (newhost) {
1700162540Ssuz		/*
1701162540Ssuz		 * set the rtrequest function to create llinfo.  It also
1702162540Ssuz		 * adjust outgoing interface of the route for the local
1703162540Ssuz		 * address when called via in6_ifaddloop() below.
1704162540Ssuz		 */
1705159390Sgnn		ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
1706159390Sgnn	}
1707159390Sgnn
170853541Sshin	/*
170978064Sume	 * Special case:
1710124337Sume	 * If a new destination address is specified for a point-to-point
171178064Sume	 * interface, install a route to the destination as an interface
1712159390Sgnn	 * direct route.  In addition, if the link is expected to have neighbor
1713159390Sgnn	 * cache entries, specify RTF_LLINFO so that a cache entry for the
1714159390Sgnn	 * destination address will be created.
1715159390Sgnn	 * created
1716124337Sume	 * XXX: the logic below rejects assigning multiple addresses on a p2p
1717159390Sgnn	 * interface that share the same destination.
171853541Sshin	 */
171978064Sume	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
1720124337Sume	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
1721124337Sume	    ia->ia_dstaddr.sin6_family == AF_INET6) {
1722159390Sgnn		int rtflags = RTF_UP | RTF_HOST;
1723159390Sgnn		struct rtentry *rt = NULL, **rtp = NULL;
1724159390Sgnn
1725159390Sgnn		if (nd6_need_cache(ifp) != 0) {
1726159390Sgnn			rtflags |= RTF_LLINFO;
1727159390Sgnn			rtp = &rt;
1728159390Sgnn		}
1729159390Sgnn
1730159390Sgnn		error = rtrequest(RTM_ADD, (struct sockaddr *)&ia->ia_dstaddr,
1731159390Sgnn		    (struct sockaddr *)&ia->ia_addr,
1732159390Sgnn		    (struct sockaddr *)&ia->ia_prefixmask,
1733159390Sgnn		    ia->ia_flags | rtflags, rtp);
1734159390Sgnn		if (error != 0)
1735120856Sume			return (error);
1736159390Sgnn		if (rt != NULL) {
1737159390Sgnn			struct llinfo_nd6 *ln;
1738159390Sgnn
1739159390Sgnn			RT_LOCK(rt);
1740159390Sgnn			ln = (struct llinfo_nd6 *)rt->rt_llinfo;
1741159390Sgnn			if (ln != NULL) {
1742159390Sgnn				/*
1743159390Sgnn				 * Set the state to STALE because we don't
1744159390Sgnn				 * have to perform address resolution on this
1745159390Sgnn				 * link.
1746159390Sgnn				 */
1747159390Sgnn				ln->ln_state = ND6_LLINFO_STALE;
1748159390Sgnn			}
1749159390Sgnn			RT_REMREF(rt);
1750159390Sgnn			RT_UNLOCK(rt);
1751159390Sgnn		}
175278064Sume		ia->ia_flags |= IFA_ROUTE;
175353541Sshin	}
175478064Sume	if (plen < 128) {
175578064Sume		/*
175678064Sume		 * The RTF_CLONING flag is necessary for in6_is_ifloop_auto().
175778064Sume		 */
175878064Sume		ia->ia_ifa.ifa_flags |= RTF_CLONING;
175978064Sume	}
176053541Sshin
176195023Ssuz	/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
1762159390Sgnn	if (newhost)
176378064Sume		in6_ifaddloop(&(ia->ia_ifa));
176453541Sshin
1765120856Sume	return (error);
176653541Sshin}
176753541Sshin
1768142215Sglebiusstruct in6_multi_mship *
1769171259Sdelphijin6_joingroup(struct ifnet *ifp, struct in6_addr *addr,
1770171259Sdelphij    int *errorp, int delay)
1771142215Sglebius{
1772142215Sglebius	struct in6_multi_mship *imm;
1773142215Sglebius
1774149849Sobrien	imm = malloc(sizeof(*imm), M_IP6MADDR, M_NOWAIT);
1775142215Sglebius	if (!imm) {
1776142215Sglebius		*errorp = ENOBUFS;
1777142215Sglebius		return NULL;
1778142215Sglebius	}
1779151539Ssuz	imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp, delay);
1780142215Sglebius	if (!imm->i6mm_maddr) {
1781142215Sglebius		/* *errorp is alrady set */
1782149849Sobrien		free(imm, M_IP6MADDR);
1783142215Sglebius		return NULL;
1784142215Sglebius	}
1785142215Sglebius	return imm;
1786142215Sglebius}
1787142215Sglebius
1788142215Sglebiusint
1789171259Sdelphijin6_leavegroup(struct in6_multi_mship *imm)
1790142215Sglebius{
1791142215Sglebius
1792142215Sglebius	if (imm->i6mm_maddr)
1793142215Sglebius		in6_delmulti(imm->i6mm_maddr);
1794149849Sobrien	free(imm,  M_IP6MADDR);
1795142215Sglebius	return 0;
1796142215Sglebius}
1797142215Sglebius
179853541Sshin/*
179953541Sshin * Find an IPv6 interface link-local address specific to an interface.
180053541Sshin */
180153541Sshinstruct in6_ifaddr *
1802171259Sdelphijin6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
180353541Sshin{
180478064Sume	struct ifaddr *ifa;
180553541Sshin
1806120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
180753541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
180853541Sshin			continue;
180962587Sitojun		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
181062587Sitojun			if ((((struct in6_ifaddr *)ifa)->ia6_flags &
181162587Sitojun			     ignoreflags) != 0)
181262587Sitojun				continue;
181353541Sshin			break;
181462587Sitojun		}
181553541Sshin	}
181653541Sshin
1817120856Sume	return ((struct in6_ifaddr *)ifa);
181853541Sshin}
181953541Sshin
182053541Sshin
182153541Sshin/*
182253541Sshin * find the internet address corresponding to a given interface and address.
182353541Sshin */
182453541Sshinstruct in6_ifaddr *
1825171259Sdelphijin6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
182653541Sshin{
182778064Sume	struct ifaddr *ifa;
182853541Sshin
1829120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
183053541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
183153541Sshin			continue;
183253541Sshin		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
183353541Sshin			break;
183453541Sshin	}
183553541Sshin
1836120856Sume	return ((struct in6_ifaddr *)ifa);
183753541Sshin}
183853541Sshin
183953541Sshin/*
1840165118Sbz * Convert IP6 address to printable (loggable) representation. Caller
1841165118Sbz * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long.
184253541Sshin */
184353541Sshinstatic char digits[] = "0123456789abcdef";
184453541Sshinchar *
1845165118Sbzip6_sprintf(char *ip6buf, const struct in6_addr *addr)
184653541Sshin{
184778064Sume	int i;
184878064Sume	char *cp;
1849126552Sume	const u_int16_t *a = (const u_int16_t *)addr;
1850126552Sume	const u_int8_t *d;
1851165287Sbz	int dcolon = 0, zero = 0;
185253541Sshin
1853165118Sbz	cp = ip6buf;
185453541Sshin
185553541Sshin	for (i = 0; i < 8; i++) {
185653541Sshin		if (dcolon == 1) {
185753541Sshin			if (*a == 0) {
185853541Sshin				if (i == 7)
185953541Sshin					*cp++ = ':';
186053541Sshin				a++;
186153541Sshin				continue;
186253541Sshin			} else
186353541Sshin				dcolon = 2;
186453541Sshin		}
186553541Sshin		if (*a == 0) {
186653541Sshin			if (dcolon == 0 && *(a + 1) == 0) {
186753541Sshin				if (i == 0)
186853541Sshin					*cp++ = ':';
186953541Sshin				*cp++ = ':';
187053541Sshin				dcolon = 1;
187153541Sshin			} else {
187253541Sshin				*cp++ = '0';
187353541Sshin				*cp++ = ':';
187453541Sshin			}
187553541Sshin			a++;
187653541Sshin			continue;
187753541Sshin		}
187891346Salfred		d = (const u_char *)a;
1879165287Sbz		/* Try to eliminate leading zeros in printout like in :0001. */
1880165287Sbz		zero = 1;
1881165287Sbz		*cp = digits[*d >> 4];
1882165287Sbz		if (*cp != '0') {
1883165287Sbz			zero = 0;
1884165287Sbz			cp++;
1885165287Sbz		}
1886165287Sbz		*cp = digits[*d++ & 0xf];
1887165287Sbz		if (zero == 0 || (*cp != '0')) {
1888165287Sbz			zero = 0;
1889165287Sbz			cp++;
1890165287Sbz		}
1891165287Sbz		*cp = digits[*d >> 4];
1892165287Sbz		if (zero == 0 || (*cp != '0')) {
1893165287Sbz			zero = 0;
1894165287Sbz			cp++;
1895165287Sbz		}
189653541Sshin		*cp++ = digits[*d & 0xf];
189753541Sshin		*cp++ = ':';
189853541Sshin		a++;
189953541Sshin	}
1900165118Sbz	*--cp = '\0';
1901165118Sbz	return (ip6buf);
190253541Sshin}
190353541Sshin
190453541Sshinint
1905171259Sdelphijin6_localaddr(struct in6_addr *in6)
190653541Sshin{
190753541Sshin	struct in6_ifaddr *ia;
190853541Sshin
190953541Sshin	if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
191053541Sshin		return 1;
191153541Sshin
1912120891Sume	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
191353541Sshin		if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
1914120891Sume		    &ia->ia_prefixmask.sin6_addr)) {
191553541Sshin			return 1;
1916120891Sume		}
1917120891Sume	}
191853541Sshin
191953541Sshin	return (0);
192053541Sshin}
192153541Sshin
192278064Sumeint
1923171259Sdelphijin6_is_addr_deprecated(struct sockaddr_in6 *sa6)
192478064Sume{
192578064Sume	struct in6_ifaddr *ia;
192678064Sume
192778064Sume	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
192878064Sume		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
192978064Sume				       &sa6->sin6_addr) &&
193078064Sume		    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
1931120856Sume			return (1); /* true */
193278064Sume
193378064Sume		/* XXX: do we still have to go thru the rest of the list? */
193478064Sume	}
193578064Sume
1936120856Sume	return (0);		/* false */
193778064Sume}
193878064Sume
193953541Sshin/*
194053541Sshin * return length of part which dst and src are equal
194153541Sshin * hard coding...
194253541Sshin */
194353541Sshinint
1944171259Sdelphijin6_matchlen(struct in6_addr *src, struct in6_addr *dst)
194553541Sshin{
194653541Sshin	int match = 0;
194753541Sshin	u_char *s = (u_char *)src, *d = (u_char *)dst;
194853541Sshin	u_char *lim = s + 16, r;
194953541Sshin
195053541Sshin	while (s < lim)
195153541Sshin		if ((r = (*d++ ^ *s++)) != 0) {
195253541Sshin			while (r < 128) {
195353541Sshin				match++;
195453541Sshin				r <<= 1;
195553541Sshin			}
195653541Sshin			break;
195753541Sshin		} else
195853541Sshin			match += 8;
195953541Sshin	return match;
196053541Sshin}
196153541Sshin
196262587Sitojun/* XXX: to be scope conscious */
196353541Sshinint
1964171259Sdelphijin6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len)
196553541Sshin{
196653541Sshin	int bytelen, bitlen;
196753541Sshin
196853541Sshin	/* sanity check */
196953541Sshin	if (0 > len || len > 128) {
197053541Sshin		log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
197153541Sshin		    len);
1972120856Sume		return (0);
197353541Sshin	}
197453541Sshin
197553541Sshin	bytelen = len / 8;
197653541Sshin	bitlen = len % 8;
197753541Sshin
197853541Sshin	if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
1979120856Sume		return (0);
1980126184Scperciva	if (bitlen != 0 &&
1981126184Scperciva	    p1->s6_addr[bytelen] >> (8 - bitlen) !=
198253541Sshin	    p2->s6_addr[bytelen] >> (8 - bitlen))
1983120856Sume		return (0);
198453541Sshin
1985120856Sume	return (1);
198653541Sshin}
198753541Sshin
198853541Sshinvoid
1989171259Sdelphijin6_prefixlen2mask(struct in6_addr *maskp, int len)
199053541Sshin{
199153541Sshin	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
199253541Sshin	int bytelen, bitlen, i;
199353541Sshin
199453541Sshin	/* sanity check */
199553541Sshin	if (0 > len || len > 128) {
199653541Sshin		log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
199753541Sshin		    len);
199853541Sshin		return;
199953541Sshin	}
200053541Sshin
200153541Sshin	bzero(maskp, sizeof(*maskp));
200253541Sshin	bytelen = len / 8;
200353541Sshin	bitlen = len % 8;
200453541Sshin	for (i = 0; i < bytelen; i++)
200553541Sshin		maskp->s6_addr[i] = 0xff;
200653541Sshin	if (bitlen)
200753541Sshin		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
200853541Sshin}
200953541Sshin
201053541Sshin/*
201153541Sshin * return the best address out of the same scope. if no address was
201253541Sshin * found, return the first valid address from designated IF.
201353541Sshin */
201453541Sshinstruct in6_ifaddr *
2015171259Sdelphijin6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
201653541Sshin{
201753541Sshin	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
201853541Sshin	struct ifaddr *ifa;
201953541Sshin	struct in6_ifaddr *besta = 0;
202095023Ssuz	struct in6_ifaddr *dep[2];	/* last-resort: deprecated */
202153541Sshin
202253541Sshin	dep[0] = dep[1] = NULL;
202353541Sshin
202453541Sshin	/*
202553541Sshin	 * We first look for addresses in the same scope.
202653541Sshin	 * If there is one, return it.
202753541Sshin	 * If two or more, return one which matches the dst longest.
202853541Sshin	 * If none, return one of global addresses assigned other ifs.
202953541Sshin	 */
2030120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
203153541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
203253541Sshin			continue;
203353541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
203453541Sshin			continue; /* XXX: is there any case to allow anycast? */
203553541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
203653541Sshin			continue; /* don't use this interface */
203753541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
203853541Sshin			continue;
203953541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
204053541Sshin			if (ip6_use_deprecated)
204153541Sshin				dep[0] = (struct in6_ifaddr *)ifa;
204253541Sshin			continue;
204353541Sshin		}
204453541Sshin
204553541Sshin		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
204653541Sshin			/*
204753541Sshin			 * call in6_matchlen() as few as possible
204853541Sshin			 */
204953541Sshin			if (besta) {
205053541Sshin				if (blen == -1)
205153541Sshin					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
205253541Sshin				tlen = in6_matchlen(IFA_IN6(ifa), dst);
205353541Sshin				if (tlen > blen) {
205453541Sshin					blen = tlen;
205553541Sshin					besta = (struct in6_ifaddr *)ifa;
205653541Sshin				}
205753541Sshin			} else
205853541Sshin				besta = (struct in6_ifaddr *)ifa;
205953541Sshin		}
206053541Sshin	}
206153541Sshin	if (besta)
2062120856Sume		return (besta);
206353541Sshin
2064120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
206553541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
206653541Sshin			continue;
206753541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
206853541Sshin			continue; /* XXX: is there any case to allow anycast? */
206953541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
207053541Sshin			continue; /* don't use this interface */
207153541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
207253541Sshin			continue;
207353541Sshin		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
207453541Sshin			if (ip6_use_deprecated)
207553541Sshin				dep[1] = (struct in6_ifaddr *)ifa;
207653541Sshin			continue;
207753541Sshin		}
207853541Sshin
207953541Sshin		return (struct in6_ifaddr *)ifa;
208053541Sshin	}
208153541Sshin
208253541Sshin	/* use the last-resort values, that are, deprecated addresses */
208353541Sshin	if (dep[0])
208453541Sshin		return dep[0];
208553541Sshin	if (dep[1])
208653541Sshin		return dep[1];
208753541Sshin
208853541Sshin	return NULL;
208953541Sshin}
209053541Sshin
209153541Sshin/*
209253541Sshin * perform DAD when interface becomes IFF_UP.
209353541Sshin */
209453541Sshinvoid
2095171259Sdelphijin6_if_up(struct ifnet *ifp)
209653541Sshin{
209753541Sshin	struct ifaddr *ifa;
209853541Sshin	struct in6_ifaddr *ia;
209953541Sshin
2100120891Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
210153541Sshin		if (ifa->ifa_addr->sa_family != AF_INET6)
210253541Sshin			continue;
210353541Sshin		ia = (struct in6_ifaddr *)ifa;
2104151539Ssuz		if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
2105151539Ssuz			/*
2106151539Ssuz			 * The TENTATIVE flag was likely set by hand
2107151539Ssuz			 * beforehand, implicitly indicating the need for DAD.
2108151539Ssuz			 * We may be able to skip the random delay in this
2109151539Ssuz			 * case, but we impose delays just in case.
2110151539Ssuz			 */
2111151539Ssuz			nd6_dad_start(ifa,
2112151539Ssuz			    arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz));
2113151539Ssuz		}
211453541Sshin	}
2115151539Ssuz
2116151539Ssuz	/*
2117151539Ssuz	 * special cases, like 6to4, are handled in in6_ifattach
2118151539Ssuz	 */
2119151539Ssuz	in6_ifattach(ifp, NULL);
212053541Sshin}
212153541Sshin
212278064Sumeint
2123171259Sdelphijin6if_do_dad(struct ifnet *ifp)
212478064Sume{
212578064Sume	if ((ifp->if_flags & IFF_LOOPBACK) != 0)
2126120856Sume		return (0);
212778064Sume
212878064Sume	switch (ifp->if_type) {
212978064Sume#ifdef IFT_DUMMY
213078064Sume	case IFT_DUMMY:
213178064Sume#endif
213278064Sume	case IFT_FAITH:
213378064Sume		/*
213478064Sume		 * These interfaces do not have the IFF_LOOPBACK flag,
213578064Sume		 * but loop packets back.  We do not have to do DAD on such
213678064Sume		 * interfaces.  We should even omit it, because loop-backed
213778064Sume		 * NS would confuse the DAD procedure.
213878064Sume		 */
2139120856Sume		return (0);
214078064Sume	default:
214178064Sume		/*
214278064Sume		 * Our DAD routine requires the interface up and running.
214378064Sume		 * However, some interfaces can be up before the RUNNING
214478064Sume		 * status.  Additionaly, users may try to assign addresses
214578064Sume		 * before the interface becomes up (or running).
214678064Sume		 * We simply skip DAD in such a case as a work around.
214778064Sume		 * XXX: we should rather mark "tentative" on such addresses,
214878064Sume		 * and do DAD after the interface becomes ready.
214978064Sume		 */
2150148887Srwatson		if (!((ifp->if_flags & IFF_UP) &&
2151148887Srwatson		    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
2152120856Sume			return (0);
215378064Sume
2154120856Sume		return (1);
215578064Sume	}
215678064Sume}
215778064Sume
215853541Sshin/*
215953541Sshin * Calculate max IPv6 MTU through all the interfaces and store it
216053541Sshin * to in6_maxmtu.
216153541Sshin */
216253541Sshinvoid
2163171259Sdelphijin6_setmaxmtu(void)
216453541Sshin{
216553541Sshin	unsigned long maxmtu = 0;
216653541Sshin	struct ifnet *ifp;
216753541Sshin
2168108172Shsu	IFNET_RLOCK();
2169120891Sume	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
2170121283Sume		/* this function can be called during ifnet initialization */
2171121283Sume		if (!ifp->if_afdata[AF_INET6])
2172121283Sume			continue;
217353541Sshin		if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
2174121283Sume		    IN6_LINKMTU(ifp) > maxmtu)
2175121283Sume			maxmtu = IN6_LINKMTU(ifp);
217653541Sshin	}
2177108172Shsu	IFNET_RUNLOCK();
2178120891Sume	if (maxmtu)	     /* update only when maxmtu is positive */
217953541Sshin		in6_maxmtu = maxmtu;
218053541Sshin}
218153541Sshin
2182151539Ssuz/*
2183151539Ssuz * Provide the length of interface identifiers to be used for the link attached
2184151539Ssuz * to the given interface.  The length should be defined in "IPv6 over
2185151539Ssuz * xxx-link" document.  Note that address architecture might also define
2186151539Ssuz * the length for a particular set of address prefixes, regardless of the
2187151539Ssuz * link type.  As clarified in rfc2462bis, those two definitions should be
2188151539Ssuz * consistent, and those really are as of August 2004.
2189151539Ssuz */
2190151539Ssuzint
2191171259Sdelphijin6_if2idlen(struct ifnet *ifp)
2192151539Ssuz{
2193151539Ssuz	switch (ifp->if_type) {
2194151539Ssuz	case IFT_ETHER:		/* RFC2464 */
2195151539Ssuz#ifdef IFT_PROPVIRTUAL
2196151539Ssuz	case IFT_PROPVIRTUAL:	/* XXX: no RFC. treat it as ether */
2197151539Ssuz#endif
2198151539Ssuz#ifdef IFT_L2VLAN
2199151539Ssuz	case IFT_L2VLAN:	/* ditto */
2200151539Ssuz#endif
2201151539Ssuz#ifdef IFT_IEEE80211
2202151539Ssuz	case IFT_IEEE80211:	/* ditto */
2203151539Ssuz#endif
2204151539Ssuz#ifdef IFT_MIP
2205151539Ssuz	case IFT_MIP:	/* ditto */
2206151539Ssuz#endif
2207151539Ssuz		return (64);
2208151539Ssuz	case IFT_FDDI:		/* RFC2467 */
2209151539Ssuz		return (64);
2210151539Ssuz	case IFT_ISO88025:	/* RFC2470 (IPv6 over Token Ring) */
2211151539Ssuz		return (64);
2212151539Ssuz	case IFT_PPP:		/* RFC2472 */
2213151539Ssuz		return (64);
2214151539Ssuz	case IFT_ARCNET:	/* RFC2497 */
2215151539Ssuz		return (64);
2216151539Ssuz	case IFT_FRELAY:	/* RFC2590 */
2217151539Ssuz		return (64);
2218151539Ssuz	case IFT_IEEE1394:	/* RFC3146 */
2219151539Ssuz		return (64);
2220151539Ssuz	case IFT_GIF:
2221151539Ssuz		return (64);	/* draft-ietf-v6ops-mech-v2-07 */
2222151539Ssuz	case IFT_LOOP:
2223151539Ssuz		return (64);	/* XXX: is this really correct? */
2224151539Ssuz	default:
2225151539Ssuz		/*
2226151539Ssuz		 * Unknown link type:
2227151539Ssuz		 * It might be controversial to use the today's common constant
2228151539Ssuz		 * of 64 for these cases unconditionally.  For full compliance,
2229151539Ssuz		 * we should return an error in this case.  On the other hand,
2230151539Ssuz		 * if we simply miss the standard for the link type or a new
2231151539Ssuz		 * standard is defined for a new link type, the IFID length
2232151539Ssuz		 * is very likely to be the common constant.  As a compromise,
2233151539Ssuz		 * we always use the constant, but make an explicit notice
2234151539Ssuz		 * indicating the "unknown" case.
2235151539Ssuz		 */
2236151539Ssuz		printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type);
2237151539Ssuz		return (64);
2238151539Ssuz	}
2239151539Ssuz}
2240151539Ssuz
2241121161Sumevoid *
2242171259Sdelphijin6_domifattach(struct ifnet *ifp)
2243121161Sume{
2244121161Sume	struct in6_ifextra *ext;
2245121161Sume
2246121161Sume	ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
2247121161Sume	bzero(ext, sizeof(*ext));
2248121161Sume
2249121161Sume	ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
2250121161Sume	    M_IFADDR, M_WAITOK);
2251121161Sume	bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
2252121161Sume
2253121161Sume	ext->icmp6_ifstat =
2254121161Sume	    (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
2255121161Sume	    M_IFADDR, M_WAITOK);
2256121161Sume	bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
2257121161Sume
2258121161Sume	ext->nd_ifinfo = nd6_ifattach(ifp);
2259121161Sume	ext->scope6_id = scope6_ifattach(ifp);
2260121161Sume	return ext;
2261121161Sume}
2262121161Sume
2263121161Sumevoid
2264171259Sdelphijin6_domifdetach(struct ifnet *ifp, void *aux)
2265121161Sume{
2266121161Sume	struct in6_ifextra *ext = (struct in6_ifextra *)aux;
2267121161Sume
2268121161Sume	scope6_ifdetach(ext->scope6_id);
2269121161Sume	nd6_ifdetach(ext->nd_ifinfo);
2270121161Sume	free(ext->in6_ifstat, M_IFADDR);
2271121161Sume	free(ext->icmp6_ifstat, M_IFADDR);
2272121161Sume	free(ext, M_IFADDR);
2273121161Sume}
2274121161Sume
227553541Sshin/*
227695023Ssuz * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
227753541Sshin * v4 mapped addr or v4 compat addr
227853541Sshin */
227953541Sshinvoid
228053541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
228153541Sshin{
2282171259Sdelphij
228353541Sshin	bzero(sin, sizeof(*sin));
228453541Sshin	sin->sin_len = sizeof(struct sockaddr_in);
228553541Sshin	sin->sin_family = AF_INET;
228653541Sshin	sin->sin_port = sin6->sin6_port;
2287120891Sume	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
228853541Sshin}
228953541Sshin
229053541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
229153541Sshinvoid
229253541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
229353541Sshin{
229453541Sshin	bzero(sin6, sizeof(*sin6));
229553541Sshin	sin6->sin6_len = sizeof(struct sockaddr_in6);
229653541Sshin	sin6->sin6_family = AF_INET6;
229753541Sshin	sin6->sin6_port = sin->sin_port;
229853541Sshin	sin6->sin6_addr.s6_addr32[0] = 0;
229953541Sshin	sin6->sin6_addr.s6_addr32[1] = 0;
230053541Sshin	sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
230153541Sshin	sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
230253541Sshin}
230353541Sshin
230453541Sshin/* Convert sockaddr_in6 into sockaddr_in. */
230553541Sshinvoid
230653541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam)
230753541Sshin{
230853541Sshin	struct sockaddr_in *sin_p;
230953541Sshin	struct sockaddr_in6 sin6;
231053541Sshin
231153541Sshin	/*
231253541Sshin	 * Save original sockaddr_in6 addr and convert it
231353541Sshin	 * to sockaddr_in.
231453541Sshin	 */
231553541Sshin	sin6 = *(struct sockaddr_in6 *)nam;
231653541Sshin	sin_p = (struct sockaddr_in *)nam;
231753541Sshin	in6_sin6_2_sin(sin_p, &sin6);
231853541Sshin}
231953541Sshin
232053541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
232153541Sshinvoid
232253541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
232353541Sshin{
232453541Sshin	struct sockaddr_in *sin_p;
232553541Sshin	struct sockaddr_in6 *sin6_p;
232653541Sshin
232753541Sshin	MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
2328111119Simp	       M_WAITOK);
232953541Sshin	sin_p = (struct sockaddr_in *)*nam;
233053541Sshin	in6_sin_2_v4mapsin6(sin_p, sin6_p);
233153541Sshin	FREE(*nam, M_SONAME);
233253541Sshin	*nam = (struct sockaddr *)sin6_p;
233353541Sshin}
2334