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 34fdc984f7STor Egge * $Id: in_pcb.c,v 1.32 1997/05/19 00:18:30 tegge Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 382ee45d7dSDavid Greenman #include <sys/queue.h> 39df8bae1dSRodney W. Grimes #include <sys/systm.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43df8bae1dSRodney W. Grimes #include <sys/socket.h> 44df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 45df8bae1dSRodney W. Grimes #include <sys/errno.h> 46df8bae1dSRodney W. Grimes #include <sys/time.h> 47df8bae1dSRodney W. Grimes #include <sys/proc.h> 48101f9fc8SPeter Wemm #include <sys/kernel.h> 49101f9fc8SPeter Wemm #include <sys/sysctl.h> 50df8bae1dSRodney W. Grimes 51df8bae1dSRodney W. Grimes #include <net/if.h> 52df8bae1dSRodney W. Grimes #include <net/route.h> 53df8bae1dSRodney W. Grimes 54df8bae1dSRodney W. Grimes #include <netinet/in.h> 55df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 56df8bae1dSRodney W. Grimes #include <netinet/ip.h> 57df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 58df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 59df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes struct in_addr zeroin_addr; 62df8bae1dSRodney W. Grimes 63bbd42ad0SPeter Wemm static void in_pcbinshash __P((struct inpcb *)); 64bbd42ad0SPeter Wemm static void in_rtchange __P((struct inpcb *, int)); 65bbd42ad0SPeter Wemm 66101f9fc8SPeter Wemm /* 67101f9fc8SPeter Wemm * These configure the range of local port addresses assigned to 68101f9fc8SPeter Wemm * "unspecified" outgoing connections/packets/whatever. 69101f9fc8SPeter Wemm */ 70bbd42ad0SPeter Wemm static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 71bbd42ad0SPeter Wemm static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 7233b3ac06SPeter Wemm static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ 7333b3ac06SPeter Wemm static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ 7433b3ac06SPeter Wemm static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 40000 */ 7533b3ac06SPeter Wemm static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ 76101f9fc8SPeter Wemm 77bbd42ad0SPeter Wemm #define RANGECHK(var, min, max) \ 78bbd42ad0SPeter Wemm if ((var) < (min)) { (var) = (min); } \ 79bbd42ad0SPeter Wemm else if ((var) > (max)) { (var) = (max); } 80bbd42ad0SPeter Wemm 81bbd42ad0SPeter Wemm static int 82bbd42ad0SPeter Wemm sysctl_net_ipport_check SYSCTL_HANDLER_ARGS 83bbd42ad0SPeter Wemm { 84bbd42ad0SPeter Wemm int error = sysctl_handle_int(oidp, 85bbd42ad0SPeter Wemm oidp->oid_arg1, oidp->oid_arg2, req); 86bbd42ad0SPeter Wemm if (!error) { 87bbd42ad0SPeter Wemm RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 88bbd42ad0SPeter Wemm RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 89bbd42ad0SPeter Wemm RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 90bbd42ad0SPeter Wemm RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 91bbd42ad0SPeter Wemm RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 92bbd42ad0SPeter Wemm RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 93bbd42ad0SPeter Wemm } 94bbd42ad0SPeter Wemm return error; 95bbd42ad0SPeter Wemm } 96bbd42ad0SPeter Wemm 97bbd42ad0SPeter Wemm #undef RANGECHK 98bbd42ad0SPeter Wemm 9933b3ac06SPeter Wemm SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 10033b3ac06SPeter Wemm 101bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 102bbd42ad0SPeter Wemm &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 103bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 104bbd42ad0SPeter Wemm &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 105bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 106bbd42ad0SPeter Wemm &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 107bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 108bbd42ad0SPeter Wemm &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 109bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 110bbd42ad0SPeter Wemm &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 111bbd42ad0SPeter Wemm SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 112bbd42ad0SPeter Wemm &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 1130312fbe9SPoul-Henning Kamp 114df8bae1dSRodney W. Grimes int 115a29f300eSGarrett Wollman in_pcballoc(so, pcbinfo, p) 116df8bae1dSRodney W. Grimes struct socket *so; 11715bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 118a29f300eSGarrett Wollman struct proc *p; 119df8bae1dSRodney W. Grimes { 120df8bae1dSRodney W. Grimes register struct inpcb *inp; 1217bc4aca7SDavid Greenman int s; 122df8bae1dSRodney W. Grimes 123a29f300eSGarrett Wollman MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, 124a29f300eSGarrett Wollman p ? M_WAITOK : M_NOWAIT); 125df8bae1dSRodney W. Grimes if (inp == NULL) 126df8bae1dSRodney W. Grimes return (ENOBUFS); 127df8bae1dSRodney W. Grimes bzero((caddr_t)inp, sizeof(*inp)); 12815bd2b43SDavid Greenman inp->inp_pcbinfo = pcbinfo; 129df8bae1dSRodney W. Grimes inp->inp_socket = so; 1307bc4aca7SDavid Greenman s = splnet(); 13115bd2b43SDavid Greenman LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 13215bd2b43SDavid Greenman in_pcbinshash(inp); 1337bc4aca7SDavid Greenman splx(s); 134df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)inp; 135df8bae1dSRodney W. Grimes return (0); 136df8bae1dSRodney W. Grimes } 137df8bae1dSRodney W. Grimes 138df8bae1dSRodney W. Grimes int 139a29f300eSGarrett Wollman in_pcbbind(inp, nam, p) 140df8bae1dSRodney W. Grimes register struct inpcb *inp; 141df8bae1dSRodney W. Grimes struct mbuf *nam; 142a29f300eSGarrett Wollman struct proc *p; 143df8bae1dSRodney W. Grimes { 144df8bae1dSRodney W. Grimes register struct socket *so = inp->inp_socket; 14537bd2b30SPeter Wemm unsigned short *lastport; 14615bd2b43SDavid Greenman struct sockaddr_in *sin; 147df8bae1dSRodney W. Grimes u_short lport = 0; 148df8bae1dSRodney W. Grimes int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 149df8bae1dSRodney W. Grimes int error; 150df8bae1dSRodney W. Grimes 15159562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 152df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 153df8bae1dSRodney W. Grimes if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 154df8bae1dSRodney W. Grimes return (EINVAL); 155df8bae1dSRodney W. Grimes if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 156df8bae1dSRodney W. Grimes ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 157df8bae1dSRodney W. Grimes (so->so_options & SO_ACCEPTCONN) == 0)) 1586d6a026bSDavid Greenman wild = 1; 159df8bae1dSRodney W. Grimes if (nam) { 160df8bae1dSRodney W. Grimes sin = mtod(nam, struct sockaddr_in *); 161df8bae1dSRodney W. Grimes if (nam->m_len != sizeof (*sin)) 162df8bae1dSRodney W. Grimes return (EINVAL); 163df8bae1dSRodney W. Grimes #ifdef notdef 164df8bae1dSRodney W. Grimes /* 165df8bae1dSRodney W. Grimes * We should check the family, but old programs 166df8bae1dSRodney W. Grimes * incorrectly fail to initialize it. 167df8bae1dSRodney W. Grimes */ 168df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 169df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 170df8bae1dSRodney W. Grimes #endif 171df8bae1dSRodney W. Grimes lport = sin->sin_port; 172df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 173df8bae1dSRodney W. Grimes /* 174df8bae1dSRodney W. Grimes * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 175df8bae1dSRodney W. Grimes * allow complete duplication of binding if 176df8bae1dSRodney W. Grimes * SO_REUSEPORT is set, or if SO_REUSEADDR is set 177df8bae1dSRodney W. Grimes * and a multicast address is bound on both 178df8bae1dSRodney W. Grimes * new and duplicated sockets. 179df8bae1dSRodney W. Grimes */ 180df8bae1dSRodney W. Grimes if (so->so_options & SO_REUSEADDR) 181df8bae1dSRodney W. Grimes reuseport = SO_REUSEADDR|SO_REUSEPORT; 182df8bae1dSRodney W. Grimes } else if (sin->sin_addr.s_addr != INADDR_ANY) { 183df8bae1dSRodney W. Grimes sin->sin_port = 0; /* yech... */ 184df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 185df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes if (lport) { 188df8bae1dSRodney W. Grimes struct inpcb *t; 189df8bae1dSRodney W. Grimes 190df8bae1dSRodney W. Grimes /* GROSS */ 191df8bae1dSRodney W. Grimes if (ntohs(lport) < IPPORT_RESERVED && 192df8bae1dSRodney W. Grimes (error = suser(p->p_ucred, &p->p_acflag))) 1932469dd60SGarrett Wollman return (EACCES); 1946d6a026bSDavid Greenman t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, 195df8bae1dSRodney W. Grimes sin->sin_addr, lport, wild); 196df8bae1dSRodney W. Grimes if (t && (reuseport & t->inp_socket->so_options) == 0) 197df8bae1dSRodney W. Grimes return (EADDRINUSE); 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes inp->inp_laddr = sin->sin_addr; 200df8bae1dSRodney W. Grimes } 20133b3ac06SPeter Wemm if (lport == 0) { 20233b3ac06SPeter Wemm ushort first, last; 20333b3ac06SPeter Wemm int count; 20433b3ac06SPeter Wemm 205321a2846SPoul-Henning Kamp inp->inp_flags |= INP_ANONPORT; 206321a2846SPoul-Henning Kamp 20733b3ac06SPeter Wemm if (inp->inp_flags & INP_HIGHPORT) { 20833b3ac06SPeter Wemm first = ipport_hifirstauto; /* sysctl */ 20933b3ac06SPeter Wemm last = ipport_hilastauto; 21037bd2b30SPeter Wemm lastport = &inp->inp_pcbinfo->lasthi; 21133b3ac06SPeter Wemm } else if (inp->inp_flags & INP_LOWPORT) { 21233b3ac06SPeter Wemm if (error = suser(p->p_ucred, &p->p_acflag)) 213a29f300eSGarrett Wollman return error; 214bbd42ad0SPeter Wemm first = ipport_lowfirstauto; /* 1023 */ 215bbd42ad0SPeter Wemm last = ipport_lowlastauto; /* 600 */ 21637bd2b30SPeter Wemm lastport = &inp->inp_pcbinfo->lastlow; 21733b3ac06SPeter Wemm } else { 21833b3ac06SPeter Wemm first = ipport_firstauto; /* sysctl */ 21933b3ac06SPeter Wemm last = ipport_lastauto; 22037bd2b30SPeter Wemm lastport = &inp->inp_pcbinfo->lastport; 22133b3ac06SPeter Wemm } 22233b3ac06SPeter Wemm /* 22333b3ac06SPeter Wemm * Simple check to ensure all ports are not used up causing 22433b3ac06SPeter Wemm * a deadlock here. 22533b3ac06SPeter Wemm * 22633b3ac06SPeter Wemm * We split the two cases (up and down) so that the direction 22733b3ac06SPeter Wemm * is not being tested on each round of the loop. 22833b3ac06SPeter Wemm */ 22933b3ac06SPeter Wemm if (first > last) { 23033b3ac06SPeter Wemm /* 23133b3ac06SPeter Wemm * counting down 23233b3ac06SPeter Wemm */ 23333b3ac06SPeter Wemm count = first - last; 23433b3ac06SPeter Wemm 235df8bae1dSRodney W. Grimes do { 23633b3ac06SPeter Wemm if (count-- <= 0) /* completely used? */ 23733b3ac06SPeter Wemm return (EADDRNOTAVAIL); 23833b3ac06SPeter Wemm --*lastport; 23933b3ac06SPeter Wemm if (*lastport > first || *lastport < last) 24033b3ac06SPeter Wemm *lastport = first; 24115bd2b43SDavid Greenman lport = htons(*lastport); 2426d6a026bSDavid Greenman } while (in_pcblookup(inp->inp_pcbinfo, 243df8bae1dSRodney W. Grimes zeroin_addr, 0, inp->inp_laddr, lport, wild)); 24433b3ac06SPeter Wemm } else { 24533b3ac06SPeter Wemm /* 24633b3ac06SPeter Wemm * counting up 24733b3ac06SPeter Wemm */ 24833b3ac06SPeter Wemm count = last - first; 24933b3ac06SPeter Wemm 25033b3ac06SPeter Wemm do { 25133b3ac06SPeter Wemm if (count-- <= 0) /* completely used? */ 25233b3ac06SPeter Wemm return (EADDRNOTAVAIL); 25333b3ac06SPeter Wemm ++*lastport; 25433b3ac06SPeter Wemm if (*lastport < first || *lastport > last) 25533b3ac06SPeter Wemm *lastport = first; 25633b3ac06SPeter Wemm lport = htons(*lastport); 2576d6a026bSDavid Greenman } while (in_pcblookup(inp->inp_pcbinfo, 25833b3ac06SPeter Wemm zeroin_addr, 0, inp->inp_laddr, lport, wild)); 25933b3ac06SPeter Wemm } 26033b3ac06SPeter Wemm } 261df8bae1dSRodney W. Grimes inp->inp_lport = lport; 26215bd2b43SDavid Greenman in_pcbrehash(inp); 263df8bae1dSRodney W. Grimes return (0); 264df8bae1dSRodney W. Grimes } 265df8bae1dSRodney W. Grimes 266999f1343SGarrett Wollman /* 267999f1343SGarrett Wollman * Transform old in_pcbconnect() into an inner subroutine for new 268999f1343SGarrett Wollman * in_pcbconnect(): Do some validity-checking on the remote 269999f1343SGarrett Wollman * address (in mbuf 'nam') and then determine local host address 270999f1343SGarrett Wollman * (i.e., which interface) to use to access that remote host. 271999f1343SGarrett Wollman * 272999f1343SGarrett Wollman * This preserves definition of in_pcbconnect(), while supporting a 273999f1343SGarrett Wollman * slightly different version for T/TCP. (This is more than 274999f1343SGarrett Wollman * a bit of a kludge, but cleaning up the internal interfaces would 275999f1343SGarrett Wollman * have forced minor changes in every protocol). 276999f1343SGarrett Wollman */ 277999f1343SGarrett Wollman 278999f1343SGarrett Wollman int 279999f1343SGarrett Wollman in_pcbladdr(inp, nam, plocal_sin) 280999f1343SGarrett Wollman register struct inpcb *inp; 281999f1343SGarrett Wollman struct mbuf *nam; 282999f1343SGarrett Wollman struct sockaddr_in **plocal_sin; 283999f1343SGarrett Wollman { 284df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 285df8bae1dSRodney W. Grimes register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 286df8bae1dSRodney W. Grimes 287df8bae1dSRodney W. Grimes if (nam->m_len != sizeof (*sin)) 288df8bae1dSRodney W. Grimes return (EINVAL); 289df8bae1dSRodney W. Grimes if (sin->sin_family != AF_INET) 290df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 291df8bae1dSRodney W. Grimes if (sin->sin_port == 0) 292df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 29359562606SGarrett Wollman if (!TAILQ_EMPTY(&in_ifaddrhead)) { 294df8bae1dSRodney W. Grimes /* 295df8bae1dSRodney W. Grimes * If the destination address is INADDR_ANY, 296df8bae1dSRodney W. Grimes * use the primary local address. 297df8bae1dSRodney W. Grimes * If the supplied address is INADDR_BROADCAST, 298df8bae1dSRodney W. Grimes * and the primary interface supports broadcast, 299df8bae1dSRodney W. Grimes * choose the broadcast address for that interface. 300df8bae1dSRodney W. Grimes */ 301df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 302df8bae1dSRodney W. Grimes #define sintosa(sin) ((struct sockaddr *)(sin)) 303df8bae1dSRodney W. Grimes #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 304df8bae1dSRodney W. Grimes if (sin->sin_addr.s_addr == INADDR_ANY) 30559562606SGarrett Wollman sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; 306df8bae1dSRodney W. Grimes else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 30759562606SGarrett Wollman (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 30859562606SGarrett Wollman sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; 309df8bae1dSRodney W. Grimes } 310df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 311df8bae1dSRodney W. Grimes register struct route *ro; 312df8bae1dSRodney W. Grimes 313df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)0; 314df8bae1dSRodney W. Grimes /* 315df8bae1dSRodney W. Grimes * If route is known or can be allocated now, 316df8bae1dSRodney W. Grimes * our src addr is taken from the i/f, else punt. 317df8bae1dSRodney W. Grimes */ 318df8bae1dSRodney W. Grimes ro = &inp->inp_route; 319df8bae1dSRodney W. Grimes if (ro->ro_rt && 320df8bae1dSRodney W. Grimes (satosin(&ro->ro_dst)->sin_addr.s_addr != 321df8bae1dSRodney W. Grimes sin->sin_addr.s_addr || 322df8bae1dSRodney W. Grimes inp->inp_socket->so_options & SO_DONTROUTE)) { 323df8bae1dSRodney W. Grimes RTFREE(ro->ro_rt); 324df8bae1dSRodney W. Grimes ro->ro_rt = (struct rtentry *)0; 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 327df8bae1dSRodney W. Grimes (ro->ro_rt == (struct rtentry *)0 || 328df8bae1dSRodney W. Grimes ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 329df8bae1dSRodney W. Grimes /* No route yet, so try to acquire one */ 330df8bae1dSRodney W. Grimes ro->ro_dst.sa_family = AF_INET; 331df8bae1dSRodney W. Grimes ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 332df8bae1dSRodney W. Grimes ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 333df8bae1dSRodney W. Grimes sin->sin_addr; 334df8bae1dSRodney W. Grimes rtalloc(ro); 335df8bae1dSRodney W. Grimes } 336df8bae1dSRodney W. Grimes /* 337df8bae1dSRodney W. Grimes * If we found a route, use the address 338df8bae1dSRodney W. Grimes * corresponding to the outgoing interface 339df8bae1dSRodney W. Grimes * unless it is the loopback (in case a route 340df8bae1dSRodney W. Grimes * to our address on another net goes to loopback). 341df8bae1dSRodney W. Grimes */ 342df8bae1dSRodney W. Grimes if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 343df8bae1dSRodney W. Grimes ia = ifatoia(ro->ro_rt->rt_ifa); 344df8bae1dSRodney W. Grimes if (ia == 0) { 345df8bae1dSRodney W. Grimes u_short fport = sin->sin_port; 346df8bae1dSRodney W. Grimes 347df8bae1dSRodney W. Grimes sin->sin_port = 0; 348df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 349df8bae1dSRodney W. Grimes if (ia == 0) 350df8bae1dSRodney W. Grimes ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 351df8bae1dSRodney W. Grimes sin->sin_port = fport; 352df8bae1dSRodney W. Grimes if (ia == 0) 35359562606SGarrett Wollman ia = in_ifaddrhead.tqh_first; 354df8bae1dSRodney W. Grimes if (ia == 0) 355df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 356df8bae1dSRodney W. Grimes } 357df8bae1dSRodney W. Grimes /* 358df8bae1dSRodney W. Grimes * If the destination address is multicast and an outgoing 359df8bae1dSRodney W. Grimes * interface has been set as a multicast option, use the 360df8bae1dSRodney W. Grimes * address of that interface as our source address. 361df8bae1dSRodney W. Grimes */ 362df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 363df8bae1dSRodney W. Grimes inp->inp_moptions != NULL) { 364df8bae1dSRodney W. Grimes struct ip_moptions *imo; 365df8bae1dSRodney W. Grimes struct ifnet *ifp; 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes imo = inp->inp_moptions; 368df8bae1dSRodney W. Grimes if (imo->imo_multicast_ifp != NULL) { 369df8bae1dSRodney W. Grimes ifp = imo->imo_multicast_ifp; 37059562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 37159562606SGarrett Wollman ia = ia->ia_link.tqe_next) 372df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp) 373df8bae1dSRodney W. Grimes break; 374df8bae1dSRodney W. Grimes if (ia == 0) 375df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 376df8bae1dSRodney W. Grimes } 377df8bae1dSRodney W. Grimes } 378999f1343SGarrett Wollman /* 379999f1343SGarrett Wollman * Don't do pcblookup call here; return interface in plocal_sin 380999f1343SGarrett Wollman * and exit to caller, that will do the lookup. 381999f1343SGarrett Wollman */ 382999f1343SGarrett Wollman *plocal_sin = &ia->ia_addr; 383999f1343SGarrett Wollman 384999f1343SGarrett Wollman } 385999f1343SGarrett Wollman return(0); 386999f1343SGarrett Wollman } 387999f1343SGarrett Wollman 388999f1343SGarrett Wollman /* 389999f1343SGarrett Wollman * Outer subroutine: 390999f1343SGarrett Wollman * Connect from a socket to a specified address. 391999f1343SGarrett Wollman * Both address and port must be specified in argument sin. 392999f1343SGarrett Wollman * If don't have a local address for this socket yet, 393999f1343SGarrett Wollman * then pick one. 394999f1343SGarrett Wollman */ 395999f1343SGarrett Wollman int 396a29f300eSGarrett Wollman in_pcbconnect(inp, nam, p) 397999f1343SGarrett Wollman register struct inpcb *inp; 398999f1343SGarrett Wollman struct mbuf *nam; 399a29f300eSGarrett Wollman struct proc *p; 400999f1343SGarrett Wollman { 401999f1343SGarrett Wollman struct sockaddr_in *ifaddr; 402999f1343SGarrett Wollman register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 403999f1343SGarrett Wollman int error; 404999f1343SGarrett Wollman 405999f1343SGarrett Wollman /* 406999f1343SGarrett Wollman * Call inner routine, to assign local interface address. 407999f1343SGarrett Wollman */ 408999f1343SGarrett Wollman if (error = in_pcbladdr(inp, nam, &ifaddr)) 409999f1343SGarrett Wollman return(error); 410999f1343SGarrett Wollman 4110d7b7d3eSDavid Greenman if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 412df8bae1dSRodney W. Grimes inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 4136d6a026bSDavid Greenman inp->inp_lport, 0) != NULL) 414df8bae1dSRodney W. Grimes return (EADDRINUSE); 415df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr == INADDR_ANY) { 416df8bae1dSRodney W. Grimes if (inp->inp_lport == 0) 417a29f300eSGarrett Wollman (void)in_pcbbind(inp, (struct mbuf *)0, p); 418df8bae1dSRodney W. Grimes inp->inp_laddr = ifaddr->sin_addr; 419df8bae1dSRodney W. Grimes } 420df8bae1dSRodney W. Grimes inp->inp_faddr = sin->sin_addr; 421df8bae1dSRodney W. Grimes inp->inp_fport = sin->sin_port; 42215bd2b43SDavid Greenman in_pcbrehash(inp); 423df8bae1dSRodney W. Grimes return (0); 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes 42626f9a767SRodney W. Grimes void 427df8bae1dSRodney W. Grimes in_pcbdisconnect(inp) 428df8bae1dSRodney W. Grimes struct inpcb *inp; 429df8bae1dSRodney W. Grimes { 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes inp->inp_faddr.s_addr = INADDR_ANY; 432df8bae1dSRodney W. Grimes inp->inp_fport = 0; 43315bd2b43SDavid Greenman in_pcbrehash(inp); 434df8bae1dSRodney W. Grimes if (inp->inp_socket->so_state & SS_NOFDREF) 435df8bae1dSRodney W. Grimes in_pcbdetach(inp); 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes 43826f9a767SRodney W. Grimes void 439df8bae1dSRodney W. Grimes in_pcbdetach(inp) 440df8bae1dSRodney W. Grimes struct inpcb *inp; 441df8bae1dSRodney W. Grimes { 442df8bae1dSRodney W. Grimes struct socket *so = inp->inp_socket; 4437bc4aca7SDavid Greenman int s; 444df8bae1dSRodney W. Grimes 445df8bae1dSRodney W. Grimes so->so_pcb = 0; 446df8bae1dSRodney W. Grimes sofree(so); 447df8bae1dSRodney W. Grimes if (inp->inp_options) 448df8bae1dSRodney W. Grimes (void)m_free(inp->inp_options); 449df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) 450df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 451df8bae1dSRodney W. Grimes ip_freemoptions(inp->inp_moptions); 4527bc4aca7SDavid Greenman s = splnet(); 45315bd2b43SDavid Greenman LIST_REMOVE(inp, inp_hash); 45415bd2b43SDavid Greenman LIST_REMOVE(inp, inp_list); 4557bc4aca7SDavid Greenman splx(s); 456df8bae1dSRodney W. Grimes FREE(inp, M_PCB); 457df8bae1dSRodney W. Grimes } 458df8bae1dSRodney W. Grimes 459117bcae7SGarrett Wollman /* 460117bcae7SGarrett Wollman * The calling convention of in_setsockaddr() and in_setpeeraddr() was 461117bcae7SGarrett Wollman * modified to match the pru_sockaddr() and pru_peeraddr() entry points 462117bcae7SGarrett Wollman * in struct pr_usrreqs, so that protocols can just reference then directly 463117bcae7SGarrett Wollman * without the need for a wrapper function. The socket must have a valid 464117bcae7SGarrett Wollman * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 465117bcae7SGarrett Wollman * except through a kernel programming error, so it is acceptable to panic 466117bcae7SGarrett Wollman * (or in this case trap) if the PCB is invalid. 467117bcae7SGarrett Wollman */ 468117bcae7SGarrett Wollman int 469117bcae7SGarrett Wollman in_setsockaddr(so, nam) 470117bcae7SGarrett Wollman struct socket *so; 471df8bae1dSRodney W. Grimes struct mbuf *nam; 472df8bae1dSRodney W. Grimes { 473fdc984f7STor Egge int s; 474fdc984f7STor Egge register struct inpcb *inp; 475df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 476df8bae1dSRodney W. Grimes 477fdc984f7STor Egge s = splnet(); 478fdc984f7STor Egge inp = sotoinpcb(so); 479db112f04STor Egge if (!inp) { 480db112f04STor Egge splx(s); 481db112f04STor Egge return EINVAL; 482db112f04STor Egge } 483df8bae1dSRodney W. Grimes nam->m_len = sizeof (*sin); 484df8bae1dSRodney W. Grimes sin = mtod(nam, struct sockaddr_in *); 485df8bae1dSRodney W. Grimes bzero((caddr_t)sin, sizeof (*sin)); 486df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 487df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 488df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_lport; 489df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_laddr; 490db112f04STor Egge splx(s); 491117bcae7SGarrett Wollman return 0; 492df8bae1dSRodney W. Grimes } 493df8bae1dSRodney W. Grimes 494117bcae7SGarrett Wollman int 495117bcae7SGarrett Wollman in_setpeeraddr(so, nam) 496117bcae7SGarrett Wollman struct socket *so; 497df8bae1dSRodney W. Grimes struct mbuf *nam; 498df8bae1dSRodney W. Grimes { 499fdc984f7STor Egge int s; 500fdc984f7STor Egge struct inpcb *inp; 501df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 502df8bae1dSRodney W. Grimes 503fdc984f7STor Egge s = splnet(); 504fdc984f7STor Egge inp = sotoinpcb(so); 505db112f04STor Egge if (!inp) { 506db112f04STor Egge splx(s); 507db112f04STor Egge return EINVAL; 508db112f04STor Egge } 509df8bae1dSRodney W. Grimes nam->m_len = sizeof (*sin); 510df8bae1dSRodney W. Grimes sin = mtod(nam, struct sockaddr_in *); 511df8bae1dSRodney W. Grimes bzero((caddr_t)sin, sizeof (*sin)); 512df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 513df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 514df8bae1dSRodney W. Grimes sin->sin_port = inp->inp_fport; 515df8bae1dSRodney W. Grimes sin->sin_addr = inp->inp_faddr; 516db112f04STor Egge splx(s); 517117bcae7SGarrett Wollman return 0; 518df8bae1dSRodney W. Grimes } 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes /* 521df8bae1dSRodney W. Grimes * Pass some notification to all connections of a protocol 522df8bae1dSRodney W. Grimes * associated with address dst. The local address and/or port numbers 523df8bae1dSRodney W. Grimes * may be specified to limit the search. The "usual action" will be 524df8bae1dSRodney W. Grimes * taken, depending on the ctlinput cmd. The caller must filter any 525df8bae1dSRodney W. Grimes * cmds that are uninteresting (e.g., no error in the map). 526df8bae1dSRodney W. Grimes * Call the protocol specific routine (if any) to report 527df8bae1dSRodney W. Grimes * any errors for each matching socket. 528df8bae1dSRodney W. Grimes * 529df8bae1dSRodney W. Grimes * Must be called at splnet. 530df8bae1dSRodney W. Grimes */ 53126f9a767SRodney W. Grimes void 532df8bae1dSRodney W. Grimes in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 53315bd2b43SDavid Greenman struct inpcbhead *head; 534df8bae1dSRodney W. Grimes struct sockaddr *dst; 535df8bae1dSRodney W. Grimes u_int fport_arg, lport_arg; 536df8bae1dSRodney W. Grimes struct in_addr laddr; 537df8bae1dSRodney W. Grimes int cmd; 538df8bae1dSRodney W. Grimes void (*notify) __P((struct inpcb *, int)); 539df8bae1dSRodney W. Grimes { 540df8bae1dSRodney W. Grimes register struct inpcb *inp, *oinp; 541df8bae1dSRodney W. Grimes struct in_addr faddr; 542df8bae1dSRodney W. Grimes u_short fport = fport_arg, lport = lport_arg; 5437bc4aca7SDavid Greenman int errno, s; 544df8bae1dSRodney W. Grimes 545df8bae1dSRodney W. Grimes if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 546df8bae1dSRodney W. Grimes return; 547df8bae1dSRodney W. Grimes faddr = ((struct sockaddr_in *)dst)->sin_addr; 548df8bae1dSRodney W. Grimes if (faddr.s_addr == INADDR_ANY) 549df8bae1dSRodney W. Grimes return; 550df8bae1dSRodney W. Grimes 551df8bae1dSRodney W. Grimes /* 552df8bae1dSRodney W. Grimes * Redirects go to all references to the destination, 553df8bae1dSRodney W. Grimes * and use in_rtchange to invalidate the route cache. 554df8bae1dSRodney W. Grimes * Dead host indications: notify all references to the destination. 555df8bae1dSRodney W. Grimes * Otherwise, if we have knowledge of the local port and address, 556df8bae1dSRodney W. Grimes * deliver only to that socket. 557df8bae1dSRodney W. Grimes */ 558df8bae1dSRodney W. Grimes if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 559df8bae1dSRodney W. Grimes fport = 0; 560df8bae1dSRodney W. Grimes lport = 0; 561df8bae1dSRodney W. Grimes laddr.s_addr = 0; 562df8bae1dSRodney W. Grimes if (cmd != PRC_HOSTDEAD) 563df8bae1dSRodney W. Grimes notify = in_rtchange; 564df8bae1dSRodney W. Grimes } 565df8bae1dSRodney W. Grimes errno = inetctlerrmap[cmd]; 5667bc4aca7SDavid Greenman s = splnet(); 56715bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL;) { 568df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != faddr.s_addr || 569df8bae1dSRodney W. Grimes inp->inp_socket == 0 || 570df8bae1dSRodney W. Grimes (lport && inp->inp_lport != lport) || 571df8bae1dSRodney W. Grimes (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 572df8bae1dSRodney W. Grimes (fport && inp->inp_fport != fport)) { 57315bd2b43SDavid Greenman inp = inp->inp_list.le_next; 574df8bae1dSRodney W. Grimes continue; 575df8bae1dSRodney W. Grimes } 576df8bae1dSRodney W. Grimes oinp = inp; 57715bd2b43SDavid Greenman inp = inp->inp_list.le_next; 578df8bae1dSRodney W. Grimes if (notify) 579df8bae1dSRodney W. Grimes (*notify)(oinp, errno); 580df8bae1dSRodney W. Grimes } 5817bc4aca7SDavid Greenman splx(s); 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes 584df8bae1dSRodney W. Grimes /* 585df8bae1dSRodney W. Grimes * Check for alternatives when higher level complains 586df8bae1dSRodney W. Grimes * about service problems. For now, invalidate cached 587df8bae1dSRodney W. Grimes * routing information. If the route was created dynamically 588df8bae1dSRodney W. Grimes * (by a redirect), time to try a default gateway again. 589df8bae1dSRodney W. Grimes */ 59026f9a767SRodney W. Grimes void 591df8bae1dSRodney W. Grimes in_losing(inp) 592df8bae1dSRodney W. Grimes struct inpcb *inp; 593df8bae1dSRodney W. Grimes { 594df8bae1dSRodney W. Grimes register struct rtentry *rt; 595df8bae1dSRodney W. Grimes struct rt_addrinfo info; 596df8bae1dSRodney W. Grimes 597df8bae1dSRodney W. Grimes if ((rt = inp->inp_route.ro_rt)) { 598df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 599df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 600df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = 601df8bae1dSRodney W. Grimes (struct sockaddr *)&inp->inp_route.ro_dst; 602df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 603df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = rt_mask(rt); 604df8bae1dSRodney W. Grimes rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 605df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_DYNAMIC) 606df8bae1dSRodney W. Grimes (void) rtrequest(RTM_DELETE, rt_key(rt), 607df8bae1dSRodney W. Grimes rt->rt_gateway, rt_mask(rt), rt->rt_flags, 608df8bae1dSRodney W. Grimes (struct rtentry **)0); 609df8bae1dSRodney W. Grimes else 610df8bae1dSRodney W. Grimes /* 611df8bae1dSRodney W. Grimes * A new route can be allocated 612df8bae1dSRodney W. Grimes * the next time output is attempted. 613df8bae1dSRodney W. Grimes */ 614df8bae1dSRodney W. Grimes rtfree(rt); 615df8bae1dSRodney W. Grimes } 616df8bae1dSRodney W. Grimes } 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes /* 619df8bae1dSRodney W. Grimes * After a routing change, flush old routing 620df8bae1dSRodney W. Grimes * and allocate a (hopefully) better one. 621df8bae1dSRodney W. Grimes */ 6220312fbe9SPoul-Henning Kamp static void 623df8bae1dSRodney W. Grimes in_rtchange(inp, errno) 624df8bae1dSRodney W. Grimes register struct inpcb *inp; 625df8bae1dSRodney W. Grimes int errno; 626df8bae1dSRodney W. Grimes { 627df8bae1dSRodney W. Grimes if (inp->inp_route.ro_rt) { 628df8bae1dSRodney W. Grimes rtfree(inp->inp_route.ro_rt); 629df8bae1dSRodney W. Grimes inp->inp_route.ro_rt = 0; 630df8bae1dSRodney W. Grimes /* 631df8bae1dSRodney W. Grimes * A new route can be allocated the next time 632df8bae1dSRodney W. Grimes * output is attempted. 633df8bae1dSRodney W. Grimes */ 634df8bae1dSRodney W. Grimes } 635df8bae1dSRodney W. Grimes } 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes struct inpcb * 6386d6a026bSDavid Greenman in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) 6396d6a026bSDavid Greenman struct inpcbinfo *pcbinfo; 640df8bae1dSRodney W. Grimes struct in_addr faddr, laddr; 641df8bae1dSRodney W. Grimes u_int fport_arg, lport_arg; 6426d6a026bSDavid Greenman int wild_okay; 643df8bae1dSRodney W. Grimes { 6443dbdc25cSDavid Greenman register struct inpcb *inp, *match = NULL; 645df8bae1dSRodney W. Grimes int matchwild = 3, wildcard; 646df8bae1dSRodney W. Grimes u_short fport = fport_arg, lport = lport_arg; 6477bc4aca7SDavid Greenman int s; 6487bc4aca7SDavid Greenman 6497bc4aca7SDavid Greenman s = splnet(); 650df8bae1dSRodney W. Grimes 6516d6a026bSDavid Greenman for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { 652df8bae1dSRodney W. Grimes if (inp->inp_lport != lport) 653df8bae1dSRodney W. Grimes continue; 654df8bae1dSRodney W. Grimes wildcard = 0; 655df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != INADDR_ANY) { 656df8bae1dSRodney W. Grimes if (faddr.s_addr == INADDR_ANY) 657df8bae1dSRodney W. Grimes wildcard++; 658df8bae1dSRodney W. Grimes else if (inp->inp_faddr.s_addr != faddr.s_addr || 659df8bae1dSRodney W. Grimes inp->inp_fport != fport) 660df8bae1dSRodney W. Grimes continue; 661df8bae1dSRodney W. Grimes } else { 662df8bae1dSRodney W. Grimes if (faddr.s_addr != INADDR_ANY) 663df8bae1dSRodney W. Grimes wildcard++; 664df8bae1dSRodney W. Grimes } 66515bd2b43SDavid Greenman if (inp->inp_laddr.s_addr != INADDR_ANY) { 66615bd2b43SDavid Greenman if (laddr.s_addr == INADDR_ANY) 66715bd2b43SDavid Greenman wildcard++; 66815bd2b43SDavid Greenman else if (inp->inp_laddr.s_addr != laddr.s_addr) 66915bd2b43SDavid Greenman continue; 67015bd2b43SDavid Greenman } else { 67115bd2b43SDavid Greenman if (laddr.s_addr != INADDR_ANY) 67215bd2b43SDavid Greenman wildcard++; 67315bd2b43SDavid Greenman } 6746d6a026bSDavid Greenman if (wildcard && wild_okay == 0) 675df8bae1dSRodney W. Grimes continue; 676df8bae1dSRodney W. Grimes if (wildcard < matchwild) { 677df8bae1dSRodney W. Grimes match = inp; 678df8bae1dSRodney W. Grimes matchwild = wildcard; 6793dbdc25cSDavid Greenman if (matchwild == 0) { 680df8bae1dSRodney W. Grimes break; 681df8bae1dSRodney W. Grimes } 682df8bae1dSRodney W. Grimes } 6833dbdc25cSDavid Greenman } 6847bc4aca7SDavid Greenman splx(s); 685df8bae1dSRodney W. Grimes return (match); 686df8bae1dSRodney W. Grimes } 68715bd2b43SDavid Greenman 68815bd2b43SDavid Greenman /* 68915bd2b43SDavid Greenman * Lookup PCB in hash list. 69015bd2b43SDavid Greenman */ 69115bd2b43SDavid Greenman struct inpcb * 6926d6a026bSDavid Greenman in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) 69315bd2b43SDavid Greenman struct inpcbinfo *pcbinfo; 69415bd2b43SDavid Greenman struct in_addr faddr, laddr; 69515bd2b43SDavid Greenman u_int fport_arg, lport_arg; 6966d6a026bSDavid Greenman int wildcard; 69715bd2b43SDavid Greenman { 69815bd2b43SDavid Greenman struct inpcbhead *head; 69915bd2b43SDavid Greenman register struct inpcb *inp; 70015bd2b43SDavid Greenman u_short fport = fport_arg, lport = lport_arg; 7017bc4aca7SDavid Greenman int s; 70215bd2b43SDavid Greenman 7037bc4aca7SDavid Greenman s = splnet(); 70415bd2b43SDavid Greenman /* 70515bd2b43SDavid Greenman * First look for an exact match. 70615bd2b43SDavid Greenman */ 707ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 70815bd2b43SDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 7096d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == faddr.s_addr && 710ca98b82cSDavid Greenman inp->inp_laddr.s_addr == laddr.s_addr && 711ca98b82cSDavid Greenman inp->inp_fport == fport && 712ca98b82cSDavid Greenman inp->inp_lport == lport) 7136d6a026bSDavid Greenman goto found; 7146d6a026bSDavid Greenman } 7156d6a026bSDavid Greenman if (wildcard) { 7166d6a026bSDavid Greenman struct inpcb *local_wild = NULL; 7176d6a026bSDavid Greenman 718ddd79a97SDavid Greenman head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 7196d6a026bSDavid Greenman for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 7206d6a026bSDavid Greenman if (inp->inp_faddr.s_addr == INADDR_ANY && 7216d6a026bSDavid Greenman inp->inp_fport == 0 && inp->inp_lport == lport) { 7226d6a026bSDavid Greenman if (inp->inp_laddr.s_addr == laddr.s_addr) 7236d6a026bSDavid Greenman goto found; 7246d6a026bSDavid Greenman else if (inp->inp_laddr.s_addr == INADDR_ANY) 7256d6a026bSDavid Greenman local_wild = inp; 7266d6a026bSDavid Greenman } 7276d6a026bSDavid Greenman } 7286d6a026bSDavid Greenman if (local_wild != NULL) { 7296d6a026bSDavid Greenman inp = local_wild; 7306d6a026bSDavid Greenman goto found; 7316d6a026bSDavid Greenman } 7326d6a026bSDavid Greenman } 7336d6a026bSDavid Greenman splx(s); 7346d6a026bSDavid Greenman return (NULL); 7356d6a026bSDavid Greenman 7366d6a026bSDavid Greenman found: 73715bd2b43SDavid Greenman /* 73815bd2b43SDavid Greenman * Move PCB to head of this hash chain so that it can be 73915bd2b43SDavid Greenman * found more quickly in the future. 7406d6a026bSDavid Greenman * XXX - this is a pessimization on machines with few 7416d6a026bSDavid Greenman * concurrent connections. 74215bd2b43SDavid Greenman */ 74315bd2b43SDavid Greenman if (inp != head->lh_first) { 74415bd2b43SDavid Greenman LIST_REMOVE(inp, inp_hash); 74515bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 74615bd2b43SDavid Greenman } 7477bc4aca7SDavid Greenman splx(s); 7480d7b7d3eSDavid Greenman return (inp); 74915bd2b43SDavid Greenman } 75015bd2b43SDavid Greenman 7517bc4aca7SDavid Greenman /* 7527bc4aca7SDavid Greenman * Insert PCB into hash chain. Must be called at splnet. 7537bc4aca7SDavid Greenman */ 7540312fbe9SPoul-Henning Kamp static void 75515bd2b43SDavid Greenman in_pcbinshash(inp) 75615bd2b43SDavid Greenman struct inpcb *inp; 75715bd2b43SDavid Greenman { 75815bd2b43SDavid Greenman struct inpcbhead *head; 75915bd2b43SDavid Greenman 760ddd79a97SDavid Greenman head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 761ddd79a97SDavid Greenman inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 76215bd2b43SDavid Greenman 76315bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 76415bd2b43SDavid Greenman } 76515bd2b43SDavid Greenman 76615bd2b43SDavid Greenman void 76715bd2b43SDavid Greenman in_pcbrehash(inp) 76815bd2b43SDavid Greenman struct inpcb *inp; 76915bd2b43SDavid Greenman { 77015bd2b43SDavid Greenman struct inpcbhead *head; 7717bc4aca7SDavid Greenman int s; 77215bd2b43SDavid Greenman 7737bc4aca7SDavid Greenman s = splnet(); 77415bd2b43SDavid Greenman LIST_REMOVE(inp, inp_hash); 77515bd2b43SDavid Greenman 776ddd79a97SDavid Greenman head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 777ddd79a97SDavid Greenman inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 77815bd2b43SDavid Greenman 77915bd2b43SDavid Greenman LIST_INSERT_HEAD(head, inp, inp_hash); 7807bc4aca7SDavid Greenman splx(s); 78115bd2b43SDavid Greenman } 782