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.32 1997/05/19 00:18:30 tegge 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, p) 116 struct socket *so; 117 struct inpcbinfo *pcbinfo; 118 struct proc *p; 119 { 120 register struct inpcb *inp; 121 int s; 122 123 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, 124 p ? M_WAITOK : M_NOWAIT); 125 if (inp == NULL) 126 return (ENOBUFS); 127 bzero((caddr_t)inp, sizeof(*inp)); 128 inp->inp_pcbinfo = pcbinfo; 129 inp->inp_socket = so; 130 s = splnet(); 131 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); 132 in_pcbinshash(inp); 133 splx(s); 134 so->so_pcb = (caddr_t)inp; 135 return (0); 136 } 137 138 int 139 in_pcbbind(inp, nam, p) 140 register struct inpcb *inp; 141 struct mbuf *nam; 142 struct proc *p; 143 { 144 register struct socket *so = inp->inp_socket; 145 unsigned short *lastport; 146 struct sockaddr_in *sin; 147 u_short lport = 0; 148 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 149 int error; 150 151 if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ 152 return (EADDRNOTAVAIL); 153 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 154 return (EINVAL); 155 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 156 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 157 (so->so_options & SO_ACCEPTCONN) == 0)) 158 wild = 1; 159 if (nam) { 160 sin = mtod(nam, struct sockaddr_in *); 161 if (nam->m_len != sizeof (*sin)) 162 return (EINVAL); 163 #ifdef notdef 164 /* 165 * We should check the family, but old programs 166 * incorrectly fail to initialize it. 167 */ 168 if (sin->sin_family != AF_INET) 169 return (EAFNOSUPPORT); 170 #endif 171 lport = sin->sin_port; 172 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 173 /* 174 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 175 * allow complete duplication of binding if 176 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 177 * and a multicast address is bound on both 178 * new and duplicated sockets. 179 */ 180 if (so->so_options & SO_REUSEADDR) 181 reuseport = SO_REUSEADDR|SO_REUSEPORT; 182 } else if (sin->sin_addr.s_addr != INADDR_ANY) { 183 sin->sin_port = 0; /* yech... */ 184 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 185 return (EADDRNOTAVAIL); 186 } 187 if (lport) { 188 struct inpcb *t; 189 190 /* GROSS */ 191 if (ntohs(lport) < IPPORT_RESERVED && 192 (error = suser(p->p_ucred, &p->p_acflag))) 193 return (EACCES); 194 t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, 195 sin->sin_addr, lport, wild); 196 if (t && (reuseport & t->inp_socket->so_options) == 0) 197 return (EADDRINUSE); 198 } 199 inp->inp_laddr = sin->sin_addr; 200 } 201 if (lport == 0) { 202 ushort first, last; 203 int count; 204 205 inp->inp_flags |= INP_ANONPORT; 206 207 if (inp->inp_flags & INP_HIGHPORT) { 208 first = ipport_hifirstauto; /* sysctl */ 209 last = ipport_hilastauto; 210 lastport = &inp->inp_pcbinfo->lasthi; 211 } else if (inp->inp_flags & INP_LOWPORT) { 212 if (error = suser(p->p_ucred, &p->p_acflag)) 213 return error; 214 first = ipport_lowfirstauto; /* 1023 */ 215 last = ipport_lowlastauto; /* 600 */ 216 lastport = &inp->inp_pcbinfo->lastlow; 217 } else { 218 first = ipport_firstauto; /* sysctl */ 219 last = ipport_lastauto; 220 lastport = &inp->inp_pcbinfo->lastport; 221 } 222 /* 223 * Simple check to ensure all ports are not used up causing 224 * a deadlock here. 225 * 226 * We split the two cases (up and down) so that the direction 227 * is not being tested on each round of the loop. 228 */ 229 if (first > last) { 230 /* 231 * counting down 232 */ 233 count = first - last; 234 235 do { 236 if (count-- <= 0) /* completely used? */ 237 return (EADDRNOTAVAIL); 238 --*lastport; 239 if (*lastport > first || *lastport < last) 240 *lastport = first; 241 lport = htons(*lastport); 242 } while (in_pcblookup(inp->inp_pcbinfo, 243 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 244 } else { 245 /* 246 * counting up 247 */ 248 count = last - first; 249 250 do { 251 if (count-- <= 0) /* completely used? */ 252 return (EADDRNOTAVAIL); 253 ++*lastport; 254 if (*lastport < first || *lastport > last) 255 *lastport = first; 256 lport = htons(*lastport); 257 } while (in_pcblookup(inp->inp_pcbinfo, 258 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 259 } 260 } 261 inp->inp_lport = lport; 262 in_pcbrehash(inp); 263 return (0); 264 } 265 266 /* 267 * Transform old in_pcbconnect() into an inner subroutine for new 268 * in_pcbconnect(): Do some validity-checking on the remote 269 * address (in mbuf 'nam') and then determine local host address 270 * (i.e., which interface) to use to access that remote host. 271 * 272 * This preserves definition of in_pcbconnect(), while supporting a 273 * slightly different version for T/TCP. (This is more than 274 * a bit of a kludge, but cleaning up the internal interfaces would 275 * have forced minor changes in every protocol). 276 */ 277 278 int 279 in_pcbladdr(inp, nam, plocal_sin) 280 register struct inpcb *inp; 281 struct mbuf *nam; 282 struct sockaddr_in **plocal_sin; 283 { 284 struct in_ifaddr *ia; 285 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 286 287 if (nam->m_len != sizeof (*sin)) 288 return (EINVAL); 289 if (sin->sin_family != AF_INET) 290 return (EAFNOSUPPORT); 291 if (sin->sin_port == 0) 292 return (EADDRNOTAVAIL); 293 if (!TAILQ_EMPTY(&in_ifaddrhead)) { 294 /* 295 * If the destination address is INADDR_ANY, 296 * use the primary local address. 297 * If the supplied address is INADDR_BROADCAST, 298 * and the primary interface supports broadcast, 299 * choose the broadcast address for that interface. 300 */ 301 #define satosin(sa) ((struct sockaddr_in *)(sa)) 302 #define sintosa(sin) ((struct sockaddr *)(sin)) 303 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 304 if (sin->sin_addr.s_addr == INADDR_ANY) 305 sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; 306 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 307 (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 308 sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; 309 } 310 if (inp->inp_laddr.s_addr == INADDR_ANY) { 311 register struct route *ro; 312 313 ia = (struct in_ifaddr *)0; 314 /* 315 * If route is known or can be allocated now, 316 * our src addr is taken from the i/f, else punt. 317 */ 318 ro = &inp->inp_route; 319 if (ro->ro_rt && 320 (satosin(&ro->ro_dst)->sin_addr.s_addr != 321 sin->sin_addr.s_addr || 322 inp->inp_socket->so_options & SO_DONTROUTE)) { 323 RTFREE(ro->ro_rt); 324 ro->ro_rt = (struct rtentry *)0; 325 } 326 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 327 (ro->ro_rt == (struct rtentry *)0 || 328 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 329 /* No route yet, so try to acquire one */ 330 ro->ro_dst.sa_family = AF_INET; 331 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 332 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 333 sin->sin_addr; 334 rtalloc(ro); 335 } 336 /* 337 * If we found a route, use the address 338 * corresponding to the outgoing interface 339 * unless it is the loopback (in case a route 340 * to our address on another net goes to loopback). 341 */ 342 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 343 ia = ifatoia(ro->ro_rt->rt_ifa); 344 if (ia == 0) { 345 u_short fport = sin->sin_port; 346 347 sin->sin_port = 0; 348 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 349 if (ia == 0) 350 ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 351 sin->sin_port = fport; 352 if (ia == 0) 353 ia = in_ifaddrhead.tqh_first; 354 if (ia == 0) 355 return (EADDRNOTAVAIL); 356 } 357 /* 358 * If the destination address is multicast and an outgoing 359 * interface has been set as a multicast option, use the 360 * address of that interface as our source address. 361 */ 362 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 363 inp->inp_moptions != NULL) { 364 struct ip_moptions *imo; 365 struct ifnet *ifp; 366 367 imo = inp->inp_moptions; 368 if (imo->imo_multicast_ifp != NULL) { 369 ifp = imo->imo_multicast_ifp; 370 for (ia = in_ifaddrhead.tqh_first; ia; 371 ia = ia->ia_link.tqe_next) 372 if (ia->ia_ifp == ifp) 373 break; 374 if (ia == 0) 375 return (EADDRNOTAVAIL); 376 } 377 } 378 /* 379 * Don't do pcblookup call here; return interface in plocal_sin 380 * and exit to caller, that will do the lookup. 381 */ 382 *plocal_sin = &ia->ia_addr; 383 384 } 385 return(0); 386 } 387 388 /* 389 * Outer subroutine: 390 * Connect from a socket to a specified address. 391 * Both address and port must be specified in argument sin. 392 * If don't have a local address for this socket yet, 393 * then pick one. 394 */ 395 int 396 in_pcbconnect(inp, nam, p) 397 register struct inpcb *inp; 398 struct mbuf *nam; 399 struct proc *p; 400 { 401 struct sockaddr_in *ifaddr; 402 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 403 int error; 404 405 /* 406 * Call inner routine, to assign local interface address. 407 */ 408 if (error = in_pcbladdr(inp, nam, &ifaddr)) 409 return(error); 410 411 if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, 412 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 413 inp->inp_lport, 0) != NULL) 414 return (EADDRINUSE); 415 if (inp->inp_laddr.s_addr == INADDR_ANY) { 416 if (inp->inp_lport == 0) 417 (void)in_pcbbind(inp, (struct mbuf *)0, p); 418 inp->inp_laddr = ifaddr->sin_addr; 419 } 420 inp->inp_faddr = sin->sin_addr; 421 inp->inp_fport = sin->sin_port; 422 in_pcbrehash(inp); 423 return (0); 424 } 425 426 void 427 in_pcbdisconnect(inp) 428 struct inpcb *inp; 429 { 430 431 inp->inp_faddr.s_addr = INADDR_ANY; 432 inp->inp_fport = 0; 433 in_pcbrehash(inp); 434 if (inp->inp_socket->so_state & SS_NOFDREF) 435 in_pcbdetach(inp); 436 } 437 438 void 439 in_pcbdetach(inp) 440 struct inpcb *inp; 441 { 442 struct socket *so = inp->inp_socket; 443 int s; 444 445 so->so_pcb = 0; 446 sofree(so); 447 if (inp->inp_options) 448 (void)m_free(inp->inp_options); 449 if (inp->inp_route.ro_rt) 450 rtfree(inp->inp_route.ro_rt); 451 ip_freemoptions(inp->inp_moptions); 452 s = splnet(); 453 LIST_REMOVE(inp, inp_hash); 454 LIST_REMOVE(inp, inp_list); 455 splx(s); 456 FREE(inp, M_PCB); 457 } 458 459 /* 460 * The calling convention of in_setsockaddr() and in_setpeeraddr() was 461 * modified to match the pru_sockaddr() and pru_peeraddr() entry points 462 * in struct pr_usrreqs, so that protocols can just reference then directly 463 * without the need for a wrapper function. The socket must have a valid 464 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 465 * except through a kernel programming error, so it is acceptable to panic 466 * (or in this case trap) if the PCB is invalid. 467 */ 468 int 469 in_setsockaddr(so, nam) 470 struct socket *so; 471 struct mbuf *nam; 472 { 473 int s; 474 register struct inpcb *inp; 475 register struct sockaddr_in *sin; 476 477 s = splnet(); 478 inp = sotoinpcb(so); 479 if (!inp) { 480 splx(s); 481 return EINVAL; 482 } 483 nam->m_len = sizeof (*sin); 484 sin = mtod(nam, struct sockaddr_in *); 485 bzero((caddr_t)sin, sizeof (*sin)); 486 sin->sin_family = AF_INET; 487 sin->sin_len = sizeof(*sin); 488 sin->sin_port = inp->inp_lport; 489 sin->sin_addr = inp->inp_laddr; 490 splx(s); 491 return 0; 492 } 493 494 int 495 in_setpeeraddr(so, nam) 496 struct socket *so; 497 struct mbuf *nam; 498 { 499 int s; 500 struct inpcb *inp; 501 register struct sockaddr_in *sin; 502 503 s = splnet(); 504 inp = sotoinpcb(so); 505 if (!inp) { 506 splx(s); 507 return EINVAL; 508 } 509 nam->m_len = sizeof (*sin); 510 sin = mtod(nam, struct sockaddr_in *); 511 bzero((caddr_t)sin, sizeof (*sin)); 512 sin->sin_family = AF_INET; 513 sin->sin_len = sizeof(*sin); 514 sin->sin_port = inp->inp_fport; 515 sin->sin_addr = inp->inp_faddr; 516 splx(s); 517 return 0; 518 } 519 520 /* 521 * Pass some notification to all connections of a protocol 522 * associated with address dst. The local address and/or port numbers 523 * may be specified to limit the search. The "usual action" will be 524 * taken, depending on the ctlinput cmd. The caller must filter any 525 * cmds that are uninteresting (e.g., no error in the map). 526 * Call the protocol specific routine (if any) to report 527 * any errors for each matching socket. 528 * 529 * Must be called at splnet. 530 */ 531 void 532 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) 533 struct inpcbhead *head; 534 struct sockaddr *dst; 535 u_int fport_arg, lport_arg; 536 struct in_addr laddr; 537 int cmd; 538 void (*notify) __P((struct inpcb *, int)); 539 { 540 register struct inpcb *inp, *oinp; 541 struct in_addr faddr; 542 u_short fport = fport_arg, lport = lport_arg; 543 int errno, s; 544 545 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 546 return; 547 faddr = ((struct sockaddr_in *)dst)->sin_addr; 548 if (faddr.s_addr == INADDR_ANY) 549 return; 550 551 /* 552 * Redirects go to all references to the destination, 553 * and use in_rtchange to invalidate the route cache. 554 * Dead host indications: notify all references to the destination. 555 * Otherwise, if we have knowledge of the local port and address, 556 * deliver only to that socket. 557 */ 558 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 559 fport = 0; 560 lport = 0; 561 laddr.s_addr = 0; 562 if (cmd != PRC_HOSTDEAD) 563 notify = in_rtchange; 564 } 565 errno = inetctlerrmap[cmd]; 566 s = splnet(); 567 for (inp = head->lh_first; inp != NULL;) { 568 if (inp->inp_faddr.s_addr != faddr.s_addr || 569 inp->inp_socket == 0 || 570 (lport && inp->inp_lport != lport) || 571 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 572 (fport && inp->inp_fport != fport)) { 573 inp = inp->inp_list.le_next; 574 continue; 575 } 576 oinp = inp; 577 inp = inp->inp_list.le_next; 578 if (notify) 579 (*notify)(oinp, errno); 580 } 581 splx(s); 582 } 583 584 /* 585 * Check for alternatives when higher level complains 586 * about service problems. For now, invalidate cached 587 * routing information. If the route was created dynamically 588 * (by a redirect), time to try a default gateway again. 589 */ 590 void 591 in_losing(inp) 592 struct inpcb *inp; 593 { 594 register struct rtentry *rt; 595 struct rt_addrinfo info; 596 597 if ((rt = inp->inp_route.ro_rt)) { 598 inp->inp_route.ro_rt = 0; 599 bzero((caddr_t)&info, sizeof(info)); 600 info.rti_info[RTAX_DST] = 601 (struct sockaddr *)&inp->inp_route.ro_dst; 602 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 603 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 604 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 605 if (rt->rt_flags & RTF_DYNAMIC) 606 (void) rtrequest(RTM_DELETE, rt_key(rt), 607 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 608 (struct rtentry **)0); 609 else 610 /* 611 * A new route can be allocated 612 * the next time output is attempted. 613 */ 614 rtfree(rt); 615 } 616 } 617 618 /* 619 * After a routing change, flush old routing 620 * and allocate a (hopefully) better one. 621 */ 622 static void 623 in_rtchange(inp, errno) 624 register struct inpcb *inp; 625 int errno; 626 { 627 if (inp->inp_route.ro_rt) { 628 rtfree(inp->inp_route.ro_rt); 629 inp->inp_route.ro_rt = 0; 630 /* 631 * A new route can be allocated the next time 632 * output is attempted. 633 */ 634 } 635 } 636 637 struct inpcb * 638 in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) 639 struct inpcbinfo *pcbinfo; 640 struct in_addr faddr, laddr; 641 u_int fport_arg, lport_arg; 642 int wild_okay; 643 { 644 register struct inpcb *inp, *match = NULL; 645 int matchwild = 3, wildcard; 646 u_short fport = fport_arg, lport = lport_arg; 647 int s; 648 649 s = splnet(); 650 651 for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { 652 if (inp->inp_lport != lport) 653 continue; 654 wildcard = 0; 655 if (inp->inp_faddr.s_addr != INADDR_ANY) { 656 if (faddr.s_addr == INADDR_ANY) 657 wildcard++; 658 else if (inp->inp_faddr.s_addr != faddr.s_addr || 659 inp->inp_fport != fport) 660 continue; 661 } else { 662 if (faddr.s_addr != INADDR_ANY) 663 wildcard++; 664 } 665 if (inp->inp_laddr.s_addr != INADDR_ANY) { 666 if (laddr.s_addr == INADDR_ANY) 667 wildcard++; 668 else if (inp->inp_laddr.s_addr != laddr.s_addr) 669 continue; 670 } else { 671 if (laddr.s_addr != INADDR_ANY) 672 wildcard++; 673 } 674 if (wildcard && wild_okay == 0) 675 continue; 676 if (wildcard < matchwild) { 677 match = inp; 678 matchwild = wildcard; 679 if (matchwild == 0) { 680 break; 681 } 682 } 683 } 684 splx(s); 685 return (match); 686 } 687 688 /* 689 * Lookup PCB in hash list. 690 */ 691 struct inpcb * 692 in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) 693 struct inpcbinfo *pcbinfo; 694 struct in_addr faddr, laddr; 695 u_int fport_arg, lport_arg; 696 int wildcard; 697 { 698 struct inpcbhead *head; 699 register struct inpcb *inp; 700 u_short fport = fport_arg, lport = lport_arg; 701 int s; 702 703 s = splnet(); 704 /* 705 * First look for an exact match. 706 */ 707 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 708 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 709 if (inp->inp_faddr.s_addr == faddr.s_addr && 710 inp->inp_laddr.s_addr == laddr.s_addr && 711 inp->inp_fport == fport && 712 inp->inp_lport == lport) 713 goto found; 714 } 715 if (wildcard) { 716 struct inpcb *local_wild = NULL; 717 718 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; 719 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 720 if (inp->inp_faddr.s_addr == INADDR_ANY && 721 inp->inp_fport == 0 && inp->inp_lport == lport) { 722 if (inp->inp_laddr.s_addr == laddr.s_addr) 723 goto found; 724 else if (inp->inp_laddr.s_addr == INADDR_ANY) 725 local_wild = inp; 726 } 727 } 728 if (local_wild != NULL) { 729 inp = local_wild; 730 goto found; 731 } 732 } 733 splx(s); 734 return (NULL); 735 736 found: 737 /* 738 * Move PCB to head of this hash chain so that it can be 739 * found more quickly in the future. 740 * XXX - this is a pessimization on machines with few 741 * concurrent connections. 742 */ 743 if (inp != head->lh_first) { 744 LIST_REMOVE(inp, inp_hash); 745 LIST_INSERT_HEAD(head, inp, inp_hash); 746 } 747 splx(s); 748 return (inp); 749 } 750 751 /* 752 * Insert PCB into hash chain. Must be called at splnet. 753 */ 754 static void 755 in_pcbinshash(inp) 756 struct inpcb *inp; 757 { 758 struct inpcbhead *head; 759 760 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 761 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 762 763 LIST_INSERT_HEAD(head, inp, inp_hash); 764 } 765 766 void 767 in_pcbrehash(inp) 768 struct inpcb *inp; 769 { 770 struct inpcbhead *head; 771 int s; 772 773 s = splnet(); 774 LIST_REMOVE(inp, inp_hash); 775 776 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, 777 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; 778 779 LIST_INSERT_HEAD(head, inp, inp_hash); 780 splx(s); 781 } 782