1 /* $NetBSD: in_pcb.c,v 1.50 1998/02/15 18:24:25 tls Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Public Access Networks Corporation ("Panix"). It was developed under 9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1982, 1986, 1991, 1993, 1995 42 * The Regents of the University of California. All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 73 */ 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/malloc.h> 78 #include <sys/mbuf.h> 79 #include <sys/protosw.h> 80 #include <sys/socket.h> 81 #include <sys/socketvar.h> 82 #include <sys/ioctl.h> 83 #include <sys/errno.h> 84 #include <sys/time.h> 85 #include <sys/proc.h> 86 87 #include <net/if.h> 88 #include <net/route.h> 89 90 #include <netinet/in.h> 91 #include <netinet/in_systm.h> 92 #include <netinet/ip.h> 93 #include <netinet/in_pcb.h> 94 #include <netinet/in_var.h> 95 #include <netinet/ip_var.h> 96 97 struct in_addr zeroin_addr; 98 99 #define INPCBHASH_BIND(table, laddr, lport) \ 100 &(table)->inpt_bindhashtbl[ \ 101 ((ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_bindhash] 102 #define INPCBHASH_CONNECT(table, faddr, fport, laddr, lport) \ 103 &(table)->inpt_connecthashtbl[ \ 104 ((ntohl((faddr).s_addr) + ntohs(fport)) + \ 105 (ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_connecthash] 106 107 struct inpcb * 108 in_pcblookup_port __P((struct inpcbtable *, 109 struct in_addr, u_int, int)); 110 111 int anonportmin = IPPORT_ANONMIN; 112 int anonportmax = IPPORT_ANONMAX; 113 114 void 115 in_pcbinit(table, bindhashsize, connecthashsize) 116 struct inpcbtable *table; 117 int bindhashsize, connecthashsize; 118 { 119 120 CIRCLEQ_INIT(&table->inpt_queue); 121 table->inpt_bindhashtbl = 122 hashinit(bindhashsize, M_PCB, M_WAITOK, &table->inpt_bindhash); 123 table->inpt_connecthashtbl = 124 hashinit(connecthashsize, M_PCB, M_WAITOK, &table->inpt_connecthash); 125 table->inpt_lastlow = IPPORT_RESERVEDMAX; 126 table->inpt_lastport = (u_int16_t)anonportmax; 127 } 128 129 int 130 in_pcballoc(so, v) 131 struct socket *so; 132 void *v; 133 { 134 struct inpcbtable *table = v; 135 register struct inpcb *inp; 136 int s; 137 138 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK); 139 if (inp == NULL) 140 return (ENOBUFS); 141 bzero((caddr_t)inp, sizeof(*inp)); 142 inp->inp_table = table; 143 inp->inp_socket = so; 144 inp->inp_errormtu = -1; 145 so->so_pcb = inp; 146 s = splnet(); 147 CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue); 148 in_pcbstate(inp, INP_ATTACHED); 149 splx(s); 150 return (0); 151 } 152 153 int 154 in_pcbbind(v, nam, p) 155 void *v; 156 struct mbuf *nam; 157 struct proc *p; 158 { 159 register struct inpcb *inp = v; 160 register struct socket *so = inp->inp_socket; 161 register struct inpcbtable *table = inp->inp_table; 162 register struct sockaddr_in *sin; 163 u_int16_t lport = 0; 164 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 165 #ifndef IPNOPRIVPORTS 166 int error; 167 #endif 168 169 if (in_ifaddr.tqh_first == 0) 170 return (EADDRNOTAVAIL); 171 if (inp->inp_lport || !in_nullhost(inp->inp_laddr)) 172 return (EINVAL); 173 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 174 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 175 (so->so_options & SO_ACCEPTCONN) == 0)) 176 wild = INPLOOKUP_WILDCARD; 177 if (nam == 0) 178 goto noname; 179 sin = mtod(nam, struct sockaddr_in *); 180 if (nam->m_len != sizeof (*sin)) 181 return (EINVAL); 182 #ifdef notdef 183 /* 184 * We should check the family, but old programs 185 * incorrectly fail to initialize it. 186 */ 187 if (sin->sin_family != AF_INET) 188 return (EAFNOSUPPORT); 189 #endif 190 lport = sin->sin_port; 191 if (IN_MULTICAST(sin->sin_addr.s_addr)) { 192 /* 193 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 194 * allow complete duplication of binding if 195 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 196 * and a multicast address is bound on both 197 * new and duplicated sockets. 198 */ 199 if (so->so_options & SO_REUSEADDR) 200 reuseport = SO_REUSEADDR|SO_REUSEPORT; 201 } else if (!in_nullhost(sin->sin_addr)) { 202 sin->sin_port = 0; /* yech... */ 203 if (ifa_ifwithaddr(sintosa(sin)) == 0) 204 return (EADDRNOTAVAIL); 205 } 206 if (lport) { 207 struct inpcb *t; 208 #ifndef IPNOPRIVPORTS 209 /* GROSS */ 210 if (ntohs(lport) < IPPORT_RESERVED && 211 (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))) 212 return (EACCES); 213 #endif 214 t = in_pcblookup_port(table, sin->sin_addr, lport, wild); 215 if (t && (reuseport & t->inp_socket->so_options) == 0) 216 return (EADDRINUSE); 217 } 218 inp->inp_laddr = sin->sin_addr; 219 220 noname: 221 if (lport == 0) { 222 int cnt; 223 u_int16_t min, max; 224 u_int16_t *lastport; 225 226 if (inp->inp_flags & INP_LOWPORT) { 227 #ifndef IPNOPRIVPORTS 228 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) 229 return (EACCES); 230 #endif 231 min = IPPORT_RESERVEDMIN; 232 max = IPPORT_RESERVEDMAX; 233 lastport = &table->inpt_lastlow; 234 } else { 235 min = anonportmin; 236 max = anonportmax; 237 lastport = &table->inpt_lastport; 238 } 239 if (min > max) { /* sanity check */ 240 u_int16_t swp; 241 242 swp = min; 243 min = max; 244 max = swp; 245 } 246 247 lport = *lastport - 1; 248 for (cnt = max - min + 1; cnt; cnt--, lport--) { 249 if (lport < min || lport > max) 250 lport = max; 251 if (!in_pcblookup_port(table, inp->inp_laddr, 252 htons(lport), wild)) 253 goto found; 254 } 255 if (!in_nullhost(inp->inp_laddr)) 256 inp->inp_laddr.s_addr = INADDR_ANY; 257 return (EAGAIN); 258 found: 259 inp->inp_flags |= INP_ANONPORT; 260 *lastport = lport; 261 lport = htons(lport); 262 } 263 inp->inp_lport = lport; 264 in_pcbstate(inp, INP_BOUND); 265 return (0); 266 } 267 268 /* 269 * Connect from a socket to a specified address. 270 * Both address and port must be specified in argument sin. 271 * If don't have a local address for this socket yet, 272 * then pick one. 273 */ 274 int 275 in_pcbconnect(v, nam) 276 register void *v; 277 struct mbuf *nam; 278 { 279 register struct inpcb *inp = v; 280 struct in_ifaddr *ia; 281 struct sockaddr_in *ifaddr = NULL; 282 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 283 int error; 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 (in_ifaddr.tqh_first != 0) { 292 /* 293 * If the destination address is INADDR_ANY, 294 * use any local address (likely loopback). 295 * If the supplied address is INADDR_BROADCAST, 296 * use the broadcast address of an interface 297 * which supports broadcast. (loopback does not) 298 */ 299 300 if (in_nullhost(sin->sin_addr)) 301 sin->sin_addr = in_ifaddr.tqh_first->ia_broadaddr.sin_addr; 302 else if (sin->sin_addr.s_addr == INADDR_BROADCAST) 303 for (ia = in_ifaddr.tqh_first; ia != NULL; 304 ia = ia->ia_list.tqe_next) 305 if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 306 sin->sin_addr = ia->ia_broadaddr.sin_addr; 307 break; 308 } 309 } 310 /* 311 * If we haven't bound which network number to use as ours, 312 * we will use the number of the outgoing interface. 313 * This depends on having done a routing lookup, which 314 * we will probably have to do anyway, so we might 315 * as well do it now. On the other hand if we are 316 * sending to multiple destinations we may have already 317 * done the lookup, so see if we can use the route 318 * from before. In any case, we only 319 * chose a port number once, even if sending to multiple 320 * destinations. 321 */ 322 if (in_nullhost(inp->inp_laddr)) { 323 register struct route *ro; 324 325 ia = (struct in_ifaddr *)0; 326 /* 327 * If route is known or can be allocated now, 328 * our src addr is taken from the i/f, else punt. 329 */ 330 ro = &inp->inp_route; 331 if (ro->ro_rt && 332 (!in_hosteq(satosin(&ro->ro_dst)->sin_addr, 333 sin->sin_addr) || 334 inp->inp_socket->so_options & SO_DONTROUTE)) { 335 RTFREE(ro->ro_rt); 336 ro->ro_rt = (struct rtentry *)0; 337 } 338 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 339 (ro->ro_rt == (struct rtentry *)0 || 340 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 341 /* No route yet, so try to acquire one */ 342 ro->ro_dst.sa_family = AF_INET; 343 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 344 satosin(&ro->ro_dst)->sin_addr = sin->sin_addr; 345 rtalloc(ro); 346 } 347 /* 348 * If we found a route, use the address 349 * corresponding to the outgoing interface 350 * unless it is the loopback (in case a route 351 * to our address on another net goes to loopback). 352 * 353 * XXX Is this still true? Do we care? 354 */ 355 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 356 ia = ifatoia(ro->ro_rt->rt_ifa); 357 if (ia == 0) { 358 u_int16_t fport = sin->sin_port; 359 360 sin->sin_port = 0; 361 ia = ifatoia(ifa_ifwithladdr(sintosa(sin))); 362 sin->sin_port = fport; 363 if (ia == 0) 364 /* Find 1st non-loopback AF_INET address */ 365 for (ia = in_ifaddr.tqh_first ; ia != NULL ; 366 ia = ia->ia_list.tqe_next) 367 if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK)) 368 break; 369 if (ia == 0) 370 return (EADDRNOTAVAIL); 371 } 372 /* 373 * If the destination address is multicast and an outgoing 374 * interface has been set as a multicast option, use the 375 * address of that interface as our source address. 376 */ 377 if (IN_MULTICAST(sin->sin_addr.s_addr) && 378 inp->inp_moptions != NULL) { 379 struct ip_moptions *imo; 380 struct ifnet *ifp; 381 382 imo = inp->inp_moptions; 383 if (imo->imo_multicast_ifp != NULL) { 384 ifp = imo->imo_multicast_ifp; 385 IFP_TO_IA(ifp, ia); /* XXX */ 386 if (ia == 0) 387 return (EADDRNOTAVAIL); 388 } 389 } 390 ifaddr = satosin(&ia->ia_addr); 391 } 392 if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port, 393 !in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr, 394 inp->inp_lport) != 0) 395 return (EADDRINUSE); 396 if (in_nullhost(inp->inp_laddr)) { 397 if (inp->inp_lport == 0) { 398 error = in_pcbbind(inp, (struct mbuf *)0, 399 (struct proc *)0); 400 /* 401 * This used to ignore the return value 402 * completely, but we need to check for 403 * ephemeral port shortage. 404 * XXX Should we check for other errors, too? 405 */ 406 if (error == EAGAIN) 407 return (error); 408 } 409 inp->inp_laddr = ifaddr->sin_addr; 410 } 411 inp->inp_faddr = sin->sin_addr; 412 inp->inp_fport = sin->sin_port; 413 in_pcbstate(inp, INP_CONNECTED); 414 return (0); 415 } 416 417 void 418 in_pcbdisconnect(v) 419 void *v; 420 { 421 struct inpcb *inp = v; 422 423 inp->inp_faddr = zeroin_addr; 424 inp->inp_fport = 0; 425 in_pcbstate(inp, INP_BOUND); 426 if (inp->inp_socket->so_state & SS_NOFDREF) 427 in_pcbdetach(inp); 428 } 429 430 void 431 in_pcbdetach(v) 432 void *v; 433 { 434 struct inpcb *inp = v; 435 struct socket *so = inp->inp_socket; 436 int s; 437 438 so->so_pcb = 0; 439 sofree(so); 440 if (inp->inp_options) 441 (void)m_free(inp->inp_options); 442 if (inp->inp_route.ro_rt) 443 rtfree(inp->inp_route.ro_rt); 444 ip_freemoptions(inp->inp_moptions); 445 s = splnet(); 446 in_pcbstate(inp, INP_ATTACHED); 447 CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue); 448 splx(s); 449 FREE(inp, M_PCB); 450 } 451 452 void 453 in_setsockaddr(inp, nam) 454 register struct inpcb *inp; 455 struct mbuf *nam; 456 { 457 register struct sockaddr_in *sin; 458 459 nam->m_len = sizeof (*sin); 460 sin = mtod(nam, struct sockaddr_in *); 461 bzero((caddr_t)sin, sizeof (*sin)); 462 sin->sin_family = AF_INET; 463 sin->sin_len = sizeof(*sin); 464 sin->sin_port = inp->inp_lport; 465 sin->sin_addr = inp->inp_laddr; 466 } 467 468 void 469 in_setpeeraddr(inp, nam) 470 struct inpcb *inp; 471 struct mbuf *nam; 472 { 473 register struct sockaddr_in *sin; 474 475 nam->m_len = sizeof (*sin); 476 sin = mtod(nam, struct sockaddr_in *); 477 bzero((caddr_t)sin, sizeof (*sin)); 478 sin->sin_family = AF_INET; 479 sin->sin_len = sizeof(*sin); 480 sin->sin_port = inp->inp_fport; 481 sin->sin_addr = inp->inp_faddr; 482 } 483 484 /* 485 * Pass some notification to all connections of a protocol 486 * associated with address dst. The local address and/or port numbers 487 * may be specified to limit the search. The "usual action" will be 488 * taken, depending on the ctlinput cmd. The caller must filter any 489 * cmds that are uninteresting (e.g., no error in the map). 490 * Call the protocol specific routine (if any) to report 491 * any errors for each matching socket. 492 * 493 * Must be called at splsoftnet. 494 */ 495 int 496 in_pcbnotify(table, faddr, fport_arg, laddr, lport_arg, errno, notify) 497 struct inpcbtable *table; 498 struct in_addr faddr, laddr; 499 u_int fport_arg, lport_arg; 500 int errno; 501 void (*notify) __P((struct inpcb *, int)); 502 { 503 struct inpcbhead *head; 504 register struct inpcb *inp, *ninp; 505 u_int16_t fport = fport_arg, lport = lport_arg; 506 int nmatch; 507 508 if (in_nullhost(faddr) || notify == 0) 509 return (0); 510 511 nmatch = 0; 512 head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport); 513 for (inp = head->lh_first; inp != NULL; inp = ninp) { 514 ninp = inp->inp_hash.le_next; 515 if (in_hosteq(inp->inp_faddr, faddr) && 516 inp->inp_fport == fport && 517 inp->inp_lport == lport && 518 in_hosteq(inp->inp_laddr, laddr)) { 519 (*notify)(inp, errno); 520 nmatch++; 521 } 522 } 523 return (nmatch); 524 } 525 526 void 527 in_pcbnotifyall(table, faddr, errno, notify) 528 struct inpcbtable *table; 529 struct in_addr faddr; 530 int errno; 531 void (*notify) __P((struct inpcb *, int)); 532 { 533 register struct inpcb *inp, *ninp; 534 535 if (in_nullhost(faddr) || notify == 0) 536 return; 537 538 for (inp = table->inpt_queue.cqh_first; 539 inp != (struct inpcb *)&table->inpt_queue; 540 inp = ninp) { 541 ninp = inp->inp_queue.cqe_next; 542 if (in_hosteq(inp->inp_faddr, faddr)) 543 (*notify)(inp, errno); 544 } 545 } 546 547 /* 548 * Check for alternatives when higher level complains 549 * about service problems. For now, invalidate cached 550 * routing information. If the route was created dynamically 551 * (by a redirect), time to try a default gateway again. 552 */ 553 void 554 in_losing(inp) 555 struct inpcb *inp; 556 { 557 register struct rtentry *rt; 558 struct rt_addrinfo info; 559 560 if ((rt = inp->inp_route.ro_rt)) { 561 inp->inp_route.ro_rt = 0; 562 bzero((caddr_t)&info, sizeof(info)); 563 info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst; 564 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 565 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 566 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 567 if (rt->rt_flags & RTF_DYNAMIC) 568 (void) rtrequest(RTM_DELETE, rt_key(rt), 569 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 570 (struct rtentry **)0); 571 else 572 /* 573 * A new route can be allocated 574 * the next time output is attempted. 575 */ 576 rtfree(rt); 577 } 578 } 579 580 /* 581 * After a routing change, flush old routing 582 * and allocate a (hopefully) better one. 583 */ 584 void 585 in_rtchange(inp, errno) 586 register struct inpcb *inp; 587 int errno; 588 { 589 590 if (inp->inp_route.ro_rt) { 591 rtfree(inp->inp_route.ro_rt); 592 inp->inp_route.ro_rt = 0; 593 /* 594 * A new route can be allocated the next time 595 * output is attempted. 596 */ 597 } 598 /* XXX SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 599 } 600 601 struct inpcb * 602 in_pcblookup_port(table, laddr, lport_arg, flags) 603 struct inpcbtable *table; 604 struct in_addr laddr; 605 u_int lport_arg; 606 int flags; 607 { 608 register struct inpcb *inp, *match = 0; 609 int matchwild = 3, wildcard; 610 u_int16_t lport = lport_arg; 611 612 for (inp = table->inpt_queue.cqh_first; 613 inp != (struct inpcb *)&table->inpt_queue; 614 inp = inp->inp_queue.cqe_next) { 615 if (inp->inp_lport != lport) 616 continue; 617 wildcard = 0; 618 if (!in_nullhost(inp->inp_faddr)) 619 wildcard++; 620 if (in_nullhost(inp->inp_laddr)) { 621 if (!in_nullhost(laddr)) 622 wildcard++; 623 } else { 624 if (in_nullhost(laddr)) 625 wildcard++; 626 else { 627 if (!in_hosteq(inp->inp_laddr, laddr)) 628 continue; 629 } 630 } 631 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 632 continue; 633 if (wildcard < matchwild) { 634 match = inp; 635 matchwild = wildcard; 636 if (matchwild == 0) 637 break; 638 } 639 } 640 return (match); 641 } 642 643 #ifdef DIAGNOSTIC 644 int in_pcbnotifymiss = 0; 645 #endif 646 647 struct inpcb * 648 in_pcblookup_connect(table, faddr, fport_arg, laddr, lport_arg) 649 struct inpcbtable *table; 650 struct in_addr faddr, laddr; 651 u_int fport_arg, lport_arg; 652 { 653 struct inpcbhead *head; 654 register struct inpcb *inp; 655 u_int16_t fport = fport_arg, lport = lport_arg; 656 657 head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport); 658 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 659 if (in_hosteq(inp->inp_faddr, faddr) && 660 inp->inp_fport == fport && 661 inp->inp_lport == lport && 662 in_hosteq(inp->inp_laddr, laddr)) 663 goto out; 664 } 665 #ifdef DIAGNOSTIC 666 if (in_pcbnotifymiss) { 667 printf("in_pcblookup_connect: faddr=%08x fport=%d laddr=%08x lport=%d\n", 668 ntohl(faddr.s_addr), ntohs(fport), 669 ntohl(laddr.s_addr), ntohs(lport)); 670 } 671 #endif 672 return (0); 673 674 out: 675 /* Move this PCB to the head of hash chain. */ 676 if (inp != head->lh_first) { 677 LIST_REMOVE(inp, inp_hash); 678 LIST_INSERT_HEAD(head, inp, inp_hash); 679 } 680 return (inp); 681 } 682 683 struct inpcb * 684 in_pcblookup_bind(table, laddr, lport_arg) 685 struct inpcbtable *table; 686 struct in_addr laddr; 687 u_int lport_arg; 688 { 689 struct inpcbhead *head; 690 register struct inpcb *inp; 691 u_int16_t lport = lport_arg; 692 693 head = INPCBHASH_BIND(table, laddr, lport); 694 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 695 if (inp->inp_lport == lport && 696 in_hosteq(inp->inp_laddr, laddr)) 697 goto out; 698 } 699 head = INPCBHASH_BIND(table, zeroin_addr, lport); 700 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { 701 if (inp->inp_lport == lport && 702 in_hosteq(inp->inp_laddr, zeroin_addr)) 703 goto out; 704 } 705 #ifdef DIAGNOSTIC 706 if (in_pcbnotifymiss) { 707 printf("in_pcblookup_bind: laddr=%08x lport=%d\n", 708 ntohl(laddr.s_addr), ntohs(lport)); 709 } 710 #endif 711 return (0); 712 713 out: 714 /* Move this PCB to the head of hash chain. */ 715 if (inp != head->lh_first) { 716 LIST_REMOVE(inp, inp_hash); 717 LIST_INSERT_HEAD(head, inp, inp_hash); 718 } 719 return (inp); 720 } 721 722 void 723 in_pcbstate(inp, state) 724 struct inpcb *inp; 725 int state; 726 { 727 728 if (inp->inp_state > INP_ATTACHED) 729 LIST_REMOVE(inp, inp_hash); 730 731 switch (state) { 732 case INP_BOUND: 733 LIST_INSERT_HEAD(INPCBHASH_BIND(inp->inp_table, 734 inp->inp_laddr, inp->inp_lport), inp, inp_hash); 735 break; 736 case INP_CONNECTED: 737 LIST_INSERT_HEAD(INPCBHASH_CONNECT(inp->inp_table, 738 inp->inp_faddr, inp->inp_fport, 739 inp->inp_laddr, inp->inp_lport), inp, inp_hash); 740 break; 741 } 742 743 inp->inp_state = state; 744 } 745 746 struct rtentry * 747 in_pcbrtentry(inp) 748 struct inpcb *inp; 749 { 750 struct route *ro; 751 752 ro = &inp->inp_route; 753 754 if (ro->ro_rt == NULL) { 755 /* 756 * No route yet, so try to acquire one. 757 */ 758 if (!in_nullhost(inp->inp_faddr)) { 759 ro->ro_dst.sa_family = AF_INET; 760 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 761 satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr; 762 rtalloc(ro); 763 } 764 } 765 return (ro->ro_rt); 766 } 767