Annotation of sys/netinet/in_pcb.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: in_pcb.c,v 1.89 2007/04/10 17:47:55 miod Exp $ */
! 2: /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1991, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
! 33: *
! 34: * NRL grants permission for redistribution and use in source and binary
! 35: * forms, with or without modification, of the software and documentation
! 36: * created at NRL provided that the following conditions are met:
! 37: *
! 38: * 1. Redistributions of source code must retain the above copyright
! 39: * notice, this list of conditions and the following disclaimer.
! 40: * 2. Redistributions in binary form must reproduce the above copyright
! 41: * notice, this list of conditions and the following disclaimer in the
! 42: * documentation and/or other materials provided with the distribution.
! 43: * 3. All advertising materials mentioning features or use of this software
! 44: * must display the following acknowledgements:
! 45: * This product includes software developed by the University of
! 46: * California, Berkeley and its contributors.
! 47: * This product includes software developed at the Information
! 48: * Technology Division, US Naval Research Laboratory.
! 49: * 4. Neither the name of the NRL nor the names of its contributors
! 50: * may be used to endorse or promote products derived from this software
! 51: * without specific prior written permission.
! 52: *
! 53: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
! 54: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
! 56: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
! 57: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 58: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 59: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 60: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 61: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 62: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 63: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 64: *
! 65: * The views and conclusions contained in the software and documentation
! 66: * are those of the authors and should not be interpreted as representing
! 67: * official policies, either expressed or implied, of the US Naval
! 68: * Research Laboratory (NRL).
! 69: */
! 70:
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/mbuf.h>
! 74: #include <sys/protosw.h>
! 75: #include <sys/socket.h>
! 76: #include <sys/socketvar.h>
! 77: #include <sys/proc.h>
! 78: #include <sys/domain.h>
! 79:
! 80: #include <net/if.h>
! 81: #include <net/route.h>
! 82:
! 83: #include <netinet/in.h>
! 84: #include <netinet/in_systm.h>
! 85: #include <netinet/ip.h>
! 86: #include <netinet/in_pcb.h>
! 87: #include <netinet/in_var.h>
! 88: #include <netinet/ip_var.h>
! 89: #include <dev/rndvar.h>
! 90:
! 91: #include <sys/mount.h>
! 92: #include <nfs/nfsproto.h>
! 93:
! 94: #ifdef INET6
! 95: #include <netinet6/ip6_var.h>
! 96: #endif /* INET6 */
! 97: #ifdef IPSEC
! 98: #include <netinet/ip_esp.h>
! 99: #endif /* IPSEC */
! 100:
! 101: struct in_addr zeroin_addr;
! 102:
! 103: extern int ipsec_auth_default_level;
! 104: extern int ipsec_esp_trans_default_level;
! 105: extern int ipsec_esp_network_default_level;
! 106: extern int ipsec_ipcomp_default_level;
! 107:
! 108: /*
! 109: * These configure the range of local port addresses assigned to
! 110: * "unspecified" outgoing connections/packets/whatever.
! 111: */
! 112: int ipport_firstauto = IPPORT_RESERVED;
! 113: int ipport_lastauto = IPPORT_USERRESERVED;
! 114: int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;
! 115: int ipport_hilastauto = IPPORT_HILASTAUTO;
! 116:
! 117: struct pool inpcb_pool;
! 118: int inpcb_pool_initalized = 0;
! 119:
! 120: #define INPCBHASH(table, faddr, fport, laddr, lport) \
! 121: &(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + \
! 122: ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)]
! 123:
! 124: #define IN6PCBHASH(table, faddr, fport, laddr, lport) \
! 125: &(table)->inpt_hashtbl[(ntohl((faddr)->s6_addr32[0] ^ \
! 126: (faddr)->s6_addr32[3]) + ntohs((fport)) + ntohs((lport))) & \
! 127: (table->inpt_hash)]
! 128:
! 129: #define INPCBLHASH(table, lport) \
! 130: &(table)->inpt_lhashtbl[lport & table->inpt_lhash]
! 131:
! 132: void
! 133: in_pcbinit(table, hashsize)
! 134: struct inpcbtable *table;
! 135: int hashsize;
! 136: {
! 137:
! 138: CIRCLEQ_INIT(&table->inpt_queue);
! 139: table->inpt_hashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
! 140: &table->inpt_hash);
! 141: if (table->inpt_hashtbl == NULL)
! 142: panic("in_pcbinit: hashinit failed");
! 143: table->inpt_lhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
! 144: &table->inpt_lhash);
! 145: if (table->inpt_lhashtbl == NULL)
! 146: panic("in_pcbinit: hashinit failed for lport");
! 147: table->inpt_lastport = 0;
! 148: }
! 149:
! 150: struct baddynamicports baddynamicports;
! 151:
! 152: /*
! 153: * Check if the specified port is invalid for dynamic allocation.
! 154: */
! 155: int
! 156: in_baddynamic(port, proto)
! 157: u_int16_t port;
! 158: u_int16_t proto;
! 159: {
! 160:
! 161:
! 162: switch (proto) {
! 163: case IPPROTO_TCP:
! 164: if (port == NFS_PORT)
! 165: return (1);
! 166: if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
! 167: return (0);
! 168: return (DP_ISSET(baddynamicports.tcp, port));
! 169: case IPPROTO_UDP:
! 170: #ifdef IPSEC
! 171: if (port == udpencap_port)
! 172: return (1);
! 173: #endif
! 174: if (port == NFS_PORT)
! 175: return (1);
! 176: if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
! 177: return (0);
! 178: return (DP_ISSET(baddynamicports.udp, port));
! 179: default:
! 180: return (0);
! 181: }
! 182: }
! 183:
! 184: int
! 185: in_pcballoc(so, v)
! 186: struct socket *so;
! 187: void *v;
! 188: {
! 189: struct inpcbtable *table = v;
! 190: struct inpcb *inp;
! 191: int s;
! 192:
! 193: if (inpcb_pool_initalized == 0) {
! 194: pool_init(&inpcb_pool, sizeof(struct inpcb), 0, 0, 0,
! 195: "inpcbpl", NULL);
! 196: inpcb_pool_initalized = 1;
! 197: }
! 198: inp = pool_get(&inpcb_pool, PR_NOWAIT);
! 199: if (inp == NULL)
! 200: return (ENOBUFS);
! 201: bzero((caddr_t)inp, sizeof(*inp));
! 202: inp->inp_table = table;
! 203: inp->inp_socket = so;
! 204: inp->inp_seclevel[SL_AUTH] = ipsec_auth_default_level;
! 205: inp->inp_seclevel[SL_ESP_TRANS] = ipsec_esp_trans_default_level;
! 206: inp->inp_seclevel[SL_ESP_NETWORK] = ipsec_esp_network_default_level;
! 207: inp->inp_seclevel[SL_IPCOMP] = ipsec_ipcomp_default_level;
! 208: s = splnet();
! 209: CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
! 210: LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport), inp, inp_lhash);
! 211: LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport,
! 212: &inp->inp_laddr, inp->inp_lport), inp, inp_hash);
! 213: splx(s);
! 214: so->so_pcb = inp;
! 215: inp->inp_hops = -1;
! 216:
! 217: #ifdef INET6
! 218: /*
! 219: * Small change in this function to set the INP_IPV6 flag so routines
! 220: * outside pcb-specific routines don't need to use sotopf(), and all
! 221: * of its pointer chasing, later.
! 222: */
! 223: if (sotopf(so) == PF_INET6)
! 224: inp->inp_flags = INP_IPV6;
! 225: inp->in6p_cksum = -1;
! 226: #endif /* INET6 */
! 227: return (0);
! 228: }
! 229:
! 230: int
! 231: in_pcbbind(v, nam)
! 232: void *v;
! 233: struct mbuf *nam;
! 234: {
! 235: struct inpcb *inp = v;
! 236: struct socket *so = inp->inp_socket;
! 237: struct inpcbtable *table = inp->inp_table;
! 238: u_int16_t *lastport = &inp->inp_table->inpt_lastport;
! 239: struct sockaddr_in *sin;
! 240: struct proc *p = curproc; /* XXX */
! 241: u_int16_t lport = 0;
! 242: int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
! 243: int error;
! 244:
! 245: #ifdef INET6
! 246: if (sotopf(so) == PF_INET6)
! 247: return in6_pcbbind(inp, nam);
! 248: #endif /* INET6 */
! 249:
! 250: if (TAILQ_EMPTY(&in_ifaddr))
! 251: return (EADDRNOTAVAIL);
! 252: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
! 253: return (EINVAL);
! 254: if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
! 255: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
! 256: (so->so_options & SO_ACCEPTCONN) == 0))
! 257: wild = INPLOOKUP_WILDCARD;
! 258: if (nam) {
! 259: sin = mtod(nam, struct sockaddr_in *);
! 260: if (nam->m_len != sizeof (*sin))
! 261: return (EINVAL);
! 262: #ifdef notdef
! 263: /*
! 264: * We should check the family, but old programs
! 265: * incorrectly fail to initialize it.
! 266: */
! 267: if (sin->sin_family != AF_INET)
! 268: return (EAFNOSUPPORT);
! 269: #endif
! 270: lport = sin->sin_port;
! 271: if (IN_MULTICAST(sin->sin_addr.s_addr)) {
! 272: /*
! 273: * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
! 274: * allow complete duplication of binding if
! 275: * SO_REUSEPORT is set, or if SO_REUSEADDR is set
! 276: * and a multicast address is bound on both
! 277: * new and duplicated sockets.
! 278: */
! 279: if (so->so_options & SO_REUSEADDR)
! 280: reuseport = SO_REUSEADDR|SO_REUSEPORT;
! 281: } else if (sin->sin_addr.s_addr != INADDR_ANY) {
! 282: sin->sin_port = 0; /* yech... */
! 283: if (in_iawithaddr(sin->sin_addr, NULL) == 0)
! 284: return (EADDRNOTAVAIL);
! 285: }
! 286: if (lport) {
! 287: struct inpcb *t;
! 288:
! 289: /* GROSS */
! 290: if (ntohs(lport) < IPPORT_RESERVED &&
! 291: (error = suser(p, 0)))
! 292: return (EACCES);
! 293: if (so->so_euid) {
! 294: t = in_pcblookup(table, &zeroin_addr, 0,
! 295: &sin->sin_addr, lport, INPLOOKUP_WILDCARD);
! 296: if (t && (so->so_euid != t->inp_socket->so_euid))
! 297: return (EADDRINUSE);
! 298: }
! 299: t = in_pcblookup(table, &zeroin_addr, 0,
! 300: &sin->sin_addr, lport, wild);
! 301: if (t && (reuseport & t->inp_socket->so_options) == 0)
! 302: return (EADDRINUSE);
! 303: }
! 304: inp->inp_laddr = sin->sin_addr;
! 305: }
! 306: if (lport == 0) {
! 307: u_int16_t first, last;
! 308: int count;
! 309:
! 310: if (inp->inp_flags & INP_HIGHPORT) {
! 311: first = ipport_hifirstauto; /* sysctl */
! 312: last = ipport_hilastauto;
! 313: } else if (inp->inp_flags & INP_LOWPORT) {
! 314: if ((error = suser(p, 0)))
! 315: return (EACCES);
! 316: first = IPPORT_RESERVED-1; /* 1023 */
! 317: last = 600; /* not IPPORT_RESERVED/2 */
! 318: } else {
! 319: first = ipport_firstauto; /* sysctl */
! 320: last = ipport_lastauto;
! 321: }
! 322:
! 323: /*
! 324: * Simple check to ensure all ports are not used up causing
! 325: * a deadlock here.
! 326: *
! 327: * We split the two cases (up and down) so that the direction
! 328: * is not being tested on each round of the loop.
! 329: */
! 330:
! 331: if (first > last) {
! 332: /*
! 333: * counting down
! 334: */
! 335: count = first - last;
! 336: if (count)
! 337: *lastport = first - (arc4random() % count);
! 338:
! 339: do {
! 340: if (count-- < 0) /* completely used? */
! 341: return (EADDRNOTAVAIL);
! 342: --*lastport;
! 343: if (*lastport > first || *lastport < last)
! 344: *lastport = first;
! 345: lport = htons(*lastport);
! 346: } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
! 347: in_pcblookup(table, &zeroin_addr, 0,
! 348: &inp->inp_laddr, lport, wild));
! 349: } else {
! 350: /*
! 351: * counting up
! 352: */
! 353: count = last - first;
! 354: if (count)
! 355: *lastport = first + (arc4random() % count);
! 356:
! 357: do {
! 358: if (count-- < 0) /* completely used? */
! 359: return (EADDRNOTAVAIL);
! 360: ++*lastport;
! 361: if (*lastport < first || *lastport > last)
! 362: *lastport = first;
! 363: lport = htons(*lastport);
! 364: } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
! 365: in_pcblookup(table, &zeroin_addr, 0,
! 366: &inp->inp_laddr, lport, wild));
! 367: }
! 368: }
! 369: inp->inp_lport = lport;
! 370: in_pcbrehash(inp);
! 371: return (0);
! 372: }
! 373:
! 374: /*
! 375: * Connect from a socket to a specified address.
! 376: * Both address and port must be specified in argument sin.
! 377: * If don't have a local address for this socket yet,
! 378: * then pick one.
! 379: */
! 380: int
! 381: in_pcbconnect(v, nam)
! 382: void *v;
! 383: struct mbuf *nam;
! 384: {
! 385: struct inpcb *inp = v;
! 386: struct sockaddr_in *ifaddr = NULL;
! 387: struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
! 388:
! 389: #ifdef INET6
! 390: if (sotopf(inp->inp_socket) == PF_INET6)
! 391: return (in6_pcbconnect(inp, nam));
! 392: if ((inp->inp_flags & INP_IPV6) != 0)
! 393: panic("IPv6 pcb passed into in_pcbconnect");
! 394: #endif /* INET6 */
! 395:
! 396: if (nam->m_len != sizeof (*sin))
! 397: return (EINVAL);
! 398: if (sin->sin_family != AF_INET)
! 399: return (EAFNOSUPPORT);
! 400: if (sin->sin_port == 0)
! 401: return (EADDRNOTAVAIL);
! 402: if (!TAILQ_EMPTY(&in_ifaddr)) {
! 403: /*
! 404: * If the destination address is INADDR_ANY,
! 405: * use the primary local address.
! 406: * If the supplied address is INADDR_BROADCAST,
! 407: * and the primary interface supports broadcast,
! 408: * choose the broadcast address for that interface.
! 409: */
! 410: if (sin->sin_addr.s_addr == INADDR_ANY)
! 411: sin->sin_addr = TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr;
! 412: else if (sin->sin_addr.s_addr == INADDR_BROADCAST &&
! 413: (TAILQ_FIRST(&in_ifaddr)->ia_ifp->if_flags & IFF_BROADCAST))
! 414: sin->sin_addr = TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr;
! 415: }
! 416: if (inp->inp_laddr.s_addr == INADDR_ANY) {
! 417: int error;
! 418: ifaddr = in_selectsrc(sin, &inp->inp_route,
! 419: inp->inp_socket->so_options, inp->inp_moptions, &error);
! 420: if (ifaddr == NULL) {
! 421: if (error == 0)
! 422: error = EADDRNOTAVAIL;
! 423: return error;
! 424: }
! 425: }
! 426: if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
! 427: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
! 428: inp->inp_lport) != 0)
! 429: return (EADDRINUSE);
! 430: if (inp->inp_laddr.s_addr == INADDR_ANY) {
! 431: if (inp->inp_lport == 0 &&
! 432: in_pcbbind(inp, (struct mbuf *)0) == EADDRNOTAVAIL)
! 433: return (EADDRNOTAVAIL);
! 434: inp->inp_laddr = ifaddr->sin_addr;
! 435: }
! 436: inp->inp_faddr = sin->sin_addr;
! 437: inp->inp_fport = sin->sin_port;
! 438: in_pcbrehash(inp);
! 439: #ifdef IPSEC
! 440: {
! 441: int error; /* This is just ignored */
! 442:
! 443: /* Cause an IPsec SA to be established. */
! 444: ipsp_spd_inp(NULL, AF_INET, 0, &error, IPSP_DIRECTION_OUT,
! 445: NULL, inp, NULL);
! 446: }
! 447: #endif
! 448: return (0);
! 449: }
! 450:
! 451: void
! 452: in_pcbdisconnect(v)
! 453: void *v;
! 454: {
! 455: struct inpcb *inp = v;
! 456:
! 457: switch (sotopf(inp->inp_socket)) {
! 458: #ifdef INET6
! 459: case PF_INET6:
! 460: inp->inp_faddr6 = in6addr_any;
! 461: break;
! 462: #endif
! 463: case PF_INET:
! 464: inp->inp_faddr.s_addr = INADDR_ANY;
! 465: break;
! 466: }
! 467:
! 468: inp->inp_fport = 0;
! 469: in_pcbrehash(inp);
! 470: if (inp->inp_socket->so_state & SS_NOFDREF)
! 471: in_pcbdetach(inp);
! 472: }
! 473:
! 474: void
! 475: in_pcbdetach(v)
! 476: void *v;
! 477: {
! 478: struct inpcb *inp = v;
! 479: struct socket *so = inp->inp_socket;
! 480: int s;
! 481:
! 482: so->so_pcb = 0;
! 483: sofree(so);
! 484: if (inp->inp_options)
! 485: (void)m_freem(inp->inp_options);
! 486: if (inp->inp_route.ro_rt)
! 487: rtfree(inp->inp_route.ro_rt);
! 488: #ifdef INET6
! 489: if (inp->inp_flags & INP_IPV6)
! 490: ip6_freemoptions(inp->inp_moptions6);
! 491: else
! 492: #endif
! 493: ip_freemoptions(inp->inp_moptions);
! 494: #ifdef IPSEC
! 495: /* IPsec cleanup here */
! 496: s = spltdb();
! 497: if (inp->inp_tdb_in)
! 498: TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in,
! 499: inp, inp_tdb_in_next);
! 500: if (inp->inp_tdb_out)
! 501: TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out, inp,
! 502: inp_tdb_out_next);
! 503: if (inp->inp_ipsec_remotecred)
! 504: ipsp_reffree(inp->inp_ipsec_remotecred);
! 505: if (inp->inp_ipsec_remoteauth)
! 506: ipsp_reffree(inp->inp_ipsec_remoteauth);
! 507: if (inp->inp_ipo)
! 508: ipsec_delete_policy(inp->inp_ipo);
! 509: splx(s);
! 510: #endif
! 511: s = splnet();
! 512: LIST_REMOVE(inp, inp_lhash);
! 513: LIST_REMOVE(inp, inp_hash);
! 514: CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
! 515: splx(s);
! 516: pool_put(&inpcb_pool, inp);
! 517: }
! 518:
! 519: void
! 520: in_setsockaddr(inp, nam)
! 521: struct inpcb *inp;
! 522: struct mbuf *nam;
! 523: {
! 524: struct sockaddr_in *sin;
! 525:
! 526: nam->m_len = sizeof (*sin);
! 527: sin = mtod(nam, struct sockaddr_in *);
! 528: bzero((caddr_t)sin, sizeof (*sin));
! 529: sin->sin_family = AF_INET;
! 530: sin->sin_len = sizeof(*sin);
! 531: sin->sin_port = inp->inp_lport;
! 532: sin->sin_addr = inp->inp_laddr;
! 533: }
! 534:
! 535: void
! 536: in_setpeeraddr(inp, nam)
! 537: struct inpcb *inp;
! 538: struct mbuf *nam;
! 539: {
! 540: struct sockaddr_in *sin;
! 541:
! 542: #ifdef INET6
! 543: if (sotopf(inp->inp_socket) == PF_INET6) {
! 544: in6_setpeeraddr(inp, nam);
! 545: return;
! 546: }
! 547: #endif /* INET6 */
! 548:
! 549: nam->m_len = sizeof (*sin);
! 550: sin = mtod(nam, struct sockaddr_in *);
! 551: bzero((caddr_t)sin, sizeof (*sin));
! 552: sin->sin_family = AF_INET;
! 553: sin->sin_len = sizeof(*sin);
! 554: sin->sin_port = inp->inp_fport;
! 555: sin->sin_addr = inp->inp_faddr;
! 556: }
! 557:
! 558: /*
! 559: * Pass some notification to all connections of a protocol
! 560: * associated with address dst. The "usual action" will be
! 561: * taken, depending on the ctlinput cmd. The caller must filter any
! 562: * cmds that are uninteresting (e.g., no error in the map).
! 563: * Call the protocol specific routine (if any) to report
! 564: * any errors for each matching socket.
! 565: *
! 566: * Must be called at splsoftnet.
! 567: */
! 568: void
! 569: in_pcbnotifyall(table, dst, errno, notify)
! 570: struct inpcbtable *table;
! 571: struct sockaddr *dst;
! 572: int errno;
! 573: void (*notify)(struct inpcb *, int);
! 574: {
! 575: struct inpcb *inp, *oinp;
! 576: struct in_addr faddr;
! 577:
! 578: splassert(IPL_SOFTNET);
! 579:
! 580: #ifdef INET6
! 581: /*
! 582: * See in6_pcbnotify() for IPv6 codepath. By the time this
! 583: * gets called, the addresses passed are either definitely IPv4 or
! 584: * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses.
! 585: */
! 586: #endif /* INET6 */
! 587:
! 588: if (dst->sa_family != AF_INET)
! 589: return;
! 590: faddr = satosin(dst)->sin_addr;
! 591: if (faddr.s_addr == INADDR_ANY)
! 592: return;
! 593:
! 594: for (inp = CIRCLEQ_FIRST(&table->inpt_queue);
! 595: inp != CIRCLEQ_END(&table->inpt_queue);) {
! 596: #ifdef INET6
! 597: if (inp->inp_flags & INP_IPV6) {
! 598: inp = CIRCLEQ_NEXT(inp, inp_queue);
! 599: continue;
! 600: }
! 601: #endif
! 602: if (inp->inp_faddr.s_addr != faddr.s_addr ||
! 603: inp->inp_socket == 0) {
! 604: inp = CIRCLEQ_NEXT(inp, inp_queue);
! 605: continue;
! 606: }
! 607: oinp = inp;
! 608: inp = CIRCLEQ_NEXT(inp, inp_queue);
! 609: if (notify)
! 610: (*notify)(oinp, errno);
! 611: }
! 612: }
! 613:
! 614: /*
! 615: * Check for alternatives when higher level complains
! 616: * about service problems. For now, invalidate cached
! 617: * routing information. If the route was created dynamically
! 618: * (by a redirect), time to try a default gateway again.
! 619: */
! 620: void
! 621: in_losing(inp)
! 622: struct inpcb *inp;
! 623: {
! 624: struct rtentry *rt;
! 625: struct rt_addrinfo info;
! 626:
! 627: if ((rt = inp->inp_route.ro_rt)) {
! 628: inp->inp_route.ro_rt = 0;
! 629: bzero((caddr_t)&info, sizeof(info));
! 630: info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst;
! 631: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
! 632: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
! 633: rt_missmsg(RTM_LOSING, &info, rt->rt_flags, rt->rt_ifp, 0, 0);
! 634: if (rt->rt_flags & RTF_DYNAMIC)
! 635: (void) rtrequest(RTM_DELETE, rt_key(rt),
! 636: rt->rt_gateway, rt_mask(rt), rt->rt_flags,
! 637: (struct rtentry **)0, 0);
! 638: /*
! 639: * A new route can be allocated
! 640: * the next time output is attempted.
! 641: * rtfree() needs to be called in anycase because the inp
! 642: * is still holding a reference to rt.
! 643: */
! 644: rtfree(rt);
! 645: }
! 646: }
! 647:
! 648: /*
! 649: * After a routing change, flush old routing
! 650: * and allocate a (hopefully) better one.
! 651: */
! 652: void
! 653: in_rtchange(inp, errno)
! 654: struct inpcb *inp;
! 655: int errno;
! 656: {
! 657: if (inp->inp_route.ro_rt) {
! 658: rtfree(inp->inp_route.ro_rt);
! 659: inp->inp_route.ro_rt = 0;
! 660: /*
! 661: * A new route can be allocated the next time
! 662: * output is attempted.
! 663: */
! 664: }
! 665: }
! 666:
! 667: struct inpcb *
! 668: in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags)
! 669: struct inpcbtable *table;
! 670: void *faddrp, *laddrp;
! 671: u_int fport_arg, lport_arg;
! 672: int flags;
! 673: {
! 674: struct inpcb *inp, *match = 0;
! 675: int matchwild = 3, wildcard;
! 676: u_int16_t fport = fport_arg, lport = lport_arg;
! 677: struct in_addr faddr = *(struct in_addr *)faddrp;
! 678: struct in_addr laddr = *(struct in_addr *)laddrp;
! 679:
! 680: for (inp = LIST_FIRST(INPCBLHASH(table, lport)); inp;
! 681: inp = LIST_NEXT(inp, inp_lhash)) {
! 682: if (inp->inp_lport != lport)
! 683: continue;
! 684: wildcard = 0;
! 685: #ifdef INET6
! 686: if (flags & INPLOOKUP_IPV6) {
! 687: struct in6_addr *laddr6 = (struct in6_addr *)laddrp;
! 688: struct in6_addr *faddr6 = (struct in6_addr *)faddrp;
! 689:
! 690: if (!(inp->inp_flags & INP_IPV6))
! 691: continue;
! 692:
! 693: if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
! 694: if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
! 695: wildcard++;
! 696: else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6))
! 697: continue;
! 698: } else {
! 699: if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
! 700: wildcard++;
! 701: }
! 702:
! 703: if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
! 704: if (IN6_IS_ADDR_UNSPECIFIED(faddr6))
! 705: wildcard++;
! 706: else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
! 707: faddr6) || inp->inp_fport != fport)
! 708: continue;
! 709: } else {
! 710: if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
! 711: wildcard++;
! 712: }
! 713: } else
! 714: #endif /* INET6 */
! 715: {
! 716: #ifdef INET6
! 717: if (inp->inp_flags & INP_IPV6)
! 718: continue;
! 719: #endif /* INET6 */
! 720:
! 721: if (inp->inp_faddr.s_addr != INADDR_ANY) {
! 722: if (faddr.s_addr == INADDR_ANY)
! 723: wildcard++;
! 724: else if (inp->inp_faddr.s_addr != faddr.s_addr ||
! 725: inp->inp_fport != fport)
! 726: continue;
! 727: } else {
! 728: if (faddr.s_addr != INADDR_ANY)
! 729: wildcard++;
! 730: }
! 731: if (inp->inp_laddr.s_addr != INADDR_ANY) {
! 732: if (laddr.s_addr == INADDR_ANY)
! 733: wildcard++;
! 734: else if (inp->inp_laddr.s_addr != laddr.s_addr)
! 735: continue;
! 736: } else {
! 737: if (laddr.s_addr != INADDR_ANY)
! 738: wildcard++;
! 739: }
! 740: }
! 741: if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) &&
! 742: wildcard < matchwild) {
! 743: match = inp;
! 744: if ((matchwild = wildcard) == 0)
! 745: break;
! 746: }
! 747: }
! 748: return (match);
! 749: }
! 750:
! 751: struct rtentry *
! 752: in_pcbrtentry(inp)
! 753: struct inpcb *inp;
! 754: {
! 755: struct route *ro;
! 756:
! 757: ro = &inp->inp_route;
! 758:
! 759: /*
! 760: * No route yet, so try to acquire one.
! 761: */
! 762: if (ro->ro_rt == NULL) {
! 763: #ifdef INET6
! 764: bzero(ro, sizeof(struct route_in6));
! 765: #else
! 766: bzero(ro, sizeof(struct route));
! 767: #endif
! 768:
! 769: switch(sotopf(inp->inp_socket)) {
! 770: #ifdef INET6
! 771: case PF_INET6:
! 772: if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
! 773: break;
! 774: ro->ro_dst.sa_family = AF_INET6;
! 775: ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
! 776: ((struct sockaddr_in6 *) &ro->ro_dst)->sin6_addr =
! 777: inp->inp_faddr6;
! 778: rtalloc_mpath(ro, &inp->inp_laddr6.s6_addr32[0], 0);
! 779: break;
! 780: #endif /* INET6 */
! 781: case PF_INET:
! 782: if (inp->inp_faddr.s_addr == INADDR_ANY)
! 783: break;
! 784: ro->ro_dst.sa_family = AF_INET;
! 785: ro->ro_dst.sa_len = sizeof(ro->ro_dst);
! 786: satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
! 787: rtalloc_mpath(ro, &inp->inp_laddr.s_addr, 0);
! 788: break;
! 789: }
! 790: }
! 791: return (ro->ro_rt);
! 792: }
! 793:
! 794: struct sockaddr_in *
! 795: in_selectsrc(sin, ro, soopts, mopts, errorp)
! 796: struct sockaddr_in *sin;
! 797: struct route *ro;
! 798: int soopts;
! 799: struct ip_moptions *mopts;
! 800: int *errorp;
! 801: {
! 802: struct sockaddr_in *sin2;
! 803: struct in_ifaddr *ia;
! 804:
! 805: ia = (struct in_ifaddr *)0;
! 806: /*
! 807: * If route is known or can be allocated now,
! 808: * our src addr is taken from the i/f, else punt.
! 809: */
! 810: if (ro->ro_rt &&
! 811: (satosin(&ro->ro_dst)->sin_addr.s_addr !=
! 812: sin->sin_addr.s_addr ||
! 813: soopts & SO_DONTROUTE)) {
! 814: RTFREE(ro->ro_rt);
! 815: ro->ro_rt = (struct rtentry *)0;
! 816: }
! 817: if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/
! 818: (ro->ro_rt == (struct rtentry *)0 ||
! 819: ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
! 820: /* No route yet, so try to acquire one */
! 821: ro->ro_dst.sa_family = AF_INET;
! 822: ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
! 823: satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
! 824: rtalloc_mpath(ro, NULL, 0);
! 825:
! 826: /*
! 827: * It is important to bzero out the rest of the
! 828: * struct sockaddr_in when mixing v6 & v4!
! 829: */
! 830: sin2 = (struct sockaddr_in *)&ro->ro_dst;
! 831: bzero(sin2->sin_zero, sizeof(sin2->sin_zero));
! 832: }
! 833: /*
! 834: * If we found a route, use the address
! 835: * corresponding to the outgoing interface
! 836: * unless it is the loopback (in case a route
! 837: * to our address on another net goes to loopback).
! 838: */
! 839: if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
! 840: ia = ifatoia(ro->ro_rt->rt_ifa);
! 841: if (ia == 0) {
! 842: u_int16_t fport = sin->sin_port;
! 843:
! 844: sin->sin_port = 0;
! 845: ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
! 846: if (ia == 0)
! 847: ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
! 848: sin->sin_port = fport;
! 849: if (ia == 0)
! 850: ia = TAILQ_FIRST(&in_ifaddr);
! 851: if (ia == 0) {
! 852: *errorp = EADDRNOTAVAIL;
! 853: return NULL;
! 854: }
! 855: }
! 856: /*
! 857: * If the destination address is multicast and an outgoing
! 858: * interface has been set as a multicast option, use the
! 859: * address of that interface as our source address.
! 860: */
! 861: if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
! 862: struct ip_moptions *imo;
! 863: struct ifnet *ifp;
! 864:
! 865: imo = mopts;
! 866: if (imo->imo_multicast_ifp != NULL) {
! 867: ifp = imo->imo_multicast_ifp;
! 868: TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
! 869: if (ia->ia_ifp == ifp)
! 870: break;
! 871: if (ia == 0) {
! 872: *errorp = EADDRNOTAVAIL;
! 873: return NULL;
! 874: }
! 875: }
! 876: }
! 877: return satosin(&ia->ia_addr);
! 878: }
! 879:
! 880: void
! 881: in_pcbrehash(inp)
! 882: struct inpcb *inp;
! 883: {
! 884: struct inpcbtable *table = inp->inp_table;
! 885: int s;
! 886:
! 887: s = splnet();
! 888: LIST_REMOVE(inp, inp_lhash);
! 889: LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport), inp, inp_lhash);
! 890: LIST_REMOVE(inp, inp_hash);
! 891: #ifdef INET6
! 892: if (inp->inp_flags & INP_IPV6) {
! 893: LIST_INSERT_HEAD(IN6PCBHASH(table, &inp->inp_faddr6,
! 894: inp->inp_fport, &inp->inp_laddr6, inp->inp_lport),
! 895: inp, inp_hash);
! 896: } else {
! 897: #endif /* INET6 */
! 898: LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr,
! 899: inp->inp_fport, &inp->inp_laddr, inp->inp_lport),
! 900: inp, inp_hash);
! 901: #ifdef INET6
! 902: }
! 903: #endif /* INET6 */
! 904: splx(s);
! 905: }
! 906:
! 907: #ifdef DIAGNOSTIC
! 908: int in_pcbnotifymiss = 0;
! 909: #endif
! 910:
! 911: /*
! 912: * The in(6)_pcbhashlookup functions are used to locate connected sockets
! 913: * quickly:
! 914: * faddr.fport <-> laddr.lport
! 915: * No wildcard matching is done so that listening sockets are not found.
! 916: * If the functions return NULL in(6)_pcblookup_listen can be used to
! 917: * find a listening/bound socket that may accept the connection.
! 918: * After those two lookups no other are necessary.
! 919: */
! 920: struct inpcb *
! 921: in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
! 922: struct inpcbtable *table;
! 923: struct in_addr faddr, laddr;
! 924: u_int fport_arg, lport_arg;
! 925: {
! 926: struct inpcbhead *head;
! 927: struct inpcb *inp;
! 928: u_int16_t fport = fport_arg, lport = lport_arg;
! 929:
! 930: head = INPCBHASH(table, &faddr, fport, &laddr, lport);
! 931: LIST_FOREACH(inp, head, inp_hash) {
! 932: #ifdef INET6
! 933: if (inp->inp_flags & INP_IPV6)
! 934: continue; /*XXX*/
! 935: #endif
! 936: if (inp->inp_faddr.s_addr == faddr.s_addr &&
! 937: inp->inp_fport == fport &&
! 938: inp->inp_lport == lport &&
! 939: inp->inp_laddr.s_addr == laddr.s_addr) {
! 940: /*
! 941: * Move this PCB to the head of hash chain so that
! 942: * repeated accesses are quicker. This is analogous to
! 943: * the historic single-entry PCB cache.
! 944: */
! 945: if (inp != LIST_FIRST(head)) {
! 946: LIST_REMOVE(inp, inp_hash);
! 947: LIST_INSERT_HEAD(head, inp, inp_hash);
! 948: }
! 949: break;
! 950: }
! 951: }
! 952: #ifdef DIAGNOSTIC
! 953: if (inp == NULL && in_pcbnotifymiss) {
! 954: printf("in_pcbhashlookup: faddr=%08x fport=%d laddr=%08x lport=%d\n",
! 955: ntohl(faddr.s_addr), ntohs(fport),
! 956: ntohl(laddr.s_addr), ntohs(lport));
! 957: }
! 958: #endif
! 959: return (inp);
! 960: }
! 961:
! 962: #ifdef INET6
! 963: struct inpcb *
! 964: in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
! 965: struct inpcbtable *table;
! 966: struct in6_addr *faddr, *laddr;
! 967: u_int fport_arg, lport_arg;
! 968: {
! 969: struct inpcbhead *head;
! 970: struct inpcb *inp;
! 971: u_int16_t fport = fport_arg, lport = lport_arg;
! 972:
! 973: head = IN6PCBHASH(table, faddr, fport, laddr, lport);
! 974: LIST_FOREACH(inp, head, inp_hash) {
! 975: if (!(inp->inp_flags & INP_IPV6))
! 976: continue;
! 977: if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) &&
! 978: inp->inp_fport == fport && inp->inp_lport == lport &&
! 979: IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr)) {
! 980: /*
! 981: * Move this PCB to the head of hash chain so that
! 982: * repeated accesses are quicker. This is analogous to
! 983: * the historic single-entry PCB cache.
! 984: */
! 985: if (inp != LIST_FIRST(head)) {
! 986: LIST_REMOVE(inp, inp_hash);
! 987: LIST_INSERT_HEAD(head, inp, inp_hash);
! 988: }
! 989: break;
! 990: }
! 991: }
! 992: #ifdef DIAGNOSTIC
! 993: if (inp == NULL && in_pcbnotifymiss) {
! 994: printf("in6_pcbhashlookup: faddr=");
! 995: printf(" fport=%d laddr=", ntohs(fport));
! 996: printf(" lport=%d\n", ntohs(lport));
! 997: }
! 998: #endif
! 999: return (inp);
! 1000: }
! 1001: #endif /* INET6 */
! 1002:
! 1003: /*
! 1004: * The in(6)_pcblookup_listen functions are used to locate listening
! 1005: * sockets quickly. This are sockets with unspecified foreign address
! 1006: * and port:
! 1007: * *.* <-> laddr.lport
! 1008: * *.* <-> *.lport
! 1009: */
! 1010: struct inpcb *
! 1011: in_pcblookup_listen(table, laddr, lport_arg, reverse)
! 1012: struct inpcbtable *table;
! 1013: struct in_addr laddr;
! 1014: u_int lport_arg;
! 1015: int reverse;
! 1016: {
! 1017: struct inpcbhead *head;
! 1018: struct in_addr *key1, *key2;
! 1019: struct inpcb *inp;
! 1020: u_int16_t lport = lport_arg;
! 1021:
! 1022: if (reverse) {
! 1023: key1 = &zeroin_addr;
! 1024: key2 = &laddr;
! 1025: } else {
! 1026: key1 = &laddr;
! 1027: key2 = &zeroin_addr;
! 1028: }
! 1029:
! 1030: head = INPCBHASH(table, &zeroin_addr, 0, key1, lport);
! 1031: LIST_FOREACH(inp, head, inp_hash) {
! 1032: #ifdef INET6
! 1033: if (inp->inp_flags & INP_IPV6)
! 1034: continue; /*XXX*/
! 1035: #endif
! 1036: if (inp->inp_lport == lport && inp->inp_fport == 0 &&
! 1037: inp->inp_laddr.s_addr == key1->s_addr &&
! 1038: inp->inp_faddr.s_addr == INADDR_ANY)
! 1039: break;
! 1040: }
! 1041: if (inp == NULL && key1->s_addr != key2->s_addr) {
! 1042: head = INPCBHASH(table, &zeroin_addr, 0, key2, lport);
! 1043: LIST_FOREACH(inp, head, inp_hash) {
! 1044: #ifdef INET6
! 1045: if (inp->inp_flags & INP_IPV6)
! 1046: continue; /*XXX*/
! 1047: #endif
! 1048: if (inp->inp_lport == lport && inp->inp_fport == 0 &&
! 1049: inp->inp_laddr.s_addr == key2->s_addr &&
! 1050: inp->inp_faddr.s_addr == INADDR_ANY)
! 1051: break;
! 1052: }
! 1053: }
! 1054: #ifdef DIAGNOSTIC
! 1055: if (inp == NULL && in_pcbnotifymiss) {
! 1056: printf("in_pcblookup_listen: laddr=%08x lport=%d\n",
! 1057: ntohl(laddr.s_addr), ntohs(lport));
! 1058: }
! 1059: #endif
! 1060: /*
! 1061: * Move this PCB to the head of hash chain so that
! 1062: * repeated accesses are quicker. This is analogous to
! 1063: * the historic single-entry PCB cache.
! 1064: */
! 1065: if (inp != NULL && inp != LIST_FIRST(head)) {
! 1066: LIST_REMOVE(inp, inp_hash);
! 1067: LIST_INSERT_HEAD(head, inp, inp_hash);
! 1068: }
! 1069: return (inp);
! 1070: }
! 1071:
! 1072: #ifdef INET6
! 1073: struct inpcb *
! 1074: in6_pcblookup_listen(table, laddr, lport_arg, reverse)
! 1075: struct inpcbtable *table;
! 1076: struct in6_addr *laddr;
! 1077: u_int lport_arg;
! 1078: int reverse;
! 1079: {
! 1080: struct inpcbhead *head;
! 1081: struct in6_addr *key1, *key2;
! 1082: struct inpcb *inp;
! 1083: u_int16_t lport = lport_arg;
! 1084:
! 1085: if (reverse) {
! 1086: key1 = &zeroin6_addr;
! 1087: key2 = laddr;
! 1088: } else {
! 1089: key1 = laddr;
! 1090: key2 = &zeroin6_addr;
! 1091: }
! 1092:
! 1093: head = IN6PCBHASH(table, &zeroin6_addr, 0, key1, lport);
! 1094: LIST_FOREACH(inp, head, inp_hash) {
! 1095: if (!(inp->inp_flags & INP_IPV6))
! 1096: continue;
! 1097: if (inp->inp_lport == lport && inp->inp_fport == 0 &&
! 1098: IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key1) &&
! 1099: IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
! 1100: break;
! 1101: }
! 1102: if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) {
! 1103: head = IN6PCBHASH(table, &zeroin6_addr, 0, key2, lport);
! 1104: LIST_FOREACH(inp, head, inp_hash) {
! 1105: if (!(inp->inp_flags & INP_IPV6))
! 1106: continue;
! 1107: if (inp->inp_lport == lport && inp->inp_fport == 0 &&
! 1108: IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key2) &&
! 1109: IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
! 1110: break;
! 1111: }
! 1112: }
! 1113: #ifdef DIAGNOSTIC
! 1114: if (inp == NULL && in_pcbnotifymiss) {
! 1115: printf("in6_pcblookup_listen: laddr= lport=%d\n",
! 1116: ntohs(lport));
! 1117: }
! 1118: #endif
! 1119: /*
! 1120: * Move this PCB to the head of hash chain so that
! 1121: * repeated accesses are quicker. This is analogous to
! 1122: * the historic single-entry PCB cache.
! 1123: */
! 1124: if (inp != NULL && inp != LIST_FIRST(head)) {
! 1125: LIST_REMOVE(inp, inp_hash);
! 1126: LIST_INSERT_HEAD(head, inp, inp_hash);
! 1127: }
! 1128: return (inp);
! 1129: }
! 1130: #endif /* INET6 */
CVSweb