1df8bae1dSRodney W. Grimes /* 22469dd60SGarrett Wollman * Copyright (c) 1982, 1986, 1991, 1993, 1995 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 332469dd60SGarrett Wollman * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 376a800098SYoshinobu Inoue #include "opt_ipsec.h" 38cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 39cfa1ca9dSYoshinobu Inoue 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41df8bae1dSRodney W. Grimes #include <sys/systm.h> 42df8bae1dSRodney W. Grimes #include <sys/malloc.h> 43df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/domain.h> 45df8bae1dSRodney W. Grimes #include <sys/protosw.h> 46df8bae1dSRodney W. Grimes #include <sys/socket.h> 47df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 48df8bae1dSRodney W. Grimes #include <sys/proc.h> 4975c13541SPoul-Henning Kamp #include <sys/jail.h> 50101f9fc8SPeter Wemm #include <sys/kernel.h> 51101f9fc8SPeter Wemm #include <sys/sysctl.h> 528781d8e9SBruce Evans 5308637435SBruce Evans #include <machine/limits.h> 5408637435SBruce Evans 558781d8e9SBruce Evans #include <vm/vm_zone.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <net/if.h> 58cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 59df8bae1dSRodney W. Grimes #include <net/route.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <netinet/in.h> 62df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 63df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 64df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 65cfa1ca9dSYoshinobu Inoue #ifdef INET6 66cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 67cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 68cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 69cfa1ca9dSYoshinobu Inoue 70cfa1ca9dSYoshinobu Inoue #include "faith.h" 71cfa1ca9dSYoshinobu Inoue 72cfa1ca9dSYoshinobu Inoue #ifdef IPSEC 73cfa1ca9dSYoshinobu Inoue #include <netinet6/ipsec.h> 74cfa1ca9dSYoshinobu Inoue #include <netkey/key.h> 75cfa1ca9dSYoshinobu Inoue #include <netkey/key_debug.h> 76cfa1ca9dSYoshinobu Inoue #endif /* IPSEC */ 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes struct in_addr zeroin_addr; 79df8bae1dSRodney W. Grimes 80bbd42ad0SPeter Wemm static void in_rtchange __P((struct inpcb *, int)); 81bbd42ad0SPeter Wemm 82101f9fc8SPeter Wemm /* 83101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 84101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 85101f9fc8SPeter Wemm */ 8682cd038dSYoshinobu Inoue int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 8782cd038dSYoshinobu Inoue int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 8882cd038dSYoshinobu Inoue int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ 8982cd038dSYoshinobu Inoue int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ 9082cd038dSYoshinobu Inoue int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ 9182cd038dSYoshinobu Inoue int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ 92101f9fc8SPeter Wemm 93bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 94bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 95bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 96bbd42ad0SPeter Wemm 97bbd42ad0SPeter Wemm static int 98bbd42ad0SPeter Wemm sysctl_net_ipport_check SYSCTL_HANDLER_ARGS 99bbd42ad0SPeter Wemm { 100bbd42ad0SPeter Wemm int error = sysctl_handle_int(oidp, 101bbd42ad0SPeter Wemm oidp->oid_arg1, oidp->oid_arg2, req); 102bbd42ad0SPeter Wemm if (!error) { 103bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 104bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 105bbd42ad0SPeter Wemm RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 106bbd42ad0SPeter Wemm RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 107bbd42ad0SPeter Wemm RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 108bbd42ad0SPeter Wemm RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 109bbd42ad0SPeter Wemm } 110bbd42ad0SPeter Wemm return error; 111bbd42ad0SPeter Wemm } 112bbd42ad0SPeter Wemm 113bbd42ad0SPeter Wemm #undef RANGECHK 114bbd42ad0SPeter Wemm 11533b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 11633b3ac06SPeter Wemm 117bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 118bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 119bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 120bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 121bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 122bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 123bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 124bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 125bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 126bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 127bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 128bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 1290312fbe9SPoul-Henning Kamp 130c3229e05SDavid Greenman /* 131c3229e05SDavid Greenman * in_pcb.c: manage the Protocol Control Blocks. 132c3229e05SDavid Greenman * 133c3229e05SDavid Greenman * NOTE: It is assumed that most of these functions will be called at 134c3229e05SDavid Greenman * splnet(). XXX - There are, unfortunately, a few exceptions to this 135c3229e05SDavid Greenman * rule that should be fixed. 136c3229e05SDavid Greenman */ 137c3229e05SDavid Greenman 138c3229e05SDavid Greenman /* 139c3229e05SDavid Greenman * Allocate a PCB and associate it with the socket. 140c3229e05SDavid Greenman */ 141df8bae1dSRodney W. Grimes int 142a29f300eSGarrett Wollman in_pcballoc(so, pcbinfo, p) 143df8bae1dSRodney W. Grimes struct socket *so; 14415bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 145a29f300eSGarrett Wollman struct proc *p; 146df8bae1dSRodney W. Grimes { 147df8bae1dSRodney W. Grimes register struct inpcb *inp; 148df8bae1dSRodney W. Grimes 1493d4d47f3SGarrett Wollman inp = zalloci(pcbinfo->ipi_zone); 150df8bae1dSRodney W. Grimes if (inp == NULL) 151df8bae1dSRodney W. Grimes return (ENOBUFS); 152df8bae1dSRodney W. Grimes bzero((caddr_t)inp, sizeof(*inp)); 1533d4d47f3SGarrett Wollman inp->inp_gencnt = ++pcbinfo->ipi_gencnt; 15415bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 155df8bae1dSRodney W. Grimes inp->inp_socket = so; 15615bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 1573d4d47f3SGarrett Wollman pcbinfo->ipi_count++; 158df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 159df8bae1dSRodney W. Grimes return (0); 160df8bae1dSRodney W. Grimes } 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes int 163a29f300eSGarrett Wollman in_pcbbind(inp, nam, p) 164df8bae1dSRodney W. Grimes register struct inpcb *inp; 16557bf258eSGarrett Wollman struct sockaddr *nam; 166a29f300eSGarrett Wollman struct proc *p; 167df8bae1dSRodney W. Grimes { 168df8bae1dSRodney W. Grimes register struct socket *so = inp->inp_socket; 16937bd2b30SPeter Wemm unsigned short *lastport; 17015bd2b43SDavid Greenman struct sockaddr_in *sin; 171c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 172df8bae1dSRodney W. Grimes u_short lport = 0; 173df8bae1dSRodney W. Grimes int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 17475c13541SPoul-Henning Kamp int error, prison = 0; 175df8bae1dSRodney W. Grimes 17659562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 177df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 178df8bae1dSRodney W. Grimes if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 179df8bae1dSRodney W. Grimes return (EINVAL); 180c3229e05SDavid Greenman if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 1816d6a026bSDavid Greenman wild = 1; 182df8bae1dSRodney W. Grimes if (nam) { 18357bf258eSGarrett Wollman sin = (struct sockaddr_in *)nam; 18457bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 185df8bae1dSRodney W. Grimes return (EINVAL); 186df8bae1dSRodney W. Grimes #ifdef notdef 187df8bae1dSRodney W. Grimes /* 188df8bae1dSRodney W. Grimes * We should check the family, but old programs 189df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 190df8bae1dSRodney W. Grimes */ 191df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 192df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 193df8bae1dSRodney W. Grimes #endif 19475c13541SPoul-Henning Kamp if (prison_ip(p, 0, &sin->sin_addr.s_addr)) 19575c13541SPoul-Henning Kamp return(EINVAL); 196df8bae1dSRodney W. Grimes lport = sin->sin_port; 197df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 198df8bae1dSRodney W. Grimes /* 199df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 200df8bae1dSRodney W. Grimes * allow complete duplication of binding if 201df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 202df8bae1dSRodney W. Grimes * and a multicast address is bound on both 203df8bae1dSRodney W. Grimes * new and duplicated sockets. 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 206df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 207df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 208df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 209df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 210df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 211df8bae1dSRodney W. Grimes } 212df8bae1dSRodney W. Grimes if (lport) { 213df8bae1dSRodney W. Grimes struct inpcb *t; 214df8bae1dSRodney W. Grimes 215df8bae1dSRodney W. Grimes /* GROSS */ 21657bf258eSGarrett Wollman if (ntohs(lport) < IPPORT_RESERVED && p && 21775c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT)) 2182469dd60SGarrett Wollman return (EACCES); 21975c13541SPoul-Henning Kamp if (p && p->p_prison) 22075c13541SPoul-Henning Kamp prison = 1; 2212f9a2132SBrian Feldman if (so->so_cred->cr_uid != 0 && 22252b65dbeSBill Fenner !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 2234049a042SGuido van Rooij t = in_pcblookup_local(inp->inp_pcbinfo, 22475c13541SPoul-Henning Kamp sin->sin_addr, lport, 22575c13541SPoul-Henning Kamp prison ? 0 : INPLOOKUP_WILDCARD); 22652b65dbeSBill Fenner if (t && 22752b65dbeSBill Fenner (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || 22852b65dbeSBill Fenner ntohl(t->inp_laddr.s_addr) != INADDR_ANY || 22952b65dbeSBill Fenner (t->inp_socket->so_options & 23052b65dbeSBill Fenner SO_REUSEPORT) == 0) && 2312f9a2132SBrian Feldman (so->so_cred->cr_uid != 232cfa1ca9dSYoshinobu Inoue t->inp_socket->so_cred->cr_uid)) { 233cfa1ca9dSYoshinobu Inoue #if defined(INET6) 234cfa1ca9dSYoshinobu Inoue if (ip6_mapped_addr_on == 0 || 235cfa1ca9dSYoshinobu Inoue ntohl(sin->sin_addr.s_addr) != 236cfa1ca9dSYoshinobu Inoue INADDR_ANY || 237cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 238cfa1ca9dSYoshinobu Inoue INADDR_ANY || 239cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 240cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 241cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 2424049a042SGuido van Rooij return (EADDRINUSE); 2434049a042SGuido van Rooij } 244cfa1ca9dSYoshinobu Inoue } 245c3229e05SDavid Greenman t = in_pcblookup_local(pcbinfo, sin->sin_addr, 24675c13541SPoul-Henning Kamp lport, prison ? 0 : wild); 247cfa1ca9dSYoshinobu Inoue if (t && 248cfa1ca9dSYoshinobu Inoue (reuseport & t->inp_socket->so_options) == 0) { 249cfa1ca9dSYoshinobu Inoue #if defined(INET6) 250cfa1ca9dSYoshinobu Inoue if (ip6_mapped_addr_on == 0 || 251cfa1ca9dSYoshinobu Inoue ntohl(sin->sin_addr.s_addr) != 252cfa1ca9dSYoshinobu Inoue INADDR_ANY || 253cfa1ca9dSYoshinobu Inoue ntohl(t->inp_laddr.s_addr) != 254cfa1ca9dSYoshinobu Inoue INADDR_ANY || 255cfa1ca9dSYoshinobu Inoue INP_SOCKAF(so) == 256cfa1ca9dSYoshinobu Inoue INP_SOCKAF(t->inp_socket)) 257cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 258df8bae1dSRodney W. Grimes return (EADDRINUSE); 259df8bae1dSRodney W. Grimes } 260cfa1ca9dSYoshinobu Inoue } 261df8bae1dSRodney W. Grimes inp->inp_laddr = sin->sin_addr; 262df8bae1dSRodney W. Grimes } 26333b3ac06SPeter Wemm if (lport == 0) { 26433b3ac06SPeter Wemm ushort first, last; 26533b3ac06SPeter Wemm int count; 26633b3ac06SPeter Wemm 26775c13541SPoul-Henning Kamp if (prison_ip(p, 0, &inp->inp_laddr.s_addr )) 26875c13541SPoul-Henning Kamp return (EINVAL); 269321a2846SPoul-Henning Kamp inp->inp_flags |= INP_ANONPORT; 270321a2846SPoul-Henning Kamp 27133b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 27233b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 27333b3ac06SPeter Wemm last = ipport_hilastauto; 274c3229e05SDavid Greenman lastport = &pcbinfo->lasthi; 27533b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 27675c13541SPoul-Henning Kamp if (p && (error = suser_xxx(0, p, PRISON_ROOT))) 277a29f300eSGarrett Wollman return error; 278bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 279bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 280c3229e05SDavid Greenman lastport = &pcbinfo->lastlow; 28133b3ac06SPeter Wemm } else { 28233b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 28333b3ac06SPeter Wemm last = ipport_lastauto; 284c3229e05SDavid Greenman lastport = &pcbinfo->lastport; 28533b3ac06SPeter Wemm } 28633b3ac06SPeter Wemm /* 28733b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 28833b3ac06SPeter Wemm * a deadlock here. 28933b3ac06SPeter Wemm * 29033b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 29133b3ac06SPeter Wemm * is not being tested on each round of the loop. 29233b3ac06SPeter Wemm */ 29333b3ac06SPeter Wemm if (first > last) { 29433b3ac06SPeter Wemm /* 29533b3ac06SPeter Wemm * counting down 29633b3ac06SPeter Wemm */ 29733b3ac06SPeter Wemm count = first - last; 29833b3ac06SPeter Wemm 299df8bae1dSRodney W. Grimes do { 300c3229e05SDavid Greenman if (count-- < 0) { /* completely used? */ 301c3229e05SDavid Greenman /* 302c3229e05SDavid Greenman * Undo any address bind that may have 303c3229e05SDavid Greenman * occurred above. 304c3229e05SDavid Greenman */ 305c3229e05SDavid Greenman inp->inp_laddr.s_addr = INADDR_ANY; 306c3229e05SDavid Greenman return (EAGAIN); 307c3229e05SDavid Greenman } 30833b3ac06SPeter Wemm --*lastport; 30933b3ac06SPeter Wemm if (*lastport > first || *lastport < last) 31033b3ac06SPeter Wemm *lastport = first; 31115bd2b43SDavid Greenman lport = htons(*lastport); 312c3229e05SDavid Greenman } while (in_pcblookup_local(pcbinfo, 313c3229e05SDavid Greenman inp->inp_laddr, lport, wild)); 31433b3ac06SPeter Wemm } else { 31533b3ac06SPeter Wemm /* 31633b3ac06SPeter Wemm * counting up 31733b3ac06SPeter Wemm */ 31833b3ac06SPeter Wemm count = last - first; 31933b3ac06SPeter Wemm 32033b3ac06SPeter Wemm do { 321c3229e05SDavid Greenman if (count-- < 0) { /* completely used? */ 322c3229e05SDavid Greenman /* 323c3229e05SDavid Greenman * Undo any address bind that may have 324c3229e05SDavid Greenman * occurred above. 325c3229e05SDavid Greenman */ 326c3229e05SDavid Greenman inp->inp_laddr.s_addr = INADDR_ANY; 327c3229e05SDavid Greenman return (EAGAIN); 328c3229e05SDavid Greenman } 32933b3ac06SPeter Wemm ++*lastport; 33033b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 33133b3ac06SPeter Wemm *lastport = first; 33233b3ac06SPeter Wemm lport = htons(*lastport); 333c3229e05SDavid Greenman } while (in_pcblookup_local(pcbinfo, 334c3229e05SDavid Greenman inp->inp_laddr, lport, wild)); 33533b3ac06SPeter Wemm } 33633b3ac06SPeter Wemm } 337df8bae1dSRodney W. Grimes inp->inp_lport = lport; 338c3229e05SDavid Greenman if (in_pcbinshash(inp) != 0) { 339c3229e05SDavid Greenman inp->inp_laddr.s_addr = INADDR_ANY; 340c3229e05SDavid Greenman inp->inp_lport = 0; 341c3229e05SDavid Greenman return (EAGAIN); 342c3229e05SDavid Greenman } 343df8bae1dSRodney W. Grimes return (0); 344df8bae1dSRodney W. Grimes } 345df8bae1dSRodney W. Grimes 346999f1343SGarrett Wollman /* 347999f1343SGarrett Wollman * Transform old in_pcbconnect() into an inner subroutine for new 348999f1343SGarrett Wollman * in_pcbconnect(): Do some validity-checking on the remote 349999f1343SGarrett Wollman * address (in mbuf 'nam') and then determine local host address 350999f1343SGarrett Wollman * (i.e., which interface) to use to access that remote host. 351999f1343SGarrett Wollman * 352999f1343SGarrett Wollman * This preserves definition of in_pcbconnect(), while supporting a 353999f1343SGarrett Wollman * slightly different version for T/TCP. (This is more than 354999f1343SGarrett Wollman * a bit of a kludge, but cleaning up the internal interfaces would 355999f1343SGarrett Wollman * have forced minor changes in every protocol). 356999f1343SGarrett Wollman */ 357999f1343SGarrett Wollman 358999f1343SGarrett Wollman int 359999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin) 360999f1343SGarrett Wollman register struct inpcb *inp; 36157bf258eSGarrett Wollman struct sockaddr *nam; 362999f1343SGarrett Wollman struct sockaddr_in **plocal_sin; 363999f1343SGarrett Wollman { 364df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 36557bf258eSGarrett Wollman register struct sockaddr_in *sin = (struct sockaddr_in *)nam; 366df8bae1dSRodney W. Grimes 36757bf258eSGarrett Wollman if (nam->sa_len != sizeof (*sin)) 368df8bae1dSRodney W. Grimes return (EINVAL); 369df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 370df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 371df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 372df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 37359562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 374df8bae1dSRodney W. Grimes /* 375df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 376df8bae1dSRodney W. Grimes * use the primary local address. 377df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 378df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 379df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 380df8bae1dSRodney W. Grimes */ 381df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 382df8bae1dSRodney W. Grimes #define sintosa(sin) ((struct sockaddr *)(sin)) 383df8bae1dSRodney W. Grimes #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 384df8bae1dSRodney W. Grimes if (sin->sin_addr.s_addr == INADDR_ANY) 38559562606SGarrett Wollman sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; 386df8bae1dSRodney W. Grimes else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 38759562606SGarrett Wollman (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 38859562606SGarrett Wollman sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 391df8bae1dSRodney W. Grimes register struct route *ro; 392df8bae1dSRodney W. Grimes 393df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 394df8bae1dSRodney W. Grimes /* 395df8bae1dSRodney W. Grimes * If route is known or can be allocated now, 396df8bae1dSRodney W. Grimes * our src addr is taken from the i/f, else punt. 397df8bae1dSRodney W. Grimes */ 398df8bae1dSRodney W. Grimes ro = &inp->inp_route; 399df8bae1dSRodney W. Grimes if (ro->ro_rt && 400df8bae1dSRodney W. Grimes (satosin(&ro->ro_dst)->sin_addr.s_addr != 401df8bae1dSRodney W. Grimes sin->sin_addr.s_addr || 402df8bae1dSRodney W. Grimes inp->inp_socket->so_options & SO_DONTROUTE)) { 403df8bae1dSRodney W. Grimes RTFREE(ro->ro_rt); 404df8bae1dSRodney W. Grimes ro->ro_rt = (struct rtentry *)0; 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 407df8bae1dSRodney W. Grimes (ro->ro_rt == (struct rtentry *)0 || 408df8bae1dSRodney W. Grimes ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 409df8bae1dSRodney W. Grimes /* No route yet, so try to acquire one */ 410df8bae1dSRodney W. Grimes ro->ro_dst.sa_family = AF_INET; 411df8bae1dSRodney W. Grimes ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 412df8bae1dSRodney W. Grimes ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 413df8bae1dSRodney W. Grimes sin->sin_addr; 414df8bae1dSRodney W. Grimes rtalloc(ro); 415df8bae1dSRodney W. Grimes } 416df8bae1dSRodney W. Grimes /* 417df8bae1dSRodney W. Grimes * If we found a route, use the address 418df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 419df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 420df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 421df8bae1dSRodney W. Grimes */ 422df8bae1dSRodney W. Grimes if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 423df8bae1dSRodney W. Grimes ia = ifatoia(ro->ro_rt->rt_ifa); 424df8bae1dSRodney W. Grimes if (ia == 0) { 425df8bae1dSRodney W. Grimes u_short fport = sin->sin_port; 426df8bae1dSRodney W. Grimes 427df8bae1dSRodney W. Grimes sin->sin_port = 0; 428df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 429df8bae1dSRodney W. Grimes if (ia == 0) 430df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 431df8bae1dSRodney W. Grimes sin->sin_port = fport; 432df8bae1dSRodney W. Grimes if (ia == 0) 43359562606SGarrett Wollman ia = in_ifaddrhead.tqh_first; 434df8bae1dSRodney W. Grimes if (ia == 0) 435df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes /* 438df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 439df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 440df8bae1dSRodney W. Grimes * address of that interface as our source address. 441df8bae1dSRodney W. Grimes */ 442df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 443df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 444df8bae1dSRodney W. Grimes struct ip_moptions *imo; 445df8bae1dSRodney W. Grimes struct ifnet *ifp; 446df8bae1dSRodney W. Grimes 447df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 448df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 449df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 45059562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 45159562606SGarrett Wollman ia = ia->ia_link.tqe_next) 452df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 453df8bae1dSRodney W. Grimes break; 454df8bae1dSRodney W. Grimes if (ia == 0) 455df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 456df8bae1dSRodney W. Grimes } 457df8bae1dSRodney W. Grimes } 458999f1343SGarrett Wollman /* 459999f1343SGarrett Wollman * Don't do pcblookup call here; return interface in plocal_sin 460999f1343SGarrett Wollman * and exit to caller, that will do the lookup. 461999f1343SGarrett Wollman */ 462999f1343SGarrett Wollman *plocal_sin = &ia->ia_addr; 463999f1343SGarrett Wollman 464999f1343SGarrett Wollman } 465999f1343SGarrett Wollman return(0); 466999f1343SGarrett Wollman } 467999f1343SGarrett Wollman 468999f1343SGarrett Wollman /* 469999f1343SGarrett Wollman * Outer subroutine: 470999f1343SGarrett Wollman * Connect from a socket to a specified address. 471999f1343SGarrett Wollman * Both address and port must be specified in argument sin. 472999f1343SGarrett Wollman * If don't have a local address for this socket yet, 473999f1343SGarrett Wollman * then pick one. 474999f1343SGarrett Wollman */ 475999f1343SGarrett Wollman int 476a29f300eSGarrett Wollman in_pcbconnect(inp, nam, p) 477999f1343SGarrett Wollman register struct inpcb *inp; 47857bf258eSGarrett Wollman struct sockaddr *nam; 479a29f300eSGarrett Wollman struct proc *p; 480999f1343SGarrett Wollman { 481999f1343SGarrett Wollman struct sockaddr_in *ifaddr; 48257bf258eSGarrett Wollman register struct sockaddr_in *sin = (struct sockaddr_in *)nam; 483999f1343SGarrett Wollman int error; 484999f1343SGarrett Wollman 485999f1343SGarrett Wollman /* 486999f1343SGarrett Wollman * Call inner routine, to assign local interface address. 487999f1343SGarrett Wollman */ 488831a80b0SMatthew Dillon if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0) 489999f1343SGarrett Wollman return(error); 490999f1343SGarrett Wollman 491c3229e05SDavid Greenman if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 492df8bae1dSRodney W. Grimes inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 493cfa1ca9dSYoshinobu Inoue inp->inp_lport, 0, NULL) != NULL) { 494df8bae1dSRodney W. Grimes return (EADDRINUSE); 495c3229e05SDavid Greenman } 496df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 4975a903f8dSPierre Beyssac if (inp->inp_lport == 0) { 4985a903f8dSPierre Beyssac error = in_pcbbind(inp, (struct sockaddr *)0, p); 4995a903f8dSPierre Beyssac if (error) 5005a903f8dSPierre Beyssac return (error); 5015a903f8dSPierre Beyssac } 502df8bae1dSRodney W. Grimes inp->inp_laddr = ifaddr->sin_addr; 503df8bae1dSRodney W. Grimes } 504df8bae1dSRodney W. Grimes inp->inp_faddr = sin->sin_addr; 505df8bae1dSRodney W. Grimes inp->inp_fport = sin->sin_port; 50615bd2b43SDavid Greenman in_pcbrehash(inp); 507df8bae1dSRodney W. Grimes return (0); 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes 51026f9a767SRodney W. Grimes void 511df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 512df8bae1dSRodney W. Grimes struct inpcb *inp; 513df8bae1dSRodney W. Grimes { 514df8bae1dSRodney W. Grimes 515df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 516df8bae1dSRodney W. Grimes inp->inp_fport = 0; 51715bd2b43SDavid Greenman in_pcbrehash(inp); 518df8bae1dSRodney W. Grimes if (inp->inp_socket->so_state & SS_NOFDREF) 519df8bae1dSRodney W. Grimes in_pcbdetach(inp); 520df8bae1dSRodney W. Grimes } 521df8bae1dSRodney W. Grimes 52226f9a767SRodney W. Grimes void 523df8bae1dSRodney W. Grimes in_pcbdetach(inp) 524df8bae1dSRodney W. Grimes struct inpcb *inp; 525df8bae1dSRodney W. Grimes { 526df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 5273d4d47f3SGarrett Wollman struct inpcbinfo *ipi = inp->inp_pcbinfo; 528df8bae1dSRodney W. Grimes 529cfa1ca9dSYoshinobu Inoue #ifdef IPSEC 530cfa1ca9dSYoshinobu Inoue ipsec4_delete_pcbpolicy(inp); 531cfa1ca9dSYoshinobu Inoue #endif /*IPSEC*/ 5323d4d47f3SGarrett Wollman inp->inp_gencnt = ++ipi->ipi_gencnt; 533c3229e05SDavid Greenman in_pcbremlists(inp); 534df8bae1dSRodney W. Grimes so->so_pcb = 0; 535df8bae1dSRodney W. Grimes sofree(so); 536df8bae1dSRodney W. Grimes if (inp->inp_options) 537df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 538df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) 539df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 540df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 541cfa1ca9dSYoshinobu Inoue inp->inp_vflag = 0; 5423d4d47f3SGarrett Wollman zfreei(ipi->ipi_zone, inp); 543df8bae1dSRodney W. Grimes } 544df8bae1dSRodney W. Grimes 545117bcae7SGarrett Wollman /* 546117bcae7SGarrett Wollman * The calling convention of in_setsockaddr() and in_setpeeraddr() was 547117bcae7SGarrett Wollman * modified to match the pru_sockaddr() and pru_peeraddr() entry points 548117bcae7SGarrett Wollman * in struct pr_usrreqs, so that protocols can just reference then directly 549117bcae7SGarrett Wollman * without the need for a wrapper function. The socket must have a valid 550117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 551117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 55257bf258eSGarrett Wollman * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 55357bf258eSGarrett Wollman * because there actually /is/ a programming error somewhere... XXX) 554117bcae7SGarrett Wollman */ 555117bcae7SGarrett Wollman int 556117bcae7SGarrett Wollman in_setsockaddr(so, nam) 557117bcae7SGarrett Wollman struct socket *so; 55857bf258eSGarrett Wollman struct sockaddr **nam; 559df8bae1dSRodney W. Grimes { 560fdc984f7STor Egge int s; 561fdc984f7STor Egge register struct inpcb *inp; 562df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 563df8bae1dSRodney W. Grimes 564c3229e05SDavid Greenman /* 565c3229e05SDavid Greenman * Do the malloc first in case it blocks. 566c3229e05SDavid Greenman */ 56742fa505bSDavid Greenman MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); 56842fa505bSDavid Greenman bzero(sin, sizeof *sin); 56942fa505bSDavid Greenman sin->sin_family = AF_INET; 57042fa505bSDavid Greenman sin->sin_len = sizeof(*sin); 57142fa505bSDavid Greenman 572fdc984f7STor Egge s = splnet(); 573fdc984f7STor Egge inp = sotoinpcb(so); 574db112f04STor Egge if (!inp) { 575db112f04STor Egge splx(s); 57642fa505bSDavid Greenman free(sin, M_SONAME); 577db112f04STor Egge return EINVAL; 578db112f04STor Egge } 579df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_lport; 580df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_laddr; 581db112f04STor Egge splx(s); 58242fa505bSDavid Greenman 58342fa505bSDavid Greenman *nam = (struct sockaddr *)sin; 584117bcae7SGarrett Wollman return 0; 585df8bae1dSRodney W. Grimes } 586df8bae1dSRodney W. Grimes 587117bcae7SGarrett Wollman int 588117bcae7SGarrett Wollman in_setpeeraddr(so, nam) 589117bcae7SGarrett Wollman struct socket *so; 59057bf258eSGarrett Wollman struct sockaddr **nam; 591df8bae1dSRodney W. Grimes { 592fdc984f7STor Egge int s; 593fdc984f7STor Egge struct inpcb *inp; 594df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 595df8bae1dSRodney W. Grimes 596c3229e05SDavid Greenman /* 597c3229e05SDavid Greenman * Do the malloc first in case it blocks. 598c3229e05SDavid Greenman */ 59942fa505bSDavid Greenman MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); 60042fa505bSDavid Greenman bzero((caddr_t)sin, sizeof (*sin)); 60142fa505bSDavid Greenman sin->sin_family = AF_INET; 60242fa505bSDavid Greenman sin->sin_len = sizeof(*sin); 60342fa505bSDavid Greenman 604fdc984f7STor Egge s = splnet(); 605fdc984f7STor Egge inp = sotoinpcb(so); 606db112f04STor Egge if (!inp) { 607db112f04STor Egge splx(s); 60842fa505bSDavid Greenman free(sin, M_SONAME); 609db112f04STor Egge return EINVAL; 610db112f04STor Egge } 611df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_fport; 612df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_faddr; 613db112f04STor Egge splx(s); 61442fa505bSDavid Greenman 61542fa505bSDavid Greenman *nam = (struct sockaddr *)sin; 616117bcae7SGarrett Wollman return 0; 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * Pass some notification to all connections of a protocol 621df8bae1dSRodney W. Grimes * associated with address dst. The local address and/or port numbers 622df8bae1dSRodney W. Grimes * may be specified to limit the search. The "usual action" will be 623df8bae1dSRodney W. Grimes * taken, depending on the ctlinput cmd. The caller must filter any 624df8bae1dSRodney W. Grimes * cmds that are uninteresting (e.g., no error in the map). 625df8bae1dSRodney W. Grimes * Call the protocol specific routine (if any) to report 626df8bae1dSRodney W. Grimes * any errors for each matching socket. 627df8bae1dSRodney W. Grimes */ 62826f9a767SRodney W. Grimes void 629df8bae1dSRodney W. Grimes in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 63015bd2b43SDavid Greenman struct inpcbhead *head; 631df8bae1dSRodney W. Grimes struct sockaddr *dst; 632df8bae1dSRodney W. Grimes u_int fport_arg, lport_arg; 633df8bae1dSRodney W. Grimes struct in_addr laddr; 634df8bae1dSRodney W. Grimes int cmd; 635df8bae1dSRodney W. Grimes void (*notify) __P((struct inpcb *, int)); 636df8bae1dSRodney W. Grimes { 637df8bae1dSRodney W. Grimes register struct inpcb *inp, *oinp; 638df8bae1dSRodney W. Grimes struct in_addr faddr; 639df8bae1dSRodney W. Grimes u_short fport = fport_arg, lport = lport_arg; 6407bc4aca7SDavid Greenman int errno, s; 641df8bae1dSRodney W. Grimes 642df8bae1dSRodney W. Grimes if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 643df8bae1dSRodney W. Grimes return; 644df8bae1dSRodney W. Grimes faddr = ((struct sockaddr_in *)dst)->sin_addr; 645df8bae1dSRodney W. Grimes if (faddr.s_addr == INADDR_ANY) 646df8bae1dSRodney W. Grimes return; 647df8bae1dSRodney W. Grimes 648df8bae1dSRodney W. Grimes /* 649df8bae1dSRodney W. Grimes * Redirects go to all references to the destination, 650df8bae1dSRodney W. Grimes * and use in_rtchange to invalidate the route cache. 651df8bae1dSRodney W. Grimes * Dead host indications: notify all references to the destination. 652df8bae1dSRodney W. Grimes * Otherwise, if we have knowledge of the local port and address, 653df8bae1dSRodney W. Grimes * deliver only to that socket. 654df8bae1dSRodney W. Grimes */ 655df8bae1dSRodney W. Grimes if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 656df8bae1dSRodney W. Grimes fport = 0; 657df8bae1dSRodney W. Grimes lport = 0; 658df8bae1dSRodney W. Grimes laddr.s_addr = 0; 659df8bae1dSRodney W. Grimes if (cmd != PRC_HOSTDEAD) 660df8bae1dSRodney W. Grimes notify = in_rtchange; 661df8bae1dSRodney W. Grimes } 662df8bae1dSRodney W. Grimes errno = inetctlerrmap[cmd]; 6637bc4aca7SDavid Greenman s = splnet(); 66415bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL;) { 665cfa1ca9dSYoshinobu Inoue #ifdef INET6 666369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) { 667cfa1ca9dSYoshinobu Inoue inp = LIST_NEXT(inp, inp_list); 668cfa1ca9dSYoshinobu Inoue continue; 669cfa1ca9dSYoshinobu Inoue } 670cfa1ca9dSYoshinobu Inoue #endif 671df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != faddr.s_addr || 672df8bae1dSRodney W. Grimes inp->inp_socket == 0 || 673df8bae1dSRodney W. Grimes (lport && inp->inp_lport != lport) || 674df8bae1dSRodney W. Grimes (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 675df8bae1dSRodney W. Grimes (fport && inp->inp_fport != fport)) { 67615bd2b43SDavid Greenman inp = inp->inp_list.le_next; 677df8bae1dSRodney W. Grimes continue; 678df8bae1dSRodney W. Grimes } 679df8bae1dSRodney W. Grimes oinp = inp; 68015bd2b43SDavid Greenman inp = inp->inp_list.le_next; 681df8bae1dSRodney W. Grimes if (notify) 682df8bae1dSRodney W. Grimes (*notify)(oinp, errno); 683df8bae1dSRodney W. Grimes } 6847bc4aca7SDavid Greenman splx(s); 685df8bae1dSRodney W. Grimes } 686df8bae1dSRodney W. Grimes 687df8bae1dSRodney W. Grimes /* 688df8bae1dSRodney W. Grimes * Check for alternatives when higher level complains 689df8bae1dSRodney W. Grimes * about service problems. For now, invalidate cached 690df8bae1dSRodney W. Grimes * routing information. If the route was created dynamically 691df8bae1dSRodney W. Grimes * (by a redirect), time to try a default gateway again. 692df8bae1dSRodney W. Grimes */ 69326f9a767SRodney W. Grimes void 694df8bae1dSRodney W. Grimes in_losing(inp) 695df8bae1dSRodney W. Grimes struct inpcb *inp; 696df8bae1dSRodney W. Grimes { 697df8bae1dSRodney W. Grimes register struct rtentry *rt; 698df8bae1dSRodney W. Grimes struct rt_addrinfo info; 699df8bae1dSRodney W. Grimes 700df8bae1dSRodney W. Grimes if ((rt = inp->inp_route.ro_rt)) { 701df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 702df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 703df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = 704df8bae1dSRodney W. Grimes (struct sockaddr *)&inp->inp_route.ro_dst; 705df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 706df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = rt_mask(rt); 707df8bae1dSRodney W. Grimes rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 708df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_DYNAMIC) 709df8bae1dSRodney W. Grimes (void) rtrequest(RTM_DELETE, rt_key(rt), 710df8bae1dSRodney W. Grimes rt->rt_gateway, rt_mask(rt), rt->rt_flags, 711df8bae1dSRodney W. Grimes (struct rtentry **)0); 712df8bae1dSRodney W. Grimes else 713df8bae1dSRodney W. Grimes /* 714df8bae1dSRodney W. Grimes * A new route can be allocated 715df8bae1dSRodney W. Grimes * the next time output is attempted. 716df8bae1dSRodney W. Grimes */ 717df8bae1dSRodney W. Grimes rtfree(rt); 718df8bae1dSRodney W. Grimes } 719df8bae1dSRodney W. Grimes } 720df8bae1dSRodney W. Grimes 721df8bae1dSRodney W. Grimes /* 722df8bae1dSRodney W. Grimes * After a routing change, flush old routing 723df8bae1dSRodney W. Grimes * and allocate a (hopefully) better one. 724df8bae1dSRodney W. Grimes */ 7250312fbe9SPoul-Henning Kamp static void 726df8bae1dSRodney W. Grimes in_rtchange(inp, errno) 727df8bae1dSRodney W. Grimes register struct inpcb *inp; 728df8bae1dSRodney W. Grimes int errno; 729df8bae1dSRodney W. Grimes { 730df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) { 731df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 732df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 733df8bae1dSRodney W. Grimes /* 734df8bae1dSRodney W. Grimes * A new route can be allocated the next time 735df8bae1dSRodney W. Grimes * output is attempted. 736df8bae1dSRodney W. Grimes */ 737df8bae1dSRodney W. Grimes } 738df8bae1dSRodney W. Grimes } 739df8bae1dSRodney W. Grimes 740c3229e05SDavid Greenman /* 741c3229e05SDavid Greenman * Lookup a PCB based on the local address and port. 742c3229e05SDavid Greenman */ 743df8bae1dSRodney W. Grimes struct inpcb * 744c3229e05SDavid Greenman in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 7456d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 746c3229e05SDavid Greenman struct in_addr laddr; 747c3229e05SDavid Greenman u_int lport_arg; 7486d6a026bSDavid Greenman int wild_okay; 749df8bae1dSRodney W. Grimes { 750f1d19042SArchie Cobbs register struct inpcb *inp; 751df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 752c3229e05SDavid Greenman u_short lport = lport_arg; 7537bc4aca7SDavid Greenman 754c3229e05SDavid Greenman if (!wild_okay) { 755c3229e05SDavid Greenman struct inpcbhead *head; 756c3229e05SDavid Greenman /* 757c3229e05SDavid Greenman * Look for an unconnected (wildcard foreign addr) PCB that 758c3229e05SDavid Greenman * matches the local address and port we're looking for. 759c3229e05SDavid Greenman */ 760c3229e05SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 761c3229e05SDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 762cfa1ca9dSYoshinobu Inoue #ifdef INET6 763369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 764cfa1ca9dSYoshinobu Inoue continue; 765cfa1ca9dSYoshinobu Inoue #endif 766c3229e05SDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 767c3229e05SDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 768c3229e05SDavid Greenman inp->inp_lport == lport) { 769c3229e05SDavid Greenman /* 770c3229e05SDavid Greenman * Found. 771c3229e05SDavid Greenman */ 772c3229e05SDavid Greenman return (inp); 773df8bae1dSRodney W. Grimes } 774c3229e05SDavid Greenman } 775c3229e05SDavid Greenman /* 776c3229e05SDavid Greenman * Not found. 777c3229e05SDavid Greenman */ 778c3229e05SDavid Greenman return (NULL); 779c3229e05SDavid Greenman } else { 780c3229e05SDavid Greenman struct inpcbporthead *porthash; 781c3229e05SDavid Greenman struct inpcbport *phd; 782c3229e05SDavid Greenman struct inpcb *match = NULL; 783c3229e05SDavid Greenman /* 784c3229e05SDavid Greenman * Best fit PCB lookup. 785c3229e05SDavid Greenman * 786c3229e05SDavid Greenman * First see if this local port is in use by looking on the 787c3229e05SDavid Greenman * port hash list. 788c3229e05SDavid Greenman */ 789c3229e05SDavid Greenman porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 790c3229e05SDavid Greenman pcbinfo->porthashmask)]; 791c3229e05SDavid Greenman for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { 792c3229e05SDavid Greenman if (phd->phd_port == lport) 793c3229e05SDavid Greenman break; 794c3229e05SDavid Greenman } 795c3229e05SDavid Greenman if (phd != NULL) { 796c3229e05SDavid Greenman /* 797c3229e05SDavid Greenman * Port is in use by one or more PCBs. Look for best 798c3229e05SDavid Greenman * fit. 799c3229e05SDavid Greenman */ 800c3229e05SDavid Greenman for (inp = phd->phd_pcblist.lh_first; inp != NULL; 801c3229e05SDavid Greenman inp = inp->inp_portlist.le_next) { 802c3229e05SDavid Greenman wildcard = 0; 803cfa1ca9dSYoshinobu Inoue #ifdef INET6 804369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 805cfa1ca9dSYoshinobu Inoue continue; 806cfa1ca9dSYoshinobu Inoue #endif 807c3229e05SDavid Greenman if (inp->inp_faddr.s_addr != INADDR_ANY) 808c3229e05SDavid Greenman wildcard++; 80915bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 81015bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 81115bd2b43SDavid Greenman wildcard++; 81215bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 81315bd2b43SDavid Greenman continue; 81415bd2b43SDavid Greenman } else { 81515bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 81615bd2b43SDavid Greenman wildcard++; 81715bd2b43SDavid Greenman } 818df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 819df8bae1dSRodney W. Grimes match = inp; 820df8bae1dSRodney W. Grimes matchwild = wildcard; 8213dbdc25cSDavid Greenman if (matchwild == 0) { 822df8bae1dSRodney W. Grimes break; 823df8bae1dSRodney W. Grimes } 824df8bae1dSRodney W. Grimes } 8253dbdc25cSDavid Greenman } 826c3229e05SDavid Greenman } 827df8bae1dSRodney W. Grimes return (match); 828df8bae1dSRodney W. Grimes } 829c3229e05SDavid Greenman } 83015bd2b43SDavid Greenman 83115bd2b43SDavid Greenman /* 83215bd2b43SDavid Greenman * Lookup PCB in hash list. 83315bd2b43SDavid Greenman */ 83415bd2b43SDavid Greenman struct inpcb * 835cfa1ca9dSYoshinobu Inoue in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, 836cfa1ca9dSYoshinobu Inoue ifp) 83715bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 83815bd2b43SDavid Greenman struct in_addr faddr, laddr; 83915bd2b43SDavid Greenman u_int fport_arg, lport_arg; 8406d6a026bSDavid Greenman int wildcard; 841cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 84215bd2b43SDavid Greenman { 84315bd2b43SDavid Greenman struct inpcbhead *head; 84415bd2b43SDavid Greenman register struct inpcb *inp; 84515bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 84615bd2b43SDavid Greenman 84715bd2b43SDavid Greenman /* 84815bd2b43SDavid Greenman * First look for an exact match. 84915bd2b43SDavid Greenman */ 850ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 85115bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 852cfa1ca9dSYoshinobu Inoue #ifdef INET6 853369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 854cfa1ca9dSYoshinobu Inoue continue; 855cfa1ca9dSYoshinobu Inoue #endif 8566d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 857ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 858ca98b82cSDavid Greenman inp->inp_fport == fport && 859c3229e05SDavid Greenman inp->inp_lport == lport) { 860c3229e05SDavid Greenman /* 861c3229e05SDavid Greenman * Found. 862c3229e05SDavid Greenman */ 863c3229e05SDavid Greenman return (inp); 864c3229e05SDavid Greenman } 8656d6a026bSDavid Greenman } 8666d6a026bSDavid Greenman if (wildcard) { 8676d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 868cfa1ca9dSYoshinobu Inoue #if defined(INET6) 869cfa1ca9dSYoshinobu Inoue struct inpcb *local_wild_mapped = NULL; 870cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 8716d6a026bSDavid Greenman 872ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 8736d6a026bSDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 874cfa1ca9dSYoshinobu Inoue #ifdef INET6 875369dc8ceSEivind Eklund if ((inp->inp_vflag & INP_IPV4) == 0) 876cfa1ca9dSYoshinobu Inoue continue; 877cfa1ca9dSYoshinobu Inoue #endif 8786d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 879c3229e05SDavid Greenman inp->inp_lport == lport) { 880cfa1ca9dSYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0 881cfa1ca9dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_FAITH && 882cfa1ca9dSYoshinobu Inoue (inp->inp_flags & INP_FAITH) == 0) 883cfa1ca9dSYoshinobu Inoue continue; 884cfa1ca9dSYoshinobu Inoue #endif 8856d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 886c3229e05SDavid Greenman return (inp); 887cfa1ca9dSYoshinobu Inoue else if (inp->inp_laddr.s_addr == INADDR_ANY) { 888cfa1ca9dSYoshinobu Inoue #if defined(INET6) 889cfa1ca9dSYoshinobu Inoue if (INP_CHECK_SOCKAF(inp->inp_socket, 890cfa1ca9dSYoshinobu Inoue AF_INET6)) 891cfa1ca9dSYoshinobu Inoue local_wild_mapped = inp; 892cfa1ca9dSYoshinobu Inoue else 893cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 8946d6a026bSDavid Greenman local_wild = inp; 8956d6a026bSDavid Greenman } 8966d6a026bSDavid Greenman } 897cfa1ca9dSYoshinobu Inoue } 898cfa1ca9dSYoshinobu Inoue #if defined(INET6) 899cfa1ca9dSYoshinobu Inoue if (local_wild == NULL) 900cfa1ca9dSYoshinobu Inoue return (local_wild_mapped); 901cfa1ca9dSYoshinobu Inoue #endif /* defined(INET6) */ 902c3229e05SDavid Greenman return (local_wild); 9036d6a026bSDavid Greenman } 904c3229e05SDavid Greenman 905c3229e05SDavid Greenman /* 906c3229e05SDavid Greenman * Not found. 907c3229e05SDavid Greenman */ 9086d6a026bSDavid Greenman return (NULL); 90915bd2b43SDavid Greenman } 91015bd2b43SDavid Greenman 9117bc4aca7SDavid Greenman /* 912c3229e05SDavid Greenman * Insert PCB onto various hash lists. 9137bc4aca7SDavid Greenman */ 914c3229e05SDavid Greenman int 91515bd2b43SDavid Greenman in_pcbinshash(inp) 91615bd2b43SDavid Greenman struct inpcb *inp; 91715bd2b43SDavid Greenman { 918c3229e05SDavid Greenman struct inpcbhead *pcbhash; 919c3229e05SDavid Greenman struct inpcbporthead *pcbporthash; 920c3229e05SDavid Greenman struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 921c3229e05SDavid Greenman struct inpcbport *phd; 922cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 92315bd2b43SDavid Greenman 924cfa1ca9dSYoshinobu Inoue #ifdef INET6 925cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 926cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 927cfa1ca9dSYoshinobu Inoue else 928cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 929cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 930cfa1ca9dSYoshinobu Inoue 931cfa1ca9dSYoshinobu Inoue pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 932c3229e05SDavid Greenman inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; 93315bd2b43SDavid Greenman 934c3229e05SDavid Greenman pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, 935c3229e05SDavid Greenman pcbinfo->porthashmask)]; 936c3229e05SDavid Greenman 937c3229e05SDavid Greenman /* 938c3229e05SDavid Greenman * Go through port list and look for a head for this lport. 939c3229e05SDavid Greenman */ 940c3229e05SDavid Greenman for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { 941c3229e05SDavid Greenman if (phd->phd_port == inp->inp_lport) 942c3229e05SDavid Greenman break; 943c3229e05SDavid Greenman } 944c3229e05SDavid Greenman /* 945c3229e05SDavid Greenman * If none exists, malloc one and tack it on. 946c3229e05SDavid Greenman */ 947c3229e05SDavid Greenman if (phd == NULL) { 948c3229e05SDavid Greenman MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); 949c3229e05SDavid Greenman if (phd == NULL) { 950c3229e05SDavid Greenman return (ENOBUFS); /* XXX */ 951c3229e05SDavid Greenman } 952c3229e05SDavid Greenman phd->phd_port = inp->inp_lport; 953c3229e05SDavid Greenman LIST_INIT(&phd->phd_pcblist); 954c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); 955c3229e05SDavid Greenman } 956c3229e05SDavid Greenman inp->inp_phd = phd; 957c3229e05SDavid Greenman LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); 958c3229e05SDavid Greenman LIST_INSERT_HEAD(pcbhash, inp, inp_hash); 959c3229e05SDavid Greenman return (0); 96015bd2b43SDavid Greenman } 96115bd2b43SDavid Greenman 962c3229e05SDavid Greenman /* 963c3229e05SDavid Greenman * Move PCB to the proper hash bucket when { faddr, fport } have been 964c3229e05SDavid Greenman * changed. NOTE: This does not handle the case of the lport changing (the 965c3229e05SDavid Greenman * hashed port list would have to be updated as well), so the lport must 966c3229e05SDavid Greenman * not change after in_pcbinshash() has been called. 967c3229e05SDavid Greenman */ 96815bd2b43SDavid Greenman void 96915bd2b43SDavid Greenman in_pcbrehash(inp) 97015bd2b43SDavid Greenman struct inpcb *inp; 97115bd2b43SDavid Greenman { 97215bd2b43SDavid Greenman struct inpcbhead *head; 973cfa1ca9dSYoshinobu Inoue u_int32_t hashkey_faddr; 97415bd2b43SDavid Greenman 975cfa1ca9dSYoshinobu Inoue #ifdef INET6 976cfa1ca9dSYoshinobu Inoue if (inp->inp_vflag & INP_IPV6) 977cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; 978cfa1ca9dSYoshinobu Inoue else 979cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 980cfa1ca9dSYoshinobu Inoue hashkey_faddr = inp->inp_faddr.s_addr; 981cfa1ca9dSYoshinobu Inoue 982cfa1ca9dSYoshinobu Inoue head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, 983ddd79a97SDavid Greenman inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 98415bd2b43SDavid Greenman 985c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 98615bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 987c3229e05SDavid Greenman } 988c3229e05SDavid Greenman 989c3229e05SDavid Greenman /* 990c3229e05SDavid Greenman * Remove PCB from various lists. 991c3229e05SDavid Greenman */ 99276429de4SYoshinobu Inoue void 993c3229e05SDavid Greenman in_pcbremlists(inp) 994c3229e05SDavid Greenman struct inpcb *inp; 995c3229e05SDavid Greenman { 99698271db4SGarrett Wollman inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt; 997c3229e05SDavid Greenman if (inp->inp_lport) { 998c3229e05SDavid Greenman struct inpcbport *phd = inp->inp_phd; 999c3229e05SDavid Greenman 1000c3229e05SDavid Greenman LIST_REMOVE(inp, inp_hash); 1001c3229e05SDavid Greenman LIST_REMOVE(inp, inp_portlist); 1002c3229e05SDavid Greenman if (phd->phd_pcblist.lh_first == NULL) { 1003c3229e05SDavid Greenman LIST_REMOVE(phd, phd_hash); 1004c3229e05SDavid Greenman free(phd, M_PCB); 1005c3229e05SDavid Greenman } 1006c3229e05SDavid Greenman } 1007c3229e05SDavid Greenman LIST_REMOVE(inp, inp_list); 10083d4d47f3SGarrett Wollman inp->inp_pcbinfo->ipi_count--; 100915bd2b43SDavid Greenman } 101075c13541SPoul-Henning Kamp 101175c13541SPoul-Henning Kamp int 101275c13541SPoul-Henning Kamp prison_xinpcb(struct proc *p, struct inpcb *inp) 101375c13541SPoul-Henning Kamp { 101475c13541SPoul-Henning Kamp if (!p->p_prison) 101575c13541SPoul-Henning Kamp return (0); 101675c13541SPoul-Henning Kamp if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip) 101775c13541SPoul-Henning Kamp return (0); 101875c13541SPoul-Henning Kamp return (1); 101975c13541SPoul-Henning Kamp } 1020