|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1991, 1993, 1995 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/systm.h> ! 63: #include <sys/malloc.h> ! 64: #include <sys/mbuf.h> ! 65: #include <sys/protosw.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/socketvar.h> ! 68: #include <sys/ioctl.h> ! 69: #include <sys/errno.h> ! 70: #include <sys/time.h> ! 71: #include <sys/proc.h> ! 72: ! 73: #include <net/if.h> ! 74: #include <net/route.h> ! 75: ! 76: #include <netinet/in.h> ! 77: #include <netinet/in_systm.h> ! 78: #include <netinet/ip.h> ! 79: #include <netinet/in_pcb.h> ! 80: #include <netinet/in_var.h> ! 81: #include <netinet/ip_var.h> ! 82: ! 83: #include <kern/kdebug.h> ! 84: ! 85: ! 86: #if KDEBUG ! 87: ! 88: #define DBG_FNC_PCB_LOOKUP NETDBG_CODE(DBG_NETTCP, (6 << 8)) ! 89: #define DBG_FNC_PCB_HLOOKUP NETDBG_CODE(DBG_NETTCP, ((6 << 8) | 1)) ! 90: ! 91: #endif ! 92: ! 93: ! 94: struct zone *inpcb_zone; ! 95: struct in_addr zeroin_addr; ! 96: ! 97: ! 98: ! 99: ! 100: void ! 101: lport_hash_remove(inp) ! 102: register struct inpcb *inp; ! 103: { ! 104: if ((*inp->lport_hash_str->hash_array)[inp->lport_hash_element] == inp) ! 105: (*inp->lport_hash_str->hash_array)[inp->lport_hash_element] = inp->lport_hash_next; ! 106: ! 107: if (inp->lport_hash_prev) ! 108: inp->lport_hash_prev->lport_hash_next = inp->lport_hash_next; ! 109: ! 110: if (inp->lport_hash_next) ! 111: inp->lport_hash_next->lport_hash_prev = inp->lport_hash_prev; ! 112: ! 113: inp->lport_hash_next = 0; ! 114: inp->lport_hash_prev = 0; ! 115: inp->lport_hash_element = -1; ! 116: } ! 117: ! 118: ! 119: ! 120: ! 121: void ! 122: lport_hash_insert(inp) ! 123: register struct inpcb *inp; ! 124: ! 125: { ! 126: register u_long h_idx; ! 127: ! 128: if (inp->lport_hash_element != -1) ! 129: return; ! 130: ! 131: h_idx = inp->inp_lport & inp->lport_hash_str->hash_mask; ! 132: ! 133: if ((*inp->lport_hash_str->hash_array)[h_idx]) { ! 134: (*inp->lport_hash_str->hash_array)[h_idx]->lport_hash_prev = inp; ! 135: inp->lport_hash_next = (*inp->lport_hash_str->hash_array)[h_idx]; ! 136: inp->lport_hash_prev = 0; ! 137: (*inp->lport_hash_str->hash_array)[h_idx] = inp; ! 138: } else { ! 139: (*inp->lport_hash_str->hash_array)[h_idx] = inp; ! 140: inp->lport_hash_next = 0; ! 141: inp->lport_hash_prev = 0; ! 142: } ! 143: ! 144: inp->lport_hash_element = h_idx; ! 145: } ! 146: ! 147: ! 148: ! 149: ! 150: void ! 151: hash_remove(inp) ! 152: register struct inpcb *inp; ! 153: { ! 154: if ((*inp->hash_str->hash_array)[inp->hash_element] == inp) ! 155: (*inp->hash_str->hash_array)[inp->hash_element] = inp->hash_next; ! 156: ! 157: if (inp->hash_prev) ! 158: inp->hash_prev->hash_next = inp->hash_next; ! 159: ! 160: if (inp->hash_next) ! 161: inp->hash_next->hash_prev = inp->hash_prev; ! 162: ! 163: inp->hash_next = 0; ! 164: inp->hash_prev = 0; ! 165: inp->hash_element = -1; ! 166: } ! 167: ! 168: ! 169: ! 170: void ! 171: hash_insert(inp) ! 172: register struct inpcb *inp; ! 173: { ! 174: register u_long h_idx; ! 175: ! 176: if (inp->hash_element != -1) ! 177: return; ! 178: ! 179: h_idx = (inp->inp_lport + inp->inp_fport + inp->inp_faddr.s_addr) & inp->hash_str->hash_mask; ! 180: ! 181: if ((*inp->hash_str->hash_array)[h_idx]) { ! 182: (*inp->hash_str->hash_array)[h_idx]->hash_prev = inp; ! 183: inp->hash_next = (*inp->hash_str->hash_array)[h_idx]; ! 184: inp->hash_prev = 0; ! 185: (*inp->hash_str->hash_array)[h_idx] = inp; ! 186: } else { ! 187: (*inp->hash_str->hash_array)[h_idx] = inp; ! 188: inp->hash_next = 0; ! 189: inp->hash_prev = 0; ! 190: } ! 191: inp->hash_element = h_idx; ! 192: } ! 193: ! 194: ! 195: struct inpcb *inet_hash1(hash_str, l_addr, l_port, f_addr, f_port) ! 196: struct inpcb_hash_str *hash_str; ! 197: u_long l_addr; ! 198: u_short l_port; ! 199: u_long f_addr; ! 200: u_short f_port; ! 201: { ! 202: return ((*hash_str->hash_array)[(l_port + f_port + f_addr) & hash_str->hash_mask]); ! 203: } ! 204: ! 205: ! 206: struct inpcb *inet_lport_hash1(lport_hash_str, l_port) ! 207: struct inpcb_hash_str *lport_hash_str; ! 208: u_short l_port; ! 209: ! 210: { ! 211: return ((*lport_hash_str->hash_array)[l_port & lport_hash_str->hash_mask]); ! 212: } ! 213: ! 214: ! 215: ! 216: int ! 217: in_pcballoc(so, head, hash_str, lport_hash_str) ! 218: struct socket *so; ! 219: struct inpcb *head; ! 220: struct inpcb_hash_str *hash_str; ! 221: struct inpcb_hash_str *lport_hash_str; ! 222: { ! 223: register struct inpcb *inp; ! 224: caddr_t temp; ! 225: ! 226: if (so->cached_in_sock_layer == 0) { ! 227: #if TEMPDEBUG ! 228: printf("PCBALLOC calling zalloc for socket %x\n", so); ! 229: #endif ! 230: inp = zalloc(inpcb_zone); ! 231: if (inp == NULL) ! 232: return (ENOBUFS); ! 233: bzero((caddr_t)inp, sizeof(*inp)); ! 234: } ! 235: else { ! 236: #if TEMPDEBUG ! 237: printf("PCBALLOC reusing PCB for socket %x\n", so); ! 238: #endif ! 239: inp = so->so_saved_pcb; ! 240: temp = inp->inp_saved_ppcb; ! 241: bzero((caddr_t) inp, sizeof(*inp)); ! 242: inp->inp_saved_ppcb = temp; ! 243: } ! 244: ! 245: inp->hash_element = -1; ! 246: inp->lport_hash_element = -1; ! 247: inp->inp_head = head; ! 248: inp->hash_str = hash_str; ! 249: inp->lport_hash_str = lport_hash_str; ! 250: inp->inp_socket = so; ! 251: if (head) ! 252: insque(inp, head); ! 253: so->so_pcb = (caddr_t)inp; ! 254: return (0); ! 255: } ! 256: ! 257: int ! 258: in_pcbbind(inp, nam) ! 259: register struct inpcb *inp; ! 260: struct mbuf *nam; ! 261: { ! 262: register struct socket *so = inp->inp_socket; ! 263: register struct inpcb *head = inp->inp_head; ! 264: register struct sockaddr_in *sin; ! 265: struct proc *p = current_proc(); /* XXX */ ! 266: u_short lport = 0; ! 267: int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); ! 268: int error; ! 269: register int loop_count = 0; ! 270: struct inpcb *hash_head; ! 271: ! 272: ! 273: if (in_ifaddr == 0) ! 274: return (EADDRNOTAVAIL); ! 275: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) ! 276: return (EINVAL); ! 277: if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ! 278: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || ! 279: (so->so_options & SO_ACCEPTCONN) == 0)) ! 280: wild = INPLOOKUP_WILDCARD; ! 281: if (nam) { ! 282: sin = mtod(nam, struct sockaddr_in *); ! 283: if (nam->m_len != sizeof (*sin)) ! 284: return (EINVAL); ! 285: #ifdef notdef ! 286: /* ! 287: * We should check the family, but old programs ! 288: * incorrectly fail to initialize it. ! 289: */ ! 290: if (sin->sin_family != AF_INET) ! 291: return (EAFNOSUPPORT); ! 292: #endif ! 293: lport = sin->sin_port; ! 294: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { ! 295: /* ! 296: * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; ! 297: * allow complete duplication of binding if ! 298: * SO_REUSEPORT is set, or if SO_REUSEADDR is set ! 299: * and a multicast address is bound on both ! 300: * new and duplicated sockets. ! 301: */ ! 302: if (so->so_options & SO_REUSEADDR) ! 303: reuseport = SO_REUSEADDR|SO_REUSEPORT; ! 304: } else if (sin->sin_addr.s_addr != INADDR_ANY) { ! 305: sin->sin_port = 0; /* yech... */ ! 306: if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) ! 307: return (EADDRNOTAVAIL); ! 308: } ! 309: if (lport) { ! 310: struct inpcb *t; ! 311: ! 312: /* GROSS */ ! 313: if (ntohs(lport) < IPPORT_RESERVED && ! 314: (error = suser(p->p_ucred, &p->p_acflag))) ! 315: return (EACCES); ! 316: ! 317: hash_head = inet_lport_hash1(inp->lport_hash_str, lport); ! 318: t = lport_hash_in_pcbwild(hash_head, ! 319: zeroin_addr, 0, sin->sin_addr, ! 320: lport, wild); ! 321: ! 322: if (t && (reuseport & t->inp_socket->so_options) == 0) ! 323: return (EADDRINUSE); ! 324: } ! 325: inp->inp_laddr = sin->sin_addr; ! 326: } ! 327: if (lport == 0) { ! 328: for (;;) { ! 329: if (++loop_count >= (IPPORT_USERRESERVED - IPPORT_RESERVED)) ! 330: return EADDRINUSE; ! 331: ! 332: if (head->inp_lport++ < IPPORT_RESERVED || ! 333: head->inp_lport > IPPORT_USERRESERVED) ! 334: head->inp_lport = IPPORT_RESERVED; ! 335: ! 336: lport = htons(head->inp_lport); ! 337: ! 338: hash_head = inet_lport_hash1(inp->lport_hash_str, lport); ! 339: if (lport_hash_in_pcbwild(hash_head, ! 340: zeroin_addr, 0, inp->inp_laddr, lport, wild)) ! 341: continue; ! 342: ! 343: break; ! 344: } ! 345: } ! 346: ! 347: inp->inp_lport = lport; ! 348: lport_hash_insert(inp); ! 349: ! 350: return (0); ! 351: } ! 352: ! 353: /* ! 354: * Connect from a socket to a specified address. ! 355: * Both address and port must be specified in argument sin. ! 356: * If don't have a local address for this socket yet, ! 357: * then pick one. ! 358: */ ! 359: int ! 360: in_pcbconnect(inp, nam) ! 361: register struct inpcb *inp; ! 362: struct mbuf *nam; ! 363: { ! 364: struct inpcb *hash_head; ! 365: struct in_ifaddr *ia; ! 366: struct sockaddr_in *ifaddr; ! 367: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! 368: ! 369: if (nam->m_len != sizeof (*sin)) ! 370: return (EINVAL); ! 371: if (sin->sin_family != AF_INET) ! 372: return (EAFNOSUPPORT); ! 373: if (sin->sin_port == 0) ! 374: return (EADDRNOTAVAIL); ! 375: if (in_ifaddr) { ! 376: /* ! 377: * If the destination address is INADDR_ANY, ! 378: * use the primary local address. ! 379: * If the supplied address is INADDR_BROADCAST, ! 380: * and the primary interface supports broadcast, ! 381: * choose the broadcast address for that interface. ! 382: */ ! 383: #define satosin(sa) ((struct sockaddr_in *)(sa)) ! 384: #define sintosa(sin) ((struct sockaddr *)(sin)) ! 385: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) ! 386: if (sin->sin_addr.s_addr == INADDR_ANY) ! 387: sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; ! 388: else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && ! 389: (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) ! 390: sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; ! 391: } ! 392: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 393: register struct route *ro; ! 394: ! 395: ia = (struct in_ifaddr *)0; ! 396: /* ! 397: * If route is known or can be allocated now, ! 398: * our src addr is taken from the i/f, else punt. ! 399: */ ! 400: ro = &inp->inp_route; ! 401: if (ro->ro_rt && ! 402: (satosin(&ro->ro_dst)->sin_addr.s_addr != ! 403: sin->sin_addr.s_addr || ! 404: inp->inp_socket->so_options & SO_DONTROUTE)) { ! 405: RTFREE(ro->ro_rt); ! 406: ro->ro_rt = (struct rtentry *)0; ! 407: } ! 408: if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ ! 409: (ro->ro_rt == (struct rtentry *)0 || ! 410: ro->ro_rt->rt_ifp == (struct ifnet *)0)) { ! 411: /* No route yet, so try to acquire one */ ! 412: ro->ro_dst.sa_family = AF_INET; ! 413: ro->ro_dst.sa_len = sizeof(struct sockaddr_in); ! 414: ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = ! 415: sin->sin_addr; ! 416: rtalloc(ro); ! 417: } ! 418: /* ! 419: * If we found a route, use the address ! 420: * corresponding to the outgoing interface ! 421: * unless it is the loopback (in case a route ! 422: * to our address on another net goes to loopback). ! 423: */ ! 424: if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) ! 425: ia = ifatoia(ro->ro_rt->rt_ifa); ! 426: if (ia == 0) { ! 427: u_short fport = sin->sin_port; ! 428: ! 429: sin->sin_port = 0; ! 430: ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); ! 431: if (ia == 0) ! 432: ia = ifatoia(ifa_ifwithnet(sintosa(sin))); ! 433: sin->sin_port = fport; ! 434: if (ia == 0) ! 435: ia = in_ifaddr; ! 436: if (ia == 0) ! 437: return (EADDRNOTAVAIL); ! 438: } ! 439: /* ! 440: * If the destination address is multicast and an outgoing ! 441: * interface has been set as a multicast option, use the ! 442: * address of that interface as our source address. ! 443: */ ! 444: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && ! 445: inp->inp_moptions != NULL) { ! 446: struct ip_moptions *imo; ! 447: struct ifnet *ifp; ! 448: ! 449: imo = inp->inp_moptions; ! 450: if (imo->imo_multicast_ifp != NULL) { ! 451: ifp = imo->imo_multicast_ifp; ! 452: for (ia = in_ifaddr; ia; ia = ia->ia_next) ! 453: if (ia->ia_ifp == ifp) ! 454: break; ! 455: if (ia == 0) ! 456: return (EADDRNOTAVAIL); ! 457: } ! 458: } ! 459: ifaddr = (struct sockaddr_in *)&ia->ia_addr; ! 460: } ! 461: ! 462: if ( !(inp->inp_flags & INP_NOLOOKUP)) { ! 463: hash_head = inet_hash1(inp->hash_str, ! 464: inp->inp_laddr.s_addr ? inp->inp_laddr.s_addr : ifaddr->sin_addr.s_addr, ! 465: inp->inp_lport, ! 466: sin->sin_addr.s_addr, ! 467: sin->sin_port); ! 468: ! 469: if (hash_in_pcblookup(hash_head, ! 470: sin->sin_addr, ! 471: sin->sin_port, ! 472: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, ! 473: inp->inp_lport)) ! 474: return (EADDRINUSE); ! 475: } ! 476: ! 477: ! 478: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 479: if (inp->inp_lport == 0) ! 480: (void)in_pcbbind(inp, (struct mbuf *)0); ! 481: inp->inp_laddr = ifaddr->sin_addr; ! 482: } ! 483: inp->inp_faddr = sin->sin_addr; ! 484: inp->inp_fport = sin->sin_port; ! 485: hash_insert(inp); ! 486: return (0); ! 487: } ! 488: ! 489: int ! 490: in_pcbdisconnect(inp) ! 491: struct inpcb *inp; ! 492: { ! 493: ! 494: inp->inp_faddr.s_addr = INADDR_ANY; ! 495: inp->inp_fport = 0; ! 496: ! 497: if (inp->inp_socket->so_state & SS_NOFDREF) ! 498: in_pcbdetach(inp); ! 499: else { ! 500: if (inp->hash_element >= 0) ! 501: hash_remove(inp); ! 502: } ! 503: } ! 504: ! 505: int ! 506: in_pcbdetach(inp) ! 507: struct inpcb *inp; ! 508: { ! 509: struct socket *so = inp->inp_socket; ! 510: ! 511: if (inp->hash_element >= 0) ! 512: hash_remove(inp); ! 513: ! 514: if (inp->lport_hash_element >= 0) ! 515: lport_hash_remove(inp); ! 516: #if TEMPDEBUG ! 517: if (so->cached_in_sock_layer) ! 518: printf("PCB_DETACH for cached socket %x\n", so); ! 519: else ! 520: printf("PCB_DETACH for allocated socket %x\n", so); ! 521: #endif ! 522: so->so_pcb = 0; ! 523: ! 524: if (inp->inp_options) ! 525: (void)m_free(inp->inp_options); ! 526: if (inp->inp_route.ro_rt) ! 527: rtfree(inp->inp_route.ro_rt); ! 528: ip_freemoptions(inp->inp_moptions); ! 529: if ((inp->inp_next) && (inp->inp_prev)) ! 530: remque(inp); ! 531: ! 532: if (so->cached_in_sock_layer) ! 533: so->so_saved_pcb = inp; ! 534: else ! 535: zfree(inpcb_zone, (vm_offset_t) inp); ! 536: sofree(so); ! 537: } ! 538: ! 539: int ! 540: in_setsockaddr(inp, nam) ! 541: register struct inpcb *inp; ! 542: struct mbuf *nam; ! 543: { ! 544: register struct sockaddr_in *sin; ! 545: ! 546: nam->m_len = sizeof (*sin); ! 547: sin = mtod(nam, struct sockaddr_in *); ! 548: bzero((caddr_t)sin, sizeof (*sin)); ! 549: sin->sin_family = AF_INET; ! 550: sin->sin_len = sizeof(*sin); ! 551: sin->sin_port = inp->inp_lport; ! 552: sin->sin_addr = inp->inp_laddr; ! 553: } ! 554: ! 555: int ! 556: in_setpeeraddr(inp, nam) ! 557: struct inpcb *inp; ! 558: struct mbuf *nam; ! 559: { ! 560: register struct sockaddr_in *sin; ! 561: ! 562: nam->m_len = sizeof (*sin); ! 563: sin = mtod(nam, struct sockaddr_in *); ! 564: bzero((caddr_t)sin, sizeof (*sin)); ! 565: sin->sin_family = AF_INET; ! 566: sin->sin_len = sizeof(*sin); ! 567: sin->sin_port = inp->inp_fport; ! 568: sin->sin_addr = inp->inp_faddr; ! 569: } ! 570: ! 571: /* ! 572: * Pass some notification to all connections of a protocol ! 573: * associated with address dst. The local address and/or port numbers ! 574: * may be specified to limit the search. The "usual action" will be ! 575: * taken, depending on the ctlinput cmd. The caller must filter any ! 576: * cmds that are uninteresting (e.g., no error in the map). ! 577: * Call the protocol specific routine (if any) to report ! 578: * any errors for each matching socket. ! 579: * ! 580: * Must be called at splnet. ! 581: */ ! 582: int ! 583: in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) ! 584: struct inpcb *head; ! 585: struct sockaddr *dst; ! 586: u_int fport_arg, lport_arg; ! 587: struct in_addr laddr; ! 588: int cmd; ! 589: void (*notify) __P((struct inpcb *, int)); ! 590: { ! 591: extern u_char inetctlerrmap[]; ! 592: register struct inpcb *inp, *oinp; ! 593: struct in_addr faddr; ! 594: u_short fport = fport_arg, lport = lport_arg; ! 595: int errno; ! 596: ! 597: if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) ! 598: return; ! 599: faddr = ((struct sockaddr_in *)dst)->sin_addr; ! 600: if (faddr.s_addr == INADDR_ANY) ! 601: return; ! 602: ! 603: /* ! 604: * Redirects go to all references to the destination, ! 605: * and use in_rtchange to invalidate the route cache. ! 606: * Dead host indications: notify all references to the destination. ! 607: * Otherwise, if we have knowledge of the local port and address, ! 608: * deliver only to that socket. ! 609: */ ! 610: if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { ! 611: fport = 0; ! 612: lport = 0; ! 613: laddr.s_addr = 0; ! 614: if (cmd != PRC_HOSTDEAD) ! 615: notify = in_rtchange; ! 616: } ! 617: errno = inetctlerrmap[cmd]; ! 618: for (inp = head->inp_next; inp != head;) { ! 619: if (inp->inp_faddr.s_addr != faddr.s_addr || ! 620: inp->inp_socket == 0 || ! 621: (lport && inp->inp_lport != lport) || ! 622: (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || ! 623: (fport && inp->inp_fport != fport)) { ! 624: inp = inp->inp_next; ! 625: continue; ! 626: } ! 627: oinp = inp; ! 628: inp = inp->inp_next; ! 629: if (notify) ! 630: (*notify)(oinp, errno); ! 631: } ! 632: } ! 633: ! 634: /* ! 635: * Check for alternatives when higher level complains ! 636: * about service problems. For now, invalidate cached ! 637: * routing information. If the route was created dynamically ! 638: * (by a redirect), time to try a default gateway again. ! 639: */ ! 640: int ! 641: in_losing(inp) ! 642: struct inpcb *inp; ! 643: { ! 644: register struct rtentry *rt; ! 645: struct rt_addrinfo info; ! 646: ! 647: if ((rt = inp->inp_route.ro_rt)) { ! 648: inp->inp_route.ro_rt = 0; ! 649: bzero((caddr_t)&info, sizeof(info)); ! 650: info.rti_info[RTAX_DST] = ! 651: (struct sockaddr *)&inp->inp_route.ro_dst; ! 652: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; ! 653: info.rti_info[RTAX_NETMASK] = rt_mask(rt); ! 654: rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); ! 655: if (rt->rt_flags & RTF_DYNAMIC) ! 656: (void) rtrequest(RTM_DELETE, rt_key(rt), ! 657: rt->rt_gateway, rt_mask(rt), rt->rt_flags, ! 658: (struct rtentry **)0); ! 659: else ! 660: /* ! 661: * A new route can be allocated ! 662: * the next time output is attempted. ! 663: */ ! 664: rtfree(rt); ! 665: } ! 666: } ! 667: ! 668: /* ! 669: * After a routing change, flush old routing ! 670: * and allocate a (hopefully) better one. ! 671: */ ! 672: void ! 673: in_rtchange(inp, errno) ! 674: register struct inpcb *inp; ! 675: int errno; ! 676: { ! 677: if (inp->inp_route.ro_rt) { ! 678: rtfree(inp->inp_route.ro_rt); ! 679: inp->inp_route.ro_rt = 0; ! 680: /* ! 681: * A new route can be allocated the next time ! 682: * output is attempted. ! 683: */ ! 684: } ! 685: } ! 686: ! 687: struct inpcb * ! 688: in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) ! 689: struct inpcb *head; ! 690: struct in_addr faddr, laddr; ! 691: u_int fport_arg, lport_arg; ! 692: int flags; ! 693: { ! 694: register struct inpcb *inp, *match = 0; ! 695: int matchwild = 3, wildcard; ! 696: u_short fport = fport_arg, lport = lport_arg; ! 697: #if KDEBUG ! 698: register int checked = 0; ! 699: #endif ! 700: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,0); ! 701: ! 702: for (inp = head->inp_next; inp != head; inp = inp->inp_next) { ! 703: #if KDEBUG ! 704: checked++; ! 705: #endif ! 706: if (inp->inp_lport != lport) ! 707: continue; ! 708: wildcard = 0; ! 709: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 710: if (laddr.s_addr == INADDR_ANY) ! 711: wildcard++; ! 712: else if (inp->inp_laddr.s_addr != laddr.s_addr) ! 713: continue; ! 714: } else { ! 715: if (laddr.s_addr != INADDR_ANY) ! 716: wildcard++; ! 717: } ! 718: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 719: if (faddr.s_addr == INADDR_ANY) ! 720: wildcard++; ! 721: else if (inp->inp_faddr.s_addr != faddr.s_addr || ! 722: inp->inp_fport != fport) ! 723: continue; ! 724: } else { ! 725: if (faddr.s_addr != INADDR_ANY) ! 726: wildcard++; ! 727: } ! 728: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) ! 729: continue; ! 730: if (wildcard < matchwild) { ! 731: match = inp; ! 732: matchwild = wildcard; ! 733: if (matchwild == 0) ! 734: break; ! 735: } ! 736: } ! 737: #if KDEBUG ! 738: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,0); ! 739: #endif ! 740: return (match); ! 741: } ! 742: ! 743: ! 744: ! 745: struct inpcb * ! 746: hash_in_pcbwild(head, faddr, fport_arg, laddr, lport_arg, flags) ! 747: struct inpcb *head; ! 748: struct in_addr faddr, laddr; ! 749: u_int fport_arg, lport_arg; ! 750: int flags; ! 751: { ! 752: register struct inpcb *inp, *match = 0; ! 753: int matchwild = 3, wildcard; ! 754: u_short fport = fport_arg, lport = lport_arg; ! 755: #if KDEBUG ! 756: register int checked = 0; ! 757: #endif ! 758: ! 759: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,-1); ! 760: ! 761: for (inp = head; inp != 0; inp = inp->hash_next) { ! 762: #if KDEBUG ! 763: checked++; ! 764: #endif ! 765: if (inp->inp_lport != lport) ! 766: continue; ! 767: wildcard = 0; ! 768: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 769: if (laddr.s_addr == INADDR_ANY) ! 770: wildcard++; ! 771: else if (inp->inp_laddr.s_addr != laddr.s_addr) ! 772: continue; ! 773: } else { ! 774: if (laddr.s_addr != INADDR_ANY) ! 775: wildcard++; ! 776: } ! 777: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 778: if (faddr.s_addr == INADDR_ANY) ! 779: wildcard++; ! 780: else if (inp->inp_faddr.s_addr != faddr.s_addr || ! 781: inp->inp_fport != fport) ! 782: continue; ! 783: } else { ! 784: if (faddr.s_addr != INADDR_ANY) ! 785: wildcard++; ! 786: } ! 787: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) ! 788: continue; ! 789: if (wildcard < matchwild) { ! 790: match = inp; ! 791: matchwild = wildcard; ! 792: if (matchwild == 0) ! 793: break; ! 794: } ! 795: } ! 796: #if KDEBUG ! 797: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,-1); ! 798: #endif ! 799: return (match); ! 800: } ! 801: ! 802: ! 803: ! 804: struct inpcb * ! 805: lport_hash_in_pcbwild(head, faddr, fport_arg, laddr, lport_arg, flags) ! 806: struct inpcb *head; ! 807: struct in_addr faddr, laddr; ! 808: u_int fport_arg, lport_arg; ! 809: int flags; ! 810: { ! 811: register struct inpcb *inp, *match = 0; ! 812: int matchwild = 3, wildcard; ! 813: u_short fport = fport_arg, lport = lport_arg; ! 814: #if KDEBUG ! 815: register int checked = 0; ! 816: #endif ! 817: ! 818: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,-1); ! 819: ! 820: for (inp = head; inp != 0; inp = inp->lport_hash_next) { ! 821: #if KDEBUG ! 822: checked++; ! 823: #endif ! 824: if (inp->inp_lport != lport) ! 825: continue; ! 826: wildcard = 0; ! 827: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 828: if (laddr.s_addr == INADDR_ANY) ! 829: wildcard++; ! 830: else if (inp->inp_laddr.s_addr != laddr.s_addr) ! 831: continue; ! 832: } else { ! 833: if (laddr.s_addr != INADDR_ANY) ! 834: wildcard++; ! 835: } ! 836: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 837: if (faddr.s_addr == INADDR_ANY) ! 838: wildcard++; ! 839: else if (inp->inp_faddr.s_addr != faddr.s_addr || ! 840: inp->inp_fport != fport) ! 841: continue; ! 842: } else { ! 843: if (faddr.s_addr != INADDR_ANY) ! 844: wildcard++; ! 845: } ! 846: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) ! 847: continue; ! 848: if (wildcard < matchwild) { ! 849: match = inp; ! 850: matchwild = wildcard; ! 851: if (matchwild == 0) ! 852: break; ! 853: } ! 854: } ! 855: #if KDEBUG ! 856: KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,-1); ! 857: #endif ! 858: return (match); ! 859: } ! 860: ! 861: ! 862: ! 863: ! 864: ! 865: struct inpcb * ! 866: hash_in_pcblookup(head, faddr, fport_arg, laddr, lport_arg) ! 867: struct inpcb *head; ! 868: struct in_addr faddr, laddr; ! 869: u_int fport_arg, lport_arg; ! 870: { ! 871: register struct inpcb *inp; ! 872: u_short fport = fport_arg, lport = lport_arg; ! 873: #if KDEBUG ! 874: register int checked = 0; ! 875: #endif ! 876: KERNEL_DEBUG(DBG_FNC_PCB_HLOOKUP | DBG_FUNC_START, 0,0,0,0,0); ! 877: ! 878: for (inp = head; inp != 0; inp = inp->hash_next) { ! 879: #if KDEBUG ! 880: checked++; ! 881: #endif ! 882: if (inp->inp_lport == lport && inp->inp_laddr.s_addr == laddr.s_addr && ! 883: inp->inp_faddr.s_addr == faddr.s_addr && inp->inp_fport == fport) ! 884: break; ! 885: } ! 886: #if KDEBUG ! 887: KERNEL_DEBUG(DBG_FNC_PCB_HLOOKUP | DBG_FUNC_END, checked,inp,0,0,0); ! 888: #endif ! 889: return (inp); ! 890: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.