in6_src.c revision 121315
11556Srgrimes/*	$FreeBSD: head/sys/netinet6/in6_src.c 121315 2003-10-21 20:05:32Z ume $	*/
21556Srgrimes/*	$KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $	*/
31556Srgrimes
41556Srgrimes/*
51556Srgrimes * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
61556Srgrimes * All rights reserved.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. Neither the name of the project nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes/*
3436150Scharnier * Copyright (c) 1982, 1986, 1991, 1993
3536150Scharnier *	The Regents of the University of California.  All rights reserved.
3636150Scharnier *
371556Srgrimes * Redistribution and use in source and binary forms, with or without
3899110Sobrien * modification, are permitted provided that the following conditions
3999110Sobrien * are met:
401556Srgrimes * 1. Redistributions of source code must retain the above copyright
4117987Speter *    notice, this list of conditions and the following disclaimer.
4217987Speter * 2. Redistributions in binary form must reproduce the above copyright
4317987Speter *    notice, this list of conditions and the following disclaimer in the
4420425Ssteve *    documentation and/or other materials provided with the distribution.
4517987Speter * 3. All advertising materials mentioning features or use of this software
4617987Speter *    must display the following acknowledgement:
47100661Stjr *	This product includes software developed by the University of
4817987Speter *	California, Berkeley and its contributors.
491556Srgrimes * 4. Neither the name of the University nor the names of its contributors
501556Srgrimes *    may be used to endorse or promote products derived from this software
511556Srgrimes *    without specific prior written permission.
521556Srgrimes *
531556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
541556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
551556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
561556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
571556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
581556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
591556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
601556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6120425Ssteve * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6217987Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
631556Srgrimes * SUCH DAMAGE.
6417987Speter *
6520425Ssteve *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94
66223060Sjilles */
671556Srgrimes
68213811Sobrien#include "opt_inet.h"
69213811Sobrien#include "opt_inet6.h"
70213811Sobrien
71213811Sobrien#include <sys/param.h>
72213811Sobrien#include <sys/systm.h>
73213811Sobrien#include <sys/malloc.h>
74213811Sobrien#include <sys/mbuf.h>
75213811Sobrien#include <sys/protosw.h>
761556Srgrimes#include <sys/socket.h>
77213760Sobrien#include <sys/socketvar.h>
78213760Sobrien#include <sys/errno.h>
79213760Sobrien#include <sys/time.h>
801556Srgrimes
811556Srgrimes#include <net/if.h>
82240541Sjilles#include <net/route.h>
8317987Speter
84201053Sjilles#include <netinet/in.h>
85200956Sjilles#include <netinet/in_var.h>
861556Srgrimes#include <netinet/in_systm.h>
871556Srgrimes#include <netinet/ip.h>
88222154Sjilles#include <netinet/in_pcb.h>
89222154Sjilles#include <netinet6/in6_var.h>
90222292Sjilles#include <netinet/ip6.h>
911556Srgrimes#include <netinet6/in6_pcb.h>
92100664Stjr#include <netinet6/ip6_var.h>
93240541Sjilles#include <netinet6/nd6.h>
9497092Stjr#ifdef ENABLE_DEFAULT_SCOPE
95222154Sjilles#include <netinet6/scope6_var.h>
96222154Sjilles#endif
97222154Sjilles
9897092Stjr#include <net/net_osdep.h>
9997092Stjr
10097092Stjr/*
10197092Stjr * Return an IPv6 address, which is the most appropriate for a given
10297092Stjr * destination and user specified options.
10397092Stjr * If necessary, this function lookups the routing table and returns
10497092Stjr * an entry to the caller for later use.
10597092Stjr */
10697092Stjrstruct in6_addr *
107240541Sjillesin6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
10897092Stjr	struct sockaddr_in6 *dstsock;
10997092Stjr	struct ip6_pktopts *opts;
110240541Sjilles	struct ip6_moptions *mopts;
1111556Srgrimes	struct route_in6 *ro;
1125234Sbde	struct in6_addr *laddr;
1135234Sbde	int *errorp;
1141556Srgrimes{
1151556Srgrimes	struct in6_addr *dst;
11612273Speter	struct in6_ifaddr *ia6 = 0;
11712273Speter	struct in6_pktinfo *pi = NULL;
11812273Speter
11912273Speter	dst = &dstsock->sin6_addr;
1201556Srgrimes	*errorp = 0;
121222381Sjilles
122222381Sjilles	/*
123222381Sjilles	 * If the source address is explicitly specified by the caller,
124222381Sjilles	 * use it.
1251556Srgrimes	 */
1261556Srgrimes	if (opts && (pi = opts->ip6po_pktinfo) &&
127230095Sjilles	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
128230095Sjilles		return (&pi->ipi6_addr);
129230095Sjilles
130230095Sjilles	/*
131230095Sjilles	 * If the source address is not specified but the socket(if any)
132230095Sjilles	 * is already bound, use the bound address.
1331556Srgrimes	 */
1341556Srgrimes	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
1351556Srgrimes		return (laddr);
1361556Srgrimes
13738886Stegge	/*
138159551Sstefanf	 * If the caller doesn't specify the source address but
139159551Sstefanf	 * the outgoing interface, use an address associated with
140159551Sstefanf	 * the interface.
1411556Srgrimes	 */
142222154Sjilles	if (pi && pi->ipi6_ifindex) {
143222154Sjilles		/* XXX boundary check is assumed to be already done. */
144222154Sjilles		ia6 = in6_ifawithscope(ifnet_byindex(pi->ipi6_ifindex), dst);
145222292Sjilles		if (ia6 == 0) {
146222292Sjilles			*errorp = EADDRNOTAVAIL;
1471556Srgrimes			return (0);
1481556Srgrimes		}
149222292Sjilles		return (&satosin6(&ia6->ia_addr)->sin6_addr);
15017987Speter	}
15117987Speter
1521556Srgrimes	/*
1531556Srgrimes	 * If the destination address is a link-local unicast address or
1541556Srgrimes	 * a multicast address, and if the outgoing interface is specified
1551556Srgrimes	 * by the sin6_scope_id filed, use an address associated with the
15697092Stjr	 * interface.
15720774Ssteve	 * XXX: We're now trying to define more specific semantics of
1581556Srgrimes	 *      sin6_scope_id field, so this part will be rewritten in
159213811Sobrien	 *      the near future.
16097092Stjr	 */
16120425Ssteve	if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
162222154Sjilles	    dstsock->sin6_scope_id) {
16397092Stjr		/*
16497092Stjr		 * I'm not sure if boundary check for scope_id is done
16597092Stjr		 * somewhere...
16697092Stjr		 */
167222154Sjilles		if (dstsock->sin6_scope_id < 0 ||
16897092Stjr		    if_index < dstsock->sin6_scope_id) {
16997092Stjr			*errorp = ENXIO; /* XXX: better error? */
17097092Stjr			return (0);
17197092Stjr		}
17297092Stjr		ia6 = in6_ifawithscope(ifnet_byindex(dstsock->sin6_scope_id),
173222154Sjilles				       dst);
17497092Stjr		if (ia6 == 0) {
17597092Stjr			*errorp = EADDRNOTAVAIL;
176213811Sobrien			return (0);
17797092Stjr		}
17897092Stjr		return (&satosin6(&ia6->ia_addr)->sin6_addr);
17938886Stegge	}
18038886Stegge
18138886Stegge	/*
18238886Stegge	 * If the destination address is a multicast address and
18338886Stegge	 * the outgoing interface for the address is specified
18438886Stegge	 * by the caller, use an address associated with the interface.
185262951Sjmmv	 * There is a sanity check here; if the destination has node-local
18620425Ssteve	 * scope, the outgoing interfacde should be a loopback address.
18738886Stegge	 * Even if the outgoing interface is not specified, we also
18838886Stegge	 * choose a loopback interface as the outgoing interface.
18938886Stegge	 */
19038886Stegge	if (IN6_IS_ADDR_MULTICAST(dst)) {
19138886Stegge		struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
19238886Stegge
193262951Sjmmv		if (ifp == NULL && IN6_IS_ADDR_MC_INTFACELOCAL(dst)) {
194262951Sjmmv			ifp = &loif[0];
195262951Sjmmv		}
19638886Stegge
19738886Stegge		if (ifp) {
19838886Stegge			ia6 = in6_ifawithscope(ifp, dst);
19938886Stegge			if (ia6 == 0) {
20038886Stegge				*errorp = EADDRNOTAVAIL;
20138886Stegge				return (0);
20238886Stegge			}
20338886Stegge			return (&satosin6(&ia6->ia_addr)->sin6_addr);
20438886Stegge		}
20538886Stegge	}
20638886Stegge
20738886Stegge	/*
20838886Stegge	 * If the next hop address for the packet is specified
209215783Sjilles	 * by caller, use an address associated with the route
21038886Stegge	 * to the next hop.
21138886Stegge	 */
21238886Stegge	{
21397092Stjr		struct sockaddr_in6 *sin6_next;
21438886Stegge		struct rtentry *rt;
21538886Stegge
21638886Stegge		if (opts && opts->ip6po_nexthop) {
21738886Stegge			sin6_next = satosin6(opts->ip6po_nexthop);
21838886Stegge			rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
2191556Srgrimes			if (rt) {
220176521Sstefanf				ia6 = in6_ifawithscope(rt->rt_ifp, dst);
2211556Srgrimes				if (ia6 == 0)
22297092Stjr					ia6 = ifatoia6(rt->rt_ifa);
2231556Srgrimes			}
224176521Sstefanf			if (ia6 == 0) {
2251556Srgrimes				*errorp = EADDRNOTAVAIL;
22697092Stjr				return (0);
2271556Srgrimes			}
2281556Srgrimes			return (&satosin6(&ia6->ia_addr)->sin6_addr);
229213811Sobrien		}
23097092Stjr	}
23197092Stjr
232176521Sstefanf	/*
233222154Sjilles	 * If route is known or can be allocated now,
2341556Srgrimes	 * our src addr is taken from the i/f, else punt.
23597092Stjr	 */
236215727Sjilles	if (ro) {
23797092Stjr		if (ro->ro_rt &&
23897092Stjr		    (!(ro->ro_rt->rt_flags & RTF_UP) ||
23997092Stjr		     satosin6(&ro->ro_dst)->sin6_family != AF_INET6 ||
240215727Sjilles		     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
241222154Sjilles					 dst))) {
242216622Sjilles			RTFREE(ro->ro_rt);
243222154Sjilles			ro->ro_rt = (struct rtentry *)0;
244222154Sjilles		}
245176521Sstefanf		if (ro->ro_rt == (struct rtentry *)0 ||
24697092Stjr		    ro->ro_rt->rt_ifp == (struct ifnet *)0) {
247222154Sjilles			struct sockaddr_in6 *sa6;
24897092Stjr
24997092Stjr			/* No route yet, so try to acquire one */
2501556Srgrimes			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
2511556Srgrimes			sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
2521556Srgrimes			sa6->sin6_family = AF_INET6;
2531556Srgrimes			sa6->sin6_len = sizeof(struct sockaddr_in6);
254213811Sobrien			sa6->sin6_addr = *dst;
25590111Simp			sa6->sin6_scope_id = dstsock->sin6_scope_id;
25620774Ssteve			if (IN6_IS_ADDR_MULTICAST(dst)) {
25725222Ssteve				ro->ro_rt = rtalloc1(&((struct route *)ro)
2581556Srgrimes						     ->ro_dst, 0, 0UL);
2591556Srgrimes				RT_UNLOCK(ro->ro_rt);
2601556Srgrimes			} else {
2611556Srgrimes				rtalloc((struct route *)ro);
2621556Srgrimes			}
2631556Srgrimes		}
2641556Srgrimes
2651556Srgrimes		/*
2661556Srgrimes		 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
2671556Srgrimes		 * the address. But we don't know why it does so.
2681556Srgrimes		 * It is necessary to ensure the scope even for lo0
2691556Srgrimes		 * so doesn't check out IFF_LOOPBACK.
2701556Srgrimes		 */
2711556Srgrimes
2721556Srgrimes		if (ro->ro_rt) {
2731556Srgrimes			ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
2741556Srgrimes			if (ia6 == 0) /* xxx scope error ?*/
275213811Sobrien				ia6 = ifatoia6(ro->ro_rt->rt_ifa);
276176521Sstefanf		}
27720774Ssteve		if (ia6 == 0) {
2781556Srgrimes			*errorp = EHOSTUNREACH;	/* no route */
2791556Srgrimes			return (0);
280262951Sjmmv		}
2811556Srgrimes		return (&satosin6(&ia6->ia_addr)->sin6_addr);
28238886Stegge	}
28338886Stegge
28438886Stegge	*errorp = EADDRNOTAVAIL;
28538886Stegge	return (0);
28638886Stegge}
287199631Sstefanf
288199631Sstefanf/*
289262951Sjmmv * Default hop limit selection. The precedence is as follows:
290262951Sjmmv * 1. Hoplimit value specified via ioctl.
291262951Sjmmv * 2. (If the outgoing interface is detected) the current
2921556Srgrimes *     hop limit of the interface specified by router advertisement.
2931556Srgrimes * 3. The system default hoplimit.
294215783Sjilles*/
295215783Sjillesint
2961556Srgrimesin6_selecthlim(in6p, ifp)
2971556Srgrimes	struct in6pcb *in6p;
2981556Srgrimes	struct ifnet *ifp;
2991556Srgrimes{
3001556Srgrimes	if (in6p && in6p->in6p_hops >= 0)
3011556Srgrimes		return (in6p->in6p_hops);
3021556Srgrimes	else if (ifp)
303215783Sjilles		return (ND_IFINFO(ifp)->chlim);
3041556Srgrimes	else
3051556Srgrimes		return (ip6_defhlim);
3061556Srgrimes}
3071556Srgrimes
3081556Srgrimes/*
309176521Sstefanf * XXX: this is borrowed from in6_pcbbind(). If possible, we should
310176521Sstefanf * share this function by all *bsd*...
311176521Sstefanf */
312176521Sstefanfint
313176521Sstefanfin6_pcbsetport(laddr, inp, td)
314176521Sstefanf	struct in6_addr *laddr;
315176521Sstefanf	struct inpcb *inp;
316176521Sstefanf	struct thread *td;
317213811Sobrien{
318176521Sstefanf	struct socket *so = inp->inp_socket;
319176521Sstefanf	u_int16_t lport = 0, first, last, *lastport;
320176521Sstefanf	int count, error = 0, wild = 0;
321176521Sstefanf	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
32238886Stegge
32338886Stegge	/* XXX: this is redundant when called from in6_pcbbind */
32438886Stegge	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
325215727Sjilles		wild = INPLOOKUP_WILDCARD;
32686176Stegge
32786176Stegge	inp->inp_flags |= INP_ANONPORT;
3281556Srgrimes
3291556Srgrimes	if (inp->inp_flags & INP_HIGHPORT) {
3301556Srgrimes		first = ipport_hifirstauto;	/* sysctl */
331240541Sjilles		last  = ipport_hilastauto;
33217987Speter		lastport = &pcbinfo->lasthi;
333199631Sstefanf	} else if (inp->inp_flags & INP_LOWPORT) {
33497092Stjr		if (td && (error = suser(td)))
3351556Srgrimes			return error;
336100664Stjr		first = ipport_lowfirstauto;	/* 1023 */
337240541Sjilles		last  = ipport_lowlastauto;	/* 600 */
33897092Stjr		lastport = &pcbinfo->lastlow;
33997092Stjr	} else {
34097092Stjr		first = ipport_firstauto;	/* sysctl */
34197092Stjr		last  = ipport_lastauto;
34297092Stjr		lastport = &pcbinfo->lastport;
34397092Stjr	}
34497092Stjr	/*
34597092Stjr	 * Simple check to ensure all ports are not used up causing
34697092Stjr	 * a deadlock here.
3471556Srgrimes	 *
348240541Sjilles	 * We split the two cases (up and down) so that the direction
34997092Stjr	 * is not being tested on each round of the loop.
35038886Stegge	 */
35197092Stjr	if (first > last) {
35297092Stjr		/*
35397092Stjr		 * counting down
35497092Stjr		 */
355199631Sstefanf		count = first - last;
35697092Stjr
357199631Sstefanf		do {
35897092Stjr			if (count-- < 0) {	/* completely used? */
35997092Stjr				/*
36038886Stegge				 * Undo any address bind that may have
36197092Stjr				 * occurred above.
36297092Stjr				 */
36338886Stegge				inp->in6p_laddr = in6addr_any;
3641556Srgrimes				return (EAGAIN);
365176521Sstefanf			}
3661556Srgrimes			--*lastport;
367213811Sobrien			if (*lastport > first || *lastport < last)
36890111Simp				*lastport = first;
36920425Ssteve			lport = htons(*lastport);
370176521Sstefanf		} while (in6_pcblookup_local(pcbinfo,
37138886Stegge					     &inp->in6p_laddr, lport, wild));
3721556Srgrimes	} else {
37338886Stegge		/*
374176521Sstefanf			 * counting up
375199631Sstefanf			 */
376176521Sstefanf		count = last - first;
377176521Sstefanf
378176521Sstefanf		do {
379176521Sstefanf			if (count-- < 0) {	/* completely used? */
380176521Sstefanf				/*
381176521Sstefanf				 * Undo any address bind that may have
382199631Sstefanf				 * occurred above.
383199631Sstefanf				 */
384176521Sstefanf				inp->in6p_laddr = in6addr_any;
385176521Sstefanf				return (EAGAIN);
386176521Sstefanf			}
387213811Sobrien			++*lastport;
388199631Sstefanf			if (*lastport < first || *lastport > last)
389176521Sstefanf				*lastport = first;
390199631Sstefanf			lport = htons(*lastport);
391199631Sstefanf		} while (in6_pcblookup_local(pcbinfo,
39238886Stegge					     &inp->in6p_laddr, lport, wild));
393199631Sstefanf	}
394199631Sstefanf
395199631Sstefanf	inp->inp_lport = lport;
396176521Sstefanf	if (in_pcbinshash(inp) != 0) {
397199631Sstefanf		inp->in6p_laddr = in6addr_any;
398199631Sstefanf		inp->inp_lport = 0;
399199631Sstefanf		return (EAGAIN);
40038886Stegge	}
401199631Sstefanf
402206759Sjilles	return (0);
403206759Sjilles}
404206759Sjilles
405206759Sjilles/*
406206759Sjilles * Generate kernel-internal form (scopeid embedded into s6_addr16[1]).
407206759Sjilles * If the address scope of is link-local, embed the interface index in the
408206759Sjilles * address.  The routine determines our precedence
409206759Sjilles * between advanced API scope/interface specification and basic API
410206759Sjilles * specification.
411206759Sjilles *
412206759Sjilles * This function should be nuked in the future, when we get rid of embedded
413206759Sjilles * scopeid thing.
414206759Sjilles *
415206759Sjilles * XXX actually, it is over-specification to return ifp against sin6_scope_id.
416199631Sstefanf * there can be multiple interfaces that belong to a particular scope zone
417199631Sstefanf * (in specification, we have 1:N mapping between a scope zone and interfaces).
418199631Sstefanf * we may want to change the function to return something other than ifp.
419199631Sstefanf */
420206759Sjillesint
421206759Sjillesin6_embedscope(in6, sin6, in6p, ifpp)
422206759Sjilles	struct in6_addr *in6;
423199631Sstefanf	const struct sockaddr_in6 *sin6;
424206759Sjilles#ifdef HAVE_NRL_INPCB
425206759Sjilles	struct inpcb *in6p;
426206759Sjilles#define in6p_outputopts	inp_outputopts6
4271556Srgrimes#define in6p_moptions	inp_moptions6
428#else
429	struct in6pcb *in6p;
430#endif
431	struct ifnet **ifpp;
432{
433	struct ifnet *ifp = NULL;
434	u_int32_t scopeid;
435
436	*in6 = sin6->sin6_addr;
437	scopeid = sin6->sin6_scope_id;
438	if (ifpp)
439		*ifpp = NULL;
440
441	/*
442	 * don't try to read sin6->sin6_addr beyond here, since the caller may
443	 * ask us to overwrite existing sockaddr_in6
444	 */
445
446#ifdef ENABLE_DEFAULT_SCOPE
447	if (scopeid == 0)
448		scopeid = scope6_addr2default(in6);
449#endif
450
451	if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
452		struct in6_pktinfo *pi;
453
454		/*
455		 * KAME assumption: link id == interface id
456		 */
457
458		if (in6p && in6p->in6p_outputopts &&
459		    (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
460		    pi->ipi6_ifindex) {
461			ifp = ifnet_byindex(pi->ipi6_ifindex);
462			in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
463		} else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
464			   in6p->in6p_moptions &&
465			   in6p->in6p_moptions->im6o_multicast_ifp) {
466			ifp = in6p->in6p_moptions->im6o_multicast_ifp;
467			in6->s6_addr16[1] = htons(ifp->if_index);
468		} else if (scopeid) {
469			/* boundary check */
470			if (scopeid < 0 || if_index < scopeid)
471				return ENXIO;  /* XXX EINVAL? */
472			ifp = ifnet_byindex(scopeid);
473			/* XXX assignment to 16bit from 32bit variable */
474			in6->s6_addr16[1] = htons(scopeid & 0xffff);
475		}
476
477		if (ifpp)
478			*ifpp = ifp;
479	}
480
481	return 0;
482}
483#ifdef HAVE_NRL_INPCB
484#undef in6p_outputopts
485#undef in6p_moptions
486#endif
487
488/*
489 * generate standard sockaddr_in6 from embedded form.
490 * touches sin6_addr and sin6_scope_id only.
491 *
492 * this function should be nuked in the future, when we get rid of
493 * embedded scopeid thing.
494 */
495int
496in6_recoverscope(sin6, in6, ifp)
497	struct sockaddr_in6 *sin6;
498	const struct in6_addr *in6;
499	struct ifnet *ifp;
500{
501	u_int32_t zoneid;
502
503	sin6->sin6_addr = *in6;
504
505	/*
506	 * don't try to read *in6 beyond here, since the caller may
507	 * ask us to overwrite existing sockaddr_in6
508	 */
509
510	sin6->sin6_scope_id = 0;
511	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
512		/*
513		 * KAME assumption: link id == interface id
514		 */
515		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
516		if (zoneid) {
517			/* sanity check */
518			if (zoneid < 0 || if_index < zoneid)
519				return ENXIO;
520			if (ifp && ifp->if_index != zoneid)
521				return ENXIO;
522			sin6->sin6_addr.s6_addr16[1] = 0;
523			sin6->sin6_scope_id = zoneid;
524		}
525	}
526
527	return 0;
528}
529
530/*
531 * just clear the embedded scope identifier.
532 */
533void
534in6_clearscope(addr)
535	struct in6_addr *addr;
536{
537	if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
538		addr->s6_addr16[1] = 0;
539}
540