1c398230bSWarner Losh /*- 22469dd60SGarrett Wollman * Copyright (c) 1982, 1986, 1991, 1993, 1995 3497057eeSRobert Watson * The Regents of the University of California. 4497057eeSRobert Watson * Copyright (c) 2007 Robert N. M. Watson 5497057eeSRobert Watson * All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 312469dd60SGarrett Wollman * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 344b421e2dSMike Silbersack #include <sys/cdefs.h> 354b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 364b421e2dSMike Silbersack 37497057eeSRobert Watson #include "opt_ddb.h" 386a800098SYoshinobu Inoue #include "opt_ipsec.h" 39cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 40a557af22SRobert Watson #include "opt_mac.h" 41cfa1ca9dSYoshinobu Inoue 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/malloc.h> 45df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 47df8bae1dSRodney W. Grimes #include <sys/protosw.h> 48df8bae1dSRodney W. Grimes #include <sys/socket.h> 49df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 50acd3428bSRobert Watson #include <sys/priv.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 5275c13541SPoul-Henning Kamp #include <sys/jail.h> 53101f9fc8SPeter Wemm #include <sys/kernel.h> 54101f9fc8SPeter Wemm #include <sys/sysctl.h> 55603724d3SBjoern A. Zeeb #include <sys/vimage.h> 568781d8e9SBruce Evans 57497057eeSRobert Watson #ifdef DDB 58497057eeSRobert Watson #include <ddb/ddb.h> 59497057eeSRobert Watson #endif 60497057eeSRobert Watson 6169c2d429SJeff Roberson #include <vm/uma.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <net/if.h> 64cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 65df8bae1dSRodney W. Grimes #include <net/route.h> 66df8bae1dSRodney W. Grimes 67df8bae1dSRodney W. Grimes #include <netinet/in.h> 68df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 70df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 71340c35deSJonathan Lemon #include <netinet/tcp_var.h> 725f311da2SMike Silbersack #include <netinet/udp.h> 735f311da2SMike Silbersack #include <netinet/udp_var.h> 74cfa1ca9dSYoshinobu Inoue #ifdef INET6 75cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 76cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 77cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 78cfa1ca9dSYoshinobu Inoue 79df8bae1dSRodney W. Grimes 80b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 81b9234fafSSam Leffler #include <netipsec/ipsec.h> 82b9234fafSSam Leffler #include <netipsec/key.h> 83b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 84b9234fafSSam Leffler 85aed55708SRobert Watson #include <security/mac/mac_framework.h> 86aed55708SRobert Watson 87101f9fc8SPeter Wemm /* 88101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 89101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 90101f9fc8SPeter Wemm */ 9182cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 9282cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 931cf6e4f5SRui Paulo int ipport_firstauto = IPPORT_EPHEMERALFIRST; /* 10000 */ 941cf6e4f5SRui Paulo int ipport_lastauto = IPPORT_EPHEMERALLAST; /* 65535 */ 9582cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9682cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 97101f9fc8SPeter Wemm 98b0d22693SCrist J. Clark /* 99b0d22693SCrist J. Clark * Reserved ports accessible only to root. There are significant 100b0d22693SCrist J. Clark * security considerations that must be accounted for when changing these, 101b0d22693SCrist J. Clark * but the security benefits can be great. Please be careful. 102b0d22693SCrist J. Clark */ 103b0d22693SCrist J. Clark int ipport_reservedhigh = IPPORT_RESERVED - 1; /* 1023 */ 104b0d22693SCrist J. Clark int ipport_reservedlow = 0; 105b0d22693SCrist J. Clark 1065f311da2SMike Silbersack /* Variables dealing with random ephemeral port allocation. */ 1075f311da2SMike Silbersack int ipport_randomized = 1; /* user controlled via sysctl */ 1085f311da2SMike Silbersack int ipport_randomcps = 10; /* user controlled via sysctl */ 1095f311da2SMike Silbersack int ipport_randomtime = 45; /* user controlled via sysctl */ 1105f311da2SMike Silbersack int ipport_stoprandom = 0; /* toggled by ipport_tick */ 1115f311da2SMike Silbersack int ipport_tcpallocs; 1125f311da2SMike Silbersack int ipport_tcplastcount; 1136ac48b74SMike Silbersack 114bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 115bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 116bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 117bbd42ad0SPeter Wemm 118bbd42ad0SPeter Wemm static int 11982d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 120bbd42ad0SPeter Wemm { 12130a4ab08SBruce Evans int error; 12230a4ab08SBruce Evans 12330a4ab08SBruce Evans error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 12430a4ab08SBruce Evans if (error == 0) { 125603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 126603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 127603724d3SBjoern A. Zeeb RANGECHK(V_ipport_firstauto, IPPORT_RESERVED, IPPORT_MAX); 128603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lastauto, IPPORT_RESERVED, IPPORT_MAX); 129603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hifirstauto, IPPORT_RESERVED, IPPORT_MAX); 130603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hilastauto, IPPORT_RESERVED, IPPORT_MAX); 131bbd42ad0SPeter Wemm } 13230a4ab08SBruce Evans return (error); 133bbd42ad0SPeter Wemm } 134bbd42ad0SPeter Wemm 135bbd42ad0SPeter Wemm #undef RANGECHK 136bbd42ad0SPeter Wemm 13733b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 13833b3ac06SPeter Wemm 1398b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1408b615593SMarko Zec lowfirst, CTLTYPE_INT|CTLFLAG_RW, ipport_lowfirstauto, 0, 1418b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1428b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1438b615593SMarko Zec lowlast, CTLTYPE_INT|CTLFLAG_RW, ipport_lowlastauto, 0, 1448b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1458b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1468b615593SMarko Zec first, CTLTYPE_INT|CTLFLAG_RW, ipport_firstauto, 0, 1478b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1488b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1498b615593SMarko Zec last, CTLTYPE_INT|CTLFLAG_RW, ipport_lastauto, 0, 1508b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1518b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1528b615593SMarko Zec hifirst, CTLTYPE_INT|CTLFLAG_RW, ipport_hifirstauto, 0, 1538b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1548b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1558b615593SMarko Zec hilast, CTLTYPE_INT|CTLFLAG_RW, ipport_hilastauto, 0, 1568b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1578b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1588b615593SMarko Zec reservedhigh, CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedhigh, 0, ""); 1598b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, reservedlow, 1608b615593SMarko Zec CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedlow, 0, ""); 1618b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomized, 1628b615593SMarko Zec CTLFLAG_RW, ipport_randomized, 0, "Enable random port allocation"); 1638b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomcps, 1648b615593SMarko Zec CTLFLAG_RW, ipport_randomcps, 0, "Maximum number of random port " 1656ee79c59SMaxim Konovalov "allocations before switching to a sequental one"); 1668b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomtime, 1678b615593SMarko Zec CTLFLAG_RW, ipport_randomtime, 0, 1688b615593SMarko Zec "Minimum time to keep sequental port " 1696ee79c59SMaxim Konovalov "allocation before switching to a random one"); 1700312fbe9SPoul-Henning Kamp 171c3229e05SDavid Greenman /* 172c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 173c3229e05SDavid Greenman * 174de35559fSRobert Watson * NOTE: It is assumed that most of these functions will be called with 175de35559fSRobert Watson * the pcbinfo lock held, and often, the inpcb lock held, as these utility 176de35559fSRobert Watson * functions often modify hash chains or addresses in pcbs. 177c3229e05SDavid Greenman */ 178c3229e05SDavid Greenman 179c3229e05SDavid Greenman /* 180c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 181d915b280SStephan Uphoff * On success return with the PCB locked. 182c3229e05SDavid Greenman */ 183df8bae1dSRodney W. Grimes int 184d915b280SStephan Uphoff in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo) 185df8bae1dSRodney W. Grimes { 1868b615593SMarko Zec #ifdef INET6 1878b615593SMarko Zec INIT_VNET_INET6(curvnet); 1888b615593SMarko Zec #endif 189136d4f1cSRobert Watson struct inpcb *inp; 19013cf67f3SHajimu UMEMOTO int error; 191a557af22SRobert Watson 19259daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 193a557af22SRobert Watson error = 0; 194d915b280SStephan Uphoff inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT); 195df8bae1dSRodney W. Grimes if (inp == NULL) 196df8bae1dSRodney W. Grimes return (ENOBUFS); 197d915b280SStephan Uphoff bzero(inp, inp_zero_size); 19815bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 199df8bae1dSRodney W. Grimes inp->inp_socket = so; 20086d02c5cSBjoern A. Zeeb inp->inp_cred = crhold(so->so_cred); 2018b07e49aSJulian Elischer inp->inp_inc.inc_fibnum = so->so_fibnum; 202a557af22SRobert Watson #ifdef MAC 20330d239bcSRobert Watson error = mac_inpcb_init(inp, M_NOWAIT); 204a557af22SRobert Watson if (error != 0) 205a557af22SRobert Watson goto out; 206310e7cebSRobert Watson SOCK_LOCK(so); 20730d239bcSRobert Watson mac_inpcb_create(so, inp); 208310e7cebSRobert Watson SOCK_UNLOCK(so); 209a557af22SRobert Watson #endif 2102cb64cb2SGeorge V. Neville-Neil 211b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 21213cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 2130bffde27SRobert Watson if (error != 0) { 2140bffde27SRobert Watson #ifdef MAC 2150bffde27SRobert Watson mac_inpcb_destroy(inp); 2160bffde27SRobert Watson #endif 217a557af22SRobert Watson goto out; 2180bffde27SRobert Watson } 219b2630c29SGeorge V. Neville-Neil #endif /*IPSEC*/ 220e3fd5ffdSRobert Watson #ifdef INET6 221340c35deSJonathan Lemon if (INP_SOCKAF(so) == AF_INET6) { 222340c35deSJonathan Lemon inp->inp_vflag |= INP_IPV6PROTO; 223603724d3SBjoern A. Zeeb if (V_ip6_v6only) 22433841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 225340c35deSJonathan Lemon } 22675daea93SPaul Saab #endif 227712fc218SRobert Watson LIST_INSERT_HEAD(pcbinfo->ipi_listhead, inp, inp_list); 2283d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 229df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 23033841545SHajimu UMEMOTO #ifdef INET6 231603724d3SBjoern A. Zeeb if (V_ip6_auto_flowlabel) 23233841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 23333841545SHajimu UMEMOTO #endif 2348501a69cSRobert Watson INP_WLOCK(inp); 235d915b280SStephan Uphoff inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 236d915b280SStephan Uphoff 237b2630c29SGeorge V. Neville-Neil #if defined(IPSEC) || defined(MAC) 238a557af22SRobert Watson out: 23986d02c5cSBjoern A. Zeeb if (error != 0) { 24086d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 241a557af22SRobert Watson uma_zfree(pcbinfo->ipi_zone, inp); 24286d02c5cSBjoern A. Zeeb } 243a557af22SRobert Watson #endif 244a557af22SRobert Watson return (error); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes 247df8bae1dSRodney W. Grimes int 248136d4f1cSRobert Watson in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 249df8bae1dSRodney W. Grimes { 2504b932371SIan Dowse int anonport, error; 2514b932371SIan Dowse 2521b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 2538501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 25459daba27SSam Leffler 2554b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 2564b932371SIan Dowse return (EINVAL); 2574b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 2584b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 2594b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 260b0330ed9SPawel Jakub Dawidek &inp->inp_lport, cred); 2614b932371SIan Dowse if (error) 2624b932371SIan Dowse return (error); 2634b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2644b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2654b932371SIan Dowse inp->inp_lport = 0; 2664b932371SIan Dowse return (EAGAIN); 2674b932371SIan Dowse } 2684b932371SIan Dowse if (anonport) 2694b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2704b932371SIan Dowse return (0); 2714b932371SIan Dowse } 2724b932371SIan Dowse 2734b932371SIan Dowse /* 2744b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2754b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2764b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2774b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2784b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2794b932371SIan Dowse * 2804b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2814b932371SIan Dowse */ 2824b932371SIan Dowse int 283136d4f1cSRobert Watson in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, 284136d4f1cSRobert Watson u_short *lportp, struct ucred *cred) 2854b932371SIan Dowse { 2868b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 2874b932371SIan Dowse struct socket *so = inp->inp_socket; 28837bd2b30SPeter Wemm unsigned short *lastport; 28915bd2b43SDavid Greenman struct sockaddr_in *sin; 290c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 2914b932371SIan Dowse struct in_addr laddr; 292df8bae1dSRodney W. Grimes u_short lport = 0; 2934cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 29475c13541SPoul-Henning Kamp int error, prison = 0; 2955f311da2SMike Silbersack int dorandom; 296df8bae1dSRodney W. Grimes 2978501a69cSRobert Watson /* 29872bed082SRobert Watson * Because no actual state changes occur here, a global write lock on 29972bed082SRobert Watson * the pcbinfo isn't required. 3008501a69cSRobert Watson */ 3018501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 30259daba27SSam Leffler INP_LOCK_ASSERT(inp); 30359daba27SSam Leffler 304603724d3SBjoern A. Zeeb if (TAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */ 305df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 3064b932371SIan Dowse laddr.s_addr = *laddrp; 3074b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 308df8bae1dSRodney W. Grimes return (EINVAL); 309c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 310421d8aa6SBjoern A. Zeeb wild = INPLOOKUP_WILDCARD; 311df8bae1dSRodney W. Grimes if (nam) { 31257bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 31357bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 314df8bae1dSRodney W. Grimes return (EINVAL); 315df8bae1dSRodney W. Grimes #ifdef notdef 316df8bae1dSRodney W. Grimes /* 317df8bae1dSRodney W. Grimes * We should check the family, but old programs 318df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 319df8bae1dSRodney W. Grimes */ 320df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 321df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 322df8bae1dSRodney W. Grimes #endif 323e4bdf25dSPoul-Henning Kamp if (sin->sin_addr.s_addr != INADDR_ANY) 324b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &sin->sin_addr.s_addr)) 32575c13541SPoul-Henning Kamp return(EINVAL); 3264b932371SIan Dowse if (sin->sin_port != *lportp) { 3274b932371SIan Dowse /* Don't allow the port to change. */ 3284b932371SIan Dowse if (*lportp != 0) 3294b932371SIan Dowse return (EINVAL); 330df8bae1dSRodney W. Grimes lport = sin->sin_port; 3314b932371SIan Dowse } 3324b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 333df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 334df8bae1dSRodney W. Grimes /* 335df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 336df8bae1dSRodney W. Grimes * allow complete duplication of binding if 337df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 338df8bae1dSRodney W. Grimes * and a multicast address is bound on both 339df8bae1dSRodney W. Grimes * new and duplicated sockets. 340df8bae1dSRodney W. Grimes */ 341df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 342df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 343df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 344df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 34583103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 346df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 347df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 348df8bae1dSRodney W. Grimes } 3494b932371SIan Dowse laddr = sin->sin_addr; 350df8bae1dSRodney W. Grimes if (lport) { 351df8bae1dSRodney W. Grimes struct inpcb *t; 352ae0e7143SRobert Watson struct tcptw *tw; 353ae0e7143SRobert Watson 354df8bae1dSRodney W. Grimes /* GROSS */ 355603724d3SBjoern A. Zeeb if (ntohs(lport) <= V_ipport_reservedhigh && 356603724d3SBjoern A. Zeeb ntohs(lport) >= V_ipport_reservedlow && 357acd3428bSRobert Watson priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 35832f9753cSRobert Watson 0)) 3592469dd60SGarrett Wollman return (EACCES); 360b0330ed9SPawel Jakub Dawidek if (jailed(cred)) 36175c13541SPoul-Henning Kamp prison = 1; 362835d4b89SPawel Jakub Dawidek if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 36386d02c5cSBjoern A. Zeeb priv_check_cred(inp->inp_cred, 36432f9753cSRobert Watson PRIV_NETINET_REUSEPORT, 0) != 0) { 365078b7042SBjoern A. Zeeb t = in_pcblookup_local(pcbinfo, sin->sin_addr, 366078b7042SBjoern A. Zeeb lport, prison ? 0 : INPLOOKUP_WILDCARD, 367078b7042SBjoern A. Zeeb cred); 368340c35deSJonathan Lemon /* 369340c35deSJonathan Lemon * XXX 370340c35deSJonathan Lemon * This entire block sorely needs a rewrite. 371340c35deSJonathan Lemon */ 3724cc20ab1SSeigo Tanimura if (t && 3734658dc83SYaroslav Tykhiy ((t->inp_vflag & INP_TIMEWAIT) == 0) && 3744658dc83SYaroslav Tykhiy (so->so_type != SOCK_STREAM || 3754658dc83SYaroslav Tykhiy ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && 3764cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 37752b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 37852b65dbeSBill Fenner (t->inp_socket->so_options & 37952b65dbeSBill Fenner SO_REUSEPORT) == 0) && 38086d02c5cSBjoern A. Zeeb (inp->inp_cred->cr_uid != 38186d02c5cSBjoern A. Zeeb t->inp_cred->cr_uid)) 3824049a042SGuido van Rooij return (EADDRINUSE); 3834049a042SGuido van Rooij } 384b0330ed9SPawel Jakub Dawidek if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr)) 385970680faSPoul-Henning Kamp return (EADDRNOTAVAIL); 386c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 387078b7042SBjoern A. Zeeb lport, prison ? 0 : wild, cred); 388340c35deSJonathan Lemon if (t && (t->inp_vflag & INP_TIMEWAIT)) { 389ae0e7143SRobert Watson /* 390ae0e7143SRobert Watson * XXXRW: If an incpb has had its timewait 391ae0e7143SRobert Watson * state recycled, we treat the address as 392ae0e7143SRobert Watson * being in use (for now). This is better 393ae0e7143SRobert Watson * than a panic, but not desirable. 394ae0e7143SRobert Watson */ 395ae0e7143SRobert Watson tw = intotw(inp); 396ae0e7143SRobert Watson if (tw == NULL || 397ae0e7143SRobert Watson (reuseport & tw->tw_so_options) == 0) 398340c35deSJonathan Lemon return (EADDRINUSE); 399ae0e7143SRobert Watson } else if (t && 4004cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 401e3fd5ffdSRobert Watson #ifdef INET6 40233841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 403cfa1ca9dSYoshinobu Inoue INADDR_ANY || 404cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 405cfa1ca9dSYoshinobu Inoue INADDR_ANY || 406cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 407cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 408e3fd5ffdSRobert Watson #endif 409df8bae1dSRodney W. Grimes return (EADDRINUSE); 410df8bae1dSRodney W. Grimes } 411cfa1ca9dSYoshinobu Inoue } 412df8bae1dSRodney W. Grimes } 4134b932371SIan Dowse if (*lportp != 0) 4144b932371SIan Dowse lport = *lportp; 41533b3ac06SPeter Wemm if (lport == 0) { 4161cf6e4f5SRui Paulo u_short first, last, aux; 417174624e0SMike Silbersack int count; 41833b3ac06SPeter Wemm 4194b932371SIan Dowse if (laddr.s_addr != INADDR_ANY) 420b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &laddr.s_addr)) 42175c13541SPoul-Henning Kamp return (EINVAL); 422321a2846SPoul-Henning Kamp 42333b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 424603724d3SBjoern A. Zeeb first = V_ipport_hifirstauto; /* sysctl */ 425603724d3SBjoern A. Zeeb last = V_ipport_hilastauto; 426712fc218SRobert Watson lastport = &pcbinfo->ipi_lasthi; 42733b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 428acd3428bSRobert Watson error = priv_check_cred(cred, 42932f9753cSRobert Watson PRIV_NETINET_RESERVEDPORT, 0); 430acd3428bSRobert Watson if (error) 431a29f300eSGarrett Wollman return error; 432603724d3SBjoern A. Zeeb first = V_ipport_lowfirstauto; /* 1023 */ 433603724d3SBjoern A. Zeeb last = V_ipport_lowlastauto; /* 600 */ 434712fc218SRobert Watson lastport = &pcbinfo->ipi_lastlow; 43533b3ac06SPeter Wemm } else { 436603724d3SBjoern A. Zeeb first = V_ipport_firstauto; /* sysctl */ 437603724d3SBjoern A. Zeeb last = V_ipport_lastauto; 438712fc218SRobert Watson lastport = &pcbinfo->ipi_lastport; 43933b3ac06SPeter Wemm } 44033b3ac06SPeter Wemm /* 4415f311da2SMike Silbersack * For UDP, use random port allocation as long as the user 4425f311da2SMike Silbersack * allows it. For TCP (and as of yet unknown) connections, 4435f311da2SMike Silbersack * use random port allocation only if the user allows it AND 44429f2a6ecSMaxim Konovalov * ipport_tick() allows it. 4455f311da2SMike Silbersack */ 446603724d3SBjoern A. Zeeb if (V_ipport_randomized && 447603724d3SBjoern A. Zeeb (!V_ipport_stoprandom || pcbinfo == &V_udbinfo)) 4485f311da2SMike Silbersack dorandom = 1; 4495f311da2SMike Silbersack else 4505f311da2SMike Silbersack dorandom = 0; 451e99971bfSMaxim Konovalov /* 452e99971bfSMaxim Konovalov * It makes no sense to do random port allocation if 453e99971bfSMaxim Konovalov * we have the only port available. 454e99971bfSMaxim Konovalov */ 455e99971bfSMaxim Konovalov if (first == last) 456e99971bfSMaxim Konovalov dorandom = 0; 4575f311da2SMike Silbersack /* Make sure to not include UDP packets in the count. */ 458603724d3SBjoern A. Zeeb if (pcbinfo != &V_udbinfo) 459603724d3SBjoern A. Zeeb V_ipport_tcpallocs++; 4605f311da2SMike Silbersack /* 46133b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 46233b3ac06SPeter Wemm * a deadlock here. 46333b3ac06SPeter Wemm */ 46433b3ac06SPeter Wemm if (first > last) { 4651cf6e4f5SRui Paulo aux = first; 4661cf6e4f5SRui Paulo first = last; 4671cf6e4f5SRui Paulo last = aux; 4681cf6e4f5SRui Paulo } 469174624e0SMike Silbersack 4705f311da2SMike Silbersack if (dorandom) 4716b2fc10bSMike Silbersack *lastport = first + 4726b2fc10bSMike Silbersack (arc4random() % (last - first)); 4731cf6e4f5SRui Paulo 47433b3ac06SPeter Wemm count = last - first; 475174624e0SMike Silbersack 47633b3ac06SPeter Wemm do { 4776ac48b74SMike Silbersack if (count-- < 0) /* completely used? */ 478550b1518SWes Peters return (EADDRNOTAVAIL); 47933b3ac06SPeter Wemm ++*lastport; 48033b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 48133b3ac06SPeter Wemm *lastport = first; 48233b3ac06SPeter Wemm lport = htons(*lastport); 483078b7042SBjoern A. Zeeb } while (in_pcblookup_local(pcbinfo, laddr, 484078b7042SBjoern A. Zeeb lport, wild, cred)); 48533b3ac06SPeter Wemm } 486b0330ed9SPawel Jakub Dawidek if (prison_ip(cred, 0, &laddr.s_addr)) 487e4bdf25dSPoul-Henning Kamp return (EINVAL); 4884b932371SIan Dowse *laddrp = laddr.s_addr; 4894b932371SIan Dowse *lportp = lport; 490df8bae1dSRodney W. Grimes return (0); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes 493999f1343SGarrett Wollman /* 4945200e00eSIan Dowse * Connect from a socket to a specified address. 4955200e00eSIan Dowse * Both address and port must be specified in argument sin. 4965200e00eSIan Dowse * If don't have a local address for this socket yet, 4975200e00eSIan Dowse * then pick one. 498999f1343SGarrett Wollman */ 499999f1343SGarrett Wollman int 500136d4f1cSRobert Watson in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 501999f1343SGarrett Wollman { 5025200e00eSIan Dowse u_short lport, fport; 5035200e00eSIan Dowse in_addr_t laddr, faddr; 5045200e00eSIan Dowse int anonport, error; 505df8bae1dSRodney W. Grimes 50627f74fd0SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 5078501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 50827f74fd0SRobert Watson 5095200e00eSIan Dowse lport = inp->inp_lport; 5105200e00eSIan Dowse laddr = inp->inp_laddr.s_addr; 5115200e00eSIan Dowse anonport = (lport == 0); 5125200e00eSIan Dowse error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport, 513b0330ed9SPawel Jakub Dawidek NULL, cred); 5145200e00eSIan Dowse if (error) 5155200e00eSIan Dowse return (error); 5165200e00eSIan Dowse 5175200e00eSIan Dowse /* Do the initial binding of the local address if required. */ 5185200e00eSIan Dowse if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) { 5195200e00eSIan Dowse inp->inp_lport = lport; 5205200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5215200e00eSIan Dowse if (in_pcbinshash(inp) != 0) { 5225200e00eSIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 5235200e00eSIan Dowse inp->inp_lport = 0; 5245200e00eSIan Dowse return (EAGAIN); 5255200e00eSIan Dowse } 5265200e00eSIan Dowse } 5275200e00eSIan Dowse 5285200e00eSIan Dowse /* Commit the remaining changes. */ 5295200e00eSIan Dowse inp->inp_lport = lport; 5305200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5315200e00eSIan Dowse inp->inp_faddr.s_addr = faddr; 5325200e00eSIan Dowse inp->inp_fport = fport; 5335200e00eSIan Dowse in_pcbrehash(inp); 5342cb64cb2SGeorge V. Neville-Neil 5355200e00eSIan Dowse if (anonport) 5365200e00eSIan Dowse inp->inp_flags |= INP_ANONPORT; 5375200e00eSIan Dowse return (0); 5385200e00eSIan Dowse } 5395200e00eSIan Dowse 5405200e00eSIan Dowse /* 5410895aec3SBjoern A. Zeeb * Do proper source address selection on an unbound socket in case 5420895aec3SBjoern A. Zeeb * of connect. Take jails into account as well. 5430895aec3SBjoern A. Zeeb */ 5440895aec3SBjoern A. Zeeb static int 5450895aec3SBjoern A. Zeeb in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, 5460895aec3SBjoern A. Zeeb struct ucred *cred) 5470895aec3SBjoern A. Zeeb { 5480895aec3SBjoern A. Zeeb struct in_ifaddr *ia; 5490895aec3SBjoern A. Zeeb struct ifaddr *ifa; 5500895aec3SBjoern A. Zeeb struct sockaddr *sa; 5510895aec3SBjoern A. Zeeb struct sockaddr_in *sin; 5520895aec3SBjoern A. Zeeb struct route sro; 5530895aec3SBjoern A. Zeeb int error; 5540895aec3SBjoern A. Zeeb 5550895aec3SBjoern A. Zeeb KASSERT(laddr != NULL, ("%s: null laddr", __func__)); 5560895aec3SBjoern A. Zeeb 5570895aec3SBjoern A. Zeeb error = 0; 5580895aec3SBjoern A. Zeeb ia = NULL; 5590895aec3SBjoern A. Zeeb bzero(&sro, sizeof(sro)); 5600895aec3SBjoern A. Zeeb 5610895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)&sro.ro_dst; 5620895aec3SBjoern A. Zeeb sin->sin_family = AF_INET; 5630895aec3SBjoern A. Zeeb sin->sin_len = sizeof(struct sockaddr_in); 5640895aec3SBjoern A. Zeeb sin->sin_addr.s_addr = faddr->s_addr; 5650895aec3SBjoern A. Zeeb 5660895aec3SBjoern A. Zeeb /* 5670895aec3SBjoern A. Zeeb * If route is known our src addr is taken from the i/f, 5680895aec3SBjoern A. Zeeb * else punt. 5690895aec3SBjoern A. Zeeb * 5700895aec3SBjoern A. Zeeb * Find out route to destination. 5710895aec3SBjoern A. Zeeb */ 5720895aec3SBjoern A. Zeeb if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) 5730895aec3SBjoern A. Zeeb in_rtalloc_ign(&sro, RTF_CLONING, inp->inp_inc.inc_fibnum); 5740895aec3SBjoern A. Zeeb 5750895aec3SBjoern A. Zeeb /* 5760895aec3SBjoern A. Zeeb * If we found a route, use the address corresponding to 5770895aec3SBjoern A. Zeeb * the outgoing interface. 5780895aec3SBjoern A. Zeeb * 5790895aec3SBjoern A. Zeeb * Otherwise assume faddr is reachable on a directly connected 5800895aec3SBjoern A. Zeeb * network and try to find a corresponding interface to take 5810895aec3SBjoern A. Zeeb * the source address from. 5820895aec3SBjoern A. Zeeb */ 5830895aec3SBjoern A. Zeeb if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) { 5840895aec3SBjoern A. Zeeb struct ifnet *ifp; 5850895aec3SBjoern A. Zeeb 5860895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin)); 5870895aec3SBjoern A. Zeeb if (ia == NULL) 5880895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin)); 5890895aec3SBjoern A. Zeeb if (ia == NULL) { 5900895aec3SBjoern A. Zeeb error = ENETUNREACH; 5910895aec3SBjoern A. Zeeb goto done; 5920895aec3SBjoern A. Zeeb } 5930895aec3SBjoern A. Zeeb 5940895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 5950895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 5960895aec3SBjoern A. Zeeb goto done; 5970895aec3SBjoern A. Zeeb } 5980895aec3SBjoern A. Zeeb 5990895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 6000895aec3SBjoern A. Zeeb ia = NULL; 6010895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 6020895aec3SBjoern A. Zeeb 6030895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6040895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6050895aec3SBjoern A. Zeeb continue; 6060895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 6070895aec3SBjoern A. Zeeb if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) { 6080895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6090895aec3SBjoern A. Zeeb break; 6100895aec3SBjoern A. Zeeb } 6110895aec3SBjoern A. Zeeb } 6120895aec3SBjoern A. Zeeb if (ia != NULL) { 6130895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6140895aec3SBjoern A. Zeeb goto done; 6150895aec3SBjoern A. Zeeb } 6160895aec3SBjoern A. Zeeb 6170895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 6180895aec3SBjoern A. Zeeb laddr->s_addr = htonl(prison_getip(cred)); 6190895aec3SBjoern A. Zeeb goto done; 6200895aec3SBjoern A. Zeeb } 6210895aec3SBjoern A. Zeeb 6220895aec3SBjoern A. Zeeb /* 6230895aec3SBjoern A. Zeeb * If the outgoing interface on the route found is not 6240895aec3SBjoern A. Zeeb * a loopback interface, use the address from that interface. 6250895aec3SBjoern A. Zeeb * In case of jails do those three steps: 6260895aec3SBjoern A. Zeeb * 1. check if the interface address belongs to the jail. If so use it. 6270895aec3SBjoern A. Zeeb * 2. check if we have any address on the outgoing interface 6280895aec3SBjoern A. Zeeb * belonging to this jail. If so use it. 6290895aec3SBjoern A. Zeeb * 3. as a last resort return the 'default' jail address. 6300895aec3SBjoern A. Zeeb */ 6310895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) { 6320895aec3SBjoern A. Zeeb 6330895aec3SBjoern A. Zeeb /* If not jailed, use the default returned. */ 6340895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6350895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6360895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6370895aec3SBjoern A. Zeeb goto done; 6380895aec3SBjoern A. Zeeb } 6390895aec3SBjoern A. Zeeb 6400895aec3SBjoern A. Zeeb /* Jailed. */ 6410895aec3SBjoern A. Zeeb /* 1. Check if the iface address belongs to the jail. */ 6420895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr; 6430895aec3SBjoern A. Zeeb if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) { 6440895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6450895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6460895aec3SBjoern A. Zeeb goto done; 6470895aec3SBjoern A. Zeeb } 6480895aec3SBjoern A. Zeeb 6490895aec3SBjoern A. Zeeb /* 6500895aec3SBjoern A. Zeeb * 2. Check if we have any address on the outgoing interface 6510895aec3SBjoern A. Zeeb * belonging to this jail. 6520895aec3SBjoern A. Zeeb */ 6530895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &sro.ro_rt->rt_ifp->if_addrhead, ifa_link) { 6540895aec3SBjoern A. Zeeb 6550895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6560895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6570895aec3SBjoern A. Zeeb continue; 6580895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 6590895aec3SBjoern A. Zeeb if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) { 6600895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6610895aec3SBjoern A. Zeeb break; 6620895aec3SBjoern A. Zeeb } 6630895aec3SBjoern A. Zeeb } 6640895aec3SBjoern A. Zeeb if (ia != NULL) { 6650895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6660895aec3SBjoern A. Zeeb goto done; 6670895aec3SBjoern A. Zeeb } 6680895aec3SBjoern A. Zeeb 6690895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 6700895aec3SBjoern A. Zeeb laddr->s_addr = htonl(prison_getip(cred)); 6710895aec3SBjoern A. Zeeb goto done; 6720895aec3SBjoern A. Zeeb } 6730895aec3SBjoern A. Zeeb 6740895aec3SBjoern A. Zeeb /* 6750895aec3SBjoern A. Zeeb * The outgoing interface is marked with 'loopback net', so a route 6760895aec3SBjoern A. Zeeb * to ourselves is here. 6770895aec3SBjoern A. Zeeb * Try to find the interface of the destination address and then 6780895aec3SBjoern A. Zeeb * take the address from there. That interface is not necessarily 6790895aec3SBjoern A. Zeeb * a loopback interface. 6800895aec3SBjoern A. Zeeb * In case of jails, check that it is an address of the jail 6810895aec3SBjoern A. Zeeb * and if we cannot find, fall back to the 'default' jail address. 6820895aec3SBjoern A. Zeeb */ 6830895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { 6840895aec3SBjoern A. Zeeb struct sockaddr_in sain; 6850895aec3SBjoern A. Zeeb 6860895aec3SBjoern A. Zeeb bzero(&sain, sizeof(struct sockaddr_in)); 6870895aec3SBjoern A. Zeeb sain.sin_family = AF_INET; 6880895aec3SBjoern A. Zeeb sain.sin_len = sizeof(struct sockaddr_in); 6890895aec3SBjoern A. Zeeb sain.sin_addr.s_addr = faddr->s_addr; 6900895aec3SBjoern A. Zeeb 6910895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sain))); 6920895aec3SBjoern A. Zeeb if (ia == NULL) 6930895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet(sintosa(&sain))); 6940895aec3SBjoern A. Zeeb 6950895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6960895aec3SBjoern A. Zeeb if (ia == NULL) { 6970895aec3SBjoern A. Zeeb error = ENETUNREACH; 6980895aec3SBjoern A. Zeeb goto done; 6990895aec3SBjoern A. Zeeb } 7000895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 7010895aec3SBjoern A. Zeeb goto done; 7020895aec3SBjoern A. Zeeb } 7030895aec3SBjoern A. Zeeb 7040895aec3SBjoern A. Zeeb /* Jailed. */ 7050895aec3SBjoern A. Zeeb if (ia != NULL) { 7060895aec3SBjoern A. Zeeb struct ifnet *ifp; 7070895aec3SBjoern A. Zeeb 7080895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 7090895aec3SBjoern A. Zeeb ia = NULL; 7100895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 7110895aec3SBjoern A. Zeeb 7120895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 7130895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 7140895aec3SBjoern A. Zeeb continue; 7150895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 7160895aec3SBjoern A. Zeeb if (htonl(prison_getip(cred)) == 7170895aec3SBjoern A. Zeeb sin->sin_addr.s_addr) { 7180895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 7190895aec3SBjoern A. Zeeb break; 7200895aec3SBjoern A. Zeeb } 7210895aec3SBjoern A. Zeeb } 7220895aec3SBjoern A. Zeeb if (ia != NULL) { 7230895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 7240895aec3SBjoern A. Zeeb goto done; 7250895aec3SBjoern A. Zeeb } 7260895aec3SBjoern A. Zeeb } 7270895aec3SBjoern A. Zeeb 7280895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 7290895aec3SBjoern A. Zeeb laddr->s_addr = htonl(prison_getip(cred)); 7300895aec3SBjoern A. Zeeb goto done; 7310895aec3SBjoern A. Zeeb } 7320895aec3SBjoern A. Zeeb 7330895aec3SBjoern A. Zeeb done: 7340895aec3SBjoern A. Zeeb if (sro.ro_rt != NULL) 7350895aec3SBjoern A. Zeeb RTFREE(sro.ro_rt); 7360895aec3SBjoern A. Zeeb return (error); 7370895aec3SBjoern A. Zeeb } 7380895aec3SBjoern A. Zeeb 7390895aec3SBjoern A. Zeeb /* 7405200e00eSIan Dowse * Set up for a connect from a socket to the specified address. 7415200e00eSIan Dowse * On entry, *laddrp and *lportp should contain the current local 7425200e00eSIan Dowse * address and port for the PCB; these are updated to the values 7435200e00eSIan Dowse * that should be placed in inp_laddr and inp_lport to complete 7445200e00eSIan Dowse * the connect. 7455200e00eSIan Dowse * 7465200e00eSIan Dowse * On success, *faddrp and *fportp will be set to the remote address 7475200e00eSIan Dowse * and port. These are not updated in the error case. 7485200e00eSIan Dowse * 7495200e00eSIan Dowse * If the operation fails because the connection already exists, 7505200e00eSIan Dowse * *oinpp will be set to the PCB of that connection so that the 7515200e00eSIan Dowse * caller can decide to override it. In all other cases, *oinpp 7525200e00eSIan Dowse * is set to NULL. 7535200e00eSIan Dowse */ 7545200e00eSIan Dowse int 755136d4f1cSRobert Watson in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, 756136d4f1cSRobert Watson in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp, 757136d4f1cSRobert Watson struct inpcb **oinpp, struct ucred *cred) 7585200e00eSIan Dowse { 7598b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 7605200e00eSIan Dowse struct sockaddr_in *sin = (struct sockaddr_in *)nam; 7615200e00eSIan Dowse struct in_ifaddr *ia; 7625200e00eSIan Dowse struct inpcb *oinp; 7635200e00eSIan Dowse struct in_addr laddr, faddr; 7645200e00eSIan Dowse u_short lport, fport; 7655200e00eSIan Dowse int error; 7665200e00eSIan Dowse 7678501a69cSRobert Watson /* 7688501a69cSRobert Watson * Because a global state change doesn't actually occur here, a read 7698501a69cSRobert Watson * lock is sufficient. 7708501a69cSRobert Watson */ 7718501a69cSRobert Watson INP_INFO_LOCK_ASSERT(inp->inp_pcbinfo); 77227f74fd0SRobert Watson INP_LOCK_ASSERT(inp); 77327f74fd0SRobert Watson 7745200e00eSIan Dowse if (oinpp != NULL) 7755200e00eSIan Dowse *oinpp = NULL; 77657bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 777df8bae1dSRodney W. Grimes return (EINVAL); 778df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 779df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 780df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 781df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 7825200e00eSIan Dowse laddr.s_addr = *laddrp; 7835200e00eSIan Dowse lport = *lportp; 7845200e00eSIan Dowse faddr = sin->sin_addr; 7855200e00eSIan Dowse fport = sin->sin_port; 7860895aec3SBjoern A. Zeeb 787603724d3SBjoern A. Zeeb if (!TAILQ_EMPTY(&V_in_ifaddrhead)) { 788df8bae1dSRodney W. Grimes /* 789df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 790df8bae1dSRodney W. Grimes * use the primary local address. 791df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 792df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 793df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 794df8bae1dSRodney W. Grimes */ 7955200e00eSIan Dowse if (faddr.s_addr == INADDR_ANY) 796603724d3SBjoern A. Zeeb faddr = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; 7975200e00eSIan Dowse else if (faddr.s_addr == (u_long)INADDR_BROADCAST && 798603724d3SBjoern A. Zeeb (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & 7995200e00eSIan Dowse IFF_BROADCAST)) 8005200e00eSIan Dowse faddr = satosin(&TAILQ_FIRST( 801603724d3SBjoern A. Zeeb &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; 802df8bae1dSRodney W. Grimes } 8035200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY) { 8040895aec3SBjoern A. Zeeb error = in_pcbladdr(inp, &faddr, &laddr, cred); 8050895aec3SBjoern A. Zeeb if (error) 8060895aec3SBjoern A. Zeeb return (error); 807df8bae1dSRodney W. Grimes 808df8bae1dSRodney W. Grimes /* 809df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 810df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 811df8bae1dSRodney W. Grimes * address of that interface as our source address. 812df8bae1dSRodney W. Grimes */ 8135200e00eSIan Dowse if (IN_MULTICAST(ntohl(faddr.s_addr)) && 814df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 815df8bae1dSRodney W. Grimes struct ip_moptions *imo; 816df8bae1dSRodney W. Grimes struct ifnet *ifp; 817df8bae1dSRodney W. Grimes 818df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 819df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 820df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 821603724d3SBjoern A. Zeeb TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) 822df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 823df8bae1dSRodney W. Grimes break; 8248699ea08SBjoern A. Zeeb if (ia == NULL) 825df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 8265200e00eSIan Dowse laddr = ia->ia_addr.sin_addr; 827999f1343SGarrett Wollman } 8280895aec3SBjoern A. Zeeb } 8290895aec3SBjoern A. Zeeb } 830999f1343SGarrett Wollman 8315200e00eSIan Dowse oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport, 8325200e00eSIan Dowse 0, NULL); 8335200e00eSIan Dowse if (oinp != NULL) { 8345200e00eSIan Dowse if (oinpp != NULL) 8355200e00eSIan Dowse *oinpp = oinp; 836df8bae1dSRodney W. Grimes return (EADDRINUSE); 837c3229e05SDavid Greenman } 8385200e00eSIan Dowse if (lport == 0) { 839b0330ed9SPawel Jakub Dawidek error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, 840b0330ed9SPawel Jakub Dawidek cred); 8415a903f8dSPierre Beyssac if (error) 8425a903f8dSPierre Beyssac return (error); 8435a903f8dSPierre Beyssac } 8445200e00eSIan Dowse *laddrp = laddr.s_addr; 8455200e00eSIan Dowse *lportp = lport; 8465200e00eSIan Dowse *faddrp = faddr.s_addr; 8475200e00eSIan Dowse *fportp = fport; 848df8bae1dSRodney W. Grimes return (0); 849df8bae1dSRodney W. Grimes } 850df8bae1dSRodney W. Grimes 85126f9a767SRodney W. Grimes void 852136d4f1cSRobert Watson in_pcbdisconnect(struct inpcb *inp) 853df8bae1dSRodney W. Grimes { 8546b348152SRobert Watson 855fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 8568501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 857df8bae1dSRodney W. Grimes 858df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 859df8bae1dSRodney W. Grimes inp->inp_fport = 0; 86015bd2b43SDavid Greenman in_pcbrehash(inp); 861df8bae1dSRodney W. Grimes } 862df8bae1dSRodney W. Grimes 8634c7c478dSRobert Watson /* 864c0a211c5SRobert Watson * Historically, in_pcbdetach() included the functionality now found in 865c0a211c5SRobert Watson * in_pcbfree() and in_pcbdrop(). They are now broken out to reflect the 866c0a211c5SRobert Watson * more complex life cycle of TCP. 867c0a211c5SRobert Watson * 868c0a211c5SRobert Watson * in_pcbdetach() is responsibe for disconnecting the socket from an inpcb. 869c0a211c5SRobert Watson * For most protocols, this will be invoked immediately prior to calling 870c0a211c5SRobert Watson * in_pcbfree(). However, for TCP the inpcb may significantly outlive the 871c0a211c5SRobert Watson * socket, in which case in_pcbfree() may be deferred. 8724c7c478dSRobert Watson */ 87326f9a767SRodney W. Grimes void 874136d4f1cSRobert Watson in_pcbdetach(struct inpcb *inp) 875df8bae1dSRodney W. Grimes { 8764c7c478dSRobert Watson 8774c7c478dSRobert Watson KASSERT(inp->inp_socket != NULL, ("in_pcbdetach: inp_socket == NULL")); 878c0a211c5SRobert Watson 8794c7c478dSRobert Watson inp->inp_socket->so_pcb = NULL; 8804c7c478dSRobert Watson inp->inp_socket = NULL; 8814c7c478dSRobert Watson } 8824c7c478dSRobert Watson 883c0a211c5SRobert Watson /* 884c0a211c5SRobert Watson * in_pcbfree() is responsible for freeing an already-detached inpcb, as well 885c0a211c5SRobert Watson * as removing it from any global inpcb lists it might be on. 886c0a211c5SRobert Watson */ 8874c7c478dSRobert Watson void 8884c7c478dSRobert Watson in_pcbfree(struct inpcb *inp) 8894c7c478dSRobert Watson { 8903d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 891df8bae1dSRodney W. Grimes 8924c7c478dSRobert Watson KASSERT(inp->inp_socket == NULL, ("in_pcbfree: inp_socket != NULL")); 8938501a69cSRobert Watson 894fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(ipi); 8958501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 89659daba27SSam Leffler 897b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 898cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 899b2630c29SGeorge V. Neville-Neil #endif /*IPSEC*/ 9003d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 901c3229e05SDavid Greenman in_pcbremlists(inp); 902df8bae1dSRodney W. Grimes if (inp->inp_options) 903df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 90471498f30SBruce M Simpson if (inp->inp_moptions != NULL) 90571498f30SBruce M Simpson inp_freemoptions(inp->inp_moptions); 906cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 90786d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 908d915b280SStephan Uphoff 909a557af22SRobert Watson #ifdef MAC 91030d239bcSRobert Watson mac_inpcb_destroy(inp); 911a557af22SRobert Watson #endif 9128501a69cSRobert Watson INP_WUNLOCK(inp); 91369c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 914df8bae1dSRodney W. Grimes } 915df8bae1dSRodney W. Grimes 91610702a28SRobert Watson /* 917c0a211c5SRobert Watson * in_pcbdrop() removes an inpcb from hashed lists, releasing its address and 918c0a211c5SRobert Watson * port reservation, and preventing it from being returned by inpcb lookups. 919c0a211c5SRobert Watson * 920c0a211c5SRobert Watson * It is used by TCP to mark an inpcb as unused and avoid future packet 921c0a211c5SRobert Watson * delivery or event notification when a socket remains open but TCP has 922c0a211c5SRobert Watson * closed. This might occur as a result of a shutdown()-initiated TCP close 923c0a211c5SRobert Watson * or a RST on the wire, and allows the port binding to be reused while still 924c0a211c5SRobert Watson * maintaining the invariant that so_pcb always points to a valid inpcb until 925c0a211c5SRobert Watson * in_pcbdetach(). 926c0a211c5SRobert Watson * 927c0a211c5SRobert Watson * XXXRW: An inp_lport of 0 is used to indicate that the inpcb is not on hash 928c0a211c5SRobert Watson * lists, but can lead to confusing netstat output, as open sockets with 929c0a211c5SRobert Watson * closed TCP connections will no longer appear to have their bound port 930c0a211c5SRobert Watson * number. An explicit flag would be better, as it would allow us to leave 931c0a211c5SRobert Watson * the port number intact after the connection is dropped. 932c0a211c5SRobert Watson * 933c0a211c5SRobert Watson * XXXRW: Possibly in_pcbdrop() should also prevent future notifications by 934c0a211c5SRobert Watson * in_pcbnotifyall() and in_pcbpurgeif0()? 93510702a28SRobert Watson */ 93610702a28SRobert Watson void 93710702a28SRobert Watson in_pcbdrop(struct inpcb *inp) 93810702a28SRobert Watson { 93910702a28SRobert Watson 9407c5a8ab2SMarcel Moolenaar INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 9418501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 94210702a28SRobert Watson 94310702a28SRobert Watson inp->inp_vflag |= INP_DROPPED; 94410702a28SRobert Watson if (inp->inp_lport) { 94510702a28SRobert Watson struct inpcbport *phd = inp->inp_phd; 94610702a28SRobert Watson 94710702a28SRobert Watson LIST_REMOVE(inp, inp_hash); 94810702a28SRobert Watson LIST_REMOVE(inp, inp_portlist); 94910702a28SRobert Watson if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 95010702a28SRobert Watson LIST_REMOVE(phd, phd_hash); 95110702a28SRobert Watson free(phd, M_PCB); 95210702a28SRobert Watson } 95310702a28SRobert Watson inp->inp_lport = 0; 95410702a28SRobert Watson } 95510702a28SRobert Watson } 95610702a28SRobert Watson 95754d642bbSRobert Watson /* 95854d642bbSRobert Watson * Common routines to return the socket addresses associated with inpcbs. 95954d642bbSRobert Watson */ 96026ef6ac4SDon Lewis struct sockaddr * 961136d4f1cSRobert Watson in_sockaddr(in_port_t port, struct in_addr *addr_p) 96226ef6ac4SDon Lewis { 96326ef6ac4SDon Lewis struct sockaddr_in *sin; 96426ef6ac4SDon Lewis 96526ef6ac4SDon Lewis MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, 966a163d034SWarner Losh M_WAITOK | M_ZERO); 96726ef6ac4SDon Lewis sin->sin_family = AF_INET; 96826ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 96926ef6ac4SDon Lewis sin->sin_addr = *addr_p; 97026ef6ac4SDon Lewis sin->sin_port = port; 97126ef6ac4SDon Lewis 97226ef6ac4SDon Lewis return (struct sockaddr *)sin; 97326ef6ac4SDon Lewis } 97426ef6ac4SDon Lewis 975117bcae7SGarrett Wollman int 97654d642bbSRobert Watson in_getsockaddr(struct socket *so, struct sockaddr **nam) 977df8bae1dSRodney W. Grimes { 978136d4f1cSRobert Watson struct inpcb *inp; 97926ef6ac4SDon Lewis struct in_addr addr; 98026ef6ac4SDon Lewis in_port_t port; 98142fa505bSDavid Greenman 982fdc984f7STor Egge inp = sotoinpcb(so); 98354d642bbSRobert Watson KASSERT(inp != NULL, ("in_getsockaddr: inp == NULL")); 9846466b28aSRobert Watson 985a69042a5SRobert Watson INP_RLOCK(inp); 98626ef6ac4SDon Lewis port = inp->inp_lport; 98726ef6ac4SDon Lewis addr = inp->inp_laddr; 988a69042a5SRobert Watson INP_RUNLOCK(inp); 98942fa505bSDavid Greenman 99026ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 991117bcae7SGarrett Wollman return 0; 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes 994117bcae7SGarrett Wollman int 99554d642bbSRobert Watson in_getpeeraddr(struct socket *so, struct sockaddr **nam) 996df8bae1dSRodney W. Grimes { 997136d4f1cSRobert Watson struct inpcb *inp; 99826ef6ac4SDon Lewis struct in_addr addr; 99926ef6ac4SDon Lewis in_port_t port; 100042fa505bSDavid Greenman 1001fdc984f7STor Egge inp = sotoinpcb(so); 100254d642bbSRobert Watson KASSERT(inp != NULL, ("in_getpeeraddr: inp == NULL")); 10036466b28aSRobert Watson 1004a69042a5SRobert Watson INP_RLOCK(inp); 100526ef6ac4SDon Lewis port = inp->inp_fport; 100626ef6ac4SDon Lewis addr = inp->inp_faddr; 1007a69042a5SRobert Watson INP_RUNLOCK(inp); 100842fa505bSDavid Greenman 100926ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 1010117bcae7SGarrett Wollman return 0; 1011df8bae1dSRodney W. Grimes } 1012df8bae1dSRodney W. Grimes 101326f9a767SRodney W. Grimes void 1014136d4f1cSRobert Watson in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr faddr, int errno, 1015136d4f1cSRobert Watson struct inpcb *(*notify)(struct inpcb *, int)) 1016d1c54148SJesper Skriver { 1017f457d580SRobert Watson struct inpcb *inp, *inp_temp; 1018d1c54148SJesper Skriver 10193dc7ebf9SJeffrey Hsu INP_INFO_WLOCK(pcbinfo); 1020f457d580SRobert Watson LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { 10218501a69cSRobert Watson INP_WLOCK(inp); 1022d1c54148SJesper Skriver #ifdef INET6 1023f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 10248501a69cSRobert Watson INP_WUNLOCK(inp); 1025d1c54148SJesper Skriver continue; 1026f76fcf6dSJeffrey Hsu } 1027d1c54148SJesper Skriver #endif 1028d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 1029f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 10308501a69cSRobert Watson INP_WUNLOCK(inp); 1031d1c54148SJesper Skriver continue; 1032d1c54148SJesper Skriver } 10333dc7ebf9SJeffrey Hsu if ((*notify)(inp, errno)) 10348501a69cSRobert Watson INP_WUNLOCK(inp); 1035f76fcf6dSJeffrey Hsu } 10363dc7ebf9SJeffrey Hsu INP_INFO_WUNLOCK(pcbinfo); 1037d1c54148SJesper Skriver } 1038d1c54148SJesper Skriver 1039e43cc4aeSHajimu UMEMOTO void 1040136d4f1cSRobert Watson in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) 1041e43cc4aeSHajimu UMEMOTO { 1042e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 1043e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 1044e43cc4aeSHajimu UMEMOTO int i, gap; 1045e43cc4aeSHajimu UMEMOTO 1046f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 1047712fc218SRobert Watson LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { 10488501a69cSRobert Watson INP_WLOCK(inp); 1049e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 1050e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 1051e43cc4aeSHajimu UMEMOTO imo != NULL) { 1052e43cc4aeSHajimu UMEMOTO /* 1053e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 1054e43cc4aeSHajimu UMEMOTO * detached. 1055e43cc4aeSHajimu UMEMOTO */ 1056e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 1057e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 1058e43cc4aeSHajimu UMEMOTO 1059e43cc4aeSHajimu UMEMOTO /* 1060e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 1061e43cc4aeSHajimu UMEMOTO * through the interface being detached. 1062e43cc4aeSHajimu UMEMOTO */ 1063e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 1064e43cc4aeSHajimu UMEMOTO i++) { 1065e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 1066e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 1067e43cc4aeSHajimu UMEMOTO gap++; 1068e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 1069e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 1070e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 1071e43cc4aeSHajimu UMEMOTO } 1072e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 1073e43cc4aeSHajimu UMEMOTO } 10748501a69cSRobert Watson INP_WUNLOCK(inp); 1075e43cc4aeSHajimu UMEMOTO } 10763cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 1077e43cc4aeSHajimu UMEMOTO } 1078e43cc4aeSHajimu UMEMOTO 1079df8bae1dSRodney W. Grimes /* 1080c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 1081c3229e05SDavid Greenman */ 1082d5e8a67eSHajimu UMEMOTO #define INP_LOOKUP_MAPPED_PCB_COST 3 1083df8bae1dSRodney W. Grimes struct inpcb * 1084136d4f1cSRobert Watson in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr, 1085078b7042SBjoern A. Zeeb u_short lport, int wild_okay, struct ucred *cred) 1086df8bae1dSRodney W. Grimes { 1087136d4f1cSRobert Watson struct inpcb *inp; 1088d5e8a67eSHajimu UMEMOTO #ifdef INET6 1089d5e8a67eSHajimu UMEMOTO int matchwild = 3 + INP_LOOKUP_MAPPED_PCB_COST; 1090d5e8a67eSHajimu UMEMOTO #else 1091d5e8a67eSHajimu UMEMOTO int matchwild = 3; 1092d5e8a67eSHajimu UMEMOTO #endif 1093d5e8a67eSHajimu UMEMOTO int wildcard; 10947bc4aca7SDavid Greenman 10958501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 10961b73ca0bSSam Leffler 1097c3229e05SDavid Greenman if (!wild_okay) { 1098c3229e05SDavid Greenman struct inpcbhead *head; 1099c3229e05SDavid Greenman /* 1100c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 1101c3229e05SDavid Greenman * matches the local address and port we're looking for. 1102c3229e05SDavid Greenman */ 1103712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1104712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1105fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1106cfa1ca9dSYoshinobu Inoue #ifdef INET6 1107369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1108cfa1ca9dSYoshinobu Inoue continue; 1109cfa1ca9dSYoshinobu Inoue #endif 1110c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1111c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1112c3229e05SDavid Greenman inp->inp_lport == lport) { 1113c3229e05SDavid Greenman /* 1114c3229e05SDavid Greenman * Found. 1115c3229e05SDavid Greenman */ 1116c3229e05SDavid Greenman return (inp); 1117df8bae1dSRodney W. Grimes } 1118c3229e05SDavid Greenman } 1119c3229e05SDavid Greenman /* 1120c3229e05SDavid Greenman * Not found. 1121c3229e05SDavid Greenman */ 1122c3229e05SDavid Greenman return (NULL); 1123c3229e05SDavid Greenman } else { 1124c3229e05SDavid Greenman struct inpcbporthead *porthash; 1125c3229e05SDavid Greenman struct inpcbport *phd; 1126c3229e05SDavid Greenman struct inpcb *match = NULL; 1127c3229e05SDavid Greenman /* 1128c3229e05SDavid Greenman * Best fit PCB lookup. 1129c3229e05SDavid Greenman * 1130c3229e05SDavid Greenman * First see if this local port is in use by looking on the 1131c3229e05SDavid Greenman * port hash list. 1132c3229e05SDavid Greenman */ 1133712fc218SRobert Watson porthash = &pcbinfo->ipi_porthashbase[INP_PCBPORTHASH(lport, 1134712fc218SRobert Watson pcbinfo->ipi_porthashmask)]; 1135fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 1136c3229e05SDavid Greenman if (phd->phd_port == lport) 1137c3229e05SDavid Greenman break; 1138c3229e05SDavid Greenman } 1139c3229e05SDavid Greenman if (phd != NULL) { 1140c3229e05SDavid Greenman /* 1141c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 1142c3229e05SDavid Greenman * fit. 1143c3229e05SDavid Greenman */ 114437d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 1145c3229e05SDavid Greenman wildcard = 0; 1146cfa1ca9dSYoshinobu Inoue #ifdef INET6 1147369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1148cfa1ca9dSYoshinobu Inoue continue; 1149d5e8a67eSHajimu UMEMOTO /* 1150d5e8a67eSHajimu UMEMOTO * We never select the PCB that has 1151d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag and is bound to :: if 1152d5e8a67eSHajimu UMEMOTO * we have another PCB which is bound 1153d5e8a67eSHajimu UMEMOTO * to 0.0.0.0. If a PCB has the 1154d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag, then we set its cost 1155d5e8a67eSHajimu UMEMOTO * higher than IPv4 only PCBs. 1156d5e8a67eSHajimu UMEMOTO * 1157d5e8a67eSHajimu UMEMOTO * Note that the case only happens 1158d5e8a67eSHajimu UMEMOTO * when a socket is bound to ::, under 1159d5e8a67eSHajimu UMEMOTO * the condition that the use of the 1160d5e8a67eSHajimu UMEMOTO * mapped address is allowed. 1161d5e8a67eSHajimu UMEMOTO */ 1162d5e8a67eSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV6) != 0) 1163d5e8a67eSHajimu UMEMOTO wildcard += INP_LOOKUP_MAPPED_PCB_COST; 1164cfa1ca9dSYoshinobu Inoue #endif 1165c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 1166c3229e05SDavid Greenman wildcard++; 116715bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 116815bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 116915bd2b43SDavid Greenman wildcard++; 117015bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 117115bd2b43SDavid Greenman continue; 117215bd2b43SDavid Greenman } else { 117315bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 117415bd2b43SDavid Greenman wildcard++; 117515bd2b43SDavid Greenman } 1176df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 1177df8bae1dSRodney W. Grimes match = inp; 1178df8bae1dSRodney W. Grimes matchwild = wildcard; 11793dbdc25cSDavid Greenman if (matchwild == 0) { 1180df8bae1dSRodney W. Grimes break; 1181df8bae1dSRodney W. Grimes } 1182df8bae1dSRodney W. Grimes } 11833dbdc25cSDavid Greenman } 1184c3229e05SDavid Greenman } 1185df8bae1dSRodney W. Grimes return (match); 1186df8bae1dSRodney W. Grimes } 1187c3229e05SDavid Greenman } 1188d5e8a67eSHajimu UMEMOTO #undef INP_LOOKUP_MAPPED_PCB_COST 118915bd2b43SDavid Greenman 119015bd2b43SDavid Greenman /* 119115bd2b43SDavid Greenman * Lookup PCB in hash list. 119215bd2b43SDavid Greenman */ 119315bd2b43SDavid Greenman struct inpcb * 1194136d4f1cSRobert Watson in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr, 1195136d4f1cSRobert Watson u_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard, 1196136d4f1cSRobert Watson struct ifnet *ifp) 119715bd2b43SDavid Greenman { 119815bd2b43SDavid Greenman struct inpcbhead *head; 1199136d4f1cSRobert Watson struct inpcb *inp; 120015bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 120115bd2b43SDavid Greenman 12028501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 1203602cc7f1SRobert Watson 120415bd2b43SDavid Greenman /* 120515bd2b43SDavid Greenman * First look for an exact match. 120615bd2b43SDavid Greenman */ 1207712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, 1208712fc218SRobert Watson pcbinfo->ipi_hashmask)]; 1209fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1210cfa1ca9dSYoshinobu Inoue #ifdef INET6 1211369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1212cfa1ca9dSYoshinobu Inoue continue; 1213cfa1ca9dSYoshinobu Inoue #endif 12146d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 1215ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1216ca98b82cSDavid Greenman inp->inp_fport == fport && 1217e3fd5ffdSRobert Watson inp->inp_lport == lport) 1218c3229e05SDavid Greenman return (inp); 1219c3229e05SDavid Greenman } 1220e3fd5ffdSRobert Watson 1221e3fd5ffdSRobert Watson /* 1222e3fd5ffdSRobert Watson * Then look for a wildcard match, if requested. 1223e3fd5ffdSRobert Watson */ 12246d6a026bSDavid Greenman if (wildcard) { 12256d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 1226e3fd5ffdSRobert Watson #ifdef INET6 1227cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 1228e3fd5ffdSRobert Watson #endif 12296d6a026bSDavid Greenman 1230712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1231712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1232fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1233cfa1ca9dSYoshinobu Inoue #ifdef INET6 1234369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1235cfa1ca9dSYoshinobu Inoue continue; 1236cfa1ca9dSYoshinobu Inoue #endif 12376d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1238c3229e05SDavid Greenman inp->inp_lport == lport) { 1239cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 1240cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 1241cfa1ca9dSYoshinobu Inoue continue; 12426d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 1243c3229e05SDavid Greenman return (inp); 1244cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 1245e3fd5ffdSRobert Watson #ifdef INET6 1246cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 1247cfa1ca9dSYoshinobu Inoue AF_INET6)) 1248cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 1249cfa1ca9dSYoshinobu Inoue else 1250e3fd5ffdSRobert Watson #endif 12516d6a026bSDavid Greenman local_wild = inp; 12526d6a026bSDavid Greenman } 12536d6a026bSDavid Greenman } 1254cfa1ca9dSYoshinobu Inoue } 1255e3fd5ffdSRobert Watson #ifdef INET6 1256cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 1257cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 1258e3fd5ffdSRobert Watson #endif 1259c3229e05SDavid Greenman return (local_wild); 12606d6a026bSDavid Greenman } 12616d6a026bSDavid Greenman return (NULL); 126215bd2b43SDavid Greenman } 126315bd2b43SDavid Greenman 12647bc4aca7SDavid Greenman /* 1265c3229e05SDavid Greenman * Insert PCB onto various hash lists. 12667bc4aca7SDavid Greenman */ 1267c3229e05SDavid Greenman int 1268136d4f1cSRobert Watson in_pcbinshash(struct inpcb *inp) 126915bd2b43SDavid Greenman { 1270c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1271c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1272c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1273c3229e05SDavid Greenman struct inpcbport *phd; 1274cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 127515bd2b43SDavid Greenman 127659daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 12778501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1278602cc7f1SRobert Watson 1279cfa1ca9dSYoshinobu Inoue #ifdef INET6 1280cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1281cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1282cfa1ca9dSYoshinobu Inoue else 1283cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1284cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1285cfa1ca9dSYoshinobu Inoue 1286712fc218SRobert Watson pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1287712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 128815bd2b43SDavid Greenman 1289712fc218SRobert Watson pcbporthash = &pcbinfo->ipi_porthashbase[ 1290712fc218SRobert Watson INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; 1291c3229e05SDavid Greenman 1292c3229e05SDavid Greenman /* 1293c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1294c3229e05SDavid Greenman */ 1295fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1296c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1297c3229e05SDavid Greenman break; 1298c3229e05SDavid Greenman } 1299c3229e05SDavid Greenman /* 1300c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1301c3229e05SDavid Greenman */ 1302c3229e05SDavid Greenman if (phd == NULL) { 1303c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1304c3229e05SDavid Greenman if (phd == NULL) { 1305c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1306c3229e05SDavid Greenman } 1307c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1308c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1309c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1310c3229e05SDavid Greenman } 1311c3229e05SDavid Greenman inp->inp_phd = phd; 1312c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1313c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1314c3229e05SDavid Greenman return (0); 131515bd2b43SDavid Greenman } 131615bd2b43SDavid Greenman 1317c3229e05SDavid Greenman /* 1318c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1319c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1320c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1321c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1322c3229e05SDavid Greenman */ 132315bd2b43SDavid Greenman void 1324136d4f1cSRobert Watson in_pcbrehash(struct inpcb *inp) 132515bd2b43SDavid Greenman { 132659daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 132715bd2b43SDavid Greenman struct inpcbhead *head; 1328cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 132915bd2b43SDavid Greenman 133059daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 13318501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1332602cc7f1SRobert Watson 1333cfa1ca9dSYoshinobu Inoue #ifdef INET6 1334cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1335cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1336cfa1ca9dSYoshinobu Inoue else 1337cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1338cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1339cfa1ca9dSYoshinobu Inoue 1340712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1341712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 134215bd2b43SDavid Greenman 1343c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 134415bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1345c3229e05SDavid Greenman } 1346c3229e05SDavid Greenman 1347c3229e05SDavid Greenman /* 1348c3229e05SDavid Greenman * Remove PCB from various lists. 1349c3229e05SDavid Greenman */ 135076429de4SYoshinobu Inoue void 1351136d4f1cSRobert Watson in_pcbremlists(struct inpcb *inp) 1352c3229e05SDavid Greenman { 135359daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 135459daba27SSam Leffler 135559daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 13568501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 135759daba27SSam Leffler 135859daba27SSam Leffler inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 1359c3229e05SDavid Greenman if (inp->inp_lport) { 1360c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1361c3229e05SDavid Greenman 1362c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1363c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1364fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1365c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1366c3229e05SDavid Greenman free(phd, M_PCB); 1367c3229e05SDavid Greenman } 1368c3229e05SDavid Greenman } 1369c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 137059daba27SSam Leffler pcbinfo->ipi_count--; 137115bd2b43SDavid Greenman } 137275c13541SPoul-Henning Kamp 1373a557af22SRobert Watson /* 1374a557af22SRobert Watson * A set label operation has occurred at the socket layer, propagate the 1375a557af22SRobert Watson * label change into the in_pcb for the socket. 1376a557af22SRobert Watson */ 1377a557af22SRobert Watson void 1378136d4f1cSRobert Watson in_pcbsosetlabel(struct socket *so) 1379a557af22SRobert Watson { 1380a557af22SRobert Watson #ifdef MAC 1381a557af22SRobert Watson struct inpcb *inp; 1382a557af22SRobert Watson 13834c7c478dSRobert Watson inp = sotoinpcb(so); 13844c7c478dSRobert Watson KASSERT(inp != NULL, ("in_pcbsosetlabel: so->so_pcb == NULL")); 1385602cc7f1SRobert Watson 13868501a69cSRobert Watson INP_WLOCK(inp); 1387310e7cebSRobert Watson SOCK_LOCK(so); 1388a557af22SRobert Watson mac_inpcb_sosetlabel(so, inp); 1389310e7cebSRobert Watson SOCK_UNLOCK(so); 13908501a69cSRobert Watson INP_WUNLOCK(inp); 1391a557af22SRobert Watson #endif 1392a557af22SRobert Watson } 13935f311da2SMike Silbersack 13945f311da2SMike Silbersack /* 1395ad3a630fSRobert Watson * ipport_tick runs once per second, determining if random port allocation 1396ad3a630fSRobert Watson * should be continued. If more than ipport_randomcps ports have been 1397ad3a630fSRobert Watson * allocated in the last second, then we return to sequential port 1398ad3a630fSRobert Watson * allocation. We return to random allocation only once we drop below 1399ad3a630fSRobert Watson * ipport_randomcps for at least ipport_randomtime seconds. 14005f311da2SMike Silbersack */ 14015f311da2SMike Silbersack void 1402136d4f1cSRobert Watson ipport_tick(void *xtp) 14035f311da2SMike Silbersack { 14048b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 1405ad3a630fSRobert Watson 14068b615593SMarko Zec VNET_LIST_RLOCK(); 14078b615593SMarko Zec VNET_FOREACH(vnet_iter) { 14088b615593SMarko Zec CURVNET_SET(vnet_iter); /* XXX appease INVARIANTS here */ 14098b615593SMarko Zec INIT_VNET_INET(vnet_iter); 14108b615593SMarko Zec if (V_ipport_tcpallocs <= 14118b615593SMarko Zec V_ipport_tcplastcount + V_ipport_randomcps) { 1412603724d3SBjoern A. Zeeb if (V_ipport_stoprandom > 0) 1413603724d3SBjoern A. Zeeb V_ipport_stoprandom--; 1414ad3a630fSRobert Watson } else 1415603724d3SBjoern A. Zeeb V_ipport_stoprandom = V_ipport_randomtime; 1416603724d3SBjoern A. Zeeb V_ipport_tcplastcount = V_ipport_tcpallocs; 14178b615593SMarko Zec CURVNET_RESTORE(); 14188b615593SMarko Zec } 14198b615593SMarko Zec VNET_LIST_RUNLOCK(); 14205f311da2SMike Silbersack callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL); 14215f311da2SMike Silbersack } 1422497057eeSRobert Watson 14233d585327SKip Macy void 14243d585327SKip Macy inp_wlock(struct inpcb *inp) 14253d585327SKip Macy { 14263d585327SKip Macy 14278501a69cSRobert Watson INP_WLOCK(inp); 14283d585327SKip Macy } 14293d585327SKip Macy 14303d585327SKip Macy void 14313d585327SKip Macy inp_wunlock(struct inpcb *inp) 14323d585327SKip Macy { 14333d585327SKip Macy 14348501a69cSRobert Watson INP_WUNLOCK(inp); 14353d585327SKip Macy } 14363d585327SKip Macy 14373d585327SKip Macy void 14383d585327SKip Macy inp_rlock(struct inpcb *inp) 14393d585327SKip Macy { 14403d585327SKip Macy 1441a69042a5SRobert Watson INP_RLOCK(inp); 14423d585327SKip Macy } 14433d585327SKip Macy 14443d585327SKip Macy void 14453d585327SKip Macy inp_runlock(struct inpcb *inp) 14463d585327SKip Macy { 14473d585327SKip Macy 1448a69042a5SRobert Watson INP_RUNLOCK(inp); 14493d585327SKip Macy } 14503d585327SKip Macy 14513d585327SKip Macy #ifdef INVARIANTS 14523d585327SKip Macy void 1453e79dd20dSKip Macy inp_lock_assert(struct inpcb *inp) 14543d585327SKip Macy { 14553d585327SKip Macy 14568501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 14573d585327SKip Macy } 14583d585327SKip Macy 14593d585327SKip Macy void 1460e79dd20dSKip Macy inp_unlock_assert(struct inpcb *inp) 14613d585327SKip Macy { 14623d585327SKip Macy 14633d585327SKip Macy INP_UNLOCK_ASSERT(inp); 14643d585327SKip Macy } 14653d585327SKip Macy #endif 14663d585327SKip Macy 14679378e437SKip Macy void 14689378e437SKip Macy inp_apply_all(void (*func)(struct inpcb *, void *), void *arg) 14699378e437SKip Macy { 14708b615593SMarko Zec INIT_VNET_INET(curvnet); 14719378e437SKip Macy struct inpcb *inp; 14729378e437SKip Macy 1473603724d3SBjoern A. Zeeb INP_INFO_RLOCK(&V_tcbinfo); 14749378e437SKip Macy LIST_FOREACH(inp, tcbinfo.ipi_listhead, inp_list) { 14759378e437SKip Macy INP_WLOCK(inp); 14769378e437SKip Macy func(inp, arg); 14779378e437SKip Macy INP_WUNLOCK(inp); 14789378e437SKip Macy } 1479603724d3SBjoern A. Zeeb INP_INFO_RUNLOCK(&V_tcbinfo); 14809378e437SKip Macy } 14819378e437SKip Macy 14829378e437SKip Macy struct socket * 14839378e437SKip Macy inp_inpcbtosocket(struct inpcb *inp) 14849378e437SKip Macy { 14859378e437SKip Macy 14869378e437SKip Macy INP_WLOCK_ASSERT(inp); 14879378e437SKip Macy return (inp->inp_socket); 14889378e437SKip Macy } 14899378e437SKip Macy 14909378e437SKip Macy struct tcpcb * 14919378e437SKip Macy inp_inpcbtotcpcb(struct inpcb *inp) 14929378e437SKip Macy { 14939378e437SKip Macy 14949378e437SKip Macy INP_WLOCK_ASSERT(inp); 14959378e437SKip Macy return ((struct tcpcb *)inp->inp_ppcb); 14969378e437SKip Macy } 14979378e437SKip Macy 14989378e437SKip Macy int 14999378e437SKip Macy inp_ip_tos_get(const struct inpcb *inp) 15009378e437SKip Macy { 15019378e437SKip Macy 15029378e437SKip Macy return (inp->inp_ip_tos); 15039378e437SKip Macy } 15049378e437SKip Macy 15059378e437SKip Macy void 15069378e437SKip Macy inp_ip_tos_set(struct inpcb *inp, int val) 15079378e437SKip Macy { 15089378e437SKip Macy 15099378e437SKip Macy inp->inp_ip_tos = val; 15109378e437SKip Macy } 15119378e437SKip Macy 15129378e437SKip Macy void 1513df9cf830STai-hwa Liang inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, 15149d29c635SKip Macy uint32_t *faddr, uint16_t *fp) 15159378e437SKip Macy { 15169378e437SKip Macy 15179d29c635SKip Macy INP_LOCK_ASSERT(inp); 1518df9cf830STai-hwa Liang *laddr = inp->inp_laddr.s_addr; 1519df9cf830STai-hwa Liang *faddr = inp->inp_faddr.s_addr; 15209378e437SKip Macy *lp = inp->inp_lport; 15219378e437SKip Macy *fp = inp->inp_fport; 15229378e437SKip Macy } 15239378e437SKip Macy 1524dd0e6c38SKip Macy struct inpcb * 1525dd0e6c38SKip Macy so_sotoinpcb(struct socket *so) 1526dd0e6c38SKip Macy { 1527dd0e6c38SKip Macy 1528dd0e6c38SKip Macy return (sotoinpcb(so)); 1529dd0e6c38SKip Macy } 1530dd0e6c38SKip Macy 1531dd0e6c38SKip Macy struct tcpcb * 1532dd0e6c38SKip Macy so_sototcpcb(struct socket *so) 1533dd0e6c38SKip Macy { 1534dd0e6c38SKip Macy 1535dd0e6c38SKip Macy return (sototcpcb(so)); 1536dd0e6c38SKip Macy } 1537dd0e6c38SKip Macy 1538497057eeSRobert Watson #ifdef DDB 1539497057eeSRobert Watson static void 1540497057eeSRobert Watson db_print_indent(int indent) 1541497057eeSRobert Watson { 1542497057eeSRobert Watson int i; 1543497057eeSRobert Watson 1544497057eeSRobert Watson for (i = 0; i < indent; i++) 1545497057eeSRobert Watson db_printf(" "); 1546497057eeSRobert Watson } 1547497057eeSRobert Watson 1548497057eeSRobert Watson static void 1549497057eeSRobert Watson db_print_inconninfo(struct in_conninfo *inc, const char *name, int indent) 1550497057eeSRobert Watson { 1551497057eeSRobert Watson char faddr_str[48], laddr_str[48]; 1552497057eeSRobert Watson 1553497057eeSRobert Watson db_print_indent(indent); 1554497057eeSRobert Watson db_printf("%s at %p\n", name, inc); 1555497057eeSRobert Watson 1556497057eeSRobert Watson indent += 2; 1557497057eeSRobert Watson 155803dc38a4SRobert Watson #ifdef INET6 1559497057eeSRobert Watson if (inc->inc_flags == 1) { 1560497057eeSRobert Watson /* IPv6. */ 1561497057eeSRobert Watson ip6_sprintf(laddr_str, &inc->inc6_laddr); 1562497057eeSRobert Watson ip6_sprintf(faddr_str, &inc->inc6_faddr); 1563497057eeSRobert Watson } else { 156403dc38a4SRobert Watson #endif 1565497057eeSRobert Watson /* IPv4. */ 1566497057eeSRobert Watson inet_ntoa_r(inc->inc_laddr, laddr_str); 1567497057eeSRobert Watson inet_ntoa_r(inc->inc_faddr, faddr_str); 156803dc38a4SRobert Watson #ifdef INET6 1569497057eeSRobert Watson } 157003dc38a4SRobert Watson #endif 1571497057eeSRobert Watson db_print_indent(indent); 1572497057eeSRobert Watson db_printf("inc_laddr %s inc_lport %u\n", laddr_str, 1573497057eeSRobert Watson ntohs(inc->inc_lport)); 1574497057eeSRobert Watson db_print_indent(indent); 1575497057eeSRobert Watson db_printf("inc_faddr %s inc_fport %u\n", faddr_str, 1576497057eeSRobert Watson ntohs(inc->inc_fport)); 1577497057eeSRobert Watson } 1578497057eeSRobert Watson 1579497057eeSRobert Watson static void 1580497057eeSRobert Watson db_print_inpflags(int inp_flags) 1581497057eeSRobert Watson { 1582497057eeSRobert Watson int comma; 1583497057eeSRobert Watson 1584497057eeSRobert Watson comma = 0; 1585497057eeSRobert Watson if (inp_flags & INP_RECVOPTS) { 1586497057eeSRobert Watson db_printf("%sINP_RECVOPTS", comma ? ", " : ""); 1587497057eeSRobert Watson comma = 1; 1588497057eeSRobert Watson } 1589497057eeSRobert Watson if (inp_flags & INP_RECVRETOPTS) { 1590497057eeSRobert Watson db_printf("%sINP_RECVRETOPTS", comma ? ", " : ""); 1591497057eeSRobert Watson comma = 1; 1592497057eeSRobert Watson } 1593497057eeSRobert Watson if (inp_flags & INP_RECVDSTADDR) { 1594497057eeSRobert Watson db_printf("%sINP_RECVDSTADDR", comma ? ", " : ""); 1595497057eeSRobert Watson comma = 1; 1596497057eeSRobert Watson } 1597497057eeSRobert Watson if (inp_flags & INP_HDRINCL) { 1598497057eeSRobert Watson db_printf("%sINP_HDRINCL", comma ? ", " : ""); 1599497057eeSRobert Watson comma = 1; 1600497057eeSRobert Watson } 1601497057eeSRobert Watson if (inp_flags & INP_HIGHPORT) { 1602497057eeSRobert Watson db_printf("%sINP_HIGHPORT", comma ? ", " : ""); 1603497057eeSRobert Watson comma = 1; 1604497057eeSRobert Watson } 1605497057eeSRobert Watson if (inp_flags & INP_LOWPORT) { 1606497057eeSRobert Watson db_printf("%sINP_LOWPORT", comma ? ", " : ""); 1607497057eeSRobert Watson comma = 1; 1608497057eeSRobert Watson } 1609497057eeSRobert Watson if (inp_flags & INP_ANONPORT) { 1610497057eeSRobert Watson db_printf("%sINP_ANONPORT", comma ? ", " : ""); 1611497057eeSRobert Watson comma = 1; 1612497057eeSRobert Watson } 1613497057eeSRobert Watson if (inp_flags & INP_RECVIF) { 1614497057eeSRobert Watson db_printf("%sINP_RECVIF", comma ? ", " : ""); 1615497057eeSRobert Watson comma = 1; 1616497057eeSRobert Watson } 1617497057eeSRobert Watson if (inp_flags & INP_MTUDISC) { 1618497057eeSRobert Watson db_printf("%sINP_MTUDISC", comma ? ", " : ""); 1619497057eeSRobert Watson comma = 1; 1620497057eeSRobert Watson } 1621497057eeSRobert Watson if (inp_flags & INP_FAITH) { 1622497057eeSRobert Watson db_printf("%sINP_FAITH", comma ? ", " : ""); 1623497057eeSRobert Watson comma = 1; 1624497057eeSRobert Watson } 1625497057eeSRobert Watson if (inp_flags & INP_RECVTTL) { 1626497057eeSRobert Watson db_printf("%sINP_RECVTTL", comma ? ", " : ""); 1627497057eeSRobert Watson comma = 1; 1628497057eeSRobert Watson } 1629497057eeSRobert Watson if (inp_flags & INP_DONTFRAG) { 1630497057eeSRobert Watson db_printf("%sINP_DONTFRAG", comma ? ", " : ""); 1631497057eeSRobert Watson comma = 1; 1632497057eeSRobert Watson } 1633497057eeSRobert Watson if (inp_flags & IN6P_IPV6_V6ONLY) { 1634497057eeSRobert Watson db_printf("%sIN6P_IPV6_V6ONLY", comma ? ", " : ""); 1635497057eeSRobert Watson comma = 1; 1636497057eeSRobert Watson } 1637497057eeSRobert Watson if (inp_flags & IN6P_PKTINFO) { 1638497057eeSRobert Watson db_printf("%sIN6P_PKTINFO", comma ? ", " : ""); 1639497057eeSRobert Watson comma = 1; 1640497057eeSRobert Watson } 1641497057eeSRobert Watson if (inp_flags & IN6P_HOPLIMIT) { 1642497057eeSRobert Watson db_printf("%sIN6P_HOPLIMIT", comma ? ", " : ""); 1643497057eeSRobert Watson comma = 1; 1644497057eeSRobert Watson } 1645497057eeSRobert Watson if (inp_flags & IN6P_HOPOPTS) { 1646497057eeSRobert Watson db_printf("%sIN6P_HOPOPTS", comma ? ", " : ""); 1647497057eeSRobert Watson comma = 1; 1648497057eeSRobert Watson } 1649497057eeSRobert Watson if (inp_flags & IN6P_DSTOPTS) { 1650497057eeSRobert Watson db_printf("%sIN6P_DSTOPTS", comma ? ", " : ""); 1651497057eeSRobert Watson comma = 1; 1652497057eeSRobert Watson } 1653497057eeSRobert Watson if (inp_flags & IN6P_RTHDR) { 1654497057eeSRobert Watson db_printf("%sIN6P_RTHDR", comma ? ", " : ""); 1655497057eeSRobert Watson comma = 1; 1656497057eeSRobert Watson } 1657497057eeSRobert Watson if (inp_flags & IN6P_RTHDRDSTOPTS) { 1658497057eeSRobert Watson db_printf("%sIN6P_RTHDRDSTOPTS", comma ? ", " : ""); 1659497057eeSRobert Watson comma = 1; 1660497057eeSRobert Watson } 1661497057eeSRobert Watson if (inp_flags & IN6P_TCLASS) { 1662497057eeSRobert Watson db_printf("%sIN6P_TCLASS", comma ? ", " : ""); 1663497057eeSRobert Watson comma = 1; 1664497057eeSRobert Watson } 1665497057eeSRobert Watson if (inp_flags & IN6P_AUTOFLOWLABEL) { 1666497057eeSRobert Watson db_printf("%sIN6P_AUTOFLOWLABEL", comma ? ", " : ""); 1667497057eeSRobert Watson comma = 1; 1668497057eeSRobert Watson } 1669497057eeSRobert Watson if (inp_flags & IN6P_RFC2292) { 1670497057eeSRobert Watson db_printf("%sIN6P_RFC2292", comma ? ", " : ""); 1671497057eeSRobert Watson comma = 1; 1672497057eeSRobert Watson } 1673497057eeSRobert Watson if (inp_flags & IN6P_MTU) { 1674497057eeSRobert Watson db_printf("IN6P_MTU%s", comma ? ", " : ""); 1675497057eeSRobert Watson comma = 1; 1676497057eeSRobert Watson } 1677497057eeSRobert Watson } 1678497057eeSRobert Watson 1679497057eeSRobert Watson static void 1680497057eeSRobert Watson db_print_inpvflag(u_char inp_vflag) 1681497057eeSRobert Watson { 1682497057eeSRobert Watson int comma; 1683497057eeSRobert Watson 1684497057eeSRobert Watson comma = 0; 1685497057eeSRobert Watson if (inp_vflag & INP_IPV4) { 1686497057eeSRobert Watson db_printf("%sINP_IPV4", comma ? ", " : ""); 1687497057eeSRobert Watson comma = 1; 1688497057eeSRobert Watson } 1689497057eeSRobert Watson if (inp_vflag & INP_IPV6) { 1690497057eeSRobert Watson db_printf("%sINP_IPV6", comma ? ", " : ""); 1691497057eeSRobert Watson comma = 1; 1692497057eeSRobert Watson } 1693497057eeSRobert Watson if (inp_vflag & INP_IPV6PROTO) { 1694497057eeSRobert Watson db_printf("%sINP_IPV6PROTO", comma ? ", " : ""); 1695497057eeSRobert Watson comma = 1; 1696497057eeSRobert Watson } 1697497057eeSRobert Watson if (inp_vflag & INP_TIMEWAIT) { 1698497057eeSRobert Watson db_printf("%sINP_TIMEWAIT", comma ? ", " : ""); 1699497057eeSRobert Watson comma = 1; 1700497057eeSRobert Watson } 1701497057eeSRobert Watson if (inp_vflag & INP_ONESBCAST) { 1702497057eeSRobert Watson db_printf("%sINP_ONESBCAST", comma ? ", " : ""); 1703497057eeSRobert Watson comma = 1; 1704497057eeSRobert Watson } 1705497057eeSRobert Watson if (inp_vflag & INP_DROPPED) { 1706497057eeSRobert Watson db_printf("%sINP_DROPPED", comma ? ", " : ""); 1707497057eeSRobert Watson comma = 1; 1708497057eeSRobert Watson } 1709497057eeSRobert Watson if (inp_vflag & INP_SOCKREF) { 1710497057eeSRobert Watson db_printf("%sINP_SOCKREF", comma ? ", " : ""); 1711497057eeSRobert Watson comma = 1; 1712497057eeSRobert Watson } 1713497057eeSRobert Watson } 1714497057eeSRobert Watson 1715497057eeSRobert Watson void 1716497057eeSRobert Watson db_print_inpcb(struct inpcb *inp, const char *name, int indent) 1717497057eeSRobert Watson { 1718497057eeSRobert Watson 1719497057eeSRobert Watson db_print_indent(indent); 1720497057eeSRobert Watson db_printf("%s at %p\n", name, inp); 1721497057eeSRobert Watson 1722497057eeSRobert Watson indent += 2; 1723497057eeSRobert Watson 1724497057eeSRobert Watson db_print_indent(indent); 1725497057eeSRobert Watson db_printf("inp_flow: 0x%x\n", inp->inp_flow); 1726497057eeSRobert Watson 1727497057eeSRobert Watson db_print_inconninfo(&inp->inp_inc, "inp_conninfo", indent); 1728497057eeSRobert Watson 1729497057eeSRobert Watson db_print_indent(indent); 1730497057eeSRobert Watson db_printf("inp_ppcb: %p inp_pcbinfo: %p inp_socket: %p\n", 1731497057eeSRobert Watson inp->inp_ppcb, inp->inp_pcbinfo, inp->inp_socket); 1732497057eeSRobert Watson 1733497057eeSRobert Watson db_print_indent(indent); 1734497057eeSRobert Watson db_printf("inp_label: %p inp_flags: 0x%x (", 1735497057eeSRobert Watson inp->inp_label, inp->inp_flags); 1736497057eeSRobert Watson db_print_inpflags(inp->inp_flags); 1737497057eeSRobert Watson db_printf(")\n"); 1738497057eeSRobert Watson 1739497057eeSRobert Watson db_print_indent(indent); 1740497057eeSRobert Watson db_printf("inp_sp: %p inp_vflag: 0x%x (", inp->inp_sp, 1741497057eeSRobert Watson inp->inp_vflag); 1742497057eeSRobert Watson db_print_inpvflag(inp->inp_vflag); 1743497057eeSRobert Watson db_printf(")\n"); 1744497057eeSRobert Watson 1745497057eeSRobert Watson db_print_indent(indent); 1746497057eeSRobert Watson db_printf("inp_ip_ttl: %d inp_ip_p: %d inp_ip_minttl: %d\n", 1747497057eeSRobert Watson inp->inp_ip_ttl, inp->inp_ip_p, inp->inp_ip_minttl); 1748497057eeSRobert Watson 1749497057eeSRobert Watson db_print_indent(indent); 1750497057eeSRobert Watson #ifdef INET6 1751497057eeSRobert Watson if (inp->inp_vflag & INP_IPV6) { 1752497057eeSRobert Watson db_printf("in6p_options: %p in6p_outputopts: %p " 1753497057eeSRobert Watson "in6p_moptions: %p\n", inp->in6p_options, 1754497057eeSRobert Watson inp->in6p_outputopts, inp->in6p_moptions); 1755497057eeSRobert Watson db_printf("in6p_icmp6filt: %p in6p_cksum %d " 1756497057eeSRobert Watson "in6p_hops %u\n", inp->in6p_icmp6filt, inp->in6p_cksum, 1757497057eeSRobert Watson inp->in6p_hops); 1758497057eeSRobert Watson } else 1759497057eeSRobert Watson #endif 1760497057eeSRobert Watson { 1761497057eeSRobert Watson db_printf("inp_ip_tos: %d inp_ip_options: %p " 1762497057eeSRobert Watson "inp_ip_moptions: %p\n", inp->inp_ip_tos, 1763497057eeSRobert Watson inp->inp_options, inp->inp_moptions); 1764497057eeSRobert Watson } 1765497057eeSRobert Watson 1766497057eeSRobert Watson db_print_indent(indent); 1767497057eeSRobert Watson db_printf("inp_phd: %p inp_gencnt: %ju\n", inp->inp_phd, 1768497057eeSRobert Watson (uintmax_t)inp->inp_gencnt); 1769497057eeSRobert Watson } 1770497057eeSRobert Watson 1771497057eeSRobert Watson DB_SHOW_COMMAND(inpcb, db_show_inpcb) 1772497057eeSRobert Watson { 1773497057eeSRobert Watson struct inpcb *inp; 1774497057eeSRobert Watson 1775497057eeSRobert Watson if (!have_addr) { 1776497057eeSRobert Watson db_printf("usage: show inpcb <addr>\n"); 1777497057eeSRobert Watson return; 1778497057eeSRobert Watson } 1779497057eeSRobert Watson inp = (struct inpcb *)addr; 1780497057eeSRobert Watson 1781497057eeSRobert Watson db_print_inpcb(inp, "inpcb", 0); 1782497057eeSRobert Watson } 1783497057eeSRobert Watson #endif 1784