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 5569c2d429SJeff Roberson #include <vm/uma.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 #ifdef IPSEC 71cfa1ca9dSYoshinobu Inoue #include <netinet6/ipsec.h> 72cfa1ca9dSYoshinobu Inoue #include <netkey/key.h> 73cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */ 74df8bae1dSRodney W. Grimes 75b9234fafSSam Leffler #ifdef FAST_IPSEC 76b9234fafSSam Leffler #if defined(IPSEC) || defined(IPSEC_ESP) 77b9234fafSSam Leffler #error "Bad idea: don't compile with both IPSEC and FAST_IPSEC!" 78b9234fafSSam Leffler #endif 79b9234fafSSam Leffler 80b9234fafSSam Leffler #include <netipsec/ipsec.h> 81b9234fafSSam Leffler #include <netipsec/key.h> 82b9234fafSSam Leffler #define IPSEC 83b9234fafSSam Leffler #endif /* FAST_IPSEC */ 84b9234fafSSam Leffler 85df8bae1dSRodney W. Grimes struct in_addr zeroin_addr; 86df8bae1dSRodney W. Grimes 87101f9fc8SPeter Wemm /* 88101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 89101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 90101f9fc8SPeter Wemm */ 9182cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 9282cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 939e5a5ed4SMike Silbersack int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 949e5a5ed4SMike Silbersack int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */ 9582cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9682cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 97101f9fc8SPeter Wemm 98bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 99bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 100bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 101bbd42ad0SPeter Wemm 102bbd42ad0SPeter Wemm static int 10382d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 104bbd42ad0SPeter Wemm { 105bbd42ad0SPeter Wemm int error = sysctl_handle_int(oidp, 106bbd42ad0SPeter Wemm oidp->oid_arg1, oidp->oid_arg2, req); 107bbd42ad0SPeter Wemm if (!error) { 108bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 109bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 110bbd42ad0SPeter Wemm RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 111bbd42ad0SPeter Wemm RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 112bbd42ad0SPeter Wemm RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 113bbd42ad0SPeter Wemm RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 114bbd42ad0SPeter Wemm } 115bbd42ad0SPeter Wemm return error; 116bbd42ad0SPeter Wemm } 117bbd42ad0SPeter Wemm 118bbd42ad0SPeter Wemm #undef RANGECHK 119bbd42ad0SPeter Wemm 12033b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 12133b3ac06SPeter Wemm 122bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 123bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 124bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 125bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 126bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 127bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 128bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 129bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 130bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 131bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 132bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 133bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 1340312fbe9SPoul-Henning Kamp 135c3229e05SDavid Greenman /* 136c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 137c3229e05SDavid Greenman * 138c3229e05SDavid Greenman * NOTE: It is assumed that most of these functions will be called at 139c3229e05SDavid Greenman * splnet(). XXX - There are, unfortunately, a few exceptions to this 140c3229e05SDavid Greenman * rule that should be fixed. 141c3229e05SDavid Greenman */ 142c3229e05SDavid Greenman 143c3229e05SDavid Greenman /* 144c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 145c3229e05SDavid Greenman */ 146df8bae1dSRodney W. Grimes int 147b40ce416SJulian Elischer in_pcballoc(so, pcbinfo, td) 148df8bae1dSRodney W. Grimes struct socket *so; 14915bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 150b40ce416SJulian Elischer struct thread *td; 151df8bae1dSRodney W. Grimes { 152df8bae1dSRodney W. Grimes register struct inpcb *inp; 15313cf67f3SHajimu UMEMOTO #ifdef IPSEC 15413cf67f3SHajimu UMEMOTO int error; 15513cf67f3SHajimu UMEMOTO #endif 156df8bae1dSRodney W. Grimes 157f76fcf6dSJeffrey Hsu inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT); 158df8bae1dSRodney W. Grimes if (inp == NULL) 159df8bae1dSRodney W. Grimes return (ENOBUFS); 160df8bae1dSRodney W. Grimes bzero((caddr_t)inp, sizeof(*inp)); 1613d4d47f3SGarrett Wollman inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 16215bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 163df8bae1dSRodney W. Grimes inp->inp_socket = so; 16413cf67f3SHajimu UMEMOTO #ifdef IPSEC 16513cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 16613cf67f3SHajimu UMEMOTO if (error != 0) { 16769c2d429SJeff Roberson uma_zfree(pcbinfo->ipi_zone, inp); 16813cf67f3SHajimu UMEMOTO return error; 16913cf67f3SHajimu UMEMOTO } 17013cf67f3SHajimu UMEMOTO #endif /*IPSEC*/ 17175daea93SPaul Saab #if defined(INET6) 172eccb7001SHajimu UMEMOTO if (INP_SOCKAF(so) == AF_INET6 && ip6_v6only) 17333841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 17475daea93SPaul Saab #endif 17515bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 1763d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 177df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 178f76fcf6dSJeffrey Hsu INP_LOCK_INIT(inp, "inp"); 17933841545SHajimu UMEMOTO #ifdef INET6 18033841545SHajimu UMEMOTO if (ip6_auto_flowlabel) 18133841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 18233841545SHajimu UMEMOTO #endif 183df8bae1dSRodney W. Grimes return (0); 184df8bae1dSRodney W. Grimes } 185df8bae1dSRodney W. Grimes 186df8bae1dSRodney W. Grimes int 187b40ce416SJulian Elischer in_pcbbind(inp, nam, td) 188df8bae1dSRodney W. Grimes register struct inpcb *inp; 18957bf258eSGarrett Wollman struct sockaddr *nam; 190b40ce416SJulian Elischer struct thread *td; 191df8bae1dSRodney W. Grimes { 1924b932371SIan Dowse int anonport, error; 1934b932371SIan Dowse 1944b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 1954b932371SIan Dowse return (EINVAL); 1964b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 1974b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 1984b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 1994b932371SIan Dowse &inp->inp_lport, td); 2004b932371SIan Dowse if (error) 2014b932371SIan Dowse return (error); 2024b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2034b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2044b932371SIan Dowse inp->inp_lport = 0; 2054b932371SIan Dowse return (EAGAIN); 2064b932371SIan Dowse } 2074b932371SIan Dowse if (anonport) 2084b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2094b932371SIan Dowse return (0); 2104b932371SIan Dowse } 2114b932371SIan Dowse 2124b932371SIan Dowse /* 2134b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2144b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2154b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2164b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2174b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2184b932371SIan Dowse * 2194b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2204b932371SIan Dowse */ 2214b932371SIan Dowse int 2224b932371SIan Dowse in_pcbbind_setup(inp, nam, laddrp, lportp, td) 2234b932371SIan Dowse struct inpcb *inp; 2244b932371SIan Dowse struct sockaddr *nam; 2254b932371SIan Dowse in_addr_t *laddrp; 2264b932371SIan Dowse u_short *lportp; 2274b932371SIan Dowse struct thread *td; 2284b932371SIan Dowse { 2294b932371SIan Dowse struct socket *so = inp->inp_socket; 23037bd2b30SPeter Wemm unsigned short *lastport; 23115bd2b43SDavid Greenman struct sockaddr_in *sin; 232c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 2334b932371SIan Dowse struct in_addr laddr; 234df8bae1dSRodney W. Grimes u_short lport = 0; 2354cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 23675c13541SPoul-Henning Kamp int error, prison = 0; 237df8bae1dSRodney W. Grimes 23859562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 239df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 2404b932371SIan Dowse laddr.s_addr = *laddrp; 2414b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 242df8bae1dSRodney W. Grimes return (EINVAL); 243c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 2446d6a026bSDavid Greenman wild = 1; 245df8bae1dSRodney W. Grimes if (nam) { 24657bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 24757bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 248df8bae1dSRodney W. Grimes return (EINVAL); 249df8bae1dSRodney W. Grimes #ifdef notdef 250df8bae1dSRodney W. Grimes /* 251df8bae1dSRodney W. Grimes * We should check the family, but old programs 252df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 253df8bae1dSRodney W. Grimes */ 254df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 255df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 256df8bae1dSRodney W. Grimes #endif 257e4bdf25dSPoul-Henning Kamp if (sin->sin_addr.s_addr != INADDR_ANY) 258a854ed98SJohn Baldwin if (prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) 25975c13541SPoul-Henning Kamp return(EINVAL); 2604b932371SIan Dowse if (sin->sin_port != *lportp) { 2614b932371SIan Dowse /* Don't allow the port to change. */ 2624b932371SIan Dowse if (*lportp != 0) 2634b932371SIan Dowse return (EINVAL); 264df8bae1dSRodney W. Grimes lport = sin->sin_port; 2654b932371SIan Dowse } 2664b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 267df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 270df8bae1dSRodney W. Grimes * allow complete duplication of binding if 271df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 272df8bae1dSRodney W. Grimes * and a multicast address is bound on both 273df8bae1dSRodney W. Grimes * new and duplicated sockets. 274df8bae1dSRodney W. Grimes */ 275df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 276df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 277df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 278df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 27983103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 280df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 281df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 282df8bae1dSRodney W. Grimes } 2834b932371SIan Dowse laddr = sin->sin_addr; 284df8bae1dSRodney W. Grimes if (lport) { 285df8bae1dSRodney W. Grimes struct inpcb *t; 286df8bae1dSRodney W. Grimes /* GROSS */ 28744731cabSJohn Baldwin if (ntohs(lport) < IPPORT_RESERVED && td && 28844731cabSJohn Baldwin suser_cred(td->td_ucred, PRISON_ROOT)) 2892469dd60SGarrett Wollman return (EACCES); 290a854ed98SJohn Baldwin if (td && jailed(td->td_ucred)) 29175c13541SPoul-Henning Kamp prison = 1; 2922f9a2132SBrian Feldman if (so->so_cred->cr_uid != 0 && 29352b65dbeSBill Fenner !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 2944049a042SGuido van Rooij t = in_pcblookup_local(inp->inp_pcbinfo, 29575c13541SPoul-Henning Kamp sin->sin_addr, lport, 29675c13541SPoul-Henning Kamp prison ? 0 : INPLOOKUP_WILDCARD); 2974cc20ab1SSeigo Tanimura if (t && 2984cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 29952b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 30052b65dbeSBill Fenner (t->inp_socket->so_options & 30152b65dbeSBill Fenner SO_REUSEPORT) == 0) && 3022f9a2132SBrian Feldman (so->so_cred->cr_uid != 303cfa1ca9dSYoshinobu Inoue t->inp_socket->so_cred->cr_uid)) { 304cfa1ca9dSYoshinobu Inoue #if defined(INET6) 30533841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 306cfa1ca9dSYoshinobu Inoue INADDR_ANY || 307cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 308cfa1ca9dSYoshinobu Inoue INADDR_ANY || 309cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 310cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 311cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 3124049a042SGuido van Rooij return (EADDRINUSE); 3134049a042SGuido van Rooij } 314cfa1ca9dSYoshinobu Inoue } 315970680faSPoul-Henning Kamp if (prison && 316a854ed98SJohn Baldwin prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) 317970680faSPoul-Henning Kamp return (EADDRNOTAVAIL); 318c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 31975c13541SPoul-Henning Kamp lport, prison ? 0 : wild); 3204cc20ab1SSeigo Tanimura if (t && 3214cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 322cfa1ca9dSYoshinobu Inoue #if defined(INET6) 32333841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 324cfa1ca9dSYoshinobu Inoue INADDR_ANY || 325cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 326cfa1ca9dSYoshinobu Inoue INADDR_ANY || 327cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 328cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 329cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 330df8bae1dSRodney W. Grimes return (EADDRINUSE); 331df8bae1dSRodney W. Grimes } 332cfa1ca9dSYoshinobu Inoue } 333df8bae1dSRodney W. Grimes } 3344b932371SIan Dowse if (*lportp != 0) 3354b932371SIan Dowse lport = *lportp; 33633b3ac06SPeter Wemm if (lport == 0) { 33733b3ac06SPeter Wemm ushort first, last; 33833b3ac06SPeter Wemm int count; 33933b3ac06SPeter Wemm 3404b932371SIan Dowse if (laddr.s_addr != INADDR_ANY) 3414b932371SIan Dowse if (prison_ip(td->td_ucred, 0, &laddr.s_addr)) 34275c13541SPoul-Henning Kamp return (EINVAL); 343321a2846SPoul-Henning Kamp 34433b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 34533b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 34633b3ac06SPeter Wemm last = ipport_hilastauto; 347c3229e05SDavid Greenman lastport = &pcbinfo->lasthi; 34833b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 3494b932371SIan Dowse if (td && (error = suser_cred(td->td_ucred, 3504b932371SIan Dowse PRISON_ROOT)) != 0) 351a29f300eSGarrett Wollman return error; 352bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 353bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 354c3229e05SDavid Greenman lastport = &pcbinfo->lastlow; 35533b3ac06SPeter Wemm } else { 35633b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 35733b3ac06SPeter Wemm last = ipport_lastauto; 358c3229e05SDavid Greenman lastport = &pcbinfo->lastport; 35933b3ac06SPeter Wemm } 36033b3ac06SPeter Wemm /* 36133b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 36233b3ac06SPeter Wemm * a deadlock here. 36333b3ac06SPeter Wemm * 36433b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 36533b3ac06SPeter Wemm * is not being tested on each round of the loop. 36633b3ac06SPeter Wemm */ 36733b3ac06SPeter Wemm if (first > last) { 36833b3ac06SPeter Wemm /* 36933b3ac06SPeter Wemm * counting down 37033b3ac06SPeter Wemm */ 37133b3ac06SPeter Wemm count = first - last; 37233b3ac06SPeter Wemm 373df8bae1dSRodney W. Grimes do { 3744b932371SIan Dowse if (count-- < 0) /* completely used? */ 375550b1518SWes Peters return (EADDRNOTAVAIL); 37633b3ac06SPeter Wemm --*lastport; 37733b3ac06SPeter Wemm if (*lastport > first || *lastport < last) 37833b3ac06SPeter Wemm *lastport = first; 37915bd2b43SDavid Greenman lport = htons(*lastport); 3804b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 3814b932371SIan Dowse wild)); 38233b3ac06SPeter Wemm } else { 38333b3ac06SPeter Wemm /* 38433b3ac06SPeter Wemm * counting up 38533b3ac06SPeter Wemm */ 38633b3ac06SPeter Wemm count = last - first; 38733b3ac06SPeter Wemm 38833b3ac06SPeter Wemm do { 3894b932371SIan Dowse if (count-- < 0) /* completely used? */ 390550b1518SWes Peters return (EADDRNOTAVAIL); 39133b3ac06SPeter Wemm ++*lastport; 39233b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 39333b3ac06SPeter Wemm *lastport = first; 39433b3ac06SPeter Wemm lport = htons(*lastport); 3954b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 3964b932371SIan Dowse wild)); 39733b3ac06SPeter Wemm } 39833b3ac06SPeter Wemm } 3994b932371SIan Dowse if (prison_ip(td->td_ucred, 0, &laddr.s_addr)) 400e4bdf25dSPoul-Henning Kamp return (EINVAL); 4014b932371SIan Dowse *laddrp = laddr.s_addr; 4024b932371SIan Dowse *lportp = lport; 403df8bae1dSRodney W. Grimes return (0); 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes 406999f1343SGarrett Wollman /* 407999f1343SGarrett Wollman * Transform old in_pcbconnect() into an inner subroutine for new 408999f1343SGarrett Wollman * in_pcbconnect(): Do some validity-checking on the remote 409999f1343SGarrett Wollman * address (in mbuf 'nam') and then determine local host address 410999f1343SGarrett Wollman * (i.e., which interface) to use to access that remote host. 411999f1343SGarrett Wollman * 412999f1343SGarrett Wollman * This preserves definition of in_pcbconnect(), while supporting a 413999f1343SGarrett Wollman * slightly different version for T/TCP. (This is more than 414999f1343SGarrett Wollman * a bit of a kludge, but cleaning up the internal interfaces would 415999f1343SGarrett Wollman * have forced minor changes in every protocol). 416999f1343SGarrett Wollman */ 417999f1343SGarrett Wollman 418999f1343SGarrett Wollman int 419999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin) 420999f1343SGarrett Wollman register struct inpcb *inp; 42157bf258eSGarrett Wollman struct sockaddr *nam; 422999f1343SGarrett Wollman struct sockaddr_in **plocal_sin; 423999f1343SGarrett Wollman { 424df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 42557bf258eSGarrett Wollman register struct sockaddr_in *sin = (struct sockaddr_in *)nam; 426df8bae1dSRodney W. Grimes 42757bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 428df8bae1dSRodney W. Grimes return (EINVAL); 429df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 430df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 431df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 432df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 43359562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 434df8bae1dSRodney W. Grimes /* 435df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 436df8bae1dSRodney W. Grimes * use the primary local address. 437df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 438df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 439df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 440df8bae1dSRodney W. Grimes */ 441df8bae1dSRodney W. Grimes if (sin->sin_addr.s_addr == INADDR_ANY) 442fc2ffbe6SPoul-Henning Kamp sin->sin_addr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; 443df8bae1dSRodney W. Grimes else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 444fc2ffbe6SPoul-Henning Kamp (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST)) 445fc2ffbe6SPoul-Henning Kamp sin->sin_addr = satosin(&TAILQ_FIRST(&in_ifaddrhead)->ia_broadaddr)->sin_addr; 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 448df8bae1dSRodney W. Grimes register struct route *ro; 449df8bae1dSRodney W. Grimes 450df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 451df8bae1dSRodney W. Grimes /* 452df8bae1dSRodney W. Grimes * If route is known or can be allocated now, 453df8bae1dSRodney W. Grimes * our src addr is taken from the i/f, else punt. 454a4a6e773SHajimu UMEMOTO * Note that we should check the address family of the cached 455a4a6e773SHajimu UMEMOTO * destination, in case of sharing the cache with IPv6. 456df8bae1dSRodney W. Grimes */ 457df8bae1dSRodney W. Grimes ro = &inp->inp_route; 458df8bae1dSRodney W. Grimes if (ro->ro_rt && 459a4a6e773SHajimu UMEMOTO (ro->ro_dst.sa_family != AF_INET || 460a4a6e773SHajimu UMEMOTO satosin(&ro->ro_dst)->sin_addr.s_addr != 461df8bae1dSRodney W. Grimes sin->sin_addr.s_addr || 462df8bae1dSRodney W. Grimes inp->inp_socket->so_options & SO_DONTROUTE)) { 463df8bae1dSRodney W. Grimes RTFREE(ro->ro_rt); 464df8bae1dSRodney W. Grimes ro->ro_rt = (struct rtentry *)0; 465df8bae1dSRodney W. Grimes } 466df8bae1dSRodney W. Grimes if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 467df8bae1dSRodney W. Grimes (ro->ro_rt == (struct rtentry *)0 || 468df8bae1dSRodney W. Grimes ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 469df8bae1dSRodney W. Grimes /* No route yet, so try to acquire one */ 470a4a6e773SHajimu UMEMOTO bzero(&ro->ro_dst, sizeof(struct sockaddr_in)); 471df8bae1dSRodney W. Grimes ro->ro_dst.sa_family = AF_INET; 472df8bae1dSRodney W. Grimes ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 473df8bae1dSRodney W. Grimes ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 474df8bae1dSRodney W. Grimes sin->sin_addr; 475df8bae1dSRodney W. Grimes rtalloc(ro); 4764cc20ab1SSeigo Tanimura } 477df8bae1dSRodney W. Grimes /* 478df8bae1dSRodney W. Grimes * If we found a route, use the address 479df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 480df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 481df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 482df8bae1dSRodney W. Grimes */ 483df8bae1dSRodney W. Grimes if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 484df8bae1dSRodney W. Grimes ia = ifatoia(ro->ro_rt->rt_ifa); 485df8bae1dSRodney W. Grimes if (ia == 0) { 486df8bae1dSRodney W. Grimes u_short fport = sin->sin_port; 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes sin->sin_port = 0; 489df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 490df8bae1dSRodney W. Grimes if (ia == 0) 491df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 492df8bae1dSRodney W. Grimes sin->sin_port = fport; 493df8bae1dSRodney W. Grimes if (ia == 0) 494fc2ffbe6SPoul-Henning Kamp ia = TAILQ_FIRST(&in_ifaddrhead); 495df8bae1dSRodney W. Grimes if (ia == 0) 496df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 497df8bae1dSRodney W. Grimes } 498df8bae1dSRodney W. Grimes /* 499df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 500df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 501df8bae1dSRodney W. Grimes * address of that interface as our source address. 502df8bae1dSRodney W. Grimes */ 503df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 504df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 505df8bae1dSRodney W. Grimes struct ip_moptions *imo; 506df8bae1dSRodney W. Grimes struct ifnet *ifp; 507df8bae1dSRodney W. Grimes 508df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 509df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 510df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 51137d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 512df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 513df8bae1dSRodney W. Grimes break; 514df8bae1dSRodney W. Grimes if (ia == 0) 515df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 516df8bae1dSRodney W. Grimes } 517df8bae1dSRodney W. Grimes } 518999f1343SGarrett Wollman /* 519999f1343SGarrett Wollman * Don't do pcblookup call here; return interface in plocal_sin 520999f1343SGarrett Wollman * and exit to caller, that will do the lookup. 521999f1343SGarrett Wollman */ 522999f1343SGarrett Wollman *plocal_sin = &ia->ia_addr; 523999f1343SGarrett Wollman 524999f1343SGarrett Wollman } 525999f1343SGarrett Wollman return(0); 526999f1343SGarrett Wollman } 527999f1343SGarrett Wollman 528999f1343SGarrett Wollman /* 529999f1343SGarrett Wollman * Outer subroutine: 530999f1343SGarrett Wollman * Connect from a socket to a specified address. 531999f1343SGarrett Wollman * Both address and port must be specified in argument sin. 532999f1343SGarrett Wollman * If don't have a local address for this socket yet, 533999f1343SGarrett Wollman * then pick one. 534999f1343SGarrett Wollman */ 535999f1343SGarrett Wollman int 536b40ce416SJulian Elischer in_pcbconnect(inp, nam, td) 537999f1343SGarrett Wollman register struct inpcb *inp; 53857bf258eSGarrett Wollman struct sockaddr *nam; 539b40ce416SJulian Elischer struct thread *td; 540999f1343SGarrett Wollman { 541999f1343SGarrett Wollman struct sockaddr_in *ifaddr; 542e4bdf25dSPoul-Henning Kamp struct sockaddr_in *sin = (struct sockaddr_in *)nam; 543e4bdf25dSPoul-Henning Kamp struct sockaddr_in sa; 54491421ba2SRobert Watson struct ucred *cred; 545999f1343SGarrett Wollman int error; 546999f1343SGarrett Wollman 54791421ba2SRobert Watson cred = inp->inp_socket->so_cred; 54891421ba2SRobert Watson if (inp->inp_laddr.s_addr == INADDR_ANY && jailed(cred)) { 549e4bdf25dSPoul-Henning Kamp bzero(&sa, sizeof (sa)); 55001137630SRobert Watson sa.sin_addr.s_addr = htonl(prison_getip(cred)); 551e4bdf25dSPoul-Henning Kamp sa.sin_len=sizeof (sa); 552e4bdf25dSPoul-Henning Kamp sa.sin_family = AF_INET; 553b40ce416SJulian Elischer error = in_pcbbind(inp, (struct sockaddr *)&sa, td); 554e4bdf25dSPoul-Henning Kamp if (error) 555e4bdf25dSPoul-Henning Kamp return (error); 556e4bdf25dSPoul-Henning Kamp } 557999f1343SGarrett Wollman /* 558999f1343SGarrett Wollman * Call inner routine, to assign local interface address. 559999f1343SGarrett Wollman */ 560831a80b0SMatthew Dillon if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0) 561999f1343SGarrett Wollman return(error); 562999f1343SGarrett Wollman 563c3229e05SDavid Greenman if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 564df8bae1dSRodney W. Grimes inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 565cfa1ca9dSYoshinobu Inoue inp->inp_lport, 0, NULL) != NULL) { 566df8bae1dSRodney W. Grimes return (EADDRINUSE); 567c3229e05SDavid Greenman } 568df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 5695a903f8dSPierre Beyssac if (inp->inp_lport == 0) { 570b40ce416SJulian Elischer error = in_pcbbind(inp, (struct sockaddr *)0, td); 5715a903f8dSPierre Beyssac if (error) 5725a903f8dSPierre Beyssac return (error); 5735a903f8dSPierre Beyssac } 574df8bae1dSRodney W. Grimes inp->inp_laddr = ifaddr->sin_addr; 575df8bae1dSRodney W. Grimes } 576df8bae1dSRodney W. Grimes inp->inp_faddr = sin->sin_addr; 577df8bae1dSRodney W. Grimes inp->inp_fport = sin->sin_port; 57815bd2b43SDavid Greenman in_pcbrehash(inp); 579df8bae1dSRodney W. Grimes return (0); 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes 58226f9a767SRodney W. Grimes void 583df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 584df8bae1dSRodney W. Grimes struct inpcb *inp; 585df8bae1dSRodney W. Grimes { 586df8bae1dSRodney W. Grimes 587df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 588df8bae1dSRodney W. Grimes inp->inp_fport = 0; 58915bd2b43SDavid Greenman in_pcbrehash(inp); 5904cc20ab1SSeigo Tanimura if (inp->inp_socket->so_state & SS_NOFDREF) 591df8bae1dSRodney W. Grimes in_pcbdetach(inp); 592df8bae1dSRodney W. Grimes } 593df8bae1dSRodney W. Grimes 59426f9a767SRodney W. Grimes void 595df8bae1dSRodney W. Grimes in_pcbdetach(inp) 596df8bae1dSRodney W. Grimes struct inpcb *inp; 597df8bae1dSRodney W. Grimes { 598df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 5993d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 600df8bae1dSRodney W. Grimes 601cfa1ca9dSYoshinobu Inoue #ifdef IPSEC 602cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 603cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/ 6043d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 605c3229e05SDavid Greenman in_pcbremlists(inp); 606df8bae1dSRodney W. Grimes so->so_pcb = 0; 607b1e4abd2SMatthew Dillon sotryfree(so); 608df8bae1dSRodney W. Grimes if (inp->inp_options) 609df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 610be2ac88cSJonathan Lemon if (inp->inp_route.ro_rt) 611be2ac88cSJonathan Lemon rtfree(inp->inp_route.ro_rt); 612df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 613cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 614f76fcf6dSJeffrey Hsu INP_LOCK_DESTROY(inp); 61569c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 616df8bae1dSRodney W. Grimes } 617df8bae1dSRodney W. Grimes 61826ef6ac4SDon Lewis struct sockaddr * 61926ef6ac4SDon Lewis in_sockaddr(port, addr_p) 62026ef6ac4SDon Lewis in_port_t port; 62126ef6ac4SDon Lewis struct in_addr *addr_p; 62226ef6ac4SDon Lewis { 62326ef6ac4SDon Lewis struct sockaddr_in *sin; 62426ef6ac4SDon Lewis 62526ef6ac4SDon Lewis MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, 62626ef6ac4SDon Lewis M_WAITOK | M_ZERO); 62726ef6ac4SDon Lewis sin->sin_family = AF_INET; 62826ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 62926ef6ac4SDon Lewis sin->sin_addr = *addr_p; 63026ef6ac4SDon Lewis sin->sin_port = port; 63126ef6ac4SDon Lewis 63226ef6ac4SDon Lewis return (struct sockaddr *)sin; 63326ef6ac4SDon Lewis } 63426ef6ac4SDon Lewis 635117bcae7SGarrett Wollman /* 636f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 637f76fcf6dSJeffrey Hsu * The socket must have a valid 638117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 639117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 64057bf258eSGarrett Wollman * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 64157bf258eSGarrett Wollman * because there actually /is/ a programming error somewhere... XXX) 642117bcae7SGarrett Wollman */ 643117bcae7SGarrett Wollman int 644f76fcf6dSJeffrey Hsu in_setsockaddr(so, nam, pcbinfo) 645117bcae7SGarrett Wollman struct socket *so; 64657bf258eSGarrett Wollman struct sockaddr **nam; 647f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 648df8bae1dSRodney W. Grimes { 649fdc984f7STor Egge int s; 650fdc984f7STor Egge register struct inpcb *inp; 65126ef6ac4SDon Lewis struct in_addr addr; 65226ef6ac4SDon Lewis in_port_t port; 65342fa505bSDavid Greenman 654fdc984f7STor Egge s = splnet(); 655f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 656fdc984f7STor Egge inp = sotoinpcb(so); 657db112f04STor Egge if (!inp) { 658f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 659db112f04STor Egge splx(s); 660ff079ca4SPeter Wemm return ECONNRESET; 661db112f04STor Egge } 662f76fcf6dSJeffrey Hsu INP_LOCK(inp); 66326ef6ac4SDon Lewis port = inp->inp_lport; 66426ef6ac4SDon Lewis addr = inp->inp_laddr; 665f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 666f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 667db112f04STor Egge splx(s); 66842fa505bSDavid Greenman 66926ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 670117bcae7SGarrett Wollman return 0; 671df8bae1dSRodney W. Grimes } 672df8bae1dSRodney W. Grimes 673f76fcf6dSJeffrey Hsu /* 674f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 675f76fcf6dSJeffrey Hsu */ 676117bcae7SGarrett Wollman int 677f76fcf6dSJeffrey Hsu in_setpeeraddr(so, nam, pcbinfo) 678117bcae7SGarrett Wollman struct socket *so; 67957bf258eSGarrett Wollman struct sockaddr **nam; 680f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 681df8bae1dSRodney W. Grimes { 682fdc984f7STor Egge int s; 683f76fcf6dSJeffrey Hsu register struct inpcb *inp; 68426ef6ac4SDon Lewis struct in_addr addr; 68526ef6ac4SDon Lewis in_port_t port; 68642fa505bSDavid Greenman 687fdc984f7STor Egge s = splnet(); 688f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 689fdc984f7STor Egge inp = sotoinpcb(so); 690db112f04STor Egge if (!inp) { 691f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 692db112f04STor Egge splx(s); 693ff079ca4SPeter Wemm return ECONNRESET; 694db112f04STor Egge } 695f76fcf6dSJeffrey Hsu INP_LOCK(inp); 69626ef6ac4SDon Lewis port = inp->inp_fport; 69726ef6ac4SDon Lewis addr = inp->inp_faddr; 698f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 699f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 700db112f04STor Egge splx(s); 70142fa505bSDavid Greenman 70226ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 703117bcae7SGarrett Wollman return 0; 704df8bae1dSRodney W. Grimes } 705df8bae1dSRodney W. Grimes 70626f9a767SRodney W. Grimes void 707f76fcf6dSJeffrey Hsu in_pcbnotifyall(pcbinfo, faddr, errno, notify) 708f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 709df8bae1dSRodney W. Grimes struct in_addr faddr; 710c693a045SJonathan Lemon int errno; 7113ce144eaSJeffrey Hsu struct inpcb *(*notify)(struct inpcb *, int); 712d1c54148SJesper Skriver { 713c693a045SJonathan Lemon struct inpcb *inp, *ninp; 714f76fcf6dSJeffrey Hsu struct inpcbhead *head; 715c693a045SJonathan Lemon int s; 716d1c54148SJesper Skriver 717d1c54148SJesper Skriver s = splnet(); 718f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 719f76fcf6dSJeffrey Hsu head = pcbinfo->listhead; 720c693a045SJonathan Lemon for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { 721f76fcf6dSJeffrey Hsu INP_LOCK(inp); 722c693a045SJonathan Lemon ninp = LIST_NEXT(inp, inp_list); 723d1c54148SJesper Skriver #ifdef INET6 724f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 725f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 726d1c54148SJesper Skriver continue; 727f76fcf6dSJeffrey Hsu } 728d1c54148SJesper Skriver #endif 729d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 730f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 731f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 732d1c54148SJesper Skriver continue; 733d1c54148SJesper Skriver } 734f76fcf6dSJeffrey Hsu (*notify)(inp, errno); 735f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 736f76fcf6dSJeffrey Hsu } 737f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 738d1c54148SJesper Skriver splx(s); 739d1c54148SJesper Skriver } 740d1c54148SJesper Skriver 741e43cc4aeSHajimu UMEMOTO void 742f76fcf6dSJeffrey Hsu in_pcbpurgeif0(pcbinfo, ifp) 743f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 744e43cc4aeSHajimu UMEMOTO struct ifnet *ifp; 745e43cc4aeSHajimu UMEMOTO { 746e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 747e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 748e43cc4aeSHajimu UMEMOTO int i, gap; 749e43cc4aeSHajimu UMEMOTO 750f76fcf6dSJeffrey Hsu /* why no splnet here? XXX */ 751f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 7523cfcc388SJeffrey Hsu LIST_FOREACH(inp, pcbinfo->listhead, inp_list) { 753f76fcf6dSJeffrey Hsu INP_LOCK(inp); 754e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 755e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 756e43cc4aeSHajimu UMEMOTO imo != NULL) { 757e43cc4aeSHajimu UMEMOTO /* 758e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 759e43cc4aeSHajimu UMEMOTO * detached. 760e43cc4aeSHajimu UMEMOTO */ 761e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 762e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 763e43cc4aeSHajimu UMEMOTO 764e43cc4aeSHajimu UMEMOTO /* 765e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 766e43cc4aeSHajimu UMEMOTO * through the interface being detached. 767e43cc4aeSHajimu UMEMOTO */ 768e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 769e43cc4aeSHajimu UMEMOTO i++) { 770e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 771e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 772e43cc4aeSHajimu UMEMOTO gap++; 773e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 774e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 775e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 776e43cc4aeSHajimu UMEMOTO } 777e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 778e43cc4aeSHajimu UMEMOTO } 779f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 780e43cc4aeSHajimu UMEMOTO } 7813cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 782e43cc4aeSHajimu UMEMOTO } 783e43cc4aeSHajimu UMEMOTO 784df8bae1dSRodney W. Grimes /* 785df8bae1dSRodney W. Grimes * Check for alternatives when higher level complains 786df8bae1dSRodney W. Grimes * about service problems. For now, invalidate cached 787df8bae1dSRodney W. Grimes * routing information. If the route was created dynamically 788df8bae1dSRodney W. Grimes * (by a redirect), time to try a default gateway again. 789df8bae1dSRodney W. Grimes */ 79026f9a767SRodney W. Grimes void 791df8bae1dSRodney W. Grimes in_losing(inp) 792df8bae1dSRodney W. Grimes struct inpcb *inp; 793df8bae1dSRodney W. Grimes { 794df8bae1dSRodney W. Grimes register struct rtentry *rt; 795df8bae1dSRodney W. Grimes struct rt_addrinfo info; 796df8bae1dSRodney W. Grimes 797df8bae1dSRodney W. Grimes if ((rt = inp->inp_route.ro_rt)) { 798df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 7998071913dSRuslan Ermilov info.rti_flags = rt->rt_flags; 8008071913dSRuslan Ermilov info.rti_info[RTAX_DST] = rt_key(rt); 801df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 802df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = rt_mask(rt); 803df8bae1dSRodney W. Grimes rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 804df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_DYNAMIC) 8058071913dSRuslan Ermilov (void) rtrequest1(RTM_DELETE, &info, NULL); 8068071913dSRuslan Ermilov inp->inp_route.ro_rt = NULL; 8078bf82a92SRuslan Ermilov rtfree(rt); 808df8bae1dSRodney W. Grimes /* 809df8bae1dSRodney W. Grimes * A new route can be allocated 810df8bae1dSRodney W. Grimes * the next time output is attempted. 811df8bae1dSRodney W. Grimes */ 812df8bae1dSRodney W. Grimes } 813df8bae1dSRodney W. Grimes } 814df8bae1dSRodney W. Grimes 815df8bae1dSRodney W. Grimes /* 816df8bae1dSRodney W. Grimes * After a routing change, flush old routing 817df8bae1dSRodney W. Grimes * and allocate a (hopefully) better one. 818df8bae1dSRodney W. Grimes */ 8193ce144eaSJeffrey Hsu struct inpcb * 820df8bae1dSRodney W. Grimes in_rtchange(inp, errno) 821df8bae1dSRodney W. Grimes register struct inpcb *inp; 822df8bae1dSRodney W. Grimes int errno; 823df8bae1dSRodney W. Grimes { 824df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) { 825df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 826df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 827df8bae1dSRodney W. Grimes /* 828df8bae1dSRodney W. Grimes * A new route can be allocated the next time 829df8bae1dSRodney W. Grimes * output is attempted. 830df8bae1dSRodney W. Grimes */ 831df8bae1dSRodney W. Grimes } 8323ce144eaSJeffrey Hsu return inp; 833df8bae1dSRodney W. Grimes } 834df8bae1dSRodney W. Grimes 835c3229e05SDavid Greenman /* 836c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 837c3229e05SDavid Greenman */ 838df8bae1dSRodney W. Grimes struct inpcb * 839c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 8406d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 841c3229e05SDavid Greenman struct in_addr laddr; 842c3229e05SDavid Greenman u_int lport_arg; 8436d6a026bSDavid Greenman int wild_okay; 844df8bae1dSRodney W. Grimes { 845f1d19042SArchie Cobbs register struct inpcb *inp; 846df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 847c3229e05SDavid Greenman u_short lport = lport_arg; 8487bc4aca7SDavid Greenman 849c3229e05SDavid Greenman if (!wild_okay) { 850c3229e05SDavid Greenman struct inpcbhead *head; 851c3229e05SDavid Greenman /* 852c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 853c3229e05SDavid Greenman * matches the local address and port we're looking for. 854c3229e05SDavid Greenman */ 855c3229e05SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 856fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 857cfa1ca9dSYoshinobu Inoue #ifdef INET6 858369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 859cfa1ca9dSYoshinobu Inoue continue; 860cfa1ca9dSYoshinobu Inoue #endif 861c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 862c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 863c3229e05SDavid Greenman inp->inp_lport == lport) { 864c3229e05SDavid Greenman /* 865c3229e05SDavid Greenman * Found. 866c3229e05SDavid Greenman */ 867c3229e05SDavid Greenman return (inp); 868df8bae1dSRodney W. Grimes } 869c3229e05SDavid Greenman } 870c3229e05SDavid Greenman /* 871c3229e05SDavid Greenman * Not found. 872c3229e05SDavid Greenman */ 873c3229e05SDavid Greenman return (NULL); 874c3229e05SDavid Greenman } else { 875c3229e05SDavid Greenman struct inpcbporthead *porthash; 876c3229e05SDavid Greenman struct inpcbport *phd; 877c3229e05SDavid Greenman struct inpcb *match = NULL; 878c3229e05SDavid Greenman /* 879c3229e05SDavid Greenman * Best fit PCB lookup. 880c3229e05SDavid Greenman * 881c3229e05SDavid Greenman * First see if this local port is in use by looking on the 882c3229e05SDavid Greenman * port hash list. 883c3229e05SDavid Greenman */ 884c3229e05SDavid Greenman porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 885c3229e05SDavid Greenman pcbinfo->porthashmask)]; 886fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 887c3229e05SDavid Greenman if (phd->phd_port == lport) 888c3229e05SDavid Greenman break; 889c3229e05SDavid Greenman } 890c3229e05SDavid Greenman if (phd != NULL) { 891c3229e05SDavid Greenman /* 892c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 893c3229e05SDavid Greenman * fit. 894c3229e05SDavid Greenman */ 89537d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 896c3229e05SDavid Greenman wildcard = 0; 897cfa1ca9dSYoshinobu Inoue #ifdef INET6 898369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 899cfa1ca9dSYoshinobu Inoue continue; 900cfa1ca9dSYoshinobu Inoue #endif 901c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 902c3229e05SDavid Greenman wildcard++; 90315bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 90415bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 90515bd2b43SDavid Greenman wildcard++; 90615bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 90715bd2b43SDavid Greenman continue; 90815bd2b43SDavid Greenman } else { 90915bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 91015bd2b43SDavid Greenman wildcard++; 91115bd2b43SDavid Greenman } 912df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 913df8bae1dSRodney W. Grimes match = inp; 914df8bae1dSRodney W. Grimes matchwild = wildcard; 9153dbdc25cSDavid Greenman if (matchwild == 0) { 916df8bae1dSRodney W. Grimes break; 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes } 9193dbdc25cSDavid Greenman } 920c3229e05SDavid Greenman } 921df8bae1dSRodney W. Grimes return (match); 922df8bae1dSRodney W. Grimes } 923c3229e05SDavid Greenman } 92415bd2b43SDavid Greenman 92515bd2b43SDavid Greenman /* 92615bd2b43SDavid Greenman * Lookup PCB in hash list. 92715bd2b43SDavid Greenman */ 92815bd2b43SDavid Greenman struct inpcb * 929cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, 930cfa1ca9dSYoshinobu Inoue ifp) 93115bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 93215bd2b43SDavid Greenman struct in_addr faddr, laddr; 93315bd2b43SDavid Greenman u_int fport_arg, lport_arg; 9346d6a026bSDavid Greenman int wildcard; 935cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 93615bd2b43SDavid Greenman { 93715bd2b43SDavid Greenman struct inpcbhead *head; 93815bd2b43SDavid Greenman register struct inpcb *inp; 93915bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 94015bd2b43SDavid Greenman 94115bd2b43SDavid Greenman /* 94215bd2b43SDavid Greenman * First look for an exact match. 94315bd2b43SDavid Greenman */ 944ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 945fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 946cfa1ca9dSYoshinobu Inoue #ifdef INET6 947369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 948cfa1ca9dSYoshinobu Inoue continue; 949cfa1ca9dSYoshinobu Inoue #endif 9506d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 951ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 952ca98b82cSDavid Greenman inp->inp_fport == fport && 953c3229e05SDavid Greenman inp->inp_lport == lport) { 954c3229e05SDavid Greenman /* 955c3229e05SDavid Greenman * Found. 956c3229e05SDavid Greenman */ 957c3229e05SDavid Greenman return (inp); 958c3229e05SDavid Greenman } 9596d6a026bSDavid Greenman } 9606d6a026bSDavid Greenman if (wildcard) { 9616d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 962cfa1ca9dSYoshinobu Inoue #if defined(INET6) 963cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 964cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 9656d6a026bSDavid Greenman 966ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 967fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 968cfa1ca9dSYoshinobu Inoue #ifdef INET6 969369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 970cfa1ca9dSYoshinobu Inoue continue; 971cfa1ca9dSYoshinobu Inoue #endif 9726d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 973c3229e05SDavid Greenman inp->inp_lport == lport) { 974cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 975cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 976cfa1ca9dSYoshinobu Inoue continue; 9776d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 978c3229e05SDavid Greenman return (inp); 979cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 980cfa1ca9dSYoshinobu Inoue #if defined(INET6) 981cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 982cfa1ca9dSYoshinobu Inoue AF_INET6)) 983cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 984cfa1ca9dSYoshinobu Inoue else 985cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 9866d6a026bSDavid Greenman local_wild = inp; 9876d6a026bSDavid Greenman } 9886d6a026bSDavid Greenman } 989cfa1ca9dSYoshinobu Inoue } 990cfa1ca9dSYoshinobu Inoue #if defined(INET6) 991cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 992cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 993cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 994c3229e05SDavid Greenman return (local_wild); 9956d6a026bSDavid Greenman } 996c3229e05SDavid Greenman 997c3229e05SDavid Greenman /* 998c3229e05SDavid Greenman * Not found. 999c3229e05SDavid Greenman */ 10006d6a026bSDavid Greenman return (NULL); 100115bd2b43SDavid Greenman } 100215bd2b43SDavid Greenman 10037bc4aca7SDavid Greenman /* 1004c3229e05SDavid Greenman * Insert PCB onto various hash lists. 10057bc4aca7SDavid Greenman */ 1006c3229e05SDavid Greenman int 100715bd2b43SDavid Greenman in_pcbinshash(inp) 100815bd2b43SDavid Greenman struct inpcb *inp; 100915bd2b43SDavid Greenman { 1010c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1011c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1012c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1013c3229e05SDavid Greenman struct inpcbport *phd; 1014cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 101515bd2b43SDavid Greenman 1016cfa1ca9dSYoshinobu Inoue #ifdef INET6 1017cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1018cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1019cfa1ca9dSYoshinobu Inoue else 1020cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1021cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1022cfa1ca9dSYoshinobu Inoue 1023cfa1ca9dSYoshinobu Inoue pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 1024c3229e05SDavid Greenman inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 102515bd2b43SDavid Greenman 1026c3229e05SDavid Greenman pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, 1027c3229e05SDavid Greenman pcbinfo->porthashmask)]; 1028c3229e05SDavid Greenman 1029c3229e05SDavid Greenman /* 1030c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1031c3229e05SDavid Greenman */ 1032fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1033c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1034c3229e05SDavid Greenman break; 1035c3229e05SDavid Greenman } 1036c3229e05SDavid Greenman /* 1037c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1038c3229e05SDavid Greenman */ 1039c3229e05SDavid Greenman if (phd == NULL) { 1040c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1041c3229e05SDavid Greenman if (phd == NULL) { 1042c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1043c3229e05SDavid Greenman } 1044c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1045c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1046c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1047c3229e05SDavid Greenman } 1048c3229e05SDavid Greenman inp->inp_phd = phd; 1049c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1050c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1051c3229e05SDavid Greenman return (0); 105215bd2b43SDavid Greenman } 105315bd2b43SDavid Greenman 1054c3229e05SDavid Greenman /* 1055c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1056c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1057c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1058c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1059c3229e05SDavid Greenman */ 106015bd2b43SDavid Greenman void 106115bd2b43SDavid Greenman in_pcbrehash(inp) 106215bd2b43SDavid Greenman struct inpcb *inp; 106315bd2b43SDavid Greenman { 106415bd2b43SDavid Greenman struct inpcbhead *head; 1065cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 106615bd2b43SDavid Greenman 1067cfa1ca9dSYoshinobu Inoue #ifdef INET6 1068cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1069cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1070cfa1ca9dSYoshinobu Inoue else 1071cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1072cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1073cfa1ca9dSYoshinobu Inoue 1074cfa1ca9dSYoshinobu Inoue head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 1075ddd79a97SDavid Greenman inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 107615bd2b43SDavid Greenman 1077c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 107815bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1079c3229e05SDavid Greenman } 1080c3229e05SDavid Greenman 1081c3229e05SDavid Greenman /* 1082c3229e05SDavid Greenman * Remove PCB from various lists. 1083c3229e05SDavid Greenman */ 108476429de4SYoshinobu Inoue void 1085c3229e05SDavid Greenman in_pcbremlists(inp) 1086c3229e05SDavid Greenman struct inpcb *inp; 1087c3229e05SDavid Greenman { 108898271db4SGarrett Wollman inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt; 1089c3229e05SDavid Greenman if (inp->inp_lport) { 1090c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1091c3229e05SDavid Greenman 1092c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1093c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1094fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1095c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1096c3229e05SDavid Greenman free(phd, M_PCB); 1097c3229e05SDavid Greenman } 1098c3229e05SDavid Greenman } 1099c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 11003d4d47f3SGarrett Wollman inp->inp_pcbinfo->ipi_count--; 110115bd2b43SDavid Greenman } 110275c13541SPoul-Henning Kamp 110375c13541SPoul-Henning Kamp int 1104ad278afdSJohn Baldwin prison_xinpcb(struct thread *td, struct inpcb *inp) 110575c13541SPoul-Henning Kamp { 1106ad278afdSJohn Baldwin if (!jailed(td->td_ucred)) 110775c13541SPoul-Henning Kamp return (0); 1108ad278afdSJohn Baldwin if (ntohl(inp->inp_laddr.s_addr) == prison_getip(td->td_ucred)) 110975c13541SPoul-Henning Kamp return (0); 111075c13541SPoul-Henning Kamp return (1); 111175c13541SPoul-Henning Kamp } 1112