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> 42104a9b7eSAlexander Kabaev #include <sys/limits.h> 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 44df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 46df8bae1dSRodney W. Grimes #include <sys/protosw.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 49df8bae1dSRodney W. Grimes #include <sys/proc.h> 5075c13541SPoul-Henning Kamp #include <sys/jail.h> 51101f9fc8SPeter Wemm #include <sys/kernel.h> 52101f9fc8SPeter Wemm #include <sys/sysctl.h> 538781d8e9SBruce Evans 5469c2d429SJeff Roberson #include <vm/uma.h> 55df8bae1dSRodney W. Grimes 56df8bae1dSRodney W. Grimes #include <net/if.h> 57cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 58df8bae1dSRodney W. Grimes #include <net/route.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <netinet/in.h> 61df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 62df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 63df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 64340c35deSJonathan Lemon #include <netinet/tcp_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 #endif /* FAST_IPSEC */ 83b9234fafSSam Leffler 84df8bae1dSRodney W. Grimes struct in_addr zeroin_addr; 85df8bae1dSRodney W. Grimes 86101f9fc8SPeter Wemm /* 87101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 88101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 89101f9fc8SPeter Wemm */ 9082cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 9182cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 929e5a5ed4SMike Silbersack int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 939e5a5ed4SMike Silbersack int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */ 9482cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9582cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 96101f9fc8SPeter Wemm 97b0d22693SCrist J. Clark /* 98b0d22693SCrist J. Clark * Reserved ports accessible only to root. There are significant 99b0d22693SCrist J. Clark * security considerations that must be accounted for when changing these, 100b0d22693SCrist J. Clark * but the security benefits can be great. Please be careful. 101b0d22693SCrist J. Clark */ 102b0d22693SCrist J. Clark int ipport_reservedhigh = IPPORT_RESERVED - 1; /* 1023 */ 103b0d22693SCrist J. Clark int ipport_reservedlow = 0; 104b0d22693SCrist J. Clark 105bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 106bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 107bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 108bbd42ad0SPeter Wemm 109bbd42ad0SPeter Wemm static int 11082d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 111bbd42ad0SPeter Wemm { 112bbd42ad0SPeter Wemm int error = sysctl_handle_int(oidp, 113bbd42ad0SPeter Wemm oidp->oid_arg1, oidp->oid_arg2, req); 114bbd42ad0SPeter Wemm if (!error) { 115bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 116bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 117bbd42ad0SPeter Wemm RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 118bbd42ad0SPeter Wemm RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 119bbd42ad0SPeter Wemm RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 120bbd42ad0SPeter Wemm RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 121bbd42ad0SPeter Wemm } 122bbd42ad0SPeter Wemm return error; 123bbd42ad0SPeter Wemm } 124bbd42ad0SPeter Wemm 125bbd42ad0SPeter Wemm #undef RANGECHK 126bbd42ad0SPeter Wemm 12733b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 12833b3ac06SPeter Wemm 129bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 130bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 131bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 132bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 133bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 134bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 135bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 136bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 137bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 138bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 139bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 140bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 141b0d22693SCrist J. Clark SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedhigh, 142b0d22693SCrist J. Clark CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedhigh, 0, ""); 143b0d22693SCrist J. Clark SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedlow, 144b0d22693SCrist J. Clark CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedlow, 0, ""); 1450312fbe9SPoul-Henning Kamp 146c3229e05SDavid Greenman /* 147c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 148c3229e05SDavid Greenman * 149c3229e05SDavid Greenman * NOTE: It is assumed that most of these functions will be called at 150c3229e05SDavid Greenman * splnet(). XXX - There are, unfortunately, a few exceptions to this 151c3229e05SDavid Greenman * rule that should be fixed. 152c3229e05SDavid Greenman */ 153c3229e05SDavid Greenman 154c3229e05SDavid Greenman /* 155c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 156c3229e05SDavid Greenman */ 157df8bae1dSRodney W. Grimes int 158b40ce416SJulian Elischer in_pcballoc(so, pcbinfo, td) 159df8bae1dSRodney W. Grimes struct socket *so; 16015bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 161b40ce416SJulian Elischer struct thread *td; 162df8bae1dSRodney W. Grimes { 163df8bae1dSRodney W. Grimes register struct inpcb *inp; 1640f9ade71SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC) 16513cf67f3SHajimu UMEMOTO int error; 16613cf67f3SHajimu UMEMOTO #endif 16759daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 168d1dd20beSSam Leffler inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT | M_ZERO); 169df8bae1dSRodney W. Grimes if (inp == NULL) 170df8bae1dSRodney W. Grimes return (ENOBUFS); 1713d4d47f3SGarrett Wollman inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 17215bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 173df8bae1dSRodney W. Grimes inp->inp_socket = so; 1740f9ade71SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC) 1750f9ade71SHajimu UMEMOTO #ifdef FAST_IPSEC 17613cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 1770f9ade71SHajimu UMEMOTO #else 1780f9ade71SHajimu UMEMOTO error = ipsec_init_pcbpolicy(so, &inp->inp_sp); 1790f9ade71SHajimu UMEMOTO #endif 18013cf67f3SHajimu UMEMOTO if (error != 0) { 18169c2d429SJeff Roberson uma_zfree(pcbinfo->ipi_zone, inp); 18213cf67f3SHajimu UMEMOTO return error; 18313cf67f3SHajimu UMEMOTO } 18413cf67f3SHajimu UMEMOTO #endif /*IPSEC*/ 18575daea93SPaul Saab #if defined(INET6) 186340c35deSJonathan Lemon if (INP_SOCKAF(so) == AF_INET6) { 187340c35deSJonathan Lemon inp->inp_vflag |= INP_IPV6PROTO; 188340c35deSJonathan Lemon if (ip6_v6only) 18933841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 190340c35deSJonathan Lemon } 19175daea93SPaul Saab #endif 19215bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 1933d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 194df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 195f76fcf6dSJeffrey Hsu INP_LOCK_INIT(inp, "inp"); 19633841545SHajimu UMEMOTO #ifdef INET6 19733841545SHajimu UMEMOTO if (ip6_auto_flowlabel) 19833841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 19933841545SHajimu UMEMOTO #endif 200df8bae1dSRodney W. Grimes return (0); 201df8bae1dSRodney W. Grimes } 202df8bae1dSRodney W. Grimes 203df8bae1dSRodney W. Grimes int 204b40ce416SJulian Elischer in_pcbbind(inp, nam, td) 205df8bae1dSRodney W. Grimes register struct inpcb *inp; 20657bf258eSGarrett Wollman struct sockaddr *nam; 207b40ce416SJulian Elischer struct thread *td; 208df8bae1dSRodney W. Grimes { 2094b932371SIan Dowse int anonport, error; 2104b932371SIan Dowse 2111b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 21259daba27SSam Leffler INP_LOCK_ASSERT(inp); 21359daba27SSam Leffler 2144b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 2154b932371SIan Dowse return (EINVAL); 2164b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 2174b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 2184b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 2194b932371SIan Dowse &inp->inp_lport, td); 2204b932371SIan Dowse if (error) 2214b932371SIan Dowse return (error); 2224b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2234b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2244b932371SIan Dowse inp->inp_lport = 0; 2254b932371SIan Dowse return (EAGAIN); 2264b932371SIan Dowse } 2274b932371SIan Dowse if (anonport) 2284b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2294b932371SIan Dowse return (0); 2304b932371SIan Dowse } 2314b932371SIan Dowse 2324b932371SIan Dowse /* 2334b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2344b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2354b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2364b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2374b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2384b932371SIan Dowse * 2394b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2404b932371SIan Dowse */ 2414b932371SIan Dowse int 2424b932371SIan Dowse in_pcbbind_setup(inp, nam, laddrp, lportp, td) 2434b932371SIan Dowse struct inpcb *inp; 2444b932371SIan Dowse struct sockaddr *nam; 2454b932371SIan Dowse in_addr_t *laddrp; 2464b932371SIan Dowse u_short *lportp; 2474b932371SIan Dowse struct thread *td; 2484b932371SIan Dowse { 2494b932371SIan Dowse struct socket *so = inp->inp_socket; 25037bd2b30SPeter Wemm unsigned short *lastport; 25115bd2b43SDavid Greenman struct sockaddr_in *sin; 252c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 2534b932371SIan Dowse struct in_addr laddr; 254df8bae1dSRodney W. Grimes u_short lport = 0; 2554cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 25675c13541SPoul-Henning Kamp int error, prison = 0; 257df8bae1dSRodney W. Grimes 2581b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 25959daba27SSam Leffler INP_LOCK_ASSERT(inp); 26059daba27SSam Leffler 26159562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 262df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 2634b932371SIan Dowse laddr.s_addr = *laddrp; 2644b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 265df8bae1dSRodney W. Grimes return (EINVAL); 266c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 2676d6a026bSDavid Greenman wild = 1; 268df8bae1dSRodney W. Grimes if (nam) { 26957bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 27057bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 271df8bae1dSRodney W. Grimes return (EINVAL); 272df8bae1dSRodney W. Grimes #ifdef notdef 273df8bae1dSRodney W. Grimes /* 274df8bae1dSRodney W. Grimes * We should check the family, but old programs 275df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 276df8bae1dSRodney W. Grimes */ 277df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 278df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 279df8bae1dSRodney W. Grimes #endif 280e4bdf25dSPoul-Henning Kamp if (sin->sin_addr.s_addr != INADDR_ANY) 281a854ed98SJohn Baldwin if (prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) 28275c13541SPoul-Henning Kamp return(EINVAL); 2834b932371SIan Dowse if (sin->sin_port != *lportp) { 2844b932371SIan Dowse /* Don't allow the port to change. */ 2854b932371SIan Dowse if (*lportp != 0) 2864b932371SIan Dowse return (EINVAL); 287df8bae1dSRodney W. Grimes lport = sin->sin_port; 2884b932371SIan Dowse } 2894b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 290df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 291df8bae1dSRodney W. Grimes /* 292df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 293df8bae1dSRodney W. Grimes * allow complete duplication of binding if 294df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 295df8bae1dSRodney W. Grimes * and a multicast address is bound on both 296df8bae1dSRodney W. Grimes * new and duplicated sockets. 297df8bae1dSRodney W. Grimes */ 298df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 299df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 300df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 301df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 30283103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 303df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 304df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 305df8bae1dSRodney W. Grimes } 3064b932371SIan Dowse laddr = sin->sin_addr; 307df8bae1dSRodney W. Grimes if (lport) { 308df8bae1dSRodney W. Grimes struct inpcb *t; 309df8bae1dSRodney W. Grimes /* GROSS */ 310b0d22693SCrist J. Clark if (ntohs(lport) <= ipport_reservedhigh && 311b0d22693SCrist J. Clark ntohs(lport) >= ipport_reservedlow && 312b0d22693SCrist J. Clark td && suser_cred(td->td_ucred, PRISON_ROOT)) 3132469dd60SGarrett Wollman return (EACCES); 314a854ed98SJohn Baldwin if (td && jailed(td->td_ucred)) 31575c13541SPoul-Henning Kamp prison = 1; 3162f9a2132SBrian Feldman if (so->so_cred->cr_uid != 0 && 31752b65dbeSBill Fenner !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 3184049a042SGuido van Rooij t = in_pcblookup_local(inp->inp_pcbinfo, 31975c13541SPoul-Henning Kamp sin->sin_addr, lport, 32075c13541SPoul-Henning Kamp prison ? 0 : INPLOOKUP_WILDCARD); 321340c35deSJonathan Lemon /* 322340c35deSJonathan Lemon * XXX 323340c35deSJonathan Lemon * This entire block sorely needs a rewrite. 324340c35deSJonathan Lemon */ 325340c35deSJonathan Lemon if (t && (t->inp_vflag & INP_TIMEWAIT)) { 326340c35deSJonathan Lemon if ((ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 327340c35deSJonathan Lemon ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 328340c35deSJonathan Lemon (intotw(t)->tw_so_options & SO_REUSEPORT) == 0) && 329340c35deSJonathan Lemon (so->so_cred->cr_uid != intotw(t)->tw_cred->cr_uid)) 330340c35deSJonathan Lemon return (EADDRINUSE); 331340c35deSJonathan Lemon } else 3324cc20ab1SSeigo Tanimura if (t && 3334cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 33452b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 33552b65dbeSBill Fenner (t->inp_socket->so_options & 33652b65dbeSBill Fenner SO_REUSEPORT) == 0) && 3372f9a2132SBrian Feldman (so->so_cred->cr_uid != 338cfa1ca9dSYoshinobu Inoue t->inp_socket->so_cred->cr_uid)) { 339cfa1ca9dSYoshinobu Inoue #if defined(INET6) 34033841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 341cfa1ca9dSYoshinobu Inoue INADDR_ANY || 342cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 343cfa1ca9dSYoshinobu Inoue INADDR_ANY || 344cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 345cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 346cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 3474049a042SGuido van Rooij return (EADDRINUSE); 3484049a042SGuido van Rooij } 349cfa1ca9dSYoshinobu Inoue } 350970680faSPoul-Henning Kamp if (prison && 351a854ed98SJohn Baldwin prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) 352970680faSPoul-Henning Kamp return (EADDRNOTAVAIL); 353c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 35475c13541SPoul-Henning Kamp lport, prison ? 0 : wild); 355340c35deSJonathan Lemon if (t && (t->inp_vflag & INP_TIMEWAIT)) { 356340c35deSJonathan Lemon if ((reuseport & intotw(t)->tw_so_options) == 0) 357340c35deSJonathan Lemon return (EADDRINUSE); 358340c35deSJonathan Lemon } else 3594cc20ab1SSeigo Tanimura if (t && 3604cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 361cfa1ca9dSYoshinobu Inoue #if defined(INET6) 36233841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 363cfa1ca9dSYoshinobu Inoue INADDR_ANY || 364cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 365cfa1ca9dSYoshinobu Inoue INADDR_ANY || 366cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 367cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 368cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 369df8bae1dSRodney W. Grimes return (EADDRINUSE); 370df8bae1dSRodney W. Grimes } 371cfa1ca9dSYoshinobu Inoue } 372df8bae1dSRodney W. Grimes } 3734b932371SIan Dowse if (*lportp != 0) 3744b932371SIan Dowse lport = *lportp; 37533b3ac06SPeter Wemm if (lport == 0) { 3768b149b51SJohn Baldwin u_short first, last; 37733b3ac06SPeter Wemm int count; 37833b3ac06SPeter Wemm 3794b932371SIan Dowse if (laddr.s_addr != INADDR_ANY) 3804b932371SIan Dowse if (prison_ip(td->td_ucred, 0, &laddr.s_addr)) 38175c13541SPoul-Henning Kamp return (EINVAL); 382321a2846SPoul-Henning Kamp 38333b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 38433b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 38533b3ac06SPeter Wemm last = ipport_hilastauto; 386c3229e05SDavid Greenman lastport = &pcbinfo->lasthi; 38733b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 3884b932371SIan Dowse if (td && (error = suser_cred(td->td_ucred, 3894b932371SIan Dowse PRISON_ROOT)) != 0) 390a29f300eSGarrett Wollman return error; 391bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 392bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 393c3229e05SDavid Greenman lastport = &pcbinfo->lastlow; 39433b3ac06SPeter Wemm } else { 39533b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 39633b3ac06SPeter Wemm last = ipport_lastauto; 397c3229e05SDavid Greenman lastport = &pcbinfo->lastport; 39833b3ac06SPeter Wemm } 39933b3ac06SPeter Wemm /* 40033b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 40133b3ac06SPeter Wemm * a deadlock here. 40233b3ac06SPeter Wemm * 40333b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 40433b3ac06SPeter Wemm * is not being tested on each round of the loop. 40533b3ac06SPeter Wemm */ 40633b3ac06SPeter Wemm if (first > last) { 40733b3ac06SPeter Wemm /* 40833b3ac06SPeter Wemm * counting down 40933b3ac06SPeter Wemm */ 41033b3ac06SPeter Wemm count = first - last; 41133b3ac06SPeter Wemm 412df8bae1dSRodney W. Grimes do { 4134b932371SIan Dowse if (count-- < 0) /* completely used? */ 414550b1518SWes Peters return (EADDRNOTAVAIL); 41533b3ac06SPeter Wemm --*lastport; 41633b3ac06SPeter Wemm if (*lastport > first || *lastport < last) 41733b3ac06SPeter Wemm *lastport = first; 41815bd2b43SDavid Greenman lport = htons(*lastport); 4194b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 4204b932371SIan Dowse wild)); 42133b3ac06SPeter Wemm } else { 42233b3ac06SPeter Wemm /* 42333b3ac06SPeter Wemm * counting up 42433b3ac06SPeter Wemm */ 42533b3ac06SPeter Wemm count = last - first; 42633b3ac06SPeter Wemm 42733b3ac06SPeter Wemm do { 4284b932371SIan Dowse if (count-- < 0) /* completely used? */ 429550b1518SWes Peters return (EADDRNOTAVAIL); 43033b3ac06SPeter Wemm ++*lastport; 43133b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 43233b3ac06SPeter Wemm *lastport = first; 43333b3ac06SPeter Wemm lport = htons(*lastport); 4344b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 4354b932371SIan Dowse wild)); 43633b3ac06SPeter Wemm } 43733b3ac06SPeter Wemm } 4384b932371SIan Dowse if (prison_ip(td->td_ucred, 0, &laddr.s_addr)) 439e4bdf25dSPoul-Henning Kamp return (EINVAL); 4404b932371SIan Dowse *laddrp = laddr.s_addr; 4414b932371SIan Dowse *lportp = lport; 442df8bae1dSRodney W. Grimes return (0); 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes 445999f1343SGarrett Wollman /* 4465200e00eSIan Dowse * Connect from a socket to a specified address. 4475200e00eSIan Dowse * Both address and port must be specified in argument sin. 4485200e00eSIan Dowse * If don't have a local address for this socket yet, 4495200e00eSIan Dowse * then pick one. 450999f1343SGarrett Wollman */ 451999f1343SGarrett Wollman int 4525200e00eSIan Dowse in_pcbconnect(inp, nam, td) 453999f1343SGarrett Wollman register struct inpcb *inp; 45457bf258eSGarrett Wollman struct sockaddr *nam; 4555200e00eSIan Dowse struct thread *td; 456999f1343SGarrett Wollman { 4575200e00eSIan Dowse u_short lport, fport; 4585200e00eSIan Dowse in_addr_t laddr, faddr; 4595200e00eSIan Dowse int anonport, error; 460df8bae1dSRodney W. Grimes 4615200e00eSIan Dowse lport = inp->inp_lport; 4625200e00eSIan Dowse laddr = inp->inp_laddr.s_addr; 4635200e00eSIan Dowse anonport = (lport == 0); 4645200e00eSIan Dowse error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport, 4655200e00eSIan Dowse NULL, td); 4665200e00eSIan Dowse if (error) 4675200e00eSIan Dowse return (error); 4685200e00eSIan Dowse 4695200e00eSIan Dowse /* Do the initial binding of the local address if required. */ 4705200e00eSIan Dowse if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) { 4715200e00eSIan Dowse inp->inp_lport = lport; 4725200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 4735200e00eSIan Dowse if (in_pcbinshash(inp) != 0) { 4745200e00eSIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 4755200e00eSIan Dowse inp->inp_lport = 0; 4765200e00eSIan Dowse return (EAGAIN); 4775200e00eSIan Dowse } 4785200e00eSIan Dowse } 4795200e00eSIan Dowse 4805200e00eSIan Dowse /* Commit the remaining changes. */ 4815200e00eSIan Dowse inp->inp_lport = lport; 4825200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 4835200e00eSIan Dowse inp->inp_faddr.s_addr = faddr; 4845200e00eSIan Dowse inp->inp_fport = fport; 4855200e00eSIan Dowse in_pcbrehash(inp); 4860f9ade71SHajimu UMEMOTO #ifdef IPSEC 4870f9ade71SHajimu UMEMOTO if (inp->inp_socket->so_type == SOCK_STREAM) 4880f9ade71SHajimu UMEMOTO ipsec_pcbconn(inp->inp_sp); 4890f9ade71SHajimu UMEMOTO #endif 4905200e00eSIan Dowse if (anonport) 4915200e00eSIan Dowse inp->inp_flags |= INP_ANONPORT; 4925200e00eSIan Dowse return (0); 4935200e00eSIan Dowse } 4945200e00eSIan Dowse 4955200e00eSIan Dowse /* 4965200e00eSIan Dowse * Set up for a connect from a socket to the specified address. 4975200e00eSIan Dowse * On entry, *laddrp and *lportp should contain the current local 4985200e00eSIan Dowse * address and port for the PCB; these are updated to the values 4995200e00eSIan Dowse * that should be placed in inp_laddr and inp_lport to complete 5005200e00eSIan Dowse * the connect. 5015200e00eSIan Dowse * 5025200e00eSIan Dowse * On success, *faddrp and *fportp will be set to the remote address 5035200e00eSIan Dowse * and port. These are not updated in the error case. 5045200e00eSIan Dowse * 5055200e00eSIan Dowse * If the operation fails because the connection already exists, 5065200e00eSIan Dowse * *oinpp will be set to the PCB of that connection so that the 5075200e00eSIan Dowse * caller can decide to override it. In all other cases, *oinpp 5085200e00eSIan Dowse * is set to NULL. 5095200e00eSIan Dowse */ 5105200e00eSIan Dowse int 5115200e00eSIan Dowse in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, td) 5125200e00eSIan Dowse register struct inpcb *inp; 5135200e00eSIan Dowse struct sockaddr *nam; 5145200e00eSIan Dowse in_addr_t *laddrp; 5155200e00eSIan Dowse u_short *lportp; 5165200e00eSIan Dowse in_addr_t *faddrp; 5175200e00eSIan Dowse u_short *fportp; 5185200e00eSIan Dowse struct inpcb **oinpp; 5195200e00eSIan Dowse struct thread *td; 5205200e00eSIan Dowse { 5215200e00eSIan Dowse struct sockaddr_in *sin = (struct sockaddr_in *)nam; 5225200e00eSIan Dowse struct in_ifaddr *ia; 5235200e00eSIan Dowse struct sockaddr_in sa; 5245200e00eSIan Dowse struct ucred *cred; 5255200e00eSIan Dowse struct inpcb *oinp; 5265200e00eSIan Dowse struct in_addr laddr, faddr; 5275200e00eSIan Dowse u_short lport, fport; 5285200e00eSIan Dowse int error; 5295200e00eSIan Dowse 5305200e00eSIan Dowse if (oinpp != NULL) 5315200e00eSIan Dowse *oinpp = NULL; 53257bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 533df8bae1dSRodney W. Grimes return (EINVAL); 534df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 535df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 536df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 537df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 5385200e00eSIan Dowse laddr.s_addr = *laddrp; 5395200e00eSIan Dowse lport = *lportp; 5405200e00eSIan Dowse faddr = sin->sin_addr; 5415200e00eSIan Dowse fport = sin->sin_port; 5425200e00eSIan Dowse cred = inp->inp_socket->so_cred; 5435200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY && jailed(cred)) { 5445200e00eSIan Dowse bzero(&sa, sizeof(sa)); 5455200e00eSIan Dowse sa.sin_addr.s_addr = htonl(prison_getip(cred)); 5465200e00eSIan Dowse sa.sin_len = sizeof(sa); 5475200e00eSIan Dowse sa.sin_family = AF_INET; 5485200e00eSIan Dowse error = in_pcbbind_setup(inp, (struct sockaddr *)&sa, 5495200e00eSIan Dowse &laddr.s_addr, &lport, td); 5505200e00eSIan Dowse if (error) 5515200e00eSIan Dowse return (error); 5525200e00eSIan Dowse } 5535200e00eSIan Dowse 55459562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 555df8bae1dSRodney W. Grimes /* 556df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 557df8bae1dSRodney W. Grimes * use the primary local address. 558df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 559df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 560df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 561df8bae1dSRodney W. Grimes */ 5625200e00eSIan Dowse if (faddr.s_addr == INADDR_ANY) 5635200e00eSIan Dowse faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; 5645200e00eSIan Dowse else if (faddr.s_addr == (u_long)INADDR_BROADCAST && 5655200e00eSIan Dowse (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & 5665200e00eSIan Dowse IFF_BROADCAST)) 5675200e00eSIan Dowse faddr = satosin(&TAILQ_FIRST( 5685200e00eSIan Dowse &in_ifaddrhead)->ia_broadaddr)->sin_addr; 569df8bae1dSRodney W. Grimes } 5705200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY) { 571df8bae1dSRodney W. Grimes register struct route *ro; 572df8bae1dSRodney W. Grimes 573df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 574df8bae1dSRodney W. Grimes /* 575df8bae1dSRodney W. Grimes * If route is known or can be allocated now, 576df8bae1dSRodney W. Grimes * our src addr is taken from the i/f, else punt. 577a4a6e773SHajimu UMEMOTO * Note that we should check the address family of the cached 578a4a6e773SHajimu UMEMOTO * destination, in case of sharing the cache with IPv6. 579df8bae1dSRodney W. Grimes */ 580df8bae1dSRodney W. Grimes ro = &inp->inp_route; 5813ab2096bSIan Dowse if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 5823ab2096bSIan Dowse ro->ro_dst.sa_family != AF_INET || 5835200e00eSIan Dowse satosin(&ro->ro_dst)->sin_addr.s_addr != faddr.s_addr || 584df8bae1dSRodney W. Grimes inp->inp_socket->so_options & SO_DONTROUTE)) { 585df8bae1dSRodney W. Grimes RTFREE(ro->ro_rt); 586df8bae1dSRodney W. Grimes ro->ro_rt = (struct rtentry *)0; 587df8bae1dSRodney W. Grimes } 588df8bae1dSRodney W. Grimes if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 589df8bae1dSRodney W. Grimes (ro->ro_rt == (struct rtentry *)0 || 590df8bae1dSRodney W. Grimes ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 591df8bae1dSRodney W. Grimes /* No route yet, so try to acquire one */ 592a4a6e773SHajimu UMEMOTO bzero(&ro->ro_dst, sizeof(struct sockaddr_in)); 593df8bae1dSRodney W. Grimes ro->ro_dst.sa_family = AF_INET; 594df8bae1dSRodney W. Grimes ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 5955200e00eSIan Dowse ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = faddr; 596df8bae1dSRodney W. Grimes rtalloc(ro); 5974cc20ab1SSeigo Tanimura } 598df8bae1dSRodney W. Grimes /* 599df8bae1dSRodney W. Grimes * If we found a route, use the address 600df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 601df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 602df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 603df8bae1dSRodney W. Grimes */ 604df8bae1dSRodney W. Grimes if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 605df8bae1dSRodney W. Grimes ia = ifatoia(ro->ro_rt->rt_ifa); 606df8bae1dSRodney W. Grimes if (ia == 0) { 6075200e00eSIan Dowse bzero(&sa, sizeof(sa)); 6085200e00eSIan Dowse sa.sin_addr = faddr; 6095200e00eSIan Dowse sa.sin_len = sizeof(sa); 6105200e00eSIan Dowse sa.sin_family = AF_INET; 611df8bae1dSRodney W. Grimes 6125200e00eSIan Dowse ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sa))); 613df8bae1dSRodney W. Grimes if (ia == 0) 6145200e00eSIan Dowse ia = ifatoia(ifa_ifwithnet(sintosa(&sa))); 615df8bae1dSRodney W. Grimes if (ia == 0) 616fc2ffbe6SPoul-Henning Kamp ia = TAILQ_FIRST(&in_ifaddrhead); 617df8bae1dSRodney W. Grimes if (ia == 0) 618df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 619df8bae1dSRodney W. Grimes } 620df8bae1dSRodney W. Grimes /* 621df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 622df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 623df8bae1dSRodney W. Grimes * address of that interface as our source address. 624df8bae1dSRodney W. Grimes */ 6255200e00eSIan Dowse if (IN_MULTICAST(ntohl(faddr.s_addr)) && 626df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 627df8bae1dSRodney W. Grimes struct ip_moptions *imo; 628df8bae1dSRodney W. Grimes struct ifnet *ifp; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 631df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 632df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 63337d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 634df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 635df8bae1dSRodney W. Grimes break; 636df8bae1dSRodney W. Grimes if (ia == 0) 637df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes } 6405200e00eSIan Dowse laddr = ia->ia_addr.sin_addr; 641999f1343SGarrett Wollman } 642999f1343SGarrett Wollman 6435200e00eSIan Dowse oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport, 6445200e00eSIan Dowse 0, NULL); 6455200e00eSIan Dowse if (oinp != NULL) { 6465200e00eSIan Dowse if (oinpp != NULL) 6475200e00eSIan Dowse *oinpp = oinp; 648df8bae1dSRodney W. Grimes return (EADDRINUSE); 649c3229e05SDavid Greenman } 6505200e00eSIan Dowse if (lport == 0) { 6515200e00eSIan Dowse error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, td); 6525a903f8dSPierre Beyssac if (error) 6535a903f8dSPierre Beyssac return (error); 6545a903f8dSPierre Beyssac } 6555200e00eSIan Dowse *laddrp = laddr.s_addr; 6565200e00eSIan Dowse *lportp = lport; 6575200e00eSIan Dowse *faddrp = faddr.s_addr; 6585200e00eSIan Dowse *fportp = fport; 659df8bae1dSRodney W. Grimes return (0); 660df8bae1dSRodney W. Grimes } 661df8bae1dSRodney W. Grimes 66226f9a767SRodney W. Grimes void 663df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 664df8bae1dSRodney W. Grimes struct inpcb *inp; 665df8bae1dSRodney W. Grimes { 66659daba27SSam Leffler INP_LOCK_ASSERT(inp); 667df8bae1dSRodney W. Grimes 668df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 669df8bae1dSRodney W. Grimes inp->inp_fport = 0; 67015bd2b43SDavid Greenman in_pcbrehash(inp); 6714cc20ab1SSeigo Tanimura if (inp->inp_socket->so_state & SS_NOFDREF) 672df8bae1dSRodney W. Grimes in_pcbdetach(inp); 6730f9ade71SHajimu UMEMOTO #ifdef IPSEC 6740f9ade71SHajimu UMEMOTO ipsec_pcbdisconn(inp->inp_sp); 6750f9ade71SHajimu UMEMOTO #endif 676df8bae1dSRodney W. Grimes } 677df8bae1dSRodney W. Grimes 67826f9a767SRodney W. Grimes void 679df8bae1dSRodney W. Grimes in_pcbdetach(inp) 680df8bae1dSRodney W. Grimes struct inpcb *inp; 681df8bae1dSRodney W. Grimes { 682df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 6833d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 684df8bae1dSRodney W. Grimes 68559daba27SSam Leffler INP_LOCK_ASSERT(inp); 68659daba27SSam Leffler 6870f9ade71SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC) 688cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 689cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/ 6903d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 691c3229e05SDavid Greenman in_pcbremlists(inp); 692340c35deSJonathan Lemon if (so) { 693df8bae1dSRodney W. Grimes so->so_pcb = 0; 694b1e4abd2SMatthew Dillon sotryfree(so); 695340c35deSJonathan Lemon } 696df8bae1dSRodney W. Grimes if (inp->inp_options) 697df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 698be2ac88cSJonathan Lemon if (inp->inp_route.ro_rt) 699d1dd20beSSam Leffler RTFREE(inp->inp_route.ro_rt); 700df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 701cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 702f76fcf6dSJeffrey Hsu INP_LOCK_DESTROY(inp); 70369c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 704df8bae1dSRodney W. Grimes } 705df8bae1dSRodney W. Grimes 70626ef6ac4SDon Lewis struct sockaddr * 70726ef6ac4SDon Lewis in_sockaddr(port, addr_p) 70826ef6ac4SDon Lewis in_port_t port; 70926ef6ac4SDon Lewis struct in_addr *addr_p; 71026ef6ac4SDon Lewis { 71126ef6ac4SDon Lewis struct sockaddr_in *sin; 71226ef6ac4SDon Lewis 71326ef6ac4SDon Lewis MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, 714a163d034SWarner Losh M_WAITOK | M_ZERO); 71526ef6ac4SDon Lewis sin->sin_family = AF_INET; 71626ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 71726ef6ac4SDon Lewis sin->sin_addr = *addr_p; 71826ef6ac4SDon Lewis sin->sin_port = port; 71926ef6ac4SDon Lewis 72026ef6ac4SDon Lewis return (struct sockaddr *)sin; 72126ef6ac4SDon Lewis } 72226ef6ac4SDon Lewis 723117bcae7SGarrett Wollman /* 724f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 725f76fcf6dSJeffrey Hsu * The socket must have a valid 726117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 727117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 72857bf258eSGarrett Wollman * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 72957bf258eSGarrett Wollman * because there actually /is/ a programming error somewhere... XXX) 730117bcae7SGarrett Wollman */ 731117bcae7SGarrett Wollman int 732f76fcf6dSJeffrey Hsu in_setsockaddr(so, nam, pcbinfo) 733117bcae7SGarrett Wollman struct socket *so; 73457bf258eSGarrett Wollman struct sockaddr **nam; 735f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 736df8bae1dSRodney W. Grimes { 737fdc984f7STor Egge int s; 738fdc984f7STor Egge register struct inpcb *inp; 73926ef6ac4SDon Lewis struct in_addr addr; 74026ef6ac4SDon Lewis in_port_t port; 74142fa505bSDavid Greenman 742fdc984f7STor Egge s = splnet(); 743f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 744fdc984f7STor Egge inp = sotoinpcb(so); 745db112f04STor Egge if (!inp) { 746f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 747db112f04STor Egge splx(s); 748ff079ca4SPeter Wemm return ECONNRESET; 749db112f04STor Egge } 750f76fcf6dSJeffrey Hsu INP_LOCK(inp); 75126ef6ac4SDon Lewis port = inp->inp_lport; 75226ef6ac4SDon Lewis addr = inp->inp_laddr; 753f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 754f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 755db112f04STor Egge splx(s); 75642fa505bSDavid Greenman 75726ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 758117bcae7SGarrett Wollman return 0; 759df8bae1dSRodney W. Grimes } 760df8bae1dSRodney W. Grimes 761f76fcf6dSJeffrey Hsu /* 762f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 763f76fcf6dSJeffrey Hsu */ 764117bcae7SGarrett Wollman int 765f76fcf6dSJeffrey Hsu in_setpeeraddr(so, nam, pcbinfo) 766117bcae7SGarrett Wollman struct socket *so; 76757bf258eSGarrett Wollman struct sockaddr **nam; 768f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 769df8bae1dSRodney W. Grimes { 770fdc984f7STor Egge int s; 771f76fcf6dSJeffrey Hsu register struct inpcb *inp; 77226ef6ac4SDon Lewis struct in_addr addr; 77326ef6ac4SDon Lewis in_port_t port; 77442fa505bSDavid Greenman 775fdc984f7STor Egge s = splnet(); 776f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 777fdc984f7STor Egge inp = sotoinpcb(so); 778db112f04STor Egge if (!inp) { 779f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 780db112f04STor Egge splx(s); 781ff079ca4SPeter Wemm return ECONNRESET; 782db112f04STor Egge } 783f76fcf6dSJeffrey Hsu INP_LOCK(inp); 78426ef6ac4SDon Lewis port = inp->inp_fport; 78526ef6ac4SDon Lewis addr = inp->inp_faddr; 786f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 787f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 788db112f04STor Egge splx(s); 78942fa505bSDavid Greenman 79026ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 791117bcae7SGarrett Wollman return 0; 792df8bae1dSRodney W. Grimes } 793df8bae1dSRodney W. Grimes 79426f9a767SRodney W. Grimes void 795f76fcf6dSJeffrey Hsu in_pcbnotifyall(pcbinfo, faddr, errno, notify) 796f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 797df8bae1dSRodney W. Grimes struct in_addr faddr; 798c693a045SJonathan Lemon int errno; 7993ce144eaSJeffrey Hsu struct inpcb *(*notify)(struct inpcb *, int); 800d1c54148SJesper Skriver { 801c693a045SJonathan Lemon struct inpcb *inp, *ninp; 802f76fcf6dSJeffrey Hsu struct inpcbhead *head; 803c693a045SJonathan Lemon int s; 804d1c54148SJesper Skriver 805d1c54148SJesper Skriver s = splnet(); 8063dc7ebf9SJeffrey Hsu INP_INFO_WLOCK(pcbinfo); 807f76fcf6dSJeffrey Hsu head = pcbinfo->listhead; 808c693a045SJonathan Lemon for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { 809f76fcf6dSJeffrey Hsu INP_LOCK(inp); 810c693a045SJonathan Lemon ninp = LIST_NEXT(inp, inp_list); 811d1c54148SJesper Skriver #ifdef INET6 812f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 813f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 814d1c54148SJesper Skriver continue; 815f76fcf6dSJeffrey Hsu } 816d1c54148SJesper Skriver #endif 817d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 818f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 819f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 820d1c54148SJesper Skriver continue; 821d1c54148SJesper Skriver } 8223dc7ebf9SJeffrey Hsu if ((*notify)(inp, errno)) 823f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 824f76fcf6dSJeffrey Hsu } 8253dc7ebf9SJeffrey Hsu INP_INFO_WUNLOCK(pcbinfo); 826d1c54148SJesper Skriver splx(s); 827d1c54148SJesper Skriver } 828d1c54148SJesper Skriver 829e43cc4aeSHajimu UMEMOTO void 830f76fcf6dSJeffrey Hsu in_pcbpurgeif0(pcbinfo, ifp) 831f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 832e43cc4aeSHajimu UMEMOTO struct ifnet *ifp; 833e43cc4aeSHajimu UMEMOTO { 834e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 835e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 836e43cc4aeSHajimu UMEMOTO int i, gap; 837e43cc4aeSHajimu UMEMOTO 838f76fcf6dSJeffrey Hsu /* why no splnet here? XXX */ 839f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 8403cfcc388SJeffrey Hsu LIST_FOREACH(inp, pcbinfo->listhead, inp_list) { 841f76fcf6dSJeffrey Hsu INP_LOCK(inp); 842e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 843e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 844e43cc4aeSHajimu UMEMOTO imo != NULL) { 845e43cc4aeSHajimu UMEMOTO /* 846e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 847e43cc4aeSHajimu UMEMOTO * detached. 848e43cc4aeSHajimu UMEMOTO */ 849e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 850e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 851e43cc4aeSHajimu UMEMOTO 852e43cc4aeSHajimu UMEMOTO /* 853e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 854e43cc4aeSHajimu UMEMOTO * through the interface being detached. 855e43cc4aeSHajimu UMEMOTO */ 856e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 857e43cc4aeSHajimu UMEMOTO i++) { 858e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 859e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 860e43cc4aeSHajimu UMEMOTO gap++; 861e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 862e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 863e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 864e43cc4aeSHajimu UMEMOTO } 865e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 866e43cc4aeSHajimu UMEMOTO } 867f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 868e43cc4aeSHajimu UMEMOTO } 8693cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 870e43cc4aeSHajimu UMEMOTO } 871e43cc4aeSHajimu UMEMOTO 872df8bae1dSRodney W. Grimes /* 873df8bae1dSRodney W. Grimes * Check for alternatives when higher level complains 874df8bae1dSRodney W. Grimes * about service problems. For now, invalidate cached 875df8bae1dSRodney W. Grimes * routing information. If the route was created dynamically 876df8bae1dSRodney W. Grimes * (by a redirect), time to try a default gateway again. 877df8bae1dSRodney W. Grimes */ 87826f9a767SRodney W. Grimes void 879df8bae1dSRodney W. Grimes in_losing(inp) 880df8bae1dSRodney W. Grimes struct inpcb *inp; 881df8bae1dSRodney W. Grimes { 882df8bae1dSRodney W. Grimes register struct rtentry *rt; 883df8bae1dSRodney W. Grimes struct rt_addrinfo info; 884df8bae1dSRodney W. Grimes 88559daba27SSam Leffler INP_LOCK_ASSERT(inp); 88659daba27SSam Leffler 887df8bae1dSRodney W. Grimes if ((rt = inp->inp_route.ro_rt)) { 888d1dd20beSSam Leffler RT_LOCK(rt); 889d1dd20beSSam Leffler inp->inp_route.ro_rt = NULL; 890df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 8918071913dSRuslan Ermilov info.rti_flags = rt->rt_flags; 8928071913dSRuslan Ermilov info.rti_info[RTAX_DST] = rt_key(rt); 893df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 894df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = rt_mask(rt); 895df8bae1dSRodney W. Grimes rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 8969c63e9dbSSam Leffler if (rt->rt_flags & RTF_DYNAMIC) 8979c63e9dbSSam Leffler rtexpunge(rt); 8989c63e9dbSSam Leffler RTFREE_LOCKED(rt); 899df8bae1dSRodney W. Grimes /* 900df8bae1dSRodney W. Grimes * A new route can be allocated 901df8bae1dSRodney W. Grimes * the next time output is attempted. 902df8bae1dSRodney W. Grimes */ 903df8bae1dSRodney W. Grimes } 904df8bae1dSRodney W. Grimes } 905df8bae1dSRodney W. Grimes 906df8bae1dSRodney W. Grimes /* 907df8bae1dSRodney W. Grimes * After a routing change, flush old routing 908df8bae1dSRodney W. Grimes * and allocate a (hopefully) better one. 909df8bae1dSRodney W. Grimes */ 9103ce144eaSJeffrey Hsu struct inpcb * 911df8bae1dSRodney W. Grimes in_rtchange(inp, errno) 912df8bae1dSRodney W. Grimes register struct inpcb *inp; 913df8bae1dSRodney W. Grimes int errno; 914df8bae1dSRodney W. Grimes { 91559daba27SSam Leffler INP_LOCK_ASSERT(inp); 91659daba27SSam Leffler 917df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) { 918d1dd20beSSam Leffler RTFREE(inp->inp_route.ro_rt); 919df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 920df8bae1dSRodney W. Grimes /* 921df8bae1dSRodney W. Grimes * A new route can be allocated the next time 922df8bae1dSRodney W. Grimes * output is attempted. 923df8bae1dSRodney W. Grimes */ 924df8bae1dSRodney W. Grimes } 9253ce144eaSJeffrey Hsu return inp; 926df8bae1dSRodney W. Grimes } 927df8bae1dSRodney W. Grimes 928c3229e05SDavid Greenman /* 929c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 930c3229e05SDavid Greenman */ 931df8bae1dSRodney W. Grimes struct inpcb * 932c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 9336d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 934c3229e05SDavid Greenman struct in_addr laddr; 935c3229e05SDavid Greenman u_int lport_arg; 9366d6a026bSDavid Greenman int wild_okay; 937df8bae1dSRodney W. Grimes { 938f1d19042SArchie Cobbs register struct inpcb *inp; 939df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 940c3229e05SDavid Greenman u_short lport = lport_arg; 9417bc4aca7SDavid Greenman 9421b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 9431b73ca0bSSam Leffler 944c3229e05SDavid Greenman if (!wild_okay) { 945c3229e05SDavid Greenman struct inpcbhead *head; 946c3229e05SDavid Greenman /* 947c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 948c3229e05SDavid Greenman * matches the local address and port we're looking for. 949c3229e05SDavid Greenman */ 950c3229e05SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 951fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 952cfa1ca9dSYoshinobu Inoue #ifdef INET6 953369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 954cfa1ca9dSYoshinobu Inoue continue; 955cfa1ca9dSYoshinobu Inoue #endif 956c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 957c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 958c3229e05SDavid Greenman inp->inp_lport == lport) { 959c3229e05SDavid Greenman /* 960c3229e05SDavid Greenman * Found. 961c3229e05SDavid Greenman */ 962c3229e05SDavid Greenman return (inp); 963df8bae1dSRodney W. Grimes } 964c3229e05SDavid Greenman } 965c3229e05SDavid Greenman /* 966c3229e05SDavid Greenman * Not found. 967c3229e05SDavid Greenman */ 968c3229e05SDavid Greenman return (NULL); 969c3229e05SDavid Greenman } else { 970c3229e05SDavid Greenman struct inpcbporthead *porthash; 971c3229e05SDavid Greenman struct inpcbport *phd; 972c3229e05SDavid Greenman struct inpcb *match = NULL; 973c3229e05SDavid Greenman /* 974c3229e05SDavid Greenman * Best fit PCB lookup. 975c3229e05SDavid Greenman * 976c3229e05SDavid Greenman * First see if this local port is in use by looking on the 977c3229e05SDavid Greenman * port hash list. 978c3229e05SDavid Greenman */ 97996af9ea5SMike Silbersack retrylookup: 980c3229e05SDavid Greenman porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 981c3229e05SDavid Greenman pcbinfo->porthashmask)]; 982fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 983c3229e05SDavid Greenman if (phd->phd_port == lport) 984c3229e05SDavid Greenman break; 985c3229e05SDavid Greenman } 986c3229e05SDavid Greenman if (phd != NULL) { 987c3229e05SDavid Greenman /* 988c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 989c3229e05SDavid Greenman * fit. 990c3229e05SDavid Greenman */ 99137d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 992c3229e05SDavid Greenman wildcard = 0; 993cfa1ca9dSYoshinobu Inoue #ifdef INET6 994369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 995cfa1ca9dSYoshinobu Inoue continue; 996cfa1ca9dSYoshinobu Inoue #endif 99796af9ea5SMike Silbersack /* 99896af9ea5SMike Silbersack * Clean out old time_wait sockets if they 99996af9ea5SMike Silbersack * are clogging up needed local ports. 100096af9ea5SMike Silbersack */ 100196af9ea5SMike Silbersack if ((inp->inp_vflag & INP_TIMEWAIT) != 0) { 100296af9ea5SMike Silbersack if (tcp_twrecycleable((struct tcptw *)inp->inp_ppcb)) { 100396af9ea5SMike Silbersack tcp_twclose((struct tcptw *)inp->inp_ppcb, 0); 100496af9ea5SMike Silbersack match = NULL; 100596af9ea5SMike Silbersack goto retrylookup; 100696af9ea5SMike Silbersack } 100796af9ea5SMike Silbersack } 1008c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 1009c3229e05SDavid Greenman wildcard++; 101015bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 101115bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 101215bd2b43SDavid Greenman wildcard++; 101315bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 101415bd2b43SDavid Greenman continue; 101515bd2b43SDavid Greenman } else { 101615bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 101715bd2b43SDavid Greenman wildcard++; 101815bd2b43SDavid Greenman } 1019df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 1020df8bae1dSRodney W. Grimes match = inp; 1021df8bae1dSRodney W. Grimes matchwild = wildcard; 10223dbdc25cSDavid Greenman if (matchwild == 0) { 1023df8bae1dSRodney W. Grimes break; 1024df8bae1dSRodney W. Grimes } 1025df8bae1dSRodney W. Grimes } 10263dbdc25cSDavid Greenman } 1027c3229e05SDavid Greenman } 1028df8bae1dSRodney W. Grimes return (match); 1029df8bae1dSRodney W. Grimes } 1030c3229e05SDavid Greenman } 103115bd2b43SDavid Greenman 103215bd2b43SDavid Greenman /* 103315bd2b43SDavid Greenman * Lookup PCB in hash list. 103415bd2b43SDavid Greenman */ 103515bd2b43SDavid Greenman struct inpcb * 1036cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, 1037cfa1ca9dSYoshinobu Inoue ifp) 103815bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 103915bd2b43SDavid Greenman struct in_addr faddr, laddr; 104015bd2b43SDavid Greenman u_int fport_arg, lport_arg; 10416d6a026bSDavid Greenman int wildcard; 1042cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 104315bd2b43SDavid Greenman { 104415bd2b43SDavid Greenman struct inpcbhead *head; 104515bd2b43SDavid Greenman register struct inpcb *inp; 104615bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 104715bd2b43SDavid Greenman 104859daba27SSam Leffler INP_INFO_RLOCK_ASSERT(pcbinfo); 104915bd2b43SDavid Greenman /* 105015bd2b43SDavid Greenman * First look for an exact match. 105115bd2b43SDavid Greenman */ 1052ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 1053fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1054cfa1ca9dSYoshinobu Inoue #ifdef INET6 1055369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1056cfa1ca9dSYoshinobu Inoue continue; 1057cfa1ca9dSYoshinobu Inoue #endif 10586d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 1059ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1060ca98b82cSDavid Greenman inp->inp_fport == fport && 1061c3229e05SDavid Greenman inp->inp_lport == lport) { 1062c3229e05SDavid Greenman /* 1063c3229e05SDavid Greenman * Found. 1064c3229e05SDavid Greenman */ 1065c3229e05SDavid Greenman return (inp); 1066c3229e05SDavid Greenman } 10676d6a026bSDavid Greenman } 10686d6a026bSDavid Greenman if (wildcard) { 10696d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 1070cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1071cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 1072cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 10736d6a026bSDavid Greenman 1074ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 1075fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1076cfa1ca9dSYoshinobu Inoue #ifdef INET6 1077369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1078cfa1ca9dSYoshinobu Inoue continue; 1079cfa1ca9dSYoshinobu Inoue #endif 10806d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1081c3229e05SDavid Greenman inp->inp_lport == lport) { 1082cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 1083cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 1084cfa1ca9dSYoshinobu Inoue continue; 10856d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 1086c3229e05SDavid Greenman return (inp); 1087cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 1088cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1089cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 1090cfa1ca9dSYoshinobu Inoue AF_INET6)) 1091cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 1092cfa1ca9dSYoshinobu Inoue else 1093cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 10946d6a026bSDavid Greenman local_wild = inp; 10956d6a026bSDavid Greenman } 10966d6a026bSDavid Greenman } 1097cfa1ca9dSYoshinobu Inoue } 1098cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1099cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 1100cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 1101cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 1102c3229e05SDavid Greenman return (local_wild); 11036d6a026bSDavid Greenman } 1104c3229e05SDavid Greenman 1105c3229e05SDavid Greenman /* 1106c3229e05SDavid Greenman * Not found. 1107c3229e05SDavid Greenman */ 11086d6a026bSDavid Greenman return (NULL); 110915bd2b43SDavid Greenman } 111015bd2b43SDavid Greenman 11117bc4aca7SDavid Greenman /* 1112c3229e05SDavid Greenman * Insert PCB onto various hash lists. 11137bc4aca7SDavid Greenman */ 1114c3229e05SDavid Greenman int 111515bd2b43SDavid Greenman in_pcbinshash(inp) 111615bd2b43SDavid Greenman struct inpcb *inp; 111715bd2b43SDavid Greenman { 1118c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1119c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1120c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1121c3229e05SDavid Greenman struct inpcbport *phd; 1122cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 112315bd2b43SDavid Greenman 112459daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 1125cfa1ca9dSYoshinobu Inoue #ifdef INET6 1126cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1127cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1128cfa1ca9dSYoshinobu Inoue else 1129cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1130cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1131cfa1ca9dSYoshinobu Inoue 1132cfa1ca9dSYoshinobu Inoue pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 1133c3229e05SDavid Greenman inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 113415bd2b43SDavid Greenman 1135c3229e05SDavid Greenman pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, 1136c3229e05SDavid Greenman pcbinfo->porthashmask)]; 1137c3229e05SDavid Greenman 1138c3229e05SDavid Greenman /* 1139c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1140c3229e05SDavid Greenman */ 1141fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1142c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1143c3229e05SDavid Greenman break; 1144c3229e05SDavid Greenman } 1145c3229e05SDavid Greenman /* 1146c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1147c3229e05SDavid Greenman */ 1148c3229e05SDavid Greenman if (phd == NULL) { 1149c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1150c3229e05SDavid Greenman if (phd == NULL) { 1151c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1152c3229e05SDavid Greenman } 1153c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1154c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1155c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1156c3229e05SDavid Greenman } 1157c3229e05SDavid Greenman inp->inp_phd = phd; 1158c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1159c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1160c3229e05SDavid Greenman return (0); 116115bd2b43SDavid Greenman } 116215bd2b43SDavid Greenman 1163c3229e05SDavid Greenman /* 1164c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1165c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1166c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1167c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1168c3229e05SDavid Greenman */ 116915bd2b43SDavid Greenman void 117015bd2b43SDavid Greenman in_pcbrehash(inp) 117115bd2b43SDavid Greenman struct inpcb *inp; 117215bd2b43SDavid Greenman { 117359daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 117415bd2b43SDavid Greenman struct inpcbhead *head; 1175cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 117615bd2b43SDavid Greenman 117759daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 117859daba27SSam Leffler /* XXX? INP_LOCK_ASSERT(inp); */ 1179cfa1ca9dSYoshinobu Inoue #ifdef INET6 1180cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1181cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1182cfa1ca9dSYoshinobu Inoue else 1183cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1184cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1185cfa1ca9dSYoshinobu Inoue 118659daba27SSam Leffler head = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 118759daba27SSam Leffler inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 118815bd2b43SDavid Greenman 1189c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 119015bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1191c3229e05SDavid Greenman } 1192c3229e05SDavid Greenman 1193c3229e05SDavid Greenman /* 1194c3229e05SDavid Greenman * Remove PCB from various lists. 1195c3229e05SDavid Greenman */ 119676429de4SYoshinobu Inoue void 1197c3229e05SDavid Greenman in_pcbremlists(inp) 1198c3229e05SDavid Greenman struct inpcb *inp; 1199c3229e05SDavid Greenman { 120059daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 120159daba27SSam Leffler 120259daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 120359daba27SSam Leffler INP_LOCK_ASSERT(inp); 120459daba27SSam Leffler 120559daba27SSam Leffler inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 1206c3229e05SDavid Greenman if (inp->inp_lport) { 1207c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1208c3229e05SDavid Greenman 1209c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1210c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1211fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1212c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1213c3229e05SDavid Greenman free(phd, M_PCB); 1214c3229e05SDavid Greenman } 1215c3229e05SDavid Greenman } 1216c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 121759daba27SSam Leffler pcbinfo->ipi_count--; 121815bd2b43SDavid Greenman } 121975c13541SPoul-Henning Kamp 122075c13541SPoul-Henning Kamp int 1221ad278afdSJohn Baldwin prison_xinpcb(struct thread *td, struct inpcb *inp) 122275c13541SPoul-Henning Kamp { 1223ad278afdSJohn Baldwin if (!jailed(td->td_ucred)) 122475c13541SPoul-Henning Kamp return (0); 1225ad278afdSJohn Baldwin if (ntohl(inp->inp_laddr.s_addr) == prison_getip(td->td_ucred)) 122675c13541SPoul-Henning Kamp return (0); 122775c13541SPoul-Henning Kamp return (1); 122875c13541SPoul-Henning Kamp } 1229