in6_pcb.c revision 56117
1139823Simp/*
298943Sluigi * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
398943Sluigi * All rights reserved.
498943Sluigi *
598943Sluigi * Redistribution and use in source and binary forms, with or without
698943Sluigi * modification, are permitted provided that the following conditions
798943Sluigi * are met:
898943Sluigi * 1. Redistributions of source code must retain the above copyright
9116763Sluigi *    notice, this list of conditions and the following disclaimer.
1098943Sluigi * 2. Redistributions in binary form must reproduce the above copyright
1198943Sluigi *    notice, this list of conditions and the following disclaimer in the
12105775Smaxim *    documentation and/or other materials provided with the distribution.
1398943Sluigi * 3. Neither the name of the project nor the names of its contributors
1498943Sluigi *    may be used to endorse or promote products derived from this software
1598943Sluigi *    without specific prior written permission.
1698943Sluigi *
1798943Sluigi * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1898943Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1998943Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2098943Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2198943Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2298943Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2398943Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2498943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2598943Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26172467Ssilby * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27172467Ssilby * SUCH DAMAGE.
28172467Ssilby *
2998943Sluigi * $FreeBSD: head/sys/netinet6/in6_pcb.c 56117 2000-01-16 18:00:06Z shin $
3098943Sluigi */
3198943Sluigi
3298943Sluigi/*
3399622Sluigi * Copyright (c) 1982, 1986, 1991, 1993
3498943Sluigi *	The Regents of the University of California.  All rights reserved.
3598943Sluigi *
36134346Sru * Redistribution and use in source and binary forms, with or without
3798943Sluigi * modification, are permitted provided that the following conditions
38166479Salc * are met:
3998943Sluigi * 1. Redistributions of source code must retain the above copyright
4098943Sluigi *    notice, this list of conditions and the following disclaimer.
4198943Sluigi * 2. Redistributions in binary form must reproduce the above copyright
4298943Sluigi *    notice, this list of conditions and the following disclaimer in the
4398943Sluigi *    documentation and/or other materials provided with the distribution.
44134346Sru * 3. All advertising materials mentioning features or use of this software
45152928Sume *    must display the following acknowledgement:
46152928Sume *	This product includes software developed by the University of
4798943Sluigi *	California, Berkeley and its contributors.
4898943Sluigi * 4. Neither the name of the University nor the names of its contributors
4998943Sluigi *    may be used to endorse or promote products derived from this software
50138642Scsjp *    without specific prior written permission.
51165648Spiso *
5298943Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5398943Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5498943Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55155201Scsjp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56133600Scsjp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57129876Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58164033Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5998943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60155201Scsjp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6198943Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6298943Sluigi * SUCH DAMAGE.
6398943Sluigi *
6498943Sluigi *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94
6598943Sluigi * $FreeBSD: head/sys/netinet6/in6_pcb.c 56117 2000-01-16 18:00:06Z shin $
66188676Sluigi */
6798943Sluigi
68130281Sru#include "opt_ipsec.h"
6998943Sluigi
70171173Smlaier#include <sys/param.h>
71185571Sbz#include <sys/systm.h>
72175659Srwatson#include <sys/malloc.h>
73175659Srwatson#include <sys/mbuf.h>
74175659Srwatson#include <sys/domain.h>
7598943Sluigi#include <sys/protosw.h>
7698943Sluigi#include <sys/socket.h>
7798943Sluigi#include <sys/socketvar.h>
7898943Sluigi#include <sys/sockio.h>
7998943Sluigi#include <sys/errno.h>
8098943Sluigi#include <sys/time.h>
8198943Sluigi#include <sys/proc.h>
82126239Smlaier#include <sys/jail.h>
8398943Sluigi
84163069Sbz#include <vm/vm_zone.h>
85161767Sjhay
8698943Sluigi#include <net/if.h>
8798943Sluigi#include <net/if_types.h>
8898943Sluigi#include <net/route.h>
89164258Sbz
90185571Sbz#include <netinet/in.h>
91141351Sglebius#include <netinet/in_var.h>
92141351Sglebius#include <netinet/in_systm.h>
93145246Sbrooks#include <netinet6/ip6.h>
94145246Sbrooks#include <netinet/ip_var.h>
95148414Sume#include <netinet6/ip6_var.h>
96148414Sume#include <netinet6/nd6.h>
97200027Sume#include <netinet/in_pcb.h>
98148414Sume#include <netinet6/in6_pcb.h>
99145246Sbrooks
10099475Sluigi#include "faith.h"
10199475Sluigi
102188580Sluigi#ifdef IPSEC
103163606Srwatson#include <netinet6/ipsec.h>
104188580Sluigi#include <netinet6/ah.h>
105163606Srwatson#include <netinet6/ipsec6.h>
106196423Sjulian#include <netinet6/ah6.h>
107196423Sjulian#include <netkey/key.h>
108101628Sluigi#ifdef IPSEC_DEBUG
109101628Sluigi#include <netkey/key_debug.h>
110101628Sluigi#else
111117654Sluigi#define	KEYDEBUG(lev,arg)
112117654Sluigi#endif /* IPSEC_DEBUG */
113101628Sluigi#endif /* IPSEC */
114117654Sluigi
115101628Sluigistruct	in6_addr zeroin6_addr;
116195699Srwatson
117195699Srwatsonint
118195699Srwatsonin6_pcbbind(inp, nam, p)
119195699Srwatson	register struct inpcb *inp;
12098943Sluigi	struct sockaddr *nam;
121195727Srwatson	struct proc *p;
122195727Srwatson{
123195727Srwatson	struct socket *so = inp->inp_socket;
124195727Srwatson	unsigned short *lastport;
125195699Srwatson	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
126191932Sjhb	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
127191932Sjhb	u_short	lport = 0;
128191932Sjhb	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
129191932Sjhb	int error;
130191932Sjhb
131141076Scsjp	if (!in6_ifaddr) /* XXX broken! */
13298943Sluigi		return (EADDRNOTAVAIL);
133193859Soleg	if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
134193859Soleg		return(EINVAL);
135130363Scsjp	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
13698943Sluigi		wild = 1;
13798943Sluigi	if (nam) {
138195699Srwatson		sin6 = (struct sockaddr_in6 *)nam;
13998943Sluigi		if (nam->sa_len != sizeof(*sin6))
14098943Sluigi			return(EINVAL);
141130281Sru		/*
142176669Spiso		 * family check.
143176669Spiso		 */
144176669Spiso		if (nam->sa_family != AF_INET6)
145176669Spiso			return(EAFNOSUPPORT);
146176669Spiso
147176669Spiso		/*
14898943Sluigi		 * If the scope of the destination is link-local, embed the
149130281Sru		 * interface index in the address.
150130281Sru		 */
151130281Sru		if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
152130281Sru			/* XXX boundary check is assumed to be already done. */
153130281Sru			/* XXX sin6_scope_id is weaker than advanced-api. */
154130281Sru			struct in6_pktinfo *pi;
155195699Srwatson			if (inp->in6p_outputopts &&
156195727Srwatson			    (pi = inp->in6p_outputopts->ip6po_pktinfo) &&
157195862Sjulian			    pi->ipi6_ifindex) {
158195862Sjulian				sin6->sin6_addr.s6_addr16[1]
15998943Sluigi					= htons(pi->ipi6_ifindex);
160158470Smlaier			} else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)
161158470Smlaier				&& inp->in6p_moptions
16298943Sluigi				&& inp->in6p_moptions->im6o_multicast_ifp) {
16398943Sluigi				sin6->sin6_addr.s6_addr16[1] =
164195699Srwatson					htons(inp->in6p_moptions->im6o_multicast_ifp->if_index);
165195699Srwatson			} else if (sin6->sin6_scope_id) {
166158470Smlaier				/* boundary check */
167195699Srwatson				if (sin6->sin6_scope_id < 0
168195862Sjulian				 || if_index < sin6->sin6_scope_id) {
169195862Sjulian					return ENXIO;  /* XXX EINVAL? */
170195699Srwatson				}
171195699Srwatson				sin6->sin6_addr.s6_addr16[1]
17298943Sluigi					= htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
173195699Srwatson				/* this must be cleared for ifa_ifwithaddr() */
174195862Sjulian				sin6->sin6_scope_id = 0;
175195862Sjulian			}
176195699Srwatson		}
177195699Srwatson
178186048Sbz		lport = sin6->sin6_port;
179182818Srik		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
180195862Sjulian			/*
181195862Sjulian			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
182183015Srik			 * allow compepte duplication of binding if
183195862Sjulian			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
184195862Sjulian			 * and a multicast address is bound on both
185191932Sjhb			 * new and duplicated sockets.
186195862Sjulian			 */
187195862Sjulian			if (so->so_options & SO_REUSEADDR)
188191932Sjhb				reuseport = SO_REUSEADDR|SO_REUSEPORT;
189200040Sluigi		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
190195862Sjulian			struct ifaddr *ia = NULL;
191195862Sjulian
192195862Sjulian			sin6->sin6_port = 0;		/* yech... */
193195862Sjulian			if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
194195862Sjulian				return(EADDRNOTAVAIL);
195195862Sjulian
196195862Sjulian			/*
197195862Sjulian			 * XXX: bind to an anycast address might accidentally
198195862Sjulian			 * cause sending a packet with anycast source address.
199200040Sluigi			 */
20098943Sluigi			if (ia &&
201200040Sluigi			    ((struct in6_ifaddr *)ia)->ia6_flags &
202200040Sluigi			    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
20398943Sluigi			     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
20498943Sluigi				return(EADDRNOTAVAIL);
20598943Sluigi			}
20698943Sluigi		}
20798943Sluigi		if (lport) {
20898943Sluigi			struct inpcb *t;
20998943Sluigi
21098943Sluigi			/* GROSS */
21198943Sluigi			if (ntohs(lport) < IPV6PORT_RESERVED && p &&
21298943Sluigi			    suser_xxx(0, p, PRISON_ROOT))
21398943Sluigi				return(EACCES);
21498943Sluigi			if (so->so_cred->cr_uid != 0 &&
21598943Sluigi			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
21698943Sluigi				t = in6_pcblookup_local(pcbinfo,
21798943Sluigi				    &sin6->sin6_addr, lport,
21898943Sluigi				    INPLOOKUP_WILDCARD);
21998943Sluigi				if (t &&
22098943Sluigi				    (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
22198943Sluigi				     !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
22298943Sluigi				     (t->inp_socket->so_options &
22398943Sluigi				      SO_REUSEPORT) == 0) &&
22498943Sluigi				    (so->so_cred->cr_uid !=
22598943Sluigi				     t->inp_socket->so_cred->cr_uid))
22698943Sluigi					return (EADDRINUSE);
22798943Sluigi				if (ip6_mapped_addr_on != 0 &&
22898943Sluigi				    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
22998943Sluigi					struct sockaddr_in sin;
23098943Sluigi
23198943Sluigi					in6_sin6_2_sin(&sin, sin6);
23298943Sluigi					t = in_pcblookup_local(pcbinfo,
23398943Sluigi						sin.sin_addr, lport,
23498943Sluigi						INPLOOKUP_WILDCARD);
23598943Sluigi					if (t &&
23698943Sluigi					    (so->so_cred->cr_uid !=
23798943Sluigi					     t->inp_socket->so_cred->cr_uid) &&
23898943Sluigi					    (ntohl(t->inp_laddr.s_addr) !=
239195699Srwatson					     INADDR_ANY ||
240195699Srwatson					     INP_SOCKAF(so) ==
241195699Srwatson					     INP_SOCKAF(t->inp_socket)))
24298943Sluigi						return (EADDRINUSE);
243195727Srwatson				}
244195727Srwatson			}
245195727Srwatson			t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
246195699Srwatson						lport, wild);
247120141Ssam			if (t && (reuseport & t->inp_socket->so_options) == 0)
248120141Ssam				return(EADDRINUSE);
249120141Ssam			if (ip6_mapped_addr_on != 0 &&
250120141Ssam			    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
251120141Ssam				struct sockaddr_in sin;
252120141Ssam
253120141Ssam				in6_sin6_2_sin(&sin, sin6);
254120141Ssam				t = in_pcblookup_local(pcbinfo, sin.sin_addr,
255200027Sume						       lport, wild);
256200027Sume				if (t &&
257200027Sume				    (reuseport & t->inp_socket->so_options)
258200027Sume				    == 0 &&
25998943Sluigi				    (ntohl(t->inp_laddr.s_addr)
26098943Sluigi				     != INADDR_ANY ||
26198943Sluigi				     INP_SOCKAF(so) ==
262195699Srwatson				     INP_SOCKAF(t->inp_socket)))
263195699Srwatson					return (EADDRINUSE);
264195699Srwatson			}
265195699Srwatson		}
266195699Srwatson		inp->in6p_laddr = sin6->sin6_addr;
267195699Srwatson	}
26898943Sluigi	if (lport == 0) {
269195727Srwatson		ushort first, last;
270195727Srwatson		int count;
271195727Srwatson
272195727Srwatson		inp->inp_flags |= INP_ANONPORT;
273195727Srwatson
274195727Srwatson		if (inp->inp_flags & INP_HIGHPORT) {
275195699Srwatson			first = ipport_hifirstauto;	/* sysctl */
276101978Sluigi			last  = ipport_hilastauto;
277101978Sluigi			lastport = &pcbinfo->lasthi;
278101978Sluigi		} else if (inp->inp_flags & INP_LOWPORT) {
279101978Sluigi			if (p && (error = suser_xxx(0, p, PRISON_ROOT)))
280101978Sluigi				return error;
281101978Sluigi			first = ipport_lowfirstauto;	/* 1023 */
282101978Sluigi			last  = ipport_lowlastauto;	/* 600 */
283105775Smaxim			lastport = &pcbinfo->lastlow;
284195699Srwatson		} else {
285195699Srwatson			first = ipport_firstauto;	/* sysctl */
286195699Srwatson			last  = ipport_lastauto;
28798943Sluigi			lastport = &pcbinfo->lastport;
288195727Srwatson		}
289195727Srwatson		/*
290195727Srwatson		 * Simple check to ensure all ports are not used up causing
29198943Sluigi		 * a deadlock here.
292195699Srwatson		 *
293195699Srwatson		 * We split the two cases (up and down) so that the direction
294195699Srwatson		 * is not being tested on each round of the loop.
295195699Srwatson		 */
296195699Srwatson		if (first > last) {
297195727Srwatson			/*
298195727Srwatson			 * counting down
299195727Srwatson			 */
300195727Srwatson			count = first - last;
301195699Srwatson
302187821Sluigi			do {
303195699Srwatson				if (count-- < 0) {	/* completely used? */
304195862Sjulian					/*
305195862Sjulian					 * Undo any address bind that may have
306195699Srwatson					 * occurred above.
307195699Srwatson					 */
308195699Srwatson					inp->in6p_laddr = in6addr_any;
309195699Srwatson					return (EAGAIN);
310195862Sjulian				}
311195862Sjulian				--*lastport;
312195699Srwatson				if (*lastport > first || *lastport < last)
313195862Sjulian					*lastport = first;
314195862Sjulian				lport = htons(*lastport);
315195699Srwatson			} while (in6_pcblookup_local(pcbinfo,
316195862Sjulian				 &inp->in6p_laddr, lport, wild));
317195862Sjulian		} else {
318195699Srwatson			/*
319195699Srwatson			 * counting up
320195699Srwatson			 */
321195699Srwatson			count = last - first;
322195699Srwatson
323195699Srwatson			do {
324195699Srwatson				if (count-- < 0) {	/* completely used? */
325195699Srwatson					/*
326195699Srwatson					 * Undo any address bind that may have
327195699Srwatson					 * occurred above.
328195699Srwatson					 */
329195699Srwatson					inp->in6p_laddr = in6addr_any;
330195699Srwatson					return (EAGAIN);
331195699Srwatson				}
332195699Srwatson				++*lastport;
333195699Srwatson				if (*lastport < first || *lastport > last)
334195699Srwatson					*lastport = first;
335183550Szec				lport = htons(*lastport);
336195699Srwatson			} while (in6_pcblookup_local(pcbinfo,
337195699Srwatson				 &inp->in6p_laddr, lport, wild));
338195699Srwatson		}
339187821Sluigi	}
34098943Sluigi	inp->inp_lport = lport;
341149020Sbz	if (in_pcbinshash(inp) != 0) {
342145093Sbrooks		inp->in6p_laddr = in6addr_any;
343145093Sbrooks		inp->inp_lport = 0;
34498943Sluigi		return (EAGAIN);
345145093Sbrooks	}
346145093Sbrooks	inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0;	/*XXX*/
347164258Sbz	return(0);
348145093Sbrooks}
349145565Sbrooks
350145246Sbrooks/*
35198943Sluigi *   Transform old in6_pcbconnect() into an inner subroutine for new
35299622Sluigi *   in6_pcbconnect(): Do some validity-checking on the remote
353145565Sbrooks *   address (in mbuf 'nam') and then determine local host address
35498943Sluigi *   (i.e., which interface) to use to access that remote host.
355145093Sbrooks *
35698943Sluigi *   This preserves definition of in6_pcbconnect(), while supporting a
35798943Sluigi *   slightly different version for T/TCP.  (This is more than
35898943Sluigi *   a bit of a kludge, but cleaning up the internal interfaces would
35998943Sluigi *   have forced minor changes in every protocol).
36098943Sluigi */
36198943Sluigi
36298943Sluigiint
36398943Sluigiin6_pcbladdr(inp, nam, plocal_addr6)
364145565Sbrooks	register struct inpcb *inp;
36598943Sluigi	struct sockaddr *nam;
366145093Sbrooks	struct in6_addr **plocal_addr6;
367145093Sbrooks{
36898943Sluigi	register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
36998943Sluigi	struct in6_pktinfo *pi;
37098943Sluigi	struct ifnet *ifp = NULL;
37198943Sluigi	int error = 0;
37298943Sluigi
37398943Sluigi	if (nam->sa_len != sizeof (*sin6))
37498943Sluigi		return (EINVAL);
37598943Sluigi	if (sin6->sin6_family != AF_INET6)
37698943Sluigi		return (EAFNOSUPPORT);
37798943Sluigi	if (sin6->sin6_port == 0)
37898943Sluigi		return (EADDRNOTAVAIL);
37998943Sluigi
38098943Sluigi	/*
38198943Sluigi	 * If the scope of the destination is link-local, embed the interface
38298943Sluigi	 * index in the address.
38398943Sluigi	 */
38498943Sluigi	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
38598943Sluigi		/* XXX boundary check is assumed to be already done. */
38698943Sluigi		/* XXX sin6_scope_id is weaker than advanced-api. */
38798943Sluigi		if (inp->in6p_outputopts &&
38898943Sluigi		    (pi = inp->in6p_outputopts->ip6po_pktinfo) &&
38998943Sluigi		    pi->ipi6_ifindex) {
39098943Sluigi			sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
39198943Sluigi			ifp = ifindex2ifnet[pi->ipi6_ifindex];
39298943Sluigi		} else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
39398943Sluigi			 inp->in6p_moptions &&
39498943Sluigi			 inp->in6p_moptions->im6o_multicast_ifp) {
39598943Sluigi			sin6->sin6_addr.s6_addr16[1] =
39698943Sluigi				htons(inp->in6p_moptions->im6o_multicast_ifp->if_index);
39798943Sluigi			ifp = ifindex2ifnet[inp->in6p_moptions->im6o_multicast_ifp->if_index];
39898943Sluigi		} else if (sin6->sin6_scope_id) {
39998943Sluigi			/* boundary check */
40098943Sluigi			if (sin6->sin6_scope_id < 0
40198943Sluigi			 || if_index < sin6->sin6_scope_id) {
40298943Sluigi				return ENXIO;  /* XXX EINVAL? */
40398943Sluigi			}
40498943Sluigi			sin6->sin6_addr.s6_addr16[1]
40598943Sluigi				= htons(sin6->sin6_scope_id & 0xffff);/*XXX*/
40698943Sluigi			ifp = ifindex2ifnet[sin6->sin6_scope_id];
40798943Sluigi		}
40898943Sluigi	}
40998943Sluigi
41098943Sluigi	if (in6_ifaddr) {
41198943Sluigi		/*
41298943Sluigi		 * If the destination address is UNSPECIFIED addr,
41398943Sluigi		 * use the loopback addr, e.g ::1.
41498943Sluigi		 */
41598943Sluigi		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
41698943Sluigi			sin6->sin6_addr = in6addr_loopback;
41798943Sluigi	}
41898943Sluigi	{
41998943Sluigi		/*
42098943Sluigi		 * XXX: in6_selectsrc might replace the bound local address
42198943Sluigi		 * with the address specified by setsockopt(IPV6_PKTINFO).
42298943Sluigi		 * Is it the intended behavior?
42398943Sluigi		 */
42498943Sluigi		*plocal_addr6 = in6_selectsrc(sin6, inp->in6p_outputopts,
42598943Sluigi					      inp->in6p_moptions,
42698943Sluigi					      &inp->in6p_route,
42798943Sluigi					      &inp->in6p_laddr, &error);
42898943Sluigi		if (*plocal_addr6 == 0) {
42998943Sluigi			if (error == 0)
43098943Sluigi				error = EADDRNOTAVAIL;
43198943Sluigi			return(error);
43298943Sluigi		}
43398943Sluigi		/*
43498943Sluigi		 * Don't do pcblookup call here; return interface in
43598943Sluigi		 * plocal_addr6
43698943Sluigi		 * and exit to caller, that will do the lookup.
43798943Sluigi		 */
43898943Sluigi	}
43998943Sluigi
44098943Sluigi	if (inp->in6p_route.ro_rt)
44198943Sluigi		ifp = inp->in6p_route.ro_rt->rt_ifp;
44298943Sluigi
443145093Sbrooks	inp->in6p_ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
44498943Sluigi
44598943Sluigi	return(0);
44698943Sluigi}
44798943Sluigi
44898943Sluigi/*
44998943Sluigi * Outer subroutine:
45098943Sluigi * Connect from a socket to a specified address.
45198943Sluigi * Both address and port must be specified in argument sin.
45298943Sluigi * If don't have a local address for this socket yet,
45398943Sluigi * then pick one.
45498943Sluigi */
45598943Sluigiint
45698943Sluigiin6_pcbconnect(inp, nam, p)
45798943Sluigi	register struct inpcb *inp;
45898943Sluigi	struct sockaddr *nam;
45998943Sluigi	struct proc *p;
46098943Sluigi{
46198943Sluigi	struct in6_addr *addr6;
46298943Sluigi	register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
46398943Sluigi	int error;
46498943Sluigi
46598943Sluigi	/*
46698943Sluigi	 *   Call inner routine, to assign local interface address.
46798943Sluigi	 */
46898943Sluigi	if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0)
46998943Sluigi		return(error);
47098943Sluigi
47198943Sluigi	if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
47298943Sluigi			       sin6->sin6_port,
47398943Sluigi			      IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
47498943Sluigi			      ? addr6 : &inp->in6p_laddr,
47598943Sluigi			      inp->inp_lport, 0, NULL) != NULL) {
47698943Sluigi		return (EADDRINUSE);
47798943Sluigi	}
47898943Sluigi	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
47998943Sluigi		if (inp->inp_lport == 0) {
48098943Sluigi			error = in6_pcbbind(inp, (struct sockaddr *)0, p);
48198943Sluigi			if (error)
48298943Sluigi				return (error);
48398943Sluigi		}
48498943Sluigi		inp->in6p_laddr = *addr6;
48598943Sluigi	}
48698943Sluigi	inp->in6p_faddr = sin6->sin6_addr;
48798943Sluigi	inp->inp_fport = sin6->sin6_port;
48898943Sluigi	/*
48998943Sluigi	 * xxx kazu flowlabel is necessary for connect?
49098943Sluigi	 * but if this line is missing, the garbage value remains.
49198943Sluigi	 */
49298943Sluigi	inp->in6p_flowinfo = sin6->sin6_flowinfo;
49398943Sluigi	if ((inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) == 0 &&
49499475Sluigi	    ip6_auto_flowlabel != 0)
49598943Sluigi		inp->in6p_flowinfo |=
496121816Sbrooks			(htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
497121816Sbrooks
498121816Sbrooks	in_pcbrehash(inp);
499121816Sbrooks	return (0);
500121816Sbrooks}
501121816Sbrooks
502121816Sbrooks/*
50398943Sluigi * Return an IPv6 address, which is the most appropriate for given
50498943Sluigi * destination and user specified options.
50598943Sluigi * If necessary, this function lookups the routing table and return
506195023Srwatson * an entry to the caller for later use.
50798943Sluigi */
50898943Sluigistruct in6_addr *
50998943Sluigiin6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
51098943Sluigi	struct sockaddr_in6 *dstsock;
511191288Srwatson	struct ip6_pktopts *opts;
512195023Srwatson	struct ip6_moptions *mopts;
51398943Sluigi	struct route_in6 *ro;
514191288Srwatson	struct in6_addr *laddr;
51598943Sluigi	int *errorp;
516195023Srwatson{
51798943Sluigi	struct in6_addr *dst;
51898943Sluigi	struct in6_ifaddr *ia6 = 0;
51998943Sluigi	struct in6_pktinfo *pi = NULL;
52098943Sluigi
521112250Scjc	dst = &dstsock->sin6_addr;
522128575Sandre	*errorp = 0;
523128575Sandre
524128575Sandre	/*
525112250Scjc	 * If the source address is explicitly specified by the caller,
526116763Sluigi	 * use it.
527128575Sandre	 */
528128575Sandre	if (opts && (pi = opts->ip6po_pktinfo) &&
529128575Sandre	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
530128575Sandre		return(&pi->ipi6_addr);
531128575Sandre
532128575Sandre	/*
533112250Scjc	 * If the source address is not specified but the socket(if any)
534112250Scjc	 * is already bound, use the bound address.
535128575Sandre	 */
536112250Scjc	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
537112250Scjc		return(laddr);
538112250Scjc
539112250Scjc	/*
540112250Scjc	 * If the caller doesn't specify the source address but
541112250Scjc	 * the outgoing interface, use an address associated with
542178888Sjulian	 * the interface.
543112250Scjc	 */
544123000Sandre	if (pi && pi->ipi6_ifindex) {
545112250Scjc		/* XXX boundary check is assumed to be already done. */
546112250Scjc		ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
547123000Sandre				       dst);
548123000Sandre		if (ia6 == 0) {
549112250Scjc			*errorp = EADDRNOTAVAIL;
550123000Sandre			return(0);
551123000Sandre		}
552123000Sandre		return(&satosin6(&ia6->ia_addr)->sin6_addr);
553186119Sqingli	}
554112250Scjc
555122922Sandre	/*
556112250Scjc	 * If the destination address is a link-local unicast address or
557128575Sandre	 * a multicast address, and if the outgoing interface is specified
558154769Soleg	 * by the sin6_scope_id filed, use an address associated with the
559154769Soleg	 * interface.
560154769Soleg	 * XXX: We're now trying to define more specific semantics of
561154769Soleg	 *      sin6_scope_id field, so this part will be rewritten in
562154769Soleg	 *      the near future.
563154769Soleg	 */
564154769Soleg	if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
565154769Soleg	    dstsock->sin6_scope_id) {
566122922Sandre		/*
567122922Sandre		 * I'm not sure if boundary check for scope_id is done
568122922Sandre		 * somewhere...
569128575Sandre		 */
570128575Sandre		if (dstsock->sin6_scope_id < 0 ||
571128575Sandre		    if_index < dstsock->sin6_scope_id) {
572128575Sandre			*errorp = ENXIO; /* XXX: better error? */
573128575Sandre			return(0);
574128575Sandre		}
575128575Sandre		ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
576128575Sandre				       dst);
577132510Sandre		if (ia6 == 0) {
578132510Sandre			*errorp = EADDRNOTAVAIL;
579132510Sandre			return(0);
580132510Sandre		}
581132510Sandre		return(&satosin6(&ia6->ia_addr)->sin6_addr);
582132510Sandre	}
583128575Sandre
584122922Sandre	/*
585116981Sluigi	 * If the destination address is a multicast address and
586112250Scjc	 * the outgoing interface for the address is specified
587112250Scjc	 * by the caller, use an address associated with the interface.
588145266Sphk	 * There is a sanity check here; if the destination has node-local
589145246Sbrooks	 * scope, the outgoing interfacde should be a loopback address.
590145246Sbrooks	 * Even if the outgoing interface is not specified, we also
591145246Sbrooks	 * choose a loopback interface as the outgoing interface.
592145246Sbrooks	 */
593145246Sbrooks	if (IN6_IS_ADDR_MULTICAST(dst)) {
594145246Sbrooks		struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
595147415Smlaier
596145246Sbrooks		if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
597112250Scjc			ifp = &loif[0];
598145246Sbrooks		}
599145246Sbrooks
600145246Sbrooks		if (ifp) {
601147415Smlaier			ia6 = in6_ifawithscope(ifp, dst);
602147415Smlaier			if (ia6 == 0) {
603147415Smlaier				*errorp = EADDRNOTAVAIL;
604147415Smlaier				return(0);
605147415Smlaier			}
606145246Sbrooks			return(&ia6->ia_addr.sin6_addr);
607145246Sbrooks		}
608145246Sbrooks	}
609145246Sbrooks
610145246Sbrooks	/*
611145246Sbrooks	 * If the next hop address for the packet is specified
612147415Smlaier	 * by caller, use an address associated with the route
613147415Smlaier	 * to the next hop.
614147415Smlaier	 */
615147415Smlaier	{
616145246Sbrooks		struct sockaddr_in6 *sin6_next;
617191288Srwatson		struct rtentry *rt;
618195023Srwatson
619191338Srwatson		if (opts && opts->ip6po_nexthop) {
620147415Smlaier			sin6_next = satosin6(opts->ip6po_nexthop);
621147415Smlaier			rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
622147415Smlaier			if (rt) {
623147415Smlaier				ia6 = in6_ifawithscope(rt->rt_ifp, dst);
624147415Smlaier				if (ia6 == 0)
625191288Srwatson					ia6 = ifatoia6(rt->rt_ifa);
626195023Srwatson			}
627147415Smlaier			if (ia6 == 0) {
628191288Srwatson				*errorp = EADDRNOTAVAIL;
629147415Smlaier				return(0);
630147415Smlaier			}
631195023Srwatson			return(&satosin6(&ia6->ia_addr)->sin6_addr);
632191288Srwatson		}
633147415Smlaier	}
634145246Sbrooks
635145246Sbrooks	/*
636145246Sbrooks	 * If route is known or can be allocated now,
637147418Smlaier	 * our src addr is taken from the i/f, else punt.
638145246Sbrooks	 */
639147418Smlaier	if (ro) {
640147415Smlaier		if (ro->ro_rt &&
641145246Sbrooks		    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
642147418Smlaier			RTFREE(ro->ro_rt);
643147418Smlaier			ro->ro_rt = (struct rtentry *)0;
644147415Smlaier		}
645147418Smlaier		if (ro->ro_rt == (struct rtentry *)0 ||
646147418Smlaier		    ro->ro_rt->rt_ifp == (struct ifnet *)0) {
647147418Smlaier			/* No route yet, so try to acquire one */
648178888Sjulian			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
649186119Sqingli			ro->ro_dst.sin6_family = AF_INET6;
650145246Sbrooks			ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
651147418Smlaier			ro->ro_dst.sin6_addr = *dst;
652147418Smlaier			if (IN6_IS_ADDR_MULTICAST(dst)) {
653147418Smlaier				ro->ro_rt = rtalloc1(&((struct route *)ro)
654152288Ssuz						     ->ro_dst, 0, 0UL);
655152288Ssuz			} else {
656152288Ssuz				rtalloc((struct route *)ro);
657152288Ssuz			}
658152288Ssuz		}
659152288Ssuz
660152288Ssuz		/*
661152288Ssuz		 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
662147418Smlaier		 * the address. But we don't know why it does so.
663147418Smlaier		 * It is necessary to ensure the scope even for lo0
664147415Smlaier		 * so doesn't check out IFF_LOOPBACK.
665147418Smlaier		 */
666147418Smlaier
667147418Smlaier		if (ro->ro_rt) {
668147418Smlaier			ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
669147418Smlaier			if (ia6 == 0) /* xxx scope error ?*/
670147415Smlaier				ia6 = ifatoia6(ro->ro_rt->rt_ifa);
671147418Smlaier		}
672147418Smlaier		if (ia6 == 0) {
673147418Smlaier			*errorp = EHOSTUNREACH;	/* no route */
674147418Smlaier			return(0);
675147418Smlaier		}
676147418Smlaier		return(&satosin6(&ia6->ia_addr)->sin6_addr);
677147418Smlaier	}
678147418Smlaier
679147418Smlaier	*errorp = EADDRNOTAVAIL;
680147418Smlaier	return(0);
681147415Smlaier}
682147418Smlaier
683145246Sbrooks/*
684145246Sbrooks * Default hop limit selection. The precedence is as follows:
685145246Sbrooks * 1. Hoplimit valued specified via ioctl.
686145246Sbrooks * 2. (If the outgoing interface is detected) the current
687147415Smlaier *     hop limit of the interface specified by router advertisement.
688158580Smlaier * 3. The system default hoplimit.
689147415Smlaier*/
690158580Smlaierint
691158580Smlaierin6_selecthlim(in6p, ifp)
692158580Smlaier	struct in6pcb *in6p;
693147415Smlaier	struct ifnet *ifp;
694145246Sbrooks{
695145246Sbrooks	if (in6p && in6p->in6p_hops >= 0)
696149020Sbz		return(in6p->in6p_hops);
697149020Sbz	else if (ifp)
698149020Sbz		return(nd_ifinfo[ifp->if_index].chlim);
699149020Sbz	else
700149020Sbz		return(ip6_defhlim);
701149020Sbz}
702149020Sbz
703149020Sbzvoid
704149020Sbzin6_pcbdisconnect(inp)
705149020Sbz	struct inpcb *inp;
706149020Sbz{
707149020Sbz	bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
708149020Sbz	inp->inp_fport = 0;
709149020Sbz	in_pcbrehash(inp);
710149020Sbz	if (inp->inp_socket->so_state & SS_NOFDREF)
711165738Sjulian		in6_pcbdetach(inp);
712149020Sbz}
713165738Sjulian
714165738Sjulianvoid
715165738Sjulianin6_pcbdetach(inp)
716160025Sbz	struct inpcb *inp;
717149020Sbz{
718165738Sjulian	struct socket *so = inp->inp_socket;
719149020Sbz	struct inpcbinfo *ipi = inp->inp_pcbinfo;
720200027Sume
721200027Sume#ifdef IPSEC
722200027Sume	if (sotoinpcb(so) != 0)
723200027Sume		key_freeso(so);
724200027Sume	ipsec6_delete_pcbpolicy(inp);
725200027Sume#endif /* IPSEC */
726200027Sume	inp->inp_gencnt = ++ipi->ipi_gencnt;
727200027Sume	in_pcbremlists(inp);
728149020Sbz	sotoinpcb(so) = 0;
729200027Sume	sofree(so);
730149020Sbz	if (inp->in6p_options)
731165738Sjulian		m_freem(inp->in6p_options);
732165738Sjulian	if (inp->in6p_outputopts) {
733165738Sjulian		if (inp->in6p_outputopts->ip6po_rthdr &&
734165738Sjulian		    inp->in6p_outputopts->ip6po_route.ro_rt)
735165738Sjulian			RTFREE(inp->in6p_outputopts->ip6po_route.ro_rt);
736165738Sjulian		if (inp->in6p_outputopts->ip6po_m)
737165738Sjulian			(void)m_free(inp->in6p_outputopts->ip6po_m);
738165738Sjulian		free(inp->in6p_outputopts, M_IP6OPT);
739165738Sjulian	}
740165738Sjulian	if (inp->in6p_route.ro_rt)
741165738Sjulian		rtfree(inp->in6p_route.ro_rt);
742165738Sjulian	ip6_freemoptions(inp->in6p_moptions);
743165738Sjulian
744149020Sbz	/* Check and free IPv4 related resources in case of mapped addr */
745165738Sjulian	if (inp->inp_options)
746149020Sbz		(void)m_free(inp->inp_options);
747149020Sbz	ip_freemoptions(inp->inp_moptions);
748149020Sbz
749149020Sbz	inp->inp_vflag = 0;
750145266Sphk	zfreei(ipi->ipi_zone, inp);
751145266Sphk}
752195699Srwatson
753195699Srwatson/*
754195727Srwatson * The calling convention of in6_setsockaddr() and in6_setpeeraddr() was
75598943Sluigi * modified to match the pru_sockaddr() and pru_peeraddr() entry points
75698943Sluigi * in struct pr_usrreqs, so that protocols can just reference then directly
75799622Sluigi * without the need for a wrapper function.  The socket must have a valid
758100004Sluigi * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
75998943Sluigi * except through a kernel programming error, so it is acceptable to panic
76098943Sluigi * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
76199622Sluigi * because there actually /is/ a programming error somewhere... XXX)
76298943Sluigi */
76398943Sluigiint
764149020Sbzin6_setsockaddr(so, nam)
765169454Srwatson	struct socket *so;
766169454Srwatson	struct sockaddr **nam;
76798943Sluigi{
768149020Sbz	int s;
76998943Sluigi	register struct inpcb *inp;
77098943Sluigi	register struct sockaddr_in6 *sin6;
771149020Sbz
77298943Sluigi	/*
77398943Sluigi	 * Do the malloc first in case it blocks.
77498943Sluigi	 */
77598943Sluigi	MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
77698943Sluigi	bzero(sin6, sizeof *sin6);
777181803Sbz	sin6->sin6_family = AF_INET6;
77898943Sluigi	sin6->sin6_len = sizeof(*sin6);
779181803Sbz
780181803Sbz	s = splnet();
781181803Sbz	inp = sotoinpcb(so);
78298943Sluigi	if (!inp) {
78398943Sluigi		splx(s);
78498943Sluigi		free(sin6, M_SONAME);
78598943Sluigi		return EINVAL;
78698943Sluigi	}
78798943Sluigi	sin6->sin6_port = inp->inp_lport;
78898943Sluigi	sin6->sin6_addr = inp->in6p_laddr;
78998943Sluigi	splx(s);
79098943Sluigi	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
79198943Sluigi		sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
79298943Sluigi	else
793136071Sgreen		sin6->sin6_scope_id = 0;	/*XXX*/
794136071Sgreen	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
795136071Sgreen		sin6->sin6_addr.s6_addr16[1] = 0;
796136071Sgreen
797136071Sgreen	*nam = (struct sockaddr *)sin6;
798136071Sgreen	return 0;
799136071Sgreen}
80098943Sluigi
80198943Sluigiint
80298943Sluigiin6_setpeeraddr(so, nam)
803158879Soleg	struct socket *so;
804158879Soleg	struct sockaddr **nam;
805158879Soleg{
80698943Sluigi	int s;
80798943Sluigi	struct inpcb *inp;
80898943Sluigi	register struct sockaddr_in6 *sin6;
80998943Sluigi
81098943Sluigi	/*
81199475Sluigi	 * Do the malloc first in case it blocks.
81298943Sluigi	 */
81399475Sluigi	MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK);
81499475Sluigi	bzero((caddr_t)sin6, sizeof (*sin6));
81599475Sluigi	sin6->sin6_family = AF_INET6;
81699475Sluigi	sin6->sin6_len = sizeof(struct sockaddr_in6);
81799475Sluigi
81899475Sluigi	s = splnet();
81999475Sluigi	inp = sotoinpcb(so);
82098943Sluigi	if (!inp) {
82199475Sluigi		splx(s);
822149020Sbz		free(sin6, M_SONAME);
823149020Sbz		return EINVAL;
824149020Sbz	}
825149020Sbz	sin6->sin6_port = inp->inp_fport;
826149020Sbz	sin6->sin6_addr = inp->in6p_faddr;
827149020Sbz	splx(s);
828149020Sbz	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
829149020Sbz		sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
83098943Sluigi	else
83198943Sluigi		sin6->sin6_scope_id = 0;	/*XXX*/
83298943Sluigi	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
83398943Sluigi		sin6->sin6_addr.s6_addr16[1] = 0;
83498943Sluigi
83598943Sluigi	*nam = (struct sockaddr *)sin6;
83698943Sluigi	return 0;
83798943Sluigi}
83898943Sluigi
83998943Sluigiint
84098943Sluigiin6_mapped_sockaddr(struct socket *so, struct sockaddr **nam)
84198943Sluigi{
84298943Sluigi	struct	inpcb *inp = sotoinpcb(so);
84398943Sluigi	int	error;
844178888Sjulian
845178888Sjulian	if (inp == NULL)
846178888Sjulian		return EINVAL;
847178888Sjulian	if (inp->inp_vflag & INP_IPV4) {
84898943Sluigi		error = in_setsockaddr(so, nam);
84998943Sluigi		if (error == 0)
85098943Sluigi			in6_sin_2_v4mapsin6_in_sock(nam);
85198943Sluigi	} else
85298943Sluigi	error = in6_setsockaddr(so, nam);
85398943Sluigi
85498943Sluigi	return error;
85598943Sluigi}
85698943Sluigi
85798943Sluigiint
85898943Sluigiin6_mapped_peeraddr(struct socket *so, struct sockaddr **nam)
85998943Sluigi{
86098943Sluigi	struct	inpcb *inp = sotoinpcb(so);
86198943Sluigi	int	error;
862100004Sluigi
863161424Sjulian	if (inp == NULL)
864161424Sjulian		return EINVAL;
865161424Sjulian	if (inp->inp_vflag & INP_IPV4) {
866161424Sjulian		error = in_setpeeraddr(so, nam);
867161424Sjulian		if (error == 0)
86898943Sluigi			in6_sin_2_v4mapsin6_in_sock(nam);
869100004Sluigi	} else
870161424Sjulian	error = in6_setpeeraddr(so, nam);
871161424Sjulian
87298943Sluigi	return error;
873100004Sluigi}
874107897Smaxim
87598943Sluigi/*
87698943Sluigi * Pass some notification to all connections of a protocol
877141351Sglebius * associated with address dst.  The local address and/or port numbers
878141351Sglebius * may be specified to limit the search.  The "usual action" will be
879141351Sglebius * taken, depending on the ctlinput cmd.  The caller must filter any
880141351Sglebius * cmds that are uninteresting (e.g., no error in the map).
881141351Sglebius * Call the protocol specific routine (if any) to report
882141351Sglebius * any errors for each matching socket.
883141351Sglebius *
884141351Sglebius * Must be called at splnet.
885165648Spiso */
886165648Spisovoid
887165648Spisoin6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
888190633Spiso	struct inpcbhead *head;
889190633Spiso	struct sockaddr *dst;
890190633Spiso	u_int fport_arg, lport_arg;
891105775Smaxim	struct in6_addr *laddr6;
89298943Sluigi	int cmd;
89398943Sluigi	void (*notify) __P((struct inpcb *, int));
89498943Sluigi{
89598943Sluigi	struct inpcb *inp, *oinp;
89698943Sluigi	struct in6_addr faddr6;
89798943Sluigi	u_short	fport = fport_arg, lport = lport_arg;
89898943Sluigi	int errno, s;
899149020Sbz
90098943Sluigi	if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
901149020Sbz		return;
902200102Sume	faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
903200102Sume	if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
904200102Sume		return;
905200102Sume
906200102Sume	/*
907149020Sbz	 * Redirects go to all references to the destination,
908149020Sbz	 * and use in_rtchange to invalidate the route cache.
909149020Sbz	 * Dead host indications: notify all references to the destination.
910149020Sbz	 * Otherwise, if we have knowledge of the local port and address,
911149020Sbz	 * deliver only to that socket.
912149020Sbz	 */
913149020Sbz	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
914149020Sbz		fport = 0;
915149020Sbz		lport = 0;
916149020Sbz		bzero((caddr_t)laddr6, sizeof(*laddr6));
917163237Smaxim		if (cmd != PRC_HOSTDEAD)
918165118Sbz			notify = in6_rtchange;
919149020Sbz	}
920165118Sbz	errno = inet6ctlerrmap[cmd];
921149020Sbz	s = splnet();
922165118Sbz	for (inp = LIST_FIRST(head); inp != NULL;) {
92398943Sluigi		if ((inp->inp_vflag & INP_IPV6) == 0) {
924165738Sjulian			inp = LIST_NEXT(inp, inp_list);
925165738Sjulian			continue;
926165738Sjulian		}
927149020Sbz		if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &faddr6) ||
928149020Sbz		   inp->inp_socket == 0 ||
929149020Sbz		   (lport && inp->inp_lport != lport) ||
930149020Sbz		   (!IN6_IS_ADDR_UNSPECIFIED(laddr6) &&
931149020Sbz		    !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr6)) ||
93298943Sluigi		   (fport && inp->inp_fport != fport)) {
933149020Sbz			inp = LIST_NEXT(inp, inp_list);
934149020Sbz			continue;
935149020Sbz		}
93698943Sluigi		oinp = inp;
937149020Sbz		inp = LIST_NEXT(inp, inp_list);
93898943Sluigi		if (notify)
939149020Sbz			(*notify)(oinp, errno);
94098943Sluigi	}
941100004Sluigi	splx(s);
942100004Sluigi}
943149020Sbz
944100004Sluigi/*
94598943Sluigi * Lookup a PCB based on the local address and port.
946149020Sbz */
94798943Sluigistruct inpcb *
94898943Sluigiin6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
94998943Sluigi	struct inpcbinfo *pcbinfo;
950149020Sbz	struct in6_addr *laddr;
95198943Sluigi	u_int lport_arg;
952100004Sluigi	int wild_okay;
953100004Sluigi{
954149020Sbz	register struct inpcb *inp;
955100004Sluigi	int matchwild = 3, wildcard;
95698943Sluigi	u_short lport = lport_arg;
957149020Sbz
95898943Sluigi	if (!wild_okay) {
95998943Sluigi		struct inpcbhead *head;
96098943Sluigi		/*
961149020Sbz		 * Look for an unconnected (wildcard foreign addr) PCB that
96298943Sluigi		 * matches the local address and port we're looking for.
96398943Sluigi		 */
96498943Sluigi		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,
96598943Sluigi						      pcbinfo->hashmask)];
96698943Sluigi		LIST_FOREACH(inp, head, inp_hash) {
96798943Sluigi			if ((inp->inp_vflag & INP_IPV6) == 0)
968149020Sbz				continue;
969149020Sbz			if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
97098943Sluigi			    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
971149020Sbz			    inp->inp_lport == lport) {
972149020Sbz				/*
973165738Sjulian				 * Found.
974149020Sbz				 */
975149020Sbz				return (inp);
976149020Sbz			}
977149020Sbz		}
978149020Sbz		/*
979149020Sbz		 * Not found.
980149020Sbz		 */
981149020Sbz		return (NULL);
982149020Sbz	} else {
983149020Sbz		struct inpcbporthead *porthash;
98498943Sluigi		struct inpcbport *phd;
985149020Sbz		struct inpcb *match = NULL;
986149020Sbz		/*
987149020Sbz		 * Best fit PCB lookup.
98898943Sluigi		 *
98998943Sluigi		 * First see if this local port is in use by looking on the
99098943Sluigi		 * port hash list.
991149020Sbz		 */
992163237Smaxim		porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
993149020Sbz		    pcbinfo->porthashmask)];
994149020Sbz		LIST_FOREACH(phd, porthash, phd_hash) {
995149020Sbz			if (phd->phd_port == lport)
996149020Sbz				break;
997149020Sbz		}
998149020Sbz		if (phd != NULL) {
999149020Sbz			/*
1000149020Sbz			 * Port is in use by one or more PCBs. Look for best
1001149020Sbz			 * fit.
1002149020Sbz			 */
1003149020Sbz			LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
1004149020Sbz				wildcard = 0;
1005149020Sbz				if ((inp->inp_vflag & INP_IPV6) == 0)
1006149020Sbz					continue;
1007149020Sbz				if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
1008149020Sbz					wildcard++;
1009149020Sbz				if (!IN6_IS_ADDR_UNSPECIFIED(
1010149020Sbz					&inp->in6p_laddr)) {
1011149020Sbz					if (IN6_IS_ADDR_UNSPECIFIED(laddr))
1012149020Sbz						wildcard++;
1013149020Sbz					else if (!IN6_ARE_ADDR_EQUAL(
1014149020Sbz						&inp->in6p_laddr, laddr))
1015149020Sbz						continue;
1016149020Sbz				} else {
1017149020Sbz					if (!IN6_IS_ADDR_UNSPECIFIED(laddr))
101898943Sluigi						wildcard++;
101998943Sluigi				}
102098943Sluigi				if (wildcard < matchwild) {
1021121816Sbrooks					match = inp;
102298943Sluigi					matchwild = wildcard;
102398943Sluigi					if (matchwild == 0) {
1024121816Sbrooks						break;
102598943Sluigi					}
102698943Sluigi				}
102798943Sluigi			}
102898943Sluigi		}
102998943Sluigi		return (match);
103098943Sluigi	}
103198943Sluigi}
103298943Sluigi
103398943Sluigi/*
103498943Sluigi * Check for alternatives when higher level complains
103598943Sluigi * about service problems.  For now, invalidate cached
103698943Sluigi * routing information.  If the route was created dynamically
103798943Sluigi * (by a redirect), time to try a default gateway again.
103898943Sluigi */
103999475Sluigivoid
104098943Sluigiin6_losing(in6p)
104198943Sluigi	struct inpcb *in6p;
104298943Sluigi{
104398943Sluigi	struct rtentry *rt;
104498943Sluigi	struct rt_addrinfo info;
104598943Sluigi
104698943Sluigi	if ((rt = in6p->in6p_route.ro_rt) != NULL) {
1047145266Sphk		in6p->in6p_route.ro_rt = 0;
1048145266Sphk		bzero((caddr_t)&info, sizeof(info));
1049145267Sphk		info.rti_info[RTAX_DST] =
1050145266Sphk			(struct sockaddr *)&in6p->in6p_route.ro_dst;
1051145266Sphk		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1052145266Sphk		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
1053181803Sbz		rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
105498943Sluigi		if (rt->rt_flags & RTF_DYNAMIC)
105598943Sluigi			(void)rtrequest(RTM_DELETE, rt_key(rt),
105698943Sluigi					rt->rt_gateway, rt_mask(rt), rt->rt_flags,
1057200055Sume					(struct rtentry **)0);
1058200055Sume		else
1059200055Sume		/*
1060200055Sume		 * A new route can be allocated
1061200102Sume		 * the next time output is attempted.
1062200102Sume		 */
1063200102Sume			rtfree(rt);
1064200102Sume	}
1065200102Sume}
1066200055Sume
1067200055Sume/*
1068200055Sume * After a routing change, flush old routing
1069200055Sume * and allocate a (hopefully) better one.
1070200055Sume */
1071200055Sumevoid
1072200055Sumein6_rtchange(inp, errno)
1073200055Sume	struct inpcb *inp;
1074200055Sume	int errno;
1075200055Sume{
1076200055Sume	if (inp->in6p_route.ro_rt) {
1077200055Sume		rtfree(inp->in6p_route.ro_rt);
1078200055Sume		inp->in6p_route.ro_rt = 0;
1079200055Sume		/*
1080200055Sume		 * A new route can be allocated the next time
1081200055Sume		 * output is attempted.
1082200055Sume		 */
108398943Sluigi	}
108498943Sluigi}
108598943Sluigi
108698943Sluigi/*
108798943Sluigi * Lookup PCB in hash list.
108898943Sluigi */
108998943Sluigistruct inpcb *
109098943Sluigiin6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
109198943Sluigi	struct inpcbinfo *pcbinfo;
109298943Sluigi	struct in6_addr *faddr, *laddr;
109398943Sluigi	u_int fport_arg, lport_arg;
109498943Sluigi	int wildcard;
1095200055Sume	struct ifnet *ifp;
109698943Sluigi{
109798943Sluigi	struct inpcbhead *head;
109898943Sluigi	register struct inpcb *inp;
109998943Sluigi	u_short fport = fport_arg, lport = lport_arg;
1100181803Sbz
1101141076Scsjp	/*
110298943Sluigi	 * First look for an exact match.
110398943Sluigi	 */
110498943Sluigi	head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */,
110598943Sluigi					      lport, fport,
110698943Sluigi					      pcbinfo->hashmask)];
110798943Sluigi	LIST_FOREACH(inp, head, inp_hash) {
110898943Sluigi		if ((inp->inp_vflag & INP_IPV6) == 0)
110998943Sluigi			continue;
111098943Sluigi		if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
111198943Sluigi		    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
111298943Sluigi		    inp->inp_fport == fport &&
111398943Sluigi		    inp->inp_lport == lport) {
111498943Sluigi			/*
111598943Sluigi			 * Found.
111698943Sluigi			 */
111798943Sluigi			return (inp);
111898943Sluigi		}
111998943Sluigi	}
112098943Sluigi	if (wildcard) {
112198943Sluigi		struct inpcb *local_wild = NULL;
112298943Sluigi
112398943Sluigi		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,
112498943Sluigi						      pcbinfo->hashmask)];
112598943Sluigi		LIST_FOREACH(inp, head, inp_hash) {
112698943Sluigi			if ((inp->inp_vflag & INP_IPV6) == 0)
1127120141Ssam				continue;
1128120141Ssam			if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
1129181803Sbz			    inp->inp_lport == lport) {
113098943Sluigi#if defined(NFAITH) && NFAITH > 0
113198943Sluigi				if (ifp && ifp->if_type == IFT_FAITH &&
1132150350Sandre				    (inp->inp_flags & INP_FAITH) == 0)
113398943Sluigi					continue;
1134150350Sandre#endif
113598943Sluigi				if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
113698943Sluigi						       laddr))
113798943Sluigi					return (inp);
113898943Sluigi				else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
113998943Sluigi					local_wild = inp;
114098943Sluigi			}
114198943Sluigi		}
1142181803Sbz		return (local_wild);
1143181803Sbz	}
114498943Sluigi
114598943Sluigi	/*
114698943Sluigi	 * Not found.
114798943Sluigi	 */
114898943Sluigi	return (NULL);
114998943Sluigi}
115098943Sluigi
115198943Sluigivoid
115298943Sluigiinit_sin6(struct sockaddr_in6 *sin6, struct mbuf *m)
115398943Sluigi{
115498943Sluigi	struct ip6_hdr *ip;
115598943Sluigi
115698943Sluigi	ip = mtod(m, struct ip6_hdr *);
115798943Sluigi	bzero(sin6, sizeof(*sin6));
115898943Sluigi	sin6->sin6_len = sizeof(*sin6);
115998943Sluigi	sin6->sin6_family = AF_INET6;
116098943Sluigi	sin6->sin6_addr = ip->ip6_src;
1161108258Smaxim	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
116298943Sluigi		sin6->sin6_addr.s6_addr16[1] = 0;
116398943Sluigi	sin6->sin6_scope_id =
116498943Sluigi		(m->m_pkthdr.rcvif && IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
116598943Sluigi		? m->m_pkthdr.rcvif->if_index : 0;
1166150350Sandre
116798943Sluigi	return;
116898943Sluigi}
1169121123Smckusick