xref: /freebsd/sys/netinet/in_pcb.c (revision 33841545909f4a4ee94aa148b3a9cbcdc1abb02a)
1df8bae1dSRodney W. Grimes /*
22469dd60SGarrett Wollman  * Copyright (c) 1982, 1986, 1991, 1993, 1995
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
332469dd60SGarrett Wollman  *	@(#)in_pcb.c	8.4 (Berkeley) 5/24/95
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
376a800098SYoshinobu Inoue #include "opt_ipsec.h"
38cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
39cfa1ca9dSYoshinobu Inoue 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
42df8bae1dSRodney W. Grimes #include <sys/malloc.h>
43df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
44cfa1ca9dSYoshinobu Inoue #include <sys/domain.h>
45df8bae1dSRodney W. Grimes #include <sys/protosw.h>
46df8bae1dSRodney W. Grimes #include <sys/socket.h>
47df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
48df8bae1dSRodney W. Grimes #include <sys/proc.h>
4975c13541SPoul-Henning Kamp #include <sys/jail.h>
50101f9fc8SPeter Wemm #include <sys/kernel.h>
51101f9fc8SPeter Wemm #include <sys/sysctl.h>
528781d8e9SBruce Evans 
5308637435SBruce Evans #include <machine/limits.h>
5408637435SBruce Evans 
558781d8e9SBruce Evans #include <vm/vm_zone.h>
56df8bae1dSRodney W. Grimes 
57df8bae1dSRodney W. Grimes #include <net/if.h>
58cfa1ca9dSYoshinobu Inoue #include <net/if_types.h>
59df8bae1dSRodney W. Grimes #include <net/route.h>
60df8bae1dSRodney W. Grimes 
61df8bae1dSRodney W. Grimes #include <netinet/in.h>
62df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
63df8bae1dSRodney W. Grimes #include <netinet/in_var.h>
64df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
65cfa1ca9dSYoshinobu Inoue #ifdef INET6
66cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h>
67cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h>
68cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
69cfa1ca9dSYoshinobu Inoue 
70cfa1ca9dSYoshinobu Inoue #include "faith.h"
71cfa1ca9dSYoshinobu Inoue 
72cfa1ca9dSYoshinobu Inoue #ifdef IPSEC
73cfa1ca9dSYoshinobu Inoue #include <netinet6/ipsec.h>
74cfa1ca9dSYoshinobu Inoue #include <netkey/key.h>
75cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes struct	in_addr zeroin_addr;
78df8bae1dSRodney W. Grimes 
79101f9fc8SPeter Wemm /*
80101f9fc8SPeter Wemm  * These configure the range of local port addresses assigned to
81101f9fc8SPeter Wemm  * "unspecified" outgoing connections/packets/whatever.
82101f9fc8SPeter Wemm  */
8382cd038dSYoshinobu Inoue int	ipport_lowfirstauto  = IPPORT_RESERVED - 1;	/* 1023 */
8482cd038dSYoshinobu Inoue int	ipport_lowlastauto = IPPORT_RESERVEDSTART;	/* 600 */
8582cd038dSYoshinobu Inoue int	ipport_firstauto = IPPORT_RESERVED;		/* 1024 */
8682cd038dSYoshinobu Inoue int	ipport_lastauto  = IPPORT_USERRESERVED;		/* 5000 */
8782cd038dSYoshinobu Inoue int	ipport_hifirstauto = IPPORT_HIFIRSTAUTO;	/* 49152 */
8882cd038dSYoshinobu Inoue int	ipport_hilastauto  = IPPORT_HILASTAUTO;		/* 65535 */
89101f9fc8SPeter Wemm 
90bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \
91bbd42ad0SPeter Wemm 	if ((var) < (min)) { (var) = (min); } \
92bbd42ad0SPeter Wemm 	else if ((var) > (max)) { (var) = (max); }
93bbd42ad0SPeter Wemm 
94bbd42ad0SPeter Wemm static int
9582d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS)
96bbd42ad0SPeter Wemm {
97bbd42ad0SPeter Wemm 	int error = sysctl_handle_int(oidp,
98bbd42ad0SPeter Wemm 		oidp->oid_arg1, oidp->oid_arg2, req);
99bbd42ad0SPeter Wemm 	if (!error) {
100bbd42ad0SPeter Wemm 		RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
101bbd42ad0SPeter Wemm 		RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
102bbd42ad0SPeter Wemm 		RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
103bbd42ad0SPeter Wemm 		RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
104bbd42ad0SPeter Wemm 		RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
105bbd42ad0SPeter Wemm 		RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
106bbd42ad0SPeter Wemm 	}
107bbd42ad0SPeter Wemm 	return error;
108bbd42ad0SPeter Wemm }
109bbd42ad0SPeter Wemm 
110bbd42ad0SPeter Wemm #undef RANGECHK
111bbd42ad0SPeter Wemm 
11233b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
11333b3ac06SPeter Wemm 
114bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
115bbd42ad0SPeter Wemm 	   &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
116bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
117bbd42ad0SPeter Wemm 	   &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
118bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
119bbd42ad0SPeter Wemm 	   &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
120bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
121bbd42ad0SPeter Wemm 	   &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
122bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
123bbd42ad0SPeter Wemm 	   &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
124bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
125bbd42ad0SPeter Wemm 	   &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
1260312fbe9SPoul-Henning Kamp 
127c3229e05SDavid Greenman /*
128c3229e05SDavid Greenman  * in_pcb.c: manage the Protocol Control Blocks.
129c3229e05SDavid Greenman  *
130c3229e05SDavid Greenman  * NOTE: It is assumed that most of these functions will be called at
131c3229e05SDavid Greenman  * splnet(). XXX - There are, unfortunately, a few exceptions to this
132c3229e05SDavid Greenman  * rule that should be fixed.
133c3229e05SDavid Greenman  */
134c3229e05SDavid Greenman 
135c3229e05SDavid Greenman /*
136c3229e05SDavid Greenman  * Allocate a PCB and associate it with the socket.
137c3229e05SDavid Greenman  */
138df8bae1dSRodney W. Grimes int
139a29f300eSGarrett Wollman in_pcballoc(so, pcbinfo, p)
140df8bae1dSRodney W. Grimes 	struct socket *so;
14115bd2b43SDavid Greenman 	struct inpcbinfo *pcbinfo;
142a29f300eSGarrett Wollman 	struct proc *p;
143df8bae1dSRodney W. Grimes {
144df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
145df8bae1dSRodney W. Grimes 
146a3ea6d41SDag-Erling Smørgrav 	inp = zalloc(pcbinfo->ipi_zone);
147df8bae1dSRodney W. Grimes 	if (inp == NULL)
148df8bae1dSRodney W. Grimes 		return (ENOBUFS);
149df8bae1dSRodney W. Grimes 	bzero((caddr_t)inp, sizeof(*inp));
1503d4d47f3SGarrett Wollman 	inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
15115bd2b43SDavid Greenman 	inp->inp_pcbinfo = pcbinfo;
152df8bae1dSRodney W. Grimes 	inp->inp_socket = so;
15375daea93SPaul Saab #if defined(INET6)
15433841545SHajimu UMEMOTO 	if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on)
15533841545SHajimu UMEMOTO 		inp->inp_flags |= IN6P_IPV6_V6ONLY;
15675daea93SPaul Saab #endif
15715bd2b43SDavid Greenman 	LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
1583d4d47f3SGarrett Wollman 	pcbinfo->ipi_count++;
159df8bae1dSRodney W. Grimes 	so->so_pcb = (caddr_t)inp;
16033841545SHajimu UMEMOTO #ifdef INET6
16133841545SHajimu UMEMOTO 	if (ip6_auto_flowlabel)
16233841545SHajimu UMEMOTO 		inp->inp_flags |= IN6P_AUTOFLOWLABEL;
16333841545SHajimu UMEMOTO #endif
164df8bae1dSRodney W. Grimes 	return (0);
165df8bae1dSRodney W. Grimes }
166df8bae1dSRodney W. Grimes 
167df8bae1dSRodney W. Grimes int
168a29f300eSGarrett Wollman in_pcbbind(inp, nam, p)
169df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
17057bf258eSGarrett Wollman 	struct sockaddr *nam;
171a29f300eSGarrett Wollman 	struct proc *p;
172df8bae1dSRodney W. Grimes {
173df8bae1dSRodney W. Grimes 	register struct socket *so = inp->inp_socket;
17437bd2b30SPeter Wemm 	unsigned short *lastport;
17515bd2b43SDavid Greenman 	struct sockaddr_in *sin;
176c3229e05SDavid Greenman 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
177df8bae1dSRodney W. Grimes 	u_short lport = 0;
178df8bae1dSRodney W. Grimes 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
17975c13541SPoul-Henning Kamp 	int error, prison = 0;
180df8bae1dSRodney W. Grimes 
18159562606SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
182df8bae1dSRodney W. Grimes 		return (EADDRNOTAVAIL);
183df8bae1dSRodney W. Grimes 	if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
184df8bae1dSRodney W. Grimes 		return (EINVAL);
185c3229e05SDavid Greenman 	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
1866d6a026bSDavid Greenman 		wild = 1;
187df8bae1dSRodney W. Grimes 	if (nam) {
18857bf258eSGarrett Wollman 		sin = (struct sockaddr_in *)nam;
18957bf258eSGarrett Wollman 		if (nam->sa_len != sizeof (*sin))
190df8bae1dSRodney W. Grimes 			return (EINVAL);
191df8bae1dSRodney W. Grimes #ifdef notdef
192df8bae1dSRodney W. Grimes 		/*
193df8bae1dSRodney W. Grimes 		 * We should check the family, but old programs
194df8bae1dSRodney W. Grimes 		 * incorrectly fail to initialize it.
195df8bae1dSRodney W. Grimes 		 */
196df8bae1dSRodney W. Grimes 		if (sin->sin_family != AF_INET)
197df8bae1dSRodney W. Grimes 			return (EAFNOSUPPORT);
198df8bae1dSRodney W. Grimes #endif
199e4bdf25dSPoul-Henning Kamp 		if (sin->sin_addr.s_addr != INADDR_ANY)
20091421ba2SRobert Watson 			if (prison_ip(p->p_ucred, 0, &sin->sin_addr.s_addr))
20175c13541SPoul-Henning Kamp 				return(EINVAL);
202df8bae1dSRodney W. Grimes 		lport = sin->sin_port;
203df8bae1dSRodney W. Grimes 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
204df8bae1dSRodney W. Grimes 			/*
205df8bae1dSRodney W. Grimes 			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
206df8bae1dSRodney W. Grimes 			 * allow complete duplication of binding if
207df8bae1dSRodney W. Grimes 			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
208df8bae1dSRodney W. Grimes 			 * and a multicast address is bound on both
209df8bae1dSRodney W. Grimes 			 * new and duplicated sockets.
210df8bae1dSRodney W. Grimes 			 */
211df8bae1dSRodney W. Grimes 			if (so->so_options & SO_REUSEADDR)
212df8bae1dSRodney W. Grimes 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
213df8bae1dSRodney W. Grimes 		} else if (sin->sin_addr.s_addr != INADDR_ANY) {
214df8bae1dSRodney W. Grimes 			sin->sin_port = 0;		/* yech... */
215df8bae1dSRodney W. Grimes 			if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
216df8bae1dSRodney W. Grimes 				return (EADDRNOTAVAIL);
217df8bae1dSRodney W. Grimes 		}
218df8bae1dSRodney W. Grimes 		if (lport) {
219df8bae1dSRodney W. Grimes 			struct inpcb *t;
220df8bae1dSRodney W. Grimes 			/* GROSS */
22157bf258eSGarrett Wollman 			if (ntohs(lport) < IPPORT_RESERVED && p &&
22275c13541SPoul-Henning Kamp 			    suser_xxx(0, p, PRISON_ROOT))
2232469dd60SGarrett Wollman 				return (EACCES);
22491421ba2SRobert Watson 			if (p && jailed(p->p_ucred))
22575c13541SPoul-Henning Kamp 				prison = 1;
2262f9a2132SBrian Feldman 			if (so->so_cred->cr_uid != 0 &&
22752b65dbeSBill Fenner 			    !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
2284049a042SGuido van Rooij 				t = in_pcblookup_local(inp->inp_pcbinfo,
22975c13541SPoul-Henning Kamp 				    sin->sin_addr, lport,
23075c13541SPoul-Henning Kamp 				    prison ? 0 :  INPLOOKUP_WILDCARD);
23152b65dbeSBill Fenner 				if (t &&
23252b65dbeSBill Fenner 				    (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
23352b65dbeSBill Fenner 				     ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
23452b65dbeSBill Fenner 				     (t->inp_socket->so_options &
23552b65dbeSBill Fenner 					 SO_REUSEPORT) == 0) &&
2362f9a2132SBrian Feldman 				    (so->so_cred->cr_uid !=
237cfa1ca9dSYoshinobu Inoue 				     t->inp_socket->so_cred->cr_uid)) {
238cfa1ca9dSYoshinobu Inoue #if defined(INET6)
23933841545SHajimu UMEMOTO 					if (ntohl(sin->sin_addr.s_addr) !=
240cfa1ca9dSYoshinobu Inoue 					    INADDR_ANY ||
241cfa1ca9dSYoshinobu Inoue 					    ntohl(t->inp_laddr.s_addr) !=
242cfa1ca9dSYoshinobu Inoue 					    INADDR_ANY ||
243cfa1ca9dSYoshinobu Inoue 					    INP_SOCKAF(so) ==
244cfa1ca9dSYoshinobu Inoue 					    INP_SOCKAF(t->inp_socket))
245cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
2464049a042SGuido van Rooij 					return (EADDRINUSE);
2474049a042SGuido van Rooij 				}
248cfa1ca9dSYoshinobu Inoue 			}
249970680faSPoul-Henning Kamp 			if (prison &&
250970680faSPoul-Henning Kamp 			    prison_ip(p->p_ucred, 0, &sin->sin_addr.s_addr))
251970680faSPoul-Henning Kamp 				return (EADDRNOTAVAIL);
252c3229e05SDavid Greenman 			t = in_pcblookup_local(pcbinfo, sin->sin_addr,
25375c13541SPoul-Henning Kamp 			    lport, prison ? 0 : wild);
254cfa1ca9dSYoshinobu Inoue 			if (t &&
255cfa1ca9dSYoshinobu Inoue 			    (reuseport & t->inp_socket->so_options) == 0) {
256cfa1ca9dSYoshinobu Inoue #if defined(INET6)
25733841545SHajimu UMEMOTO 				if (ntohl(sin->sin_addr.s_addr) !=
258cfa1ca9dSYoshinobu Inoue 				    INADDR_ANY ||
259cfa1ca9dSYoshinobu Inoue 				    ntohl(t->inp_laddr.s_addr) !=
260cfa1ca9dSYoshinobu Inoue 				    INADDR_ANY ||
261cfa1ca9dSYoshinobu Inoue 				    INP_SOCKAF(so) ==
262cfa1ca9dSYoshinobu Inoue 				    INP_SOCKAF(t->inp_socket))
263cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
264df8bae1dSRodney W. Grimes 				return (EADDRINUSE);
265df8bae1dSRodney W. Grimes 			}
266cfa1ca9dSYoshinobu Inoue 		}
267df8bae1dSRodney W. Grimes 		inp->inp_laddr = sin->sin_addr;
268df8bae1dSRodney W. Grimes 	}
26933b3ac06SPeter Wemm 	if (lport == 0) {
27033b3ac06SPeter Wemm 		ushort first, last;
27133b3ac06SPeter Wemm 		int count;
27233b3ac06SPeter Wemm 
273e4bdf25dSPoul-Henning Kamp 		if (inp->inp_laddr.s_addr != INADDR_ANY)
274503d3c02SPoul-Henning Kamp 			if (prison_ip(p->p_ucred, 0, &inp->inp_laddr.s_addr )) {
275503d3c02SPoul-Henning Kamp 				inp->inp_laddr.s_addr = INADDR_ANY;
27675c13541SPoul-Henning Kamp 				return (EINVAL);
277503d3c02SPoul-Henning Kamp 			}
278321a2846SPoul-Henning Kamp 		inp->inp_flags |= INP_ANONPORT;
279321a2846SPoul-Henning Kamp 
28033b3ac06SPeter Wemm 		if (inp->inp_flags & INP_HIGHPORT) {
28133b3ac06SPeter Wemm 			first = ipport_hifirstauto;	/* sysctl */
28233b3ac06SPeter Wemm 			last  = ipport_hilastauto;
283c3229e05SDavid Greenman 			lastport = &pcbinfo->lasthi;
28433b3ac06SPeter Wemm 		} else if (inp->inp_flags & INP_LOWPORT) {
285503d3c02SPoul-Henning Kamp 			if (p && (error = suser_xxx(0, p, PRISON_ROOT))) {
286503d3c02SPoul-Henning Kamp 				inp->inp_laddr.s_addr = INADDR_ANY;
287a29f300eSGarrett Wollman 				return error;
288503d3c02SPoul-Henning Kamp 			}
289bbd42ad0SPeter Wemm 			first = ipport_lowfirstauto;	/* 1023 */
290bbd42ad0SPeter Wemm 			last  = ipport_lowlastauto;	/* 600 */
291c3229e05SDavid Greenman 			lastport = &pcbinfo->lastlow;
29233b3ac06SPeter Wemm 		} else {
29333b3ac06SPeter Wemm 			first = ipport_firstauto;	/* sysctl */
29433b3ac06SPeter Wemm 			last  = ipport_lastauto;
295c3229e05SDavid Greenman 			lastport = &pcbinfo->lastport;
29633b3ac06SPeter Wemm 		}
29733b3ac06SPeter Wemm 		/*
29833b3ac06SPeter Wemm 		 * Simple check to ensure all ports are not used up causing
29933b3ac06SPeter Wemm 		 * a deadlock here.
30033b3ac06SPeter Wemm 		 *
30133b3ac06SPeter Wemm 		 * We split the two cases (up and down) so that the direction
30233b3ac06SPeter Wemm 		 * is not being tested on each round of the loop.
30333b3ac06SPeter Wemm 		 */
30433b3ac06SPeter Wemm 		if (first > last) {
30533b3ac06SPeter Wemm 			/*
30633b3ac06SPeter Wemm 			 * counting down
30733b3ac06SPeter Wemm 			 */
30833b3ac06SPeter Wemm 			count = first - last;
30933b3ac06SPeter Wemm 
310df8bae1dSRodney W. Grimes 			do {
311c3229e05SDavid Greenman 				if (count-- < 0) {	/* completely used? */
312c3229e05SDavid Greenman 					inp->inp_laddr.s_addr = INADDR_ANY;
313550b1518SWes Peters 					return (EADDRNOTAVAIL);
314c3229e05SDavid Greenman 				}
31533b3ac06SPeter Wemm 				--*lastport;
31633b3ac06SPeter Wemm 				if (*lastport > first || *lastport < last)
31733b3ac06SPeter Wemm 					*lastport = first;
31815bd2b43SDavid Greenman 				lport = htons(*lastport);
319c3229e05SDavid Greenman 			} while (in_pcblookup_local(pcbinfo,
320c3229e05SDavid Greenman 				 inp->inp_laddr, lport, wild));
32133b3ac06SPeter Wemm 		} else {
32233b3ac06SPeter Wemm 			/*
32333b3ac06SPeter Wemm 			 * counting up
32433b3ac06SPeter Wemm 			 */
32533b3ac06SPeter Wemm 			count = last - first;
32633b3ac06SPeter Wemm 
32733b3ac06SPeter Wemm 			do {
328c3229e05SDavid Greenman 				if (count-- < 0) {	/* completely used? */
329c3229e05SDavid Greenman 					/*
330c3229e05SDavid Greenman 					 * Undo any address bind that may have
331c3229e05SDavid Greenman 					 * occurred above.
332c3229e05SDavid Greenman 					 */
333c3229e05SDavid Greenman 					inp->inp_laddr.s_addr = INADDR_ANY;
334550b1518SWes Peters 					return (EADDRNOTAVAIL);
335c3229e05SDavid Greenman 				}
33633b3ac06SPeter Wemm 				++*lastport;
33733b3ac06SPeter Wemm 				if (*lastport < first || *lastport > last)
33833b3ac06SPeter Wemm 					*lastport = first;
33933b3ac06SPeter Wemm 				lport = htons(*lastport);
340c3229e05SDavid Greenman 			} while (in_pcblookup_local(pcbinfo,
341c3229e05SDavid Greenman 				 inp->inp_laddr, lport, wild));
34233b3ac06SPeter Wemm 		}
34333b3ac06SPeter Wemm 	}
344df8bae1dSRodney W. Grimes 	inp->inp_lport = lport;
345503d3c02SPoul-Henning Kamp 	if (prison_ip(p->p_ucred, 0, &inp->inp_laddr.s_addr)) {
346503d3c02SPoul-Henning Kamp 		inp->inp_laddr.s_addr = INADDR_ANY;
347503d3c02SPoul-Henning Kamp 		inp->inp_lport = 0;
348e4bdf25dSPoul-Henning Kamp 		return(EINVAL);
349503d3c02SPoul-Henning Kamp 	}
350c3229e05SDavid Greenman 	if (in_pcbinshash(inp) != 0) {
351c3229e05SDavid Greenman 		inp->inp_laddr.s_addr = INADDR_ANY;
352c3229e05SDavid Greenman 		inp->inp_lport = 0;
353c3229e05SDavid Greenman 		return (EAGAIN);
354c3229e05SDavid Greenman 	}
355df8bae1dSRodney W. Grimes 	return (0);
356df8bae1dSRodney W. Grimes }
357df8bae1dSRodney W. Grimes 
358999f1343SGarrett Wollman /*
359999f1343SGarrett Wollman  *   Transform old in_pcbconnect() into an inner subroutine for new
360999f1343SGarrett Wollman  *   in_pcbconnect(): Do some validity-checking on the remote
361999f1343SGarrett Wollman  *   address (in mbuf 'nam') and then determine local host address
362999f1343SGarrett Wollman  *   (i.e., which interface) to use to access that remote host.
363999f1343SGarrett Wollman  *
364999f1343SGarrett Wollman  *   This preserves definition of in_pcbconnect(), while supporting a
365999f1343SGarrett Wollman  *   slightly different version for T/TCP.  (This is more than
366999f1343SGarrett Wollman  *   a bit of a kludge, but cleaning up the internal interfaces would
367999f1343SGarrett Wollman  *   have forced minor changes in every protocol).
368999f1343SGarrett Wollman  */
369999f1343SGarrett Wollman 
370999f1343SGarrett Wollman int
371999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin)
372999f1343SGarrett Wollman 	register struct inpcb *inp;
37357bf258eSGarrett Wollman 	struct sockaddr *nam;
374999f1343SGarrett Wollman 	struct sockaddr_in **plocal_sin;
375999f1343SGarrett Wollman {
376df8bae1dSRodney W. Grimes 	struct in_ifaddr *ia;
37757bf258eSGarrett Wollman 	register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
378df8bae1dSRodney W. Grimes 
37957bf258eSGarrett Wollman 	if (nam->sa_len != sizeof (*sin))
380df8bae1dSRodney W. Grimes 		return (EINVAL);
381df8bae1dSRodney W. Grimes 	if (sin->sin_family != AF_INET)
382df8bae1dSRodney W. Grimes 		return (EAFNOSUPPORT);
383df8bae1dSRodney W. Grimes 	if (sin->sin_port == 0)
384df8bae1dSRodney W. Grimes 		return (EADDRNOTAVAIL);
38559562606SGarrett Wollman 	if (!TAILQ_EMPTY(&in_ifaddrhead)) {
386df8bae1dSRodney W. Grimes 		/*
387df8bae1dSRodney W. Grimes 		 * If the destination address is INADDR_ANY,
388df8bae1dSRodney W. Grimes 		 * use the primary local address.
389df8bae1dSRodney W. Grimes 		 * If the supplied address is INADDR_BROADCAST,
390df8bae1dSRodney W. Grimes 		 * and the primary interface supports broadcast,
391df8bae1dSRodney W. Grimes 		 * choose the broadcast address for that interface.
392df8bae1dSRodney W. Grimes 		 */
393df8bae1dSRodney W. Grimes #define	satosin(sa)	((struct sockaddr_in *)(sa))
394df8bae1dSRodney W. Grimes #define sintosa(sin)	((struct sockaddr *)(sin))
395df8bae1dSRodney W. Grimes #define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
396df8bae1dSRodney W. Grimes 		if (sin->sin_addr.s_addr == INADDR_ANY)
397fc2ffbe6SPoul-Henning Kamp 		    sin->sin_addr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
398df8bae1dSRodney W. Grimes 		else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
399fc2ffbe6SPoul-Henning Kamp 		  (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST))
400fc2ffbe6SPoul-Henning Kamp 		    sin->sin_addr = satosin(&TAILQ_FIRST(&in_ifaddrhead)->ia_broadaddr)->sin_addr;
401df8bae1dSRodney W. Grimes 	}
402df8bae1dSRodney W. Grimes 	if (inp->inp_laddr.s_addr == INADDR_ANY) {
403df8bae1dSRodney W. Grimes 		register struct route *ro;
404df8bae1dSRodney W. Grimes 
405df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)0;
406df8bae1dSRodney W. Grimes 		/*
407df8bae1dSRodney W. Grimes 		 * If route is known or can be allocated now,
408df8bae1dSRodney W. Grimes 		 * our src addr is taken from the i/f, else punt.
409df8bae1dSRodney W. Grimes 		 */
410df8bae1dSRodney W. Grimes 		ro = &inp->inp_route;
411df8bae1dSRodney W. Grimes 		if (ro->ro_rt &&
412df8bae1dSRodney W. Grimes 		    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
413df8bae1dSRodney W. Grimes 			sin->sin_addr.s_addr ||
414df8bae1dSRodney W. Grimes 		    inp->inp_socket->so_options & SO_DONTROUTE)) {
415df8bae1dSRodney W. Grimes 			RTFREE(ro->ro_rt);
416df8bae1dSRodney W. Grimes 			ro->ro_rt = (struct rtentry *)0;
417df8bae1dSRodney W. Grimes 		}
418df8bae1dSRodney W. Grimes 		if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
419df8bae1dSRodney W. Grimes 		    (ro->ro_rt == (struct rtentry *)0 ||
420df8bae1dSRodney W. Grimes 		    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
421df8bae1dSRodney W. Grimes 			/* No route yet, so try to acquire one */
422df8bae1dSRodney W. Grimes 			ro->ro_dst.sa_family = AF_INET;
423df8bae1dSRodney W. Grimes 			ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
424df8bae1dSRodney W. Grimes 			((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
425df8bae1dSRodney W. Grimes 				sin->sin_addr;
426df8bae1dSRodney W. Grimes 			rtalloc(ro);
427df8bae1dSRodney W. Grimes 		}
428df8bae1dSRodney W. Grimes 		/*
429df8bae1dSRodney W. Grimes 		 * If we found a route, use the address
430df8bae1dSRodney W. Grimes 		 * corresponding to the outgoing interface
431df8bae1dSRodney W. Grimes 		 * unless it is the loopback (in case a route
432df8bae1dSRodney W. Grimes 		 * to our address on another net goes to loopback).
433df8bae1dSRodney W. Grimes 		 */
434df8bae1dSRodney W. Grimes 		if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
435df8bae1dSRodney W. Grimes 			ia = ifatoia(ro->ro_rt->rt_ifa);
436df8bae1dSRodney W. Grimes 		if (ia == 0) {
437df8bae1dSRodney W. Grimes 			u_short fport = sin->sin_port;
438df8bae1dSRodney W. Grimes 
439df8bae1dSRodney W. Grimes 			sin->sin_port = 0;
440df8bae1dSRodney W. Grimes 			ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
441df8bae1dSRodney W. Grimes 			if (ia == 0)
442df8bae1dSRodney W. Grimes 				ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
443df8bae1dSRodney W. Grimes 			sin->sin_port = fport;
444df8bae1dSRodney W. Grimes 			if (ia == 0)
445fc2ffbe6SPoul-Henning Kamp 				ia = TAILQ_FIRST(&in_ifaddrhead);
446df8bae1dSRodney W. Grimes 			if (ia == 0)
447df8bae1dSRodney W. Grimes 				return (EADDRNOTAVAIL);
448df8bae1dSRodney W. Grimes 		}
449df8bae1dSRodney W. Grimes 		/*
450df8bae1dSRodney W. Grimes 		 * If the destination address is multicast and an outgoing
451df8bae1dSRodney W. Grimes 		 * interface has been set as a multicast option, use the
452df8bae1dSRodney W. Grimes 		 * address of that interface as our source address.
453df8bae1dSRodney W. Grimes 		 */
454df8bae1dSRodney W. Grimes 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
455df8bae1dSRodney W. Grimes 		    inp->inp_moptions != NULL) {
456df8bae1dSRodney W. Grimes 			struct ip_moptions *imo;
457df8bae1dSRodney W. Grimes 			struct ifnet *ifp;
458df8bae1dSRodney W. Grimes 
459df8bae1dSRodney W. Grimes 			imo = inp->inp_moptions;
460df8bae1dSRodney W. Grimes 			if (imo->imo_multicast_ifp != NULL) {
461df8bae1dSRodney W. Grimes 				ifp = imo->imo_multicast_ifp;
46237d40066SPoul-Henning Kamp 				TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
463df8bae1dSRodney W. Grimes 					if (ia->ia_ifp == ifp)
464df8bae1dSRodney W. Grimes 						break;
465df8bae1dSRodney W. Grimes 				if (ia == 0)
466df8bae1dSRodney W. Grimes 					return (EADDRNOTAVAIL);
467df8bae1dSRodney W. Grimes 			}
468df8bae1dSRodney W. Grimes 		}
469999f1343SGarrett Wollman 	/*
470999f1343SGarrett Wollman 	 * Don't do pcblookup call here; return interface in plocal_sin
471999f1343SGarrett Wollman 	 * and exit to caller, that will do the lookup.
472999f1343SGarrett Wollman 	 */
473999f1343SGarrett Wollman 		*plocal_sin = &ia->ia_addr;
474999f1343SGarrett Wollman 
475999f1343SGarrett Wollman 	}
476999f1343SGarrett Wollman 	return(0);
477999f1343SGarrett Wollman }
478999f1343SGarrett Wollman 
479999f1343SGarrett Wollman /*
480999f1343SGarrett Wollman  * Outer subroutine:
481999f1343SGarrett Wollman  * Connect from a socket to a specified address.
482999f1343SGarrett Wollman  * Both address and port must be specified in argument sin.
483999f1343SGarrett Wollman  * If don't have a local address for this socket yet,
484999f1343SGarrett Wollman  * then pick one.
485999f1343SGarrett Wollman  */
486999f1343SGarrett Wollman int
487a29f300eSGarrett Wollman in_pcbconnect(inp, nam, p)
488999f1343SGarrett Wollman 	register struct inpcb *inp;
48957bf258eSGarrett Wollman 	struct sockaddr *nam;
490a29f300eSGarrett Wollman 	struct proc *p;
491999f1343SGarrett Wollman {
492999f1343SGarrett Wollman 	struct sockaddr_in *ifaddr;
493e4bdf25dSPoul-Henning Kamp 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
494e4bdf25dSPoul-Henning Kamp 	struct sockaddr_in sa;
49591421ba2SRobert Watson 	struct ucred *cred;
496999f1343SGarrett Wollman 	int error;
497999f1343SGarrett Wollman 
49891421ba2SRobert Watson 	cred = inp->inp_socket->so_cred;
49991421ba2SRobert Watson 	if (inp->inp_laddr.s_addr == INADDR_ANY && jailed(cred)) {
500e4bdf25dSPoul-Henning Kamp 		bzero(&sa, sizeof (sa));
50191421ba2SRobert Watson 		sa.sin_addr.s_addr = htonl(cred->cr_prison->pr_ip);
502e4bdf25dSPoul-Henning Kamp 		sa.sin_len=sizeof (sa);
503e4bdf25dSPoul-Henning Kamp 		sa.sin_family = AF_INET;
504e4bdf25dSPoul-Henning Kamp 		error = in_pcbbind(inp, (struct sockaddr *)&sa, p);
505e4bdf25dSPoul-Henning Kamp 		if (error)
506e4bdf25dSPoul-Henning Kamp 		    return (error);
507e4bdf25dSPoul-Henning Kamp 	}
508999f1343SGarrett Wollman 	/*
509999f1343SGarrett Wollman 	 *   Call inner routine, to assign local interface address.
510999f1343SGarrett Wollman 	 */
511831a80b0SMatthew Dillon 	if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
512999f1343SGarrett Wollman 		return(error);
513999f1343SGarrett Wollman 
514c3229e05SDavid Greenman 	if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
515df8bae1dSRodney W. Grimes 	    inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
516cfa1ca9dSYoshinobu Inoue 	    inp->inp_lport, 0, NULL) != NULL) {
517df8bae1dSRodney W. Grimes 		return (EADDRINUSE);
518c3229e05SDavid Greenman 	}
519df8bae1dSRodney W. Grimes 	if (inp->inp_laddr.s_addr == INADDR_ANY) {
5205a903f8dSPierre Beyssac 		if (inp->inp_lport == 0) {
5215a903f8dSPierre Beyssac 			error = in_pcbbind(inp, (struct sockaddr *)0, p);
5225a903f8dSPierre Beyssac 			if (error)
5235a903f8dSPierre Beyssac 				return (error);
5245a903f8dSPierre Beyssac 		}
525df8bae1dSRodney W. Grimes 		inp->inp_laddr = ifaddr->sin_addr;
526df8bae1dSRodney W. Grimes 	}
527df8bae1dSRodney W. Grimes 	inp->inp_faddr = sin->sin_addr;
528df8bae1dSRodney W. Grimes 	inp->inp_fport = sin->sin_port;
52915bd2b43SDavid Greenman 	in_pcbrehash(inp);
530df8bae1dSRodney W. Grimes 	return (0);
531df8bae1dSRodney W. Grimes }
532df8bae1dSRodney W. Grimes 
53326f9a767SRodney W. Grimes void
534df8bae1dSRodney W. Grimes in_pcbdisconnect(inp)
535df8bae1dSRodney W. Grimes 	struct inpcb *inp;
536df8bae1dSRodney W. Grimes {
537df8bae1dSRodney W. Grimes 
538df8bae1dSRodney W. Grimes 	inp->inp_faddr.s_addr = INADDR_ANY;
539df8bae1dSRodney W. Grimes 	inp->inp_fport = 0;
54015bd2b43SDavid Greenman 	in_pcbrehash(inp);
541df8bae1dSRodney W. Grimes 	if (inp->inp_socket->so_state & SS_NOFDREF)
542df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
543df8bae1dSRodney W. Grimes }
544df8bae1dSRodney W. Grimes 
54526f9a767SRodney W. Grimes void
546df8bae1dSRodney W. Grimes in_pcbdetach(inp)
547df8bae1dSRodney W. Grimes 	struct inpcb *inp;
548df8bae1dSRodney W. Grimes {
549df8bae1dSRodney W. Grimes 	struct socket *so = inp->inp_socket;
5503d4d47f3SGarrett Wollman 	struct inpcbinfo *ipi = inp->inp_pcbinfo;
551e7f32693SJayanth Vijayaraghavan 	struct rtentry *rt  = inp->inp_route.ro_rt;
552df8bae1dSRodney W. Grimes 
553cfa1ca9dSYoshinobu Inoue #ifdef IPSEC
554cfa1ca9dSYoshinobu Inoue 	ipsec4_delete_pcbpolicy(inp);
555cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/
5563d4d47f3SGarrett Wollman 	inp->inp_gencnt = ++ipi->ipi_gencnt;
557c3229e05SDavid Greenman 	in_pcbremlists(inp);
558df8bae1dSRodney W. Grimes 	so->so_pcb = 0;
559df8bae1dSRodney W. Grimes 	sofree(so);
560df8bae1dSRodney W. Grimes 	if (inp->inp_options)
561df8bae1dSRodney W. Grimes 		(void)m_free(inp->inp_options);
562e7f32693SJayanth Vijayaraghavan 	if (rt) {
563e7f32693SJayanth Vijayaraghavan 		/*
564e7f32693SJayanth Vijayaraghavan 		 * route deletion requires reference count to be <= zero
565e7f32693SJayanth Vijayaraghavan 		 */
566e7f32693SJayanth Vijayaraghavan 		if ((rt->rt_flags & RTF_DELCLONE) &&
567234ff7c4SBosko Milekic 		    (rt->rt_flags & RTF_WASCLONED) &&
568234ff7c4SBosko Milekic 		    (rt->rt_refcnt <= 1)) {
569234ff7c4SBosko Milekic 			rt->rt_refcnt--;
570e7f32693SJayanth Vijayaraghavan 			rt->rt_flags &= ~RTF_UP;
571e7f32693SJayanth Vijayaraghavan 			rtrequest(RTM_DELETE, rt_key(rt),
572e7f32693SJayanth Vijayaraghavan 				  rt->rt_gateway, rt_mask(rt),
573e7f32693SJayanth Vijayaraghavan 				  rt->rt_flags, (struct rtentry **)0);
574e7f32693SJayanth Vijayaraghavan 		}
575e7f32693SJayanth Vijayaraghavan 		else
576e7f32693SJayanth Vijayaraghavan 			rtfree(rt);
577e7f32693SJayanth Vijayaraghavan 	}
578df8bae1dSRodney W. Grimes 	ip_freemoptions(inp->inp_moptions);
579cfa1ca9dSYoshinobu Inoue 	inp->inp_vflag = 0;
580a3ea6d41SDag-Erling Smørgrav 	zfree(ipi->ipi_zone, inp);
581df8bae1dSRodney W. Grimes }
582df8bae1dSRodney W. Grimes 
583117bcae7SGarrett Wollman /*
584117bcae7SGarrett Wollman  * The calling convention of in_setsockaddr() and in_setpeeraddr() was
585117bcae7SGarrett Wollman  * modified to match the pru_sockaddr() and pru_peeraddr() entry points
586117bcae7SGarrett Wollman  * in struct pr_usrreqs, so that protocols can just reference then directly
587117bcae7SGarrett Wollman  * without the need for a wrapper function.  The socket must have a valid
588117bcae7SGarrett Wollman  * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
589117bcae7SGarrett Wollman  * except through a kernel programming error, so it is acceptable to panic
59057bf258eSGarrett Wollman  * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
59157bf258eSGarrett Wollman  * because there actually /is/ a programming error somewhere... XXX)
592117bcae7SGarrett Wollman  */
593117bcae7SGarrett Wollman int
594117bcae7SGarrett Wollman in_setsockaddr(so, nam)
595117bcae7SGarrett Wollman 	struct socket *so;
59657bf258eSGarrett Wollman 	struct sockaddr **nam;
597df8bae1dSRodney W. Grimes {
598fdc984f7STor Egge 	int s;
599fdc984f7STor Egge 	register struct inpcb *inp;
600df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
601df8bae1dSRodney W. Grimes 
602c3229e05SDavid Greenman 	/*
603c3229e05SDavid Greenman 	 * Do the malloc first in case it blocks.
604c3229e05SDavid Greenman 	 */
6057cc0979fSDavid Malone 	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
6067cc0979fSDavid Malone 		M_WAITOK | M_ZERO);
60742fa505bSDavid Greenman 	sin->sin_family = AF_INET;
60842fa505bSDavid Greenman 	sin->sin_len = sizeof(*sin);
60942fa505bSDavid Greenman 
610fdc984f7STor Egge 	s = splnet();
611fdc984f7STor Egge 	inp = sotoinpcb(so);
612db112f04STor Egge 	if (!inp) {
613db112f04STor Egge 		splx(s);
61442fa505bSDavid Greenman 		free(sin, M_SONAME);
615ff079ca4SPeter Wemm 		return ECONNRESET;
616db112f04STor Egge 	}
617df8bae1dSRodney W. Grimes 	sin->sin_port = inp->inp_lport;
618df8bae1dSRodney W. Grimes 	sin->sin_addr = inp->inp_laddr;
619db112f04STor Egge 	splx(s);
62042fa505bSDavid Greenman 
62142fa505bSDavid Greenman 	*nam = (struct sockaddr *)sin;
622117bcae7SGarrett Wollman 	return 0;
623df8bae1dSRodney W. Grimes }
624df8bae1dSRodney W. Grimes 
625117bcae7SGarrett Wollman int
626117bcae7SGarrett Wollman in_setpeeraddr(so, nam)
627117bcae7SGarrett Wollman 	struct socket *so;
62857bf258eSGarrett Wollman 	struct sockaddr **nam;
629df8bae1dSRodney W. Grimes {
630fdc984f7STor Egge 	int s;
631fdc984f7STor Egge 	struct inpcb *inp;
632df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
633df8bae1dSRodney W. Grimes 
634c3229e05SDavid Greenman 	/*
635c3229e05SDavid Greenman 	 * Do the malloc first in case it blocks.
636c3229e05SDavid Greenman 	 */
6377cc0979fSDavid Malone 	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
6387cc0979fSDavid Malone 		M_WAITOK | M_ZERO);
63942fa505bSDavid Greenman 	sin->sin_family = AF_INET;
64042fa505bSDavid Greenman 	sin->sin_len = sizeof(*sin);
64142fa505bSDavid Greenman 
642fdc984f7STor Egge 	s = splnet();
643fdc984f7STor Egge 	inp = sotoinpcb(so);
644db112f04STor Egge 	if (!inp) {
645db112f04STor Egge 		splx(s);
64642fa505bSDavid Greenman 		free(sin, M_SONAME);
647ff079ca4SPeter Wemm 		return ECONNRESET;
648db112f04STor Egge 	}
649df8bae1dSRodney W. Grimes 	sin->sin_port = inp->inp_fport;
650df8bae1dSRodney W. Grimes 	sin->sin_addr = inp->inp_faddr;
651db112f04STor Egge 	splx(s);
65242fa505bSDavid Greenman 
65342fa505bSDavid Greenman 	*nam = (struct sockaddr *)sin;
654117bcae7SGarrett Wollman 	return 0;
655df8bae1dSRodney W. Grimes }
656df8bae1dSRodney W. Grimes 
65726f9a767SRodney W. Grimes void
658c693a045SJonathan Lemon in_pcbnotifyall(head, faddr, errno, notify)
65915bd2b43SDavid Greenman 	struct inpcbhead *head;
660df8bae1dSRodney W. Grimes 	struct in_addr faddr;
661c693a045SJonathan Lemon 	int errno;
662d1c54148SJesper Skriver 	void (*notify) __P((struct inpcb *, int));
663d1c54148SJesper Skriver {
664c693a045SJonathan Lemon 	struct inpcb *inp, *ninp;
665c693a045SJonathan Lemon 	int s;
666d1c54148SJesper Skriver 
667d1c54148SJesper Skriver 	s = splnet();
668c693a045SJonathan Lemon 	for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
669c693a045SJonathan Lemon 		ninp = LIST_NEXT(inp, inp_list);
670d1c54148SJesper Skriver #ifdef INET6
671c693a045SJonathan Lemon 		if ((inp->inp_vflag & INP_IPV4) == 0)
672d1c54148SJesper Skriver 			continue;
673d1c54148SJesper Skriver #endif
674d1c54148SJesper Skriver 		if (inp->inp_faddr.s_addr != faddr.s_addr ||
675c693a045SJonathan Lemon 		    inp->inp_socket == NULL)
676d1c54148SJesper Skriver 				continue;
677c693a045SJonathan Lemon 		(*notify)(inp, errno);
678d1c54148SJesper Skriver 	}
679d1c54148SJesper Skriver 	splx(s);
680d1c54148SJesper Skriver }
681d1c54148SJesper Skriver 
682df8bae1dSRodney W. Grimes /*
683df8bae1dSRodney W. Grimes  * Check for alternatives when higher level complains
684df8bae1dSRodney W. Grimes  * about service problems.  For now, invalidate cached
685df8bae1dSRodney W. Grimes  * routing information.  If the route was created dynamically
686df8bae1dSRodney W. Grimes  * (by a redirect), time to try a default gateway again.
687df8bae1dSRodney W. Grimes  */
68826f9a767SRodney W. Grimes void
689df8bae1dSRodney W. Grimes in_losing(inp)
690df8bae1dSRodney W. Grimes 	struct inpcb *inp;
691df8bae1dSRodney W. Grimes {
692df8bae1dSRodney W. Grimes 	register struct rtentry *rt;
693df8bae1dSRodney W. Grimes 	struct rt_addrinfo info;
694df8bae1dSRodney W. Grimes 
695df8bae1dSRodney W. Grimes 	if ((rt = inp->inp_route.ro_rt)) {
696df8bae1dSRodney W. Grimes 		inp->inp_route.ro_rt = 0;
697df8bae1dSRodney W. Grimes 		bzero((caddr_t)&info, sizeof(info));
698df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_DST] =
699df8bae1dSRodney W. Grimes 			(struct sockaddr *)&inp->inp_route.ro_dst;
700df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
701df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
702df8bae1dSRodney W. Grimes 		rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
703df8bae1dSRodney W. Grimes 		if (rt->rt_flags & RTF_DYNAMIC)
704df8bae1dSRodney W. Grimes 			(void) rtrequest(RTM_DELETE, rt_key(rt),
705df8bae1dSRodney W. Grimes 				rt->rt_gateway, rt_mask(rt), rt->rt_flags,
706df8bae1dSRodney W. Grimes 				(struct rtentry **)0);
707df8bae1dSRodney W. Grimes 		else
708df8bae1dSRodney W. Grimes 		/*
709df8bae1dSRodney W. Grimes 		 * A new route can be allocated
710df8bae1dSRodney W. Grimes 		 * the next time output is attempted.
711df8bae1dSRodney W. Grimes 		 */
712df8bae1dSRodney W. Grimes 			rtfree(rt);
713df8bae1dSRodney W. Grimes 	}
714df8bae1dSRodney W. Grimes }
715df8bae1dSRodney W. Grimes 
716df8bae1dSRodney W. Grimes /*
717df8bae1dSRodney W. Grimes  * After a routing change, flush old routing
718df8bae1dSRodney W. Grimes  * and allocate a (hopefully) better one.
719df8bae1dSRodney W. Grimes  */
720d1c54148SJesper Skriver void
721df8bae1dSRodney W. Grimes in_rtchange(inp, errno)
722df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
723df8bae1dSRodney W. Grimes 	int errno;
724df8bae1dSRodney W. Grimes {
725df8bae1dSRodney W. Grimes 	if (inp->inp_route.ro_rt) {
726df8bae1dSRodney W. Grimes 		rtfree(inp->inp_route.ro_rt);
727df8bae1dSRodney W. Grimes 		inp->inp_route.ro_rt = 0;
728df8bae1dSRodney W. Grimes 		/*
729df8bae1dSRodney W. Grimes 		 * A new route can be allocated the next time
730df8bae1dSRodney W. Grimes 		 * output is attempted.
731df8bae1dSRodney W. Grimes 		 */
732df8bae1dSRodney W. Grimes 	}
733df8bae1dSRodney W. Grimes }
734df8bae1dSRodney W. Grimes 
735c3229e05SDavid Greenman /*
736c3229e05SDavid Greenman  * Lookup a PCB based on the local address and port.
737c3229e05SDavid Greenman  */
738df8bae1dSRodney W. Grimes struct inpcb *
739c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
7406d6a026bSDavid Greenman 	struct inpcbinfo *pcbinfo;
741c3229e05SDavid Greenman 	struct in_addr laddr;
742c3229e05SDavid Greenman 	u_int lport_arg;
7436d6a026bSDavid Greenman 	int wild_okay;
744df8bae1dSRodney W. Grimes {
745f1d19042SArchie Cobbs 	register struct inpcb *inp;
746df8bae1dSRodney W. Grimes 	int matchwild = 3, wildcard;
747c3229e05SDavid Greenman 	u_short lport = lport_arg;
7487bc4aca7SDavid Greenman 
749c3229e05SDavid Greenman 	if (!wild_okay) {
750c3229e05SDavid Greenman 		struct inpcbhead *head;
751c3229e05SDavid Greenman 		/*
752c3229e05SDavid Greenman 		 * Look for an unconnected (wildcard foreign addr) PCB that
753c3229e05SDavid Greenman 		 * matches the local address and port we're looking for.
754c3229e05SDavid Greenman 		 */
755c3229e05SDavid Greenman 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
756fc2ffbe6SPoul-Henning Kamp 		LIST_FOREACH(inp, head, inp_hash) {
757cfa1ca9dSYoshinobu Inoue #ifdef INET6
758369dc8ceSEivind Eklund 			if ((inp->inp_vflag & INP_IPV4) == 0)
759cfa1ca9dSYoshinobu Inoue 				continue;
760cfa1ca9dSYoshinobu Inoue #endif
761c3229e05SDavid Greenman 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
762c3229e05SDavid Greenman 			    inp->inp_laddr.s_addr == laddr.s_addr &&
763c3229e05SDavid Greenman 			    inp->inp_lport == lport) {
764c3229e05SDavid Greenman 				/*
765c3229e05SDavid Greenman 				 * Found.
766c3229e05SDavid Greenman 				 */
767c3229e05SDavid Greenman 				return (inp);
768df8bae1dSRodney W. Grimes 			}
769c3229e05SDavid Greenman 		}
770c3229e05SDavid Greenman 		/*
771c3229e05SDavid Greenman 		 * Not found.
772c3229e05SDavid Greenman 		 */
773c3229e05SDavid Greenman 		return (NULL);
774c3229e05SDavid Greenman 	} else {
775c3229e05SDavid Greenman 		struct inpcbporthead *porthash;
776c3229e05SDavid Greenman 		struct inpcbport *phd;
777c3229e05SDavid Greenman 		struct inpcb *match = NULL;
778c3229e05SDavid Greenman 		/*
779c3229e05SDavid Greenman 		 * Best fit PCB lookup.
780c3229e05SDavid Greenman 		 *
781c3229e05SDavid Greenman 		 * First see if this local port is in use by looking on the
782c3229e05SDavid Greenman 		 * port hash list.
783c3229e05SDavid Greenman 		 */
784c3229e05SDavid Greenman 		porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
785c3229e05SDavid Greenman 		    pcbinfo->porthashmask)];
786fc2ffbe6SPoul-Henning Kamp 		LIST_FOREACH(phd, porthash, phd_hash) {
787c3229e05SDavid Greenman 			if (phd->phd_port == lport)
788c3229e05SDavid Greenman 				break;
789c3229e05SDavid Greenman 		}
790c3229e05SDavid Greenman 		if (phd != NULL) {
791c3229e05SDavid Greenman 			/*
792c3229e05SDavid Greenman 			 * Port is in use by one or more PCBs. Look for best
793c3229e05SDavid Greenman 			 * fit.
794c3229e05SDavid Greenman 			 */
79537d40066SPoul-Henning Kamp 			LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
796c3229e05SDavid Greenman 				wildcard = 0;
797cfa1ca9dSYoshinobu Inoue #ifdef INET6
798369dc8ceSEivind Eklund 				if ((inp->inp_vflag & INP_IPV4) == 0)
799cfa1ca9dSYoshinobu Inoue 					continue;
800cfa1ca9dSYoshinobu Inoue #endif
801c3229e05SDavid Greenman 				if (inp->inp_faddr.s_addr != INADDR_ANY)
802c3229e05SDavid Greenman 					wildcard++;
80315bd2b43SDavid Greenman 				if (inp->inp_laddr.s_addr != INADDR_ANY) {
80415bd2b43SDavid Greenman 					if (laddr.s_addr == INADDR_ANY)
80515bd2b43SDavid Greenman 						wildcard++;
80615bd2b43SDavid Greenman 					else if (inp->inp_laddr.s_addr != laddr.s_addr)
80715bd2b43SDavid Greenman 						continue;
80815bd2b43SDavid Greenman 				} else {
80915bd2b43SDavid Greenman 					if (laddr.s_addr != INADDR_ANY)
81015bd2b43SDavid Greenman 						wildcard++;
81115bd2b43SDavid Greenman 				}
812df8bae1dSRodney W. Grimes 				if (wildcard < matchwild) {
813df8bae1dSRodney W. Grimes 					match = inp;
814df8bae1dSRodney W. Grimes 					matchwild = wildcard;
8153dbdc25cSDavid Greenman 					if (matchwild == 0) {
816df8bae1dSRodney W. Grimes 						break;
817df8bae1dSRodney W. Grimes 					}
818df8bae1dSRodney W. Grimes 				}
8193dbdc25cSDavid Greenman 			}
820c3229e05SDavid Greenman 		}
821df8bae1dSRodney W. Grimes 		return (match);
822df8bae1dSRodney W. Grimes 	}
823c3229e05SDavid Greenman }
82415bd2b43SDavid Greenman 
82515bd2b43SDavid Greenman /*
82615bd2b43SDavid Greenman  * Lookup PCB in hash list.
82715bd2b43SDavid Greenman  */
82815bd2b43SDavid Greenman struct inpcb *
829cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
830cfa1ca9dSYoshinobu Inoue 		  ifp)
83115bd2b43SDavid Greenman 	struct inpcbinfo *pcbinfo;
83215bd2b43SDavid Greenman 	struct in_addr faddr, laddr;
83315bd2b43SDavid Greenman 	u_int fport_arg, lport_arg;
8346d6a026bSDavid Greenman 	int wildcard;
835cfa1ca9dSYoshinobu Inoue 	struct ifnet *ifp;
83615bd2b43SDavid Greenman {
83715bd2b43SDavid Greenman 	struct inpcbhead *head;
83815bd2b43SDavid Greenman 	register struct inpcb *inp;
83915bd2b43SDavid Greenman 	u_short fport = fport_arg, lport = lport_arg;
84015bd2b43SDavid Greenman 
84115bd2b43SDavid Greenman 	/*
84215bd2b43SDavid Greenman 	 * First look for an exact match.
84315bd2b43SDavid Greenman 	 */
844ddd79a97SDavid Greenman 	head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
845fc2ffbe6SPoul-Henning Kamp 	LIST_FOREACH(inp, head, inp_hash) {
846cfa1ca9dSYoshinobu Inoue #ifdef INET6
847369dc8ceSEivind Eklund 		if ((inp->inp_vflag & INP_IPV4) == 0)
848cfa1ca9dSYoshinobu Inoue 			continue;
849cfa1ca9dSYoshinobu Inoue #endif
8506d6a026bSDavid Greenman 		if (inp->inp_faddr.s_addr == faddr.s_addr &&
851ca98b82cSDavid Greenman 		    inp->inp_laddr.s_addr == laddr.s_addr &&
852ca98b82cSDavid Greenman 		    inp->inp_fport == fport &&
853c3229e05SDavid Greenman 		    inp->inp_lport == lport) {
854c3229e05SDavid Greenman 			/*
855c3229e05SDavid Greenman 			 * Found.
856c3229e05SDavid Greenman 			 */
857c3229e05SDavid Greenman 			return (inp);
858c3229e05SDavid Greenman 		}
8596d6a026bSDavid Greenman 	}
8606d6a026bSDavid Greenman 	if (wildcard) {
8616d6a026bSDavid Greenman 		struct inpcb *local_wild = NULL;
862cfa1ca9dSYoshinobu Inoue #if defined(INET6)
863cfa1ca9dSYoshinobu Inoue 		struct inpcb *local_wild_mapped = NULL;
864cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
8656d6a026bSDavid Greenman 
866ddd79a97SDavid Greenman 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
867fc2ffbe6SPoul-Henning Kamp 		LIST_FOREACH(inp, head, inp_hash) {
868cfa1ca9dSYoshinobu Inoue #ifdef INET6
869369dc8ceSEivind Eklund 			if ((inp->inp_vflag & INP_IPV4) == 0)
870cfa1ca9dSYoshinobu Inoue 				continue;
871cfa1ca9dSYoshinobu Inoue #endif
8726d6a026bSDavid Greenman 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
873c3229e05SDavid Greenman 			    inp->inp_lport == lport) {
874cfa1ca9dSYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0
875cfa1ca9dSYoshinobu Inoue 				if (ifp && ifp->if_type == IFT_FAITH &&
876cfa1ca9dSYoshinobu Inoue 				    (inp->inp_flags & INP_FAITH) == 0)
877cfa1ca9dSYoshinobu Inoue 					continue;
878cfa1ca9dSYoshinobu Inoue #endif
8796d6a026bSDavid Greenman 				if (inp->inp_laddr.s_addr == laddr.s_addr)
880c3229e05SDavid Greenman 					return (inp);
881cfa1ca9dSYoshinobu Inoue 				else if (inp->inp_laddr.s_addr == INADDR_ANY) {
882cfa1ca9dSYoshinobu Inoue #if defined(INET6)
883cfa1ca9dSYoshinobu Inoue 					if (INP_CHECK_SOCKAF(inp->inp_socket,
884cfa1ca9dSYoshinobu Inoue 							     AF_INET6))
885cfa1ca9dSYoshinobu Inoue 						local_wild_mapped = inp;
886cfa1ca9dSYoshinobu Inoue 					else
887cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
8886d6a026bSDavid Greenman 					local_wild = inp;
8896d6a026bSDavid Greenman 				}
8906d6a026bSDavid Greenman 			}
891cfa1ca9dSYoshinobu Inoue 		}
892cfa1ca9dSYoshinobu Inoue #if defined(INET6)
893cfa1ca9dSYoshinobu Inoue 		if (local_wild == NULL)
894cfa1ca9dSYoshinobu Inoue 			return (local_wild_mapped);
895cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
896c3229e05SDavid Greenman 		return (local_wild);
8976d6a026bSDavid Greenman 	}
898c3229e05SDavid Greenman 
899c3229e05SDavid Greenman 	/*
900c3229e05SDavid Greenman 	 * Not found.
901c3229e05SDavid Greenman 	 */
9026d6a026bSDavid Greenman 	return (NULL);
90315bd2b43SDavid Greenman }
90415bd2b43SDavid Greenman 
9057bc4aca7SDavid Greenman /*
906c3229e05SDavid Greenman  * Insert PCB onto various hash lists.
9077bc4aca7SDavid Greenman  */
908c3229e05SDavid Greenman int
90915bd2b43SDavid Greenman in_pcbinshash(inp)
91015bd2b43SDavid Greenman 	struct inpcb *inp;
91115bd2b43SDavid Greenman {
912c3229e05SDavid Greenman 	struct inpcbhead *pcbhash;
913c3229e05SDavid Greenman 	struct inpcbporthead *pcbporthash;
914c3229e05SDavid Greenman 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
915c3229e05SDavid Greenman 	struct inpcbport *phd;
916cfa1ca9dSYoshinobu Inoue 	u_int32_t hashkey_faddr;
91715bd2b43SDavid Greenman 
918cfa1ca9dSYoshinobu Inoue #ifdef INET6
919cfa1ca9dSYoshinobu Inoue 	if (inp->inp_vflag & INP_IPV6)
920cfa1ca9dSYoshinobu Inoue 		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
921cfa1ca9dSYoshinobu Inoue 	else
922cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
923cfa1ca9dSYoshinobu Inoue 	hashkey_faddr = inp->inp_faddr.s_addr;
924cfa1ca9dSYoshinobu Inoue 
925cfa1ca9dSYoshinobu Inoue 	pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
926c3229e05SDavid Greenman 		 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
92715bd2b43SDavid Greenman 
928c3229e05SDavid Greenman 	pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
929c3229e05SDavid Greenman 	    pcbinfo->porthashmask)];
930c3229e05SDavid Greenman 
931c3229e05SDavid Greenman 	/*
932c3229e05SDavid Greenman 	 * Go through port list and look for a head for this lport.
933c3229e05SDavid Greenman 	 */
934fc2ffbe6SPoul-Henning Kamp 	LIST_FOREACH(phd, pcbporthash, phd_hash) {
935c3229e05SDavid Greenman 		if (phd->phd_port == inp->inp_lport)
936c3229e05SDavid Greenman 			break;
937c3229e05SDavid Greenman 	}
938c3229e05SDavid Greenman 	/*
939c3229e05SDavid Greenman 	 * If none exists, malloc one and tack it on.
940c3229e05SDavid Greenman 	 */
941c3229e05SDavid Greenman 	if (phd == NULL) {
942c3229e05SDavid Greenman 		MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
943c3229e05SDavid Greenman 		if (phd == NULL) {
944c3229e05SDavid Greenman 			return (ENOBUFS); /* XXX */
945c3229e05SDavid Greenman 		}
946c3229e05SDavid Greenman 		phd->phd_port = inp->inp_lport;
947c3229e05SDavid Greenman 		LIST_INIT(&phd->phd_pcblist);
948c3229e05SDavid Greenman 		LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
949c3229e05SDavid Greenman 	}
950c3229e05SDavid Greenman 	inp->inp_phd = phd;
951c3229e05SDavid Greenman 	LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
952c3229e05SDavid Greenman 	LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
953c3229e05SDavid Greenman 	return (0);
95415bd2b43SDavid Greenman }
95515bd2b43SDavid Greenman 
956c3229e05SDavid Greenman /*
957c3229e05SDavid Greenman  * Move PCB to the proper hash bucket when { faddr, fport } have  been
958c3229e05SDavid Greenman  * changed. NOTE: This does not handle the case of the lport changing (the
959c3229e05SDavid Greenman  * hashed port list would have to be updated as well), so the lport must
960c3229e05SDavid Greenman  * not change after in_pcbinshash() has been called.
961c3229e05SDavid Greenman  */
96215bd2b43SDavid Greenman void
96315bd2b43SDavid Greenman in_pcbrehash(inp)
96415bd2b43SDavid Greenman 	struct inpcb *inp;
96515bd2b43SDavid Greenman {
96615bd2b43SDavid Greenman 	struct inpcbhead *head;
967cfa1ca9dSYoshinobu Inoue 	u_int32_t hashkey_faddr;
96815bd2b43SDavid Greenman 
969cfa1ca9dSYoshinobu Inoue #ifdef INET6
970cfa1ca9dSYoshinobu Inoue 	if (inp->inp_vflag & INP_IPV6)
971cfa1ca9dSYoshinobu Inoue 		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
972cfa1ca9dSYoshinobu Inoue 	else
973cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
974cfa1ca9dSYoshinobu Inoue 	hashkey_faddr = inp->inp_faddr.s_addr;
975cfa1ca9dSYoshinobu Inoue 
976cfa1ca9dSYoshinobu Inoue 	head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
977ddd79a97SDavid Greenman 		inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
97815bd2b43SDavid Greenman 
979c3229e05SDavid Greenman 	LIST_REMOVE(inp, inp_hash);
98015bd2b43SDavid Greenman 	LIST_INSERT_HEAD(head, inp, inp_hash);
981c3229e05SDavid Greenman }
982c3229e05SDavid Greenman 
983c3229e05SDavid Greenman /*
984c3229e05SDavid Greenman  * Remove PCB from various lists.
985c3229e05SDavid Greenman  */
98676429de4SYoshinobu Inoue void
987c3229e05SDavid Greenman in_pcbremlists(inp)
988c3229e05SDavid Greenman 	struct inpcb *inp;
989c3229e05SDavid Greenman {
99098271db4SGarrett Wollman 	inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
991c3229e05SDavid Greenman 	if (inp->inp_lport) {
992c3229e05SDavid Greenman 		struct inpcbport *phd = inp->inp_phd;
993c3229e05SDavid Greenman 
994c3229e05SDavid Greenman 		LIST_REMOVE(inp, inp_hash);
995c3229e05SDavid Greenman 		LIST_REMOVE(inp, inp_portlist);
996fc2ffbe6SPoul-Henning Kamp 		if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
997c3229e05SDavid Greenman 			LIST_REMOVE(phd, phd_hash);
998c3229e05SDavid Greenman 			free(phd, M_PCB);
999c3229e05SDavid Greenman 		}
1000c3229e05SDavid Greenman 	}
1001c3229e05SDavid Greenman 	LIST_REMOVE(inp, inp_list);
10023d4d47f3SGarrett Wollman 	inp->inp_pcbinfo->ipi_count--;
100315bd2b43SDavid Greenman }
100475c13541SPoul-Henning Kamp 
100575c13541SPoul-Henning Kamp int
100675c13541SPoul-Henning Kamp prison_xinpcb(struct proc *p, struct inpcb *inp)
100775c13541SPoul-Henning Kamp {
100891421ba2SRobert Watson 	if (!jailed(p->p_ucred))
100975c13541SPoul-Henning Kamp 		return (0);
101091421ba2SRobert Watson 	if (ntohl(inp->inp_laddr.s_addr) == p->p_ucred->cr_prison->pr_ip)
101175c13541SPoul-Henning Kamp 		return (0);
101275c13541SPoul-Henning Kamp 	return (1);
101375c13541SPoul-Henning Kamp }
1014