1c398230bSWarner Losh /*- 22469dd60SGarrett Wollman * Copyright (c) 1982, 1986, 1991, 1993, 1995 3497057eeSRobert Watson * The Regents of the University of California. 4497057eeSRobert Watson * Copyright (c) 2007 Robert N. M. Watson 5497057eeSRobert Watson * All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 312469dd60SGarrett Wollman * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 344b421e2dSMike Silbersack #include <sys/cdefs.h> 354b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 364b421e2dSMike Silbersack 37497057eeSRobert Watson #include "opt_ddb.h" 386a800098SYoshinobu Inoue #include "opt_ipsec.h" 39cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 40a557af22SRobert Watson #include "opt_mac.h" 41cfa1ca9dSYoshinobu Inoue 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/malloc.h> 45df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 47df8bae1dSRodney W. Grimes #include <sys/protosw.h> 48df8bae1dSRodney W. Grimes #include <sys/socket.h> 49df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 50acd3428bSRobert Watson #include <sys/priv.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 5275c13541SPoul-Henning Kamp #include <sys/jail.h> 53101f9fc8SPeter Wemm #include <sys/kernel.h> 54101f9fc8SPeter Wemm #include <sys/sysctl.h> 55603724d3SBjoern A. Zeeb #include <sys/vimage.h> 568781d8e9SBruce Evans 57497057eeSRobert Watson #ifdef DDB 58497057eeSRobert Watson #include <ddb/ddb.h> 59497057eeSRobert Watson #endif 60497057eeSRobert Watson 6169c2d429SJeff Roberson #include <vm/uma.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <net/if.h> 64cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 65df8bae1dSRodney W. Grimes #include <net/route.h> 66df8bae1dSRodney W. Grimes 67df8bae1dSRodney W. Grimes #include <netinet/in.h> 68df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 70df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 71340c35deSJonathan Lemon #include <netinet/tcp_var.h> 725f311da2SMike Silbersack #include <netinet/udp.h> 735f311da2SMike Silbersack #include <netinet/udp_var.h> 74cfa1ca9dSYoshinobu Inoue #ifdef INET6 75cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 76cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 77cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 78cfa1ca9dSYoshinobu Inoue 79df8bae1dSRodney W. Grimes 80b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 81b9234fafSSam Leffler #include <netipsec/ipsec.h> 82b9234fafSSam Leffler #include <netipsec/key.h> 83b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 84b9234fafSSam Leffler 85aed55708SRobert Watson #include <security/mac/mac_framework.h> 86aed55708SRobert Watson 8744e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 88101f9fc8SPeter Wemm /* 89101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 90101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 91101f9fc8SPeter Wemm */ 9244e33a07SMarko Zec int ipport_lowfirstauto; 9344e33a07SMarko Zec int ipport_lowlastauto; 9444e33a07SMarko Zec int ipport_firstauto; 9544e33a07SMarko Zec int ipport_lastauto; 9644e33a07SMarko Zec int ipport_hifirstauto; 9744e33a07SMarko Zec int ipport_hilastauto; 98101f9fc8SPeter Wemm 99b0d22693SCrist J. Clark /* 100b0d22693SCrist J. Clark * Reserved ports accessible only to root. There are significant 101b0d22693SCrist J. Clark * security considerations that must be accounted for when changing these, 102b0d22693SCrist J. Clark * but the security benefits can be great. Please be careful. 103b0d22693SCrist J. Clark */ 10444e33a07SMarko Zec int ipport_reservedhigh; 10544e33a07SMarko Zec int ipport_reservedlow; 106b0d22693SCrist J. Clark 1075f311da2SMike Silbersack /* Variables dealing with random ephemeral port allocation. */ 10844e33a07SMarko Zec int ipport_randomized; 10944e33a07SMarko Zec int ipport_randomcps; 11044e33a07SMarko Zec int ipport_randomtime; 11144e33a07SMarko Zec int ipport_stoprandom; 1125f311da2SMike Silbersack int ipport_tcpallocs; 1135f311da2SMike Silbersack int ipport_tcplastcount; 11444e33a07SMarko Zec #endif 1156ac48b74SMike Silbersack 116bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 117bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 118bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 119bbd42ad0SPeter Wemm 120bbd42ad0SPeter Wemm static int 12182d9ae4eSPoul-Henning Kamp sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS) 122bbd42ad0SPeter Wemm { 12397021c24SMarko Zec INIT_VNET_INET(curvnet); 12430a4ab08SBruce Evans int error; 12530a4ab08SBruce Evans 12630a4ab08SBruce Evans error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 12730a4ab08SBruce Evans if (error == 0) { 128603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 129603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 130603724d3SBjoern A. Zeeb RANGECHK(V_ipport_firstauto, IPPORT_RESERVED, IPPORT_MAX); 131603724d3SBjoern A. Zeeb RANGECHK(V_ipport_lastauto, IPPORT_RESERVED, IPPORT_MAX); 132603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hifirstauto, IPPORT_RESERVED, IPPORT_MAX); 133603724d3SBjoern A. Zeeb RANGECHK(V_ipport_hilastauto, IPPORT_RESERVED, IPPORT_MAX); 134bbd42ad0SPeter Wemm } 13530a4ab08SBruce Evans return (error); 136bbd42ad0SPeter Wemm } 137bbd42ad0SPeter Wemm 138bbd42ad0SPeter Wemm #undef RANGECHK 139bbd42ad0SPeter Wemm 14033b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 14133b3ac06SPeter Wemm 1428b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1438b615593SMarko Zec lowfirst, CTLTYPE_INT|CTLFLAG_RW, ipport_lowfirstauto, 0, 1448b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1458b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1468b615593SMarko Zec lowlast, CTLTYPE_INT|CTLFLAG_RW, ipport_lowlastauto, 0, 1478b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1488b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1498b615593SMarko Zec first, CTLTYPE_INT|CTLFLAG_RW, ipport_firstauto, 0, 1508b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1518b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1528b615593SMarko Zec last, CTLTYPE_INT|CTLFLAG_RW, ipport_lastauto, 0, 1538b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1548b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1558b615593SMarko Zec hifirst, CTLTYPE_INT|CTLFLAG_RW, ipport_hifirstauto, 0, 1568b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1578b615593SMarko Zec SYSCTL_V_PROC(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1588b615593SMarko Zec hilast, CTLTYPE_INT|CTLFLAG_RW, ipport_hilastauto, 0, 1598b615593SMarko Zec &sysctl_net_ipport_check, "I", ""); 1608b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, 1618b615593SMarko Zec reservedhigh, CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedhigh, 0, ""); 1628b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, reservedlow, 1638b615593SMarko Zec CTLFLAG_RW|CTLFLAG_SECURE, ipport_reservedlow, 0, ""); 1648b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomized, 1658b615593SMarko Zec CTLFLAG_RW, ipport_randomized, 0, "Enable random port allocation"); 1668b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomcps, 1678b615593SMarko Zec CTLFLAG_RW, ipport_randomcps, 0, "Maximum number of random port " 1686ee79c59SMaxim Konovalov "allocations before switching to a sequental one"); 1698b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip_portrange, OID_AUTO, randomtime, 1708b615593SMarko Zec CTLFLAG_RW, ipport_randomtime, 0, 1718b615593SMarko Zec "Minimum time to keep sequental port " 1726ee79c59SMaxim Konovalov "allocation before switching to a random one"); 1730312fbe9SPoul-Henning Kamp 174c3229e05SDavid Greenman /* 175c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 176c3229e05SDavid Greenman * 177de35559fSRobert Watson * NOTE: It is assumed that most of these functions will be called with 178de35559fSRobert Watson * the pcbinfo lock held, and often, the inpcb lock held, as these utility 179de35559fSRobert Watson * functions often modify hash chains or addresses in pcbs. 180c3229e05SDavid Greenman */ 181c3229e05SDavid Greenman 182c3229e05SDavid Greenman /* 183c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 184d915b280SStephan Uphoff * On success return with the PCB locked. 185c3229e05SDavid Greenman */ 186df8bae1dSRodney W. Grimes int 187d915b280SStephan Uphoff in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo) 188df8bae1dSRodney W. Grimes { 1898b615593SMarko Zec #ifdef INET6 1908b615593SMarko Zec INIT_VNET_INET6(curvnet); 1918b615593SMarko Zec #endif 192136d4f1cSRobert Watson struct inpcb *inp; 19313cf67f3SHajimu UMEMOTO int error; 194a557af22SRobert Watson 19559daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 196a557af22SRobert Watson error = 0; 197d915b280SStephan Uphoff inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT); 198df8bae1dSRodney W. Grimes if (inp == NULL) 199df8bae1dSRodney W. Grimes return (ENOBUFS); 200d915b280SStephan Uphoff bzero(inp, inp_zero_size); 20115bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 202df8bae1dSRodney W. Grimes inp->inp_socket = so; 20386d02c5cSBjoern A. Zeeb inp->inp_cred = crhold(so->so_cred); 2048b07e49aSJulian Elischer inp->inp_inc.inc_fibnum = so->so_fibnum; 205a557af22SRobert Watson #ifdef MAC 20630d239bcSRobert Watson error = mac_inpcb_init(inp, M_NOWAIT); 207a557af22SRobert Watson if (error != 0) 208a557af22SRobert Watson goto out; 209310e7cebSRobert Watson SOCK_LOCK(so); 21030d239bcSRobert Watson mac_inpcb_create(so, inp); 211310e7cebSRobert Watson SOCK_UNLOCK(so); 212a557af22SRobert Watson #endif 2132cb64cb2SGeorge V. Neville-Neil 214b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 21513cf67f3SHajimu UMEMOTO error = ipsec_init_policy(so, &inp->inp_sp); 2160bffde27SRobert Watson if (error != 0) { 2170bffde27SRobert Watson #ifdef MAC 2180bffde27SRobert Watson mac_inpcb_destroy(inp); 2190bffde27SRobert Watson #endif 220a557af22SRobert Watson goto out; 2210bffde27SRobert Watson } 222b2630c29SGeorge V. Neville-Neil #endif /*IPSEC*/ 223e3fd5ffdSRobert Watson #ifdef INET6 224340c35deSJonathan Lemon if (INP_SOCKAF(so) == AF_INET6) { 225340c35deSJonathan Lemon inp->inp_vflag |= INP_IPV6PROTO; 226603724d3SBjoern A. Zeeb if (V_ip6_v6only) 22733841545SHajimu UMEMOTO inp->inp_flags |= IN6P_IPV6_V6ONLY; 228340c35deSJonathan Lemon } 22975daea93SPaul Saab #endif 230712fc218SRobert Watson LIST_INSERT_HEAD(pcbinfo->ipi_listhead, inp, inp_list); 2313d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 232df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 23333841545SHajimu UMEMOTO #ifdef INET6 234603724d3SBjoern A. Zeeb if (V_ip6_auto_flowlabel) 23533841545SHajimu UMEMOTO inp->inp_flags |= IN6P_AUTOFLOWLABEL; 23633841545SHajimu UMEMOTO #endif 2378501a69cSRobert Watson INP_WLOCK(inp); 238d915b280SStephan Uphoff inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 239d915b280SStephan Uphoff 240b2630c29SGeorge V. Neville-Neil #if defined(IPSEC) || defined(MAC) 241a557af22SRobert Watson out: 24286d02c5cSBjoern A. Zeeb if (error != 0) { 24386d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 244a557af22SRobert Watson uma_zfree(pcbinfo->ipi_zone, inp); 24586d02c5cSBjoern A. Zeeb } 246a557af22SRobert Watson #endif 247a557af22SRobert Watson return (error); 248df8bae1dSRodney W. Grimes } 249df8bae1dSRodney W. Grimes 250df8bae1dSRodney W. Grimes int 251136d4f1cSRobert Watson in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 252df8bae1dSRodney W. Grimes { 2534b932371SIan Dowse int anonport, error; 2544b932371SIan Dowse 2551b73ca0bSSam Leffler INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 2568501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 25759daba27SSam Leffler 2584b932371SIan Dowse if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY) 2594b932371SIan Dowse return (EINVAL); 2604b932371SIan Dowse anonport = inp->inp_lport == 0 && (nam == NULL || 2614b932371SIan Dowse ((struct sockaddr_in *)nam)->sin_port == 0); 2624b932371SIan Dowse error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr, 263b0330ed9SPawel Jakub Dawidek &inp->inp_lport, cred); 2644b932371SIan Dowse if (error) 2654b932371SIan Dowse return (error); 2664b932371SIan Dowse if (in_pcbinshash(inp) != 0) { 2674b932371SIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 2684b932371SIan Dowse inp->inp_lport = 0; 2694b932371SIan Dowse return (EAGAIN); 2704b932371SIan Dowse } 2714b932371SIan Dowse if (anonport) 2724b932371SIan Dowse inp->inp_flags |= INP_ANONPORT; 2734b932371SIan Dowse return (0); 2744b932371SIan Dowse } 2754b932371SIan Dowse 2764b932371SIan Dowse /* 2774b932371SIan Dowse * Set up a bind operation on a PCB, performing port allocation 2784b932371SIan Dowse * as required, but do not actually modify the PCB. Callers can 2794b932371SIan Dowse * either complete the bind by setting inp_laddr/inp_lport and 2804b932371SIan Dowse * calling in_pcbinshash(), or they can just use the resulting 2814b932371SIan Dowse * port and address to authorise the sending of a once-off packet. 2824b932371SIan Dowse * 2834b932371SIan Dowse * On error, the values of *laddrp and *lportp are not changed. 2844b932371SIan Dowse */ 2854b932371SIan Dowse int 286136d4f1cSRobert Watson in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, 287136d4f1cSRobert Watson u_short *lportp, struct ucred *cred) 2884b932371SIan Dowse { 2898b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 2904b932371SIan Dowse struct socket *so = inp->inp_socket; 29137bd2b30SPeter Wemm unsigned short *lastport; 29215bd2b43SDavid Greenman struct sockaddr_in *sin; 293c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 2944b932371SIan Dowse struct in_addr laddr; 295df8bae1dSRodney W. Grimes u_short lport = 0; 2964cc20ab1SSeigo Tanimura int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 297413628a7SBjoern A. Zeeb int error; 2985f311da2SMike Silbersack int dorandom; 299df8bae1dSRodney W. Grimes 3008501a69cSRobert Watson /* 30172bed082SRobert Watson * Because no actual state changes occur here, a global write lock on 30272bed082SRobert Watson * the pcbinfo isn't required. 3038501a69cSRobert Watson */ 3048501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 30559daba27SSam Leffler INP_LOCK_ASSERT(inp); 30659daba27SSam Leffler 307603724d3SBjoern A. Zeeb if (TAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */ 308df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 3094b932371SIan Dowse laddr.s_addr = *laddrp; 3104b932371SIan Dowse if (nam != NULL && laddr.s_addr != INADDR_ANY) 311df8bae1dSRodney W. Grimes return (EINVAL); 312c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 313421d8aa6SBjoern A. Zeeb wild = INPLOOKUP_WILDCARD; 314df8bae1dSRodney W. Grimes if (nam) { 31557bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 31657bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 317df8bae1dSRodney W. Grimes return (EINVAL); 318df8bae1dSRodney W. Grimes #ifdef notdef 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * We should check the family, but old programs 321df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 322df8bae1dSRodney W. Grimes */ 323df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 324df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 325df8bae1dSRodney W. Grimes #endif 326413628a7SBjoern A. Zeeb if (prison_local_ip4(cred, &sin->sin_addr)) 32775c13541SPoul-Henning Kamp return (EINVAL); 3284b932371SIan Dowse if (sin->sin_port != *lportp) { 3294b932371SIan Dowse /* Don't allow the port to change. */ 3304b932371SIan Dowse if (*lportp != 0) 3314b932371SIan Dowse return (EINVAL); 332df8bae1dSRodney W. Grimes lport = sin->sin_port; 3334b932371SIan Dowse } 3344b932371SIan Dowse /* NB: lport is left as 0 if the port isn't being changed. */ 335df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 336df8bae1dSRodney W. Grimes /* 337df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 338df8bae1dSRodney W. Grimes * allow complete duplication of binding if 339df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 340df8bae1dSRodney W. Grimes * and a multicast address is bound on both 341df8bae1dSRodney W. Grimes * new and duplicated sockets. 342df8bae1dSRodney W. Grimes */ 343df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 344df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 345df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 346df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 34783103a73SAndrew R. Reiter bzero(&sin->sin_zero, sizeof(sin->sin_zero)); 348df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 349df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 350df8bae1dSRodney W. Grimes } 3514b932371SIan Dowse laddr = sin->sin_addr; 352df8bae1dSRodney W. Grimes if (lport) { 353df8bae1dSRodney W. Grimes struct inpcb *t; 354ae0e7143SRobert Watson struct tcptw *tw; 355ae0e7143SRobert Watson 356df8bae1dSRodney W. Grimes /* GROSS */ 357603724d3SBjoern A. Zeeb if (ntohs(lport) <= V_ipport_reservedhigh && 358603724d3SBjoern A. Zeeb ntohs(lport) >= V_ipport_reservedlow && 359acd3428bSRobert Watson priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 36032f9753cSRobert Watson 0)) 3612469dd60SGarrett Wollman return (EACCES); 362835d4b89SPawel Jakub Dawidek if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 36386d02c5cSBjoern A. Zeeb priv_check_cred(inp->inp_cred, 36432f9753cSRobert Watson PRIV_NETINET_REUSEPORT, 0) != 0) { 365078b7042SBjoern A. Zeeb t = in_pcblookup_local(pcbinfo, sin->sin_addr, 366413628a7SBjoern A. Zeeb lport, INPLOOKUP_WILDCARD, cred); 367340c35deSJonathan Lemon /* 368340c35deSJonathan Lemon * XXX 369340c35deSJonathan Lemon * This entire block sorely needs a rewrite. 370340c35deSJonathan Lemon */ 3714cc20ab1SSeigo Tanimura if (t && 3724658dc83SYaroslav Tykhiy ((t->inp_vflag & INP_TIMEWAIT) == 0) && 3734658dc83SYaroslav Tykhiy (so->so_type != SOCK_STREAM || 3744658dc83SYaroslav Tykhiy ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && 3754cc20ab1SSeigo Tanimura (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 37652b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 37752b65dbeSBill Fenner (t->inp_socket->so_options & 37852b65dbeSBill Fenner SO_REUSEPORT) == 0) && 37986d02c5cSBjoern A. Zeeb (inp->inp_cred->cr_uid != 38086d02c5cSBjoern A. Zeeb t->inp_cred->cr_uid)) 3814049a042SGuido van Rooij return (EADDRINUSE); 3824049a042SGuido van Rooij } 383413628a7SBjoern A. Zeeb if (prison_local_ip4(cred, &sin->sin_addr)) 384970680faSPoul-Henning Kamp return (EADDRNOTAVAIL); 385c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 386413628a7SBjoern A. Zeeb lport, wild, cred); 387340c35deSJonathan Lemon if (t && (t->inp_vflag & INP_TIMEWAIT)) { 388ae0e7143SRobert Watson /* 389ae0e7143SRobert Watson * XXXRW: If an incpb has had its timewait 390ae0e7143SRobert Watson * state recycled, we treat the address as 391ae0e7143SRobert Watson * being in use (for now). This is better 392ae0e7143SRobert Watson * than a panic, but not desirable. 393ae0e7143SRobert Watson */ 394ae0e7143SRobert Watson tw = intotw(inp); 395ae0e7143SRobert Watson if (tw == NULL || 396ae0e7143SRobert Watson (reuseport & tw->tw_so_options) == 0) 397340c35deSJonathan Lemon return (EADDRINUSE); 398ae0e7143SRobert Watson } else if (t && 3994cc20ab1SSeigo Tanimura (reuseport & t->inp_socket->so_options) == 0) { 400e3fd5ffdSRobert Watson #ifdef INET6 40133841545SHajimu UMEMOTO if (ntohl(sin->sin_addr.s_addr) != 402cfa1ca9dSYoshinobu Inoue INADDR_ANY || 403cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 404cfa1ca9dSYoshinobu Inoue INADDR_ANY || 405cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 406cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 407e3fd5ffdSRobert Watson #endif 408df8bae1dSRodney W. Grimes return (EADDRINUSE); 409df8bae1dSRodney W. Grimes } 410cfa1ca9dSYoshinobu Inoue } 411df8bae1dSRodney W. Grimes } 4124b932371SIan Dowse if (*lportp != 0) 4134b932371SIan Dowse lport = *lportp; 41433b3ac06SPeter Wemm if (lport == 0) { 4151cf6e4f5SRui Paulo u_short first, last, aux; 416174624e0SMike Silbersack int count; 41733b3ac06SPeter Wemm 418413628a7SBjoern A. Zeeb if (prison_local_ip4(cred, &laddr)) 41975c13541SPoul-Henning Kamp return (EINVAL); 420321a2846SPoul-Henning Kamp 42133b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 422603724d3SBjoern A. Zeeb first = V_ipport_hifirstauto; /* sysctl */ 423603724d3SBjoern A. Zeeb last = V_ipport_hilastauto; 424712fc218SRobert Watson lastport = &pcbinfo->ipi_lasthi; 42533b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 426acd3428bSRobert Watson error = priv_check_cred(cred, 42732f9753cSRobert Watson PRIV_NETINET_RESERVEDPORT, 0); 428acd3428bSRobert Watson if (error) 429a29f300eSGarrett Wollman return error; 430603724d3SBjoern A. Zeeb first = V_ipport_lowfirstauto; /* 1023 */ 431603724d3SBjoern A. Zeeb last = V_ipport_lowlastauto; /* 600 */ 432712fc218SRobert Watson lastport = &pcbinfo->ipi_lastlow; 43333b3ac06SPeter Wemm } else { 434603724d3SBjoern A. Zeeb first = V_ipport_firstauto; /* sysctl */ 435603724d3SBjoern A. Zeeb last = V_ipport_lastauto; 436712fc218SRobert Watson lastport = &pcbinfo->ipi_lastport; 43733b3ac06SPeter Wemm } 43833b3ac06SPeter Wemm /* 4395f311da2SMike Silbersack * For UDP, use random port allocation as long as the user 4405f311da2SMike Silbersack * allows it. For TCP (and as of yet unknown) connections, 4415f311da2SMike Silbersack * use random port allocation only if the user allows it AND 44229f2a6ecSMaxim Konovalov * ipport_tick() allows it. 4435f311da2SMike Silbersack */ 444603724d3SBjoern A. Zeeb if (V_ipport_randomized && 445603724d3SBjoern A. Zeeb (!V_ipport_stoprandom || pcbinfo == &V_udbinfo)) 4465f311da2SMike Silbersack dorandom = 1; 4475f311da2SMike Silbersack else 4485f311da2SMike Silbersack dorandom = 0; 449e99971bfSMaxim Konovalov /* 450e99971bfSMaxim Konovalov * It makes no sense to do random port allocation if 451e99971bfSMaxim Konovalov * we have the only port available. 452e99971bfSMaxim Konovalov */ 453e99971bfSMaxim Konovalov if (first == last) 454e99971bfSMaxim Konovalov dorandom = 0; 4555f311da2SMike Silbersack /* Make sure to not include UDP packets in the count. */ 456603724d3SBjoern A. Zeeb if (pcbinfo != &V_udbinfo) 457603724d3SBjoern A. Zeeb V_ipport_tcpallocs++; 4585f311da2SMike Silbersack /* 4597e1bc272SBjoern A. Zeeb * Instead of having two loops further down counting up or down 4607e1bc272SBjoern A. Zeeb * make sure that first is always <= last and go with only one 4617e1bc272SBjoern A. Zeeb * code path implementing all logic. 46233b3ac06SPeter Wemm */ 46333b3ac06SPeter Wemm if (first > last) { 4641cf6e4f5SRui Paulo aux = first; 4651cf6e4f5SRui Paulo first = last; 4661cf6e4f5SRui Paulo last = aux; 4671cf6e4f5SRui Paulo } 468174624e0SMike Silbersack 4695f311da2SMike Silbersack if (dorandom) 4706b2fc10bSMike Silbersack *lastport = first + 4716b2fc10bSMike Silbersack (arc4random() % (last - first)); 4721cf6e4f5SRui Paulo 47333b3ac06SPeter Wemm count = last - first; 474174624e0SMike Silbersack 47533b3ac06SPeter Wemm do { 4766ac48b74SMike Silbersack if (count-- < 0) /* completely used? */ 477550b1518SWes Peters return (EADDRNOTAVAIL); 47833b3ac06SPeter Wemm ++*lastport; 47933b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 48033b3ac06SPeter Wemm *lastport = first; 48133b3ac06SPeter Wemm lport = htons(*lastport); 482078b7042SBjoern A. Zeeb } while (in_pcblookup_local(pcbinfo, laddr, 483078b7042SBjoern A. Zeeb lport, wild, cred)); 48433b3ac06SPeter Wemm } 485413628a7SBjoern A. Zeeb if (prison_local_ip4(cred, &laddr)) 486e4bdf25dSPoul-Henning Kamp return (EINVAL); 4874b932371SIan Dowse *laddrp = laddr.s_addr; 4884b932371SIan Dowse *lportp = lport; 489df8bae1dSRodney W. Grimes return (0); 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes 492999f1343SGarrett Wollman /* 4935200e00eSIan Dowse * Connect from a socket to a specified address. 4945200e00eSIan Dowse * Both address and port must be specified in argument sin. 4955200e00eSIan Dowse * If don't have a local address for this socket yet, 4965200e00eSIan Dowse * then pick one. 497999f1343SGarrett Wollman */ 498999f1343SGarrett Wollman int 499136d4f1cSRobert Watson in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) 500999f1343SGarrett Wollman { 5015200e00eSIan Dowse u_short lport, fport; 5025200e00eSIan Dowse in_addr_t laddr, faddr; 5035200e00eSIan Dowse int anonport, error; 504df8bae1dSRodney W. Grimes 50527f74fd0SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 5068501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 50727f74fd0SRobert Watson 5085200e00eSIan Dowse lport = inp->inp_lport; 5095200e00eSIan Dowse laddr = inp->inp_laddr.s_addr; 5105200e00eSIan Dowse anonport = (lport == 0); 5115200e00eSIan Dowse error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport, 512b0330ed9SPawel Jakub Dawidek NULL, cred); 5135200e00eSIan Dowse if (error) 5145200e00eSIan Dowse return (error); 5155200e00eSIan Dowse 5165200e00eSIan Dowse /* Do the initial binding of the local address if required. */ 5175200e00eSIan Dowse if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) { 5185200e00eSIan Dowse inp->inp_lport = lport; 5195200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5205200e00eSIan Dowse if (in_pcbinshash(inp) != 0) { 5215200e00eSIan Dowse inp->inp_laddr.s_addr = INADDR_ANY; 5225200e00eSIan Dowse inp->inp_lport = 0; 5235200e00eSIan Dowse return (EAGAIN); 5245200e00eSIan Dowse } 5255200e00eSIan Dowse } 5265200e00eSIan Dowse 5275200e00eSIan Dowse /* Commit the remaining changes. */ 5285200e00eSIan Dowse inp->inp_lport = lport; 5295200e00eSIan Dowse inp->inp_laddr.s_addr = laddr; 5305200e00eSIan Dowse inp->inp_faddr.s_addr = faddr; 5315200e00eSIan Dowse inp->inp_fport = fport; 5325200e00eSIan Dowse in_pcbrehash(inp); 5332cb64cb2SGeorge V. Neville-Neil 5345200e00eSIan Dowse if (anonport) 5355200e00eSIan Dowse inp->inp_flags |= INP_ANONPORT; 5365200e00eSIan Dowse return (0); 5375200e00eSIan Dowse } 5385200e00eSIan Dowse 5395200e00eSIan Dowse /* 5400895aec3SBjoern A. Zeeb * Do proper source address selection on an unbound socket in case 5410895aec3SBjoern A. Zeeb * of connect. Take jails into account as well. 5420895aec3SBjoern A. Zeeb */ 5430895aec3SBjoern A. Zeeb static int 5440895aec3SBjoern A. Zeeb in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, 5450895aec3SBjoern A. Zeeb struct ucred *cred) 5460895aec3SBjoern A. Zeeb { 5470895aec3SBjoern A. Zeeb struct in_ifaddr *ia; 5480895aec3SBjoern A. Zeeb struct ifaddr *ifa; 5490895aec3SBjoern A. Zeeb struct sockaddr *sa; 5500895aec3SBjoern A. Zeeb struct sockaddr_in *sin; 5510895aec3SBjoern A. Zeeb struct route sro; 5520895aec3SBjoern A. Zeeb int error; 5530895aec3SBjoern A. Zeeb 554413628a7SBjoern A. Zeeb KASSERT(laddr != NULL, ("%s: laddr NULL", __func__)); 5550895aec3SBjoern A. Zeeb 5560895aec3SBjoern A. Zeeb error = 0; 5570895aec3SBjoern A. Zeeb ia = NULL; 5580895aec3SBjoern A. Zeeb bzero(&sro, sizeof(sro)); 5590895aec3SBjoern A. Zeeb 5600895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)&sro.ro_dst; 5610895aec3SBjoern A. Zeeb sin->sin_family = AF_INET; 5620895aec3SBjoern A. Zeeb sin->sin_len = sizeof(struct sockaddr_in); 5630895aec3SBjoern A. Zeeb sin->sin_addr.s_addr = faddr->s_addr; 5640895aec3SBjoern A. Zeeb 5650895aec3SBjoern A. Zeeb /* 5660895aec3SBjoern A. Zeeb * If route is known our src addr is taken from the i/f, 5670895aec3SBjoern A. Zeeb * else punt. 5680895aec3SBjoern A. Zeeb * 5690895aec3SBjoern A. Zeeb * Find out route to destination. 5700895aec3SBjoern A. Zeeb */ 5710895aec3SBjoern A. Zeeb if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) 5720895aec3SBjoern A. Zeeb in_rtalloc_ign(&sro, RTF_CLONING, inp->inp_inc.inc_fibnum); 5730895aec3SBjoern A. Zeeb 5740895aec3SBjoern A. Zeeb /* 5750895aec3SBjoern A. Zeeb * If we found a route, use the address corresponding to 5760895aec3SBjoern A. Zeeb * the outgoing interface. 5770895aec3SBjoern A. Zeeb * 5780895aec3SBjoern A. Zeeb * Otherwise assume faddr is reachable on a directly connected 5790895aec3SBjoern A. Zeeb * network and try to find a corresponding interface to take 5800895aec3SBjoern A. Zeeb * the source address from. 5810895aec3SBjoern A. Zeeb */ 5820895aec3SBjoern A. Zeeb if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) { 5830895aec3SBjoern A. Zeeb struct ifnet *ifp; 5840895aec3SBjoern A. Zeeb 5850895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin)); 5860895aec3SBjoern A. Zeeb if (ia == NULL) 5870895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin)); 5880895aec3SBjoern A. Zeeb if (ia == NULL) { 5890895aec3SBjoern A. Zeeb error = ENETUNREACH; 5900895aec3SBjoern A. Zeeb goto done; 5910895aec3SBjoern A. Zeeb } 5920895aec3SBjoern A. Zeeb 5930895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 5940895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 5950895aec3SBjoern A. Zeeb goto done; 5960895aec3SBjoern A. Zeeb } 5970895aec3SBjoern A. Zeeb 5980895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 5990895aec3SBjoern A. Zeeb ia = NULL; 6000895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 6010895aec3SBjoern A. Zeeb 6020895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6030895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6040895aec3SBjoern A. Zeeb continue; 6050895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 606413628a7SBjoern A. Zeeb if (prison_check_ip4(cred, &sin->sin_addr)) { 6070895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6080895aec3SBjoern A. Zeeb break; 6090895aec3SBjoern A. Zeeb } 6100895aec3SBjoern A. Zeeb } 6110895aec3SBjoern A. Zeeb if (ia != NULL) { 6120895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6130895aec3SBjoern A. Zeeb goto done; 6140895aec3SBjoern A. Zeeb } 6150895aec3SBjoern A. Zeeb 6160895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 617413628a7SBjoern A. Zeeb if (prison_getip4(cred, laddr) != 0) 618413628a7SBjoern A. Zeeb error = EADDRNOTAVAIL; 6190895aec3SBjoern A. Zeeb goto done; 6200895aec3SBjoern A. Zeeb } 6210895aec3SBjoern A. Zeeb 6220895aec3SBjoern A. Zeeb /* 6230895aec3SBjoern A. Zeeb * If the outgoing interface on the route found is not 6240895aec3SBjoern A. Zeeb * a loopback interface, use the address from that interface. 6250895aec3SBjoern A. Zeeb * In case of jails do those three steps: 6260895aec3SBjoern A. Zeeb * 1. check if the interface address belongs to the jail. If so use it. 6270895aec3SBjoern A. Zeeb * 2. check if we have any address on the outgoing interface 6280895aec3SBjoern A. Zeeb * belonging to this jail. If so use it. 6290895aec3SBjoern A. Zeeb * 3. as a last resort return the 'default' jail address. 6300895aec3SBjoern A. Zeeb */ 6310895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) { 6320895aec3SBjoern A. Zeeb 6330895aec3SBjoern A. Zeeb /* If not jailed, use the default returned. */ 6340895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6350895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6360895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6370895aec3SBjoern A. Zeeb goto done; 6380895aec3SBjoern A. Zeeb } 6390895aec3SBjoern A. Zeeb 6400895aec3SBjoern A. Zeeb /* Jailed. */ 6410895aec3SBjoern A. Zeeb /* 1. Check if the iface address belongs to the jail. */ 6420895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr; 643413628a7SBjoern A. Zeeb if (prison_check_ip4(cred, &sin->sin_addr)) { 6440895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; 6450895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6460895aec3SBjoern A. Zeeb goto done; 6470895aec3SBjoern A. Zeeb } 6480895aec3SBjoern A. Zeeb 6490895aec3SBjoern A. Zeeb /* 6500895aec3SBjoern A. Zeeb * 2. Check if we have any address on the outgoing interface 6510895aec3SBjoern A. Zeeb * belonging to this jail. 6520895aec3SBjoern A. Zeeb */ 6530895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &sro.ro_rt->rt_ifp->if_addrhead, ifa_link) { 6540895aec3SBjoern A. Zeeb 6550895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 6560895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 6570895aec3SBjoern A. Zeeb continue; 6580895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 659413628a7SBjoern A. Zeeb if (prison_check_ip4(cred, &sin->sin_addr)) { 6600895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 6610895aec3SBjoern A. Zeeb break; 6620895aec3SBjoern A. Zeeb } 6630895aec3SBjoern A. Zeeb } 6640895aec3SBjoern A. Zeeb if (ia != NULL) { 6650895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 6660895aec3SBjoern A. Zeeb goto done; 6670895aec3SBjoern A. Zeeb } 6680895aec3SBjoern A. Zeeb 6690895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 670413628a7SBjoern A. Zeeb if (prison_getip4(cred, laddr) != 0) 671413628a7SBjoern A. Zeeb error = EADDRNOTAVAIL; 6720895aec3SBjoern A. Zeeb goto done; 6730895aec3SBjoern A. Zeeb } 6740895aec3SBjoern A. Zeeb 6750895aec3SBjoern A. Zeeb /* 6760895aec3SBjoern A. Zeeb * The outgoing interface is marked with 'loopback net', so a route 6770895aec3SBjoern A. Zeeb * to ourselves is here. 6780895aec3SBjoern A. Zeeb * Try to find the interface of the destination address and then 6790895aec3SBjoern A. Zeeb * take the address from there. That interface is not necessarily 6800895aec3SBjoern A. Zeeb * a loopback interface. 6810895aec3SBjoern A. Zeeb * In case of jails, check that it is an address of the jail 6820895aec3SBjoern A. Zeeb * and if we cannot find, fall back to the 'default' jail address. 6830895aec3SBjoern A. Zeeb */ 6840895aec3SBjoern A. Zeeb if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { 6850895aec3SBjoern A. Zeeb struct sockaddr_in sain; 6860895aec3SBjoern A. Zeeb 6870895aec3SBjoern A. Zeeb bzero(&sain, sizeof(struct sockaddr_in)); 6880895aec3SBjoern A. Zeeb sain.sin_family = AF_INET; 6890895aec3SBjoern A. Zeeb sain.sin_len = sizeof(struct sockaddr_in); 6900895aec3SBjoern A. Zeeb sain.sin_addr.s_addr = faddr->s_addr; 6910895aec3SBjoern A. Zeeb 6920895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sain))); 6930895aec3SBjoern A. Zeeb if (ia == NULL) 6940895aec3SBjoern A. Zeeb ia = ifatoia(ifa_ifwithnet(sintosa(&sain))); 6950895aec3SBjoern A. Zeeb 6960895aec3SBjoern A. Zeeb if (cred == NULL || !jailed(cred)) { 6970895aec3SBjoern A. Zeeb if (ia == NULL) { 6980895aec3SBjoern A. Zeeb error = ENETUNREACH; 6990895aec3SBjoern A. Zeeb goto done; 7000895aec3SBjoern A. Zeeb } 7010895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 7020895aec3SBjoern A. Zeeb goto done; 7030895aec3SBjoern A. Zeeb } 7040895aec3SBjoern A. Zeeb 7050895aec3SBjoern A. Zeeb /* Jailed. */ 7060895aec3SBjoern A. Zeeb if (ia != NULL) { 7070895aec3SBjoern A. Zeeb struct ifnet *ifp; 7080895aec3SBjoern A. Zeeb 7090895aec3SBjoern A. Zeeb ifp = ia->ia_ifp; 7100895aec3SBjoern A. Zeeb ia = NULL; 7110895aec3SBjoern A. Zeeb TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 7120895aec3SBjoern A. Zeeb 7130895aec3SBjoern A. Zeeb sa = ifa->ifa_addr; 7140895aec3SBjoern A. Zeeb if (sa->sa_family != AF_INET) 7150895aec3SBjoern A. Zeeb continue; 7160895aec3SBjoern A. Zeeb sin = (struct sockaddr_in *)sa; 717413628a7SBjoern A. Zeeb if (prison_check_ip4(cred, &sin->sin_addr)) { 7180895aec3SBjoern A. Zeeb ia = (struct in_ifaddr *)ifa; 7190895aec3SBjoern A. Zeeb break; 7200895aec3SBjoern A. Zeeb } 7210895aec3SBjoern A. Zeeb } 7220895aec3SBjoern A. Zeeb if (ia != NULL) { 7230895aec3SBjoern A. Zeeb laddr->s_addr = ia->ia_addr.sin_addr.s_addr; 7240895aec3SBjoern A. Zeeb goto done; 7250895aec3SBjoern A. Zeeb } 7260895aec3SBjoern A. Zeeb } 7270895aec3SBjoern A. Zeeb 7280895aec3SBjoern A. Zeeb /* 3. As a last resort return the 'default' jail address. */ 729413628a7SBjoern A. Zeeb if (prison_getip4(cred, laddr) != 0) 730413628a7SBjoern A. Zeeb error = EADDRNOTAVAIL; 7310895aec3SBjoern A. Zeeb goto done; 7320895aec3SBjoern A. Zeeb } 7330895aec3SBjoern A. Zeeb 7340895aec3SBjoern A. Zeeb done: 7350895aec3SBjoern A. Zeeb if (sro.ro_rt != NULL) 7360895aec3SBjoern A. Zeeb RTFREE(sro.ro_rt); 7370895aec3SBjoern A. Zeeb return (error); 7380895aec3SBjoern A. Zeeb } 7390895aec3SBjoern A. Zeeb 7400895aec3SBjoern A. Zeeb /* 7415200e00eSIan Dowse * Set up for a connect from a socket to the specified address. 7425200e00eSIan Dowse * On entry, *laddrp and *lportp should contain the current local 7435200e00eSIan Dowse * address and port for the PCB; these are updated to the values 7445200e00eSIan Dowse * that should be placed in inp_laddr and inp_lport to complete 7455200e00eSIan Dowse * the connect. 7465200e00eSIan Dowse * 7475200e00eSIan Dowse * On success, *faddrp and *fportp will be set to the remote address 7485200e00eSIan Dowse * and port. These are not updated in the error case. 7495200e00eSIan Dowse * 7505200e00eSIan Dowse * If the operation fails because the connection already exists, 7515200e00eSIan Dowse * *oinpp will be set to the PCB of that connection so that the 7525200e00eSIan Dowse * caller can decide to override it. In all other cases, *oinpp 7535200e00eSIan Dowse * is set to NULL. 7545200e00eSIan Dowse */ 7555200e00eSIan Dowse int 756136d4f1cSRobert Watson in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, 757136d4f1cSRobert Watson in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp, 758136d4f1cSRobert Watson struct inpcb **oinpp, struct ucred *cred) 7595200e00eSIan Dowse { 7608b615593SMarko Zec INIT_VNET_INET(inp->inp_vnet); 7615200e00eSIan Dowse struct sockaddr_in *sin = (struct sockaddr_in *)nam; 7625200e00eSIan Dowse struct in_ifaddr *ia; 7635200e00eSIan Dowse struct inpcb *oinp; 764413628a7SBjoern A. Zeeb struct in_addr laddr, faddr, jailia; 7655200e00eSIan Dowse u_short lport, fport; 7665200e00eSIan Dowse int error; 7675200e00eSIan Dowse 7688501a69cSRobert Watson /* 7698501a69cSRobert Watson * Because a global state change doesn't actually occur here, a read 7708501a69cSRobert Watson * lock is sufficient. 7718501a69cSRobert Watson */ 7728501a69cSRobert Watson INP_INFO_LOCK_ASSERT(inp->inp_pcbinfo); 77327f74fd0SRobert Watson INP_LOCK_ASSERT(inp); 77427f74fd0SRobert Watson 7755200e00eSIan Dowse if (oinpp != NULL) 7765200e00eSIan Dowse *oinpp = NULL; 77757bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 778df8bae1dSRodney W. Grimes return (EINVAL); 779df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 780df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 781df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 782df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 7835200e00eSIan Dowse laddr.s_addr = *laddrp; 7845200e00eSIan Dowse lport = *lportp; 7855200e00eSIan Dowse faddr = sin->sin_addr; 7865200e00eSIan Dowse fport = sin->sin_port; 7870895aec3SBjoern A. Zeeb 788603724d3SBjoern A. Zeeb if (!TAILQ_EMPTY(&V_in_ifaddrhead)) { 789df8bae1dSRodney W. Grimes /* 790df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 791df8bae1dSRodney W. Grimes * use the primary local address. 792df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 793df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 794df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 795df8bae1dSRodney W. Grimes */ 796413628a7SBjoern A. Zeeb if (faddr.s_addr == INADDR_ANY) { 797413628a7SBjoern A. Zeeb if (cred != NULL && jailed(cred)) { 798413628a7SBjoern A. Zeeb if (prison_getip4(cred, &jailia) != 0) 799413628a7SBjoern A. Zeeb return (EADDRNOTAVAIL); 800413628a7SBjoern A. Zeeb faddr.s_addr = jailia.s_addr; 801413628a7SBjoern A. Zeeb } else { 802413628a7SBjoern A. Zeeb faddr = 803413628a7SBjoern A. Zeeb IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))-> 804413628a7SBjoern A. Zeeb sin_addr; 805413628a7SBjoern A. Zeeb } 806413628a7SBjoern A. Zeeb } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && 807603724d3SBjoern A. Zeeb (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & 8085200e00eSIan Dowse IFF_BROADCAST)) 8095200e00eSIan Dowse faddr = satosin(&TAILQ_FIRST( 810603724d3SBjoern A. Zeeb &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; 811df8bae1dSRodney W. Grimes } 8125200e00eSIan Dowse if (laddr.s_addr == INADDR_ANY) { 8130895aec3SBjoern A. Zeeb error = in_pcbladdr(inp, &faddr, &laddr, cred); 8140895aec3SBjoern A. Zeeb if (error) 8150895aec3SBjoern A. Zeeb return (error); 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes /* 818df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 819df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 820df8bae1dSRodney W. Grimes * address of that interface as our source address. 821df8bae1dSRodney W. Grimes */ 8225200e00eSIan Dowse if (IN_MULTICAST(ntohl(faddr.s_addr)) && 823df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 824df8bae1dSRodney W. Grimes struct ip_moptions *imo; 825df8bae1dSRodney W. Grimes struct ifnet *ifp; 826df8bae1dSRodney W. Grimes 827df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 828df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 829df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 830603724d3SBjoern A. Zeeb TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) 831df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 832df8bae1dSRodney W. Grimes break; 8338699ea08SBjoern A. Zeeb if (ia == NULL) 834df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 8355200e00eSIan Dowse laddr = ia->ia_addr.sin_addr; 836999f1343SGarrett Wollman } 8370895aec3SBjoern A. Zeeb } 8380895aec3SBjoern A. Zeeb } 839999f1343SGarrett Wollman 8405200e00eSIan Dowse oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport, 8415200e00eSIan Dowse 0, NULL); 8425200e00eSIan Dowse if (oinp != NULL) { 8435200e00eSIan Dowse if (oinpp != NULL) 8445200e00eSIan Dowse *oinpp = oinp; 845df8bae1dSRodney W. Grimes return (EADDRINUSE); 846c3229e05SDavid Greenman } 8475200e00eSIan Dowse if (lport == 0) { 848b0330ed9SPawel Jakub Dawidek error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, 849b0330ed9SPawel Jakub Dawidek cred); 8505a903f8dSPierre Beyssac if (error) 8515a903f8dSPierre Beyssac return (error); 8525a903f8dSPierre Beyssac } 8535200e00eSIan Dowse *laddrp = laddr.s_addr; 8545200e00eSIan Dowse *lportp = lport; 8555200e00eSIan Dowse *faddrp = faddr.s_addr; 8565200e00eSIan Dowse *fportp = fport; 857df8bae1dSRodney W. Grimes return (0); 858df8bae1dSRodney W. Grimes } 859df8bae1dSRodney W. Grimes 86026f9a767SRodney W. Grimes void 861136d4f1cSRobert Watson in_pcbdisconnect(struct inpcb *inp) 862df8bae1dSRodney W. Grimes { 8636b348152SRobert Watson 864fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 8658501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 866df8bae1dSRodney W. Grimes 867df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 868df8bae1dSRodney W. Grimes inp->inp_fport = 0; 86915bd2b43SDavid Greenman in_pcbrehash(inp); 870df8bae1dSRodney W. Grimes } 871df8bae1dSRodney W. Grimes 8724c7c478dSRobert Watson /* 873c0a211c5SRobert Watson * Historically, in_pcbdetach() included the functionality now found in 874c0a211c5SRobert Watson * in_pcbfree() and in_pcbdrop(). They are now broken out to reflect the 875c0a211c5SRobert Watson * more complex life cycle of TCP. 876c0a211c5SRobert Watson * 877c0a211c5SRobert Watson * in_pcbdetach() is responsibe for disconnecting the socket from an inpcb. 878c0a211c5SRobert Watson * For most protocols, this will be invoked immediately prior to calling 879c0a211c5SRobert Watson * in_pcbfree(). However, for TCP the inpcb may significantly outlive the 880c0a211c5SRobert Watson * socket, in which case in_pcbfree() may be deferred. 8814c7c478dSRobert Watson */ 88226f9a767SRodney W. Grimes void 883136d4f1cSRobert Watson in_pcbdetach(struct inpcb *inp) 884df8bae1dSRodney W. Grimes { 8854c7c478dSRobert Watson 886a7df09e8SBjoern A. Zeeb KASSERT(inp->inp_socket != NULL, ("%s: inp_socket == NULL", __func__)); 887c0a211c5SRobert Watson 8884c7c478dSRobert Watson inp->inp_socket->so_pcb = NULL; 8894c7c478dSRobert Watson inp->inp_socket = NULL; 8904c7c478dSRobert Watson } 8914c7c478dSRobert Watson 892c0a211c5SRobert Watson /* 893c0a211c5SRobert Watson * in_pcbfree() is responsible for freeing an already-detached inpcb, as well 894c0a211c5SRobert Watson * as removing it from any global inpcb lists it might be on. 895c0a211c5SRobert Watson */ 8964c7c478dSRobert Watson void 8974c7c478dSRobert Watson in_pcbfree(struct inpcb *inp) 8984c7c478dSRobert Watson { 8993d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 900df8bae1dSRodney W. Grimes 901a7df09e8SBjoern A. Zeeb KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); 9028501a69cSRobert Watson 903fe6bfc37SRobert Watson INP_INFO_WLOCK_ASSERT(ipi); 9048501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 90559daba27SSam Leffler 906b2630c29SGeorge V. Neville-Neil #ifdef IPSEC 9076aee2fc5SBjoern A. Zeeb if (inp->inp_sp != NULL) 9086974bd9eSBjoern A. Zeeb ipsec_delete_pcbpolicy(inp); 909b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */ 9103d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 911c3229e05SDavid Greenman in_pcbremlists(inp); 9126aee2fc5SBjoern A. Zeeb #ifdef INET6 9136aee2fc5SBjoern A. Zeeb if (inp->inp_vflag & INP_IPV6PROTO) { 9146aee2fc5SBjoern A. Zeeb ip6_freepcbopts(inp->in6p_outputopts); 9156aee2fc5SBjoern A. Zeeb ip6_freemoptions(inp->in6p_moptions); 9166aee2fc5SBjoern A. Zeeb } 9176aee2fc5SBjoern A. Zeeb #endif 918df8bae1dSRodney W. Grimes if (inp->inp_options) 919df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 92071498f30SBruce M Simpson if (inp->inp_moptions != NULL) 92171498f30SBruce M Simpson inp_freemoptions(inp->inp_moptions); 922cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 92386d02c5cSBjoern A. Zeeb crfree(inp->inp_cred); 924d915b280SStephan Uphoff 925a557af22SRobert Watson #ifdef MAC 92630d239bcSRobert Watson mac_inpcb_destroy(inp); 927a557af22SRobert Watson #endif 9288501a69cSRobert Watson INP_WUNLOCK(inp); 92969c2d429SJeff Roberson uma_zfree(ipi->ipi_zone, inp); 930df8bae1dSRodney W. Grimes } 931df8bae1dSRodney W. Grimes 93210702a28SRobert Watson /* 933c0a211c5SRobert Watson * in_pcbdrop() removes an inpcb from hashed lists, releasing its address and 934c0a211c5SRobert Watson * port reservation, and preventing it from being returned by inpcb lookups. 935c0a211c5SRobert Watson * 936c0a211c5SRobert Watson * It is used by TCP to mark an inpcb as unused and avoid future packet 937c0a211c5SRobert Watson * delivery or event notification when a socket remains open but TCP has 938c0a211c5SRobert Watson * closed. This might occur as a result of a shutdown()-initiated TCP close 939c0a211c5SRobert Watson * or a RST on the wire, and allows the port binding to be reused while still 940c0a211c5SRobert Watson * maintaining the invariant that so_pcb always points to a valid inpcb until 941c0a211c5SRobert Watson * in_pcbdetach(). 942c0a211c5SRobert Watson * 943c0a211c5SRobert Watson * XXXRW: An inp_lport of 0 is used to indicate that the inpcb is not on hash 944c0a211c5SRobert Watson * lists, but can lead to confusing netstat output, as open sockets with 945c0a211c5SRobert Watson * closed TCP connections will no longer appear to have their bound port 946c0a211c5SRobert Watson * number. An explicit flag would be better, as it would allow us to leave 947c0a211c5SRobert Watson * the port number intact after the connection is dropped. 948c0a211c5SRobert Watson * 949c0a211c5SRobert Watson * XXXRW: Possibly in_pcbdrop() should also prevent future notifications by 950c0a211c5SRobert Watson * in_pcbnotifyall() and in_pcbpurgeif0()? 95110702a28SRobert Watson */ 95210702a28SRobert Watson void 95310702a28SRobert Watson in_pcbdrop(struct inpcb *inp) 95410702a28SRobert Watson { 95510702a28SRobert Watson 9567c5a8ab2SMarcel Moolenaar INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); 9578501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 95810702a28SRobert Watson 95910702a28SRobert Watson inp->inp_vflag |= INP_DROPPED; 96010702a28SRobert Watson if (inp->inp_lport) { 96110702a28SRobert Watson struct inpcbport *phd = inp->inp_phd; 96210702a28SRobert Watson 96310702a28SRobert Watson LIST_REMOVE(inp, inp_hash); 96410702a28SRobert Watson LIST_REMOVE(inp, inp_portlist); 96510702a28SRobert Watson if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 96610702a28SRobert Watson LIST_REMOVE(phd, phd_hash); 96710702a28SRobert Watson free(phd, M_PCB); 96810702a28SRobert Watson } 96910702a28SRobert Watson inp->inp_lport = 0; 97010702a28SRobert Watson } 97110702a28SRobert Watson } 97210702a28SRobert Watson 97354d642bbSRobert Watson /* 97454d642bbSRobert Watson * Common routines to return the socket addresses associated with inpcbs. 97554d642bbSRobert Watson */ 97626ef6ac4SDon Lewis struct sockaddr * 977136d4f1cSRobert Watson in_sockaddr(in_port_t port, struct in_addr *addr_p) 97826ef6ac4SDon Lewis { 97926ef6ac4SDon Lewis struct sockaddr_in *sin; 98026ef6ac4SDon Lewis 9811ede983cSDag-Erling Smørgrav sin = malloc(sizeof *sin, M_SONAME, 982a163d034SWarner Losh M_WAITOK | M_ZERO); 98326ef6ac4SDon Lewis sin->sin_family = AF_INET; 98426ef6ac4SDon Lewis sin->sin_len = sizeof(*sin); 98526ef6ac4SDon Lewis sin->sin_addr = *addr_p; 98626ef6ac4SDon Lewis sin->sin_port = port; 98726ef6ac4SDon Lewis 98826ef6ac4SDon Lewis return (struct sockaddr *)sin; 98926ef6ac4SDon Lewis } 99026ef6ac4SDon Lewis 991117bcae7SGarrett Wollman int 99254d642bbSRobert Watson in_getsockaddr(struct socket *so, struct sockaddr **nam) 993df8bae1dSRodney W. Grimes { 994136d4f1cSRobert Watson struct inpcb *inp; 99526ef6ac4SDon Lewis struct in_addr addr; 99626ef6ac4SDon Lewis in_port_t port; 99742fa505bSDavid Greenman 998fdc984f7STor Egge inp = sotoinpcb(so); 99954d642bbSRobert Watson KASSERT(inp != NULL, ("in_getsockaddr: inp == NULL")); 10006466b28aSRobert Watson 1001a69042a5SRobert Watson INP_RLOCK(inp); 100226ef6ac4SDon Lewis port = inp->inp_lport; 100326ef6ac4SDon Lewis addr = inp->inp_laddr; 1004a69042a5SRobert Watson INP_RUNLOCK(inp); 100542fa505bSDavid Greenman 100626ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 1007117bcae7SGarrett Wollman return 0; 1008df8bae1dSRodney W. Grimes } 1009df8bae1dSRodney W. Grimes 1010117bcae7SGarrett Wollman int 101154d642bbSRobert Watson in_getpeeraddr(struct socket *so, struct sockaddr **nam) 1012df8bae1dSRodney W. Grimes { 1013136d4f1cSRobert Watson struct inpcb *inp; 101426ef6ac4SDon Lewis struct in_addr addr; 101526ef6ac4SDon Lewis in_port_t port; 101642fa505bSDavid Greenman 1017fdc984f7STor Egge inp = sotoinpcb(so); 101854d642bbSRobert Watson KASSERT(inp != NULL, ("in_getpeeraddr: inp == NULL")); 10196466b28aSRobert Watson 1020a69042a5SRobert Watson INP_RLOCK(inp); 102126ef6ac4SDon Lewis port = inp->inp_fport; 102226ef6ac4SDon Lewis addr = inp->inp_faddr; 1023a69042a5SRobert Watson INP_RUNLOCK(inp); 102442fa505bSDavid Greenman 102526ef6ac4SDon Lewis *nam = in_sockaddr(port, &addr); 1026117bcae7SGarrett Wollman return 0; 1027df8bae1dSRodney W. Grimes } 1028df8bae1dSRodney W. Grimes 102926f9a767SRodney W. Grimes void 1030136d4f1cSRobert Watson in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr faddr, int errno, 1031136d4f1cSRobert Watson struct inpcb *(*notify)(struct inpcb *, int)) 1032d1c54148SJesper Skriver { 1033f457d580SRobert Watson struct inpcb *inp, *inp_temp; 1034d1c54148SJesper Skriver 10353dc7ebf9SJeffrey Hsu INP_INFO_WLOCK(pcbinfo); 1036f457d580SRobert Watson LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { 10378501a69cSRobert Watson INP_WLOCK(inp); 1038d1c54148SJesper Skriver #ifdef INET6 1039f76fcf6dSJeffrey Hsu if ((inp->inp_vflag & INP_IPV4) == 0) { 10408501a69cSRobert Watson INP_WUNLOCK(inp); 1041d1c54148SJesper Skriver continue; 1042f76fcf6dSJeffrey Hsu } 1043d1c54148SJesper Skriver #endif 1044d1c54148SJesper Skriver if (inp->inp_faddr.s_addr != faddr.s_addr || 1045f76fcf6dSJeffrey Hsu inp->inp_socket == NULL) { 10468501a69cSRobert Watson INP_WUNLOCK(inp); 1047d1c54148SJesper Skriver continue; 1048d1c54148SJesper Skriver } 10493dc7ebf9SJeffrey Hsu if ((*notify)(inp, errno)) 10508501a69cSRobert Watson INP_WUNLOCK(inp); 1051f76fcf6dSJeffrey Hsu } 10523dc7ebf9SJeffrey Hsu INP_INFO_WUNLOCK(pcbinfo); 1053d1c54148SJesper Skriver } 1054d1c54148SJesper Skriver 1055e43cc4aeSHajimu UMEMOTO void 1056136d4f1cSRobert Watson in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) 1057e43cc4aeSHajimu UMEMOTO { 1058e43cc4aeSHajimu UMEMOTO struct inpcb *inp; 1059e43cc4aeSHajimu UMEMOTO struct ip_moptions *imo; 1060e43cc4aeSHajimu UMEMOTO int i, gap; 1061e43cc4aeSHajimu UMEMOTO 1062f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(pcbinfo); 1063712fc218SRobert Watson LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { 10648501a69cSRobert Watson INP_WLOCK(inp); 1065e43cc4aeSHajimu UMEMOTO imo = inp->inp_moptions; 1066e43cc4aeSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV4) && 1067e43cc4aeSHajimu UMEMOTO imo != NULL) { 1068e43cc4aeSHajimu UMEMOTO /* 1069e43cc4aeSHajimu UMEMOTO * Unselect the outgoing interface if it is being 1070e43cc4aeSHajimu UMEMOTO * detached. 1071e43cc4aeSHajimu UMEMOTO */ 1072e43cc4aeSHajimu UMEMOTO if (imo->imo_multicast_ifp == ifp) 1073e43cc4aeSHajimu UMEMOTO imo->imo_multicast_ifp = NULL; 1074e43cc4aeSHajimu UMEMOTO 1075e43cc4aeSHajimu UMEMOTO /* 1076e43cc4aeSHajimu UMEMOTO * Drop multicast group membership if we joined 1077e43cc4aeSHajimu UMEMOTO * through the interface being detached. 1078e43cc4aeSHajimu UMEMOTO */ 1079e43cc4aeSHajimu UMEMOTO for (i = 0, gap = 0; i < imo->imo_num_memberships; 1080e43cc4aeSHajimu UMEMOTO i++) { 1081e43cc4aeSHajimu UMEMOTO if (imo->imo_membership[i]->inm_ifp == ifp) { 1082e43cc4aeSHajimu UMEMOTO in_delmulti(imo->imo_membership[i]); 1083e43cc4aeSHajimu UMEMOTO gap++; 1084e43cc4aeSHajimu UMEMOTO } else if (gap != 0) 1085e43cc4aeSHajimu UMEMOTO imo->imo_membership[i - gap] = 1086e43cc4aeSHajimu UMEMOTO imo->imo_membership[i]; 1087e43cc4aeSHajimu UMEMOTO } 1088e43cc4aeSHajimu UMEMOTO imo->imo_num_memberships -= gap; 1089e43cc4aeSHajimu UMEMOTO } 10908501a69cSRobert Watson INP_WUNLOCK(inp); 1091e43cc4aeSHajimu UMEMOTO } 10923cfcc388SJeffrey Hsu INP_INFO_RUNLOCK(pcbinfo); 1093e43cc4aeSHajimu UMEMOTO } 1094e43cc4aeSHajimu UMEMOTO 1095df8bae1dSRodney W. Grimes /* 1096c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 1097c3229e05SDavid Greenman */ 1098d5e8a67eSHajimu UMEMOTO #define INP_LOOKUP_MAPPED_PCB_COST 3 1099df8bae1dSRodney W. Grimes struct inpcb * 1100136d4f1cSRobert Watson in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr, 1101078b7042SBjoern A. Zeeb u_short lport, int wild_okay, struct ucred *cred) 1102df8bae1dSRodney W. Grimes { 1103136d4f1cSRobert Watson struct inpcb *inp; 1104d5e8a67eSHajimu UMEMOTO #ifdef INET6 1105d5e8a67eSHajimu UMEMOTO int matchwild = 3 + INP_LOOKUP_MAPPED_PCB_COST; 1106d5e8a67eSHajimu UMEMOTO #else 1107d5e8a67eSHajimu UMEMOTO int matchwild = 3; 1108d5e8a67eSHajimu UMEMOTO #endif 1109d5e8a67eSHajimu UMEMOTO int wildcard; 11107bc4aca7SDavid Greenman 11118501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 11121b73ca0bSSam Leffler 1113c3229e05SDavid Greenman if (!wild_okay) { 1114c3229e05SDavid Greenman struct inpcbhead *head; 1115c3229e05SDavid Greenman /* 1116c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 1117c3229e05SDavid Greenman * matches the local address and port we're looking for. 1118c3229e05SDavid Greenman */ 1119712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1120712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1121fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1122cfa1ca9dSYoshinobu Inoue #ifdef INET6 1123413628a7SBjoern A. Zeeb /* XXX inp locking */ 1124369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1125cfa1ca9dSYoshinobu Inoue continue; 1126cfa1ca9dSYoshinobu Inoue #endif 1127c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 1128c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1129c3229e05SDavid Greenman inp->inp_lport == lport) { 1130c3229e05SDavid Greenman /* 1131413628a7SBjoern A. Zeeb * Found? 1132c3229e05SDavid Greenman */ 1133413628a7SBjoern A. Zeeb if (cred == NULL || 1134413628a7SBjoern A. Zeeb inp->inp_cred->cr_prison == cred->cr_prison) 1135c3229e05SDavid Greenman return (inp); 1136df8bae1dSRodney W. Grimes } 1137c3229e05SDavid Greenman } 1138c3229e05SDavid Greenman /* 1139c3229e05SDavid Greenman * Not found. 1140c3229e05SDavid Greenman */ 1141c3229e05SDavid Greenman return (NULL); 1142c3229e05SDavid Greenman } else { 1143c3229e05SDavid Greenman struct inpcbporthead *porthash; 1144c3229e05SDavid Greenman struct inpcbport *phd; 1145c3229e05SDavid Greenman struct inpcb *match = NULL; 1146c3229e05SDavid Greenman /* 1147c3229e05SDavid Greenman * Best fit PCB lookup. 1148c3229e05SDavid Greenman * 1149c3229e05SDavid Greenman * First see if this local port is in use by looking on the 1150c3229e05SDavid Greenman * port hash list. 1151c3229e05SDavid Greenman */ 1152712fc218SRobert Watson porthash = &pcbinfo->ipi_porthashbase[INP_PCBPORTHASH(lport, 1153712fc218SRobert Watson pcbinfo->ipi_porthashmask)]; 1154fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, porthash, phd_hash) { 1155c3229e05SDavid Greenman if (phd->phd_port == lport) 1156c3229e05SDavid Greenman break; 1157c3229e05SDavid Greenman } 1158c3229e05SDavid Greenman if (phd != NULL) { 1159c3229e05SDavid Greenman /* 1160c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 1161c3229e05SDavid Greenman * fit. 1162c3229e05SDavid Greenman */ 116337d40066SPoul-Henning Kamp LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 1164c3229e05SDavid Greenman wildcard = 0; 1165413628a7SBjoern A. Zeeb if (cred != NULL && 1166413628a7SBjoern A. Zeeb inp->inp_cred->cr_prison != cred->cr_prison) 1167413628a7SBjoern A. Zeeb continue; 1168cfa1ca9dSYoshinobu Inoue #ifdef INET6 1169413628a7SBjoern A. Zeeb /* XXX inp locking */ 1170369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1171cfa1ca9dSYoshinobu Inoue continue; 1172d5e8a67eSHajimu UMEMOTO /* 1173d5e8a67eSHajimu UMEMOTO * We never select the PCB that has 1174d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag and is bound to :: if 1175d5e8a67eSHajimu UMEMOTO * we have another PCB which is bound 1176d5e8a67eSHajimu UMEMOTO * to 0.0.0.0. If a PCB has the 1177d5e8a67eSHajimu UMEMOTO * INP_IPV6 flag, then we set its cost 1178d5e8a67eSHajimu UMEMOTO * higher than IPv4 only PCBs. 1179d5e8a67eSHajimu UMEMOTO * 1180d5e8a67eSHajimu UMEMOTO * Note that the case only happens 1181d5e8a67eSHajimu UMEMOTO * when a socket is bound to ::, under 1182d5e8a67eSHajimu UMEMOTO * the condition that the use of the 1183d5e8a67eSHajimu UMEMOTO * mapped address is allowed. 1184d5e8a67eSHajimu UMEMOTO */ 1185d5e8a67eSHajimu UMEMOTO if ((inp->inp_vflag & INP_IPV6) != 0) 1186d5e8a67eSHajimu UMEMOTO wildcard += INP_LOOKUP_MAPPED_PCB_COST; 1187cfa1ca9dSYoshinobu Inoue #endif 1188c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 1189c3229e05SDavid Greenman wildcard++; 119015bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 119115bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 119215bd2b43SDavid Greenman wildcard++; 119315bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 119415bd2b43SDavid Greenman continue; 119515bd2b43SDavid Greenman } else { 119615bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 119715bd2b43SDavid Greenman wildcard++; 119815bd2b43SDavid Greenman } 1199df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 1200df8bae1dSRodney W. Grimes match = inp; 1201df8bae1dSRodney W. Grimes matchwild = wildcard; 1202413628a7SBjoern A. Zeeb if (matchwild == 0) 1203df8bae1dSRodney W. Grimes break; 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes } 12063dbdc25cSDavid Greenman } 1207df8bae1dSRodney W. Grimes return (match); 1208df8bae1dSRodney W. Grimes } 1209c3229e05SDavid Greenman } 1210d5e8a67eSHajimu UMEMOTO #undef INP_LOOKUP_MAPPED_PCB_COST 121115bd2b43SDavid Greenman 121215bd2b43SDavid Greenman /* 121315bd2b43SDavid Greenman * Lookup PCB in hash list. 121415bd2b43SDavid Greenman */ 121515bd2b43SDavid Greenman struct inpcb * 1216136d4f1cSRobert Watson in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr, 1217136d4f1cSRobert Watson u_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard, 1218136d4f1cSRobert Watson struct ifnet *ifp) 121915bd2b43SDavid Greenman { 122015bd2b43SDavid Greenman struct inpcbhead *head; 1221413628a7SBjoern A. Zeeb struct inpcb *inp, *tmpinp; 122215bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 122315bd2b43SDavid Greenman 12248501a69cSRobert Watson INP_INFO_LOCK_ASSERT(pcbinfo); 1225602cc7f1SRobert Watson 122615bd2b43SDavid Greenman /* 122715bd2b43SDavid Greenman * First look for an exact match. 122815bd2b43SDavid Greenman */ 1229413628a7SBjoern A. Zeeb tmpinp = NULL; 1230712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, 1231712fc218SRobert Watson pcbinfo->ipi_hashmask)]; 1232fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1233cfa1ca9dSYoshinobu Inoue #ifdef INET6 1234413628a7SBjoern A. Zeeb /* XXX inp locking */ 1235369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1236cfa1ca9dSYoshinobu Inoue continue; 1237cfa1ca9dSYoshinobu Inoue #endif 12386d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 1239ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 1240ca98b82cSDavid Greenman inp->inp_fport == fport && 1241413628a7SBjoern A. Zeeb inp->inp_lport == lport) { 1242413628a7SBjoern A. Zeeb /* 1243413628a7SBjoern A. Zeeb * XXX We should be able to directly return 1244413628a7SBjoern A. Zeeb * the inp here, without any checks. 1245413628a7SBjoern A. Zeeb * Well unless both bound with SO_REUSEPORT? 1246413628a7SBjoern A. Zeeb */ 1247413628a7SBjoern A. Zeeb if (jailed(inp->inp_cred)) 1248c3229e05SDavid Greenman return (inp); 1249413628a7SBjoern A. Zeeb if (tmpinp == NULL) 1250413628a7SBjoern A. Zeeb tmpinp = inp; 1251c3229e05SDavid Greenman } 1252413628a7SBjoern A. Zeeb } 1253413628a7SBjoern A. Zeeb if (tmpinp != NULL) 1254413628a7SBjoern A. Zeeb return (tmpinp); 1255e3fd5ffdSRobert Watson 1256e3fd5ffdSRobert Watson /* 1257e3fd5ffdSRobert Watson * Then look for a wildcard match, if requested. 1258e3fd5ffdSRobert Watson */ 1259413628a7SBjoern A. Zeeb if (wildcard == INPLOOKUP_WILDCARD) { 1260413628a7SBjoern A. Zeeb struct inpcb *local_wild = NULL, *local_exact = NULL; 1261e3fd5ffdSRobert Watson #ifdef INET6 1262cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 1263e3fd5ffdSRobert Watson #endif 1264413628a7SBjoern A. Zeeb struct inpcb *jail_wild = NULL; 1265413628a7SBjoern A. Zeeb int injail; 1266413628a7SBjoern A. Zeeb 1267413628a7SBjoern A. Zeeb /* 1268413628a7SBjoern A. Zeeb * Order of socket selection - we always prefer jails. 1269413628a7SBjoern A. Zeeb * 1. jailed, non-wild. 1270413628a7SBjoern A. Zeeb * 2. jailed, wild. 1271413628a7SBjoern A. Zeeb * 3. non-jailed, non-wild. 1272413628a7SBjoern A. Zeeb * 4. non-jailed, wild. 1273413628a7SBjoern A. Zeeb */ 12746d6a026bSDavid Greenman 1275712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, 1276712fc218SRobert Watson 0, pcbinfo->ipi_hashmask)]; 1277fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(inp, head, inp_hash) { 1278cfa1ca9dSYoshinobu Inoue #ifdef INET6 1279413628a7SBjoern A. Zeeb /* XXX inp locking */ 1280369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 1281cfa1ca9dSYoshinobu Inoue continue; 1282cfa1ca9dSYoshinobu Inoue #endif 1283413628a7SBjoern A. Zeeb if (inp->inp_faddr.s_addr != INADDR_ANY || 1284413628a7SBjoern A. Zeeb inp->inp_lport != lport) 1285413628a7SBjoern A. Zeeb continue; 1286413628a7SBjoern A. Zeeb 1287413628a7SBjoern A. Zeeb /* XXX inp locking */ 1288cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 1289cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 1290cfa1ca9dSYoshinobu Inoue continue; 1291413628a7SBjoern A. Zeeb 1292413628a7SBjoern A. Zeeb injail = jailed(inp->inp_cred); 1293413628a7SBjoern A. Zeeb if (injail) { 1294413628a7SBjoern A. Zeeb if (!prison_check_ip4(inp->inp_cred, &laddr)) 1295413628a7SBjoern A. Zeeb continue; 1296413628a7SBjoern A. Zeeb } else { 1297413628a7SBjoern A. Zeeb if (local_exact != NULL) 1298413628a7SBjoern A. Zeeb continue; 1299413628a7SBjoern A. Zeeb } 1300413628a7SBjoern A. Zeeb 1301413628a7SBjoern A. Zeeb if (inp->inp_laddr.s_addr == laddr.s_addr) { 1302413628a7SBjoern A. Zeeb if (injail) 1303c3229e05SDavid Greenman return (inp); 1304413628a7SBjoern A. Zeeb else 1305413628a7SBjoern A. Zeeb local_exact = inp; 1306413628a7SBjoern A. Zeeb } else if (inp->inp_laddr.s_addr == INADDR_ANY) { 1307e3fd5ffdSRobert Watson #ifdef INET6 1308413628a7SBjoern A. Zeeb /* XXX inp locking, NULL check */ 13095cd54324SBjoern A. Zeeb if (inp->inp_vflag & INP_IPV6PROTO) 1310cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 1311cfa1ca9dSYoshinobu Inoue else 1312413628a7SBjoern A. Zeeb #endif /* INET6 */ 1313413628a7SBjoern A. Zeeb if (injail) 1314413628a7SBjoern A. Zeeb jail_wild = inp; 1315413628a7SBjoern A. Zeeb else 13166d6a026bSDavid Greenman local_wild = inp; 13176d6a026bSDavid Greenman } 1318413628a7SBjoern A. Zeeb } /* LIST_FOREACH */ 1319413628a7SBjoern A. Zeeb if (jail_wild != NULL) 1320413628a7SBjoern A. Zeeb return (jail_wild); 1321413628a7SBjoern A. Zeeb if (local_exact != NULL) 1322413628a7SBjoern A. Zeeb return (local_exact); 1323413628a7SBjoern A. Zeeb if (local_wild != NULL) 1324c3229e05SDavid Greenman return (local_wild); 1325413628a7SBjoern A. Zeeb #ifdef INET6 1326413628a7SBjoern A. Zeeb if (local_wild_mapped != NULL) 1327413628a7SBjoern A. Zeeb return (local_wild_mapped); 1328413628a7SBjoern A. Zeeb #endif /* defined(INET6) */ 1329413628a7SBjoern A. Zeeb } /* if (wildcard == INPLOOKUP_WILDCARD) */ 1330413628a7SBjoern A. Zeeb 13316d6a026bSDavid Greenman return (NULL); 133215bd2b43SDavid Greenman } 133315bd2b43SDavid Greenman 13347bc4aca7SDavid Greenman /* 1335c3229e05SDavid Greenman * Insert PCB onto various hash lists. 13367bc4aca7SDavid Greenman */ 1337c3229e05SDavid Greenman int 1338136d4f1cSRobert Watson in_pcbinshash(struct inpcb *inp) 133915bd2b43SDavid Greenman { 1340c3229e05SDavid Greenman struct inpcbhead *pcbhash; 1341c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 1342c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 1343c3229e05SDavid Greenman struct inpcbport *phd; 1344cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 134515bd2b43SDavid Greenman 134659daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 13478501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1348602cc7f1SRobert Watson 1349cfa1ca9dSYoshinobu Inoue #ifdef INET6 1350cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1351cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1352cfa1ca9dSYoshinobu Inoue else 1353cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1354cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1355cfa1ca9dSYoshinobu Inoue 1356712fc218SRobert Watson pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1357712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 135815bd2b43SDavid Greenman 1359712fc218SRobert Watson pcbporthash = &pcbinfo->ipi_porthashbase[ 1360712fc218SRobert Watson INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; 1361c3229e05SDavid Greenman 1362c3229e05SDavid Greenman /* 1363c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 1364c3229e05SDavid Greenman */ 1365fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(phd, pcbporthash, phd_hash) { 1366c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 1367c3229e05SDavid Greenman break; 1368c3229e05SDavid Greenman } 1369c3229e05SDavid Greenman /* 1370c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 1371c3229e05SDavid Greenman */ 1372c3229e05SDavid Greenman if (phd == NULL) { 13731ede983cSDag-Erling Smørgrav phd = malloc(sizeof(struct inpcbport), M_PCB, M_NOWAIT); 1374c3229e05SDavid Greenman if (phd == NULL) { 1375c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 1376c3229e05SDavid Greenman } 1377c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 1378c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 1379c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 1380c3229e05SDavid Greenman } 1381c3229e05SDavid Greenman inp->inp_phd = phd; 1382c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 1383c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 1384c3229e05SDavid Greenman return (0); 138515bd2b43SDavid Greenman } 138615bd2b43SDavid Greenman 1387c3229e05SDavid Greenman /* 1388c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 1389c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 1390c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 1391c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 1392c3229e05SDavid Greenman */ 139315bd2b43SDavid Greenman void 1394136d4f1cSRobert Watson in_pcbrehash(struct inpcb *inp) 139515bd2b43SDavid Greenman { 139659daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 139715bd2b43SDavid Greenman struct inpcbhead *head; 1398cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 139915bd2b43SDavid Greenman 140059daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 14018501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 1402602cc7f1SRobert Watson 1403cfa1ca9dSYoshinobu Inoue #ifdef INET6 1404cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 1405cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 1406cfa1ca9dSYoshinobu Inoue else 1407cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 1408cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 1409cfa1ca9dSYoshinobu Inoue 1410712fc218SRobert Watson head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, 1411712fc218SRobert Watson inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; 141215bd2b43SDavid Greenman 1413c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 141415bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 1415c3229e05SDavid Greenman } 1416c3229e05SDavid Greenman 1417c3229e05SDavid Greenman /* 1418c3229e05SDavid Greenman * Remove PCB from various lists. 1419c3229e05SDavid Greenman */ 142076429de4SYoshinobu Inoue void 1421136d4f1cSRobert Watson in_pcbremlists(struct inpcb *inp) 1422c3229e05SDavid Greenman { 142359daba27SSam Leffler struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 142459daba27SSam Leffler 142559daba27SSam Leffler INP_INFO_WLOCK_ASSERT(pcbinfo); 14268501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 142759daba27SSam Leffler 142859daba27SSam Leffler inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 1429c3229e05SDavid Greenman if (inp->inp_lport) { 1430c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 1431c3229e05SDavid Greenman 1432c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1433c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1434fc2ffbe6SPoul-Henning Kamp if (LIST_FIRST(&phd->phd_pcblist) == NULL) { 1435c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1436c3229e05SDavid Greenman free(phd, M_PCB); 1437c3229e05SDavid Greenman } 1438c3229e05SDavid Greenman } 1439c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 144059daba27SSam Leffler pcbinfo->ipi_count--; 144115bd2b43SDavid Greenman } 144275c13541SPoul-Henning Kamp 1443a557af22SRobert Watson /* 1444a557af22SRobert Watson * A set label operation has occurred at the socket layer, propagate the 1445a557af22SRobert Watson * label change into the in_pcb for the socket. 1446a557af22SRobert Watson */ 1447a557af22SRobert Watson void 1448136d4f1cSRobert Watson in_pcbsosetlabel(struct socket *so) 1449a557af22SRobert Watson { 1450a557af22SRobert Watson #ifdef MAC 1451a557af22SRobert Watson struct inpcb *inp; 1452a557af22SRobert Watson 14534c7c478dSRobert Watson inp = sotoinpcb(so); 14544c7c478dSRobert Watson KASSERT(inp != NULL, ("in_pcbsosetlabel: so->so_pcb == NULL")); 1455602cc7f1SRobert Watson 14568501a69cSRobert Watson INP_WLOCK(inp); 1457310e7cebSRobert Watson SOCK_LOCK(so); 1458a557af22SRobert Watson mac_inpcb_sosetlabel(so, inp); 1459310e7cebSRobert Watson SOCK_UNLOCK(so); 14608501a69cSRobert Watson INP_WUNLOCK(inp); 1461a557af22SRobert Watson #endif 1462a557af22SRobert Watson } 14635f311da2SMike Silbersack 14645f311da2SMike Silbersack /* 1465ad3a630fSRobert Watson * ipport_tick runs once per second, determining if random port allocation 1466ad3a630fSRobert Watson * should be continued. If more than ipport_randomcps ports have been 1467ad3a630fSRobert Watson * allocated in the last second, then we return to sequential port 1468ad3a630fSRobert Watson * allocation. We return to random allocation only once we drop below 1469ad3a630fSRobert Watson * ipport_randomcps for at least ipport_randomtime seconds. 14705f311da2SMike Silbersack */ 14715f311da2SMike Silbersack void 1472136d4f1cSRobert Watson ipport_tick(void *xtp) 14735f311da2SMike Silbersack { 14748b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 1475ad3a630fSRobert Watson 14768b615593SMarko Zec VNET_LIST_RLOCK(); 14778b615593SMarko Zec VNET_FOREACH(vnet_iter) { 14788b615593SMarko Zec CURVNET_SET(vnet_iter); /* XXX appease INVARIANTS here */ 14798b615593SMarko Zec INIT_VNET_INET(vnet_iter); 14808b615593SMarko Zec if (V_ipport_tcpallocs <= 14818b615593SMarko Zec V_ipport_tcplastcount + V_ipport_randomcps) { 1482603724d3SBjoern A. Zeeb if (V_ipport_stoprandom > 0) 1483603724d3SBjoern A. Zeeb V_ipport_stoprandom--; 1484ad3a630fSRobert Watson } else 1485603724d3SBjoern A. Zeeb V_ipport_stoprandom = V_ipport_randomtime; 1486603724d3SBjoern A. Zeeb V_ipport_tcplastcount = V_ipport_tcpallocs; 14878b615593SMarko Zec CURVNET_RESTORE(); 14888b615593SMarko Zec } 14898b615593SMarko Zec VNET_LIST_RUNLOCK(); 14905f311da2SMike Silbersack callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL); 14915f311da2SMike Silbersack } 1492497057eeSRobert Watson 14933d585327SKip Macy void 14943d585327SKip Macy inp_wlock(struct inpcb *inp) 14953d585327SKip Macy { 14963d585327SKip Macy 14978501a69cSRobert Watson INP_WLOCK(inp); 14983d585327SKip Macy } 14993d585327SKip Macy 15003d585327SKip Macy void 15013d585327SKip Macy inp_wunlock(struct inpcb *inp) 15023d585327SKip Macy { 15033d585327SKip Macy 15048501a69cSRobert Watson INP_WUNLOCK(inp); 15053d585327SKip Macy } 15063d585327SKip Macy 15073d585327SKip Macy void 15083d585327SKip Macy inp_rlock(struct inpcb *inp) 15093d585327SKip Macy { 15103d585327SKip Macy 1511a69042a5SRobert Watson INP_RLOCK(inp); 15123d585327SKip Macy } 15133d585327SKip Macy 15143d585327SKip Macy void 15153d585327SKip Macy inp_runlock(struct inpcb *inp) 15163d585327SKip Macy { 15173d585327SKip Macy 1518a69042a5SRobert Watson INP_RUNLOCK(inp); 15193d585327SKip Macy } 15203d585327SKip Macy 15213d585327SKip Macy #ifdef INVARIANTS 15223d585327SKip Macy void 1523e79dd20dSKip Macy inp_lock_assert(struct inpcb *inp) 15243d585327SKip Macy { 15253d585327SKip Macy 15268501a69cSRobert Watson INP_WLOCK_ASSERT(inp); 15273d585327SKip Macy } 15283d585327SKip Macy 15293d585327SKip Macy void 1530e79dd20dSKip Macy inp_unlock_assert(struct inpcb *inp) 15313d585327SKip Macy { 15323d585327SKip Macy 15333d585327SKip Macy INP_UNLOCK_ASSERT(inp); 15343d585327SKip Macy } 15353d585327SKip Macy #endif 15363d585327SKip Macy 15379378e437SKip Macy void 15389378e437SKip Macy inp_apply_all(void (*func)(struct inpcb *, void *), void *arg) 15399378e437SKip Macy { 15408b615593SMarko Zec INIT_VNET_INET(curvnet); 15419378e437SKip Macy struct inpcb *inp; 15429378e437SKip Macy 1543603724d3SBjoern A. Zeeb INP_INFO_RLOCK(&V_tcbinfo); 154497021c24SMarko Zec LIST_FOREACH(inp, V_tcbinfo.ipi_listhead, inp_list) { 15459378e437SKip Macy INP_WLOCK(inp); 15469378e437SKip Macy func(inp, arg); 15479378e437SKip Macy INP_WUNLOCK(inp); 15489378e437SKip Macy } 1549603724d3SBjoern A. Zeeb INP_INFO_RUNLOCK(&V_tcbinfo); 15509378e437SKip Macy } 15519378e437SKip Macy 15529378e437SKip Macy struct socket * 15539378e437SKip Macy inp_inpcbtosocket(struct inpcb *inp) 15549378e437SKip Macy { 15559378e437SKip Macy 15569378e437SKip Macy INP_WLOCK_ASSERT(inp); 15579378e437SKip Macy return (inp->inp_socket); 15589378e437SKip Macy } 15599378e437SKip Macy 15609378e437SKip Macy struct tcpcb * 15619378e437SKip Macy inp_inpcbtotcpcb(struct inpcb *inp) 15629378e437SKip Macy { 15639378e437SKip Macy 15649378e437SKip Macy INP_WLOCK_ASSERT(inp); 15659378e437SKip Macy return ((struct tcpcb *)inp->inp_ppcb); 15669378e437SKip Macy } 15679378e437SKip Macy 15689378e437SKip Macy int 15699378e437SKip Macy inp_ip_tos_get(const struct inpcb *inp) 15709378e437SKip Macy { 15719378e437SKip Macy 15729378e437SKip Macy return (inp->inp_ip_tos); 15739378e437SKip Macy } 15749378e437SKip Macy 15759378e437SKip Macy void 15769378e437SKip Macy inp_ip_tos_set(struct inpcb *inp, int val) 15779378e437SKip Macy { 15789378e437SKip Macy 15799378e437SKip Macy inp->inp_ip_tos = val; 15809378e437SKip Macy } 15819378e437SKip Macy 15829378e437SKip Macy void 1583df9cf830STai-hwa Liang inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, 15849d29c635SKip Macy uint32_t *faddr, uint16_t *fp) 15859378e437SKip Macy { 15869378e437SKip Macy 15879d29c635SKip Macy INP_LOCK_ASSERT(inp); 1588df9cf830STai-hwa Liang *laddr = inp->inp_laddr.s_addr; 1589df9cf830STai-hwa Liang *faddr = inp->inp_faddr.s_addr; 15909378e437SKip Macy *lp = inp->inp_lport; 15919378e437SKip Macy *fp = inp->inp_fport; 15929378e437SKip Macy } 15939378e437SKip Macy 1594dd0e6c38SKip Macy struct inpcb * 1595dd0e6c38SKip Macy so_sotoinpcb(struct socket *so) 1596dd0e6c38SKip Macy { 1597dd0e6c38SKip Macy 1598dd0e6c38SKip Macy return (sotoinpcb(so)); 1599dd0e6c38SKip Macy } 1600dd0e6c38SKip Macy 1601dd0e6c38SKip Macy struct tcpcb * 1602dd0e6c38SKip Macy so_sototcpcb(struct socket *so) 1603dd0e6c38SKip Macy { 1604dd0e6c38SKip Macy 1605dd0e6c38SKip Macy return (sototcpcb(so)); 1606dd0e6c38SKip Macy } 1607dd0e6c38SKip Macy 1608497057eeSRobert Watson #ifdef DDB 1609497057eeSRobert Watson static void 1610497057eeSRobert Watson db_print_indent(int indent) 1611497057eeSRobert Watson { 1612497057eeSRobert Watson int i; 1613497057eeSRobert Watson 1614497057eeSRobert Watson for (i = 0; i < indent; i++) 1615497057eeSRobert Watson db_printf(" "); 1616497057eeSRobert Watson } 1617497057eeSRobert Watson 1618497057eeSRobert Watson static void 1619497057eeSRobert Watson db_print_inconninfo(struct in_conninfo *inc, const char *name, int indent) 1620497057eeSRobert Watson { 1621497057eeSRobert Watson char faddr_str[48], laddr_str[48]; 1622497057eeSRobert Watson 1623497057eeSRobert Watson db_print_indent(indent); 1624497057eeSRobert Watson db_printf("%s at %p\n", name, inc); 1625497057eeSRobert Watson 1626497057eeSRobert Watson indent += 2; 1627497057eeSRobert Watson 162803dc38a4SRobert Watson #ifdef INET6 1629497057eeSRobert Watson if (inc->inc_flags == 1) { 1630497057eeSRobert Watson /* IPv6. */ 1631497057eeSRobert Watson ip6_sprintf(laddr_str, &inc->inc6_laddr); 1632497057eeSRobert Watson ip6_sprintf(faddr_str, &inc->inc6_faddr); 1633497057eeSRobert Watson } else { 163403dc38a4SRobert Watson #endif 1635497057eeSRobert Watson /* IPv4. */ 1636497057eeSRobert Watson inet_ntoa_r(inc->inc_laddr, laddr_str); 1637497057eeSRobert Watson inet_ntoa_r(inc->inc_faddr, faddr_str); 163803dc38a4SRobert Watson #ifdef INET6 1639497057eeSRobert Watson } 164003dc38a4SRobert Watson #endif 1641497057eeSRobert Watson db_print_indent(indent); 1642497057eeSRobert Watson db_printf("inc_laddr %s inc_lport %u\n", laddr_str, 1643497057eeSRobert Watson ntohs(inc->inc_lport)); 1644497057eeSRobert Watson db_print_indent(indent); 1645497057eeSRobert Watson db_printf("inc_faddr %s inc_fport %u\n", faddr_str, 1646497057eeSRobert Watson ntohs(inc->inc_fport)); 1647497057eeSRobert Watson } 1648497057eeSRobert Watson 1649497057eeSRobert Watson static void 1650497057eeSRobert Watson db_print_inpflags(int inp_flags) 1651497057eeSRobert Watson { 1652497057eeSRobert Watson int comma; 1653497057eeSRobert Watson 1654497057eeSRobert Watson comma = 0; 1655497057eeSRobert Watson if (inp_flags & INP_RECVOPTS) { 1656497057eeSRobert Watson db_printf("%sINP_RECVOPTS", comma ? ", " : ""); 1657497057eeSRobert Watson comma = 1; 1658497057eeSRobert Watson } 1659497057eeSRobert Watson if (inp_flags & INP_RECVRETOPTS) { 1660497057eeSRobert Watson db_printf("%sINP_RECVRETOPTS", comma ? ", " : ""); 1661497057eeSRobert Watson comma = 1; 1662497057eeSRobert Watson } 1663497057eeSRobert Watson if (inp_flags & INP_RECVDSTADDR) { 1664497057eeSRobert Watson db_printf("%sINP_RECVDSTADDR", comma ? ", " : ""); 1665497057eeSRobert Watson comma = 1; 1666497057eeSRobert Watson } 1667497057eeSRobert Watson if (inp_flags & INP_HDRINCL) { 1668497057eeSRobert Watson db_printf("%sINP_HDRINCL", comma ? ", " : ""); 1669497057eeSRobert Watson comma = 1; 1670497057eeSRobert Watson } 1671497057eeSRobert Watson if (inp_flags & INP_HIGHPORT) { 1672497057eeSRobert Watson db_printf("%sINP_HIGHPORT", comma ? ", " : ""); 1673497057eeSRobert Watson comma = 1; 1674497057eeSRobert Watson } 1675497057eeSRobert Watson if (inp_flags & INP_LOWPORT) { 1676497057eeSRobert Watson db_printf("%sINP_LOWPORT", comma ? ", " : ""); 1677497057eeSRobert Watson comma = 1; 1678497057eeSRobert Watson } 1679497057eeSRobert Watson if (inp_flags & INP_ANONPORT) { 1680497057eeSRobert Watson db_printf("%sINP_ANONPORT", comma ? ", " : ""); 1681497057eeSRobert Watson comma = 1; 1682497057eeSRobert Watson } 1683497057eeSRobert Watson if (inp_flags & INP_RECVIF) { 1684497057eeSRobert Watson db_printf("%sINP_RECVIF", comma ? ", " : ""); 1685497057eeSRobert Watson comma = 1; 1686497057eeSRobert Watson } 1687497057eeSRobert Watson if (inp_flags & INP_MTUDISC) { 1688497057eeSRobert Watson db_printf("%sINP_MTUDISC", comma ? ", " : ""); 1689497057eeSRobert Watson comma = 1; 1690497057eeSRobert Watson } 1691497057eeSRobert Watson if (inp_flags & INP_FAITH) { 1692497057eeSRobert Watson db_printf("%sINP_FAITH", comma ? ", " : ""); 1693497057eeSRobert Watson comma = 1; 1694497057eeSRobert Watson } 1695497057eeSRobert Watson if (inp_flags & INP_RECVTTL) { 1696497057eeSRobert Watson db_printf("%sINP_RECVTTL", comma ? ", " : ""); 1697497057eeSRobert Watson comma = 1; 1698497057eeSRobert Watson } 1699497057eeSRobert Watson if (inp_flags & INP_DONTFRAG) { 1700497057eeSRobert Watson db_printf("%sINP_DONTFRAG", comma ? ", " : ""); 1701497057eeSRobert Watson comma = 1; 1702497057eeSRobert Watson } 1703497057eeSRobert Watson if (inp_flags & IN6P_IPV6_V6ONLY) { 1704497057eeSRobert Watson db_printf("%sIN6P_IPV6_V6ONLY", comma ? ", " : ""); 1705497057eeSRobert Watson comma = 1; 1706497057eeSRobert Watson } 1707497057eeSRobert Watson if (inp_flags & IN6P_PKTINFO) { 1708497057eeSRobert Watson db_printf("%sIN6P_PKTINFO", comma ? ", " : ""); 1709497057eeSRobert Watson comma = 1; 1710497057eeSRobert Watson } 1711497057eeSRobert Watson if (inp_flags & IN6P_HOPLIMIT) { 1712497057eeSRobert Watson db_printf("%sIN6P_HOPLIMIT", comma ? ", " : ""); 1713497057eeSRobert Watson comma = 1; 1714497057eeSRobert Watson } 1715497057eeSRobert Watson if (inp_flags & IN6P_HOPOPTS) { 1716497057eeSRobert Watson db_printf("%sIN6P_HOPOPTS", comma ? ", " : ""); 1717497057eeSRobert Watson comma = 1; 1718497057eeSRobert Watson } 1719497057eeSRobert Watson if (inp_flags & IN6P_DSTOPTS) { 1720497057eeSRobert Watson db_printf("%sIN6P_DSTOPTS", comma ? ", " : ""); 1721497057eeSRobert Watson comma = 1; 1722497057eeSRobert Watson } 1723497057eeSRobert Watson if (inp_flags & IN6P_RTHDR) { 1724497057eeSRobert Watson db_printf("%sIN6P_RTHDR", comma ? ", " : ""); 1725497057eeSRobert Watson comma = 1; 1726497057eeSRobert Watson } 1727497057eeSRobert Watson if (inp_flags & IN6P_RTHDRDSTOPTS) { 1728497057eeSRobert Watson db_printf("%sIN6P_RTHDRDSTOPTS", comma ? ", " : ""); 1729497057eeSRobert Watson comma = 1; 1730497057eeSRobert Watson } 1731497057eeSRobert Watson if (inp_flags & IN6P_TCLASS) { 1732497057eeSRobert Watson db_printf("%sIN6P_TCLASS", comma ? ", " : ""); 1733497057eeSRobert Watson comma = 1; 1734497057eeSRobert Watson } 1735497057eeSRobert Watson if (inp_flags & IN6P_AUTOFLOWLABEL) { 1736497057eeSRobert Watson db_printf("%sIN6P_AUTOFLOWLABEL", comma ? ", " : ""); 1737497057eeSRobert Watson comma = 1; 1738497057eeSRobert Watson } 1739497057eeSRobert Watson if (inp_flags & IN6P_RFC2292) { 1740497057eeSRobert Watson db_printf("%sIN6P_RFC2292", comma ? ", " : ""); 1741497057eeSRobert Watson comma = 1; 1742497057eeSRobert Watson } 1743497057eeSRobert Watson if (inp_flags & IN6P_MTU) { 1744497057eeSRobert Watson db_printf("IN6P_MTU%s", comma ? ", " : ""); 1745497057eeSRobert Watson comma = 1; 1746497057eeSRobert Watson } 1747497057eeSRobert Watson } 1748497057eeSRobert Watson 1749497057eeSRobert Watson static void 1750497057eeSRobert Watson db_print_inpvflag(u_char inp_vflag) 1751497057eeSRobert Watson { 1752497057eeSRobert Watson int comma; 1753497057eeSRobert Watson 1754497057eeSRobert Watson comma = 0; 1755497057eeSRobert Watson if (inp_vflag & INP_IPV4) { 1756497057eeSRobert Watson db_printf("%sINP_IPV4", comma ? ", " : ""); 1757497057eeSRobert Watson comma = 1; 1758497057eeSRobert Watson } 1759497057eeSRobert Watson if (inp_vflag & INP_IPV6) { 1760497057eeSRobert Watson db_printf("%sINP_IPV6", comma ? ", " : ""); 1761497057eeSRobert Watson comma = 1; 1762497057eeSRobert Watson } 1763497057eeSRobert Watson if (inp_vflag & INP_IPV6PROTO) { 1764497057eeSRobert Watson db_printf("%sINP_IPV6PROTO", comma ? ", " : ""); 1765497057eeSRobert Watson comma = 1; 1766497057eeSRobert Watson } 1767497057eeSRobert Watson if (inp_vflag & INP_TIMEWAIT) { 1768497057eeSRobert Watson db_printf("%sINP_TIMEWAIT", comma ? ", " : ""); 1769497057eeSRobert Watson comma = 1; 1770497057eeSRobert Watson } 1771497057eeSRobert Watson if (inp_vflag & INP_ONESBCAST) { 1772497057eeSRobert Watson db_printf("%sINP_ONESBCAST", comma ? ", " : ""); 1773497057eeSRobert Watson comma = 1; 1774497057eeSRobert Watson } 1775497057eeSRobert Watson if (inp_vflag & INP_DROPPED) { 1776497057eeSRobert Watson db_printf("%sINP_DROPPED", comma ? ", " : ""); 1777497057eeSRobert Watson comma = 1; 1778497057eeSRobert Watson } 1779497057eeSRobert Watson if (inp_vflag & INP_SOCKREF) { 1780497057eeSRobert Watson db_printf("%sINP_SOCKREF", comma ? ", " : ""); 1781497057eeSRobert Watson comma = 1; 1782497057eeSRobert Watson } 1783497057eeSRobert Watson } 1784497057eeSRobert Watson 1785497057eeSRobert Watson void 1786497057eeSRobert Watson db_print_inpcb(struct inpcb *inp, const char *name, int indent) 1787497057eeSRobert Watson { 1788497057eeSRobert Watson 1789497057eeSRobert Watson db_print_indent(indent); 1790497057eeSRobert Watson db_printf("%s at %p\n", name, inp); 1791497057eeSRobert Watson 1792497057eeSRobert Watson indent += 2; 1793497057eeSRobert Watson 1794497057eeSRobert Watson db_print_indent(indent); 1795497057eeSRobert Watson db_printf("inp_flow: 0x%x\n", inp->inp_flow); 1796497057eeSRobert Watson 1797497057eeSRobert Watson db_print_inconninfo(&inp->inp_inc, "inp_conninfo", indent); 1798497057eeSRobert Watson 1799497057eeSRobert Watson db_print_indent(indent); 1800497057eeSRobert Watson db_printf("inp_ppcb: %p inp_pcbinfo: %p inp_socket: %p\n", 1801497057eeSRobert Watson inp->inp_ppcb, inp->inp_pcbinfo, inp->inp_socket); 1802497057eeSRobert Watson 1803497057eeSRobert Watson db_print_indent(indent); 1804497057eeSRobert Watson db_printf("inp_label: %p inp_flags: 0x%x (", 1805497057eeSRobert Watson inp->inp_label, inp->inp_flags); 1806497057eeSRobert Watson db_print_inpflags(inp->inp_flags); 1807497057eeSRobert Watson db_printf(")\n"); 1808497057eeSRobert Watson 1809497057eeSRobert Watson db_print_indent(indent); 1810497057eeSRobert Watson db_printf("inp_sp: %p inp_vflag: 0x%x (", inp->inp_sp, 1811497057eeSRobert Watson inp->inp_vflag); 1812497057eeSRobert Watson db_print_inpvflag(inp->inp_vflag); 1813497057eeSRobert Watson db_printf(")\n"); 1814497057eeSRobert Watson 1815497057eeSRobert Watson db_print_indent(indent); 1816497057eeSRobert Watson db_printf("inp_ip_ttl: %d inp_ip_p: %d inp_ip_minttl: %d\n", 1817497057eeSRobert Watson inp->inp_ip_ttl, inp->inp_ip_p, inp->inp_ip_minttl); 1818497057eeSRobert Watson 1819497057eeSRobert Watson db_print_indent(indent); 1820497057eeSRobert Watson #ifdef INET6 1821497057eeSRobert Watson if (inp->inp_vflag & INP_IPV6) { 1822497057eeSRobert Watson db_printf("in6p_options: %p in6p_outputopts: %p " 1823497057eeSRobert Watson "in6p_moptions: %p\n", inp->in6p_options, 1824497057eeSRobert Watson inp->in6p_outputopts, inp->in6p_moptions); 1825497057eeSRobert Watson db_printf("in6p_icmp6filt: %p in6p_cksum %d " 1826497057eeSRobert Watson "in6p_hops %u\n", inp->in6p_icmp6filt, inp->in6p_cksum, 1827497057eeSRobert Watson inp->in6p_hops); 1828497057eeSRobert Watson } else 1829497057eeSRobert Watson #endif 1830497057eeSRobert Watson { 1831497057eeSRobert Watson db_printf("inp_ip_tos: %d inp_ip_options: %p " 1832497057eeSRobert Watson "inp_ip_moptions: %p\n", inp->inp_ip_tos, 1833497057eeSRobert Watson inp->inp_options, inp->inp_moptions); 1834497057eeSRobert Watson } 1835497057eeSRobert Watson 1836497057eeSRobert Watson db_print_indent(indent); 1837497057eeSRobert Watson db_printf("inp_phd: %p inp_gencnt: %ju\n", inp->inp_phd, 1838497057eeSRobert Watson (uintmax_t)inp->inp_gencnt); 1839497057eeSRobert Watson } 1840497057eeSRobert Watson 1841497057eeSRobert Watson DB_SHOW_COMMAND(inpcb, db_show_inpcb) 1842497057eeSRobert Watson { 1843497057eeSRobert Watson struct inpcb *inp; 1844497057eeSRobert Watson 1845497057eeSRobert Watson if (!have_addr) { 1846497057eeSRobert Watson db_printf("usage: show inpcb <addr>\n"); 1847497057eeSRobert Watson return; 1848497057eeSRobert Watson } 1849497057eeSRobert Watson inp = (struct inpcb *)addr; 1850497057eeSRobert Watson 1851497057eeSRobert Watson db_print_inpcb(inp, "inpcb", 0); 1852497057eeSRobert Watson } 1853497057eeSRobert Watson #endif 1854