|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1991, 1993, 1995 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 ! 55: */ ! 56: ! 57: #include <sys/param.h> ! 58: #include <sys/systm.h> ! 59: #include <sys/malloc.h> ! 60: #include <sys/mbuf.h> ! 61: #include <sys/protosw.h> ! 62: #include <sys/socket.h> ! 63: #include <sys/socketvar.h> ! 64: #include <sys/proc.h> ! 65: #include <sys/kernel.h> ! 66: #include <sys/sysctl.h> ! 67: ! 68: #include <machine/limits.h> ! 69: ! 70: #if ISFB31 ! 71: #include <vm/vm_zone.h> ! 72: #else ! 73: #include <kern/zalloc.h> ! 74: #endif ! 75: ! 76: #include <net/if.h> ! 77: #include <net/route.h> ! 78: ! 79: #include <netinet/in.h> ! 80: #include <netinet/in_pcb.h> ! 81: #include <netinet/in_var.h> ! 82: #include <netinet/ip_var.h> ! 83: ! 84: struct in_addr zeroin_addr; ! 85: ! 86: static void in_pcbremlists __P((struct inpcb *)); ! 87: static void in_rtchange __P((struct inpcb *, int)); ! 88: ! 89: ! 90: /* ! 91: * These configure the range of local port addresses assigned to ! 92: * "unspecified" outgoing connections/packets/whatever. ! 93: */ ! 94: static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ ! 95: static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ ! 96: static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ ! 97: static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ ! 98: static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ ! 99: static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ ! 100: ! 101: #define RANGECHK(var, min, max) \ ! 102: if ((var) < (min)) { (var) = (min); } \ ! 103: else if ((var) > (max)) { (var) = (max); } ! 104: ! 105: ! 106: static int ! 107: sysctl_net_ipport_check SYSCTL_HANDLER_ARGS ! 108: { ! 109: int error = sysctl_handle_int(oidp, ! 110: oidp->oid_arg1, oidp->oid_arg2, req); ! 111: if (!error) { ! 112: RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); ! 113: RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); ! 114: RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); ! 115: RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); ! 116: RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); ! 117: RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); ! 118: } ! 119: return error; ! 120: } ! 121: ! 122: #undef RANGECHK ! 123: ! 124: SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); ! 125: ! 126: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, ! 127: &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); ! 128: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, ! 129: &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); ! 130: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, ! 131: &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); ! 132: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, ! 133: &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); ! 134: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, ! 135: &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); ! 136: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, ! 137: &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); ! 138: ! 139: /* ! 140: * in_pcb.c: manage the Protocol Control Blocks. ! 141: * ! 142: * NOTE: It is assumed that most of these functions will be called at ! 143: * splnet(). XXX - There are, unfortunately, a few exceptions to this ! 144: * rule that should be fixed. ! 145: */ ! 146: ! 147: /* ! 148: * Allocate a PCB and associate it with the socket. ! 149: */ ! 150: int ! 151: in_pcballoc(so, pcbinfo, p) ! 152: struct socket *so; ! 153: struct inpcbinfo *pcbinfo; ! 154: struct proc *p; ! 155: { ! 156: register struct inpcb *inp; ! 157: ! 158: inp = (struct inpcb *) zalloc(pcbinfo->ipi_zone); ! 159: if (inp == NULL) ! 160: return (ENOBUFS); ! 161: bzero((caddr_t)inp, sizeof(*inp)); ! 162: inp->inp_gencnt = ++pcbinfo->ipi_gencnt; ! 163: inp->inp_pcbinfo = pcbinfo; ! 164: inp->inp_socket = so; ! 165: LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); ! 166: pcbinfo->ipi_count++; ! 167: so->so_pcb = (caddr_t)inp; ! 168: return (0); ! 169: } ! 170: ! 171: int ! 172: in_pcbbind(inp, nam, p) ! 173: register struct inpcb *inp; ! 174: struct sockaddr *nam; ! 175: struct proc *p; ! 176: { ! 177: register struct socket *so = inp->inp_socket; ! 178: u_short *lastport; ! 179: struct sockaddr_in *sin; ! 180: struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; ! 181: u_short lport = 0; ! 182: int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); ! 183: int error; ! 184: ! 185: if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ ! 186: return (EADDRNOTAVAIL); ! 187: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) ! 188: return (EINVAL); ! 189: if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) ! 190: wild = 1; ! 191: if (nam) { ! 192: sin = (struct sockaddr_in *)nam; ! 193: if (nam->sa_len != sizeof (*sin)) ! 194: return (EINVAL); ! 195: #ifdef notdef ! 196: /* ! 197: * We should check the family, but old programs ! 198: * incorrectly fail to initialize it. ! 199: */ ! 200: if (sin->sin_family != AF_INET) ! 201: return (EAFNOSUPPORT); ! 202: #endif ! 203: lport = sin->sin_port; ! 204: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { ! 205: /* ! 206: * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; ! 207: * allow complete duplication of binding if ! 208: * SO_REUSEPORT is set, or if SO_REUSEADDR is set ! 209: * and a multicast address is bound on both ! 210: * new and duplicated sockets. ! 211: */ ! 212: if (so->so_options & SO_REUSEADDR) ! 213: reuseport = SO_REUSEADDR|SO_REUSEPORT; ! 214: } else if (sin->sin_addr.s_addr != INADDR_ANY) { ! 215: sin->sin_port = 0; /* yech... */ ! 216: if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) ! 217: return (EADDRNOTAVAIL); ! 218: } ! 219: if (lport) { ! 220: struct inpcb *t; ! 221: ! 222: /* GROSS */ ! 223: if (ntohs(lport) < IPPORT_RESERVED && p && ! 224: suser(p->p_ucred, &p->p_acflag)) ! 225: return (EACCES); ! 226: if (so->so_uid && ! 227: !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { ! 228: t = in_pcblookup_local(inp->inp_pcbinfo, ! 229: sin->sin_addr, lport, INPLOOKUP_WILDCARD); ! 230: if (t && ! 231: (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ! 232: ntohl(t->inp_laddr.s_addr) != INADDR_ANY || ! 233: (t->inp_socket->so_options & ! 234: SO_REUSEPORT) == 0) && ! 235: (so->so_uid != t->inp_socket->so_uid)) ! 236: return (EADDRINUSE); ! 237: } ! 238: t = in_pcblookup_local(pcbinfo, sin->sin_addr, ! 239: lport, wild); ! 240: if (t && (reuseport & t->inp_socket->so_options) == 0) ! 241: return (EADDRINUSE); ! 242: } ! 243: inp->inp_laddr = sin->sin_addr; ! 244: } ! 245: if (lport == 0) { ! 246: u_short first, last; ! 247: int count; ! 248: ! 249: inp->inp_flags |= INP_ANONPORT; ! 250: ! 251: if (inp->inp_flags & INP_HIGHPORT) { ! 252: first = ipport_hifirstauto; /* sysctl */ ! 253: last = ipport_hilastauto; ! 254: lastport = &pcbinfo->lasthi; ! 255: } else if (inp->inp_flags & INP_LOWPORT) { ! 256: if (p && (error = suser(p->p_ucred, &p->p_acflag))) ! 257: return error; ! 258: first = ipport_lowfirstauto; /* 1023 */ ! 259: last = ipport_lowlastauto; /* 600 */ ! 260: lastport = &pcbinfo->lastlow; ! 261: } else { ! 262: first = ipport_firstauto; /* sysctl */ ! 263: last = ipport_lastauto; ! 264: lastport = &pcbinfo->lastport; ! 265: } ! 266: /* ! 267: * Simple check to ensure all ports are not used up causing ! 268: * a deadlock here. ! 269: * ! 270: * We split the two cases (up and down) so that the direction ! 271: * is not being tested on each round of the loop. ! 272: */ ! 273: if (first > last) { ! 274: /* ! 275: * counting down ! 276: */ ! 277: count = first - last; ! 278: ! 279: do { ! 280: if (count-- < 0) { /* completely used? */ ! 281: /* ! 282: * Undo any address bind that may have ! 283: * occurred above. ! 284: */ ! 285: inp->inp_laddr.s_addr = INADDR_ANY; ! 286: return (EAGAIN); ! 287: } ! 288: --*lastport; ! 289: if (*lastport > first || *lastport < last) ! 290: *lastport = first; ! 291: lport = htons(*lastport); ! 292: } while (in_pcblookup_local(pcbinfo, ! 293: inp->inp_laddr, lport, wild)); ! 294: } else { ! 295: /* ! 296: * counting up ! 297: */ ! 298: count = last - first; ! 299: ! 300: do { ! 301: if (count-- < 0) { /* completely used? */ ! 302: /* ! 303: * Undo any address bind that may have ! 304: * occurred above. ! 305: */ ! 306: inp->inp_laddr.s_addr = INADDR_ANY; ! 307: return (EAGAIN); ! 308: } ! 309: ++*lastport; ! 310: if (*lastport < first || *lastport > last) ! 311: *lastport = first; ! 312: lport = htons(*lastport); ! 313: } while (in_pcblookup_local(pcbinfo, ! 314: inp->inp_laddr, lport, wild)); ! 315: } ! 316: } ! 317: inp->inp_lport = lport; ! 318: if (in_pcbinshash(inp) != 0) { ! 319: inp->inp_laddr.s_addr = INADDR_ANY; ! 320: inp->inp_lport = 0; ! 321: return (EAGAIN); ! 322: } ! 323: return (0); ! 324: } ! 325: ! 326: /* ! 327: * Transform old in_pcbconnect() into an inner subroutine for new ! 328: * in_pcbconnect(): Do some validity-checking on the remote ! 329: * address (in mbuf 'nam') and then determine local host address ! 330: * (i.e., which interface) to use to access that remote host. ! 331: * ! 332: * This preserves definition of in_pcbconnect(), while supporting a ! 333: * slightly different version for T/TCP. (This is more than ! 334: * a bit of a kludge, but cleaning up the internal interfaces would ! 335: * have forced minor changes in every protocol). ! 336: */ ! 337: ! 338: int ! 339: in_pcbladdr(inp, nam, plocal_sin) ! 340: register struct inpcb *inp; ! 341: struct sockaddr *nam; ! 342: struct sockaddr_in **plocal_sin; ! 343: { ! 344: struct in_ifaddr *ia; ! 345: register struct sockaddr_in *sin = (struct sockaddr_in *)nam; ! 346: ! 347: if (nam->sa_len != sizeof (*sin)) ! 348: return (EINVAL); ! 349: if (sin->sin_family != AF_INET) ! 350: return (EAFNOSUPPORT); ! 351: if (sin->sin_port == 0) ! 352: return (EADDRNOTAVAIL); ! 353: if (!TAILQ_EMPTY(&in_ifaddrhead)) { ! 354: /* ! 355: * If the destination address is INADDR_ANY, ! 356: * use the primary local address. ! 357: * If the supplied address is INADDR_BROADCAST, ! 358: * and the primary interface supports broadcast, ! 359: * choose the broadcast address for that interface. ! 360: */ ! 361: #define satosin(sa) ((struct sockaddr_in *)(sa)) ! 362: #define sintosa(sin) ((struct sockaddr *)(sin)) ! 363: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) ! 364: if (sin->sin_addr.s_addr == INADDR_ANY) ! 365: sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; ! 366: else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && ! 367: (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) ! 368: sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; ! 369: } ! 370: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 371: register struct route *ro; ! 372: ! 373: ia = (struct in_ifaddr *)0; ! 374: /* ! 375: * If route is known or can be allocated now, ! 376: * our src addr is taken from the i/f, else punt. ! 377: */ ! 378: ro = &inp->inp_route; ! 379: if (ro->ro_rt && ! 380: (satosin(&ro->ro_dst)->sin_addr.s_addr != ! 381: sin->sin_addr.s_addr || ! 382: inp->inp_socket->so_options & SO_DONTROUTE)) { ! 383: RTFREE(ro->ro_rt); ! 384: ro->ro_rt = (struct rtentry *)0; ! 385: } ! 386: if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ ! 387: (ro->ro_rt == (struct rtentry *)0 || ! 388: ro->ro_rt->rt_ifp == (struct ifnet *)0)) { ! 389: /* No route yet, so try to acquire one */ ! 390: ro->ro_dst.sa_family = AF_INET; ! 391: ro->ro_dst.sa_len = sizeof(struct sockaddr_in); ! 392: ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = ! 393: sin->sin_addr; ! 394: rtalloc(ro); ! 395: } ! 396: /* ! 397: * If we found a route, use the address ! 398: * corresponding to the outgoing interface ! 399: * unless it is the loopback (in case a route ! 400: * to our address on another net goes to loopback). ! 401: */ ! 402: if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) ! 403: ia = ifatoia(ro->ro_rt->rt_ifa); ! 404: if (ia == 0) { ! 405: u_short fport = sin->sin_port; ! 406: ! 407: sin->sin_port = 0; ! 408: ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); ! 409: if (ia == 0) ! 410: ia = ifatoia(ifa_ifwithnet(sintosa(sin))); ! 411: sin->sin_port = fport; ! 412: if (ia == 0) ! 413: ia = in_ifaddrhead.tqh_first; ! 414: if (ia == 0) ! 415: return (EADDRNOTAVAIL); ! 416: } ! 417: /* ! 418: * If the destination address is multicast and an outgoing ! 419: * interface has been set as a multicast option, use the ! 420: * address of that interface as our source address. ! 421: */ ! 422: if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && ! 423: inp->inp_moptions != NULL) { ! 424: struct ip_moptions *imo; ! 425: struct ifnet *ifp; ! 426: ! 427: imo = inp->inp_moptions; ! 428: if (imo->imo_multicast_ifp != NULL) { ! 429: ifp = imo->imo_multicast_ifp; ! 430: for (ia = in_ifaddrhead.tqh_first; ia; ! 431: ia = ia->ia_link.tqe_next) ! 432: if (ia->ia_ifp == ifp) ! 433: break; ! 434: if (ia == 0) ! 435: return (EADDRNOTAVAIL); ! 436: } ! 437: } ! 438: /* ! 439: * Don't do pcblookup call here; return interface in plocal_sin ! 440: * and exit to caller, that will do the lookup. ! 441: */ ! 442: *plocal_sin = &ia->ia_addr; ! 443: ! 444: } ! 445: return(0); ! 446: } ! 447: ! 448: /* ! 449: * Outer subroutine: ! 450: * Connect from a socket to a specified address. ! 451: * Both address and port must be specified in argument sin. ! 452: * If don't have a local address for this socket yet, ! 453: * then pick one. ! 454: */ ! 455: int ! 456: in_pcbconnect(inp, nam, p) ! 457: register struct inpcb *inp; ! 458: struct sockaddr *nam; ! 459: struct proc *p; ! 460: { ! 461: struct sockaddr_in *ifaddr; ! 462: register struct sockaddr_in *sin = (struct sockaddr_in *)nam; ! 463: int error; ! 464: ! 465: /* ! 466: * Call inner routine, to assign local interface address. ! 467: */ ! 468: if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0) ! 469: return(error); ! 470: ! 471: if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, ! 472: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, ! 473: inp->inp_lport, 0) != NULL) { ! 474: return (EADDRINUSE); ! 475: } ! 476: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 477: if (inp->inp_lport == 0) ! 478: (void)in_pcbbind(inp, (struct sockaddr *)0, p); ! 479: inp->inp_laddr = ifaddr->sin_addr; ! 480: } ! 481: inp->inp_faddr = sin->sin_addr; ! 482: inp->inp_fport = sin->sin_port; ! 483: in_pcbrehash(inp); ! 484: return (0); ! 485: } ! 486: ! 487: void ! 488: in_pcbdisconnect(inp) ! 489: struct inpcb *inp; ! 490: { ! 491: ! 492: inp->inp_faddr.s_addr = INADDR_ANY; ! 493: inp->inp_fport = 0; ! 494: in_pcbrehash(inp); ! 495: if (inp->inp_socket->so_state & SS_NOFDREF) ! 496: in_pcbdetach(inp); ! 497: } ! 498: ! 499: void ! 500: in_pcbdetach(inp) ! 501: struct inpcb *inp; ! 502: { ! 503: struct socket *so = inp->inp_socket; ! 504: struct inpcbinfo *ipi = inp->inp_pcbinfo; ! 505: ! 506: inp->inp_gencnt = ++ipi->ipi_gencnt; ! 507: in_pcbremlists(inp); ! 508: so->so_pcb = 0; ! 509: sofree(so); ! 510: if (inp->inp_options) ! 511: (void)m_free(inp->inp_options); ! 512: if (inp->inp_route.ro_rt) ! 513: rtfree(inp->inp_route.ro_rt); ! 514: ip_freemoptions(inp->inp_moptions); ! 515: zfree(ipi->ipi_zone, (vm_offset_t) inp); ! 516: } ! 517: ! 518: /* ! 519: * The calling convention of in_setsockaddr() and in_setpeeraddr() was ! 520: * modified to match the pru_sockaddr() and pru_peeraddr() entry points ! 521: * in struct pr_usrreqs, so that protocols can just reference then directly ! 522: * without the need for a wrapper function. The socket must have a valid ! 523: * (i.e., non-nil) PCB, but it should be impossible to get an invalid one ! 524: * except through a kernel programming error, so it is acceptable to panic ! 525: * (or in this case trap) if the PCB is invalid. (Actually, we don't trap ! 526: * because there actually /is/ a programming error somewhere... XXX) ! 527: */ ! 528: int ! 529: in_setsockaddr(so, nam) ! 530: struct socket *so; ! 531: struct sockaddr **nam; ! 532: { ! 533: int s; ! 534: register struct inpcb *inp; ! 535: register struct sockaddr_in *sin; ! 536: ! 537: /* ! 538: * Do the malloc first in case it blocks. ! 539: */ ! 540: MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); ! 541: bzero(sin, sizeof *sin); ! 542: sin->sin_family = AF_INET; ! 543: sin->sin_len = sizeof(*sin); ! 544: ! 545: s = splnet(); ! 546: inp = sotoinpcb(so); ! 547: if (!inp) { ! 548: splx(s); ! 549: FREE(sin, M_SONAME); ! 550: return EINVAL; ! 551: } ! 552: sin->sin_port = inp->inp_lport; ! 553: sin->sin_addr = inp->inp_laddr; ! 554: splx(s); ! 555: ! 556: *nam = (struct sockaddr *)sin; ! 557: return 0; ! 558: } ! 559: ! 560: int ! 561: in_setpeeraddr(so, nam) ! 562: struct socket *so; ! 563: struct sockaddr **nam; ! 564: { ! 565: int s; ! 566: struct inpcb *inp; ! 567: register struct sockaddr_in *sin; ! 568: ! 569: /* ! 570: * Do the malloc first in case it blocks. ! 571: */ ! 572: MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK); ! 573: bzero((caddr_t)sin, sizeof (*sin)); ! 574: sin->sin_family = AF_INET; ! 575: sin->sin_len = sizeof(*sin); ! 576: ! 577: s = splnet(); ! 578: inp = sotoinpcb(so); ! 579: if (!inp) { ! 580: splx(s); ! 581: FREE(sin, M_SONAME); ! 582: return EINVAL; ! 583: } ! 584: sin->sin_port = inp->inp_fport; ! 585: sin->sin_addr = inp->inp_faddr; ! 586: splx(s); ! 587: ! 588: *nam = (struct sockaddr *)sin; ! 589: return 0; ! 590: } ! 591: ! 592: /* ! 593: * Pass some notification to all connections of a protocol ! 594: * associated with address dst. The local address and/or port numbers ! 595: * may be specified to limit the search. The "usual action" will be ! 596: * taken, depending on the ctlinput cmd. The caller must filter any ! 597: * cmds that are uninteresting (e.g., no error in the map). ! 598: * Call the protocol specific routine (if any) to report ! 599: * any errors for each matching socket. ! 600: */ ! 601: void ! 602: in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) ! 603: struct inpcbhead *head; ! 604: struct sockaddr *dst; ! 605: u_int fport_arg, lport_arg; ! 606: struct in_addr laddr; ! 607: int cmd; ! 608: void (*notify) __P((struct inpcb *, int)); ! 609: { ! 610: register struct inpcb *inp, *oinp; ! 611: struct in_addr faddr; ! 612: u_short fport = fport_arg, lport = lport_arg; ! 613: int errno, s; ! 614: ! 615: if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) ! 616: return; ! 617: faddr = ((struct sockaddr_in *)dst)->sin_addr; ! 618: if (faddr.s_addr == INADDR_ANY) ! 619: return; ! 620: ! 621: /* ! 622: * Redirects go to all references to the destination, ! 623: * and use in_rtchange to invalidate the route cache. ! 624: * Dead host indications: notify all references to the destination. ! 625: * Otherwise, if we have knowledge of the local port and address, ! 626: * deliver only to that socket. ! 627: */ ! 628: if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { ! 629: fport = 0; ! 630: lport = 0; ! 631: laddr.s_addr = 0; ! 632: if (cmd != PRC_HOSTDEAD) ! 633: notify = in_rtchange; ! 634: } ! 635: errno = inetctlerrmap[cmd]; ! 636: s = splnet(); ! 637: for (inp = head->lh_first; inp != NULL;) { ! 638: if (inp->inp_faddr.s_addr != faddr.s_addr || ! 639: inp->inp_socket == 0 || ! 640: (lport && inp->inp_lport != lport) || ! 641: (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || ! 642: (fport && inp->inp_fport != fport)) { ! 643: inp = inp->inp_list.le_next; ! 644: continue; ! 645: } ! 646: oinp = inp; ! 647: inp = inp->inp_list.le_next; ! 648: if (notify) ! 649: (*notify)(oinp, errno); ! 650: } ! 651: splx(s); ! 652: } ! 653: ! 654: /* ! 655: * Check for alternatives when higher level complains ! 656: * about service problems. For now, invalidate cached ! 657: * routing information. If the route was created dynamically ! 658: * (by a redirect), time to try a default gateway again. ! 659: */ ! 660: void ! 661: in_losing(inp) ! 662: struct inpcb *inp; ! 663: { ! 664: register struct rtentry *rt; ! 665: struct rt_addrinfo info; ! 666: ! 667: if ((rt = inp->inp_route.ro_rt)) { ! 668: inp->inp_route.ro_rt = 0; ! 669: bzero((caddr_t)&info, sizeof(info)); ! 670: info.rti_info[RTAX_DST] = ! 671: (struct sockaddr *)&inp->inp_route.ro_dst; ! 672: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; ! 673: info.rti_info[RTAX_NETMASK] = rt_mask(rt); ! 674: rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); ! 675: if (rt->rt_flags & RTF_DYNAMIC) ! 676: (void) rtrequest(RTM_DELETE, rt_key(rt), ! 677: rt->rt_gateway, rt_mask(rt), rt->rt_flags, ! 678: (struct rtentry **)0); ! 679: else ! 680: /* ! 681: * A new route can be allocated ! 682: * the next time output is attempted. ! 683: */ ! 684: rtfree(rt); ! 685: } ! 686: } ! 687: ! 688: /* ! 689: * After a routing change, flush old routing ! 690: * and allocate a (hopefully) better one. ! 691: */ ! 692: static void ! 693: in_rtchange(inp, errno) ! 694: register struct inpcb *inp; ! 695: int errno; ! 696: { ! 697: if (inp->inp_route.ro_rt) { ! 698: rtfree(inp->inp_route.ro_rt); ! 699: inp->inp_route.ro_rt = 0; ! 700: /* ! 701: * A new route can be allocated the next time ! 702: * output is attempted. ! 703: */ ! 704: } ! 705: } ! 706: ! 707: /* ! 708: * Lookup a PCB based on the local address and port. ! 709: */ ! 710: struct inpcb * ! 711: in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) ! 712: struct inpcbinfo *pcbinfo; ! 713: struct in_addr laddr; ! 714: u_int lport_arg; ! 715: int wild_okay; ! 716: { ! 717: register struct inpcb *inp; ! 718: int matchwild = 3, wildcard; ! 719: u_short lport = lport_arg; ! 720: ! 721: if (!wild_okay) { ! 722: struct inpcbhead *head; ! 723: /* ! 724: * Look for an unconnected (wildcard foreign addr) PCB that ! 725: * matches the local address and port we're looking for. ! 726: */ ! 727: head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; ! 728: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { ! 729: if (inp->inp_faddr.s_addr == INADDR_ANY && ! 730: inp->inp_laddr.s_addr == laddr.s_addr && ! 731: inp->inp_lport == lport) { ! 732: /* ! 733: * Found. ! 734: */ ! 735: return (inp); ! 736: } ! 737: } ! 738: /* ! 739: * Not found. ! 740: */ ! 741: return (NULL); ! 742: } else { ! 743: struct inpcbporthead *porthash; ! 744: struct inpcbport *phd; ! 745: struct inpcb *match = NULL; ! 746: /* ! 747: * Best fit PCB lookup. ! 748: * ! 749: * First see if this local port is in use by looking on the ! 750: * port hash list. ! 751: */ ! 752: porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, ! 753: pcbinfo->porthashmask)]; ! 754: for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { ! 755: if (phd->phd_port == lport) ! 756: break; ! 757: } ! 758: if (phd != NULL) { ! 759: /* ! 760: * Port is in use by one or more PCBs. Look for best ! 761: * fit. ! 762: */ ! 763: for (inp = phd->phd_pcblist.lh_first; inp != NULL; ! 764: inp = inp->inp_portlist.le_next) { ! 765: wildcard = 0; ! 766: if (inp->inp_faddr.s_addr != INADDR_ANY) ! 767: wildcard++; ! 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 (wildcard < matchwild) { ! 778: match = inp; ! 779: matchwild = wildcard; ! 780: if (matchwild == 0) { ! 781: break; ! 782: } ! 783: } ! 784: } ! 785: } ! 786: return (match); ! 787: } ! 788: } ! 789: ! 790: /* ! 791: * Lookup PCB in hash list. ! 792: */ ! 793: struct inpcb * ! 794: in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) ! 795: struct inpcbinfo *pcbinfo; ! 796: struct in_addr faddr, laddr; ! 797: u_int fport_arg, lport_arg; ! 798: int wildcard; ! 799: { ! 800: struct inpcbhead *head; ! 801: register struct inpcb *inp; ! 802: u_short fport = fport_arg, lport = lport_arg; ! 803: ! 804: /* ! 805: * We may have found the pcb in the last lookup - check this first. ! 806: */ ! 807: ! 808: if ((!IN_MULTICAST(laddr.s_addr)) && (pcbinfo->last_pcb)) { ! 809: if (faddr.s_addr == pcbinfo->last_pcb->inp_faddr.s_addr && ! 810: laddr.s_addr == pcbinfo->last_pcb->inp_laddr.s_addr && ! 811: fport_arg == pcbinfo->last_pcb->inp_fport && ! 812: lport_arg == pcbinfo->last_pcb->inp_lport) { ! 813: /* ! 814: * Found. ! 815: */ ! 816: return (pcbinfo->last_pcb); ! 817: } ! 818: ! 819: pcbinfo->last_pcb = 0; ! 820: } ! 821: ! 822: /* ! 823: * First look for an exact match. ! 824: */ ! 825: head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; ! 826: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { ! 827: if (inp->inp_faddr.s_addr == faddr.s_addr && ! 828: inp->inp_laddr.s_addr == laddr.s_addr && ! 829: inp->inp_fport == fport && ! 830: inp->inp_lport == lport) { ! 831: /* ! 832: * Found. ! 833: */ ! 834: return (inp); ! 835: } ! 836: } ! 837: if (wildcard) { ! 838: struct inpcb *local_wild = NULL; ! 839: ! 840: head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; ! 841: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { ! 842: if (inp->inp_faddr.s_addr == INADDR_ANY && ! 843: inp->inp_lport == lport) { ! 844: if (inp->inp_laddr.s_addr == laddr.s_addr) ! 845: return (inp); ! 846: else if (inp->inp_laddr.s_addr == INADDR_ANY) ! 847: local_wild = inp; ! 848: } ! 849: } ! 850: return (local_wild); ! 851: } ! 852: ! 853: /* ! 854: * Not found. ! 855: */ ! 856: return (NULL); ! 857: } ! 858: ! 859: /* ! 860: * Insert PCB onto various hash lists. ! 861: */ ! 862: int ! 863: in_pcbinshash(inp) ! 864: struct inpcb *inp; ! 865: { ! 866: struct inpcbhead *pcbhash; ! 867: struct inpcbporthead *pcbporthash; ! 868: struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; ! 869: struct inpcbport *phd; ! 870: ! 871: pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, ! 872: inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; ! 873: ! 874: pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, ! 875: pcbinfo->porthashmask)]; ! 876: ! 877: /* ! 878: * Go through port list and look for a head for this lport. ! 879: */ ! 880: for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { ! 881: if (phd->phd_port == inp->inp_lport) ! 882: break; ! 883: } ! 884: /* ! 885: * If none exists, malloc one and tack it on. ! 886: */ ! 887: if (phd == NULL) { ! 888: MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT); ! 889: if (phd == NULL) { ! 890: return (ENOBUFS); /* XXX */ ! 891: } ! 892: phd->phd_port = inp->inp_lport; ! 893: LIST_INIT(&phd->phd_pcblist); ! 894: LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); ! 895: } ! 896: inp->inp_phd = phd; ! 897: LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); ! 898: LIST_INSERT_HEAD(pcbhash, inp, inp_hash); ! 899: return (0); ! 900: } ! 901: ! 902: /* ! 903: * Move PCB to the proper hash bucket when { faddr, fport } have been ! 904: * changed. NOTE: This does not handle the case of the lport changing (the ! 905: * hashed port list would have to be updated as well), so the lport must ! 906: * not change after in_pcbinshash() has been called. ! 907: */ ! 908: void ! 909: in_pcbrehash(inp) ! 910: struct inpcb *inp; ! 911: { ! 912: struct inpcbhead *head; ! 913: ! 914: head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, ! 915: inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; ! 916: ! 917: if (inp == inp->inp_pcbinfo->last_pcb) ! 918: inp->inp_pcbinfo->last_pcb = 0; ! 919: ! 920: LIST_REMOVE(inp, inp_hash); ! 921: LIST_INSERT_HEAD(head, inp, inp_hash); ! 922: } ! 923: ! 924: /* ! 925: * Remove PCB from various lists. ! 926: */ ! 927: static void ! 928: in_pcbremlists(inp) ! 929: struct inpcb *inp; ! 930: { ! 931: inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt; ! 932: if (inp == inp->inp_pcbinfo->last_pcb) ! 933: inp->inp_pcbinfo->last_pcb = 0; ! 934: ! 935: if (inp->inp_lport) { ! 936: struct inpcbport *phd = inp->inp_phd; ! 937: ! 938: LIST_REMOVE(inp, inp_hash); ! 939: LIST_REMOVE(inp, inp_portlist); ! 940: if (phd->phd_pcblist.lh_first == NULL) { ! 941: LIST_REMOVE(phd, phd_hash); ! 942: FREE(phd, M_PCB); ! 943: } ! 944: } ! 945: ! 946: LIST_REMOVE(inp, inp_list); ! 947: inp->inp_pcbinfo->ipi_count--; ! 948: } ! 949: ! 950: int ! 951: in_pcb_grab_port __P((struct inpcbinfo *pcbinfo, ! 952: u_short options, ! 953: struct in_addr laddr, ! 954: u_short *lport, ! 955: struct in_addr faddr, ! 956: u_short fport, ! 957: u_int cookie, ! 958: u_char owner_id)) ! 959: { ! 960: struct inpcb *pcb; ! 961: struct sockaddr_in sin; ! 962: struct proc *p = current_proc(); ! 963: int stat; ! 964: ! 965: ! 966: pcbinfo->nat_dummy_socket.so_pcb = 0; ! 967: pcbinfo->nat_dummy_socket.so_options = 0; ! 968: if (*lport) { ! 969: /* The grabber wants a particular port */ ! 970: ! 971: if (faddr.s_addr || fport) { ! 972: /* ! 973: * This is either the second half of an active connect, or ! 974: * it's from the acceptance of an incoming connection. ! 975: */ ! 976: if (laddr.s_addr == 0) { ! 977: return EINVAL; ! 978: } ! 979: ! 980: if (in_pcblookup_hash(pcbinfo, faddr, fport, ! 981: laddr, *lport, 0) != NULL) { ! 982: if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) { ! 983: return (EADDRINUSE); ! 984: } ! 985: } ! 986: ! 987: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p); ! 988: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket); ! 989: pcb->inp_lport = *lport; ! 990: pcb->inp_laddr.s_addr = laddr.s_addr; ! 991: ! 992: pcb->inp_faddr = faddr; ! 993: pcb->inp_fport = fport; ! 994: in_pcbinshash(pcb); ! 995: } ! 996: else { ! 997: /* ! 998: * This is either a bind for a passive socket, or it's the ! 999: * first part of bind-connect sequence (not likely since an ! 1000: * ephemeral port is usually used in this case). Or, it's ! 1001: * the result of a connection acceptance when the foreign ! 1002: * address/port cannot be provided (which requires the SO_REUSEADDR ! 1003: * flag if laddr is not multicast). ! 1004: */ ! 1005: ! 1006: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p); ! 1007: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket); ! 1008: ! 1009: pcbinfo->nat_dummy_socket.so_options = options; ! 1010: bzero(&sin, sizeof(struct sockaddr_in)); ! 1011: sin.sin_len = sizeof(struct sockaddr_in); ! 1012: sin.sin_family = AF_INET; ! 1013: sin.sin_addr.s_addr = laddr.s_addr; ! 1014: sin.sin_port = *lport; ! 1015: ! 1016: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, ! 1017: (struct sockaddr *) &sin, p); ! 1018: if (stat) { ! 1019: in_pcbdetach(pcb); ! 1020: return stat; ! 1021: } ! 1022: } ! 1023: } ! 1024: else { ! 1025: /* The grabber wants an ephemeral port */ ! 1026: ! 1027: in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p); ! 1028: pcb = sotoinpcb(&pcbinfo->nat_dummy_socket); ! 1029: ! 1030: bzero(&sin, sizeof(struct sockaddr_in)); ! 1031: sin.sin_len = sizeof(struct sockaddr_in); ! 1032: sin.sin_family = AF_INET; ! 1033: sin.sin_addr.s_addr = laddr.s_addr; ! 1034: sin.sin_port = 0; ! 1035: ! 1036: if (faddr.s_addr || fport) { ! 1037: /* ! 1038: * Not sure if this case will be used - could occur when connect ! 1039: * is called, skipping the bind. ! 1040: */ ! 1041: ! 1042: if (laddr.s_addr == 0) { ! 1043: in_pcbdetach(pcb); ! 1044: return EINVAL; ! 1045: } ! 1046: ! 1047: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, ! 1048: (struct sockaddr *) &sin, p); ! 1049: if (stat) { ! 1050: in_pcbdetach(pcb); ! 1051: return stat; ! 1052: } ! 1053: ! 1054: if (in_pcblookup_hash(pcbinfo, faddr, fport, ! 1055: pcb->inp_laddr, pcb->inp_lport, 0) != NULL) { ! 1056: in_pcbdetach(pcb); ! 1057: return (EADDRINUSE); ! 1058: } ! 1059: ! 1060: pcb->inp_faddr = faddr; ! 1061: pcb->inp_fport = fport; ! 1062: in_pcbrehash(pcb); ! 1063: } ! 1064: else { ! 1065: /* ! 1066: * This is a simple bind of an ephemeral port. The local addr ! 1067: * may or may not be defined. ! 1068: */ ! 1069: ! 1070: stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, ! 1071: (struct sockaddr *) &sin, p); ! 1072: if (stat) { ! 1073: in_pcbdetach(pcb); ! 1074: return stat; ! 1075: } ! 1076: } ! 1077: *lport = pcb->inp_lport; ! 1078: } ! 1079: ! 1080: ! 1081: pcb->nat_owner = owner_id; ! 1082: pcb->nat_cookie = cookie; ! 1083: pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb; ! 1084: return 0; ! 1085: } ! 1086: ! 1087: int ! 1088: in_pcb_letgo_port __P((struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport, ! 1089: struct in_addr faddr, u_short fport, u_char owner_id)) ! 1090: { ! 1091: struct inpcbhead *head; ! 1092: register struct inpcb *inp; ! 1093: ! 1094: ! 1095: /* ! 1096: * First look for an exact match. ! 1097: */ ! 1098: head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; ! 1099: for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { ! 1100: if (inp->inp_faddr.s_addr == faddr.s_addr && ! 1101: inp->inp_laddr.s_addr == laddr.s_addr && ! 1102: inp->inp_fport == fport && ! 1103: inp->inp_lport == lport && ! 1104: inp->nat_owner == owner_id) { ! 1105: /* ! 1106: * Found. ! 1107: */ ! 1108: in_pcbdetach(inp); ! 1109: return 0; ! 1110: } ! 1111: } ! 1112: ! 1113: return ENOENT; ! 1114: } ! 1115: ! 1116: u_char ! 1117: in_pcb_get_owner(struct inpcbinfo *pcbinfo, ! 1118: struct in_addr laddr, u_short lport, ! 1119: struct in_addr faddr, u_short fport, ! 1120: u_int *cookie) ! 1121: ! 1122: { ! 1123: struct inpcb *inp; ! 1124: u_char owner_id = INPCB_NO_OWNER; ! 1125: struct inpcbport *phd; ! 1126: struct inpcbporthead *porthash; ! 1127: ! 1128: ! 1129: if (IN_MULTICAST(laddr.s_addr)) { ! 1130: /* ! 1131: * Walk through PCB's looking for registered ! 1132: * owners. ! 1133: */ ! 1134: ! 1135: porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, ! 1136: pcbinfo->porthashmask)]; ! 1137: for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { ! 1138: if (phd->phd_port == lport) ! 1139: break; ! 1140: } ! 1141: ! 1142: if (phd == 0) { ! 1143: return INPCB_NO_OWNER; ! 1144: } ! 1145: ! 1146: owner_id = INPCB_NO_OWNER; ! 1147: for (inp = phd->phd_pcblist.lh_first; inp != NULL; ! 1148: inp = inp->inp_portlist.le_next) { ! 1149: ! 1150: if (inp->inp_laddr.s_addr == laddr.s_addr) { ! 1151: if (inp->nat_owner == 0) ! 1152: owner_id |= INPCB_OWNED_BY_X; ! 1153: else ! 1154: owner_id |= inp->nat_owner; ! 1155: } ! 1156: } ! 1157: ! 1158: return owner_id; ! 1159: } ! 1160: else { ! 1161: inp = in_pcblookup_hash(pcbinfo, faddr, fport, ! 1162: laddr, lport, 1); ! 1163: if (inp) { ! 1164: if (inp->nat_owner) { ! 1165: owner_id = inp->nat_owner; ! 1166: *cookie = inp->nat_cookie; ! 1167: } ! 1168: else { ! 1169: pcbinfo->last_pcb = inp; ! 1170: owner_id = INPCB_OWNED_BY_X; ! 1171: } ! 1172: } ! 1173: else ! 1174: owner_id = INPCB_NO_OWNER; ! 1175: ! 1176: return owner_id; ! 1177: } ! 1178: } ! 1179: ! 1180: int ! 1181: in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id) ! 1182: { ! 1183: ! 1184: int i; ! 1185: ! 1186: ! 1187: for (i=0; i < INPCB_MAX_IDS; i++) { ! 1188: if ((pcbinfo->all_owners & (1 << i)) == 0) { ! 1189: pcbinfo->all_owners |= (1 << i); ! 1190: *owner_id = (1 << i); ! 1191: return 0; ! 1192: } ! 1193: } ! 1194: ! 1195: return ENOSPC; ! 1196: } ! 1197: ! 1198: int ! 1199: in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id) ! 1200: { ! 1201: struct inpcb *inp; ! 1202: ! 1203: ! 1204: if (pcbinfo->all_owners & owner_id) { ! 1205: pcbinfo->all_owners &= ~owner_id; ! 1206: for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { ! 1207: if (inp->nat_owner & owner_id) { ! 1208: if (inp->nat_owner == owner_id) ! 1209: /* ! 1210: * Deallocate the pcb ! 1211: */ ! 1212: in_pcbdetach(inp); ! 1213: else ! 1214: inp->nat_owner &= ~owner_id; ! 1215: } ! 1216: } ! 1217: } ! 1218: else { ! 1219: return ENOENT; ! 1220: } ! 1221: ! 1222: return 0; ! 1223: } ! 1224: ! 1225: void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily, ! 1226: int pfamily, int protocol) ! 1227: { ! 1228: bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket)); ! 1229: pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol); ! 1230: pcbinfo->all_owners = 0; ! 1231: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.