1c398230bSWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 292469dd60SGarrett Wollman * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 336a800098SYoshinobu Inoue #include "opt_ipsec.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 35a557af22SRobert Watson #include "opt_mac.h" 36cfa1ca9dSYoshinobu Inoue 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39a557af22SRobert Watson #include <sys/mac.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 43df8bae1dSRodney W. Grimes #include <sys/protosw.h> 44df8bae1dSRodney W. Grimes #include <sys/socket.h> 45df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 46df8bae1dSRodney W. Grimes #include <sys/proc.h> 4775c13541SPoul-Henning Kamp #include <sys/jail.h> 48101f9fc8SPeter Wemm #include <sys/kernel.h> 49101f9fc8SPeter Wemm #include <sys/sysctl.h> 508781d8e9SBruce Evans 5169c2d429SJeff Roberson #include <vm/uma.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <net/if.h> 54cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 55df8bae1dSRodney W. Grimes #include <net/route.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <netinet/in.h> 58df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 59df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 60df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 61340c35deSJonathan Lemon #include <netinet/tcp_var.h> 625f311da2SMike Silbersack #include <netinet/udp.h> 635f311da2SMike Silbersack #include <netinet/udp_var.h> 64cfa1ca9dSYoshinobu Inoue #ifdef INET6 65cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 66cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 67cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 68cfa1ca9dSYoshinobu Inoue 69cfa1ca9dSYoshinobu Inoue #ifdef IPSEC 70cfa1ca9dSYoshinobu Inoue #include <netinet6/ipsec.h> 71cfa1ca9dSYoshinobu Inoue #include <netkey/key.h> 72cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */ 73df8bae1dSRodney W. Grimes 74b9234fafSSam Leffler #ifdef FAST_IPSEC 75b9234fafSSam Leffler #if defined(IPSEC) || defined(IPSEC_ESP) 76b9234fafSSam Leffler #error "Bad idea: don't compile with both IPSEC and FAST_IPSEC!" 77b9234fafSSam Leffler #endif 78b9234fafSSam Leffler 79b9234fafSSam Leffler #include <netipsec/ipsec.h> 80b9234fafSSam Leffler #include <netipsec/key.h> 81b9234fafSSam Leffler #endif /* FAST_IPSEC */ 82b9234fafSSam Leffler 83101f9fc8SPeter Wemm /* 84101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 85101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 86101f9fc8SPeter Wemm */ 8782cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 8882cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 899e5a5ed4SMike Silbersack int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 909e5a5ed4SMike Silbersack int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */ 9182cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9282cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 93101f9fc8SPeter Wemm 94b0d22693SCrist J. Clark /* 95b0d22693SCrist J. Clark * Reserved ports accessible only to root. There are significant 96b0d22693SCrist J. Clark * security considerations that must be accounted for when changing these, 97b0d22693SCrist J. Clark * but the security benefits can be great. Please be careful. 98b0d22693SCrist J. Clark */ 99b0d22693SCrist J. Clark int ipport_reservedhigh = IPPORT_RESERVED - 1; /* 1023 */ 100b0d22693SCrist J. Clark int ipport_reservedlow = 0; 101b0d22693SCrist J. Clark 1025f311da2SMike Silbersack /* Variables dealing with random ephemeral port allocation. */ 1035f311da2SMike Silbersack int ipport_randomized = 1; /* user controlled via sysctl */ 1045f311da2SMike Silbersack int ipport_randomcps = 10; /* user controlled via sysctl */ 1055f311da2SMike Silbersack int ipport_randomtime = 45; /* user controlled via sysctl */ 1065f311da2SMike Silbersack int ipport_stoprandom = 0; /* toggled by ipport_tick */ 1075f311da2SMike Silbersack int ipport_tcpallocs; 1085f311da2SMike Silbersack int ipport_tcplastcount; 1096ac48b74SMike Silbersack 110bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 111bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 112bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 113bbd42ad0SPeter Wemm 114bbd42ad0SPeter Wemm static int 11582d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 116bbd42ad0SPeter Wemm { 11730a4ab08SBruce Evans int error; 11830a4ab08SBruce Evans 11930a4ab08SBruce Evans error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 12030a4ab08SBruce Evans if (error == 0) { 121bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 122bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 12330a4ab08SBruce Evans RANGECHK(ipport_firstauto, IPPORT_RESERVED, IPPORT_MAX); 12430a4ab08SBruce Evans RANGECHK(ipport_lastauto, IPPORT_RESERVED, IPPORT_MAX); 12530a4ab08SBruce Evans RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, IPPORT_MAX); 12630a4ab08SBruce Evans RANGECHK(ipport_hilastauto, IPPORT_RESERVED, IPPORT_MAX); 127bbd42ad0SPeter Wemm } 12830a4ab08SBruce Evans return (error); 129bbd42ad0SPeter Wemm } 130bbd42ad0SPeter Wemm 131bbd42ad0SPeter Wemm #undef RANGECHK 132bbd42ad0SPeter Wemm 13333b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 13433b3ac06SPeter Wemm 135bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 136bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 137bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 138bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 139bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 140bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 141bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 142bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 143bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 144bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 145bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 146bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 147b0d22693SCrist J. Clark SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedhigh, 148b0d22693SCrist J. Clark CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedhigh, 0, ""); 149b0d22693SCrist J. Clark SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedlow, 150b0d22693SCrist J. Clark CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedlow, 0, ""); 1516ac48b74SMike Silbersack SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomized, 1526ac48b74SMike Silbersack CTLFLAG_RW, &ipport_randomized, 0, ""); 1535f311da2SMike Silbersack SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomcps, 1545f311da2SMike Silbersack CTLFLAG_RW, &ipport_randomcps, 0, ""); 1555f311da2SMike Silbersack SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomtime, 1565f311da2SMike Silbersack CTLFLAG_RW, &ipport_randomtime, 0, ""); 1570312fbe9SPoul-Henning Kamp 158c3229e05SDavid Greenman /* 159c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 160c3229e05SDavid Greenman * 161c3229e05SDavid Greenman * NOTE: It is assumed that most of these functions will be called at 162c3229e05SDavid Greenman * splnet(). XXX - There are, unfortunately, a few exceptions to this 163c3229e05SDavid Greenman * rule that should be fixed. 164c3229e05SDavid Greenman */ 165c3229e05SDavid Greenman 166c3229e05SDavid Greenman /* 167c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 168c3229e05SDavid Greenman */ 169df8bae1dSRodney W. Grimes int 1706823b823SPawel Jakub Dawidek in_pcballoc(so, pcbinfo, type) 171df8bae1dSRodney W. Grimes struct socket *so; 17215bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 1735bd311a5SSam Leffler const char *type; 174df8bae1dSRodney W. Grimes { 175df8bae1dSRodney W. Grimes register struct inpcb *inp; 17613cf67f3SHajimu UMEMOTO int error; 177a557af22SRobert Watson 17859daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 179a557af22SRobert Watson error = 0; 180d1dd20beSSam Leffler inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT | M_ZERO); 181df8bae1dSRodney W. Grimes if (inp == NULL) 182df8bae1dSRodney W. Grimes return (ENOBUFS); 1833d4d47f3SGarrett Wollman inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 18415bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 185df8bae1dSRodney W. Grimes inp->inp_socket = so; 186a557af22SRobert Watson #ifdef MAC 187a557af22SRobert Watson error = mac_init_inpcb(inp, M_NOWAIT); 188a557af22SRobert Watson if (error != 0) 189a557af22SRobert Watson goto out; 190310e7cebSRobert Watson SOCK_LOCK(so); 191a557af22SRobert Watson mac_create_inpcb_from_socket(so, inp); 192310e7cebSRobert Watson SOCK_UNLOCK(so); 193a557af22SRobert Watson #endif 1940f9ade71SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC) 1950f9ade71SHajimu UMEMOTO #ifdef FAST_IPSEC 19613cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 1970f9ade71SHajimu UMEMOTO #else 1980f9ade71SHajimu UMEMOTO error = ipsec_init_pcbpolicy(so, &inp->inp_sp); 1990f9ade71SHajimu UMEMOTO #endif 200a557af22SRobert Watson if (error != 0) 201a557af22SRobert Watson goto out; 20213cf67f3SHajimu UMEMOTO #endif /*IPSEC*/ 20375daea93SPaul Saab #if defined(INET6) 204340c35deSJonathan Lemon if (INP_SOCKAF(so) == AF_INET6) { 205340c35deSJonathan Lemon inp->inp_vflag |= INP_IPV6PROTO; 206340c35deSJonathan Lemon if (ip6_v6only) 20733841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 208340c35deSJonathan Lemon } 20975daea93SPaul Saab #endif 21015bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 2113d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 212df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 2135bd311a5SSam Leffler INP_LOCK_INIT(inp, "inp", type); 21433841545SHajimu UMEMOTO #ifdef INET6 21533841545SHajimu UMEMOTO if (ip6_auto_flowlabel) 21633841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 21733841545SHajimu UMEMOTO #endif 218a557af22SRobert Watson #if defined(IPSEC) || defined(FAST_IPSEC) || defined(MAC) 219a557af22SRobert Watson out: 220a557af22SRobert Watson if (error != 0) 221a557af22SRobert Watson uma_zfree(pcbinfo->ipi_zone, inp); 222a557af22SRobert Watson #endif 223a557af22SRobert Watson return (error); 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes 226df8bae1dSRodney W. Grimes int 227b0330ed9SPawel Jakub Dawidek in_pcbbind(inp, nam, cred) 228df8bae1dSRodney W. Grimes register struct inpcb *inp; 22957bf258eSGarrett Wollman struct sockaddr *nam; 230b0330ed9SPawel Jakub Dawidek struct ucred *cred; 231df8bae1dSRodney W. Grimes { 2324b932371SIan Dowse int anonport, error; 2334b932371SIan Dowse 2341b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 23559daba27SSam Leffler INP_LOCK_ASSERT(inp); 23659daba27SSam Leffler 2374b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 2384b932371SIan Dowse return (EINVAL); 2394b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 2404b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 2414b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 242b0330ed9SPawel Jakub Dawidek &inp->inp_lport, cred); 2434b932371SIan Dowse if (error) 2444b932371SIan Dowse return (error); 2454b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2464b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2474b932371SIan Dowse inp->inp_lport = 0; 2484b932371SIan Dowse return (EAGAIN); 2494b932371SIan Dowse } 2504b932371SIan Dowse if (anonport) 2514b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2524b932371SIan Dowse return (0); 2534b932371SIan Dowse } 2544b932371SIan Dowse 2554b932371SIan Dowse /* 2564b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2574b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2584b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2594b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2604b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2614b932371SIan Dowse * 2624b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2634b932371SIan Dowse */ 2644b932371SIan Dowse int 265b0330ed9SPawel Jakub Dawidek in_pcbbind_setup(inp, nam, laddrp, lportp, cred) 2664b932371SIan Dowse struct inpcb *inp; 2674b932371SIan Dowse struct sockaddr *nam; 2684b932371SIan Dowse in_addr_t *laddrp; 2694b932371SIan Dowse u_short *lportp; 270b0330ed9SPawel Jakub Dawidek struct ucred *cred; 2714b932371SIan Dowse { 2724b932371SIan Dowse struct socket *so = inp->inp_socket; 27337bd2b30SPeter Wemm unsigned short *lastport; 27415bd2b43SDavid Greenman struct sockaddr_in *sin; 275c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 2764b932371SIan Dowse struct in_addr laddr; 277df8bae1dSRodney W. Grimes u_short lport = 0; 2784cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 27975c13541SPoul-Henning Kamp int error, prison = 0; 2805f311da2SMike Silbersack int dorandom; 281df8bae1dSRodney W. Grimes 2821b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 28359daba27SSam Leffler INP_LOCK_ASSERT(inp); 28459daba27SSam Leffler 28559562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 286df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 2874b932371SIan Dowse laddr.s_addr = *laddrp; 2884b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 289df8bae1dSRodney W. Grimes return (EINVAL); 290c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 2916d6a026bSDavid Greenman wild = 1; 292df8bae1dSRodney W. Grimes if (nam) { 29357bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 29457bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 295df8bae1dSRodney W. Grimes return (EINVAL); 296df8bae1dSRodney W. Grimes #ifdef notdef 297df8bae1dSRodney W. Grimes /* 298df8bae1dSRodney W. Grimes * We should check the family, but old programs 299df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 300df8bae1dSRodney W. Grimes */ 301df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 302df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 303df8bae1dSRodney W. Grimes #endif 304e4bdf25dSPoul-Henning Kamp if (sin->sin_addr.s_addr != INADDR_ANY) 305b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &sin->sin_addr.s_addr)) 30675c13541SPoul-Henning Kamp return(EINVAL); 3074b932371SIan Dowse if (sin->sin_port != *lportp) { 3084b932371SIan Dowse /* Don't allow the port to change. */ 3094b932371SIan Dowse if (*lportp != 0) 3104b932371SIan Dowse return (EINVAL); 311df8bae1dSRodney W. Grimes lport = sin->sin_port; 3124b932371SIan Dowse } 3134b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 314df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 315df8bae1dSRodney W. Grimes /* 316df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 317df8bae1dSRodney W. Grimes * allow complete duplication of binding if 318df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 319df8bae1dSRodney W. Grimes * and a multicast address is bound on both 320df8bae1dSRodney W. Grimes * new and duplicated sockets. 321df8bae1dSRodney W. Grimes */ 322df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 323df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 324df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 325df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 32683103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 327df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 328df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 329df8bae1dSRodney W. Grimes } 3304b932371SIan Dowse laddr = sin->sin_addr; 331df8bae1dSRodney W. Grimes if (lport) { 332df8bae1dSRodney W. Grimes struct inpcb *t; 333df8bae1dSRodney W. Grimes /* GROSS */ 334b0d22693SCrist J. Clark if (ntohs(lport) <= ipport_reservedhigh && 335b0d22693SCrist J. Clark ntohs(lport) >= ipport_reservedlow && 33656f21b9dSColin Percival suser_cred(cred, SUSER_ALLOWJAIL)) 3372469dd60SGarrett Wollman return (EACCES); 338b0330ed9SPawel Jakub Dawidek if (jailed(cred)) 33975c13541SPoul-Henning Kamp prison = 1; 3402f9a2132SBrian Feldman if (so->so_cred->cr_uid != 0 && 34152b65dbeSBill Fenner !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 3424049a042SGuido van Rooij t = in_pcblookup_local(inp->inp_pcbinfo, 34375c13541SPoul-Henning Kamp sin->sin_addr, lport, 34475c13541SPoul-Henning Kamp prison ? 0 : INPLOOKUP_WILDCARD); 345340c35deSJonathan Lemon /* 346340c35deSJonathan Lemon * XXX 347340c35deSJonathan Lemon * This entire block sorely needs a rewrite. 348340c35deSJonathan Lemon */ 3494cc20ab1SSeigo Tanimura if (t && 3504658dc83SYaroslav Tykhiy ((t->inp_vflag & INP_TIMEWAIT) == 0) && 3514658dc83SYaroslav Tykhiy (so->so_type != SOCK_STREAM || 3524658dc83SYaroslav Tykhiy ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && 3534cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 35452b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 35552b65dbeSBill Fenner (t->inp_socket->so_options & 35652b65dbeSBill Fenner SO_REUSEPORT) == 0) && 3572f9a2132SBrian Feldman (so->so_cred->cr_uid != 358a4eb4405SYaroslav Tykhiy t->inp_socket->so_cred->cr_uid)) 3594049a042SGuido van Rooij return (EADDRINUSE); 3604049a042SGuido van Rooij } 361b0330ed9SPawel Jakub Dawidek if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr)) 362970680faSPoul-Henning Kamp return (EADDRNOTAVAIL); 363c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 36475c13541SPoul-Henning Kamp lport, prison ? 0 : wild); 365340c35deSJonathan Lemon if (t && (t->inp_vflag & INP_TIMEWAIT)) { 366340c35deSJonathan Lemon if ((reuseport & intotw(t)->tw_so_options) == 0) 367340c35deSJonathan Lemon return (EADDRINUSE); 368340c35deSJonathan Lemon } else 3694cc20ab1SSeigo Tanimura if (t && 3704cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 371cfa1ca9dSYoshinobu Inoue #if defined(INET6) 37233841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 373cfa1ca9dSYoshinobu Inoue INADDR_ANY || 374cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 375cfa1ca9dSYoshinobu Inoue INADDR_ANY || 376cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 377cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 378cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 379df8bae1dSRodney W. Grimes return (EADDRINUSE); 380df8bae1dSRodney W. Grimes } 381cfa1ca9dSYoshinobu Inoue } 382df8bae1dSRodney W. Grimes } 3834b932371SIan Dowse if (*lportp != 0) 3844b932371SIan Dowse lport = *lportp; 38533b3ac06SPeter Wemm if (lport == 0) { 3866ac48b74SMike Silbersack u_short first, last; 387174624e0SMike Silbersack int count; 38833b3ac06SPeter Wemm 3894b932371SIan Dowse if (laddr.s_addr != INADDR_ANY) 390b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &laddr.s_addr)) 39175c13541SPoul-Henning Kamp return (EINVAL); 392321a2846SPoul-Henning Kamp 39333b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 39433b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 39533b3ac06SPeter Wemm last = ipport_hilastauto; 396c3229e05SDavid Greenman lastport = &pcbinfo->lasthi; 39733b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 39856f21b9dSColin Percival if ((error = suser_cred(cred, SUSER_ALLOWJAIL)) != 0) 399a29f300eSGarrett Wollman return error; 400bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 401bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 402c3229e05SDavid Greenman lastport = &pcbinfo->lastlow; 40333b3ac06SPeter Wemm } else { 40433b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 40533b3ac06SPeter Wemm last = ipport_lastauto; 406c3229e05SDavid Greenman lastport = &pcbinfo->lastport; 40733b3ac06SPeter Wemm } 40833b3ac06SPeter Wemm /* 4095f311da2SMike Silbersack * For UDP, use random port allocation as long as the user 4105f311da2SMike Silbersack * allows it. For TCP (and as of yet unknown) connections, 4115f311da2SMike Silbersack * use random port allocation only if the user allows it AND 4125f311da2SMike Silbersack * ipport_tick allows it. 4135f311da2SMike Silbersack */ 4145f311da2SMike Silbersack if (ipport_randomized && 4155f311da2SMike Silbersack (!ipport_stoprandom || pcbinfo == &udbinfo)) 4165f311da2SMike Silbersack dorandom = 1; 4175f311da2SMike Silbersack else 4185f311da2SMike Silbersack dorandom = 0; 4195f311da2SMike Silbersack /* Make sure to not include UDP packets in the count. */ 4205f311da2SMike Silbersack if (pcbinfo != &udbinfo) 4215f311da2SMike Silbersack ipport_tcpallocs++; 4225f311da2SMike Silbersack /* 42333b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 42433b3ac06SPeter Wemm * a deadlock here. 42533b3ac06SPeter Wemm * 42633b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 42733b3ac06SPeter Wemm * is not being tested on each round of the loop. 42833b3ac06SPeter Wemm */ 42933b3ac06SPeter Wemm if (first > last) { 43033b3ac06SPeter Wemm /* 43133b3ac06SPeter Wemm * counting down 43233b3ac06SPeter Wemm */ 4335f311da2SMike Silbersack if (dorandom) 4346b2fc10bSMike Silbersack *lastport = first - 4356b2fc10bSMike Silbersack (arc4random() % (first - last)); 43633b3ac06SPeter Wemm count = first - last; 437174624e0SMike Silbersack 438df8bae1dSRodney W. Grimes do { 4396ac48b74SMike Silbersack if (count-- < 0) /* completely used? */ 440550b1518SWes Peters return (EADDRNOTAVAIL); 44133b3ac06SPeter Wemm --*lastport; 44233b3ac06SPeter Wemm if (*lastport > first || *lastport < last) 44333b3ac06SPeter Wemm *lastport = first; 44415bd2b43SDavid Greenman lport = htons(*lastport); 4454b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 4464b932371SIan Dowse wild)); 44733b3ac06SPeter Wemm } else { 44833b3ac06SPeter Wemm /* 44933b3ac06SPeter Wemm * counting up 45033b3ac06SPeter Wemm */ 4515f311da2SMike Silbersack if (dorandom) 4526b2fc10bSMike Silbersack *lastport = first + 4536b2fc10bSMike Silbersack (arc4random() % (last - first)); 45433b3ac06SPeter Wemm count = last - first; 455174624e0SMike Silbersack 45633b3ac06SPeter Wemm do { 4576ac48b74SMike Silbersack if (count-- < 0) /* completely used? */ 458550b1518SWes Peters return (EADDRNOTAVAIL); 45933b3ac06SPeter Wemm ++*lastport; 46033b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 46133b3ac06SPeter Wemm *lastport = first; 46233b3ac06SPeter Wemm lport = htons(*lastport); 4634b932371SIan Dowse } while (in_pcblookup_local(pcbinfo, laddr, lport, 4644b932371SIan Dowse wild)); 46533b3ac06SPeter Wemm } 46633b3ac06SPeter Wemm } 467b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &laddr.s_addr)) 468e4bdf25dSPoul-Henning Kamp return (EINVAL); 4694b932371SIan Dowse *laddrp = laddr.s_addr; 4704b932371SIan Dowse *lportp = lport; 471df8bae1dSRodney W. Grimes return (0); 472df8bae1dSRodney W. Grimes } 473df8bae1dSRodney W. Grimes 474999f1343SGarrett Wollman /* 4755200e00eSIan Dowse * Connect from a socket to a specified address. 4765200e00eSIan Dowse * Both address and port must be specified in argument sin. 4775200e00eSIan Dowse * If don't have a local address for this socket yet, 4785200e00eSIan Dowse * then pick one. 479999f1343SGarrett Wollman */ 480999f1343SGarrett Wollman int 481b0330ed9SPawel Jakub Dawidek in_pcbconnect(inp, nam, cred) 482999f1343SGarrett Wollman register struct inpcb *inp; 48357bf258eSGarrett Wollman struct sockaddr *nam; 484b0330ed9SPawel Jakub Dawidek struct ucred *cred; 485999f1343SGarrett Wollman { 4865200e00eSIan Dowse u_short lport, fport; 4875200e00eSIan Dowse in_addr_t laddr, faddr; 4885200e00eSIan Dowse int anonport, error; 489df8bae1dSRodney W. Grimes 49027f74fd0SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 49127f74fd0SRobert Watson INP_LOCK_ASSERT(inp); 49227f74fd0SRobert Watson 4935200e00eSIan Dowse lport = inp->inp_lport; 4945200e00eSIan Dowse laddr = inp->inp_laddr.s_addr; 4955200e00eSIan Dowse anonport = (lport == 0); 4965200e00eSIan Dowse error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport, 497b0330ed9SPawel Jakub Dawidek NULL, cred); 4985200e00eSIan Dowse if (error) 4995200e00eSIan Dowse return (error); 5005200e00eSIan Dowse 5015200e00eSIan Dowse /* Do the initial binding of the local address if required. */ 5025200e00eSIan Dowse if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) { 5035200e00eSIan Dowse inp->inp_lport = lport; 5045200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5055200e00eSIan Dowse if (in_pcbinshash(inp) != 0) { 5065200e00eSIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 5075200e00eSIan Dowse inp->inp_lport = 0; 5085200e00eSIan Dowse return (EAGAIN); 5095200e00eSIan Dowse } 5105200e00eSIan Dowse } 5115200e00eSIan Dowse 5125200e00eSIan Dowse /* Commit the remaining changes. */ 5135200e00eSIan Dowse inp->inp_lport = lport; 5145200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5155200e00eSIan Dowse inp->inp_faddr.s_addr = faddr; 5165200e00eSIan Dowse inp->inp_fport = fport; 5175200e00eSIan Dowse in_pcbrehash(inp); 5180f9ade71SHajimu UMEMOTO #ifdef IPSEC 5190f9ade71SHajimu UMEMOTO if (inp->inp_socket->so_type == SOCK_STREAM) 5200f9ade71SHajimu UMEMOTO ipsec_pcbconn(inp->inp_sp); 5210f9ade71SHajimu UMEMOTO #endif 5225200e00eSIan Dowse if (anonport) 5235200e00eSIan Dowse inp->inp_flags |= INP_ANONPORT; 5245200e00eSIan Dowse return (0); 5255200e00eSIan Dowse } 5265200e00eSIan Dowse 5275200e00eSIan Dowse /* 5285200e00eSIan Dowse * Set up for a connect from a socket to the specified address. 5295200e00eSIan Dowse * On entry, *laddrp and *lportp should contain the current local 5305200e00eSIan Dowse * address and port for the PCB; these are updated to the values 5315200e00eSIan Dowse * that should be placed in inp_laddr and inp_lport to complete 5325200e00eSIan Dowse * the connect. 5335200e00eSIan Dowse * 5345200e00eSIan Dowse * On success, *faddrp and *fportp will be set to the remote address 5355200e00eSIan Dowse * and port. These are not updated in the error case. 5365200e00eSIan Dowse * 5375200e00eSIan Dowse * If the operation fails because the connection already exists, 5385200e00eSIan Dowse * *oinpp will be set to the PCB of that connection so that the 5395200e00eSIan Dowse * caller can decide to override it. In all other cases, *oinpp 5405200e00eSIan Dowse * is set to NULL. 5415200e00eSIan Dowse */ 5425200e00eSIan Dowse int 543b0330ed9SPawel Jakub Dawidek in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, cred) 5445200e00eSIan Dowse register struct inpcb *inp; 5455200e00eSIan Dowse struct sockaddr *nam; 5465200e00eSIan Dowse in_addr_t *laddrp; 5475200e00eSIan Dowse u_short *lportp; 5485200e00eSIan Dowse in_addr_t *faddrp; 5495200e00eSIan Dowse u_short *fportp; 5505200e00eSIan Dowse struct inpcb **oinpp; 551b0330ed9SPawel Jakub Dawidek struct ucred *cred; 5525200e00eSIan Dowse { 5535200e00eSIan Dowse struct sockaddr_in *sin = (struct sockaddr_in *)nam; 5545200e00eSIan Dowse struct in_ifaddr *ia; 5555200e00eSIan Dowse struct sockaddr_in sa; 556b0330ed9SPawel Jakub Dawidek struct ucred *socred; 5575200e00eSIan Dowse struct inpcb *oinp; 5585200e00eSIan Dowse struct in_addr laddr, faddr; 5595200e00eSIan Dowse u_short lport, fport; 5605200e00eSIan Dowse int error; 5615200e00eSIan Dowse 56227f74fd0SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 56327f74fd0SRobert Watson INP_LOCK_ASSERT(inp); 56427f74fd0SRobert Watson 5655200e00eSIan Dowse if (oinpp != NULL) 5665200e00eSIan Dowse *oinpp = NULL; 56757bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 568df8bae1dSRodney W. Grimes return (EINVAL); 569df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 570df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 571df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 572df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 5735200e00eSIan Dowse laddr.s_addr = *laddrp; 5745200e00eSIan Dowse lport = *lportp; 5755200e00eSIan Dowse faddr = sin->sin_addr; 5765200e00eSIan Dowse fport = sin->sin_port; 577b0330ed9SPawel Jakub Dawidek socred = inp->inp_socket->so_cred; 578b0330ed9SPawel Jakub Dawidek if (laddr.s_addr == INADDR_ANY && jailed(socred)) { 5795200e00eSIan Dowse bzero(&sa, sizeof(sa)); 580b0330ed9SPawel Jakub Dawidek sa.sin_addr.s_addr = htonl(prison_getip(socred)); 5815200e00eSIan Dowse sa.sin_len = sizeof(sa); 5825200e00eSIan Dowse sa.sin_family = AF_INET; 5835200e00eSIan Dowse error = in_pcbbind_setup(inp, (struct sockaddr *)&sa, 584b0330ed9SPawel Jakub Dawidek &laddr.s_addr, &lport, cred); 5855200e00eSIan Dowse if (error) 5865200e00eSIan Dowse return (error); 5875200e00eSIan Dowse } 58859562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 589df8bae1dSRodney W. Grimes /* 590df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 591df8bae1dSRodney W. Grimes * use the primary local address. 592df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 593df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 594df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 595df8bae1dSRodney W. Grimes */ 5965200e00eSIan Dowse if (faddr.s_addr == INADDR_ANY) 5975200e00eSIan Dowse faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; 5985200e00eSIan Dowse else if (faddr.s_addr == (u_long)INADDR_BROADCAST && 5995200e00eSIan Dowse (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & 6005200e00eSIan Dowse IFF_BROADCAST)) 6015200e00eSIan Dowse faddr = satosin(&TAILQ_FIRST( 6025200e00eSIan Dowse &in_ifaddrhead)->ia_broadaddr)->sin_addr; 603df8bae1dSRodney W. Grimes } 6045200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY) { 60597d8d152SAndre Oppermann struct route sro; 606df8bae1dSRodney W. Grimes 6070cfbbe3bSAndre Oppermann bzero(&sro, sizeof(sro)); 608df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 609df8bae1dSRodney W. Grimes /* 61097d8d152SAndre Oppermann * If route is known our src addr is taken from the i/f, 61197d8d152SAndre Oppermann * else punt. 612df8bae1dSRodney W. Grimes */ 61397d8d152SAndre Oppermann if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) { 61497d8d152SAndre Oppermann /* Find out route to destination */ 61597d8d152SAndre Oppermann sro.ro_dst.sa_family = AF_INET; 61697d8d152SAndre Oppermann sro.ro_dst.sa_len = sizeof(struct sockaddr_in); 61797d8d152SAndre Oppermann ((struct sockaddr_in *)&sro.ro_dst)->sin_addr = faddr; 61897d8d152SAndre Oppermann rtalloc_ign(&sro, RTF_CLONING); 6194cc20ab1SSeigo Tanimura } 620df8bae1dSRodney W. Grimes /* 621df8bae1dSRodney W. Grimes * If we found a route, use the address 622df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 623df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 624df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 625df8bae1dSRodney W. Grimes */ 62697d8d152SAndre Oppermann if (sro.ro_rt && !(sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 62797d8d152SAndre Oppermann ia = ifatoia(sro.ro_rt->rt_ifa); 62897d8d152SAndre Oppermann if (sro.ro_rt) 62997d8d152SAndre Oppermann RTFREE(sro.ro_rt); 630df8bae1dSRodney W. Grimes if (ia == 0) { 6315200e00eSIan Dowse bzero(&sa, sizeof(sa)); 6325200e00eSIan Dowse sa.sin_addr = faddr; 6335200e00eSIan Dowse sa.sin_len = sizeof(sa); 6345200e00eSIan Dowse sa.sin_family = AF_INET; 635df8bae1dSRodney W. Grimes 6365200e00eSIan Dowse ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sa))); 637df8bae1dSRodney W. Grimes if (ia == 0) 6385200e00eSIan Dowse ia = ifatoia(ifa_ifwithnet(sintosa(&sa))); 639df8bae1dSRodney W. Grimes if (ia == 0) 640ef14c369SMaxim Konovalov return (ENETUNREACH); 641df8bae1dSRodney W. Grimes } 642df8bae1dSRodney W. Grimes /* 643df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 644df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 645df8bae1dSRodney W. Grimes * address of that interface as our source address. 646df8bae1dSRodney W. Grimes */ 6475200e00eSIan Dowse if (IN_MULTICAST(ntohl(faddr.s_addr)) && 648df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 649df8bae1dSRodney W. Grimes struct ip_moptions *imo; 650df8bae1dSRodney W. Grimes struct ifnet *ifp; 651df8bae1dSRodney W. Grimes 652df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 653df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 654df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 65537d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 656df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 657df8bae1dSRodney W. Grimes break; 658df8bae1dSRodney W. Grimes if (ia == 0) 659df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 660df8bae1dSRodney W. Grimes } 661df8bae1dSRodney W. Grimes } 6625200e00eSIan Dowse laddr = ia->ia_addr.sin_addr; 663999f1343SGarrett Wollman } 664999f1343SGarrett Wollman 6655200e00eSIan Dowse oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport, 6665200e00eSIan Dowse 0, NULL); 6675200e00eSIan Dowse if (oinp != NULL) { 6685200e00eSIan Dowse if (oinpp != NULL) 6695200e00eSIan Dowse *oinpp = oinp; 670df8bae1dSRodney W. Grimes return (EADDRINUSE); 671c3229e05SDavid Greenman } 6725200e00eSIan Dowse if (lport == 0) { 673b0330ed9SPawel Jakub Dawidek error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, 674b0330ed9SPawel Jakub Dawidek cred); 6755a903f8dSPierre Beyssac if (error) 6765a903f8dSPierre Beyssac return (error); 6775a903f8dSPierre Beyssac } 6785200e00eSIan Dowse *laddrp = laddr.s_addr; 6795200e00eSIan Dowse *lportp = lport; 6805200e00eSIan Dowse *faddrp = faddr.s_addr; 6815200e00eSIan Dowse *fportp = fport; 682df8bae1dSRodney W. Grimes return (0); 683df8bae1dSRodney W. Grimes } 684df8bae1dSRodney W. Grimes 68526f9a767SRodney W. Grimes void 686df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 687df8bae1dSRodney W. Grimes struct inpcb *inp; 688df8bae1dSRodney W. Grimes { 68959daba27SSam Leffler INP_LOCK_ASSERT(inp); 690df8bae1dSRodney W. Grimes 691df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 692df8bae1dSRodney W. Grimes inp->inp_fport = 0; 69315bd2b43SDavid Greenman in_pcbrehash(inp); 6940f9ade71SHajimu UMEMOTO #ifdef IPSEC 6950f9ade71SHajimu UMEMOTO ipsec_pcbdisconn(inp->inp_sp); 6960f9ade71SHajimu UMEMOTO #endif 697548c676bSHajimu UMEMOTO if (inp->inp_socket->so_state & SS_NOFDREF) 698548c676bSHajimu UMEMOTO in_pcbdetach(inp); 699df8bae1dSRodney W. Grimes } 700df8bae1dSRodney W. Grimes 70126f9a767SRodney W. Grimes void 702df8bae1dSRodney W. Grimes in_pcbdetach(inp) 703df8bae1dSRodney W. Grimes struct inpcb *inp; 704df8bae1dSRodney W. Grimes { 705df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 7063d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 707df8bae1dSRodney W. Grimes 70859daba27SSam Leffler INP_LOCK_ASSERT(inp); 70959daba27SSam Leffler 7100f9ade71SHajimu UMEMOTO #if defined(IPSEC) || defined(FAST_IPSEC) 711cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 712cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/ 7133d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 714c3229e05SDavid Greenman in_pcbremlists(inp); 715340c35deSJonathan Lemon if (so) { 71681158452SRobert Watson ACCEPT_LOCK(); 717395a08c9SRobert Watson SOCK_LOCK(so); 71848ac555dSRobert Watson so->so_pcb = NULL; 719b1e4abd2SMatthew Dillon sotryfree(so); 720340c35deSJonathan Lemon } 721df8bae1dSRodney W. Grimes if (inp->inp_options) 722df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 723df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 724cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 725f76fcf6dSJeffrey Hsu INP_LOCK_DESTROY(inp); 726a557af22SRobert Watson #ifdef MAC 727a557af22SRobert Watson mac_destroy_inpcb(inp); 728a557af22SRobert Watson #endif 72969c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 730df8bae1dSRodney W. Grimes } 731df8bae1dSRodney W. Grimes 73226ef6ac4SDon Lewis struct sockaddr * 73326ef6ac4SDon Lewis in_sockaddr(port, addr_p) 73426ef6ac4SDon Lewis in_port_t port; 73526ef6ac4SDon Lewis struct in_addr *addr_p; 73626ef6ac4SDon Lewis { 73726ef6ac4SDon Lewis struct sockaddr_in *sin; 73826ef6ac4SDon Lewis 73926ef6ac4SDon Lewis MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, 740a163d034SWarner Losh M_WAITOK | M_ZERO); 74126ef6ac4SDon Lewis sin->sin_family = AF_INET; 74226ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 74326ef6ac4SDon Lewis sin->sin_addr = *addr_p; 74426ef6ac4SDon Lewis sin->sin_port = port; 74526ef6ac4SDon Lewis 74626ef6ac4SDon Lewis return (struct sockaddr *)sin; 74726ef6ac4SDon Lewis } 74826ef6ac4SDon Lewis 749117bcae7SGarrett Wollman /* 750f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 751f76fcf6dSJeffrey Hsu * The socket must have a valid 752117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 753117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 75457bf258eSGarrett Wollman * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 75557bf258eSGarrett Wollman * because there actually /is/ a programming error somewhere... XXX) 756117bcae7SGarrett Wollman */ 757117bcae7SGarrett Wollman int 758f76fcf6dSJeffrey Hsu in_setsockaddr(so, nam, pcbinfo) 759117bcae7SGarrett Wollman struct socket *so; 76057bf258eSGarrett Wollman struct sockaddr **nam; 761f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 762df8bae1dSRodney W. Grimes { 763fdc984f7STor Egge int s; 764fdc984f7STor Egge register struct inpcb *inp; 76526ef6ac4SDon Lewis struct in_addr addr; 76626ef6ac4SDon Lewis in_port_t port; 76742fa505bSDavid Greenman 768fdc984f7STor Egge s = splnet(); 769f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 770fdc984f7STor Egge inp = sotoinpcb(so); 771db112f04STor Egge if (!inp) { 772f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 773db112f04STor Egge splx(s); 774ff079ca4SPeter Wemm return ECONNRESET; 775db112f04STor Egge } 776f76fcf6dSJeffrey Hsu INP_LOCK(inp); 77726ef6ac4SDon Lewis port = inp->inp_lport; 77826ef6ac4SDon Lewis addr = inp->inp_laddr; 779f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 780f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 781db112f04STor Egge splx(s); 78242fa505bSDavid Greenman 78326ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 784117bcae7SGarrett Wollman return 0; 785df8bae1dSRodney W. Grimes } 786df8bae1dSRodney W. Grimes 787f76fcf6dSJeffrey Hsu /* 788f76fcf6dSJeffrey Hsu * The wrapper function will pass down the pcbinfo for this function to lock. 789f76fcf6dSJeffrey Hsu */ 790117bcae7SGarrett Wollman int 791f76fcf6dSJeffrey Hsu in_setpeeraddr(so, nam, pcbinfo) 792117bcae7SGarrett Wollman struct socket *so; 79357bf258eSGarrett Wollman struct sockaddr **nam; 794f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 795df8bae1dSRodney W. Grimes { 796fdc984f7STor Egge int s; 797f76fcf6dSJeffrey Hsu register struct inpcb *inp; 79826ef6ac4SDon Lewis struct in_addr addr; 79926ef6ac4SDon Lewis in_port_t port; 80042fa505bSDavid Greenman 801fdc984f7STor Egge s = splnet(); 802f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 803fdc984f7STor Egge inp = sotoinpcb(so); 804db112f04STor Egge if (!inp) { 805f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 806db112f04STor Egge splx(s); 807ff079ca4SPeter Wemm return ECONNRESET; 808db112f04STor Egge } 809f76fcf6dSJeffrey Hsu INP_LOCK(inp); 81026ef6ac4SDon Lewis port = inp->inp_fport; 81126ef6ac4SDon Lewis addr = inp->inp_faddr; 812f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 813f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 814db112f04STor Egge splx(s); 81542fa505bSDavid Greenman 81626ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 817117bcae7SGarrett Wollman return 0; 818df8bae1dSRodney W. Grimes } 819df8bae1dSRodney W. Grimes 82026f9a767SRodney W. Grimes void 821f76fcf6dSJeffrey Hsu in_pcbnotifyall(pcbinfo, faddr, errno, notify) 822f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 823df8bae1dSRodney W. Grimes struct in_addr faddr; 824c693a045SJonathan Lemon int errno; 8253ce144eaSJeffrey Hsu struct inpcb *(*notify)(struct inpcb *, int); 826d1c54148SJesper Skriver { 827c693a045SJonathan Lemon struct inpcb *inp, *ninp; 828f76fcf6dSJeffrey Hsu struct inpcbhead *head; 829c693a045SJonathan Lemon int s; 830d1c54148SJesper Skriver 831d1c54148SJesper Skriver s = splnet(); 8323dc7ebf9SJeffrey Hsu INP_INFO_WLOCK(pcbinfo); 833f76fcf6dSJeffrey Hsu head = pcbinfo->listhead; 834c693a045SJonathan Lemon for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { 835f76fcf6dSJeffrey Hsu INP_LOCK(inp); 836c693a045SJonathan Lemon ninp = LIST_NEXT(inp, inp_list); 837d1c54148SJesper Skriver #ifdef INET6 838f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 839f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 840d1c54148SJesper Skriver continue; 841f76fcf6dSJeffrey Hsu } 842d1c54148SJesper Skriver #endif 843d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 844f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 845f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 846d1c54148SJesper Skriver continue; 847d1c54148SJesper Skriver } 8483dc7ebf9SJeffrey Hsu if ((*notify)(inp, errno)) 849f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 850f76fcf6dSJeffrey Hsu } 8513dc7ebf9SJeffrey Hsu INP_INFO_WUNLOCK(pcbinfo); 852d1c54148SJesper Skriver splx(s); 853d1c54148SJesper Skriver } 854d1c54148SJesper Skriver 855e43cc4aeSHajimu UMEMOTO void 856f76fcf6dSJeffrey Hsu in_pcbpurgeif0(pcbinfo, ifp) 857f76fcf6dSJeffrey Hsu struct inpcbinfo *pcbinfo; 858e43cc4aeSHajimu UMEMOTO struct ifnet *ifp; 859e43cc4aeSHajimu UMEMOTO { 860e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 861e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 862e43cc4aeSHajimu UMEMOTO int i, gap; 863e43cc4aeSHajimu UMEMOTO 864f76fcf6dSJeffrey Hsu /* why no splnet here? XXX */ 865f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 8663cfcc388SJeffrey Hsu LIST_FOREACH(inp, pcbinfo->listhead, inp_list) { 867f76fcf6dSJeffrey Hsu INP_LOCK(inp); 868e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 869e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 870e43cc4aeSHajimu UMEMOTO imo != NULL) { 871e43cc4aeSHajimu UMEMOTO /* 872e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 873e43cc4aeSHajimu UMEMOTO * detached. 874e43cc4aeSHajimu UMEMOTO */ 875e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 876e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 877e43cc4aeSHajimu UMEMOTO 878e43cc4aeSHajimu UMEMOTO /* 879e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 880e43cc4aeSHajimu UMEMOTO * through the interface being detached. 881e43cc4aeSHajimu UMEMOTO */ 882e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 883e43cc4aeSHajimu UMEMOTO i++) { 884e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 885e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 886e43cc4aeSHajimu UMEMOTO gap++; 887e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 888e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 889e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 890e43cc4aeSHajimu UMEMOTO } 891e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 892e43cc4aeSHajimu UMEMOTO } 893f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 894e43cc4aeSHajimu UMEMOTO } 8953cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 896e43cc4aeSHajimu UMEMOTO } 897e43cc4aeSHajimu UMEMOTO 898df8bae1dSRodney W. Grimes /* 899c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 900c3229e05SDavid Greenman */ 901df8bae1dSRodney W. Grimes struct inpcb * 902c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 9036d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 904c3229e05SDavid Greenman struct in_addr laddr; 905c3229e05SDavid Greenman u_int lport_arg; 9066d6a026bSDavid Greenman int wild_okay; 907df8bae1dSRodney W. Grimes { 908f1d19042SArchie Cobbs register struct inpcb *inp; 909df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 910c3229e05SDavid Greenman u_short lport = lport_arg; 9117bc4aca7SDavid Greenman 9121b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 9131b73ca0bSSam Leffler 914c3229e05SDavid Greenman if (!wild_okay) { 915c3229e05SDavid Greenman struct inpcbhead *head; 916c3229e05SDavid Greenman /* 917c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 918c3229e05SDavid Greenman * matches the local address and port we're looking for. 919c3229e05SDavid Greenman */ 920c3229e05SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 921fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 922cfa1ca9dSYoshinobu Inoue #ifdef INET6 923369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 924cfa1ca9dSYoshinobu Inoue continue; 925cfa1ca9dSYoshinobu Inoue #endif 926c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 927c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 928c3229e05SDavid Greenman inp->inp_lport == lport) { 929c3229e05SDavid Greenman /* 930c3229e05SDavid Greenman * Found. 931c3229e05SDavid Greenman */ 932c3229e05SDavid Greenman return (inp); 933df8bae1dSRodney W. Grimes } 934c3229e05SDavid Greenman } 935c3229e05SDavid Greenman /* 936c3229e05SDavid Greenman * Not found. 937c3229e05SDavid Greenman */ 938c3229e05SDavid Greenman return (NULL); 939c3229e05SDavid Greenman } else { 940c3229e05SDavid Greenman struct inpcbporthead *porthash; 941c3229e05SDavid Greenman struct inpcbport *phd; 942c3229e05SDavid Greenman struct inpcb *match = NULL; 943c3229e05SDavid Greenman /* 944c3229e05SDavid Greenman * Best fit PCB lookup. 945c3229e05SDavid Greenman * 946c3229e05SDavid Greenman * First see if this local port is in use by looking on the 947c3229e05SDavid Greenman * port hash list. 948c3229e05SDavid Greenman */ 94996af9ea5SMike Silbersack retrylookup: 950c3229e05SDavid Greenman porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 951c3229e05SDavid Greenman pcbinfo->porthashmask)]; 952fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 953c3229e05SDavid Greenman if (phd->phd_port == lport) 954c3229e05SDavid Greenman break; 955c3229e05SDavid Greenman } 956c3229e05SDavid Greenman if (phd != NULL) { 957c3229e05SDavid Greenman /* 958c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 959c3229e05SDavid Greenman * fit. 960c3229e05SDavid Greenman */ 96137d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 962c3229e05SDavid Greenman wildcard = 0; 963cfa1ca9dSYoshinobu Inoue #ifdef INET6 964369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 965cfa1ca9dSYoshinobu Inoue continue; 966cfa1ca9dSYoshinobu Inoue #endif 96796af9ea5SMike Silbersack /* 96896af9ea5SMike Silbersack * Clean out old time_wait sockets if they 96996af9ea5SMike Silbersack * are clogging up needed local ports. 97096af9ea5SMike Silbersack */ 97196af9ea5SMike Silbersack if ((inp->inp_vflag & INP_TIMEWAIT) != 0) { 97296af9ea5SMike Silbersack if (tcp_twrecycleable((struct tcptw *)inp->inp_ppcb)) { 973f7bbe2c0SSam Leffler INP_LOCK(inp); 97496af9ea5SMike Silbersack tcp_twclose((struct tcptw *)inp->inp_ppcb, 0); 97596af9ea5SMike Silbersack match = NULL; 97696af9ea5SMike Silbersack goto retrylookup; 97796af9ea5SMike Silbersack } 97896af9ea5SMike Silbersack } 979c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 980c3229e05SDavid Greenman wildcard++; 98115bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 98215bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 98315bd2b43SDavid Greenman wildcard++; 98415bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 98515bd2b43SDavid Greenman continue; 98615bd2b43SDavid Greenman } else { 98715bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 98815bd2b43SDavid Greenman wildcard++; 98915bd2b43SDavid Greenman } 990df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 991df8bae1dSRodney W. Grimes match = inp; 992df8bae1dSRodney W. Grimes matchwild = wildcard; 9933dbdc25cSDavid Greenman if (matchwild == 0) { 994df8bae1dSRodney W. Grimes break; 995df8bae1dSRodney W. Grimes } 996df8bae1dSRodney W. Grimes } 9973dbdc25cSDavid Greenman } 998c3229e05SDavid Greenman } 999df8bae1dSRodney W. Grimes return (match); 1000df8bae1dSRodney W. Grimes } 1001c3229e05SDavid Greenman } 100215bd2b43SDavid Greenman 100315bd2b43SDavid Greenman /* 100415bd2b43SDavid Greenman * Lookup PCB in hash list. 100515bd2b43SDavid Greenman */ 100615bd2b43SDavid Greenman struct inpcb * 1007cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, 1008cfa1ca9dSYoshinobu Inoue ifp) 100915bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 101015bd2b43SDavid Greenman struct in_addr faddr, laddr; 101115bd2b43SDavid Greenman u_int fport_arg, lport_arg; 10126d6a026bSDavid Greenman int wildcard; 1013cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 101415bd2b43SDavid Greenman { 101515bd2b43SDavid Greenman struct inpcbhead *head; 101615bd2b43SDavid Greenman register struct inpcb *inp; 101715bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 101815bd2b43SDavid Greenman 101959daba27SSam Leffler INP_INFO_RLOCK_ASSERT(pcbinfo); 102015bd2b43SDavid Greenman /* 102115bd2b43SDavid Greenman * First look for an exact match. 102215bd2b43SDavid Greenman */ 1023ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 1024fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1025cfa1ca9dSYoshinobu Inoue #ifdef INET6 1026369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1027cfa1ca9dSYoshinobu Inoue continue; 1028cfa1ca9dSYoshinobu Inoue #endif 10296d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 1030ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1031ca98b82cSDavid Greenman inp->inp_fport == fport && 1032c3229e05SDavid Greenman inp->inp_lport == lport) { 1033c3229e05SDavid Greenman /* 1034c3229e05SDavid Greenman * Found. 1035c3229e05SDavid Greenman */ 1036c3229e05SDavid Greenman return (inp); 1037c3229e05SDavid Greenman } 10386d6a026bSDavid Greenman } 10396d6a026bSDavid Greenman if (wildcard) { 10406d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 1041cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1042cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 1043cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 10446d6a026bSDavid Greenman 1045ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 1046fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1047cfa1ca9dSYoshinobu Inoue #ifdef INET6 1048369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1049cfa1ca9dSYoshinobu Inoue continue; 1050cfa1ca9dSYoshinobu Inoue #endif 10516d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1052c3229e05SDavid Greenman inp->inp_lport == lport) { 1053cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 1054cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 1055cfa1ca9dSYoshinobu Inoue continue; 10566d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 1057c3229e05SDavid Greenman return (inp); 1058cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 1059cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1060cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 1061cfa1ca9dSYoshinobu Inoue AF_INET6)) 1062cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 1063cfa1ca9dSYoshinobu Inoue else 1064cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 10656d6a026bSDavid Greenman local_wild = inp; 10666d6a026bSDavid Greenman } 10676d6a026bSDavid Greenman } 1068cfa1ca9dSYoshinobu Inoue } 1069cfa1ca9dSYoshinobu Inoue #if defined(INET6) 1070cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 1071cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 1072cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 1073c3229e05SDavid Greenman return (local_wild); 10746d6a026bSDavid Greenman } 1075c3229e05SDavid Greenman 1076c3229e05SDavid Greenman /* 1077c3229e05SDavid Greenman * Not found. 1078c3229e05SDavid Greenman */ 10796d6a026bSDavid Greenman return (NULL); 108015bd2b43SDavid Greenman } 108115bd2b43SDavid Greenman 10827bc4aca7SDavid Greenman /* 1083c3229e05SDavid Greenman * Insert PCB onto various hash lists. 10847bc4aca7SDavid Greenman */ 1085c3229e05SDavid Greenman int 108615bd2b43SDavid Greenman in_pcbinshash(inp) 108715bd2b43SDavid Greenman struct inpcb *inp; 108815bd2b43SDavid Greenman { 1089c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1090c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1091c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1092c3229e05SDavid Greenman struct inpcbport *phd; 1093cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 109415bd2b43SDavid Greenman 109559daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 1096cfa1ca9dSYoshinobu Inoue #ifdef INET6 1097cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1098cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1099cfa1ca9dSYoshinobu Inoue else 1100cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1101cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1102cfa1ca9dSYoshinobu Inoue 1103cfa1ca9dSYoshinobu Inoue pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 1104c3229e05SDavid Greenman inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 110515bd2b43SDavid Greenman 1106c3229e05SDavid Greenman pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, 1107c3229e05SDavid Greenman pcbinfo->porthashmask)]; 1108c3229e05SDavid Greenman 1109c3229e05SDavid Greenman /* 1110c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1111c3229e05SDavid Greenman */ 1112fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1113c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1114c3229e05SDavid Greenman break; 1115c3229e05SDavid Greenman } 1116c3229e05SDavid Greenman /* 1117c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1118c3229e05SDavid Greenman */ 1119c3229e05SDavid Greenman if (phd == NULL) { 1120c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1121c3229e05SDavid Greenman if (phd == NULL) { 1122c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1123c3229e05SDavid Greenman } 1124c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1125c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1126c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1127c3229e05SDavid Greenman } 1128c3229e05SDavid Greenman inp->inp_phd = phd; 1129c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1130c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1131c3229e05SDavid Greenman return (0); 113215bd2b43SDavid Greenman } 113315bd2b43SDavid Greenman 1134c3229e05SDavid Greenman /* 1135c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1136c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1137c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1138c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1139c3229e05SDavid Greenman */ 114015bd2b43SDavid Greenman void 114115bd2b43SDavid Greenman in_pcbrehash(inp) 114215bd2b43SDavid Greenman struct inpcb *inp; 114315bd2b43SDavid Greenman { 114459daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 114515bd2b43SDavid Greenman struct inpcbhead *head; 1146cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 114715bd2b43SDavid Greenman 114859daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 11494c2bb15aSRobert Watson INP_LOCK_ASSERT(inp); 1150cfa1ca9dSYoshinobu Inoue #ifdef INET6 1151cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1152cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1153cfa1ca9dSYoshinobu Inoue else 1154cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1155cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1156cfa1ca9dSYoshinobu Inoue 115759daba27SSam Leffler head = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 115859daba27SSam Leffler inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 115915bd2b43SDavid Greenman 1160c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 116115bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1162c3229e05SDavid Greenman } 1163c3229e05SDavid Greenman 1164c3229e05SDavid Greenman /* 1165c3229e05SDavid Greenman * Remove PCB from various lists. 1166c3229e05SDavid Greenman */ 116776429de4SYoshinobu Inoue void 1168c3229e05SDavid Greenman in_pcbremlists(inp) 1169c3229e05SDavid Greenman struct inpcb *inp; 1170c3229e05SDavid Greenman { 117159daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 117259daba27SSam Leffler 117359daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 117459daba27SSam Leffler INP_LOCK_ASSERT(inp); 117559daba27SSam Leffler 117659daba27SSam Leffler inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 1177c3229e05SDavid Greenman if (inp->inp_lport) { 1178c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1179c3229e05SDavid Greenman 1180c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1181c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1182fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1183c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1184c3229e05SDavid Greenman free(phd, M_PCB); 1185c3229e05SDavid Greenman } 1186c3229e05SDavid Greenman } 1187c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 118859daba27SSam Leffler pcbinfo->ipi_count--; 118915bd2b43SDavid Greenman } 119075c13541SPoul-Henning Kamp 1191a557af22SRobert Watson /* 1192a557af22SRobert Watson * A set label operation has occurred at the socket layer, propagate the 1193a557af22SRobert Watson * label change into the in_pcb for the socket. 1194a557af22SRobert Watson */ 1195a557af22SRobert Watson void 1196a557af22SRobert Watson in_pcbsosetlabel(so) 1197a557af22SRobert Watson struct socket *so; 1198a557af22SRobert Watson { 1199a557af22SRobert Watson #ifdef MAC 1200a557af22SRobert Watson struct inpcb *inp; 1201a557af22SRobert Watson 1202a557af22SRobert Watson inp = (struct inpcb *)so->so_pcb; 1203a557af22SRobert Watson INP_LOCK(inp); 1204310e7cebSRobert Watson SOCK_LOCK(so); 1205a557af22SRobert Watson mac_inpcb_sosetlabel(so, inp); 1206310e7cebSRobert Watson SOCK_UNLOCK(so); 1207a557af22SRobert Watson INP_UNLOCK(inp); 1208a557af22SRobert Watson #endif 1209a557af22SRobert Watson } 12105f311da2SMike Silbersack 12115f311da2SMike Silbersack /* 12125f311da2SMike Silbersack * ipport_tick runs once per second, determining if random port 12135f311da2SMike Silbersack * allocation should be continued. If more than ipport_randomcps 12145f311da2SMike Silbersack * ports have been allocated in the last second, then we return to 12155f311da2SMike Silbersack * sequential port allocation. We return to random allocation only 12165f311da2SMike Silbersack * once we drop below ipport_randomcps for at least 5 seconds. 12175f311da2SMike Silbersack */ 12185f311da2SMike Silbersack 12195f311da2SMike Silbersack void 12205f311da2SMike Silbersack ipport_tick(xtp) 12215f311da2SMike Silbersack void *xtp; 12225f311da2SMike Silbersack { 12235f311da2SMike Silbersack if (ipport_tcpallocs > ipport_tcplastcount + ipport_randomcps) { 12245f311da2SMike Silbersack ipport_stoprandom = ipport_randomtime; 12255f311da2SMike Silbersack } else { 12265f311da2SMike Silbersack if (ipport_stoprandom > 0) 12275f311da2SMike Silbersack ipport_stoprandom--; 12285f311da2SMike Silbersack } 12295f311da2SMike Silbersack ipport_tcplastcount = ipport_tcpallocs; 12305f311da2SMike Silbersack callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL); 12315f311da2SMike Silbersack } 1232