1c398230bSWarner Losh /*- 22469dd60SGarrett Wollman * Copyright (c) 1982, 1986, 1991, 1993, 1995 3497057eeSRobert Watson * The Regents of the University of California. 4111d57a6SRobert Watson * Copyright (c) 2007-2009 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" 38be9347e3SAdrian Chadd #include "opt_inet.h" 396a800098SYoshinobu Inoue #include "opt_ipsec.h" 40cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 41a557af22SRobert Watson #include "opt_mac.h" 42cfa1ca9dSYoshinobu Inoue 43df8bae1dSRodney W. Grimes #include <sys/param.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 45df8bae1dSRodney W. Grimes #include <sys/malloc.h> 46df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 47cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 48df8bae1dSRodney W. Grimes #include <sys/protosw.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 50df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 51acd3428bSRobert Watson #include <sys/priv.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 5375c13541SPoul-Henning Kamp #include <sys/jail.h> 54101f9fc8SPeter Wemm #include <sys/kernel.h> 55101f9fc8SPeter Wemm #include <sys/sysctl.h> 56603724d3SBjoern A. Zeeb #include <sys/vimage.h> 578781d8e9SBruce Evans 58497057eeSRobert Watson #ifdef DDB 59497057eeSRobert Watson #include <ddb/ddb.h> 60497057eeSRobert Watson #endif 61497057eeSRobert Watson 6269c2d429SJeff Roberson #include <vm/uma.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <net/if.h> 65cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 66df8bae1dSRodney W. Grimes #include <net/route.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #include <netinet/in.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 70df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 71df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 72340c35deSJonathan Lemon #include <netinet/tcp_var.h> 735f311da2SMike Silbersack #include <netinet/udp.h> 745f311da2SMike Silbersack #include <netinet/udp_var.h> 754b79449eSBjoern A. Zeeb #include <netinet/vinet.h> 76cfa1ca9dSYoshinobu Inoue #ifdef INET6 77cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 78cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 794b79449eSBjoern A. Zeeb #include <netinet6/vinet6.h> 80cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 81cfa1ca9dSYoshinobu Inoue 82df8bae1dSRodney W. Grimes 83b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 84b9234fafSSam Leffler #include <netipsec/ipsec.h> 85b9234fafSSam Leffler #include <netipsec/key.h> 86b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 87b9234fafSSam Leffler 88aed55708SRobert Watson #include <security/mac/mac_framework.h> 89aed55708SRobert Watson 9044e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 91101f9fc8SPeter Wemm /* 92101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 93101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 94101f9fc8SPeter Wemm */ 9544e33a07SMarko Zec int ipport_lowfirstauto; 9644e33a07SMarko Zec int ipport_lowlastauto; 9744e33a07SMarko Zec int ipport_firstauto; 9844e33a07SMarko Zec int ipport_lastauto; 9944e33a07SMarko Zec int ipport_hifirstauto; 10044e33a07SMarko Zec int ipport_hilastauto; 101101f9fc8SPeter Wemm 102b0d22693SCrist J. Clark /* 103b0d22693SCrist J. Clark * Reserved ports accessible only to root. There are significant 104b0d22693SCrist J. Clark * security considerations that must be accounted for when changing these, 105b0d22693SCrist J. Clark * but the security benefits can be great. Please be careful. 106b0d22693SCrist J. Clark */ 10744e33a07SMarko Zec int ipport_reservedhigh; 10844e33a07SMarko Zec int ipport_reservedlow; 109b0d22693SCrist J. Clark 1105f311da2SMike Silbersack /* Variables dealing with random ephemeral port allocation. */ 11144e33a07SMarko Zec int ipport_randomized; 11244e33a07SMarko Zec int ipport_randomcps; 11344e33a07SMarko Zec int ipport_randomtime; 11444e33a07SMarko Zec int ipport_stoprandom; 1155f311da2SMike Silbersack int ipport_tcpallocs; 1165f311da2SMike Silbersack int ipport_tcplastcount; 11744e33a07SMarko Zec #endif 1186ac48b74SMike Silbersack 119bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 120bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 121bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 122bbd42ad0SPeter Wemm 1236d888973SRobert Watson static void in_pcbremlists(struct inpcb *inp); 1246d888973SRobert Watson 125bbd42ad0SPeter Wemm static int 12682d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 127bbd42ad0SPeter Wemm { 12897021c24SMarko Zec INIT_VNET_INET(curvnet); 12930a4ab08SBruce Evans int error; 13030a4ab08SBruce Evans 131f6dfe47aSMarko Zec SYSCTL_RESOLVE_V_ARG1(); 132f6dfe47aSMarko Zec 133f6dfe47aSMarko Zec error = sysctl_handle_int(oidp, arg1, arg2, req); 13430a4ab08SBruce Evans if (error == 0) { 135603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 136603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 137603724d3SBjoern A. Zeeb RANGECHK(V_ipport_firstauto, IPPORT_RESERVED, IPPORT_MAX); 138603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lastauto, IPPORT_RESERVED, IPPORT_MAX); 139603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hifirstauto, IPPORT_RESERVED, IPPORT_MAX); 140603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hilastauto, IPPORT_RESERVED, IPPORT_MAX); 141bbd42ad0SPeter Wemm } 14230a4ab08SBruce Evans return (error); 143bbd42ad0SPeter Wemm } 144bbd42ad0SPeter Wemm 145bbd42ad0SPeter Wemm #undef RANGECHK 146bbd42ad0SPeter Wemm 14733b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 14833b3ac06SPeter Wemm 1498b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1508b615593SMarko Zec lowfirst, CTLTYPE_INT|CTLFLAG_RW, ipport_lowfirstauto, 0, 1518b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1528b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1538b615593SMarko Zec lowlast, CTLTYPE_INT|CTLFLAG_RW, ipport_lowlastauto, 0, 1548b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1558b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1568b615593SMarko Zec first, CTLTYPE_INT|CTLFLAG_RW, ipport_firstauto, 0, 1578b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1588b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1598b615593SMarko Zec last, CTLTYPE_INT|CTLFLAG_RW, ipport_lastauto, 0, 1608b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1618b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1628b615593SMarko Zec hifirst, CTLTYPE_INT|CTLFLAG_RW, ipport_hifirstauto, 0, 1638b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1648b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1658b615593SMarko Zec hilast, CTLTYPE_INT|CTLFLAG_RW, ipport_hilastauto, 0, 1668b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1678b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1688b615593SMarko Zec reservedhigh, CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedhigh, 0, ""); 1698b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, reservedlow, 1708b615593SMarko Zec CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedlow, 0, ""); 1718b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomized, 1728b615593SMarko Zec CTLFLAG_RW, ipport_randomized, 0, "Enable random port allocation"); 1738b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomcps, 1748b615593SMarko Zec CTLFLAG_RW, ipport_randomcps, 0, "Maximum number of random port " 1756ee79c59SMaxim Konovalov "allocations before switching to a sequental one"); 1768b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomtime, 1778b615593SMarko Zec CTLFLAG_RW, ipport_randomtime, 0, 1788b615593SMarko Zec "Minimum time to keep sequental port " 1796ee79c59SMaxim Konovalov "allocation before switching to a random one"); 1800312fbe9SPoul-Henning Kamp 181c3229e05SDavid Greenman /* 182c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 183c3229e05SDavid Greenman * 184de35559fSRobert Watson * NOTE: It is assumed that most of these functions will be called with 185de35559fSRobert Watson * the pcbinfo lock held, and often, the inpcb lock held, as these utility 186de35559fSRobert Watson * functions often modify hash chains or addresses in pcbs. 187c3229e05SDavid Greenman */ 188c3229e05SDavid Greenman 189c3229e05SDavid Greenman /* 190c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 191d915b280SStephan Uphoff * On success return with the PCB locked. 192c3229e05SDavid Greenman */ 193df8bae1dSRodney W. Grimes int 194d915b280SStephan Uphoff in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo) 195df8bae1dSRodney W. Grimes { 1968b615593SMarko Zec #ifdef INET6 1978b615593SMarko Zec INIT_VNET_INET6(curvnet); 1988b615593SMarko Zec #endif 199136d4f1cSRobert Watson struct inpcb *inp; 20013cf67f3SHajimu UMEMOTO int error; 201a557af22SRobert Watson 20259daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 203a557af22SRobert Watson error = 0; 204d915b280SStephan Uphoff inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT); 205df8bae1dSRodney W. Grimes if (inp == NULL) 206df8bae1dSRodney W. Grimes return (ENOBUFS); 207d915b280SStephan Uphoff bzero(inp, inp_zero_size); 20815bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 209df8bae1dSRodney W. Grimes inp->inp_socket = so; 21086d02c5cSBjoern A. Zeeb inp->inp_cred = crhold(so->so_cred); 2118b07e49aSJulian Elischer inp->inp_inc.inc_fibnum = so->so_fibnum; 212a557af22SRobert Watson #ifdef MAC 21330d239bcSRobert Watson error = mac_inpcb_init(inp, M_NOWAIT); 214a557af22SRobert Watson if (error != 0) 215a557af22SRobert Watson goto out; 216310e7cebSRobert Watson SOCK_LOCK(so); 21730d239bcSRobert Watson mac_inpcb_create(so, inp); 218310e7cebSRobert Watson SOCK_UNLOCK(so); 219a557af22SRobert Watson #endif 220b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 22113cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 2220bffde27SRobert Watson if (error != 0) { 2230bffde27SRobert Watson #ifdef MAC 2240bffde27SRobert Watson mac_inpcb_destroy(inp); 2250bffde27SRobert Watson #endif 226a557af22SRobert Watson goto out; 2270bffde27SRobert Watson } 228b2630c29SGeorge V. Neville-Neil #endif /*IPSEC*/ 229e3fd5ffdSRobert Watson #ifdef INET6 230340c35deSJonathan Lemon if (INP_SOCKAF(so) == AF_INET6) { 231340c35deSJonathan Lemon inp->inp_vflag |= INP_IPV6PROTO; 232603724d3SBjoern A. Zeeb if (V_ip6_v6only) 23333841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 234340c35deSJonathan Lemon } 23575daea93SPaul Saab #endif 236712fc218SRobert Watson LIST_INSERT_HEAD(pcbinfo->ipi_listhead, inp, inp_list); 2373d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 238df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 23933841545SHajimu UMEMOTO #ifdef INET6 240603724d3SBjoern A. Zeeb if (V_ip6_auto_flowlabel) 24133841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 24233841545SHajimu UMEMOTO #endif 2438501a69cSRobert Watson INP_WLOCK(inp); 244d915b280SStephan Uphoff inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 24528696211SRobert Watson inp->inp_refcount = 1; /* Reference from the inpcbinfo */ 246b2630c29SGeorge V. Neville-Neil #if defined(IPSEC) || defined(MAC) 247a557af22SRobert Watson out: 24886d02c5cSBjoern A. Zeeb if (error != 0) { 24986d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 250a557af22SRobert Watson uma_zfree(pcbinfo->ipi_zone, inp); 25186d02c5cSBjoern A. Zeeb } 252a557af22SRobert Watson #endif 253a557af22SRobert Watson return (error); 254df8bae1dSRodney W. Grimes } 255df8bae1dSRodney W. Grimes 256df8bae1dSRodney W. Grimes int 257136d4f1cSRobert Watson in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 258df8bae1dSRodney W. Grimes { 2594b932371SIan Dowse int anonport, error; 2604b932371SIan Dowse 2611b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 2628501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 26359daba27SSam Leffler 2644b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 2654b932371SIan Dowse return (EINVAL); 2664b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 2674b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 2684b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 269b0330ed9SPawel Jakub Dawidek &inp->inp_lport, cred); 2704b932371SIan Dowse if (error) 2714b932371SIan Dowse return (error); 2724b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2734b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2744b932371SIan Dowse inp->inp_lport = 0; 2754b932371SIan Dowse return (EAGAIN); 2764b932371SIan Dowse } 2774b932371SIan Dowse if (anonport) 2784b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2794b932371SIan Dowse return (0); 2804b932371SIan Dowse } 2814b932371SIan Dowse 2824b932371SIan Dowse /* 2834b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2844b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2854b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2864b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2874b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2884b932371SIan Dowse * 2894b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2904b932371SIan Dowse */ 2914b932371SIan Dowse int 292136d4f1cSRobert Watson in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, 293136d4f1cSRobert Watson u_short *lportp, struct ucred *cred) 2944b932371SIan Dowse { 2958b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 2964b932371SIan Dowse struct socket *so = inp->inp_socket; 29737bd2b30SPeter Wemm unsigned short *lastport; 29815bd2b43SDavid Greenman struct sockaddr_in *sin; 299c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 3004b932371SIan Dowse struct in_addr laddr; 301df8bae1dSRodney W. Grimes u_short lport = 0; 3024cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 303413628a7SBjoern A. Zeeb int error; 3045f311da2SMike Silbersack int dorandom; 305df8bae1dSRodney W. Grimes 3068501a69cSRobert Watson /* 30772bed082SRobert Watson * Because no actual state changes occur here, a global write lock on 30872bed082SRobert Watson * the pcbinfo isn't required. 3098501a69cSRobert Watson */ 3108501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 31159daba27SSam Leffler INP_LOCK_ASSERT(inp); 31259daba27SSam Leffler 313603724d3SBjoern A. Zeeb if (TAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */ 314df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 3154b932371SIan Dowse laddr.s_addr = *laddrp; 3164b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 317df8bae1dSRodney W. Grimes return (EINVAL); 318c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 319421d8aa6SBjoern A. Zeeb wild = INPLOOKUP_WILDCARD; 3207c2f3cb9SJamie Gritton if (nam == NULL) { 3217c2f3cb9SJamie Gritton if ((error = prison_local_ip4(cred, &laddr)) != 0) 3227c2f3cb9SJamie Gritton return (error); 3237c2f3cb9SJamie Gritton } else { 32457bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 32557bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 326df8bae1dSRodney W. Grimes return (EINVAL); 327df8bae1dSRodney W. Grimes #ifdef notdef 328df8bae1dSRodney W. Grimes /* 329df8bae1dSRodney W. Grimes * We should check the family, but old programs 330df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 331df8bae1dSRodney W. Grimes */ 332df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 333df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 334df8bae1dSRodney W. Grimes #endif 335b89e82ddSJamie Gritton error = prison_local_ip4(cred, &sin->sin_addr); 336b89e82ddSJamie Gritton if (error) 337b89e82ddSJamie Gritton return (error); 3384b932371SIan Dowse if (sin->sin_port != *lportp) { 3394b932371SIan Dowse /* Don't allow the port to change. */ 3404b932371SIan Dowse if (*lportp != 0) 3414b932371SIan Dowse return (EINVAL); 342df8bae1dSRodney W. Grimes lport = sin->sin_port; 3434b932371SIan Dowse } 3444b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 345df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 346df8bae1dSRodney W. Grimes /* 347df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 348df8bae1dSRodney W. Grimes * allow complete duplication of binding if 349df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 350df8bae1dSRodney W. Grimes * and a multicast address is bound on both 351df8bae1dSRodney W. Grimes * new and duplicated sockets. 352df8bae1dSRodney W. Grimes */ 353df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 354df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 355df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 356df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 35783103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 3584209e01aSAdrian Chadd /* 3594209e01aSAdrian Chadd * Is the address a local IP address? 3604209e01aSAdrian Chadd * If INP_NONLOCALOK is set, then the socket may be bound 3618696873dSAdrian Chadd * to any endpoint address, local or not. 3624209e01aSAdrian Chadd */ 363be9347e3SAdrian Chadd if ( 364be9347e3SAdrian Chadd #if defined(IP_NONLOCALBIND) 365be9347e3SAdrian Chadd ((inp->inp_flags & INP_NONLOCALOK) == 0) && 366be9347e3SAdrian Chadd #endif 367be9347e3SAdrian Chadd (ifa_ifwithaddr((struct sockaddr *)sin) == 0)) 368df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 369df8bae1dSRodney W. Grimes } 3704b932371SIan Dowse laddr = sin->sin_addr; 371df8bae1dSRodney W. Grimes if (lport) { 372df8bae1dSRodney W. Grimes struct inpcb *t; 373ae0e7143SRobert Watson struct tcptw *tw; 374ae0e7143SRobert Watson 375df8bae1dSRodney W. Grimes /* GROSS */ 376603724d3SBjoern A. Zeeb if (ntohs(lport) <= V_ipport_reservedhigh && 377603724d3SBjoern A. Zeeb ntohs(lport) >= V_ipport_reservedlow && 378acd3428bSRobert Watson priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 37932f9753cSRobert Watson 0)) 3802469dd60SGarrett Wollman return (EACCES); 381835d4b89SPawel Jakub Dawidek if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 38286d02c5cSBjoern A. Zeeb priv_check_cred(inp->inp_cred, 38332f9753cSRobert Watson PRIV_NETINET_REUSEPORT, 0) != 0) { 384078b7042SBjoern A. Zeeb t = in_pcblookup_local(pcbinfo, sin->sin_addr, 385413628a7SBjoern A. Zeeb lport, INPLOOKUP_WILDCARD, cred); 386340c35deSJonathan Lemon /* 387340c35deSJonathan Lemon * XXX 388340c35deSJonathan Lemon * This entire block sorely needs a rewrite. 389340c35deSJonathan Lemon */ 3904cc20ab1SSeigo Tanimura if (t && 391ad71fe3cSRobert Watson ((t->inp_flags & INP_TIMEWAIT) == 0) && 3924658dc83SYaroslav Tykhiy (so->so_type != SOCK_STREAM || 3934658dc83SYaroslav Tykhiy ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && 3944cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 39552b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 39652b65dbeSBill Fenner (t->inp_socket->so_options & 39752b65dbeSBill Fenner SO_REUSEPORT) == 0) && 39886d02c5cSBjoern A. Zeeb (inp->inp_cred->cr_uid != 39986d02c5cSBjoern A. Zeeb t->inp_cred->cr_uid)) 4004049a042SGuido van Rooij return (EADDRINUSE); 4014049a042SGuido van Rooij } 402c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 403413628a7SBjoern A. Zeeb lport, wild, cred); 404ad71fe3cSRobert Watson if (t && (t->inp_flags & INP_TIMEWAIT)) { 405ae0e7143SRobert Watson /* 406ae0e7143SRobert Watson * XXXRW: If an incpb has had its timewait 407ae0e7143SRobert Watson * state recycled, we treat the address as 408ae0e7143SRobert Watson * being in use (for now). This is better 409ae0e7143SRobert Watson * than a panic, but not desirable. 410ae0e7143SRobert Watson */ 411ae0e7143SRobert Watson tw = intotw(inp); 412ae0e7143SRobert Watson if (tw == NULL || 413ae0e7143SRobert Watson (reuseport & tw->tw_so_options) == 0) 414340c35deSJonathan Lemon return (EADDRINUSE); 415ae0e7143SRobert Watson } else if (t && 4164cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 417e3fd5ffdSRobert Watson #ifdef INET6 41833841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 419cfa1ca9dSYoshinobu Inoue INADDR_ANY || 420cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 421cfa1ca9dSYoshinobu Inoue INADDR_ANY || 422cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 423cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 424e3fd5ffdSRobert Watson #endif 425df8bae1dSRodney W. Grimes return (EADDRINUSE); 426df8bae1dSRodney W. Grimes } 427cfa1ca9dSYoshinobu Inoue } 428df8bae1dSRodney W. Grimes } 4294b932371SIan Dowse if (*lportp != 0) 4304b932371SIan Dowse lport = *lportp; 43133b3ac06SPeter Wemm if (lport == 0) { 4321cf6e4f5SRui Paulo u_short first, last, aux; 433174624e0SMike Silbersack int count; 43433b3ac06SPeter Wemm 43533b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 436603724d3SBjoern A. Zeeb first = V_ipport_hifirstauto; /* sysctl */ 437603724d3SBjoern A. Zeeb last = V_ipport_hilastauto; 438712fc218SRobert Watson lastport = &pcbinfo->ipi_lasthi; 43933b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 440acd3428bSRobert Watson error = priv_check_cred(cred, 44132f9753cSRobert Watson PRIV_NETINET_RESERVEDPORT, 0); 442acd3428bSRobert Watson if (error) 443a29f300eSGarrett Wollman return error; 444603724d3SBjoern A. Zeeb first = V_ipport_lowfirstauto; /* 1023 */ 445603724d3SBjoern A. Zeeb last = V_ipport_lowlastauto; /* 600 */ 446712fc218SRobert Watson lastport = &pcbinfo->ipi_lastlow; 44733b3ac06SPeter Wemm } else { 448603724d3SBjoern A. Zeeb first = V_ipport_firstauto; /* sysctl */ 449603724d3SBjoern A. Zeeb last = V_ipport_lastauto; 450712fc218SRobert Watson lastport = &pcbinfo->ipi_lastport; 45133b3ac06SPeter Wemm } 45233b3ac06SPeter Wemm /* 4535f311da2SMike Silbersack * For UDP, use random port allocation as long as the user 4545f311da2SMike Silbersack * allows it. For TCP (and as of yet unknown) connections, 4555f311da2SMike Silbersack * use random port allocation only if the user allows it AND 45629f2a6ecSMaxim Konovalov * ipport_tick() allows it. 4575f311da2SMike Silbersack */ 458603724d3SBjoern A. Zeeb if (V_ipport_randomized && 459603724d3SBjoern A. Zeeb (!V_ipport_stoprandom || pcbinfo == &V_udbinfo)) 4605f311da2SMike Silbersack dorandom = 1; 4615f311da2SMike Silbersack else 4625f311da2SMike Silbersack dorandom = 0; 463e99971bfSMaxim Konovalov /* 464e99971bfSMaxim Konovalov * It makes no sense to do random port allocation if 465e99971bfSMaxim Konovalov * we have the only port available. 466e99971bfSMaxim Konovalov */ 467e99971bfSMaxim Konovalov if (first == last) 468e99971bfSMaxim Konovalov dorandom = 0; 4695f311da2SMike Silbersack /* Make sure to not include UDP packets in the count. */ 470603724d3SBjoern A. Zeeb if (pcbinfo != &V_udbinfo) 471603724d3SBjoern A. Zeeb V_ipport_tcpallocs++; 4725f311da2SMike Silbersack /* 4737e1bc272SBjoern A. Zeeb * Instead of having two loops further down counting up or down 4747e1bc272SBjoern A. Zeeb * make sure that first is always <= last and go with only one 4757e1bc272SBjoern A. Zeeb * code path implementing all logic. 47633b3ac06SPeter Wemm */ 47733b3ac06SPeter Wemm if (first > last) { 4781cf6e4f5SRui Paulo aux = first; 4791cf6e4f5SRui Paulo first = last; 4801cf6e4f5SRui Paulo last = aux; 4811cf6e4f5SRui Paulo } 482174624e0SMike Silbersack 4835f311da2SMike Silbersack if (dorandom) 4846b2fc10bSMike Silbersack *lastport = first + 4856b2fc10bSMike Silbersack (arc4random() % (last - first)); 4861cf6e4f5SRui Paulo 48733b3ac06SPeter Wemm count = last - first; 488174624e0SMike Silbersack 48933b3ac06SPeter Wemm do { 4906ac48b74SMike Silbersack if (count-- < 0) /* completely used? */ 491550b1518SWes Peters return (EADDRNOTAVAIL); 49233b3ac06SPeter Wemm ++*lastport; 49333b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 49433b3ac06SPeter Wemm *lastport = first; 49533b3ac06SPeter Wemm lport = htons(*lastport); 496078b7042SBjoern A. Zeeb } while (in_pcblookup_local(pcbinfo, laddr, 497078b7042SBjoern A. Zeeb lport, wild, cred)); 49833b3ac06SPeter Wemm } 4994b932371SIan Dowse *laddrp = laddr.s_addr; 5004b932371SIan Dowse *lportp = lport; 501df8bae1dSRodney W. Grimes return (0); 502df8bae1dSRodney W. Grimes } 503df8bae1dSRodney W. Grimes 504999f1343SGarrett Wollman /* 5055200e00eSIan Dowse * Connect from a socket to a specified address. 5065200e00eSIan Dowse * Both address and port must be specified in argument sin. 5075200e00eSIan Dowse * If don't have a local address for this socket yet, 5085200e00eSIan Dowse * then pick one. 509999f1343SGarrett Wollman */ 510999f1343SGarrett Wollman int 511136d4f1cSRobert Watson in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 512999f1343SGarrett Wollman { 5135200e00eSIan Dowse u_short lport, fport; 5145200e00eSIan Dowse in_addr_t laddr, faddr; 5155200e00eSIan Dowse int anonport, error; 516df8bae1dSRodney W. Grimes 51727f74fd0SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 5188501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 51927f74fd0SRobert Watson 5205200e00eSIan Dowse lport = inp->inp_lport; 5215200e00eSIan Dowse laddr = inp->inp_laddr.s_addr; 5225200e00eSIan Dowse anonport = (lport == 0); 5235200e00eSIan Dowse error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport, 524b0330ed9SPawel Jakub Dawidek NULL, cred); 5255200e00eSIan Dowse if (error) 5265200e00eSIan Dowse return (error); 5275200e00eSIan Dowse 5285200e00eSIan Dowse /* Do the initial binding of the local address if required. */ 5295200e00eSIan Dowse if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) { 5305200e00eSIan Dowse inp->inp_lport = lport; 5315200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5325200e00eSIan Dowse if (in_pcbinshash(inp) != 0) { 5335200e00eSIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 5345200e00eSIan Dowse inp->inp_lport = 0; 5355200e00eSIan Dowse return (EAGAIN); 5365200e00eSIan Dowse } 5375200e00eSIan Dowse } 5385200e00eSIan Dowse 5395200e00eSIan Dowse /* Commit the remaining changes. */ 5405200e00eSIan Dowse inp->inp_lport = lport; 5415200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5425200e00eSIan Dowse inp->inp_faddr.s_addr = faddr; 5435200e00eSIan Dowse inp->inp_fport = fport; 5445200e00eSIan Dowse in_pcbrehash(inp); 5452cb64cb2SGeorge V. Neville-Neil 5465200e00eSIan Dowse if (anonport) 5475200e00eSIan Dowse inp->inp_flags |= INP_ANONPORT; 5485200e00eSIan Dowse return (0); 5495200e00eSIan Dowse } 5505200e00eSIan Dowse 5515200e00eSIan Dowse /* 5520895aec3SBjoern A. Zeeb * Do proper source address selection on an unbound socket in case 5530895aec3SBjoern A. Zeeb * of connect. Take jails into account as well. 5540895aec3SBjoern A. Zeeb */ 5550895aec3SBjoern A. Zeeb static int 5560895aec3SBjoern A. Zeeb in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, 5570895aec3SBjoern A. Zeeb struct ucred *cred) 5580895aec3SBjoern A. Zeeb { 5590895aec3SBjoern A. Zeeb struct in_ifaddr *ia; 5600895aec3SBjoern A. Zeeb struct ifaddr *ifa; 5610895aec3SBjoern A. Zeeb struct sockaddr *sa; 5620895aec3SBjoern A. Zeeb struct sockaddr_in *sin; 5630895aec3SBjoern A. Zeeb struct route sro; 5640895aec3SBjoern A. Zeeb int error; 5650895aec3SBjoern A. Zeeb 566413628a7SBjoern A. Zeeb KASSERT(laddr != NULL, ("%s: laddr NULL", __func__)); 5670895aec3SBjoern A. Zeeb 5680895aec3SBjoern A. Zeeb error = 0; 5690895aec3SBjoern A. Zeeb ia = NULL; 5700895aec3SBjoern A. Zeeb bzero(&sro, sizeof(sro)); 5710895aec3SBjoern A. Zeeb 5720895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)&sro.ro_dst; 5730895aec3SBjoern A. Zeeb sin->sin_family = AF_INET; 5740895aec3SBjoern A. Zeeb sin->sin_len = sizeof(struct sockaddr_in); 5750895aec3SBjoern A. Zeeb sin->sin_addr.s_addr = faddr->s_addr; 5760895aec3SBjoern A. Zeeb 5770895aec3SBjoern A. Zeeb /* 5780895aec3SBjoern A. Zeeb * If route is known our src addr is taken from the i/f, 5790895aec3SBjoern A. Zeeb * else punt. 5800895aec3SBjoern A. Zeeb * 5810895aec3SBjoern A. Zeeb * Find out route to destination. 5820895aec3SBjoern A. Zeeb */ 5830895aec3SBjoern A. Zeeb if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) 5846e6b3f7cSQing Li in_rtalloc_ign(&sro, 0, inp->inp_inc.inc_fibnum); 5850895aec3SBjoern A. Zeeb 5860895aec3SBjoern A. Zeeb /* 5870895aec3SBjoern A. Zeeb * If we found a route, use the address corresponding to 5880895aec3SBjoern A. Zeeb * the outgoing interface. 5890895aec3SBjoern A. Zeeb * 5900895aec3SBjoern A. Zeeb * Otherwise assume faddr is reachable on a directly connected 5910895aec3SBjoern A. Zeeb * network and try to find a corresponding interface to take 5920895aec3SBjoern A. Zeeb * the source address from. 5930895aec3SBjoern A. Zeeb */ 5940895aec3SBjoern A. Zeeb if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) { 5950895aec3SBjoern A. Zeeb struct ifnet *ifp; 5960895aec3SBjoern A. Zeeb 5970895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin)); 5980895aec3SBjoern A. Zeeb if (ia == NULL) 5990895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin)); 6000895aec3SBjoern A. Zeeb if (ia == NULL) { 6010895aec3SBjoern A. Zeeb error = ENETUNREACH; 6020895aec3SBjoern A. Zeeb goto done; 6030895aec3SBjoern A. Zeeb } 6040895aec3SBjoern A. Zeeb 6050895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6060895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6070895aec3SBjoern A. Zeeb goto done; 6080895aec3SBjoern A. Zeeb } 6090895aec3SBjoern A. Zeeb 6100895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 6110895aec3SBjoern A. Zeeb ia = NULL; 6129317b04eSRobert Watson IF_ADDR_LOCK(ifp); 6130895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 6140895aec3SBjoern A. Zeeb 6150895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6160895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6170895aec3SBjoern A. Zeeb continue; 6180895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 619b89e82ddSJamie Gritton if (prison_check_ip4(cred, &sin->sin_addr) == 0) { 6200895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6210895aec3SBjoern A. Zeeb break; 6220895aec3SBjoern A. Zeeb } 6230895aec3SBjoern A. Zeeb } 6240895aec3SBjoern A. Zeeb if (ia != NULL) { 6250895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6269317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 6270895aec3SBjoern A. Zeeb goto done; 6280895aec3SBjoern A. Zeeb } 6299317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 6300895aec3SBjoern A. Zeeb 6310895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 632b89e82ddSJamie Gritton error = prison_get_ip4(cred, laddr); 6330895aec3SBjoern A. Zeeb goto done; 6340895aec3SBjoern A. Zeeb } 6350895aec3SBjoern A. Zeeb 6360895aec3SBjoern A. Zeeb /* 6370895aec3SBjoern A. Zeeb * If the outgoing interface on the route found is not 6380895aec3SBjoern A. Zeeb * a loopback interface, use the address from that interface. 6390895aec3SBjoern A. Zeeb * In case of jails do those three steps: 6400895aec3SBjoern A. Zeeb * 1. check if the interface address belongs to the jail. If so use it. 6410895aec3SBjoern A. Zeeb * 2. check if we have any address on the outgoing interface 6420895aec3SBjoern A. Zeeb * belonging to this jail. If so use it. 6430895aec3SBjoern A. Zeeb * 3. as a last resort return the 'default' jail address. 6440895aec3SBjoern A. Zeeb */ 6450895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) { 6469317b04eSRobert Watson struct ifnet *ifp; 6470895aec3SBjoern A. Zeeb 6480895aec3SBjoern A. Zeeb /* If not jailed, use the default returned. */ 6490895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6500895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6510895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6520895aec3SBjoern A. Zeeb goto done; 6530895aec3SBjoern A. Zeeb } 6540895aec3SBjoern A. Zeeb 6550895aec3SBjoern A. Zeeb /* Jailed. */ 6560895aec3SBjoern A. Zeeb /* 1. Check if the iface address belongs to the jail. */ 6570895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr; 658b89e82ddSJamie Gritton if (prison_check_ip4(cred, &sin->sin_addr) == 0) { 6590895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6600895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6610895aec3SBjoern A. Zeeb goto done; 6620895aec3SBjoern A. Zeeb } 6630895aec3SBjoern A. Zeeb 6640895aec3SBjoern A. Zeeb /* 6650895aec3SBjoern A. Zeeb * 2. Check if we have any address on the outgoing interface 6660895aec3SBjoern A. Zeeb * belonging to this jail. 6670895aec3SBjoern A. Zeeb */ 6689317b04eSRobert Watson ifp = sro.ro_rt->rt_ifp; 6699317b04eSRobert Watson IF_ADDR_LOCK(ifp); 6709317b04eSRobert Watson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 6710895aec3SBjoern A. Zeeb 6720895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6730895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6740895aec3SBjoern A. Zeeb continue; 6750895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 676b89e82ddSJamie Gritton if (prison_check_ip4(cred, &sin->sin_addr) == 0) { 6770895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6780895aec3SBjoern A. Zeeb break; 6790895aec3SBjoern A. Zeeb } 6800895aec3SBjoern A. Zeeb } 6810895aec3SBjoern A. Zeeb if (ia != NULL) { 6820895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6839317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 6840895aec3SBjoern A. Zeeb goto done; 6850895aec3SBjoern A. Zeeb } 6869317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 6870895aec3SBjoern A. Zeeb 6880895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 689b89e82ddSJamie Gritton error = prison_get_ip4(cred, laddr); 6900895aec3SBjoern A. Zeeb goto done; 6910895aec3SBjoern A. Zeeb } 6920895aec3SBjoern A. Zeeb 6930895aec3SBjoern A. Zeeb /* 6940895aec3SBjoern A. Zeeb * The outgoing interface is marked with 'loopback net', so a route 6950895aec3SBjoern A. Zeeb * to ourselves is here. 6960895aec3SBjoern A. Zeeb * Try to find the interface of the destination address and then 6970895aec3SBjoern A. Zeeb * take the address from there. That interface is not necessarily 6980895aec3SBjoern A. Zeeb * a loopback interface. 6990895aec3SBjoern A. Zeeb * In case of jails, check that it is an address of the jail 7000895aec3SBjoern A. Zeeb * and if we cannot find, fall back to the 'default' jail address. 7010895aec3SBjoern A. Zeeb */ 7020895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { 7030895aec3SBjoern A. Zeeb struct sockaddr_in sain; 7040895aec3SBjoern A. Zeeb 7050895aec3SBjoern A. Zeeb bzero(&sain, sizeof(struct sockaddr_in)); 7060895aec3SBjoern A. Zeeb sain.sin_family = AF_INET; 7070895aec3SBjoern A. Zeeb sain.sin_len = sizeof(struct sockaddr_in); 7080895aec3SBjoern A. Zeeb sain.sin_addr.s_addr = faddr->s_addr; 7090895aec3SBjoern A. Zeeb 7100895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sain))); 7110895aec3SBjoern A. Zeeb if (ia == NULL) 7120895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet(sintosa(&sain))); 7130895aec3SBjoern A. Zeeb 7140895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 71503d8b6fdSBjoern A. Zeeb #if __FreeBSD_version < 800000 71603d8b6fdSBjoern A. Zeeb if (ia == NULL) 71703d8b6fdSBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 71803d8b6fdSBjoern A. Zeeb #endif 7190895aec3SBjoern A. Zeeb if (ia == NULL) { 7200895aec3SBjoern A. Zeeb error = ENETUNREACH; 7210895aec3SBjoern A. Zeeb goto done; 7220895aec3SBjoern A. Zeeb } 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 /* Jailed. */ 7280895aec3SBjoern A. Zeeb if (ia != NULL) { 7290895aec3SBjoern A. Zeeb struct ifnet *ifp; 7300895aec3SBjoern A. Zeeb 7310895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 7320895aec3SBjoern A. Zeeb ia = NULL; 7339317b04eSRobert Watson IF_ADDR_LOCK(ifp); 7340895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 7350895aec3SBjoern A. Zeeb 7360895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 7370895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 7380895aec3SBjoern A. Zeeb continue; 7390895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 740b89e82ddSJamie Gritton if (prison_check_ip4(cred, 741b89e82ddSJamie Gritton &sin->sin_addr) == 0) { 7420895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 7430895aec3SBjoern A. Zeeb break; 7440895aec3SBjoern A. Zeeb } 7450895aec3SBjoern A. Zeeb } 7460895aec3SBjoern A. Zeeb if (ia != NULL) { 7470895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 7489317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 7490895aec3SBjoern A. Zeeb goto done; 7500895aec3SBjoern A. Zeeb } 7519317b04eSRobert Watson IF_ADDR_UNLOCK(ifp); 7520895aec3SBjoern A. Zeeb } 7530895aec3SBjoern A. Zeeb 7540895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 755b89e82ddSJamie Gritton error = prison_get_ip4(cred, laddr); 7560895aec3SBjoern A. Zeeb goto done; 7570895aec3SBjoern A. Zeeb } 7580895aec3SBjoern A. Zeeb 7590895aec3SBjoern A. Zeeb done: 7600895aec3SBjoern A. Zeeb if (sro.ro_rt != NULL) 7610895aec3SBjoern A. Zeeb RTFREE(sro.ro_rt); 7620895aec3SBjoern A. Zeeb return (error); 7630895aec3SBjoern A. Zeeb } 7640895aec3SBjoern A. Zeeb 7650895aec3SBjoern A. Zeeb /* 7665200e00eSIan Dowse * Set up for a connect from a socket to the specified address. 7675200e00eSIan Dowse * On entry, *laddrp and *lportp should contain the current local 7685200e00eSIan Dowse * address and port for the PCB; these are updated to the values 7695200e00eSIan Dowse * that should be placed in inp_laddr and inp_lport to complete 7705200e00eSIan Dowse * the connect. 7715200e00eSIan Dowse * 7725200e00eSIan Dowse * On success, *faddrp and *fportp will be set to the remote address 7735200e00eSIan Dowse * and port. These are not updated in the error case. 7745200e00eSIan Dowse * 7755200e00eSIan Dowse * If the operation fails because the connection already exists, 7765200e00eSIan Dowse * *oinpp will be set to the PCB of that connection so that the 7775200e00eSIan Dowse * caller can decide to override it. In all other cases, *oinpp 7785200e00eSIan Dowse * is set to NULL. 7795200e00eSIan Dowse */ 7805200e00eSIan Dowse int 781136d4f1cSRobert Watson in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, 782136d4f1cSRobert Watson in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp, 783136d4f1cSRobert Watson struct inpcb **oinpp, struct ucred *cred) 7845200e00eSIan Dowse { 7858b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 7865200e00eSIan Dowse struct sockaddr_in *sin = (struct sockaddr_in *)nam; 7875200e00eSIan Dowse struct in_ifaddr *ia; 7885200e00eSIan Dowse struct inpcb *oinp; 789b89e82ddSJamie Gritton struct in_addr laddr, faddr; 7905200e00eSIan Dowse u_short lport, fport; 7915200e00eSIan Dowse int error; 7925200e00eSIan Dowse 7938501a69cSRobert Watson /* 7948501a69cSRobert Watson * Because a global state change doesn't actually occur here, a read 7958501a69cSRobert Watson * lock is sufficient. 7968501a69cSRobert Watson */ 7978501a69cSRobert Watson INP_INFO_LOCK_ASSERT(inp->inp_pcbinfo); 79827f74fd0SRobert Watson INP_LOCK_ASSERT(inp); 79927f74fd0SRobert Watson 8005200e00eSIan Dowse if (oinpp != NULL) 8015200e00eSIan Dowse *oinpp = NULL; 80257bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 803df8bae1dSRodney W. Grimes return (EINVAL); 804df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 805df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 806df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 807df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 8085200e00eSIan Dowse laddr.s_addr = *laddrp; 8095200e00eSIan Dowse lport = *lportp; 8105200e00eSIan Dowse faddr = sin->sin_addr; 8115200e00eSIan Dowse fport = sin->sin_port; 8120895aec3SBjoern A. Zeeb 813603724d3SBjoern A. Zeeb if (!TAILQ_EMPTY(&V_in_ifaddrhead)) { 814df8bae1dSRodney W. Grimes /* 815df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 816df8bae1dSRodney W. Grimes * use the primary local address. 817df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 818df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 819df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 820df8bae1dSRodney W. Grimes */ 821413628a7SBjoern A. Zeeb if (faddr.s_addr == INADDR_ANY) { 822413628a7SBjoern A. Zeeb faddr = 823b89e82ddSJamie Gritton IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; 824b89e82ddSJamie Gritton if (cred != NULL && 825b89e82ddSJamie Gritton (error = prison_get_ip4(cred, &faddr)) != 0) 826b89e82ddSJamie Gritton return (error); 827413628a7SBjoern A. Zeeb } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && 828603724d3SBjoern A. Zeeb (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & 8295200e00eSIan Dowse IFF_BROADCAST)) 8305200e00eSIan Dowse faddr = satosin(&TAILQ_FIRST( 831603724d3SBjoern A. Zeeb &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; 832df8bae1dSRodney W. Grimes } 8335200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY) { 8340895aec3SBjoern A. Zeeb error = in_pcbladdr(inp, &faddr, &laddr, cred); 8350895aec3SBjoern A. Zeeb if (error) 8360895aec3SBjoern A. Zeeb return (error); 837df8bae1dSRodney W. Grimes 838df8bae1dSRodney W. Grimes /* 839df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 840df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 841df8bae1dSRodney W. Grimes * address of that interface as our source address. 842df8bae1dSRodney W. Grimes */ 8435200e00eSIan Dowse if (IN_MULTICAST(ntohl(faddr.s_addr)) && 844df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 845df8bae1dSRodney W. Grimes struct ip_moptions *imo; 846df8bae1dSRodney W. Grimes struct ifnet *ifp; 847df8bae1dSRodney W. Grimes 848df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 849df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 850df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 851603724d3SBjoern A. Zeeb TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) 852df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 853df8bae1dSRodney W. Grimes break; 8548699ea08SBjoern A. Zeeb if (ia == NULL) 855df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 8565200e00eSIan Dowse laddr = ia->ia_addr.sin_addr; 857999f1343SGarrett Wollman } 8580895aec3SBjoern A. Zeeb } 8590895aec3SBjoern A. Zeeb } 860999f1343SGarrett Wollman 8615200e00eSIan Dowse oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport, 8625200e00eSIan Dowse 0, NULL); 8635200e00eSIan Dowse if (oinp != NULL) { 8645200e00eSIan Dowse if (oinpp != NULL) 8655200e00eSIan Dowse *oinpp = oinp; 866df8bae1dSRodney W. Grimes return (EADDRINUSE); 867c3229e05SDavid Greenman } 8685200e00eSIan Dowse if (lport == 0) { 869b0330ed9SPawel Jakub Dawidek error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, 870b0330ed9SPawel Jakub Dawidek cred); 8715a903f8dSPierre Beyssac if (error) 8725a903f8dSPierre Beyssac return (error); 8735a903f8dSPierre Beyssac } 8745200e00eSIan Dowse *laddrp = laddr.s_addr; 8755200e00eSIan Dowse *lportp = lport; 8765200e00eSIan Dowse *faddrp = faddr.s_addr; 8775200e00eSIan Dowse *fportp = fport; 878df8bae1dSRodney W. Grimes return (0); 879df8bae1dSRodney W. Grimes } 880df8bae1dSRodney W. Grimes 88126f9a767SRodney W. Grimes void 882136d4f1cSRobert Watson in_pcbdisconnect(struct inpcb *inp) 883df8bae1dSRodney W. Grimes { 8846b348152SRobert Watson 885fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 8868501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 887df8bae1dSRodney W. Grimes 888df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 889df8bae1dSRodney W. Grimes inp->inp_fport = 0; 89015bd2b43SDavid Greenman in_pcbrehash(inp); 891df8bae1dSRodney W. Grimes } 892df8bae1dSRodney W. Grimes 8934c7c478dSRobert Watson /* 89428696211SRobert Watson * in_pcbdetach() is responsibe for disassociating a socket from an inpcb. 895c0a211c5SRobert Watson * For most protocols, this will be invoked immediately prior to calling 89628696211SRobert Watson * in_pcbfree(). However, with TCP the inpcb may significantly outlive the 89728696211SRobert Watson * socket, in which case in_pcbfree() is deferred. 8984c7c478dSRobert Watson */ 89926f9a767SRodney W. Grimes void 900136d4f1cSRobert Watson in_pcbdetach(struct inpcb *inp) 901df8bae1dSRodney W. Grimes { 9024c7c478dSRobert Watson 903a7df09e8SBjoern A. Zeeb KASSERT(inp->inp_socket != NULL, ("%s: inp_socket == NULL", __func__)); 904c0a211c5SRobert Watson 9054c7c478dSRobert Watson inp->inp_socket->so_pcb = NULL; 9064c7c478dSRobert Watson inp->inp_socket = NULL; 9074c7c478dSRobert Watson } 9084c7c478dSRobert Watson 909c0a211c5SRobert Watson /* 91028696211SRobert Watson * in_pcbfree_internal() frees an inpcb that has been detached from its 91128696211SRobert Watson * socket, and whose reference count has reached 0. It will also remove the 91228696211SRobert Watson * inpcb from any global lists it might remain on. 913c0a211c5SRobert Watson */ 91428696211SRobert Watson static void 91528696211SRobert Watson in_pcbfree_internal(struct inpcb *inp) 9164c7c478dSRobert Watson { 9173d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 918df8bae1dSRodney W. Grimes 919a7df09e8SBjoern A. Zeeb KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); 92028696211SRobert Watson KASSERT(inp->inp_refcount == 0, ("%s: refcount !0", __func__)); 9218501a69cSRobert Watson 922fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(ipi); 9238501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 92459daba27SSam Leffler 925b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 9266aee2fc5SBjoern A. Zeeb if (inp->inp_sp != NULL) 9276974bd9eSBjoern A. Zeeb ipsec_delete_pcbpolicy(inp); 928b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 9293d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 930c3229e05SDavid Greenman in_pcbremlists(inp); 9316aee2fc5SBjoern A. Zeeb #ifdef INET6 9326aee2fc5SBjoern A. Zeeb if (inp->inp_vflag & INP_IPV6PROTO) { 9336aee2fc5SBjoern A. Zeeb ip6_freepcbopts(inp->in6p_outputopts); 9341096332aSBruce M Simpson if (inp->in6p_moptions != NULL) 9356aee2fc5SBjoern A. Zeeb ip6_freemoptions(inp->in6p_moptions); 9366aee2fc5SBjoern A. Zeeb } 9376aee2fc5SBjoern A. Zeeb #endif 938df8bae1dSRodney W. Grimes if (inp->inp_options) 939df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 94071498f30SBruce M Simpson if (inp->inp_moptions != NULL) 94171498f30SBruce M Simpson inp_freemoptions(inp->inp_moptions); 942cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 94386d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 944d915b280SStephan Uphoff 945a557af22SRobert Watson #ifdef MAC 94630d239bcSRobert Watson mac_inpcb_destroy(inp); 947a557af22SRobert Watson #endif 9488501a69cSRobert Watson INP_WUNLOCK(inp); 94969c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 950df8bae1dSRodney W. Grimes } 951df8bae1dSRodney W. Grimes 95210702a28SRobert Watson /* 95328696211SRobert Watson * in_pcbref() bumps the reference count on an inpcb in order to maintain 95428696211SRobert Watson * stability of an inpcb pointer despite the inpcb lock being released. This 95528696211SRobert Watson * is used in TCP when the inpcbinfo lock needs to be acquired or upgraded, 95628696211SRobert Watson * but where the inpcb lock is already held. 95728696211SRobert Watson * 95828696211SRobert Watson * While the inpcb will not be freed, releasing the inpcb lock means that the 95928696211SRobert Watson * connection's state may change, so the caller should be careful to 96028696211SRobert Watson * revalidate any cached state on reacquiring the lock. Drop the reference 96128696211SRobert Watson * using in_pcbrele(). 96228696211SRobert Watson */ 96328696211SRobert Watson void 96428696211SRobert Watson in_pcbref(struct inpcb *inp) 96528696211SRobert Watson { 96628696211SRobert Watson 96728696211SRobert Watson INP_WLOCK_ASSERT(inp); 96828696211SRobert Watson 96928696211SRobert Watson KASSERT(inp->inp_refcount > 0, ("%s: refcount 0", __func__)); 97028696211SRobert Watson 97128696211SRobert Watson inp->inp_refcount++; 97228696211SRobert Watson } 97328696211SRobert Watson 97428696211SRobert Watson /* 97528696211SRobert Watson * Drop a refcount on an inpcb elevated using in_pcbref(); because a call to 97628696211SRobert Watson * in_pcbfree() may have been made between in_pcbref() and in_pcbrele(), we 97728696211SRobert Watson * return a flag indicating whether or not the inpcb remains valid. If it is 97828696211SRobert Watson * valid, we return with the inpcb lock held. 97928696211SRobert Watson */ 98028696211SRobert Watson int 98128696211SRobert Watson in_pcbrele(struct inpcb *inp) 98228696211SRobert Watson { 98328696211SRobert Watson #ifdef INVARIANTS 98428696211SRobert Watson struct inpcbinfo *ipi = inp->inp_pcbinfo; 98528696211SRobert Watson #endif 98628696211SRobert Watson 98728696211SRobert Watson KASSERT(inp->inp_refcount > 0, ("%s: refcount 0", __func__)); 98828696211SRobert Watson 98928696211SRobert Watson INP_INFO_WLOCK_ASSERT(ipi); 99028696211SRobert Watson INP_WLOCK_ASSERT(inp); 99128696211SRobert Watson 99228696211SRobert Watson inp->inp_refcount--; 99328696211SRobert Watson if (inp->inp_refcount > 0) 99428696211SRobert Watson return (0); 99528696211SRobert Watson in_pcbfree_internal(inp); 99628696211SRobert Watson return (1); 99728696211SRobert Watson } 99828696211SRobert Watson 99928696211SRobert Watson /* 100028696211SRobert Watson * Unconditionally schedule an inpcb to be freed by decrementing its 100128696211SRobert Watson * reference count, which should occur only after the inpcb has been detached 100228696211SRobert Watson * from its socket. If another thread holds a temporary reference (acquired 100328696211SRobert Watson * using in_pcbref()) then the free is deferred until that reference is 100428696211SRobert Watson * released using in_pcbrele(), but the inpcb is still unlocked. 100528696211SRobert Watson */ 100628696211SRobert Watson void 100728696211SRobert Watson in_pcbfree(struct inpcb *inp) 100828696211SRobert Watson { 100928696211SRobert Watson #ifdef INVARIANTS 101028696211SRobert Watson struct inpcbinfo *ipi = inp->inp_pcbinfo; 101128696211SRobert Watson #endif 101228696211SRobert Watson 101328696211SRobert Watson KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", 101428696211SRobert Watson __func__)); 101528696211SRobert Watson 101628696211SRobert Watson INP_INFO_WLOCK_ASSERT(ipi); 101728696211SRobert Watson INP_WLOCK_ASSERT(inp); 101828696211SRobert Watson 101928696211SRobert Watson if (!in_pcbrele(inp)) 102028696211SRobert Watson INP_WUNLOCK(inp); 102128696211SRobert Watson } 102228696211SRobert Watson 102328696211SRobert Watson /* 1024c0a211c5SRobert Watson * in_pcbdrop() removes an inpcb from hashed lists, releasing its address and 1025c0a211c5SRobert Watson * port reservation, and preventing it from being returned by inpcb lookups. 1026c0a211c5SRobert Watson * 1027c0a211c5SRobert Watson * It is used by TCP to mark an inpcb as unused and avoid future packet 1028c0a211c5SRobert Watson * delivery or event notification when a socket remains open but TCP has 1029c0a211c5SRobert Watson * closed. This might occur as a result of a shutdown()-initiated TCP close 1030c0a211c5SRobert Watson * or a RST on the wire, and allows the port binding to be reused while still 1031c0a211c5SRobert Watson * maintaining the invariant that so_pcb always points to a valid inpcb until 1032c0a211c5SRobert Watson * in_pcbdetach(). 1033c0a211c5SRobert Watson * 1034c0a211c5SRobert Watson * XXXRW: An inp_lport of 0 is used to indicate that the inpcb is not on hash 1035c0a211c5SRobert Watson * lists, but can lead to confusing netstat output, as open sockets with 1036c0a211c5SRobert Watson * closed TCP connections will no longer appear to have their bound port 1037c0a211c5SRobert Watson * number. An explicit flag would be better, as it would allow us to leave 1038c0a211c5SRobert Watson * the port number intact after the connection is dropped. 1039c0a211c5SRobert Watson * 1040c0a211c5SRobert Watson * XXXRW: Possibly in_pcbdrop() should also prevent future notifications by 1041c0a211c5SRobert Watson * in_pcbnotifyall() and in_pcbpurgeif0()? 104210702a28SRobert Watson */ 104310702a28SRobert Watson void 104410702a28SRobert Watson in_pcbdrop(struct inpcb *inp) 104510702a28SRobert Watson { 104610702a28SRobert Watson 10477c5a8ab2SMarcel Moolenaar INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 10488501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 104910702a28SRobert Watson 1050ad71fe3cSRobert Watson inp->inp_flags |= INP_DROPPED; 1051111d57a6SRobert Watson if (inp->inp_flags & INP_INHASHLIST) { 105210702a28SRobert Watson struct inpcbport *phd = inp->inp_phd; 105310702a28SRobert Watson 105410702a28SRobert Watson LIST_REMOVE(inp, inp_hash); 105510702a28SRobert Watson LIST_REMOVE(inp, inp_portlist); 105610702a28SRobert Watson if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 105710702a28SRobert Watson LIST_REMOVE(phd, phd_hash); 105810702a28SRobert Watson free(phd, M_PCB); 105910702a28SRobert Watson } 1060111d57a6SRobert Watson inp->inp_flags &= ~INP_INHASHLIST; 106110702a28SRobert Watson } 106210702a28SRobert Watson } 106310702a28SRobert Watson 106454d642bbSRobert Watson /* 106554d642bbSRobert Watson * Common routines to return the socket addresses associated with inpcbs. 106654d642bbSRobert Watson */ 106726ef6ac4SDon Lewis struct sockaddr * 1068136d4f1cSRobert Watson in_sockaddr(in_port_t port, struct in_addr *addr_p) 106926ef6ac4SDon Lewis { 107026ef6ac4SDon Lewis struct sockaddr_in *sin; 107126ef6ac4SDon Lewis 10721ede983cSDag-Erling Smørgrav sin = malloc(sizeof *sin, M_SONAME, 1073a163d034SWarner Losh M_WAITOK | M_ZERO); 107426ef6ac4SDon Lewis sin->sin_family = AF_INET; 107526ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 107626ef6ac4SDon Lewis sin->sin_addr = *addr_p; 107726ef6ac4SDon Lewis sin->sin_port = port; 107826ef6ac4SDon Lewis 107926ef6ac4SDon Lewis return (struct sockaddr *)sin; 108026ef6ac4SDon Lewis } 108126ef6ac4SDon Lewis 1082117bcae7SGarrett Wollman int 108354d642bbSRobert Watson in_getsockaddr(struct socket *so, struct sockaddr **nam) 1084df8bae1dSRodney W. Grimes { 1085136d4f1cSRobert Watson struct inpcb *inp; 108626ef6ac4SDon Lewis struct in_addr addr; 108726ef6ac4SDon Lewis in_port_t port; 108842fa505bSDavid Greenman 1089fdc984f7STor Egge inp = sotoinpcb(so); 109054d642bbSRobert Watson KASSERT(inp != NULL, ("in_getsockaddr: inp == NULL")); 10916466b28aSRobert Watson 1092a69042a5SRobert Watson INP_RLOCK(inp); 109326ef6ac4SDon Lewis port = inp->inp_lport; 109426ef6ac4SDon Lewis addr = inp->inp_laddr; 1095a69042a5SRobert Watson INP_RUNLOCK(inp); 109642fa505bSDavid Greenman 109726ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 1098117bcae7SGarrett Wollman return 0; 1099df8bae1dSRodney W. Grimes } 1100df8bae1dSRodney W. Grimes 1101117bcae7SGarrett Wollman int 110254d642bbSRobert Watson in_getpeeraddr(struct socket *so, struct sockaddr **nam) 1103df8bae1dSRodney W. Grimes { 1104136d4f1cSRobert Watson struct inpcb *inp; 110526ef6ac4SDon Lewis struct in_addr addr; 110626ef6ac4SDon Lewis in_port_t port; 110742fa505bSDavid Greenman 1108fdc984f7STor Egge inp = sotoinpcb(so); 110954d642bbSRobert Watson KASSERT(inp != NULL, ("in_getpeeraddr: inp == NULL")); 11106466b28aSRobert Watson 1111a69042a5SRobert Watson INP_RLOCK(inp); 111226ef6ac4SDon Lewis port = inp->inp_fport; 111326ef6ac4SDon Lewis addr = inp->inp_faddr; 1114a69042a5SRobert Watson INP_RUNLOCK(inp); 111542fa505bSDavid Greenman 111626ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 1117117bcae7SGarrett Wollman return 0; 1118df8bae1dSRodney W. Grimes } 1119df8bae1dSRodney W. Grimes 112026f9a767SRodney W. Grimes void 1121136d4f1cSRobert Watson in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr faddr, int errno, 1122136d4f1cSRobert Watson struct inpcb *(*notify)(struct inpcb *, int)) 1123d1c54148SJesper Skriver { 1124f457d580SRobert Watson struct inpcb *inp, *inp_temp; 1125d1c54148SJesper Skriver 11263dc7ebf9SJeffrey Hsu INP_INFO_WLOCK(pcbinfo); 1127f457d580SRobert Watson LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { 11288501a69cSRobert Watson INP_WLOCK(inp); 1129d1c54148SJesper Skriver #ifdef INET6 1130f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 11318501a69cSRobert Watson INP_WUNLOCK(inp); 1132d1c54148SJesper Skriver continue; 1133f76fcf6dSJeffrey Hsu } 1134d1c54148SJesper Skriver #endif 1135d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 1136f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 11378501a69cSRobert Watson INP_WUNLOCK(inp); 1138d1c54148SJesper Skriver continue; 1139d1c54148SJesper Skriver } 11403dc7ebf9SJeffrey Hsu if ((*notify)(inp, errno)) 11418501a69cSRobert Watson INP_WUNLOCK(inp); 1142f76fcf6dSJeffrey Hsu } 11433dc7ebf9SJeffrey Hsu INP_INFO_WUNLOCK(pcbinfo); 1144d1c54148SJesper Skriver } 1145d1c54148SJesper Skriver 1146e43cc4aeSHajimu UMEMOTO void 1147136d4f1cSRobert Watson in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) 1148e43cc4aeSHajimu UMEMOTO { 1149e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 1150e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 1151e43cc4aeSHajimu UMEMOTO int i, gap; 1152e43cc4aeSHajimu UMEMOTO 1153f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 1154712fc218SRobert Watson LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { 11558501a69cSRobert Watson INP_WLOCK(inp); 1156e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 1157e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 1158e43cc4aeSHajimu UMEMOTO imo != NULL) { 1159e43cc4aeSHajimu UMEMOTO /* 1160e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 1161e43cc4aeSHajimu UMEMOTO * detached. 1162e43cc4aeSHajimu UMEMOTO */ 1163e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 1164e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 1165e43cc4aeSHajimu UMEMOTO 1166e43cc4aeSHajimu UMEMOTO /* 1167e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 1168e43cc4aeSHajimu UMEMOTO * through the interface being detached. 1169e43cc4aeSHajimu UMEMOTO */ 1170e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 1171e43cc4aeSHajimu UMEMOTO i++) { 1172e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 1173e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 1174e43cc4aeSHajimu UMEMOTO gap++; 1175e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 1176e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 1177e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 1178e43cc4aeSHajimu UMEMOTO } 1179e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 1180e43cc4aeSHajimu UMEMOTO } 11818501a69cSRobert Watson INP_WUNLOCK(inp); 1182e43cc4aeSHajimu UMEMOTO } 11833cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 1184e43cc4aeSHajimu UMEMOTO } 1185e43cc4aeSHajimu UMEMOTO 1186df8bae1dSRodney W. Grimes /* 1187c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 1188c3229e05SDavid Greenman */ 1189d5e8a67eSHajimu UMEMOTO #define INP_LOOKUP_MAPPED_PCB_COST 3 1190df8bae1dSRodney W. Grimes struct inpcb * 1191136d4f1cSRobert Watson in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr, 1192078b7042SBjoern A. Zeeb u_short lport, int wild_okay, struct ucred *cred) 1193df8bae1dSRodney W. Grimes { 1194136d4f1cSRobert Watson struct inpcb *inp; 1195d5e8a67eSHajimu UMEMOTO #ifdef INET6 1196d5e8a67eSHajimu UMEMOTO int matchwild = 3 + INP_LOOKUP_MAPPED_PCB_COST; 1197d5e8a67eSHajimu UMEMOTO #else 1198d5e8a67eSHajimu UMEMOTO int matchwild = 3; 1199d5e8a67eSHajimu UMEMOTO #endif 1200d5e8a67eSHajimu UMEMOTO int wildcard; 12017bc4aca7SDavid Greenman 12028501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 12031b73ca0bSSam Leffler 1204c3229e05SDavid Greenman if (!wild_okay) { 1205c3229e05SDavid Greenman struct inpcbhead *head; 1206c3229e05SDavid Greenman /* 1207c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 1208c3229e05SDavid Greenman * matches the local address and port we're looking for. 1209c3229e05SDavid Greenman */ 1210712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1211712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1212fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1213cfa1ca9dSYoshinobu Inoue #ifdef INET6 1214413628a7SBjoern A. Zeeb /* XXX inp locking */ 1215369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1216cfa1ca9dSYoshinobu Inoue continue; 1217cfa1ca9dSYoshinobu Inoue #endif 1218c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1219c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1220c3229e05SDavid Greenman inp->inp_lport == lport) { 1221c3229e05SDavid Greenman /* 1222413628a7SBjoern A. Zeeb * Found? 1223c3229e05SDavid Greenman */ 1224413628a7SBjoern A. Zeeb if (cred == NULL || 1225413628a7SBjoern A. Zeeb inp->inp_cred->cr_prison == cred->cr_prison) 1226c3229e05SDavid Greenman return (inp); 1227df8bae1dSRodney W. Grimes } 1228c3229e05SDavid Greenman } 1229c3229e05SDavid Greenman /* 1230c3229e05SDavid Greenman * Not found. 1231c3229e05SDavid Greenman */ 1232c3229e05SDavid Greenman return (NULL); 1233c3229e05SDavid Greenman } else { 1234c3229e05SDavid Greenman struct inpcbporthead *porthash; 1235c3229e05SDavid Greenman struct inpcbport *phd; 1236c3229e05SDavid Greenman struct inpcb *match = NULL; 1237c3229e05SDavid Greenman /* 1238c3229e05SDavid Greenman * Best fit PCB lookup. 1239c3229e05SDavid Greenman * 1240c3229e05SDavid Greenman * First see if this local port is in use by looking on the 1241c3229e05SDavid Greenman * port hash list. 1242c3229e05SDavid Greenman */ 1243712fc218SRobert Watson porthash = &pcbinfo->ipi_porthashbase[INP_PCBPORTHASH(lport, 1244712fc218SRobert Watson pcbinfo->ipi_porthashmask)]; 1245fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 1246c3229e05SDavid Greenman if (phd->phd_port == lport) 1247c3229e05SDavid Greenman break; 1248c3229e05SDavid Greenman } 1249c3229e05SDavid Greenman if (phd != NULL) { 1250c3229e05SDavid Greenman /* 1251c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 1252c3229e05SDavid Greenman * fit. 1253c3229e05SDavid Greenman */ 125437d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 1255c3229e05SDavid Greenman wildcard = 0; 1256413628a7SBjoern A. Zeeb if (cred != NULL && 1257413628a7SBjoern A. Zeeb inp->inp_cred->cr_prison != cred->cr_prison) 1258413628a7SBjoern A. Zeeb continue; 1259cfa1ca9dSYoshinobu Inoue #ifdef INET6 1260413628a7SBjoern A. Zeeb /* XXX inp locking */ 1261369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1262cfa1ca9dSYoshinobu Inoue continue; 1263d5e8a67eSHajimu UMEMOTO /* 1264d5e8a67eSHajimu UMEMOTO * We never select the PCB that has 1265d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag and is bound to :: if 1266d5e8a67eSHajimu UMEMOTO * we have another PCB which is bound 1267d5e8a67eSHajimu UMEMOTO * to 0.0.0.0. If a PCB has the 1268d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag, then we set its cost 1269d5e8a67eSHajimu UMEMOTO * higher than IPv4 only PCBs. 1270d5e8a67eSHajimu UMEMOTO * 1271d5e8a67eSHajimu UMEMOTO * Note that the case only happens 1272d5e8a67eSHajimu UMEMOTO * when a socket is bound to ::, under 1273d5e8a67eSHajimu UMEMOTO * the condition that the use of the 1274d5e8a67eSHajimu UMEMOTO * mapped address is allowed. 1275d5e8a67eSHajimu UMEMOTO */ 1276d5e8a67eSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV6) != 0) 1277d5e8a67eSHajimu UMEMOTO wildcard += INP_LOOKUP_MAPPED_PCB_COST; 1278cfa1ca9dSYoshinobu Inoue #endif 1279c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 1280c3229e05SDavid Greenman wildcard++; 128115bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 128215bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 128315bd2b43SDavid Greenman wildcard++; 128415bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 128515bd2b43SDavid Greenman continue; 128615bd2b43SDavid Greenman } else { 128715bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 128815bd2b43SDavid Greenman wildcard++; 128915bd2b43SDavid Greenman } 1290df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 1291df8bae1dSRodney W. Grimes match = inp; 1292df8bae1dSRodney W. Grimes matchwild = wildcard; 1293413628a7SBjoern A. Zeeb if (matchwild == 0) 1294df8bae1dSRodney W. Grimes break; 1295df8bae1dSRodney W. Grimes } 1296df8bae1dSRodney W. Grimes } 12973dbdc25cSDavid Greenman } 1298df8bae1dSRodney W. Grimes return (match); 1299df8bae1dSRodney W. Grimes } 1300c3229e05SDavid Greenman } 1301d5e8a67eSHajimu UMEMOTO #undef INP_LOOKUP_MAPPED_PCB_COST 130215bd2b43SDavid Greenman 130315bd2b43SDavid Greenman /* 130415bd2b43SDavid Greenman * Lookup PCB in hash list. 130515bd2b43SDavid Greenman */ 130615bd2b43SDavid Greenman struct inpcb * 1307136d4f1cSRobert Watson in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr, 1308136d4f1cSRobert Watson u_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard, 1309136d4f1cSRobert Watson struct ifnet *ifp) 131015bd2b43SDavid Greenman { 131115bd2b43SDavid Greenman struct inpcbhead *head; 1312413628a7SBjoern A. Zeeb struct inpcb *inp, *tmpinp; 131315bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 131415bd2b43SDavid Greenman 13158501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 1316602cc7f1SRobert Watson 131715bd2b43SDavid Greenman /* 131815bd2b43SDavid Greenman * First look for an exact match. 131915bd2b43SDavid Greenman */ 1320413628a7SBjoern A. Zeeb tmpinp = NULL; 1321712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, 1322712fc218SRobert Watson pcbinfo->ipi_hashmask)]; 1323fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1324cfa1ca9dSYoshinobu Inoue #ifdef INET6 1325413628a7SBjoern A. Zeeb /* XXX inp locking */ 1326369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1327cfa1ca9dSYoshinobu Inoue continue; 1328cfa1ca9dSYoshinobu Inoue #endif 13296d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 1330ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1331ca98b82cSDavid Greenman inp->inp_fport == fport && 1332413628a7SBjoern A. Zeeb inp->inp_lport == lport) { 1333413628a7SBjoern A. Zeeb /* 1334413628a7SBjoern A. Zeeb * XXX We should be able to directly return 1335413628a7SBjoern A. Zeeb * the inp here, without any checks. 1336413628a7SBjoern A. Zeeb * Well unless both bound with SO_REUSEPORT? 1337413628a7SBjoern A. Zeeb */ 1338413628a7SBjoern A. Zeeb if (jailed(inp->inp_cred)) 1339c3229e05SDavid Greenman return (inp); 1340413628a7SBjoern A. Zeeb if (tmpinp == NULL) 1341413628a7SBjoern A. Zeeb tmpinp = inp; 1342c3229e05SDavid Greenman } 1343413628a7SBjoern A. Zeeb } 1344413628a7SBjoern A. Zeeb if (tmpinp != NULL) 1345413628a7SBjoern A. Zeeb return (tmpinp); 1346e3fd5ffdSRobert Watson 1347e3fd5ffdSRobert Watson /* 1348e3fd5ffdSRobert Watson * Then look for a wildcard match, if requested. 1349e3fd5ffdSRobert Watson */ 1350413628a7SBjoern A. Zeeb if (wildcard == INPLOOKUP_WILDCARD) { 1351413628a7SBjoern A. Zeeb struct inpcb *local_wild = NULL, *local_exact = NULL; 1352e3fd5ffdSRobert Watson #ifdef INET6 1353cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 1354e3fd5ffdSRobert Watson #endif 1355413628a7SBjoern A. Zeeb struct inpcb *jail_wild = NULL; 1356413628a7SBjoern A. Zeeb int injail; 1357413628a7SBjoern A. Zeeb 1358413628a7SBjoern A. Zeeb /* 1359413628a7SBjoern A. Zeeb * Order of socket selection - we always prefer jails. 1360413628a7SBjoern A. Zeeb * 1. jailed, non-wild. 1361413628a7SBjoern A. Zeeb * 2. jailed, wild. 1362413628a7SBjoern A. Zeeb * 3. non-jailed, non-wild. 1363413628a7SBjoern A. Zeeb * 4. non-jailed, wild. 1364413628a7SBjoern A. Zeeb */ 13656d6a026bSDavid Greenman 1366712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1367712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1368fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1369cfa1ca9dSYoshinobu Inoue #ifdef INET6 1370413628a7SBjoern A. Zeeb /* XXX inp locking */ 1371369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1372cfa1ca9dSYoshinobu Inoue continue; 1373cfa1ca9dSYoshinobu Inoue #endif 1374413628a7SBjoern A. Zeeb if (inp->inp_faddr.s_addr != INADDR_ANY || 1375413628a7SBjoern A. Zeeb inp->inp_lport != lport) 1376413628a7SBjoern A. Zeeb continue; 1377413628a7SBjoern A. Zeeb 1378413628a7SBjoern A. Zeeb /* XXX inp locking */ 1379cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 1380cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 1381cfa1ca9dSYoshinobu Inoue continue; 1382413628a7SBjoern A. Zeeb 1383413628a7SBjoern A. Zeeb injail = jailed(inp->inp_cred); 1384413628a7SBjoern A. Zeeb if (injail) { 1385b89e82ddSJamie Gritton if (prison_check_ip4(inp->inp_cred, 1386b89e82ddSJamie Gritton &laddr) != 0) 1387413628a7SBjoern A. Zeeb continue; 1388413628a7SBjoern A. Zeeb } else { 1389413628a7SBjoern A. Zeeb if (local_exact != NULL) 1390413628a7SBjoern A. Zeeb continue; 1391413628a7SBjoern A. Zeeb } 1392413628a7SBjoern A. Zeeb 1393413628a7SBjoern A. Zeeb if (inp->inp_laddr.s_addr == laddr.s_addr) { 1394413628a7SBjoern A. Zeeb if (injail) 1395c3229e05SDavid Greenman return (inp); 1396413628a7SBjoern A. Zeeb else 1397413628a7SBjoern A. Zeeb local_exact = inp; 1398413628a7SBjoern A. Zeeb } else if (inp->inp_laddr.s_addr == INADDR_ANY) { 1399e3fd5ffdSRobert Watson #ifdef INET6 1400413628a7SBjoern A. Zeeb /* XXX inp locking, NULL check */ 14015cd54324SBjoern A. Zeeb if (inp->inp_vflag & INP_IPV6PROTO) 1402cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 1403cfa1ca9dSYoshinobu Inoue else 1404413628a7SBjoern A. Zeeb #endif /* INET6 */ 1405413628a7SBjoern A. Zeeb if (injail) 1406413628a7SBjoern A. Zeeb jail_wild = inp; 1407413628a7SBjoern A. Zeeb else 14086d6a026bSDavid Greenman local_wild = inp; 14096d6a026bSDavid Greenman } 1410413628a7SBjoern A. Zeeb } /* LIST_FOREACH */ 1411413628a7SBjoern A. Zeeb if (jail_wild != NULL) 1412413628a7SBjoern A. Zeeb return (jail_wild); 1413413628a7SBjoern A. Zeeb if (local_exact != NULL) 1414413628a7SBjoern A. Zeeb return (local_exact); 1415413628a7SBjoern A. Zeeb if (local_wild != NULL) 1416c3229e05SDavid Greenman return (local_wild); 1417413628a7SBjoern A. Zeeb #ifdef INET6 1418413628a7SBjoern A. Zeeb if (local_wild_mapped != NULL) 1419413628a7SBjoern A. Zeeb return (local_wild_mapped); 1420413628a7SBjoern A. Zeeb #endif /* defined(INET6) */ 1421413628a7SBjoern A. Zeeb } /* if (wildcard == INPLOOKUP_WILDCARD) */ 1422413628a7SBjoern A. Zeeb 14236d6a026bSDavid Greenman return (NULL); 142415bd2b43SDavid Greenman } 142515bd2b43SDavid Greenman 14267bc4aca7SDavid Greenman /* 1427c3229e05SDavid Greenman * Insert PCB onto various hash lists. 14287bc4aca7SDavid Greenman */ 1429c3229e05SDavid Greenman int 1430136d4f1cSRobert Watson in_pcbinshash(struct inpcb *inp) 143115bd2b43SDavid Greenman { 1432c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1433c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1434c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1435c3229e05SDavid Greenman struct inpcbport *phd; 1436cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 143715bd2b43SDavid Greenman 143859daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 14398501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1440111d57a6SRobert Watson KASSERT((inp->inp_flags & INP_INHASHLIST) == 0, 1441111d57a6SRobert Watson ("in_pcbinshash: INP_INHASHLIST")); 1442602cc7f1SRobert Watson 1443cfa1ca9dSYoshinobu Inoue #ifdef INET6 1444cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1445cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1446cfa1ca9dSYoshinobu Inoue else 1447cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1448cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1449cfa1ca9dSYoshinobu Inoue 1450712fc218SRobert Watson pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1451712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 145215bd2b43SDavid Greenman 1453712fc218SRobert Watson pcbporthash = &pcbinfo->ipi_porthashbase[ 1454712fc218SRobert Watson INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; 1455c3229e05SDavid Greenman 1456c3229e05SDavid Greenman /* 1457c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1458c3229e05SDavid Greenman */ 1459fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1460c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1461c3229e05SDavid Greenman break; 1462c3229e05SDavid Greenman } 1463c3229e05SDavid Greenman /* 1464c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1465c3229e05SDavid Greenman */ 1466c3229e05SDavid Greenman if (phd == NULL) { 14671ede983cSDag-Erling Smørgrav phd = malloc(sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1468c3229e05SDavid Greenman if (phd == NULL) { 1469c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1470c3229e05SDavid Greenman } 1471c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1472c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1473c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1474c3229e05SDavid Greenman } 1475c3229e05SDavid Greenman inp->inp_phd = phd; 1476c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1477c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1478111d57a6SRobert Watson inp->inp_flags |= INP_INHASHLIST; 1479c3229e05SDavid Greenman return (0); 148015bd2b43SDavid Greenman } 148115bd2b43SDavid Greenman 1482c3229e05SDavid Greenman /* 1483c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1484c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1485c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1486c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1487c3229e05SDavid Greenman */ 148815bd2b43SDavid Greenman void 1489136d4f1cSRobert Watson in_pcbrehash(struct inpcb *inp) 149015bd2b43SDavid Greenman { 149159daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 149215bd2b43SDavid Greenman struct inpcbhead *head; 1493cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 149415bd2b43SDavid Greenman 149559daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 14968501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1497111d57a6SRobert Watson KASSERT(inp->inp_flags & INP_INHASHLIST, 1498111d57a6SRobert Watson ("in_pcbrehash: !INP_INHASHLIST")); 1499602cc7f1SRobert Watson 1500cfa1ca9dSYoshinobu Inoue #ifdef INET6 1501cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1502cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1503cfa1ca9dSYoshinobu Inoue else 1504cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1505cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1506cfa1ca9dSYoshinobu Inoue 1507712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1508712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 150915bd2b43SDavid Greenman 1510c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 151115bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1512c3229e05SDavid Greenman } 1513c3229e05SDavid Greenman 1514c3229e05SDavid Greenman /* 1515c3229e05SDavid Greenman * Remove PCB from various lists. 1516c3229e05SDavid Greenman */ 15176d888973SRobert Watson static void 1518136d4f1cSRobert Watson in_pcbremlists(struct inpcb *inp) 1519c3229e05SDavid Greenman { 152059daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 152159daba27SSam Leffler 152259daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 15238501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 152459daba27SSam Leffler 152559daba27SSam Leffler inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 1526111d57a6SRobert Watson if (inp->inp_flags & INP_INHASHLIST) { 1527c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1528c3229e05SDavid Greenman 1529c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1530c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1531fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1532c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1533c3229e05SDavid Greenman free(phd, M_PCB); 1534c3229e05SDavid Greenman } 1535111d57a6SRobert Watson inp->inp_flags &= ~INP_INHASHLIST; 1536c3229e05SDavid Greenman } 1537c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 153859daba27SSam Leffler pcbinfo->ipi_count--; 153915bd2b43SDavid Greenman } 154075c13541SPoul-Henning Kamp 1541a557af22SRobert Watson /* 1542a557af22SRobert Watson * A set label operation has occurred at the socket layer, propagate the 1543a557af22SRobert Watson * label change into the in_pcb for the socket. 1544a557af22SRobert Watson */ 1545a557af22SRobert Watson void 1546136d4f1cSRobert Watson in_pcbsosetlabel(struct socket *so) 1547a557af22SRobert Watson { 1548a557af22SRobert Watson #ifdef MAC 1549a557af22SRobert Watson struct inpcb *inp; 1550a557af22SRobert Watson 15514c7c478dSRobert Watson inp = sotoinpcb(so); 15524c7c478dSRobert Watson KASSERT(inp != NULL, ("in_pcbsosetlabel: so->so_pcb == NULL")); 1553602cc7f1SRobert Watson 15548501a69cSRobert Watson INP_WLOCK(inp); 1555310e7cebSRobert Watson SOCK_LOCK(so); 1556a557af22SRobert Watson mac_inpcb_sosetlabel(so, inp); 1557310e7cebSRobert Watson SOCK_UNLOCK(so); 15588501a69cSRobert Watson INP_WUNLOCK(inp); 1559a557af22SRobert Watson #endif 1560a557af22SRobert Watson } 15615f311da2SMike Silbersack 15625f311da2SMike Silbersack /* 1563ad3a630fSRobert Watson * ipport_tick runs once per second, determining if random port allocation 1564ad3a630fSRobert Watson * should be continued. If more than ipport_randomcps ports have been 1565ad3a630fSRobert Watson * allocated in the last second, then we return to sequential port 1566ad3a630fSRobert Watson * allocation. We return to random allocation only once we drop below 1567ad3a630fSRobert Watson * ipport_randomcps for at least ipport_randomtime seconds. 15685f311da2SMike Silbersack */ 15695f311da2SMike Silbersack void 1570136d4f1cSRobert Watson ipport_tick(void *xtp) 15715f311da2SMike Silbersack { 15728b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 1573ad3a630fSRobert Watson 15748b615593SMarko Zec VNET_LIST_RLOCK(); 15758b615593SMarko Zec VNET_FOREACH(vnet_iter) { 15768b615593SMarko Zec CURVNET_SET(vnet_iter); /* XXX appease INVARIANTS here */ 15778b615593SMarko Zec INIT_VNET_INET(vnet_iter); 15788b615593SMarko Zec if (V_ipport_tcpallocs <= 15798b615593SMarko Zec V_ipport_tcplastcount + V_ipport_randomcps) { 1580603724d3SBjoern A. Zeeb if (V_ipport_stoprandom > 0) 1581603724d3SBjoern A. Zeeb V_ipport_stoprandom--; 1582ad3a630fSRobert Watson } else 1583603724d3SBjoern A. Zeeb V_ipport_stoprandom = V_ipport_randomtime; 1584603724d3SBjoern A. Zeeb V_ipport_tcplastcount = V_ipport_tcpallocs; 15858b615593SMarko Zec CURVNET_RESTORE(); 15868b615593SMarko Zec } 15878b615593SMarko Zec VNET_LIST_RUNLOCK(); 15885f311da2SMike Silbersack callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL); 15895f311da2SMike Silbersack } 1590497057eeSRobert Watson 15913d585327SKip Macy void 15923d585327SKip Macy inp_wlock(struct inpcb *inp) 15933d585327SKip Macy { 15943d585327SKip Macy 15958501a69cSRobert Watson INP_WLOCK(inp); 15963d585327SKip Macy } 15973d585327SKip Macy 15983d585327SKip Macy void 15993d585327SKip Macy inp_wunlock(struct inpcb *inp) 16003d585327SKip Macy { 16013d585327SKip Macy 16028501a69cSRobert Watson INP_WUNLOCK(inp); 16033d585327SKip Macy } 16043d585327SKip Macy 16053d585327SKip Macy void 16063d585327SKip Macy inp_rlock(struct inpcb *inp) 16073d585327SKip Macy { 16083d585327SKip Macy 1609a69042a5SRobert Watson INP_RLOCK(inp); 16103d585327SKip Macy } 16113d585327SKip Macy 16123d585327SKip Macy void 16133d585327SKip Macy inp_runlock(struct inpcb *inp) 16143d585327SKip Macy { 16153d585327SKip Macy 1616a69042a5SRobert Watson INP_RUNLOCK(inp); 16173d585327SKip Macy } 16183d585327SKip Macy 16193d585327SKip Macy #ifdef INVARIANTS 16203d585327SKip Macy void 1621e79dd20dSKip Macy inp_lock_assert(struct inpcb *inp) 16223d585327SKip Macy { 16233d585327SKip Macy 16248501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 16253d585327SKip Macy } 16263d585327SKip Macy 16273d585327SKip Macy void 1628e79dd20dSKip Macy inp_unlock_assert(struct inpcb *inp) 16293d585327SKip Macy { 16303d585327SKip Macy 16313d585327SKip Macy INP_UNLOCK_ASSERT(inp); 16323d585327SKip Macy } 16333d585327SKip Macy #endif 16343d585327SKip Macy 16359378e437SKip Macy void 16369378e437SKip Macy inp_apply_all(void (*func)(struct inpcb *, void *), void *arg) 16379378e437SKip Macy { 16388b615593SMarko Zec INIT_VNET_INET(curvnet); 16399378e437SKip Macy struct inpcb *inp; 16409378e437SKip Macy 1641603724d3SBjoern A. Zeeb INP_INFO_RLOCK(&V_tcbinfo); 164297021c24SMarko Zec LIST_FOREACH(inp, V_tcbinfo.ipi_listhead, inp_list) { 16439378e437SKip Macy INP_WLOCK(inp); 16449378e437SKip Macy func(inp, arg); 16459378e437SKip Macy INP_WUNLOCK(inp); 16469378e437SKip Macy } 1647603724d3SBjoern A. Zeeb INP_INFO_RUNLOCK(&V_tcbinfo); 16489378e437SKip Macy } 16499378e437SKip Macy 16509378e437SKip Macy struct socket * 16519378e437SKip Macy inp_inpcbtosocket(struct inpcb *inp) 16529378e437SKip Macy { 16539378e437SKip Macy 16549378e437SKip Macy INP_WLOCK_ASSERT(inp); 16559378e437SKip Macy return (inp->inp_socket); 16569378e437SKip Macy } 16579378e437SKip Macy 16589378e437SKip Macy struct tcpcb * 16599378e437SKip Macy inp_inpcbtotcpcb(struct inpcb *inp) 16609378e437SKip Macy { 16619378e437SKip Macy 16629378e437SKip Macy INP_WLOCK_ASSERT(inp); 16639378e437SKip Macy return ((struct tcpcb *)inp->inp_ppcb); 16649378e437SKip Macy } 16659378e437SKip Macy 16669378e437SKip Macy int 16679378e437SKip Macy inp_ip_tos_get(const struct inpcb *inp) 16689378e437SKip Macy { 16699378e437SKip Macy 16709378e437SKip Macy return (inp->inp_ip_tos); 16719378e437SKip Macy } 16729378e437SKip Macy 16739378e437SKip Macy void 16749378e437SKip Macy inp_ip_tos_set(struct inpcb *inp, int val) 16759378e437SKip Macy { 16769378e437SKip Macy 16779378e437SKip Macy inp->inp_ip_tos = val; 16789378e437SKip Macy } 16799378e437SKip Macy 16809378e437SKip Macy void 1681df9cf830STai-hwa Liang inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, 16829d29c635SKip Macy uint32_t *faddr, uint16_t *fp) 16839378e437SKip Macy { 16849378e437SKip Macy 16859d29c635SKip Macy INP_LOCK_ASSERT(inp); 1686df9cf830STai-hwa Liang *laddr = inp->inp_laddr.s_addr; 1687df9cf830STai-hwa Liang *faddr = inp->inp_faddr.s_addr; 16889378e437SKip Macy *lp = inp->inp_lport; 16899378e437SKip Macy *fp = inp->inp_fport; 16909378e437SKip Macy } 16919378e437SKip Macy 1692dd0e6c38SKip Macy struct inpcb * 1693dd0e6c38SKip Macy so_sotoinpcb(struct socket *so) 1694dd0e6c38SKip Macy { 1695dd0e6c38SKip Macy 1696dd0e6c38SKip Macy return (sotoinpcb(so)); 1697dd0e6c38SKip Macy } 1698dd0e6c38SKip Macy 1699dd0e6c38SKip Macy struct tcpcb * 1700dd0e6c38SKip Macy so_sototcpcb(struct socket *so) 1701dd0e6c38SKip Macy { 1702dd0e6c38SKip Macy 1703dd0e6c38SKip Macy return (sototcpcb(so)); 1704dd0e6c38SKip Macy } 1705dd0e6c38SKip Macy 1706497057eeSRobert Watson #ifdef DDB 1707497057eeSRobert Watson static void 1708497057eeSRobert Watson db_print_indent(int indent) 1709497057eeSRobert Watson { 1710497057eeSRobert Watson int i; 1711497057eeSRobert Watson 1712497057eeSRobert Watson for (i = 0; i < indent; i++) 1713497057eeSRobert Watson db_printf(" "); 1714497057eeSRobert Watson } 1715497057eeSRobert Watson 1716497057eeSRobert Watson static void 1717497057eeSRobert Watson db_print_inconninfo(struct in_conninfo *inc, const char *name, int indent) 1718497057eeSRobert Watson { 1719497057eeSRobert Watson char faddr_str[48], laddr_str[48]; 1720497057eeSRobert Watson 1721497057eeSRobert Watson db_print_indent(indent); 1722497057eeSRobert Watson db_printf("%s at %p\n", name, inc); 1723497057eeSRobert Watson 1724497057eeSRobert Watson indent += 2; 1725497057eeSRobert Watson 172603dc38a4SRobert Watson #ifdef INET6 1727dcdb4371SBjoern A. Zeeb if (inc->inc_flags & INC_ISIPV6) { 1728497057eeSRobert Watson /* IPv6. */ 1729497057eeSRobert Watson ip6_sprintf(laddr_str, &inc->inc6_laddr); 1730497057eeSRobert Watson ip6_sprintf(faddr_str, &inc->inc6_faddr); 1731497057eeSRobert Watson } else { 173203dc38a4SRobert Watson #endif 1733497057eeSRobert Watson /* IPv4. */ 1734497057eeSRobert Watson inet_ntoa_r(inc->inc_laddr, laddr_str); 1735497057eeSRobert Watson inet_ntoa_r(inc->inc_faddr, faddr_str); 173603dc38a4SRobert Watson #ifdef INET6 1737497057eeSRobert Watson } 173803dc38a4SRobert Watson #endif 1739497057eeSRobert Watson db_print_indent(indent); 1740497057eeSRobert Watson db_printf("inc_laddr %s inc_lport %u\n", laddr_str, 1741497057eeSRobert Watson ntohs(inc->inc_lport)); 1742497057eeSRobert Watson db_print_indent(indent); 1743497057eeSRobert Watson db_printf("inc_faddr %s inc_fport %u\n", faddr_str, 1744497057eeSRobert Watson ntohs(inc->inc_fport)); 1745497057eeSRobert Watson } 1746497057eeSRobert Watson 1747497057eeSRobert Watson static void 1748497057eeSRobert Watson db_print_inpflags(int inp_flags) 1749497057eeSRobert Watson { 1750497057eeSRobert Watson int comma; 1751497057eeSRobert Watson 1752497057eeSRobert Watson comma = 0; 1753497057eeSRobert Watson if (inp_flags & INP_RECVOPTS) { 1754497057eeSRobert Watson db_printf("%sINP_RECVOPTS", comma ? ", " : ""); 1755497057eeSRobert Watson comma = 1; 1756497057eeSRobert Watson } 1757497057eeSRobert Watson if (inp_flags & INP_RECVRETOPTS) { 1758497057eeSRobert Watson db_printf("%sINP_RECVRETOPTS", comma ? ", " : ""); 1759497057eeSRobert Watson comma = 1; 1760497057eeSRobert Watson } 1761497057eeSRobert Watson if (inp_flags & INP_RECVDSTADDR) { 1762497057eeSRobert Watson db_printf("%sINP_RECVDSTADDR", comma ? ", " : ""); 1763497057eeSRobert Watson comma = 1; 1764497057eeSRobert Watson } 1765497057eeSRobert Watson if (inp_flags & INP_HDRINCL) { 1766497057eeSRobert Watson db_printf("%sINP_HDRINCL", comma ? ", " : ""); 1767497057eeSRobert Watson comma = 1; 1768497057eeSRobert Watson } 1769497057eeSRobert Watson if (inp_flags & INP_HIGHPORT) { 1770497057eeSRobert Watson db_printf("%sINP_HIGHPORT", comma ? ", " : ""); 1771497057eeSRobert Watson comma = 1; 1772497057eeSRobert Watson } 1773497057eeSRobert Watson if (inp_flags & INP_LOWPORT) { 1774497057eeSRobert Watson db_printf("%sINP_LOWPORT", comma ? ", " : ""); 1775497057eeSRobert Watson comma = 1; 1776497057eeSRobert Watson } 1777497057eeSRobert Watson if (inp_flags & INP_ANONPORT) { 1778497057eeSRobert Watson db_printf("%sINP_ANONPORT", comma ? ", " : ""); 1779497057eeSRobert Watson comma = 1; 1780497057eeSRobert Watson } 1781497057eeSRobert Watson if (inp_flags & INP_RECVIF) { 1782497057eeSRobert Watson db_printf("%sINP_RECVIF", comma ? ", " : ""); 1783497057eeSRobert Watson comma = 1; 1784497057eeSRobert Watson } 1785497057eeSRobert Watson if (inp_flags & INP_MTUDISC) { 1786497057eeSRobert Watson db_printf("%sINP_MTUDISC", comma ? ", " : ""); 1787497057eeSRobert Watson comma = 1; 1788497057eeSRobert Watson } 1789497057eeSRobert Watson if (inp_flags & INP_FAITH) { 1790497057eeSRobert Watson db_printf("%sINP_FAITH", comma ? ", " : ""); 1791497057eeSRobert Watson comma = 1; 1792497057eeSRobert Watson } 1793497057eeSRobert Watson if (inp_flags & INP_RECVTTL) { 1794497057eeSRobert Watson db_printf("%sINP_RECVTTL", comma ? ", " : ""); 1795497057eeSRobert Watson comma = 1; 1796497057eeSRobert Watson } 1797497057eeSRobert Watson if (inp_flags & INP_DONTFRAG) { 1798497057eeSRobert Watson db_printf("%sINP_DONTFRAG", comma ? ", " : ""); 1799497057eeSRobert Watson comma = 1; 1800497057eeSRobert Watson } 1801497057eeSRobert Watson if (inp_flags & IN6P_IPV6_V6ONLY) { 1802497057eeSRobert Watson db_printf("%sIN6P_IPV6_V6ONLY", comma ? ", " : ""); 1803497057eeSRobert Watson comma = 1; 1804497057eeSRobert Watson } 1805497057eeSRobert Watson if (inp_flags & IN6P_PKTINFO) { 1806497057eeSRobert Watson db_printf("%sIN6P_PKTINFO", comma ? ", " : ""); 1807497057eeSRobert Watson comma = 1; 1808497057eeSRobert Watson } 1809497057eeSRobert Watson if (inp_flags & IN6P_HOPLIMIT) { 1810497057eeSRobert Watson db_printf("%sIN6P_HOPLIMIT", comma ? ", " : ""); 1811497057eeSRobert Watson comma = 1; 1812497057eeSRobert Watson } 1813497057eeSRobert Watson if (inp_flags & IN6P_HOPOPTS) { 1814497057eeSRobert Watson db_printf("%sIN6P_HOPOPTS", comma ? ", " : ""); 1815497057eeSRobert Watson comma = 1; 1816497057eeSRobert Watson } 1817497057eeSRobert Watson if (inp_flags & IN6P_DSTOPTS) { 1818497057eeSRobert Watson db_printf("%sIN6P_DSTOPTS", comma ? ", " : ""); 1819497057eeSRobert Watson comma = 1; 1820497057eeSRobert Watson } 1821497057eeSRobert Watson if (inp_flags & IN6P_RTHDR) { 1822497057eeSRobert Watson db_printf("%sIN6P_RTHDR", comma ? ", " : ""); 1823497057eeSRobert Watson comma = 1; 1824497057eeSRobert Watson } 1825497057eeSRobert Watson if (inp_flags & IN6P_RTHDRDSTOPTS) { 1826497057eeSRobert Watson db_printf("%sIN6P_RTHDRDSTOPTS", comma ? ", " : ""); 1827497057eeSRobert Watson comma = 1; 1828497057eeSRobert Watson } 1829497057eeSRobert Watson if (inp_flags & IN6P_TCLASS) { 1830497057eeSRobert Watson db_printf("%sIN6P_TCLASS", comma ? ", " : ""); 1831497057eeSRobert Watson comma = 1; 1832497057eeSRobert Watson } 1833497057eeSRobert Watson if (inp_flags & IN6P_AUTOFLOWLABEL) { 1834497057eeSRobert Watson db_printf("%sIN6P_AUTOFLOWLABEL", comma ? ", " : ""); 1835497057eeSRobert Watson comma = 1; 1836497057eeSRobert Watson } 1837ad71fe3cSRobert Watson if (inp_flags & INP_TIMEWAIT) { 1838ad71fe3cSRobert Watson db_printf("%sINP_TIMEWAIT", comma ? ", " : ""); 1839ad71fe3cSRobert Watson comma = 1; 1840ad71fe3cSRobert Watson } 1841ad71fe3cSRobert Watson if (inp_flags & INP_ONESBCAST) { 1842ad71fe3cSRobert Watson db_printf("%sINP_ONESBCAST", comma ? ", " : ""); 1843ad71fe3cSRobert Watson comma = 1; 1844ad71fe3cSRobert Watson } 1845ad71fe3cSRobert Watson if (inp_flags & INP_DROPPED) { 1846ad71fe3cSRobert Watson db_printf("%sINP_DROPPED", comma ? ", " : ""); 1847ad71fe3cSRobert Watson comma = 1; 1848ad71fe3cSRobert Watson } 1849ad71fe3cSRobert Watson if (inp_flags & INP_SOCKREF) { 1850ad71fe3cSRobert Watson db_printf("%sINP_SOCKREF", comma ? ", " : ""); 1851ad71fe3cSRobert Watson comma = 1; 1852ad71fe3cSRobert Watson } 1853497057eeSRobert Watson if (inp_flags & IN6P_RFC2292) { 1854497057eeSRobert Watson db_printf("%sIN6P_RFC2292", comma ? ", " : ""); 1855497057eeSRobert Watson comma = 1; 1856497057eeSRobert Watson } 1857497057eeSRobert Watson if (inp_flags & IN6P_MTU) { 1858497057eeSRobert Watson db_printf("IN6P_MTU%s", comma ? ", " : ""); 1859497057eeSRobert Watson comma = 1; 1860497057eeSRobert Watson } 1861497057eeSRobert Watson } 1862497057eeSRobert Watson 1863497057eeSRobert Watson static void 1864497057eeSRobert Watson db_print_inpvflag(u_char inp_vflag) 1865497057eeSRobert Watson { 1866497057eeSRobert Watson int comma; 1867497057eeSRobert Watson 1868497057eeSRobert Watson comma = 0; 1869497057eeSRobert Watson if (inp_vflag & INP_IPV4) { 1870497057eeSRobert Watson db_printf("%sINP_IPV4", comma ? ", " : ""); 1871497057eeSRobert Watson comma = 1; 1872497057eeSRobert Watson } 1873497057eeSRobert Watson if (inp_vflag & INP_IPV6) { 1874497057eeSRobert Watson db_printf("%sINP_IPV6", comma ? ", " : ""); 1875497057eeSRobert Watson comma = 1; 1876497057eeSRobert Watson } 1877497057eeSRobert Watson if (inp_vflag & INP_IPV6PROTO) { 1878497057eeSRobert Watson db_printf("%sINP_IPV6PROTO", comma ? ", " : ""); 1879497057eeSRobert Watson comma = 1; 1880497057eeSRobert Watson } 1881497057eeSRobert Watson } 1882497057eeSRobert Watson 18836d888973SRobert Watson static void 1884497057eeSRobert Watson db_print_inpcb(struct inpcb *inp, const char *name, int indent) 1885497057eeSRobert Watson { 1886497057eeSRobert Watson 1887497057eeSRobert Watson db_print_indent(indent); 1888497057eeSRobert Watson db_printf("%s at %p\n", name, inp); 1889497057eeSRobert Watson 1890497057eeSRobert Watson indent += 2; 1891497057eeSRobert Watson 1892497057eeSRobert Watson db_print_indent(indent); 1893497057eeSRobert Watson db_printf("inp_flow: 0x%x\n", inp->inp_flow); 1894497057eeSRobert Watson 1895497057eeSRobert Watson db_print_inconninfo(&inp->inp_inc, "inp_conninfo", indent); 1896497057eeSRobert Watson 1897497057eeSRobert Watson db_print_indent(indent); 1898497057eeSRobert Watson db_printf("inp_ppcb: %p inp_pcbinfo: %p inp_socket: %p\n", 1899497057eeSRobert Watson inp->inp_ppcb, inp->inp_pcbinfo, inp->inp_socket); 1900497057eeSRobert Watson 1901497057eeSRobert Watson db_print_indent(indent); 1902497057eeSRobert Watson db_printf("inp_label: %p inp_flags: 0x%x (", 1903497057eeSRobert Watson inp->inp_label, inp->inp_flags); 1904497057eeSRobert Watson db_print_inpflags(inp->inp_flags); 1905497057eeSRobert Watson db_printf(")\n"); 1906497057eeSRobert Watson 1907497057eeSRobert Watson db_print_indent(indent); 1908497057eeSRobert Watson db_printf("inp_sp: %p inp_vflag: 0x%x (", inp->inp_sp, 1909497057eeSRobert Watson inp->inp_vflag); 1910497057eeSRobert Watson db_print_inpvflag(inp->inp_vflag); 1911497057eeSRobert Watson db_printf(")\n"); 1912497057eeSRobert Watson 1913497057eeSRobert Watson db_print_indent(indent); 1914497057eeSRobert Watson db_printf("inp_ip_ttl: %d inp_ip_p: %d inp_ip_minttl: %d\n", 1915497057eeSRobert Watson inp->inp_ip_ttl, inp->inp_ip_p, inp->inp_ip_minttl); 1916497057eeSRobert Watson 1917497057eeSRobert Watson db_print_indent(indent); 1918497057eeSRobert Watson #ifdef INET6 1919497057eeSRobert Watson if (inp->inp_vflag & INP_IPV6) { 1920497057eeSRobert Watson db_printf("in6p_options: %p in6p_outputopts: %p " 1921497057eeSRobert Watson "in6p_moptions: %p\n", inp->in6p_options, 1922497057eeSRobert Watson inp->in6p_outputopts, inp->in6p_moptions); 1923497057eeSRobert Watson db_printf("in6p_icmp6filt: %p in6p_cksum %d " 1924497057eeSRobert Watson "in6p_hops %u\n", inp->in6p_icmp6filt, inp->in6p_cksum, 1925497057eeSRobert Watson inp->in6p_hops); 1926497057eeSRobert Watson } else 1927497057eeSRobert Watson #endif 1928497057eeSRobert Watson { 1929497057eeSRobert Watson db_printf("inp_ip_tos: %d inp_ip_options: %p " 1930497057eeSRobert Watson "inp_ip_moptions: %p\n", inp->inp_ip_tos, 1931497057eeSRobert Watson inp->inp_options, inp->inp_moptions); 1932497057eeSRobert Watson } 1933497057eeSRobert Watson 1934497057eeSRobert Watson db_print_indent(indent); 1935497057eeSRobert Watson db_printf("inp_phd: %p inp_gencnt: %ju\n", inp->inp_phd, 1936497057eeSRobert Watson (uintmax_t)inp->inp_gencnt); 1937497057eeSRobert Watson } 1938497057eeSRobert Watson 1939497057eeSRobert Watson DB_SHOW_COMMAND(inpcb, db_show_inpcb) 1940497057eeSRobert Watson { 1941497057eeSRobert Watson struct inpcb *inp; 1942497057eeSRobert Watson 1943497057eeSRobert Watson if (!have_addr) { 1944497057eeSRobert Watson db_printf("usage: show inpcb <addr>\n"); 1945497057eeSRobert Watson return; 1946497057eeSRobert Watson } 1947497057eeSRobert Watson inp = (struct inpcb *)addr; 1948497057eeSRobert Watson 1949497057eeSRobert Watson db_print_inpcb(inp, "inpcb", 0); 1950497057eeSRobert Watson } 1951497057eeSRobert Watson #endif 1952