1 /* 2 * Copyright (c) 1982, 1986, 1991, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 34 * $Id: in_pcb.c,v 1.29 1997/03/24 11:24:50 bde Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/queue.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/errno.h> 46 #include <sys/time.h> 47 #include <sys/proc.h> 48 #include <sys/kernel.h> 49 #include <sys/sysctl.h> 50 51 #include <net/if.h> 52 #include <net/route.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 #include <netinet/in_pcb.h> 58 #include <netinet/in_var.h> 59 #include <netinet/ip_var.h> 60 61 struct in_addr zeroin_addr; 62 63 static void in_pcbinshash __P((struct inpcb *)); 64 static void in_rtchange __P((struct inpcb *, int)); 65 66 /* 67 * These configure the range of local port addresses assigned to 68 * "unspecified" outgoing connections/packets/whatever. 69 */ 70 static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ 71 static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ 72 static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ 73 static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ 74 static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 40000 */ 75 static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ 76 77 #define RANGECHK(var, min, max) \ 78 if ((var) < (min)) { (var) = (min); } \ 79 else if ((var) > (max)) { (var) = (max); } 80 81 static int 82 sysctl_net_ipport_check SYSCTL_HANDLER_ARGS 83 { 84 int error = sysctl_handle_int(oidp, 85 oidp->oid_arg1, oidp->oid_arg2, req); 86 if (!error) { 87 RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); 88 RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); 89 RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); 90 RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); 91 RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); 92 RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); 93 } 94 return error; 95 } 96 97 #undef RANGECHK 98 99 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 100 101 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, 102 &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); 103 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, 104 &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); 105 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, 106 &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); 107 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, 108 &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); 109 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, 110 &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); 111 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, 112 &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); 113 114 int 115 in_pcballoc(so, pcbinfo) 116 struct socket *so; 117 struct inpcbinfo *pcbinfo; 118 { 119 register struct inpcb *inp; 120 int s; 121 122 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT); 123 if (inp == NULL) 124 return (ENOBUFS); 125 bzero((caddr_t)inp, sizeof(*inp)); 126 inp->inp_pcbinfo = pcbinfo; 127 inp->inp_socket = so; 128 s = splnet(); 129 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 130 in_pcbinshash(inp); 131 splx(s); 132 so->so_pcb = (caddr_t)inp; 133 return (0); 134 } 135 136 int 137 in_pcbbind(inp, nam) 138 register struct inpcb *inp; 139 struct mbuf *nam; 140 { 141 register struct socket *so = inp->inp_socket; 142 unsigned short *lastport; 143 struct sockaddr_in *sin; 144 struct proc *p = curproc; /* XXX */ 145 u_short lport = 0; 146 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 147 int error; 148 149 if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 150 return (EADDRNOTAVAIL); 151 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 152 return (EINVAL); 153 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 154 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 155 (so->so_options & SO_ACCEPTCONN) == 0)) 156 wild = 1; 157 if (nam) { 158 sin = mtod(nam, struct sockaddr_in *); 159 if (nam->m_len != sizeof (*sin)) 160 return (EINVAL); 161 #ifdef notdef 162 /* 163 * We should check the family, but old programs 164 * incorrectly fail to initialize it. 165 */ 166 if (sin->sin_family != AF_INET) 167 return (EAFNOSUPPORT); 168 #endif 169 lport = sin->sin_port; 170 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 171 /* 172 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 173 * allow complete duplication of binding if 174 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 175 * and a multicast address is bound on both 176 * new and duplicated sockets. 177 */ 178 if (so->so_options & SO_REUSEADDR) 179 reuseport = SO_REUSEADDR|SO_REUSEPORT; 180 } else if (sin->sin_addr.s_addr != INADDR_ANY) { 181 sin->sin_port = 0; /* yech... */ 182 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 183 return (EADDRNOTAVAIL); 184 } 185 if (lport) { 186 struct inpcb *t; 187 188 /* GROSS */ 189 if (ntohs(lport) < IPPORT_RESERVED && 190 (error = suser(p->p_ucred, &p->p_acflag))) 191 return (EACCES); 192 t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, 193 sin->sin_addr, lport, wild); 194 if (t && (reuseport & t->inp_socket->so_options) == 0) 195 return (EADDRINUSE); 196 } 197 inp->inp_laddr = sin->sin_addr; 198 } 199 if (lport == 0) { 200 ushort first, last; 201 int count; 202 203 inp->inp_flags |= INP_ANONPORT; 204 205 if (inp->inp_flags & INP_HIGHPORT) { 206 first = ipport_hifirstauto; /* sysctl */ 207 last = ipport_hilastauto; 208 lastport = &inp->inp_pcbinfo->lasthi; 209 } else if (inp->inp_flags & INP_LOWPORT) { 210 if (error = suser(p->p_ucred, &p->p_acflag)) 211 return (EACCES); 212 first = ipport_lowfirstauto; /* 1023 */ 213 last = ipport_lowlastauto; /* 600 */ 214 lastport = &inp->inp_pcbinfo->lastlow; 215 } else { 216 first = ipport_firstauto; /* sysctl */ 217 last = ipport_lastauto; 218 lastport = &inp->inp_pcbinfo->lastport; 219 } 220 /* 221 * Simple check to ensure all ports are not used up causing 222 * a deadlock here. 223 * 224 * We split the two cases (up and down) so that the direction 225 * is not being tested on each round of the loop. 226 */ 227 if (first > last) { 228 /* 229 * counting down 230 */ 231 count = first - last; 232 233 do { 234 if (count-- <= 0) /* completely used? */ 235 return (EADDRNOTAVAIL); 236 --*lastport; 237 if (*lastport > first || *lastport < last) 238 *lastport = first; 239 lport = htons(*lastport); 240 } while (in_pcblookup(inp->inp_pcbinfo, 241 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 242 } else { 243 /* 244 * counting up 245 */ 246 count = last - first; 247 248 do { 249 if (count-- <= 0) /* completely used? */ 250 return (EADDRNOTAVAIL); 251 ++*lastport; 252 if (*lastport < first || *lastport > last) 253 *lastport = first; 254 lport = htons(*lastport); 255 } while (in_pcblookup(inp->inp_pcbinfo, 256 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 257 } 258 } 259 inp->inp_lport = lport; 260 in_pcbrehash(inp); 261 return (0); 262 } 263 264 /* 265 * Transform old in_pcbconnect() into an inner subroutine for new 266 * in_pcbconnect(): Do some validity-checking on the remote 267 * address (in mbuf 'nam') and then determine local host address 268 * (i.e., which interface) to use to access that remote host. 269 * 270 * This preserves definition of in_pcbconnect(), while supporting a 271 * slightly different version for T/TCP. (This is more than 272 * a bit of a kludge, but cleaning up the internal interfaces would 273 * have forced minor changes in every protocol). 274 */ 275 276 int 277 in_pcbladdr(inp, nam, plocal_sin) 278 register struct inpcb *inp; 279 struct mbuf *nam; 280 struct sockaddr_in **plocal_sin; 281 { 282 struct in_ifaddr *ia; 283 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 284 285 if (nam->m_len != sizeof (*sin)) 286 return (EINVAL); 287 if (sin->sin_family != AF_INET) 288 return (EAFNOSUPPORT); 289 if (sin->sin_port == 0) 290 return (EADDRNOTAVAIL); 291 if (!TAILQ_EMPTY(&in_ifaddrhead)) { 292 /* 293 * If the destination address is INADDR_ANY, 294 * use the primary local address. 295 * If the supplied address is INADDR_BROADCAST, 296 * and the primary interface supports broadcast, 297 * choose the broadcast address for that interface. 298 */ 299 #define satosin(sa) ((struct sockaddr_in *)(sa)) 300 #define sintosa(sin) ((struct sockaddr *)(sin)) 301 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 302 if (sin->sin_addr.s_addr == INADDR_ANY) 303 sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; 304 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 305 (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 306 sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; 307 } 308 if (inp->inp_laddr.s_addr == INADDR_ANY) { 309 register struct route *ro; 310 311 ia = (struct in_ifaddr *)0; 312 /* 313 * If route is known or can be allocated now, 314 * our src addr is taken from the i/f, else punt. 315 */ 316 ro = &inp->inp_route; 317 if (ro->ro_rt && 318 (satosin(&ro->ro_dst)->sin_addr.s_addr != 319 sin->sin_addr.s_addr || 320 inp->inp_socket->so_options & SO_DONTROUTE)) { 321 RTFREE(ro->ro_rt); 322 ro->ro_rt = (struct rtentry *)0; 323 } 324 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 325 (ro->ro_rt == (struct rtentry *)0 || 326 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 327 /* No route yet, so try to acquire one */ 328 ro->ro_dst.sa_family = AF_INET; 329 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 330 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 331 sin->sin_addr; 332 rtalloc(ro); 333 } 334 /* 335 * If we found a route, use the address 336 * corresponding to the outgoing interface 337 * unless it is the loopback (in case a route 338 * to our address on another net goes to loopback). 339 */ 340 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 341 ia = ifatoia(ro->ro_rt->rt_ifa); 342 if (ia == 0) { 343 u_short fport = sin->sin_port; 344 345 sin->sin_port = 0; 346 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 347 if (ia == 0) 348 ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 349 sin->sin_port = fport; 350 if (ia == 0) 351 ia = in_ifaddrhead.tqh_first; 352 if (ia == 0) 353 return (EADDRNOTAVAIL); 354 } 355 /* 356 * If the destination address is multicast and an outgoing 357 * interface has been set as a multicast option, use the 358 * address of that interface as our source address. 359 */ 360 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 361 inp->inp_moptions != NULL) { 362 struct ip_moptions *imo; 363 struct ifnet *ifp; 364 365 imo = inp->inp_moptions; 366 if (imo->imo_multicast_ifp != NULL) { 367 ifp = imo->imo_multicast_ifp; 368 for (ia = in_ifaddrhead.tqh_first; ia; 369 ia = ia->ia_link.tqe_next) 370 if (ia->ia_ifp == ifp) 371 break; 372 if (ia == 0) 373 return (EADDRNOTAVAIL); 374 } 375 } 376 /* 377 * Don't do pcblookup call here; return interface in plocal_sin 378 * and exit to caller, that will do the lookup. 379 */ 380 *plocal_sin = &ia->ia_addr; 381 382 } 383 return(0); 384 } 385 386 /* 387 * Outer subroutine: 388 * Connect from a socket to a specified address. 389 * Both address and port must be specified in argument sin. 390 * If don't have a local address for this socket yet, 391 * then pick one. 392 */ 393 int 394 in_pcbconnect(inp, nam) 395 register struct inpcb *inp; 396 struct mbuf *nam; 397 { 398 struct sockaddr_in *ifaddr; 399 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 400 int error; 401 402 /* 403 * Call inner routine, to assign local interface address. 404 */ 405 if (error = in_pcbladdr(inp, nam, &ifaddr)) 406 return(error); 407 408 if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 409 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 410 inp->inp_lport, 0) != NULL) 411 return (EADDRINUSE); 412 if (inp->inp_laddr.s_addr == INADDR_ANY) { 413 if (inp->inp_lport == 0) 414 (void)in_pcbbind(inp, (struct mbuf *)0); 415 inp->inp_laddr = ifaddr->sin_addr; 416 } 417 inp->inp_faddr = sin->sin_addr; 418 inp->inp_fport = sin->sin_port; 419 in_pcbrehash(inp); 420 return (0); 421 } 422 423 void 424 in_pcbdisconnect(inp) 425 struct inpcb *inp; 426 { 427 428 inp->inp_faddr.s_addr = INADDR_ANY; 429 inp->inp_fport = 0; 430 in_pcbrehash(inp); 431 if (inp->inp_socket->so_state & SS_NOFDREF) 432 in_pcbdetach(inp); 433 } 434 435 void 436 in_pcbdetach(inp) 437 struct inpcb *inp; 438 { 439 struct socket *so = inp->inp_socket; 440 int s; 441 442 so->so_pcb = 0; 443 sofree(so); 444 if (inp->inp_options) 445 (void)m_free(inp->inp_options); 446 if (inp->inp_route.ro_rt) 447 rtfree(inp->inp_route.ro_rt); 448 ip_freemoptions(inp->inp_moptions); 449 s = splnet(); 450 LIST_REMOVE(inp, inp_hash); 451 LIST_REMOVE(inp, inp_list); 452 splx(s); 453 FREE(inp, M_PCB); 454 } 455 456 /* 457 * The calling convention of in_setsockaddr() and in_setpeeraddr() was 458 * modified to match the pru_sockaddr() and pru_peeraddr() entry points 459 * in struct pr_usrreqs, so that protocols can just reference then directly 460 * without the need for a wrapper function. The socket must have a valid 461 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 462 * except through a kernel programming error, so it is acceptable to panic 463 * (or in this case trap) if the PCB is invalid. 464 */ 465 int 466 in_setsockaddr(so, nam) 467 struct socket *so; 468 struct mbuf *nam; 469 { 470 register struct inpcb *inp = sotoinpcb(so); 471 register struct sockaddr_in *sin; 472 473 nam->m_len = sizeof (*sin); 474 sin = mtod(nam, struct sockaddr_in *); 475 bzero((caddr_t)sin, sizeof (*sin)); 476 sin->sin_family = AF_INET; 477 sin->sin_len = sizeof(*sin); 478 sin->sin_port = inp->inp_lport; 479 sin->sin_addr = inp->inp_laddr; 480 return 0; 481 } 482 483 int 484 in_setpeeraddr(so, nam) 485 struct socket *so; 486 struct mbuf *nam; 487 { 488 struct inpcb *inp = sotoinpcb(so); 489 register struct sockaddr_in *sin; 490 491 nam->m_len = sizeof (*sin); 492 sin = mtod(nam, struct sockaddr_in *); 493 bzero((caddr_t)sin, sizeof (*sin)); 494 sin->sin_family = AF_INET; 495 sin->sin_len = sizeof(*sin); 496 sin->sin_port = inp->inp_fport; 497 sin->sin_addr = inp->inp_faddr; 498 return 0; 499 } 500 501 /* 502 * Pass some notification to all connections of a protocol 503 * associated with address dst. The local address and/or port numbers 504 * may be specified to limit the search. The "usual action" will be 505 * taken, depending on the ctlinput cmd. The caller must filter any 506 * cmds that are uninteresting (e.g., no error in the map). 507 * Call the protocol specific routine (if any) to report 508 * any errors for each matching socket. 509 * 510 * Must be called at splnet. 511 */ 512 void 513 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 514 struct inpcbhead *head; 515 struct sockaddr *dst; 516 u_int fport_arg, lport_arg; 517 struct in_addr laddr; 518 int cmd; 519 void (*notify) __P((struct inpcb *, int)); 520 { 521 register struct inpcb *inp, *oinp; 522 struct in_addr faddr; 523 u_short fport = fport_arg, lport = lport_arg; 524 int errno, s; 525 526 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 527 return; 528 faddr = ((struct sockaddr_in *)dst)->sin_addr; 529 if (faddr.s_addr == INADDR_ANY) 530 return; 531 532 /* 533 * Redirects go to all references to the destination, 534 * and use in_rtchange to invalidate the route cache. 535 * Dead host indications: notify all references to the destination. 536 * Otherwise, if we have knowledge of the local port and address, 537 * deliver only to that socket. 538 */ 539 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 540 fport = 0; 541 lport = 0; 542 laddr.s_addr = 0; 543 if (cmd != PRC_HOSTDEAD) 544 notify = in_rtchange; 545 } 546 errno = inetctlerrmap[cmd]; 547 s = splnet(); 548 for (inp = head->lh_first; inp != NULL;) { 549 if (inp->inp_faddr.s_addr != faddr.s_addr || 550 inp->inp_socket == 0 || 551 (lport && inp->inp_lport != lport) || 552 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 553 (fport && inp->inp_fport != fport)) { 554 inp = inp->inp_list.le_next; 555 continue; 556 } 557 oinp = inp; 558 inp = inp->inp_list.le_next; 559 if (notify) 560 (*notify)(oinp, errno); 561 } 562 splx(s); 563 } 564 565 /* 566 * Check for alternatives when higher level complains 567 * about service problems. For now, invalidate cached 568 * routing information. If the route was created dynamically 569 * (by a redirect), time to try a default gateway again. 570 */ 571 void 572 in_losing(inp) 573 struct inpcb *inp; 574 { 575 register struct rtentry *rt; 576 struct rt_addrinfo info; 577 578 if ((rt = inp->inp_route.ro_rt)) { 579 inp->inp_route.ro_rt = 0; 580 bzero((caddr_t)&info, sizeof(info)); 581 info.rti_info[RTAX_DST] = 582 (struct sockaddr *)&inp->inp_route.ro_dst; 583 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 584 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 585 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 586 if (rt->rt_flags & RTF_DYNAMIC) 587 (void) rtrequest(RTM_DELETE, rt_key(rt), 588 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 589 (struct rtentry **)0); 590 else 591 /* 592 * A new route can be allocated 593 * the next time output is attempted. 594 */ 595 rtfree(rt); 596 } 597 } 598 599 /* 600 * After a routing change, flush old routing 601 * and allocate a (hopefully) better one. 602 */ 603 static void 604 in_rtchange(inp, errno) 605 register struct inpcb *inp; 606 int errno; 607 { 608 if (inp->inp_route.ro_rt) { 609 rtfree(inp->inp_route.ro_rt); 610 inp->inp_route.ro_rt = 0; 611 /* 612 * A new route can be allocated the next time 613 * output is attempted. 614 */ 615 } 616 } 617 618 struct inpcb * 619 in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) 620 struct inpcbinfo *pcbinfo; 621 struct in_addr faddr, laddr; 622 u_int fport_arg, lport_arg; 623 int wild_okay; 624 { 625 register struct inpcb *inp, *match = NULL; 626 int matchwild = 3, wildcard; 627 u_short fport = fport_arg, lport = lport_arg; 628 int s; 629 630 s = splnet(); 631 632 for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { 633 if (inp->inp_lport != lport) 634 continue; 635 wildcard = 0; 636 if (inp->inp_faddr.s_addr != INADDR_ANY) { 637 if (faddr.s_addr == INADDR_ANY) 638 wildcard++; 639 else if (inp->inp_faddr.s_addr != faddr.s_addr || 640 inp->inp_fport != fport) 641 continue; 642 } else { 643 if (faddr.s_addr != INADDR_ANY) 644 wildcard++; 645 } 646 if (inp->inp_laddr.s_addr != INADDR_ANY) { 647 if (laddr.s_addr == INADDR_ANY) 648 wildcard++; 649 else if (inp->inp_laddr.s_addr != laddr.s_addr) 650 continue; 651 } else { 652 if (laddr.s_addr != INADDR_ANY) 653 wildcard++; 654 } 655 if (wildcard && wild_okay == 0) 656 continue; 657 if (wildcard < matchwild) { 658 match = inp; 659 matchwild = wildcard; 660 if (matchwild == 0) { 661 break; 662 } 663 } 664 } 665 splx(s); 666 return (match); 667 } 668 669 /* 670 * Lookup PCB in hash list. 671 */ 672 struct inpcb * 673 in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) 674 struct inpcbinfo *pcbinfo; 675 struct in_addr faddr, laddr; 676 u_int fport_arg, lport_arg; 677 int wildcard; 678 { 679 struct inpcbhead *head; 680 register struct inpcb *inp; 681 u_short fport = fport_arg, lport = lport_arg; 682 int s; 683 684 s = splnet(); 685 /* 686 * First look for an exact match. 687 */ 688 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 689 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 690 if (inp->inp_faddr.s_addr == faddr.s_addr && 691 inp->inp_laddr.s_addr == laddr.s_addr && 692 inp->inp_fport == fport && 693 inp->inp_lport == lport) 694 goto found; 695 } 696 if (wildcard) { 697 struct inpcb *local_wild = NULL; 698 699 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 700 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 701 if (inp->inp_faddr.s_addr == INADDR_ANY && 702 inp->inp_fport == 0 && inp->inp_lport == lport) { 703 if (inp->inp_laddr.s_addr == laddr.s_addr) 704 goto found; 705 else if (inp->inp_laddr.s_addr == INADDR_ANY) 706 local_wild = inp; 707 } 708 } 709 if (local_wild != NULL) { 710 inp = local_wild; 711 goto found; 712 } 713 } 714 splx(s); 715 return (NULL); 716 717 found: 718 /* 719 * Move PCB to head of this hash chain so that it can be 720 * found more quickly in the future. 721 * XXX - this is a pessimization on machines with few 722 * concurrent connections. 723 */ 724 if (inp != head->lh_first) { 725 LIST_REMOVE(inp, inp_hash); 726 LIST_INSERT_HEAD(head, inp, inp_hash); 727 } 728 splx(s); 729 return (inp); 730 } 731 732 /* 733 * Insert PCB into hash chain. Must be called at splnet. 734 */ 735 static void 736 in_pcbinshash(inp) 737 struct inpcb *inp; 738 { 739 struct inpcbhead *head; 740 741 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 742 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 743 744 LIST_INSERT_HEAD(head, inp, inp_hash); 745 } 746 747 void 748 in_pcbrehash(inp) 749 struct inpcb *inp; 750 { 751 struct inpcbhead *head; 752 int s; 753 754 s = splnet(); 755 LIST_REMOVE(inp, inp_hash); 756 757 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 758 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 759 760 LIST_INSERT_HEAD(head, inp, inp_hash); 761 splx(s); 762 } 763