xref: /freebsd/sys/netinet/in_pcb.c (revision cfa1ca9dfa0ee5bed5cc1cb0b07820701abbb431)
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 
37cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
38cfa1ca9dSYoshinobu Inoue 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
40df8bae1dSRodney W. Grimes #include <sys/systm.h>
41df8bae1dSRodney W. Grimes #include <sys/malloc.h>
42df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
43cfa1ca9dSYoshinobu Inoue #include <sys/domain.h>
44df8bae1dSRodney W. Grimes #include <sys/protosw.h>
45df8bae1dSRodney W. Grimes #include <sys/socket.h>
46df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
47df8bae1dSRodney W. Grimes #include <sys/proc.h>
4875c13541SPoul-Henning Kamp #include <sys/jail.h>
49101f9fc8SPeter Wemm #include <sys/kernel.h>
50101f9fc8SPeter Wemm #include <sys/sysctl.h>
518781d8e9SBruce Evans 
5208637435SBruce Evans #include <machine/limits.h>
5308637435SBruce Evans 
548781d8e9SBruce Evans #include <vm/vm_zone.h>
55df8bae1dSRodney W. Grimes 
56df8bae1dSRodney W. Grimes #include <net/if.h>
57cfa1ca9dSYoshinobu Inoue #include <net/if_types.h>
58df8bae1dSRodney W. Grimes #include <net/route.h>
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes #include <netinet/in.h>
61df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
62df8bae1dSRodney W. Grimes #include <netinet/in_var.h>
63df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
64cfa1ca9dSYoshinobu Inoue #ifdef INET6
65cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h>
66cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h>
67cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
68cfa1ca9dSYoshinobu Inoue 
69cfa1ca9dSYoshinobu Inoue #include "faith.h"
70cfa1ca9dSYoshinobu Inoue 
71cfa1ca9dSYoshinobu Inoue #ifdef IPSEC
72cfa1ca9dSYoshinobu Inoue #include <netinet6/ipsec.h>
73cfa1ca9dSYoshinobu Inoue #include <netkey/key.h>
74cfa1ca9dSYoshinobu Inoue #include <netkey/key_debug.h>
75cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes struct	in_addr zeroin_addr;
78df8bae1dSRodney W. Grimes 
79bbd42ad0SPeter Wemm static void	in_rtchange __P((struct inpcb *, int));
80bbd42ad0SPeter Wemm 
81101f9fc8SPeter Wemm /*
82101f9fc8SPeter Wemm  * These configure the range of local port addresses assigned to
83101f9fc8SPeter Wemm  * "unspecified" outgoing connections/packets/whatever.
84101f9fc8SPeter Wemm  */
8582cd038dSYoshinobu Inoue int	ipport_lowfirstauto  = IPPORT_RESERVED - 1;	/* 1023 */
8682cd038dSYoshinobu Inoue int	ipport_lowlastauto = IPPORT_RESERVEDSTART;	/* 600 */
8782cd038dSYoshinobu Inoue int	ipport_firstauto = IPPORT_RESERVED;		/* 1024 */
8882cd038dSYoshinobu Inoue int	ipport_lastauto  = IPPORT_USERRESERVED;		/* 5000 */
8982cd038dSYoshinobu Inoue int	ipport_hifirstauto = IPPORT_HIFIRSTAUTO;	/* 49152 */
9082cd038dSYoshinobu Inoue int	ipport_hilastauto  = IPPORT_HILASTAUTO;		/* 65535 */
91101f9fc8SPeter Wemm 
92bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \
93bbd42ad0SPeter Wemm 	if ((var) < (min)) { (var) = (min); } \
94bbd42ad0SPeter Wemm 	else if ((var) > (max)) { (var) = (max); }
95bbd42ad0SPeter Wemm 
96bbd42ad0SPeter Wemm static int
97bbd42ad0SPeter Wemm sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
98bbd42ad0SPeter Wemm {
99bbd42ad0SPeter Wemm 	int error = sysctl_handle_int(oidp,
100bbd42ad0SPeter Wemm 		oidp->oid_arg1, oidp->oid_arg2, req);
101bbd42ad0SPeter Wemm 	if (!error) {
102bbd42ad0SPeter Wemm 		RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
103bbd42ad0SPeter Wemm 		RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
104bbd42ad0SPeter Wemm 		RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
105bbd42ad0SPeter Wemm 		RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
106bbd42ad0SPeter Wemm 		RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
107bbd42ad0SPeter Wemm 		RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
108bbd42ad0SPeter Wemm 	}
109bbd42ad0SPeter Wemm 	return error;
110bbd42ad0SPeter Wemm }
111bbd42ad0SPeter Wemm 
112bbd42ad0SPeter Wemm #undef RANGECHK
113bbd42ad0SPeter Wemm 
11433b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
11533b3ac06SPeter Wemm 
116bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
117bbd42ad0SPeter Wemm 	   &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
118bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
119bbd42ad0SPeter Wemm 	   &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
120bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
121bbd42ad0SPeter Wemm 	   &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
122bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
123bbd42ad0SPeter Wemm 	   &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
124bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
125bbd42ad0SPeter Wemm 	   &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
126bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
127bbd42ad0SPeter Wemm 	   &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
1280312fbe9SPoul-Henning Kamp 
129c3229e05SDavid Greenman /*
130c3229e05SDavid Greenman  * in_pcb.c: manage the Protocol Control Blocks.
131c3229e05SDavid Greenman  *
132c3229e05SDavid Greenman  * NOTE: It is assumed that most of these functions will be called at
133c3229e05SDavid Greenman  * splnet(). XXX - There are, unfortunately, a few exceptions to this
134c3229e05SDavid Greenman  * rule that should be fixed.
135c3229e05SDavid Greenman  */
136c3229e05SDavid Greenman 
137c3229e05SDavid Greenman /*
138c3229e05SDavid Greenman  * Allocate a PCB and associate it with the socket.
139c3229e05SDavid Greenman  */
140df8bae1dSRodney W. Grimes int
141a29f300eSGarrett Wollman in_pcballoc(so, pcbinfo, p)
142df8bae1dSRodney W. Grimes 	struct socket *so;
14315bd2b43SDavid Greenman 	struct inpcbinfo *pcbinfo;
144a29f300eSGarrett Wollman 	struct proc *p;
145df8bae1dSRodney W. Grimes {
146df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
147df8bae1dSRodney W. Grimes 
1483d4d47f3SGarrett Wollman 	inp = zalloci(pcbinfo->ipi_zone);
149df8bae1dSRodney W. Grimes 	if (inp == NULL)
150df8bae1dSRodney W. Grimes 		return (ENOBUFS);
151df8bae1dSRodney W. Grimes 	bzero((caddr_t)inp, sizeof(*inp));
1523d4d47f3SGarrett Wollman 	inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
15315bd2b43SDavid Greenman 	inp->inp_pcbinfo = pcbinfo;
154df8bae1dSRodney W. Grimes 	inp->inp_socket = so;
15515bd2b43SDavid Greenman 	LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
1563d4d47f3SGarrett Wollman 	pcbinfo->ipi_count++;
157df8bae1dSRodney W. Grimes 	so->so_pcb = (caddr_t)inp;
158df8bae1dSRodney W. Grimes 	return (0);
159df8bae1dSRodney W. Grimes }
160df8bae1dSRodney W. Grimes 
161df8bae1dSRodney W. Grimes int
162a29f300eSGarrett Wollman in_pcbbind(inp, nam, p)
163df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
16457bf258eSGarrett Wollman 	struct sockaddr *nam;
165a29f300eSGarrett Wollman 	struct proc *p;
166df8bae1dSRodney W. Grimes {
167df8bae1dSRodney W. Grimes 	register struct socket *so = inp->inp_socket;
16837bd2b30SPeter Wemm 	unsigned short *lastport;
16915bd2b43SDavid Greenman 	struct sockaddr_in *sin;
170c3229e05SDavid Greenman 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
171df8bae1dSRodney W. Grimes 	u_short lport = 0;
172df8bae1dSRodney W. Grimes 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
17375c13541SPoul-Henning Kamp 	int error, prison = 0;
174df8bae1dSRodney W. Grimes 
17559562606SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
176df8bae1dSRodney W. Grimes 		return (EADDRNOTAVAIL);
177df8bae1dSRodney W. Grimes 	if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
178df8bae1dSRodney W. Grimes 		return (EINVAL);
179c3229e05SDavid Greenman 	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
1806d6a026bSDavid Greenman 		wild = 1;
181df8bae1dSRodney W. Grimes 	if (nam) {
18257bf258eSGarrett Wollman 		sin = (struct sockaddr_in *)nam;
18357bf258eSGarrett Wollman 		if (nam->sa_len != sizeof (*sin))
184df8bae1dSRodney W. Grimes 			return (EINVAL);
185df8bae1dSRodney W. Grimes #ifdef notdef
186df8bae1dSRodney W. Grimes 		/*
187df8bae1dSRodney W. Grimes 		 * We should check the family, but old programs
188df8bae1dSRodney W. Grimes 		 * incorrectly fail to initialize it.
189df8bae1dSRodney W. Grimes 		 */
190df8bae1dSRodney W. Grimes 		if (sin->sin_family != AF_INET)
191df8bae1dSRodney W. Grimes 			return (EAFNOSUPPORT);
192df8bae1dSRodney W. Grimes #endif
19375c13541SPoul-Henning Kamp 		if (prison_ip(p, 0, &sin->sin_addr.s_addr))
19475c13541SPoul-Henning Kamp 			return(EINVAL);
195df8bae1dSRodney W. Grimes 		lport = sin->sin_port;
196df8bae1dSRodney W. Grimes 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
197df8bae1dSRodney W. Grimes 			/*
198df8bae1dSRodney W. Grimes 			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
199df8bae1dSRodney W. Grimes 			 * allow complete duplication of binding if
200df8bae1dSRodney W. Grimes 			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
201df8bae1dSRodney W. Grimes 			 * and a multicast address is bound on both
202df8bae1dSRodney W. Grimes 			 * new and duplicated sockets.
203df8bae1dSRodney W. Grimes 			 */
204df8bae1dSRodney W. Grimes 			if (so->so_options & SO_REUSEADDR)
205df8bae1dSRodney W. Grimes 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
206df8bae1dSRodney W. Grimes 		} else if (sin->sin_addr.s_addr != INADDR_ANY) {
207df8bae1dSRodney W. Grimes 			sin->sin_port = 0;		/* yech... */
208df8bae1dSRodney W. Grimes 			if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
209df8bae1dSRodney W. Grimes 				return (EADDRNOTAVAIL);
210df8bae1dSRodney W. Grimes 		}
211df8bae1dSRodney W. Grimes 		if (lport) {
212df8bae1dSRodney W. Grimes 			struct inpcb *t;
213df8bae1dSRodney W. Grimes 
214df8bae1dSRodney W. Grimes 			/* GROSS */
21557bf258eSGarrett Wollman 			if (ntohs(lport) < IPPORT_RESERVED && p &&
21675c13541SPoul-Henning Kamp 			    suser_xxx(0, p, PRISON_ROOT))
2172469dd60SGarrett Wollman 				return (EACCES);
21875c13541SPoul-Henning Kamp 			if (p && p->p_prison)
21975c13541SPoul-Henning Kamp 				prison = 1;
2202f9a2132SBrian Feldman 			if (so->so_cred->cr_uid != 0 &&
22152b65dbeSBill Fenner 			    !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
2224049a042SGuido van Rooij 				t = in_pcblookup_local(inp->inp_pcbinfo,
22375c13541SPoul-Henning Kamp 				    sin->sin_addr, lport,
22475c13541SPoul-Henning Kamp 				    prison ? 0 :  INPLOOKUP_WILDCARD);
22552b65dbeSBill Fenner 				if (t &&
22652b65dbeSBill Fenner 				    (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
22752b65dbeSBill Fenner 				     ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
22852b65dbeSBill Fenner 				     (t->inp_socket->so_options &
22952b65dbeSBill Fenner 					 SO_REUSEPORT) == 0) &&
2302f9a2132SBrian Feldman 				    (so->so_cred->cr_uid !=
231cfa1ca9dSYoshinobu Inoue 				     t->inp_socket->so_cred->cr_uid)) {
232cfa1ca9dSYoshinobu Inoue #if defined(INET6)
233cfa1ca9dSYoshinobu Inoue 					if (ip6_mapped_addr_on == 0 ||
234cfa1ca9dSYoshinobu Inoue 					    ntohl(sin->sin_addr.s_addr) !=
235cfa1ca9dSYoshinobu Inoue 					    INADDR_ANY ||
236cfa1ca9dSYoshinobu Inoue 					    ntohl(t->inp_laddr.s_addr) !=
237cfa1ca9dSYoshinobu Inoue 					    INADDR_ANY ||
238cfa1ca9dSYoshinobu Inoue 					    INP_SOCKAF(so) ==
239cfa1ca9dSYoshinobu Inoue 					    INP_SOCKAF(t->inp_socket))
240cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
2414049a042SGuido van Rooij 					return (EADDRINUSE);
2424049a042SGuido van Rooij 				}
243cfa1ca9dSYoshinobu Inoue 			}
244c3229e05SDavid Greenman 			t = in_pcblookup_local(pcbinfo, sin->sin_addr,
24575c13541SPoul-Henning Kamp 			    lport, prison ? 0 : wild);
246cfa1ca9dSYoshinobu Inoue 			if (t &&
247cfa1ca9dSYoshinobu Inoue 			    (reuseport & t->inp_socket->so_options) == 0) {
248cfa1ca9dSYoshinobu Inoue #if defined(INET6)
249cfa1ca9dSYoshinobu Inoue 				if (ip6_mapped_addr_on == 0 ||
250cfa1ca9dSYoshinobu Inoue 				    ntohl(sin->sin_addr.s_addr) !=
251cfa1ca9dSYoshinobu Inoue 				    INADDR_ANY ||
252cfa1ca9dSYoshinobu Inoue 				    ntohl(t->inp_laddr.s_addr) !=
253cfa1ca9dSYoshinobu Inoue 				    INADDR_ANY ||
254cfa1ca9dSYoshinobu Inoue 				    INP_SOCKAF(so) ==
255cfa1ca9dSYoshinobu Inoue 				    INP_SOCKAF(t->inp_socket))
256cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
257df8bae1dSRodney W. Grimes 				return (EADDRINUSE);
258df8bae1dSRodney W. Grimes 			}
259cfa1ca9dSYoshinobu Inoue 		}
260df8bae1dSRodney W. Grimes 		inp->inp_laddr = sin->sin_addr;
261df8bae1dSRodney W. Grimes 	}
26233b3ac06SPeter Wemm 	if (lport == 0) {
26333b3ac06SPeter Wemm 		ushort first, last;
26433b3ac06SPeter Wemm 		int count;
26533b3ac06SPeter Wemm 
26675c13541SPoul-Henning Kamp 		if (prison_ip(p, 0, &inp->inp_laddr.s_addr ))
26775c13541SPoul-Henning Kamp 			return (EINVAL);
268321a2846SPoul-Henning Kamp 		inp->inp_flags |= INP_ANONPORT;
269321a2846SPoul-Henning Kamp 
27033b3ac06SPeter Wemm 		if (inp->inp_flags & INP_HIGHPORT) {
27133b3ac06SPeter Wemm 			first = ipport_hifirstauto;	/* sysctl */
27233b3ac06SPeter Wemm 			last  = ipport_hilastauto;
273c3229e05SDavid Greenman 			lastport = &pcbinfo->lasthi;
27433b3ac06SPeter Wemm 		} else if (inp->inp_flags & INP_LOWPORT) {
27575c13541SPoul-Henning Kamp 			if (p && (error = suser_xxx(0, p, PRISON_ROOT)))
276a29f300eSGarrett Wollman 				return error;
277bbd42ad0SPeter Wemm 			first = ipport_lowfirstauto;	/* 1023 */
278bbd42ad0SPeter Wemm 			last  = ipport_lowlastauto;	/* 600 */
279c3229e05SDavid Greenman 			lastport = &pcbinfo->lastlow;
28033b3ac06SPeter Wemm 		} else {
28133b3ac06SPeter Wemm 			first = ipport_firstauto;	/* sysctl */
28233b3ac06SPeter Wemm 			last  = ipport_lastauto;
283c3229e05SDavid Greenman 			lastport = &pcbinfo->lastport;
28433b3ac06SPeter Wemm 		}
28533b3ac06SPeter Wemm 		/*
28633b3ac06SPeter Wemm 		 * Simple check to ensure all ports are not used up causing
28733b3ac06SPeter Wemm 		 * a deadlock here.
28833b3ac06SPeter Wemm 		 *
28933b3ac06SPeter Wemm 		 * We split the two cases (up and down) so that the direction
29033b3ac06SPeter Wemm 		 * is not being tested on each round of the loop.
29133b3ac06SPeter Wemm 		 */
29233b3ac06SPeter Wemm 		if (first > last) {
29333b3ac06SPeter Wemm 			/*
29433b3ac06SPeter Wemm 			 * counting down
29533b3ac06SPeter Wemm 			 */
29633b3ac06SPeter Wemm 			count = first - last;
29733b3ac06SPeter Wemm 
298df8bae1dSRodney W. Grimes 			do {
299c3229e05SDavid Greenman 				if (count-- < 0) {	/* completely used? */
300c3229e05SDavid Greenman 					/*
301c3229e05SDavid Greenman 					 * Undo any address bind that may have
302c3229e05SDavid Greenman 					 * occurred above.
303c3229e05SDavid Greenman 					 */
304c3229e05SDavid Greenman 					inp->inp_laddr.s_addr = INADDR_ANY;
305c3229e05SDavid Greenman 					return (EAGAIN);
306c3229e05SDavid Greenman 				}
30733b3ac06SPeter Wemm 				--*lastport;
30833b3ac06SPeter Wemm 				if (*lastport > first || *lastport < last)
30933b3ac06SPeter Wemm 					*lastport = first;
31015bd2b43SDavid Greenman 				lport = htons(*lastport);
311c3229e05SDavid Greenman 			} while (in_pcblookup_local(pcbinfo,
312c3229e05SDavid Greenman 				 inp->inp_laddr, lport, wild));
31333b3ac06SPeter Wemm 		} else {
31433b3ac06SPeter Wemm 			/*
31533b3ac06SPeter Wemm 			 * counting up
31633b3ac06SPeter Wemm 			 */
31733b3ac06SPeter Wemm 			count = last - first;
31833b3ac06SPeter Wemm 
31933b3ac06SPeter Wemm 			do {
320c3229e05SDavid Greenman 				if (count-- < 0) {	/* completely used? */
321c3229e05SDavid Greenman 					/*
322c3229e05SDavid Greenman 					 * Undo any address bind that may have
323c3229e05SDavid Greenman 					 * occurred above.
324c3229e05SDavid Greenman 					 */
325c3229e05SDavid Greenman 					inp->inp_laddr.s_addr = INADDR_ANY;
326c3229e05SDavid Greenman 					return (EAGAIN);
327c3229e05SDavid Greenman 				}
32833b3ac06SPeter Wemm 				++*lastport;
32933b3ac06SPeter Wemm 				if (*lastport < first || *lastport > last)
33033b3ac06SPeter Wemm 					*lastport = first;
33133b3ac06SPeter Wemm 				lport = htons(*lastport);
332c3229e05SDavid Greenman 			} while (in_pcblookup_local(pcbinfo,
333c3229e05SDavid Greenman 				 inp->inp_laddr, lport, wild));
33433b3ac06SPeter Wemm 		}
33533b3ac06SPeter Wemm 	}
336df8bae1dSRodney W. Grimes 	inp->inp_lport = lport;
337c3229e05SDavid Greenman 	if (in_pcbinshash(inp) != 0) {
338c3229e05SDavid Greenman 		inp->inp_laddr.s_addr = INADDR_ANY;
339c3229e05SDavid Greenman 		inp->inp_lport = 0;
340c3229e05SDavid Greenman 		return (EAGAIN);
341c3229e05SDavid Greenman 	}
342df8bae1dSRodney W. Grimes 	return (0);
343df8bae1dSRodney W. Grimes }
344df8bae1dSRodney W. Grimes 
345999f1343SGarrett Wollman /*
346999f1343SGarrett Wollman  *   Transform old in_pcbconnect() into an inner subroutine for new
347999f1343SGarrett Wollman  *   in_pcbconnect(): Do some validity-checking on the remote
348999f1343SGarrett Wollman  *   address (in mbuf 'nam') and then determine local host address
349999f1343SGarrett Wollman  *   (i.e., which interface) to use to access that remote host.
350999f1343SGarrett Wollman  *
351999f1343SGarrett Wollman  *   This preserves definition of in_pcbconnect(), while supporting a
352999f1343SGarrett Wollman  *   slightly different version for T/TCP.  (This is more than
353999f1343SGarrett Wollman  *   a bit of a kludge, but cleaning up the internal interfaces would
354999f1343SGarrett Wollman  *   have forced minor changes in every protocol).
355999f1343SGarrett Wollman  */
356999f1343SGarrett Wollman 
357999f1343SGarrett Wollman int
358999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin)
359999f1343SGarrett Wollman 	register struct inpcb *inp;
36057bf258eSGarrett Wollman 	struct sockaddr *nam;
361999f1343SGarrett Wollman 	struct sockaddr_in **plocal_sin;
362999f1343SGarrett Wollman {
363df8bae1dSRodney W. Grimes 	struct in_ifaddr *ia;
36457bf258eSGarrett Wollman 	register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
365df8bae1dSRodney W. Grimes 
36657bf258eSGarrett Wollman 	if (nam->sa_len != sizeof (*sin))
367df8bae1dSRodney W. Grimes 		return (EINVAL);
368df8bae1dSRodney W. Grimes 	if (sin->sin_family != AF_INET)
369df8bae1dSRodney W. Grimes 		return (EAFNOSUPPORT);
370df8bae1dSRodney W. Grimes 	if (sin->sin_port == 0)
371df8bae1dSRodney W. Grimes 		return (EADDRNOTAVAIL);
37259562606SGarrett Wollman 	if (!TAILQ_EMPTY(&in_ifaddrhead)) {
373df8bae1dSRodney W. Grimes 		/*
374df8bae1dSRodney W. Grimes 		 * If the destination address is INADDR_ANY,
375df8bae1dSRodney W. Grimes 		 * use the primary local address.
376df8bae1dSRodney W. Grimes 		 * If the supplied address is INADDR_BROADCAST,
377df8bae1dSRodney W. Grimes 		 * and the primary interface supports broadcast,
378df8bae1dSRodney W. Grimes 		 * choose the broadcast address for that interface.
379df8bae1dSRodney W. Grimes 		 */
380df8bae1dSRodney W. Grimes #define	satosin(sa)	((struct sockaddr_in *)(sa))
381df8bae1dSRodney W. Grimes #define sintosa(sin)	((struct sockaddr *)(sin))
382df8bae1dSRodney W. Grimes #define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
383df8bae1dSRodney W. Grimes 		if (sin->sin_addr.s_addr == INADDR_ANY)
38459562606SGarrett Wollman 		    sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
385df8bae1dSRodney W. Grimes 		else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
38659562606SGarrett Wollman 		  (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
38759562606SGarrett Wollman 		    sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
388df8bae1dSRodney W. Grimes 	}
389df8bae1dSRodney W. Grimes 	if (inp->inp_laddr.s_addr == INADDR_ANY) {
390df8bae1dSRodney W. Grimes 		register struct route *ro;
391df8bae1dSRodney W. Grimes 
392df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)0;
393df8bae1dSRodney W. Grimes 		/*
394df8bae1dSRodney W. Grimes 		 * If route is known or can be allocated now,
395df8bae1dSRodney W. Grimes 		 * our src addr is taken from the i/f, else punt.
396df8bae1dSRodney W. Grimes 		 */
397df8bae1dSRodney W. Grimes 		ro = &inp->inp_route;
398df8bae1dSRodney W. Grimes 		if (ro->ro_rt &&
399df8bae1dSRodney W. Grimes 		    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
400df8bae1dSRodney W. Grimes 			sin->sin_addr.s_addr ||
401df8bae1dSRodney W. Grimes 		    inp->inp_socket->so_options & SO_DONTROUTE)) {
402df8bae1dSRodney W. Grimes 			RTFREE(ro->ro_rt);
403df8bae1dSRodney W. Grimes 			ro->ro_rt = (struct rtentry *)0;
404df8bae1dSRodney W. Grimes 		}
405df8bae1dSRodney W. Grimes 		if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
406df8bae1dSRodney W. Grimes 		    (ro->ro_rt == (struct rtentry *)0 ||
407df8bae1dSRodney W. Grimes 		    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
408df8bae1dSRodney W. Grimes 			/* No route yet, so try to acquire one */
409df8bae1dSRodney W. Grimes 			ro->ro_dst.sa_family = AF_INET;
410df8bae1dSRodney W. Grimes 			ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
411df8bae1dSRodney W. Grimes 			((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
412df8bae1dSRodney W. Grimes 				sin->sin_addr;
413df8bae1dSRodney W. Grimes 			rtalloc(ro);
414df8bae1dSRodney W. Grimes 		}
415df8bae1dSRodney W. Grimes 		/*
416df8bae1dSRodney W. Grimes 		 * If we found a route, use the address
417df8bae1dSRodney W. Grimes 		 * corresponding to the outgoing interface
418df8bae1dSRodney W. Grimes 		 * unless it is the loopback (in case a route
419df8bae1dSRodney W. Grimes 		 * to our address on another net goes to loopback).
420df8bae1dSRodney W. Grimes 		 */
421df8bae1dSRodney W. Grimes 		if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
422df8bae1dSRodney W. Grimes 			ia = ifatoia(ro->ro_rt->rt_ifa);
423df8bae1dSRodney W. Grimes 		if (ia == 0) {
424df8bae1dSRodney W. Grimes 			u_short fport = sin->sin_port;
425df8bae1dSRodney W. Grimes 
426df8bae1dSRodney W. Grimes 			sin->sin_port = 0;
427df8bae1dSRodney W. Grimes 			ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
428df8bae1dSRodney W. Grimes 			if (ia == 0)
429df8bae1dSRodney W. Grimes 				ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
430df8bae1dSRodney W. Grimes 			sin->sin_port = fport;
431df8bae1dSRodney W. Grimes 			if (ia == 0)
43259562606SGarrett Wollman 				ia = in_ifaddrhead.tqh_first;
433df8bae1dSRodney W. Grimes 			if (ia == 0)
434df8bae1dSRodney W. Grimes 				return (EADDRNOTAVAIL);
435df8bae1dSRodney W. Grimes 		}
436df8bae1dSRodney W. Grimes 		/*
437df8bae1dSRodney W. Grimes 		 * If the destination address is multicast and an outgoing
438df8bae1dSRodney W. Grimes 		 * interface has been set as a multicast option, use the
439df8bae1dSRodney W. Grimes 		 * address of that interface as our source address.
440df8bae1dSRodney W. Grimes 		 */
441df8bae1dSRodney W. Grimes 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
442df8bae1dSRodney W. Grimes 		    inp->inp_moptions != NULL) {
443df8bae1dSRodney W. Grimes 			struct ip_moptions *imo;
444df8bae1dSRodney W. Grimes 			struct ifnet *ifp;
445df8bae1dSRodney W. Grimes 
446df8bae1dSRodney W. Grimes 			imo = inp->inp_moptions;
447df8bae1dSRodney W. Grimes 			if (imo->imo_multicast_ifp != NULL) {
448df8bae1dSRodney W. Grimes 				ifp = imo->imo_multicast_ifp;
44959562606SGarrett Wollman 				for (ia = in_ifaddrhead.tqh_first; ia;
45059562606SGarrett Wollman 				     ia = ia->ia_link.tqe_next)
451df8bae1dSRodney W. Grimes 					if (ia->ia_ifp == ifp)
452df8bae1dSRodney W. Grimes 						break;
453df8bae1dSRodney W. Grimes 				if (ia == 0)
454df8bae1dSRodney W. Grimes 					return (EADDRNOTAVAIL);
455df8bae1dSRodney W. Grimes 			}
456df8bae1dSRodney W. Grimes 		}
457999f1343SGarrett Wollman 	/*
458999f1343SGarrett Wollman 	 * Don't do pcblookup call here; return interface in plocal_sin
459999f1343SGarrett Wollman 	 * and exit to caller, that will do the lookup.
460999f1343SGarrett Wollman 	 */
461999f1343SGarrett Wollman 		*plocal_sin = &ia->ia_addr;
462999f1343SGarrett Wollman 
463999f1343SGarrett Wollman 	}
464999f1343SGarrett Wollman 	return(0);
465999f1343SGarrett Wollman }
466999f1343SGarrett Wollman 
467999f1343SGarrett Wollman /*
468999f1343SGarrett Wollman  * Outer subroutine:
469999f1343SGarrett Wollman  * Connect from a socket to a specified address.
470999f1343SGarrett Wollman  * Both address and port must be specified in argument sin.
471999f1343SGarrett Wollman  * If don't have a local address for this socket yet,
472999f1343SGarrett Wollman  * then pick one.
473999f1343SGarrett Wollman  */
474999f1343SGarrett Wollman int
475a29f300eSGarrett Wollman in_pcbconnect(inp, nam, p)
476999f1343SGarrett Wollman 	register struct inpcb *inp;
47757bf258eSGarrett Wollman 	struct sockaddr *nam;
478a29f300eSGarrett Wollman 	struct proc *p;
479999f1343SGarrett Wollman {
480999f1343SGarrett Wollman 	struct sockaddr_in *ifaddr;
48157bf258eSGarrett Wollman 	register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
482999f1343SGarrett Wollman 	int error;
483999f1343SGarrett Wollman 
484999f1343SGarrett Wollman 	/*
485999f1343SGarrett Wollman 	 *   Call inner routine, to assign local interface address.
486999f1343SGarrett Wollman 	 */
487831a80b0SMatthew Dillon 	if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
488999f1343SGarrett Wollman 		return(error);
489999f1343SGarrett Wollman 
490c3229e05SDavid Greenman 	if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
491df8bae1dSRodney W. Grimes 	    inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
492cfa1ca9dSYoshinobu Inoue 	    inp->inp_lport, 0, NULL) != NULL) {
493df8bae1dSRodney W. Grimes 		return (EADDRINUSE);
494c3229e05SDavid Greenman 	}
495df8bae1dSRodney W. Grimes 	if (inp->inp_laddr.s_addr == INADDR_ANY) {
4965a903f8dSPierre Beyssac 		if (inp->inp_lport == 0) {
4975a903f8dSPierre Beyssac 			error = in_pcbbind(inp, (struct sockaddr *)0, p);
4985a903f8dSPierre Beyssac 			if (error)
4995a903f8dSPierre Beyssac 			    return (error);
5005a903f8dSPierre Beyssac 		}
501df8bae1dSRodney W. Grimes 		inp->inp_laddr = ifaddr->sin_addr;
502df8bae1dSRodney W. Grimes 	}
503df8bae1dSRodney W. Grimes 	inp->inp_faddr = sin->sin_addr;
504df8bae1dSRodney W. Grimes 	inp->inp_fport = sin->sin_port;
50515bd2b43SDavid Greenman 	in_pcbrehash(inp);
506df8bae1dSRodney W. Grimes 	return (0);
507df8bae1dSRodney W. Grimes }
508df8bae1dSRodney W. Grimes 
50926f9a767SRodney W. Grimes void
510df8bae1dSRodney W. Grimes in_pcbdisconnect(inp)
511df8bae1dSRodney W. Grimes 	struct inpcb *inp;
512df8bae1dSRodney W. Grimes {
513df8bae1dSRodney W. Grimes 
514df8bae1dSRodney W. Grimes 	inp->inp_faddr.s_addr = INADDR_ANY;
515df8bae1dSRodney W. Grimes 	inp->inp_fport = 0;
51615bd2b43SDavid Greenman 	in_pcbrehash(inp);
517df8bae1dSRodney W. Grimes 	if (inp->inp_socket->so_state & SS_NOFDREF)
518df8bae1dSRodney W. Grimes 		in_pcbdetach(inp);
519df8bae1dSRodney W. Grimes }
520df8bae1dSRodney W. Grimes 
52126f9a767SRodney W. Grimes void
522df8bae1dSRodney W. Grimes in_pcbdetach(inp)
523df8bae1dSRodney W. Grimes 	struct inpcb *inp;
524df8bae1dSRodney W. Grimes {
525df8bae1dSRodney W. Grimes 	struct socket *so = inp->inp_socket;
5263d4d47f3SGarrett Wollman 	struct inpcbinfo *ipi = inp->inp_pcbinfo;
527df8bae1dSRodney W. Grimes 
528cfa1ca9dSYoshinobu Inoue #ifdef IPSEC
529cfa1ca9dSYoshinobu Inoue 	ipsec4_delete_pcbpolicy(inp);
530cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/
5313d4d47f3SGarrett Wollman 	inp->inp_gencnt = ++ipi->ipi_gencnt;
532c3229e05SDavid Greenman 	in_pcbremlists(inp);
533df8bae1dSRodney W. Grimes 	so->so_pcb = 0;
534df8bae1dSRodney W. Grimes 	sofree(so);
535df8bae1dSRodney W. Grimes 	if (inp->inp_options)
536df8bae1dSRodney W. Grimes 		(void)m_free(inp->inp_options);
537df8bae1dSRodney W. Grimes 	if (inp->inp_route.ro_rt)
538df8bae1dSRodney W. Grimes 		rtfree(inp->inp_route.ro_rt);
539df8bae1dSRodney W. Grimes 	ip_freemoptions(inp->inp_moptions);
540cfa1ca9dSYoshinobu Inoue 	inp->inp_vflag = 0;
5413d4d47f3SGarrett Wollman 	zfreei(ipi->ipi_zone, inp);
542df8bae1dSRodney W. Grimes }
543df8bae1dSRodney W. Grimes 
544117bcae7SGarrett Wollman /*
545117bcae7SGarrett Wollman  * The calling convention of in_setsockaddr() and in_setpeeraddr() was
546117bcae7SGarrett Wollman  * modified to match the pru_sockaddr() and pru_peeraddr() entry points
547117bcae7SGarrett Wollman  * in struct pr_usrreqs, so that protocols can just reference then directly
548117bcae7SGarrett Wollman  * without the need for a wrapper function.  The socket must have a valid
549117bcae7SGarrett Wollman  * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
550117bcae7SGarrett Wollman  * except through a kernel programming error, so it is acceptable to panic
55157bf258eSGarrett Wollman  * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
55257bf258eSGarrett Wollman  * because there actually /is/ a programming error somewhere... XXX)
553117bcae7SGarrett Wollman  */
554117bcae7SGarrett Wollman int
555117bcae7SGarrett Wollman in_setsockaddr(so, nam)
556117bcae7SGarrett Wollman 	struct socket *so;
55757bf258eSGarrett Wollman 	struct sockaddr **nam;
558df8bae1dSRodney W. Grimes {
559fdc984f7STor Egge 	int s;
560fdc984f7STor Egge 	register struct inpcb *inp;
561df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
562df8bae1dSRodney W. Grimes 
563c3229e05SDavid Greenman 	/*
564c3229e05SDavid Greenman 	 * Do the malloc first in case it blocks.
565c3229e05SDavid Greenman 	 */
56642fa505bSDavid Greenman 	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
56742fa505bSDavid Greenman 	bzero(sin, sizeof *sin);
56842fa505bSDavid Greenman 	sin->sin_family = AF_INET;
56942fa505bSDavid Greenman 	sin->sin_len = sizeof(*sin);
57042fa505bSDavid Greenman 
571fdc984f7STor Egge 	s = splnet();
572fdc984f7STor Egge 	inp = sotoinpcb(so);
573db112f04STor Egge 	if (!inp) {
574db112f04STor Egge 		splx(s);
57542fa505bSDavid Greenman 		free(sin, M_SONAME);
576db112f04STor Egge 		return EINVAL;
577db112f04STor Egge 	}
578df8bae1dSRodney W. Grimes 	sin->sin_port = inp->inp_lport;
579df8bae1dSRodney W. Grimes 	sin->sin_addr = inp->inp_laddr;
580db112f04STor Egge 	splx(s);
58142fa505bSDavid Greenman 
58242fa505bSDavid Greenman 	*nam = (struct sockaddr *)sin;
583117bcae7SGarrett Wollman 	return 0;
584df8bae1dSRodney W. Grimes }
585df8bae1dSRodney W. Grimes 
586117bcae7SGarrett Wollman int
587117bcae7SGarrett Wollman in_setpeeraddr(so, nam)
588117bcae7SGarrett Wollman 	struct socket *so;
58957bf258eSGarrett Wollman 	struct sockaddr **nam;
590df8bae1dSRodney W. Grimes {
591fdc984f7STor Egge 	int s;
592fdc984f7STor Egge 	struct inpcb *inp;
593df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
594df8bae1dSRodney W. Grimes 
595c3229e05SDavid Greenman 	/*
596c3229e05SDavid Greenman 	 * Do the malloc first in case it blocks.
597c3229e05SDavid Greenman 	 */
59842fa505bSDavid Greenman 	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
59942fa505bSDavid Greenman 	bzero((caddr_t)sin, sizeof (*sin));
60042fa505bSDavid Greenman 	sin->sin_family = AF_INET;
60142fa505bSDavid Greenman 	sin->sin_len = sizeof(*sin);
60242fa505bSDavid Greenman 
603fdc984f7STor Egge 	s = splnet();
604fdc984f7STor Egge 	inp = sotoinpcb(so);
605db112f04STor Egge 	if (!inp) {
606db112f04STor Egge 		splx(s);
60742fa505bSDavid Greenman 		free(sin, M_SONAME);
608db112f04STor Egge 		return EINVAL;
609db112f04STor Egge 	}
610df8bae1dSRodney W. Grimes 	sin->sin_port = inp->inp_fport;
611df8bae1dSRodney W. Grimes 	sin->sin_addr = inp->inp_faddr;
612db112f04STor Egge 	splx(s);
61342fa505bSDavid Greenman 
61442fa505bSDavid Greenman 	*nam = (struct sockaddr *)sin;
615117bcae7SGarrett Wollman 	return 0;
616df8bae1dSRodney W. Grimes }
617df8bae1dSRodney W. Grimes 
618df8bae1dSRodney W. Grimes /*
619df8bae1dSRodney W. Grimes  * Pass some notification to all connections of a protocol
620df8bae1dSRodney W. Grimes  * associated with address dst.  The local address and/or port numbers
621df8bae1dSRodney W. Grimes  * may be specified to limit the search.  The "usual action" will be
622df8bae1dSRodney W. Grimes  * taken, depending on the ctlinput cmd.  The caller must filter any
623df8bae1dSRodney W. Grimes  * cmds that are uninteresting (e.g., no error in the map).
624df8bae1dSRodney W. Grimes  * Call the protocol specific routine (if any) to report
625df8bae1dSRodney W. Grimes  * any errors for each matching socket.
626df8bae1dSRodney W. Grimes  */
62726f9a767SRodney W. Grimes void
628df8bae1dSRodney W. Grimes in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
62915bd2b43SDavid Greenman 	struct inpcbhead *head;
630df8bae1dSRodney W. Grimes 	struct sockaddr *dst;
631df8bae1dSRodney W. Grimes 	u_int fport_arg, lport_arg;
632df8bae1dSRodney W. Grimes 	struct in_addr laddr;
633df8bae1dSRodney W. Grimes 	int cmd;
634df8bae1dSRodney W. Grimes 	void (*notify) __P((struct inpcb *, int));
635df8bae1dSRodney W. Grimes {
636df8bae1dSRodney W. Grimes 	register struct inpcb *inp, *oinp;
637df8bae1dSRodney W. Grimes 	struct in_addr faddr;
638df8bae1dSRodney W. Grimes 	u_short fport = fport_arg, lport = lport_arg;
6397bc4aca7SDavid Greenman 	int errno, s;
640df8bae1dSRodney W. Grimes 
641df8bae1dSRodney W. Grimes 	if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
642df8bae1dSRodney W. Grimes 		return;
643df8bae1dSRodney W. Grimes 	faddr = ((struct sockaddr_in *)dst)->sin_addr;
644df8bae1dSRodney W. Grimes 	if (faddr.s_addr == INADDR_ANY)
645df8bae1dSRodney W. Grimes 		return;
646df8bae1dSRodney W. Grimes 
647df8bae1dSRodney W. Grimes 	/*
648df8bae1dSRodney W. Grimes 	 * Redirects go to all references to the destination,
649df8bae1dSRodney W. Grimes 	 * and use in_rtchange to invalidate the route cache.
650df8bae1dSRodney W. Grimes 	 * Dead host indications: notify all references to the destination.
651df8bae1dSRodney W. Grimes 	 * Otherwise, if we have knowledge of the local port and address,
652df8bae1dSRodney W. Grimes 	 * deliver only to that socket.
653df8bae1dSRodney W. Grimes 	 */
654df8bae1dSRodney W. Grimes 	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
655df8bae1dSRodney W. Grimes 		fport = 0;
656df8bae1dSRodney W. Grimes 		lport = 0;
657df8bae1dSRodney W. Grimes 		laddr.s_addr = 0;
658df8bae1dSRodney W. Grimes 		if (cmd != PRC_HOSTDEAD)
659df8bae1dSRodney W. Grimes 			notify = in_rtchange;
660df8bae1dSRodney W. Grimes 	}
661df8bae1dSRodney W. Grimes 	errno = inetctlerrmap[cmd];
6627bc4aca7SDavid Greenman 	s = splnet();
66315bd2b43SDavid Greenman 	for (inp = head->lh_first; inp != NULL;) {
664cfa1ca9dSYoshinobu Inoue #ifdef INET6
665cfa1ca9dSYoshinobu Inoue 		if ((inp->inp_vflag & INP_IPV4) == NULL) {
666cfa1ca9dSYoshinobu Inoue 			inp = LIST_NEXT(inp, inp_list);
667cfa1ca9dSYoshinobu Inoue 			continue;
668cfa1ca9dSYoshinobu Inoue 		}
669cfa1ca9dSYoshinobu Inoue #endif
670df8bae1dSRodney W. Grimes 		if (inp->inp_faddr.s_addr != faddr.s_addr ||
671df8bae1dSRodney W. Grimes 		    inp->inp_socket == 0 ||
672df8bae1dSRodney W. Grimes 		    (lport && inp->inp_lport != lport) ||
673df8bae1dSRodney W. Grimes 		    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
674df8bae1dSRodney W. Grimes 		    (fport && inp->inp_fport != fport)) {
67515bd2b43SDavid Greenman 			inp = inp->inp_list.le_next;
676df8bae1dSRodney W. Grimes 			continue;
677df8bae1dSRodney W. Grimes 		}
678df8bae1dSRodney W. Grimes 		oinp = inp;
67915bd2b43SDavid Greenman 		inp = inp->inp_list.le_next;
680df8bae1dSRodney W. Grimes 		if (notify)
681df8bae1dSRodney W. Grimes 			(*notify)(oinp, errno);
682df8bae1dSRodney W. Grimes 	}
6837bc4aca7SDavid Greenman 	splx(s);
684df8bae1dSRodney W. Grimes }
685df8bae1dSRodney W. Grimes 
686df8bae1dSRodney W. Grimes /*
687df8bae1dSRodney W. Grimes  * Check for alternatives when higher level complains
688df8bae1dSRodney W. Grimes  * about service problems.  For now, invalidate cached
689df8bae1dSRodney W. Grimes  * routing information.  If the route was created dynamically
690df8bae1dSRodney W. Grimes  * (by a redirect), time to try a default gateway again.
691df8bae1dSRodney W. Grimes  */
69226f9a767SRodney W. Grimes void
693df8bae1dSRodney W. Grimes in_losing(inp)
694df8bae1dSRodney W. Grimes 	struct inpcb *inp;
695df8bae1dSRodney W. Grimes {
696df8bae1dSRodney W. Grimes 	register struct rtentry *rt;
697df8bae1dSRodney W. Grimes 	struct rt_addrinfo info;
698df8bae1dSRodney W. Grimes 
699df8bae1dSRodney W. Grimes 	if ((rt = inp->inp_route.ro_rt)) {
700df8bae1dSRodney W. Grimes 		inp->inp_route.ro_rt = 0;
701df8bae1dSRodney W. Grimes 		bzero((caddr_t)&info, sizeof(info));
702df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_DST] =
703df8bae1dSRodney W. Grimes 			(struct sockaddr *)&inp->inp_route.ro_dst;
704df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
705df8bae1dSRodney W. Grimes 		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
706df8bae1dSRodney W. Grimes 		rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
707df8bae1dSRodney W. Grimes 		if (rt->rt_flags & RTF_DYNAMIC)
708df8bae1dSRodney W. Grimes 			(void) rtrequest(RTM_DELETE, rt_key(rt),
709df8bae1dSRodney W. Grimes 				rt->rt_gateway, rt_mask(rt), rt->rt_flags,
710df8bae1dSRodney W. Grimes 				(struct rtentry **)0);
711df8bae1dSRodney W. Grimes 		else
712df8bae1dSRodney W. Grimes 		/*
713df8bae1dSRodney W. Grimes 		 * A new route can be allocated
714df8bae1dSRodney W. Grimes 		 * the next time output is attempted.
715df8bae1dSRodney W. Grimes 		 */
716df8bae1dSRodney W. Grimes 			rtfree(rt);
717df8bae1dSRodney W. Grimes 	}
718df8bae1dSRodney W. Grimes }
719df8bae1dSRodney W. Grimes 
720df8bae1dSRodney W. Grimes /*
721df8bae1dSRodney W. Grimes  * After a routing change, flush old routing
722df8bae1dSRodney W. Grimes  * and allocate a (hopefully) better one.
723df8bae1dSRodney W. Grimes  */
7240312fbe9SPoul-Henning Kamp static void
725df8bae1dSRodney W. Grimes in_rtchange(inp, errno)
726df8bae1dSRodney W. Grimes 	register struct inpcb *inp;
727df8bae1dSRodney W. Grimes 	int errno;
728df8bae1dSRodney W. Grimes {
729df8bae1dSRodney W. Grimes 	if (inp->inp_route.ro_rt) {
730df8bae1dSRodney W. Grimes 		rtfree(inp->inp_route.ro_rt);
731df8bae1dSRodney W. Grimes 		inp->inp_route.ro_rt = 0;
732df8bae1dSRodney W. Grimes 		/*
733df8bae1dSRodney W. Grimes 		 * A new route can be allocated the next time
734df8bae1dSRodney W. Grimes 		 * output is attempted.
735df8bae1dSRodney W. Grimes 		 */
736df8bae1dSRodney W. Grimes 	}
737df8bae1dSRodney W. Grimes }
738df8bae1dSRodney W. Grimes 
739c3229e05SDavid Greenman /*
740c3229e05SDavid Greenman  * Lookup a PCB based on the local address and port.
741c3229e05SDavid Greenman  */
742df8bae1dSRodney W. Grimes struct inpcb *
743c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
7446d6a026bSDavid Greenman 	struct inpcbinfo *pcbinfo;
745c3229e05SDavid Greenman 	struct in_addr laddr;
746c3229e05SDavid Greenman 	u_int lport_arg;
7476d6a026bSDavid Greenman 	int wild_okay;
748df8bae1dSRodney W. Grimes {
749f1d19042SArchie Cobbs 	register struct inpcb *inp;
750df8bae1dSRodney W. Grimes 	int matchwild = 3, wildcard;
751c3229e05SDavid Greenman 	u_short lport = lport_arg;
7527bc4aca7SDavid Greenman 
753c3229e05SDavid Greenman 	if (!wild_okay) {
754c3229e05SDavid Greenman 		struct inpcbhead *head;
755c3229e05SDavid Greenman 		/*
756c3229e05SDavid Greenman 		 * Look for an unconnected (wildcard foreign addr) PCB that
757c3229e05SDavid Greenman 		 * matches the local address and port we're looking for.
758c3229e05SDavid Greenman 		 */
759c3229e05SDavid Greenman 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
760c3229e05SDavid Greenman 		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
761cfa1ca9dSYoshinobu Inoue #ifdef INET6
762cfa1ca9dSYoshinobu Inoue 			if ((inp->inp_vflag & INP_IPV4) == NULL)
763cfa1ca9dSYoshinobu Inoue 				continue;
764cfa1ca9dSYoshinobu Inoue #endif
765c3229e05SDavid Greenman 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
766c3229e05SDavid Greenman 			    inp->inp_laddr.s_addr == laddr.s_addr &&
767c3229e05SDavid Greenman 			    inp->inp_lport == lport) {
768c3229e05SDavid Greenman 				/*
769c3229e05SDavid Greenman 				 * Found.
770c3229e05SDavid Greenman 				 */
771c3229e05SDavid Greenman 				return (inp);
772df8bae1dSRodney W. Grimes 			}
773c3229e05SDavid Greenman 		}
774c3229e05SDavid Greenman 		/*
775c3229e05SDavid Greenman 		 * Not found.
776c3229e05SDavid Greenman 		 */
777c3229e05SDavid Greenman 		return (NULL);
778c3229e05SDavid Greenman 	} else {
779c3229e05SDavid Greenman 		struct inpcbporthead *porthash;
780c3229e05SDavid Greenman 		struct inpcbport *phd;
781c3229e05SDavid Greenman 		struct inpcb *match = NULL;
782c3229e05SDavid Greenman 		/*
783c3229e05SDavid Greenman 		 * Best fit PCB lookup.
784c3229e05SDavid Greenman 		 *
785c3229e05SDavid Greenman 		 * First see if this local port is in use by looking on the
786c3229e05SDavid Greenman 		 * port hash list.
787c3229e05SDavid Greenman 		 */
788c3229e05SDavid Greenman 		porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
789c3229e05SDavid Greenman 		    pcbinfo->porthashmask)];
790c3229e05SDavid Greenman 		for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
791c3229e05SDavid Greenman 			if (phd->phd_port == lport)
792c3229e05SDavid Greenman 				break;
793c3229e05SDavid Greenman 		}
794c3229e05SDavid Greenman 		if (phd != NULL) {
795c3229e05SDavid Greenman 			/*
796c3229e05SDavid Greenman 			 * Port is in use by one or more PCBs. Look for best
797c3229e05SDavid Greenman 			 * fit.
798c3229e05SDavid Greenman 			 */
799c3229e05SDavid Greenman 			for (inp = phd->phd_pcblist.lh_first; inp != NULL;
800c3229e05SDavid Greenman 			    inp = inp->inp_portlist.le_next) {
801c3229e05SDavid Greenman 				wildcard = 0;
802cfa1ca9dSYoshinobu Inoue #ifdef INET6
803cfa1ca9dSYoshinobu Inoue 				if ((inp->inp_vflag & INP_IPV4) == NULL)
804cfa1ca9dSYoshinobu Inoue 					continue;
805cfa1ca9dSYoshinobu Inoue #endif
806c3229e05SDavid Greenman 				if (inp->inp_faddr.s_addr != INADDR_ANY)
807c3229e05SDavid Greenman 					wildcard++;
80815bd2b43SDavid Greenman 				if (inp->inp_laddr.s_addr != INADDR_ANY) {
80915bd2b43SDavid Greenman 					if (laddr.s_addr == INADDR_ANY)
81015bd2b43SDavid Greenman 						wildcard++;
81115bd2b43SDavid Greenman 					else if (inp->inp_laddr.s_addr != laddr.s_addr)
81215bd2b43SDavid Greenman 						continue;
81315bd2b43SDavid Greenman 				} else {
81415bd2b43SDavid Greenman 					if (laddr.s_addr != INADDR_ANY)
81515bd2b43SDavid Greenman 						wildcard++;
81615bd2b43SDavid Greenman 				}
817df8bae1dSRodney W. Grimes 				if (wildcard < matchwild) {
818df8bae1dSRodney W. Grimes 					match = inp;
819df8bae1dSRodney W. Grimes 					matchwild = wildcard;
8203dbdc25cSDavid Greenman 					if (matchwild == 0) {
821df8bae1dSRodney W. Grimes 						break;
822df8bae1dSRodney W. Grimes 					}
823df8bae1dSRodney W. Grimes 				}
8243dbdc25cSDavid Greenman 			}
825c3229e05SDavid Greenman 		}
826df8bae1dSRodney W. Grimes 		return (match);
827df8bae1dSRodney W. Grimes 	}
828c3229e05SDavid Greenman }
82915bd2b43SDavid Greenman 
83015bd2b43SDavid Greenman /*
83115bd2b43SDavid Greenman  * Lookup PCB in hash list.
83215bd2b43SDavid Greenman  */
83315bd2b43SDavid Greenman struct inpcb *
834cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
835cfa1ca9dSYoshinobu Inoue 		  ifp)
83615bd2b43SDavid Greenman 	struct inpcbinfo *pcbinfo;
83715bd2b43SDavid Greenman 	struct in_addr faddr, laddr;
83815bd2b43SDavid Greenman 	u_int fport_arg, lport_arg;
8396d6a026bSDavid Greenman 	int wildcard;
840cfa1ca9dSYoshinobu Inoue 	struct ifnet *ifp;
84115bd2b43SDavid Greenman {
84215bd2b43SDavid Greenman 	struct inpcbhead *head;
84315bd2b43SDavid Greenman 	register struct inpcb *inp;
84415bd2b43SDavid Greenman 	u_short fport = fport_arg, lport = lport_arg;
84515bd2b43SDavid Greenman 
84615bd2b43SDavid Greenman 	/*
84715bd2b43SDavid Greenman 	 * First look for an exact match.
84815bd2b43SDavid Greenman 	 */
849ddd79a97SDavid Greenman 	head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
85015bd2b43SDavid Greenman 	for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
851cfa1ca9dSYoshinobu Inoue #ifdef INET6
852cfa1ca9dSYoshinobu Inoue 		if ((inp->inp_vflag & INP_IPV4) == NULL)
853cfa1ca9dSYoshinobu Inoue 			continue;
854cfa1ca9dSYoshinobu Inoue #endif
8556d6a026bSDavid Greenman 		if (inp->inp_faddr.s_addr == faddr.s_addr &&
856ca98b82cSDavid Greenman 		    inp->inp_laddr.s_addr == laddr.s_addr &&
857ca98b82cSDavid Greenman 		    inp->inp_fport == fport &&
858c3229e05SDavid Greenman 		    inp->inp_lport == lport) {
859c3229e05SDavid Greenman 			/*
860c3229e05SDavid Greenman 			 * Found.
861c3229e05SDavid Greenman 			 */
862c3229e05SDavid Greenman 			return (inp);
863c3229e05SDavid Greenman 		}
8646d6a026bSDavid Greenman 	}
8656d6a026bSDavid Greenman 	if (wildcard) {
8666d6a026bSDavid Greenman 		struct inpcb *local_wild = NULL;
867cfa1ca9dSYoshinobu Inoue #if defined(INET6)
868cfa1ca9dSYoshinobu Inoue 		struct inpcb *local_wild_mapped = NULL;
869cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
8706d6a026bSDavid Greenman 
871ddd79a97SDavid Greenman 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
8726d6a026bSDavid Greenman 		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
873cfa1ca9dSYoshinobu Inoue #ifdef INET6
874cfa1ca9dSYoshinobu Inoue 			if ((inp->inp_vflag & INP_IPV4) == NULL)
875cfa1ca9dSYoshinobu Inoue 				continue;
876cfa1ca9dSYoshinobu Inoue #endif
8776d6a026bSDavid Greenman 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
878c3229e05SDavid Greenman 			    inp->inp_lport == lport) {
879cfa1ca9dSYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0
880cfa1ca9dSYoshinobu Inoue 				if (ifp && ifp->if_type == IFT_FAITH &&
881cfa1ca9dSYoshinobu Inoue 				    (inp->inp_flags & INP_FAITH) == 0)
882cfa1ca9dSYoshinobu Inoue 					continue;
883cfa1ca9dSYoshinobu Inoue #endif
8846d6a026bSDavid Greenman 				if (inp->inp_laddr.s_addr == laddr.s_addr)
885c3229e05SDavid Greenman 					return (inp);
886cfa1ca9dSYoshinobu Inoue 				else if (inp->inp_laddr.s_addr == INADDR_ANY) {
887cfa1ca9dSYoshinobu Inoue #if defined(INET6)
888cfa1ca9dSYoshinobu Inoue 					if (INP_CHECK_SOCKAF(inp->inp_socket,
889cfa1ca9dSYoshinobu Inoue 							     AF_INET6))
890cfa1ca9dSYoshinobu Inoue 						local_wild_mapped = inp;
891cfa1ca9dSYoshinobu Inoue 					else
892cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
8936d6a026bSDavid Greenman 					local_wild = inp;
8946d6a026bSDavid Greenman 				}
8956d6a026bSDavid Greenman 			}
896cfa1ca9dSYoshinobu Inoue 		}
897cfa1ca9dSYoshinobu Inoue #if defined(INET6)
898cfa1ca9dSYoshinobu Inoue 		if (local_wild == NULL)
899cfa1ca9dSYoshinobu Inoue 			return (local_wild_mapped);
900cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */
901c3229e05SDavid Greenman 		return (local_wild);
9026d6a026bSDavid Greenman 	}
903c3229e05SDavid Greenman 
904c3229e05SDavid Greenman 	/*
905c3229e05SDavid Greenman 	 * Not found.
906c3229e05SDavid Greenman 	 */
9076d6a026bSDavid Greenman 	return (NULL);
90815bd2b43SDavid Greenman }
90915bd2b43SDavid Greenman 
9107bc4aca7SDavid Greenman /*
911c3229e05SDavid Greenman  * Insert PCB onto various hash lists.
9127bc4aca7SDavid Greenman  */
913c3229e05SDavid Greenman int
91415bd2b43SDavid Greenman in_pcbinshash(inp)
91515bd2b43SDavid Greenman 	struct inpcb *inp;
91615bd2b43SDavid Greenman {
917c3229e05SDavid Greenman 	struct inpcbhead *pcbhash;
918c3229e05SDavid Greenman 	struct inpcbporthead *pcbporthash;
919c3229e05SDavid Greenman 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
920c3229e05SDavid Greenman 	struct inpcbport *phd;
921cfa1ca9dSYoshinobu Inoue 	u_int32_t hashkey_faddr;
92215bd2b43SDavid Greenman 
923cfa1ca9dSYoshinobu Inoue #ifdef INET6
924cfa1ca9dSYoshinobu Inoue 	if (inp->inp_vflag & INP_IPV6)
925cfa1ca9dSYoshinobu Inoue 		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
926cfa1ca9dSYoshinobu Inoue 	else
927cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
928cfa1ca9dSYoshinobu Inoue 	hashkey_faddr = inp->inp_faddr.s_addr;
929cfa1ca9dSYoshinobu Inoue 
930cfa1ca9dSYoshinobu Inoue 	pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
931c3229e05SDavid Greenman 		 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
93215bd2b43SDavid Greenman 
933c3229e05SDavid Greenman 	pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
934c3229e05SDavid Greenman 	    pcbinfo->porthashmask)];
935c3229e05SDavid Greenman 
936c3229e05SDavid Greenman 	/*
937c3229e05SDavid Greenman 	 * Go through port list and look for a head for this lport.
938c3229e05SDavid Greenman 	 */
939c3229e05SDavid Greenman 	for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
940c3229e05SDavid Greenman 		if (phd->phd_port == inp->inp_lport)
941c3229e05SDavid Greenman 			break;
942c3229e05SDavid Greenman 	}
943c3229e05SDavid Greenman 	/*
944c3229e05SDavid Greenman 	 * If none exists, malloc one and tack it on.
945c3229e05SDavid Greenman 	 */
946c3229e05SDavid Greenman 	if (phd == NULL) {
947c3229e05SDavid Greenman 		MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
948c3229e05SDavid Greenman 		if (phd == NULL) {
949c3229e05SDavid Greenman 			return (ENOBUFS); /* XXX */
950c3229e05SDavid Greenman 		}
951c3229e05SDavid Greenman 		phd->phd_port = inp->inp_lport;
952c3229e05SDavid Greenman 		LIST_INIT(&phd->phd_pcblist);
953c3229e05SDavid Greenman 		LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
954c3229e05SDavid Greenman 	}
955c3229e05SDavid Greenman 	inp->inp_phd = phd;
956c3229e05SDavid Greenman 	LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
957c3229e05SDavid Greenman 	LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
958c3229e05SDavid Greenman 	return (0);
95915bd2b43SDavid Greenman }
96015bd2b43SDavid Greenman 
961c3229e05SDavid Greenman /*
962c3229e05SDavid Greenman  * Move PCB to the proper hash bucket when { faddr, fport } have  been
963c3229e05SDavid Greenman  * changed. NOTE: This does not handle the case of the lport changing (the
964c3229e05SDavid Greenman  * hashed port list would have to be updated as well), so the lport must
965c3229e05SDavid Greenman  * not change after in_pcbinshash() has been called.
966c3229e05SDavid Greenman  */
96715bd2b43SDavid Greenman void
96815bd2b43SDavid Greenman in_pcbrehash(inp)
96915bd2b43SDavid Greenman 	struct inpcb *inp;
97015bd2b43SDavid Greenman {
97115bd2b43SDavid Greenman 	struct inpcbhead *head;
972cfa1ca9dSYoshinobu Inoue 	u_int32_t hashkey_faddr;
97315bd2b43SDavid Greenman 
974cfa1ca9dSYoshinobu Inoue #ifdef INET6
975cfa1ca9dSYoshinobu Inoue 	if (inp->inp_vflag & INP_IPV6)
976cfa1ca9dSYoshinobu Inoue 		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
977cfa1ca9dSYoshinobu Inoue 	else
978cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
979cfa1ca9dSYoshinobu Inoue 	hashkey_faddr = inp->inp_faddr.s_addr;
980cfa1ca9dSYoshinobu Inoue 
981cfa1ca9dSYoshinobu Inoue 	head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
982ddd79a97SDavid Greenman 		inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
98315bd2b43SDavid Greenman 
984c3229e05SDavid Greenman 	LIST_REMOVE(inp, inp_hash);
98515bd2b43SDavid Greenman 	LIST_INSERT_HEAD(head, inp, inp_hash);
986c3229e05SDavid Greenman }
987c3229e05SDavid Greenman 
988c3229e05SDavid Greenman /*
989c3229e05SDavid Greenman  * Remove PCB from various lists.
990c3229e05SDavid Greenman  */
99176429de4SYoshinobu Inoue void
992c3229e05SDavid Greenman in_pcbremlists(inp)
993c3229e05SDavid Greenman 	struct inpcb *inp;
994c3229e05SDavid Greenman {
99598271db4SGarrett Wollman 	inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
996c3229e05SDavid Greenman 	if (inp->inp_lport) {
997c3229e05SDavid Greenman 		struct inpcbport *phd = inp->inp_phd;
998c3229e05SDavid Greenman 
999c3229e05SDavid Greenman 		LIST_REMOVE(inp, inp_hash);
1000c3229e05SDavid Greenman 		LIST_REMOVE(inp, inp_portlist);
1001c3229e05SDavid Greenman 		if (phd->phd_pcblist.lh_first == NULL) {
1002c3229e05SDavid Greenman 			LIST_REMOVE(phd, phd_hash);
1003c3229e05SDavid Greenman 			free(phd, M_PCB);
1004c3229e05SDavid Greenman 		}
1005c3229e05SDavid Greenman 	}
1006c3229e05SDavid Greenman 	LIST_REMOVE(inp, inp_list);
10073d4d47f3SGarrett Wollman 	inp->inp_pcbinfo->ipi_count--;
100815bd2b43SDavid Greenman }
100975c13541SPoul-Henning Kamp 
101075c13541SPoul-Henning Kamp int
101175c13541SPoul-Henning Kamp prison_xinpcb(struct proc *p, struct inpcb *inp)
101275c13541SPoul-Henning Kamp {
101375c13541SPoul-Henning Kamp 	if (!p->p_prison)
101475c13541SPoul-Henning Kamp 		return (0);
101575c13541SPoul-Henning Kamp 	if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip)
101675c13541SPoul-Henning Kamp 		return (0);
101775c13541SPoul-Henning Kamp 	return (1);
101875c13541SPoul-Henning Kamp }
1019