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.16 1996/01/19 08:00:58 peter Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/protosw.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/ioctl.h> 45 #include <sys/errno.h> 46 #include <sys/time.h> 47 #include <sys/proc.h> 48 #include <sys/queue.h> 49 #include <sys/kernel.h> 50 #include <sys/sysctl.h> 51 52 #include <net/if.h> 53 #include <net/route.h> 54 55 #include <netinet/in.h> 56 #include <netinet/in_systm.h> 57 #include <netinet/ip.h> 58 #include <netinet/in_pcb.h> 59 #include <netinet/in_var.h> 60 #include <netinet/ip_var.h> 61 62 struct in_addr zeroin_addr; 63 64 /* 65 * These configure the range of local port addresses assigned to 66 * "unspecified" outgoing connections/packets/whatever. 67 */ 68 static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ 69 static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ 70 static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 40000 */ 71 static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ 72 73 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); 74 75 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, first, CTLFLAG_RW, 76 &ipport_firstauto, 0, ""); 77 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, last, CTLFLAG_RW, 78 &ipport_lastauto, 0, ""); 79 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLFLAG_RW, 80 &ipport_hifirstauto, 0, ""); 81 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, hilast, CTLFLAG_RW, 82 &ipport_hilastauto, 0, ""); 83 84 static void in_pcbinshash __P((struct inpcb *)); 85 static void in_rtchange __P((struct inpcb *, int)); 86 87 int 88 in_pcballoc(so, pcbinfo) 89 struct socket *so; 90 struct inpcbinfo *pcbinfo; 91 { 92 register struct inpcb *inp; 93 int s; 94 95 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT); 96 if (inp == NULL) 97 return (ENOBUFS); 98 bzero((caddr_t)inp, sizeof(*inp)); 99 inp->inp_pcbinfo = pcbinfo; 100 inp->inp_socket = so; 101 s = splnet(); 102 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 103 in_pcbinshash(inp); 104 splx(s); 105 so->so_pcb = (caddr_t)inp; 106 return (0); 107 } 108 109 int 110 in_pcbbind(inp, nam) 111 register struct inpcb *inp; 112 struct mbuf *nam; 113 { 114 register struct socket *so = inp->inp_socket; 115 struct inpcbhead *head = inp->inp_pcbinfo->listhead; 116 unsigned short *lastport = &inp->inp_pcbinfo->lastport; 117 struct sockaddr_in *sin; 118 struct proc *p = curproc; /* XXX */ 119 u_short lport = 0; 120 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 121 int error; 122 123 if (in_ifaddr == 0) 124 return (EADDRNOTAVAIL); 125 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 126 return (EINVAL); 127 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 128 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 129 (so->so_options & SO_ACCEPTCONN) == 0)) 130 wild = INPLOOKUP_WILDCARD; 131 if (nam) { 132 sin = mtod(nam, struct sockaddr_in *); 133 if (nam->m_len != sizeof (*sin)) 134 return (EINVAL); 135 #ifdef notdef 136 /* 137 * We should check the family, but old programs 138 * incorrectly fail to initialize it. 139 */ 140 if (sin->sin_family != AF_INET) 141 return (EAFNOSUPPORT); 142 #endif 143 lport = sin->sin_port; 144 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 145 /* 146 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 147 * allow complete duplication of binding if 148 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 149 * and a multicast address is bound on both 150 * new and duplicated sockets. 151 */ 152 if (so->so_options & SO_REUSEADDR) 153 reuseport = SO_REUSEADDR|SO_REUSEPORT; 154 } else if (sin->sin_addr.s_addr != INADDR_ANY) { 155 sin->sin_port = 0; /* yech... */ 156 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 157 return (EADDRNOTAVAIL); 158 } 159 if (lport) { 160 struct inpcb *t; 161 162 /* GROSS */ 163 if (ntohs(lport) < IPPORT_RESERVED && 164 (error = suser(p->p_ucred, &p->p_acflag))) 165 return (EACCES); 166 t = in_pcblookup(head, zeroin_addr, 0, 167 sin->sin_addr, lport, wild); 168 if (t && (reuseport & t->inp_socket->so_options) == 0) 169 return (EADDRINUSE); 170 } 171 inp->inp_laddr = sin->sin_addr; 172 } 173 if (lport == 0) { 174 ushort first, last; 175 int count; 176 177 if (inp->inp_flags & INP_HIGHPORT) { 178 first = ipport_hifirstauto; /* sysctl */ 179 last = ipport_hilastauto; 180 } else if (inp->inp_flags & INP_LOWPORT) { 181 if (error = suser(p->p_ucred, &p->p_acflag)) 182 return (EACCES); 183 first = IPPORT_RESERVED - 1; /* 1023 */ 184 last = 1; 185 } else { 186 first = ipport_firstauto; /* sysctl */ 187 last = ipport_lastauto; 188 } 189 /* 190 * Simple check to ensure all ports are not used up causing 191 * a deadlock here. 192 * 193 * We split the two cases (up and down) so that the direction 194 * is not being tested on each round of the loop. 195 */ 196 if (first > last) { 197 /* 198 * counting down 199 */ 200 count = first - last; 201 202 do { 203 if (count-- <= 0) /* completely used? */ 204 return (EADDRNOTAVAIL); 205 --*lastport; 206 if (*lastport > first || *lastport < last) 207 *lastport = first; 208 lport = htons(*lastport); 209 } while (in_pcblookup(head, 210 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 211 } else { 212 /* 213 * counting up 214 */ 215 count = last - first; 216 217 do { 218 if (count-- <= 0) /* completely used? */ 219 return (EADDRNOTAVAIL); 220 ++*lastport; 221 if (*lastport < first || *lastport > last) 222 *lastport = first; 223 lport = htons(*lastport); 224 } while (in_pcblookup(head, 225 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 226 } 227 } 228 inp->inp_lport = lport; 229 in_pcbrehash(inp); 230 return (0); 231 } 232 233 /* 234 * Transform old in_pcbconnect() into an inner subroutine for new 235 * in_pcbconnect(): Do some validity-checking on the remote 236 * address (in mbuf 'nam') and then determine local host address 237 * (i.e., which interface) to use to access that remote host. 238 * 239 * This preserves definition of in_pcbconnect(), while supporting a 240 * slightly different version for T/TCP. (This is more than 241 * a bit of a kludge, but cleaning up the internal interfaces would 242 * have forced minor changes in every protocol). 243 */ 244 245 int 246 in_pcbladdr(inp, nam, plocal_sin) 247 register struct inpcb *inp; 248 struct mbuf *nam; 249 struct sockaddr_in **plocal_sin; 250 { 251 struct in_ifaddr *ia; 252 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 253 254 if (nam->m_len != sizeof (*sin)) 255 return (EINVAL); 256 if (sin->sin_family != AF_INET) 257 return (EAFNOSUPPORT); 258 if (sin->sin_port == 0) 259 return (EADDRNOTAVAIL); 260 if (in_ifaddr) { 261 /* 262 * If the destination address is INADDR_ANY, 263 * use the primary local address. 264 * If the supplied address is INADDR_BROADCAST, 265 * and the primary interface supports broadcast, 266 * choose the broadcast address for that interface. 267 */ 268 #define satosin(sa) ((struct sockaddr_in *)(sa)) 269 #define sintosa(sin) ((struct sockaddr *)(sin)) 270 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 271 if (sin->sin_addr.s_addr == INADDR_ANY) 272 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 273 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 274 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 275 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 276 } 277 if (inp->inp_laddr.s_addr == INADDR_ANY) { 278 register struct route *ro; 279 280 ia = (struct in_ifaddr *)0; 281 /* 282 * If route is known or can be allocated now, 283 * our src addr is taken from the i/f, else punt. 284 */ 285 ro = &inp->inp_route; 286 if (ro->ro_rt && 287 (satosin(&ro->ro_dst)->sin_addr.s_addr != 288 sin->sin_addr.s_addr || 289 inp->inp_socket->so_options & SO_DONTROUTE)) { 290 RTFREE(ro->ro_rt); 291 ro->ro_rt = (struct rtentry *)0; 292 } 293 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 294 (ro->ro_rt == (struct rtentry *)0 || 295 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 296 /* No route yet, so try to acquire one */ 297 ro->ro_dst.sa_family = AF_INET; 298 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 299 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 300 sin->sin_addr; 301 rtalloc(ro); 302 } 303 /* 304 * If we found a route, use the address 305 * corresponding to the outgoing interface 306 * unless it is the loopback (in case a route 307 * to our address on another net goes to loopback). 308 */ 309 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 310 ia = ifatoia(ro->ro_rt->rt_ifa); 311 if (ia == 0) { 312 u_short fport = sin->sin_port; 313 314 sin->sin_port = 0; 315 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 316 if (ia == 0) 317 ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 318 sin->sin_port = fport; 319 if (ia == 0) 320 ia = in_ifaddr; 321 if (ia == 0) 322 return (EADDRNOTAVAIL); 323 } 324 /* 325 * If the destination address is multicast and an outgoing 326 * interface has been set as a multicast option, use the 327 * address of that interface as our source address. 328 */ 329 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 330 inp->inp_moptions != NULL) { 331 struct ip_moptions *imo; 332 struct ifnet *ifp; 333 334 imo = inp->inp_moptions; 335 if (imo->imo_multicast_ifp != NULL) { 336 ifp = imo->imo_multicast_ifp; 337 for (ia = in_ifaddr; ia; ia = ia->ia_next) 338 if (ia->ia_ifp == ifp) 339 break; 340 if (ia == 0) 341 return (EADDRNOTAVAIL); 342 } 343 } 344 /* 345 * Don't do pcblookup call here; return interface in plocal_sin 346 * and exit to caller, that will do the lookup. 347 */ 348 *plocal_sin = &ia->ia_addr; 349 350 } 351 return(0); 352 } 353 354 /* 355 * Outer subroutine: 356 * Connect from a socket to a specified address. 357 * Both address and port must be specified in argument sin. 358 * If don't have a local address for this socket yet, 359 * then pick one. 360 */ 361 int 362 in_pcbconnect(inp, nam) 363 register struct inpcb *inp; 364 struct mbuf *nam; 365 { 366 struct sockaddr_in *ifaddr; 367 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 368 int error; 369 370 /* 371 * Call inner routine, to assign local interface address. 372 */ 373 if (error = in_pcbladdr(inp, nam, &ifaddr)) 374 return(error); 375 376 if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 377 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 378 inp->inp_lport) != NULL) 379 return (EADDRINUSE); 380 if (inp->inp_laddr.s_addr == INADDR_ANY) { 381 if (inp->inp_lport == 0) 382 (void)in_pcbbind(inp, (struct mbuf *)0); 383 inp->inp_laddr = ifaddr->sin_addr; 384 } 385 inp->inp_faddr = sin->sin_addr; 386 inp->inp_fport = sin->sin_port; 387 in_pcbrehash(inp); 388 return (0); 389 } 390 391 void 392 in_pcbdisconnect(inp) 393 struct inpcb *inp; 394 { 395 396 inp->inp_faddr.s_addr = INADDR_ANY; 397 inp->inp_fport = 0; 398 in_pcbrehash(inp); 399 if (inp->inp_socket->so_state & SS_NOFDREF) 400 in_pcbdetach(inp); 401 } 402 403 void 404 in_pcbdetach(inp) 405 struct inpcb *inp; 406 { 407 struct socket *so = inp->inp_socket; 408 int s; 409 410 so->so_pcb = 0; 411 sofree(so); 412 if (inp->inp_options) 413 (void)m_free(inp->inp_options); 414 if (inp->inp_route.ro_rt) 415 rtfree(inp->inp_route.ro_rt); 416 ip_freemoptions(inp->inp_moptions); 417 s = splnet(); 418 LIST_REMOVE(inp, inp_hash); 419 LIST_REMOVE(inp, inp_list); 420 splx(s); 421 FREE(inp, M_PCB); 422 } 423 424 void 425 in_setsockaddr(inp, nam) 426 register struct inpcb *inp; 427 struct mbuf *nam; 428 { 429 register struct sockaddr_in *sin; 430 431 nam->m_len = sizeof (*sin); 432 sin = mtod(nam, struct sockaddr_in *); 433 bzero((caddr_t)sin, sizeof (*sin)); 434 sin->sin_family = AF_INET; 435 sin->sin_len = sizeof(*sin); 436 sin->sin_port = inp->inp_lport; 437 sin->sin_addr = inp->inp_laddr; 438 } 439 440 void 441 in_setpeeraddr(inp, nam) 442 struct inpcb *inp; 443 struct mbuf *nam; 444 { 445 register struct sockaddr_in *sin; 446 447 nam->m_len = sizeof (*sin); 448 sin = mtod(nam, struct sockaddr_in *); 449 bzero((caddr_t)sin, sizeof (*sin)); 450 sin->sin_family = AF_INET; 451 sin->sin_len = sizeof(*sin); 452 sin->sin_port = inp->inp_fport; 453 sin->sin_addr = inp->inp_faddr; 454 } 455 456 /* 457 * Pass some notification to all connections of a protocol 458 * associated with address dst. The local address and/or port numbers 459 * may be specified to limit the search. The "usual action" will be 460 * taken, depending on the ctlinput cmd. The caller must filter any 461 * cmds that are uninteresting (e.g., no error in the map). 462 * Call the protocol specific routine (if any) to report 463 * any errors for each matching socket. 464 * 465 * Must be called at splnet. 466 */ 467 void 468 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 469 struct inpcbhead *head; 470 struct sockaddr *dst; 471 u_int fport_arg, lport_arg; 472 struct in_addr laddr; 473 int cmd; 474 void (*notify) __P((struct inpcb *, int)); 475 { 476 register struct inpcb *inp, *oinp; 477 struct in_addr faddr; 478 u_short fport = fport_arg, lport = lport_arg; 479 int errno, s; 480 481 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 482 return; 483 faddr = ((struct sockaddr_in *)dst)->sin_addr; 484 if (faddr.s_addr == INADDR_ANY) 485 return; 486 487 /* 488 * Redirects go to all references to the destination, 489 * and use in_rtchange to invalidate the route cache. 490 * Dead host indications: notify all references to the destination. 491 * Otherwise, if we have knowledge of the local port and address, 492 * deliver only to that socket. 493 */ 494 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 495 fport = 0; 496 lport = 0; 497 laddr.s_addr = 0; 498 if (cmd != PRC_HOSTDEAD) 499 notify = in_rtchange; 500 } 501 errno = inetctlerrmap[cmd]; 502 s = splnet(); 503 for (inp = head->lh_first; inp != NULL;) { 504 if (inp->inp_faddr.s_addr != faddr.s_addr || 505 inp->inp_socket == 0 || 506 (lport && inp->inp_lport != lport) || 507 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 508 (fport && inp->inp_fport != fport)) { 509 inp = inp->inp_list.le_next; 510 continue; 511 } 512 oinp = inp; 513 inp = inp->inp_list.le_next; 514 if (notify) 515 (*notify)(oinp, errno); 516 } 517 splx(s); 518 } 519 520 /* 521 * Check for alternatives when higher level complains 522 * about service problems. For now, invalidate cached 523 * routing information. If the route was created dynamically 524 * (by a redirect), time to try a default gateway again. 525 */ 526 void 527 in_losing(inp) 528 struct inpcb *inp; 529 { 530 register struct rtentry *rt; 531 struct rt_addrinfo info; 532 533 if ((rt = inp->inp_route.ro_rt)) { 534 inp->inp_route.ro_rt = 0; 535 bzero((caddr_t)&info, sizeof(info)); 536 info.rti_info[RTAX_DST] = 537 (struct sockaddr *)&inp->inp_route.ro_dst; 538 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 539 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 540 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 541 if (rt->rt_flags & RTF_DYNAMIC) 542 (void) rtrequest(RTM_DELETE, rt_key(rt), 543 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 544 (struct rtentry **)0); 545 else 546 /* 547 * A new route can be allocated 548 * the next time output is attempted. 549 */ 550 rtfree(rt); 551 } 552 } 553 554 /* 555 * After a routing change, flush old routing 556 * and allocate a (hopefully) better one. 557 */ 558 static void 559 in_rtchange(inp, errno) 560 register struct inpcb *inp; 561 int errno; 562 { 563 if (inp->inp_route.ro_rt) { 564 rtfree(inp->inp_route.ro_rt); 565 inp->inp_route.ro_rt = 0; 566 /* 567 * A new route can be allocated the next time 568 * output is attempted. 569 */ 570 } 571 } 572 573 struct inpcb * 574 in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) 575 struct inpcbhead *head; 576 struct in_addr faddr, laddr; 577 u_int fport_arg, lport_arg; 578 int flags; 579 { 580 register struct inpcb *inp, *match = NULL; 581 int matchwild = 3, wildcard; 582 u_short fport = fport_arg, lport = lport_arg; 583 int s; 584 585 s = splnet(); 586 587 for (inp = head->lh_first; inp != NULL; inp = inp->inp_list.le_next) { 588 if (inp->inp_lport != lport) 589 continue; 590 wildcard = 0; 591 if (inp->inp_faddr.s_addr != INADDR_ANY) { 592 if (faddr.s_addr == INADDR_ANY) 593 wildcard++; 594 else if (inp->inp_faddr.s_addr != faddr.s_addr || 595 inp->inp_fport != fport) 596 continue; 597 } else { 598 if (faddr.s_addr != INADDR_ANY) 599 wildcard++; 600 } 601 if (inp->inp_laddr.s_addr != INADDR_ANY) { 602 if (laddr.s_addr == INADDR_ANY) 603 wildcard++; 604 else if (inp->inp_laddr.s_addr != laddr.s_addr) 605 continue; 606 } else { 607 if (laddr.s_addr != INADDR_ANY) 608 wildcard++; 609 } 610 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 611 continue; 612 if (wildcard < matchwild) { 613 match = inp; 614 matchwild = wildcard; 615 if (matchwild == 0) { 616 break; 617 } 618 } 619 } 620 splx(s); 621 return (match); 622 } 623 624 /* 625 * Lookup PCB in hash list. 626 */ 627 struct inpcb * 628 in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg) 629 struct inpcbinfo *pcbinfo; 630 struct in_addr faddr, laddr; 631 u_int fport_arg, lport_arg; 632 { 633 struct inpcbhead *head; 634 register struct inpcb *inp; 635 u_short fport = fport_arg, lport = lport_arg; 636 int s; 637 638 s = splnet(); 639 /* 640 * First look for an exact match. 641 */ 642 head = &pcbinfo->hashbase[(faddr.s_addr + lport + fport) % pcbinfo->hashsize]; 643 644 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 645 if (inp->inp_faddr.s_addr != faddr.s_addr || 646 inp->inp_fport != fport || 647 inp->inp_lport != lport || 648 inp->inp_laddr.s_addr != laddr.s_addr) 649 continue; 650 /* 651 * Move PCB to head of this hash chain so that it can be 652 * found more quickly in the future. 653 */ 654 if (inp != head->lh_first) { 655 LIST_REMOVE(inp, inp_hash); 656 LIST_INSERT_HEAD(head, inp, inp_hash); 657 } 658 break; 659 } 660 splx(s); 661 return (inp); 662 } 663 664 /* 665 * Insert PCB into hash chain. Must be called at splnet. 666 */ 667 static void 668 in_pcbinshash(inp) 669 struct inpcb *inp; 670 { 671 struct inpcbhead *head; 672 673 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr + 674 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize]; 675 676 LIST_INSERT_HEAD(head, inp, inp_hash); 677 } 678 679 void 680 in_pcbrehash(inp) 681 struct inpcb *inp; 682 { 683 struct inpcbhead *head; 684 int s; 685 686 s = splnet(); 687 LIST_REMOVE(inp, inp_hash); 688 689 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr + 690 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize]; 691 692 LIST_INSERT_HEAD(head, inp, inp_hash); 693 splx(s); 694 } 695