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 #include <netkey/key_debug.h> 76cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */ 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes struct in_addr zeroin_addr; 79df8bae1dSRodney W. Grimes 80bbd42ad0SPeter Wemm static void in_rtchange __P((struct inpcb *, int)); 81bbd42ad0SPeter Wemm 82101f9fc8SPeter Wemm /* 83101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 84101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 85101f9fc8SPeter Wemm */ 8682cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 8782cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 8882cd038dSYoshinobu Inoue int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ 8982cd038dSYoshinobu Inoue int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ 9082cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9182cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 92101f9fc8SPeter Wemm 93bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 94bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 95bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 96bbd42ad0SPeter Wemm 97bbd42ad0SPeter Wemm static int 9882d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check (SYSCTL_HANDLER_ARGS) 99bbd42ad0SPeter Wemm { 100bbd42ad0SPeter Wemm int error = sysctl_handle_int(oidp, 101bbd42ad0SPeter Wemm oidp->oid_arg1, oidp->oid_arg2, req); 102bbd42ad0SPeter Wemm if (!error) { 103bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 104bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 105bbd42ad0SPeter Wemm RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 106bbd42ad0SPeter Wemm RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 107bbd42ad0SPeter Wemm RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 108bbd42ad0SPeter Wemm RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 109bbd42ad0SPeter Wemm } 110bbd42ad0SPeter Wemm return error; 111bbd42ad0SPeter Wemm } 112bbd42ad0SPeter Wemm 113bbd42ad0SPeter Wemm #undef RANGECHK 114bbd42ad0SPeter Wemm 11533b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 11633b3ac06SPeter Wemm 117bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 118bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 119bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 120bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 121bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 122bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 123bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 124bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 125bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 126bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 127bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 128bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 1290312fbe9SPoul-Henning Kamp 130c3229e05SDavid Greenman /* 131c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 132c3229e05SDavid Greenman * 133c3229e05SDavid Greenman * NOTE: It is assumed that most of these functions will be called at 134c3229e05SDavid Greenman * splnet(). XXX - There are, unfortunately, a few exceptions to this 135c3229e05SDavid Greenman * rule that should be fixed. 136c3229e05SDavid Greenman */ 137c3229e05SDavid Greenman 138c3229e05SDavid Greenman /* 139c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 140c3229e05SDavid Greenman */ 141df8bae1dSRodney W. Grimes int 142a29f300eSGarrett Wollman in_pcballoc(so, pcbinfo, p) 143df8bae1dSRodney W. Grimes struct socket *so; 14415bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 145a29f300eSGarrett Wollman struct proc *p; 146df8bae1dSRodney W. Grimes { 147df8bae1dSRodney W. Grimes register struct inpcb *inp; 148df8bae1dSRodney W. Grimes 1493d4d47f3SGarrett Wollman inp = zalloci(pcbinfo->ipi_zone); 150df8bae1dSRodney W. Grimes if (inp == NULL) 151df8bae1dSRodney W. Grimes return (ENOBUFS); 152df8bae1dSRodney W. Grimes bzero((caddr_t)inp, sizeof(*inp)); 1533d4d47f3SGarrett Wollman inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 15415bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 155df8bae1dSRodney W. Grimes inp->inp_socket = so; 15675daea93SPaul Saab #if defined(INET6) 157fdaf052eSYoshinobu Inoue if (ip6_mapped_addr_on) 158fdaf052eSYoshinobu Inoue inp->inp_flags &= ~IN6P_BINDV6ONLY; 159fdaf052eSYoshinobu Inoue else 160fdaf052eSYoshinobu Inoue inp->inp_flags |= IN6P_BINDV6ONLY; 16175daea93SPaul Saab #endif 16215bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 1633d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 164df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 165df8bae1dSRodney W. Grimes return (0); 166df8bae1dSRodney W. Grimes } 167df8bae1dSRodney W. Grimes 168df8bae1dSRodney W. Grimes int 169a29f300eSGarrett Wollman in_pcbbind(inp, nam, p) 170df8bae1dSRodney W. Grimes register struct inpcb *inp; 17157bf258eSGarrett Wollman struct sockaddr *nam; 172a29f300eSGarrett Wollman struct proc *p; 173df8bae1dSRodney W. Grimes { 174df8bae1dSRodney W. Grimes register struct socket *so = inp->inp_socket; 17537bd2b30SPeter Wemm unsigned short *lastport; 17615bd2b43SDavid Greenman struct sockaddr_in *sin; 177c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 178df8bae1dSRodney W. Grimes u_short lport = 0; 179df8bae1dSRodney W. Grimes int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 18075c13541SPoul-Henning Kamp int error, prison = 0; 181df8bae1dSRodney W. Grimes 18259562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 183df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 184df8bae1dSRodney W. Grimes if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 185df8bae1dSRodney W. Grimes return (EINVAL); 186c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 1876d6a026bSDavid Greenman wild = 1; 188df8bae1dSRodney W. Grimes if (nam) { 18957bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 19057bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 191df8bae1dSRodney W. Grimes return (EINVAL); 192df8bae1dSRodney W. Grimes #ifdef notdef 193df8bae1dSRodney W. Grimes /* 194df8bae1dSRodney W. Grimes * We should check the family, but old programs 195df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 196df8bae1dSRodney W. Grimes */ 197df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 198df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 199df8bae1dSRodney W. Grimes #endif 20075c13541SPoul-Henning Kamp if (prison_ip(p, 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 221df8bae1dSRodney W. Grimes /* GROSS */ 22257bf258eSGarrett Wollman if (ntohs(lport) < IPPORT_RESERVED && p && 22375c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT)) 2242469dd60SGarrett Wollman return (EACCES); 22575c13541SPoul-Henning Kamp if (p && p->p_prison) 22675c13541SPoul-Henning Kamp prison = 1; 2272f9a2132SBrian Feldman if (so->so_cred->cr_uid != 0 && 22852b65dbeSBill Fenner !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 2294049a042SGuido van Rooij t = in_pcblookup_local(inp->inp_pcbinfo, 23075c13541SPoul-Henning Kamp sin->sin_addr, lport, 23175c13541SPoul-Henning Kamp prison ? 0 : INPLOOKUP_WILDCARD); 23252b65dbeSBill Fenner if (t && 23352b65dbeSBill Fenner (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 23452b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 23552b65dbeSBill Fenner (t->inp_socket->so_options & 23652b65dbeSBill Fenner SO_REUSEPORT) == 0) && 2372f9a2132SBrian Feldman (so->so_cred->cr_uid != 238cfa1ca9dSYoshinobu Inoue t->inp_socket->so_cred->cr_uid)) { 239cfa1ca9dSYoshinobu Inoue #if defined(INET6) 240fdaf052eSYoshinobu Inoue if ((inp->inp_flags & 241fdaf052eSYoshinobu Inoue IN6P_BINDV6ONLY) != 0 || 242cfa1ca9dSYoshinobu Inoue ntohl(sin->sin_addr.s_addr) != 243cfa1ca9dSYoshinobu Inoue INADDR_ANY || 244cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 245cfa1ca9dSYoshinobu Inoue INADDR_ANY || 246cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 247cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 248cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 2494049a042SGuido van Rooij return (EADDRINUSE); 2504049a042SGuido van Rooij } 251cfa1ca9dSYoshinobu Inoue } 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) 257fdaf052eSYoshinobu Inoue if ((inp->inp_flags & IN6P_BINDV6ONLY) != 0 || 258cfa1ca9dSYoshinobu Inoue ntohl(sin->sin_addr.s_addr) != 259cfa1ca9dSYoshinobu Inoue INADDR_ANY || 260cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 261cfa1ca9dSYoshinobu Inoue INADDR_ANY || 262cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 263cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 264cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 265df8bae1dSRodney W. Grimes return (EADDRINUSE); 266df8bae1dSRodney W. Grimes } 267cfa1ca9dSYoshinobu Inoue } 268df8bae1dSRodney W. Grimes inp->inp_laddr = sin->sin_addr; 269df8bae1dSRodney W. Grimes } 27033b3ac06SPeter Wemm if (lport == 0) { 27133b3ac06SPeter Wemm ushort first, last; 27233b3ac06SPeter Wemm int count; 27333b3ac06SPeter Wemm 27475c13541SPoul-Henning Kamp if (prison_ip(p, 0, &inp->inp_laddr.s_addr )) 27575c13541SPoul-Henning Kamp return (EINVAL); 276321a2846SPoul-Henning Kamp inp->inp_flags |= INP_ANONPORT; 277321a2846SPoul-Henning Kamp 27833b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 27933b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 28033b3ac06SPeter Wemm last = ipport_hilastauto; 281c3229e05SDavid Greenman lastport = &pcbinfo->lasthi; 28233b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 28375c13541SPoul-Henning Kamp if (p && (error = suser_xxx(0, p, PRISON_ROOT))) 284a29f300eSGarrett Wollman return error; 285bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 286bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 287c3229e05SDavid Greenman lastport = &pcbinfo->lastlow; 28833b3ac06SPeter Wemm } else { 28933b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 29033b3ac06SPeter Wemm last = ipport_lastauto; 291c3229e05SDavid Greenman lastport = &pcbinfo->lastport; 29233b3ac06SPeter Wemm } 29333b3ac06SPeter Wemm /* 29433b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 29533b3ac06SPeter Wemm * a deadlock here. 29633b3ac06SPeter Wemm * 29733b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 29833b3ac06SPeter Wemm * is not being tested on each round of the loop. 29933b3ac06SPeter Wemm */ 30033b3ac06SPeter Wemm if (first > last) { 30133b3ac06SPeter Wemm /* 30233b3ac06SPeter Wemm * counting down 30333b3ac06SPeter Wemm */ 30433b3ac06SPeter Wemm count = first - last; 30533b3ac06SPeter Wemm 306df8bae1dSRodney W. Grimes do { 307c3229e05SDavid Greenman if (count-- < 0) { /* completely used? */ 308c3229e05SDavid Greenman /* 309c3229e05SDavid Greenman * Undo any address bind that may have 310c3229e05SDavid Greenman * occurred above. 311c3229e05SDavid Greenman */ 312c3229e05SDavid Greenman inp->inp_laddr.s_addr = INADDR_ANY; 313c3229e05SDavid Greenman return (EAGAIN); 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; 334c3229e05SDavid Greenman return (EAGAIN); 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; 345c3229e05SDavid Greenman if (in_pcbinshash(inp) != 0) { 346c3229e05SDavid Greenman inp->inp_laddr.s_addr = INADDR_ANY; 347c3229e05SDavid Greenman inp->inp_lport = 0; 348c3229e05SDavid Greenman return (EAGAIN); 349c3229e05SDavid Greenman } 350df8bae1dSRodney W. Grimes return (0); 351df8bae1dSRodney W. Grimes } 352df8bae1dSRodney W. Grimes 353999f1343SGarrett Wollman /* 354999f1343SGarrett Wollman * Transform old in_pcbconnect() into an inner subroutine for new 355999f1343SGarrett Wollman * in_pcbconnect(): Do some validity-checking on the remote 356999f1343SGarrett Wollman * address (in mbuf 'nam') and then determine local host address 357999f1343SGarrett Wollman * (i.e., which interface) to use to access that remote host. 358999f1343SGarrett Wollman * 359999f1343SGarrett Wollman * This preserves definition of in_pcbconnect(), while supporting a 360999f1343SGarrett Wollman * slightly different version for T/TCP. (This is more than 361999f1343SGarrett Wollman * a bit of a kludge, but cleaning up the internal interfaces would 362999f1343SGarrett Wollman * have forced minor changes in every protocol). 363999f1343SGarrett Wollman */ 364999f1343SGarrett Wollman 365999f1343SGarrett Wollman int 366999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin) 367999f1343SGarrett Wollman register struct inpcb *inp; 36857bf258eSGarrett Wollman struct sockaddr *nam; 369999f1343SGarrett Wollman struct sockaddr_in **plocal_sin; 370999f1343SGarrett Wollman { 371df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 37257bf258eSGarrett Wollman register struct sockaddr_in *sin = (struct sockaddr_in *)nam; 373df8bae1dSRodney W. Grimes 37457bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 375df8bae1dSRodney W. Grimes return (EINVAL); 376df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 377df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 378df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 379df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 38059562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 381df8bae1dSRodney W. Grimes /* 382df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 383df8bae1dSRodney W. Grimes * use the primary local address. 384df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 385df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 386df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 387df8bae1dSRodney W. Grimes */ 388df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 389df8bae1dSRodney W. Grimes #define sintosa(sin) ((struct sockaddr *)(sin)) 390df8bae1dSRodney W. Grimes #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 391df8bae1dSRodney W. Grimes if (sin->sin_addr.s_addr == INADDR_ANY) 39259562606SGarrett Wollman sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; 393df8bae1dSRodney W. Grimes else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 39459562606SGarrett Wollman (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 39559562606SGarrett Wollman sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; 396df8bae1dSRodney W. Grimes } 397df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 398df8bae1dSRodney W. Grimes register struct route *ro; 399df8bae1dSRodney W. Grimes 400df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * If route is known or can be allocated now, 403df8bae1dSRodney W. Grimes * our src addr is taken from the i/f, else punt. 404df8bae1dSRodney W. Grimes */ 405df8bae1dSRodney W. Grimes ro = &inp->inp_route; 406df8bae1dSRodney W. Grimes if (ro->ro_rt && 407df8bae1dSRodney W. Grimes (satosin(&ro->ro_dst)->sin_addr.s_addr != 408df8bae1dSRodney W. Grimes sin->sin_addr.s_addr || 409df8bae1dSRodney W. Grimes inp->inp_socket->so_options & SO_DONTROUTE)) { 410df8bae1dSRodney W. Grimes RTFREE(ro->ro_rt); 411df8bae1dSRodney W. Grimes ro->ro_rt = (struct rtentry *)0; 412df8bae1dSRodney W. Grimes } 413df8bae1dSRodney W. Grimes if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 414df8bae1dSRodney W. Grimes (ro->ro_rt == (struct rtentry *)0 || 415df8bae1dSRodney W. Grimes ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 416df8bae1dSRodney W. Grimes /* No route yet, so try to acquire one */ 417df8bae1dSRodney W. Grimes ro->ro_dst.sa_family = AF_INET; 418df8bae1dSRodney W. Grimes ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 419df8bae1dSRodney W. Grimes ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 420df8bae1dSRodney W. Grimes sin->sin_addr; 421df8bae1dSRodney W. Grimes rtalloc(ro); 422df8bae1dSRodney W. Grimes } 423df8bae1dSRodney W. Grimes /* 424df8bae1dSRodney W. Grimes * If we found a route, use the address 425df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 426df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 427df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 428df8bae1dSRodney W. Grimes */ 429df8bae1dSRodney W. Grimes if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 430df8bae1dSRodney W. Grimes ia = ifatoia(ro->ro_rt->rt_ifa); 431df8bae1dSRodney W. Grimes if (ia == 0) { 432df8bae1dSRodney W. Grimes u_short fport = sin->sin_port; 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes sin->sin_port = 0; 435df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 436df8bae1dSRodney W. Grimes if (ia == 0) 437df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 438df8bae1dSRodney W. Grimes sin->sin_port = fport; 439df8bae1dSRodney W. Grimes if (ia == 0) 44059562606SGarrett Wollman ia = in_ifaddrhead.tqh_first; 441df8bae1dSRodney W. Grimes if (ia == 0) 442df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes /* 445df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 446df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 447df8bae1dSRodney W. Grimes * address of that interface as our source address. 448df8bae1dSRodney W. Grimes */ 449df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 450df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 451df8bae1dSRodney W. Grimes struct ip_moptions *imo; 452df8bae1dSRodney W. Grimes struct ifnet *ifp; 453df8bae1dSRodney W. Grimes 454df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 455df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 456df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 45759562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 45859562606SGarrett Wollman ia = ia->ia_link.tqe_next) 459df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 460df8bae1dSRodney W. Grimes break; 461df8bae1dSRodney W. Grimes if (ia == 0) 462df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 463df8bae1dSRodney W. Grimes } 464df8bae1dSRodney W. Grimes } 465999f1343SGarrett Wollman /* 466999f1343SGarrett Wollman * Don't do pcblookup call here; return interface in plocal_sin 467999f1343SGarrett Wollman * and exit to caller, that will do the lookup. 468999f1343SGarrett Wollman */ 469999f1343SGarrett Wollman *plocal_sin = &ia->ia_addr; 470999f1343SGarrett Wollman 471999f1343SGarrett Wollman } 472999f1343SGarrett Wollman return(0); 473999f1343SGarrett Wollman } 474999f1343SGarrett Wollman 475999f1343SGarrett Wollman /* 476999f1343SGarrett Wollman * Outer subroutine: 477999f1343SGarrett Wollman * Connect from a socket to a specified address. 478999f1343SGarrett Wollman * Both address and port must be specified in argument sin. 479999f1343SGarrett Wollman * If don't have a local address for this socket yet, 480999f1343SGarrett Wollman * then pick one. 481999f1343SGarrett Wollman */ 482999f1343SGarrett Wollman int 483a29f300eSGarrett Wollman in_pcbconnect(inp, nam, p) 484999f1343SGarrett Wollman register struct inpcb *inp; 48557bf258eSGarrett Wollman struct sockaddr *nam; 486a29f300eSGarrett Wollman struct proc *p; 487999f1343SGarrett Wollman { 488999f1343SGarrett Wollman struct sockaddr_in *ifaddr; 48957bf258eSGarrett Wollman register struct sockaddr_in *sin = (struct sockaddr_in *)nam; 490999f1343SGarrett Wollman int error; 491999f1343SGarrett Wollman 492999f1343SGarrett Wollman /* 493999f1343SGarrett Wollman * Call inner routine, to assign local interface address. 494999f1343SGarrett Wollman */ 495831a80b0SMatthew Dillon if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0) 496999f1343SGarrett Wollman return(error); 497999f1343SGarrett Wollman 498c3229e05SDavid Greenman if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 499df8bae1dSRodney W. Grimes inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 500cfa1ca9dSYoshinobu Inoue inp->inp_lport, 0, NULL) != NULL) { 501df8bae1dSRodney W. Grimes return (EADDRINUSE); 502c3229e05SDavid Greenman } 503df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 5045a903f8dSPierre Beyssac if (inp->inp_lport == 0) { 5055a903f8dSPierre Beyssac error = in_pcbbind(inp, (struct sockaddr *)0, p); 5065a903f8dSPierre Beyssac if (error) 5075a903f8dSPierre Beyssac return (error); 5085a903f8dSPierre Beyssac } 509df8bae1dSRodney W. Grimes inp->inp_laddr = ifaddr->sin_addr; 510df8bae1dSRodney W. Grimes } 511df8bae1dSRodney W. Grimes inp->inp_faddr = sin->sin_addr; 512df8bae1dSRodney W. Grimes inp->inp_fport = sin->sin_port; 51315bd2b43SDavid Greenman in_pcbrehash(inp); 514df8bae1dSRodney W. Grimes return (0); 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes 51726f9a767SRodney W. Grimes void 518df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 519df8bae1dSRodney W. Grimes struct inpcb *inp; 520df8bae1dSRodney W. Grimes { 521df8bae1dSRodney W. Grimes 522df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 523df8bae1dSRodney W. Grimes inp->inp_fport = 0; 52415bd2b43SDavid Greenman in_pcbrehash(inp); 525df8bae1dSRodney W. Grimes if (inp->inp_socket->so_state & SS_NOFDREF) 526df8bae1dSRodney W. Grimes in_pcbdetach(inp); 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes 52926f9a767SRodney W. Grimes void 530df8bae1dSRodney W. Grimes in_pcbdetach(inp) 531df8bae1dSRodney W. Grimes struct inpcb *inp; 532df8bae1dSRodney W. Grimes { 533df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 5343d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 535df8bae1dSRodney W. Grimes 536cfa1ca9dSYoshinobu Inoue #ifdef IPSEC 537333aa64dSBrian Feldman if (inp->inp_sp != NULL) 538cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 539cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/ 5403d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 541c3229e05SDavid Greenman in_pcbremlists(inp); 542df8bae1dSRodney W. Grimes so->so_pcb = 0; 543df8bae1dSRodney W. Grimes sofree(so); 544df8bae1dSRodney W. Grimes if (inp->inp_options) 545df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 546df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) 547df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 548df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 549cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 5503d4d47f3SGarrett Wollman zfreei(ipi->ipi_zone, inp); 551df8bae1dSRodney W. Grimes } 552df8bae1dSRodney W. Grimes 553117bcae7SGarrett Wollman /* 554117bcae7SGarrett Wollman * The calling convention of in_setsockaddr() and in_setpeeraddr() was 555117bcae7SGarrett Wollman * modified to match the pru_sockaddr() and pru_peeraddr() entry points 556117bcae7SGarrett Wollman * in struct pr_usrreqs, so that protocols can just reference then directly 557117bcae7SGarrett Wollman * without the need for a wrapper function. The socket must have a valid 558117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 559117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 56057bf258eSGarrett Wollman * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 56157bf258eSGarrett Wollman * because there actually /is/ a programming error somewhere... XXX) 562117bcae7SGarrett Wollman */ 563117bcae7SGarrett Wollman int 564117bcae7SGarrett Wollman in_setsockaddr(so, nam) 565117bcae7SGarrett Wollman struct socket *so; 56657bf258eSGarrett Wollman struct sockaddr **nam; 567df8bae1dSRodney W. Grimes { 568fdc984f7STor Egge int s; 569fdc984f7STor Egge register struct inpcb *inp; 570df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 571df8bae1dSRodney W. Grimes 572c3229e05SDavid Greenman /* 573c3229e05SDavid Greenman * Do the malloc first in case it blocks. 574c3229e05SDavid Greenman */ 57542fa505bSDavid Greenman MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); 57642fa505bSDavid Greenman bzero(sin, sizeof *sin); 57742fa505bSDavid Greenman sin->sin_family = AF_INET; 57842fa505bSDavid Greenman sin->sin_len = sizeof(*sin); 57942fa505bSDavid Greenman 580fdc984f7STor Egge s = splnet(); 581fdc984f7STor Egge inp = sotoinpcb(so); 582db112f04STor Egge if (!inp) { 583db112f04STor Egge splx(s); 58442fa505bSDavid Greenman free(sin, M_SONAME); 585ff079ca4SPeter Wemm return ECONNRESET; 586db112f04STor Egge } 587df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_lport; 588df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_laddr; 589db112f04STor Egge splx(s); 59042fa505bSDavid Greenman 59142fa505bSDavid Greenman *nam = (struct sockaddr *)sin; 592117bcae7SGarrett Wollman return 0; 593df8bae1dSRodney W. Grimes } 594df8bae1dSRodney W. Grimes 595117bcae7SGarrett Wollman int 596117bcae7SGarrett Wollman in_setpeeraddr(so, nam) 597117bcae7SGarrett Wollman struct socket *so; 59857bf258eSGarrett Wollman struct sockaddr **nam; 599df8bae1dSRodney W. Grimes { 600fdc984f7STor Egge int s; 601fdc984f7STor Egge struct inpcb *inp; 602df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 603df8bae1dSRodney W. Grimes 604c3229e05SDavid Greenman /* 605c3229e05SDavid Greenman * Do the malloc first in case it blocks. 606c3229e05SDavid Greenman */ 60742fa505bSDavid Greenman MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); 608ff079ca4SPeter Wemm bzero(sin, sizeof (*sin)); 60942fa505bSDavid Greenman sin->sin_family = AF_INET; 61042fa505bSDavid Greenman sin->sin_len = sizeof(*sin); 61142fa505bSDavid Greenman 612fdc984f7STor Egge s = splnet(); 613fdc984f7STor Egge inp = sotoinpcb(so); 614db112f04STor Egge if (!inp) { 615db112f04STor Egge splx(s); 61642fa505bSDavid Greenman free(sin, M_SONAME); 617ff079ca4SPeter Wemm return ECONNRESET; 618db112f04STor Egge } 619df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_fport; 620df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_faddr; 621db112f04STor Egge splx(s); 62242fa505bSDavid Greenman 62342fa505bSDavid Greenman *nam = (struct sockaddr *)sin; 624117bcae7SGarrett Wollman return 0; 625df8bae1dSRodney W. Grimes } 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes /* 628df8bae1dSRodney W. Grimes * Pass some notification to all connections of a protocol 629df8bae1dSRodney W. Grimes * associated with address dst. The local address and/or port numbers 630df8bae1dSRodney W. Grimes * may be specified to limit the search. The "usual action" will be 631df8bae1dSRodney W. Grimes * taken, depending on the ctlinput cmd. The caller must filter any 632df8bae1dSRodney W. Grimes * cmds that are uninteresting (e.g., no error in the map). 633df8bae1dSRodney W. Grimes * Call the protocol specific routine (if any) to report 634df8bae1dSRodney W. Grimes * any errors for each matching socket. 635df8bae1dSRodney W. Grimes */ 63626f9a767SRodney W. Grimes void 637df8bae1dSRodney W. Grimes in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 63815bd2b43SDavid Greenman struct inpcbhead *head; 639df8bae1dSRodney W. Grimes struct sockaddr *dst; 640df8bae1dSRodney W. Grimes u_int fport_arg, lport_arg; 641df8bae1dSRodney W. Grimes struct in_addr laddr; 642df8bae1dSRodney W. Grimes int cmd; 643df8bae1dSRodney W. Grimes void (*notify) __P((struct inpcb *, int)); 644df8bae1dSRodney W. Grimes { 645df8bae1dSRodney W. Grimes register struct inpcb *inp, *oinp; 646df8bae1dSRodney W. Grimes struct in_addr faddr; 647df8bae1dSRodney W. Grimes u_short fport = fport_arg, lport = lport_arg; 6487bc4aca7SDavid Greenman int errno, s; 649df8bae1dSRodney W. Grimes 650df8bae1dSRodney W. Grimes if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 651df8bae1dSRodney W. Grimes return; 652df8bae1dSRodney W. Grimes faddr = ((struct sockaddr_in *)dst)->sin_addr; 653df8bae1dSRodney W. Grimes if (faddr.s_addr == INADDR_ANY) 654df8bae1dSRodney W. Grimes return; 655df8bae1dSRodney W. Grimes 656df8bae1dSRodney W. Grimes /* 657df8bae1dSRodney W. Grimes * Redirects go to all references to the destination, 658df8bae1dSRodney W. Grimes * and use in_rtchange to invalidate the route cache. 659df8bae1dSRodney W. Grimes * Dead host indications: notify all references to the destination. 660df8bae1dSRodney W. Grimes * Otherwise, if we have knowledge of the local port and address, 661df8bae1dSRodney W. Grimes * deliver only to that socket. 662df8bae1dSRodney W. Grimes */ 663df8bae1dSRodney W. Grimes if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 664df8bae1dSRodney W. Grimes fport = 0; 665df8bae1dSRodney W. Grimes lport = 0; 666df8bae1dSRodney W. Grimes laddr.s_addr = 0; 667df8bae1dSRodney W. Grimes if (cmd != PRC_HOSTDEAD) 668df8bae1dSRodney W. Grimes notify = in_rtchange; 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes errno = inetctlerrmap[cmd]; 6717bc4aca7SDavid Greenman s = splnet(); 67215bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL;) { 673cfa1ca9dSYoshinobu Inoue #ifdef INET6 674369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) { 675cfa1ca9dSYoshinobu Inoue inp = LIST_NEXT(inp, inp_list); 676cfa1ca9dSYoshinobu Inoue continue; 677cfa1ca9dSYoshinobu Inoue } 678cfa1ca9dSYoshinobu Inoue #endif 679df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != faddr.s_addr || 680df8bae1dSRodney W. Grimes inp->inp_socket == 0 || 681df8bae1dSRodney W. Grimes (lport && inp->inp_lport != lport) || 682df8bae1dSRodney W. Grimes (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 683df8bae1dSRodney W. Grimes (fport && inp->inp_fport != fport)) { 68415bd2b43SDavid Greenman inp = inp->inp_list.le_next; 685df8bae1dSRodney W. Grimes continue; 686df8bae1dSRodney W. Grimes } 687df8bae1dSRodney W. Grimes oinp = inp; 68815bd2b43SDavid Greenman inp = inp->inp_list.le_next; 689df8bae1dSRodney W. Grimes if (notify) 690df8bae1dSRodney W. Grimes (*notify)(oinp, errno); 691df8bae1dSRodney W. Grimes } 6927bc4aca7SDavid Greenman splx(s); 693df8bae1dSRodney W. Grimes } 694df8bae1dSRodney W. Grimes 695df8bae1dSRodney W. Grimes /* 696df8bae1dSRodney W. Grimes * Check for alternatives when higher level complains 697df8bae1dSRodney W. Grimes * about service problems. For now, invalidate cached 698df8bae1dSRodney W. Grimes * routing information. If the route was created dynamically 699df8bae1dSRodney W. Grimes * (by a redirect), time to try a default gateway again. 700df8bae1dSRodney W. Grimes */ 70126f9a767SRodney W. Grimes void 702df8bae1dSRodney W. Grimes in_losing(inp) 703df8bae1dSRodney W. Grimes struct inpcb *inp; 704df8bae1dSRodney W. Grimes { 705df8bae1dSRodney W. Grimes register struct rtentry *rt; 706df8bae1dSRodney W. Grimes struct rt_addrinfo info; 707df8bae1dSRodney W. Grimes 708df8bae1dSRodney W. Grimes if ((rt = inp->inp_route.ro_rt)) { 709df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 710df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 711df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = 712df8bae1dSRodney W. Grimes (struct sockaddr *)&inp->inp_route.ro_dst; 713df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 714df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = rt_mask(rt); 715df8bae1dSRodney W. Grimes rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 716df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_DYNAMIC) 717df8bae1dSRodney W. Grimes (void) rtrequest(RTM_DELETE, rt_key(rt), 718df8bae1dSRodney W. Grimes rt->rt_gateway, rt_mask(rt), rt->rt_flags, 719df8bae1dSRodney W. Grimes (struct rtentry **)0); 720df8bae1dSRodney W. Grimes else 721df8bae1dSRodney W. Grimes /* 722df8bae1dSRodney W. Grimes * A new route can be allocated 723df8bae1dSRodney W. Grimes * the next time output is attempted. 724df8bae1dSRodney W. Grimes */ 725df8bae1dSRodney W. Grimes rtfree(rt); 726df8bae1dSRodney W. Grimes } 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * After a routing change, flush old routing 731df8bae1dSRodney W. Grimes * and allocate a (hopefully) better one. 732df8bae1dSRodney W. Grimes */ 7330312fbe9SPoul-Henning Kamp static void 734df8bae1dSRodney W. Grimes in_rtchange(inp, errno) 735df8bae1dSRodney W. Grimes register struct inpcb *inp; 736df8bae1dSRodney W. Grimes int errno; 737df8bae1dSRodney W. Grimes { 738df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) { 739df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 740df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 741df8bae1dSRodney W. Grimes /* 742df8bae1dSRodney W. Grimes * A new route can be allocated the next time 743df8bae1dSRodney W. Grimes * output is attempted. 744df8bae1dSRodney W. Grimes */ 745df8bae1dSRodney W. Grimes } 746df8bae1dSRodney W. Grimes } 747df8bae1dSRodney W. Grimes 748c3229e05SDavid Greenman /* 749c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 750c3229e05SDavid Greenman */ 751df8bae1dSRodney W. Grimes struct inpcb * 752c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 7536d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 754c3229e05SDavid Greenman struct in_addr laddr; 755c3229e05SDavid Greenman u_int lport_arg; 7566d6a026bSDavid Greenman int wild_okay; 757df8bae1dSRodney W. Grimes { 758f1d19042SArchie Cobbs register struct inpcb *inp; 759df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 760c3229e05SDavid Greenman u_short lport = lport_arg; 7617bc4aca7SDavid Greenman 762c3229e05SDavid Greenman if (!wild_okay) { 763c3229e05SDavid Greenman struct inpcbhead *head; 764c3229e05SDavid Greenman /* 765c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 766c3229e05SDavid Greenman * matches the local address and port we're looking for. 767c3229e05SDavid Greenman */ 768c3229e05SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 769c3229e05SDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 770cfa1ca9dSYoshinobu Inoue #ifdef INET6 771369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 772cfa1ca9dSYoshinobu Inoue continue; 773cfa1ca9dSYoshinobu Inoue #endif 774c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 775c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 776c3229e05SDavid Greenman inp->inp_lport == lport) { 777c3229e05SDavid Greenman /* 778c3229e05SDavid Greenman * Found. 779c3229e05SDavid Greenman */ 780c3229e05SDavid Greenman return (inp); 781df8bae1dSRodney W. Grimes } 782c3229e05SDavid Greenman } 783c3229e05SDavid Greenman /* 784c3229e05SDavid Greenman * Not found. 785c3229e05SDavid Greenman */ 786c3229e05SDavid Greenman return (NULL); 787c3229e05SDavid Greenman } else { 788c3229e05SDavid Greenman struct inpcbporthead *porthash; 789c3229e05SDavid Greenman struct inpcbport *phd; 790c3229e05SDavid Greenman struct inpcb *match = NULL; 791c3229e05SDavid Greenman /* 792c3229e05SDavid Greenman * Best fit PCB lookup. 793c3229e05SDavid Greenman * 794c3229e05SDavid Greenman * First see if this local port is in use by looking on the 795c3229e05SDavid Greenman * port hash list. 796c3229e05SDavid Greenman */ 797c3229e05SDavid Greenman porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 798c3229e05SDavid Greenman pcbinfo->porthashmask)]; 799c3229e05SDavid Greenman for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { 800c3229e05SDavid Greenman if (phd->phd_port == lport) 801c3229e05SDavid Greenman break; 802c3229e05SDavid Greenman } 803c3229e05SDavid Greenman if (phd != NULL) { 804c3229e05SDavid Greenman /* 805c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 806c3229e05SDavid Greenman * fit. 807c3229e05SDavid Greenman */ 808c3229e05SDavid Greenman for (inp = phd->phd_pcblist.lh_first; inp != NULL; 809c3229e05SDavid Greenman inp = inp->inp_portlist.le_next) { 810c3229e05SDavid Greenman wildcard = 0; 811cfa1ca9dSYoshinobu Inoue #ifdef INET6 812369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 813cfa1ca9dSYoshinobu Inoue continue; 814cfa1ca9dSYoshinobu Inoue #endif 815c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 816c3229e05SDavid Greenman wildcard++; 81715bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 81815bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 81915bd2b43SDavid Greenman wildcard++; 82015bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 82115bd2b43SDavid Greenman continue; 82215bd2b43SDavid Greenman } else { 82315bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 82415bd2b43SDavid Greenman wildcard++; 82515bd2b43SDavid Greenman } 826df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 827df8bae1dSRodney W. Grimes match = inp; 828df8bae1dSRodney W. Grimes matchwild = wildcard; 8293dbdc25cSDavid Greenman if (matchwild == 0) { 830df8bae1dSRodney W. Grimes break; 831df8bae1dSRodney W. Grimes } 832df8bae1dSRodney W. Grimes } 8333dbdc25cSDavid Greenman } 834c3229e05SDavid Greenman } 835df8bae1dSRodney W. Grimes return (match); 836df8bae1dSRodney W. Grimes } 837c3229e05SDavid Greenman } 83815bd2b43SDavid Greenman 83915bd2b43SDavid Greenman /* 84015bd2b43SDavid Greenman * Lookup PCB in hash list. 84115bd2b43SDavid Greenman */ 84215bd2b43SDavid Greenman struct inpcb * 843cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, 844cfa1ca9dSYoshinobu Inoue ifp) 84515bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 84615bd2b43SDavid Greenman struct in_addr faddr, laddr; 84715bd2b43SDavid Greenman u_int fport_arg, lport_arg; 8486d6a026bSDavid Greenman int wildcard; 849cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 85015bd2b43SDavid Greenman { 85115bd2b43SDavid Greenman struct inpcbhead *head; 85215bd2b43SDavid Greenman register struct inpcb *inp; 85315bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 85415bd2b43SDavid Greenman 85515bd2b43SDavid Greenman /* 85615bd2b43SDavid Greenman * First look for an exact match. 85715bd2b43SDavid Greenman */ 858ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 85915bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 860cfa1ca9dSYoshinobu Inoue #ifdef INET6 861369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 862cfa1ca9dSYoshinobu Inoue continue; 863cfa1ca9dSYoshinobu Inoue #endif 8646d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 865ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 866ca98b82cSDavid Greenman inp->inp_fport == fport && 867c3229e05SDavid Greenman inp->inp_lport == lport) { 868c3229e05SDavid Greenman /* 869c3229e05SDavid Greenman * Found. 870c3229e05SDavid Greenman */ 871c3229e05SDavid Greenman return (inp); 872c3229e05SDavid Greenman } 8736d6a026bSDavid Greenman } 8746d6a026bSDavid Greenman if (wildcard) { 8756d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 876cfa1ca9dSYoshinobu Inoue #if defined(INET6) 877cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 878cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 8796d6a026bSDavid Greenman 880ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 8816d6a026bSDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 882cfa1ca9dSYoshinobu Inoue #ifdef INET6 883369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 884cfa1ca9dSYoshinobu Inoue continue; 885cfa1ca9dSYoshinobu Inoue #endif 8866d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 887c3229e05SDavid Greenman inp->inp_lport == lport) { 888cfa1ca9dSYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0 889cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 890cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 891cfa1ca9dSYoshinobu Inoue continue; 892cfa1ca9dSYoshinobu Inoue #endif 8936d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 894c3229e05SDavid Greenman return (inp); 895cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 896cfa1ca9dSYoshinobu Inoue #if defined(INET6) 897cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 898cfa1ca9dSYoshinobu Inoue AF_INET6)) 899cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 900cfa1ca9dSYoshinobu Inoue else 901cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 9026d6a026bSDavid Greenman local_wild = inp; 9036d6a026bSDavid Greenman } 9046d6a026bSDavid Greenman } 905cfa1ca9dSYoshinobu Inoue } 906cfa1ca9dSYoshinobu Inoue #if defined(INET6) 907cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 908cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 909cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 910c3229e05SDavid Greenman return (local_wild); 9116d6a026bSDavid Greenman } 912c3229e05SDavid Greenman 913c3229e05SDavid Greenman /* 914c3229e05SDavid Greenman * Not found. 915c3229e05SDavid Greenman */ 9166d6a026bSDavid Greenman return (NULL); 91715bd2b43SDavid Greenman } 91815bd2b43SDavid Greenman 9197bc4aca7SDavid Greenman /* 920c3229e05SDavid Greenman * Insert PCB onto various hash lists. 9217bc4aca7SDavid Greenman */ 922c3229e05SDavid Greenman int 92315bd2b43SDavid Greenman in_pcbinshash(inp) 92415bd2b43SDavid Greenman struct inpcb *inp; 92515bd2b43SDavid Greenman { 926c3229e05SDavid Greenman struct inpcbhead *pcbhash; 927c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 928c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 929c3229e05SDavid Greenman struct inpcbport *phd; 930cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 93115bd2b43SDavid Greenman 932cfa1ca9dSYoshinobu Inoue #ifdef INET6 933cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 934cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 935cfa1ca9dSYoshinobu Inoue else 936cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 937cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 938cfa1ca9dSYoshinobu Inoue 939cfa1ca9dSYoshinobu Inoue pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 940c3229e05SDavid Greenman inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 94115bd2b43SDavid Greenman 942c3229e05SDavid Greenman pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, 943c3229e05SDavid Greenman pcbinfo->porthashmask)]; 944c3229e05SDavid Greenman 945c3229e05SDavid Greenman /* 946c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 947c3229e05SDavid Greenman */ 948c3229e05SDavid Greenman for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { 949c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 950c3229e05SDavid Greenman break; 951c3229e05SDavid Greenman } 952c3229e05SDavid Greenman /* 953c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 954c3229e05SDavid Greenman */ 955c3229e05SDavid Greenman if (phd == NULL) { 956c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 957c3229e05SDavid Greenman if (phd == NULL) { 958c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 959c3229e05SDavid Greenman } 960c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 961c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 962c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 963c3229e05SDavid Greenman } 964c3229e05SDavid Greenman inp->inp_phd = phd; 965c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 966c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 967c3229e05SDavid Greenman return (0); 96815bd2b43SDavid Greenman } 96915bd2b43SDavid Greenman 970c3229e05SDavid Greenman /* 971c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 972c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 973c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 974c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 975c3229e05SDavid Greenman */ 97615bd2b43SDavid Greenman void 97715bd2b43SDavid Greenman in_pcbrehash(inp) 97815bd2b43SDavid Greenman struct inpcb *inp; 97915bd2b43SDavid Greenman { 98015bd2b43SDavid Greenman struct inpcbhead *head; 981cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 98215bd2b43SDavid Greenman 983cfa1ca9dSYoshinobu Inoue #ifdef INET6 984cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 985cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 986cfa1ca9dSYoshinobu Inoue else 987cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 988cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 989cfa1ca9dSYoshinobu Inoue 990cfa1ca9dSYoshinobu Inoue head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 991ddd79a97SDavid Greenman inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 99215bd2b43SDavid Greenman 993c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 99415bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 995c3229e05SDavid Greenman } 996c3229e05SDavid Greenman 997c3229e05SDavid Greenman /* 998c3229e05SDavid Greenman * Remove PCB from various lists. 999c3229e05SDavid Greenman */ 100076429de4SYoshinobu Inoue void 1001c3229e05SDavid Greenman in_pcbremlists(inp) 1002c3229e05SDavid Greenman struct inpcb *inp; 1003c3229e05SDavid Greenman { 100498271db4SGarrett Wollman inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt; 1005c3229e05SDavid Greenman if (inp->inp_lport) { 1006c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1007c3229e05SDavid Greenman 1008c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1009c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1010c3229e05SDavid Greenman if (phd->phd_pcblist.lh_first == NULL) { 1011c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1012c3229e05SDavid Greenman free(phd, M_PCB); 1013c3229e05SDavid Greenman } 1014c3229e05SDavid Greenman } 1015c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 10163d4d47f3SGarrett Wollman inp->inp_pcbinfo->ipi_count--; 101715bd2b43SDavid Greenman } 101875c13541SPoul-Henning Kamp 101975c13541SPoul-Henning Kamp int 102075c13541SPoul-Henning Kamp prison_xinpcb(struct proc *p, struct inpcb *inp) 102175c13541SPoul-Henning Kamp { 102275c13541SPoul-Henning Kamp if (!p->p_prison) 102375c13541SPoul-Henning Kamp return (0); 102475c13541SPoul-Henning Kamp if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip) 102575c13541SPoul-Henning Kamp return (0); 102675c13541SPoul-Henning Kamp return (1); 102775c13541SPoul-Henning Kamp } 1028