The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/in_pcb.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1982, 1986, 1991, 1993, 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 4. Neither the name of the University nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
   30  * $FreeBSD: releng/6.0/sys/netinet/in_pcb.c 149331 2005-08-20 13:34:59Z rwatson $
   31  */
   32 
   33 #include "opt_ipsec.h"
   34 #include "opt_inet6.h"
   35 #include "opt_mac.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/mac.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/domain.h>
   43 #include <sys/protosw.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/proc.h>
   47 #include <sys/jail.h>
   48 #include <sys/kernel.h>
   49 #include <sys/sysctl.h>
   50 
   51 #include <vm/uma.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_types.h>
   55 #include <net/route.h>
   56 
   57 #include <netinet/in.h>
   58 #include <netinet/in_pcb.h>
   59 #include <netinet/in_var.h>
   60 #include <netinet/ip_var.h>
   61 #include <netinet/tcp_var.h>
   62 #include <netinet/udp.h>
   63 #include <netinet/udp_var.h>
   64 #ifdef INET6
   65 #include <netinet/ip6.h>
   66 #include <netinet6/ip6_var.h>
   67 #endif /* INET6 */
   68 
   69 #ifdef IPSEC
   70 #include <netinet6/ipsec.h>
   71 #include <netkey/key.h>
   72 #endif /* IPSEC */
   73 
   74 #ifdef FAST_IPSEC
   75 #if defined(IPSEC) || defined(IPSEC_ESP)
   76 #error "Bad idea: don't compile with both IPSEC and FAST_IPSEC!"
   77 #endif
   78 
   79 #include <netipsec/ipsec.h>
   80 #include <netipsec/key.h>
   81 #endif /* FAST_IPSEC */
   82 
   83 /*
   84  * These configure the range of local port addresses assigned to
   85  * "unspecified" outgoing connections/packets/whatever.
   86  */
   87 int     ipport_lowfirstauto  = IPPORT_RESERVED - 1;     /* 1023 */
   88 int     ipport_lowlastauto = IPPORT_RESERVEDSTART;      /* 600 */
   89 int     ipport_firstauto = IPPORT_HIFIRSTAUTO;          /* 49152 */
   90 int     ipport_lastauto  = IPPORT_HILASTAUTO;           /* 65535 */
   91 int     ipport_hifirstauto = IPPORT_HIFIRSTAUTO;        /* 49152 */
   92 int     ipport_hilastauto  = IPPORT_HILASTAUTO;         /* 65535 */
   93 
   94 /*
   95  * Reserved ports accessible only to root. There are significant
   96  * security considerations that must be accounted for when changing these,
   97  * but the security benefits can be great. Please be careful.
   98  */
   99 int     ipport_reservedhigh = IPPORT_RESERVED - 1;      /* 1023 */
  100 int     ipport_reservedlow = 0;
  101 
  102 /* Variables dealing with random ephemeral port allocation. */
  103 int     ipport_randomized = 1;  /* user controlled via sysctl */
  104 int     ipport_randomcps = 10;  /* user controlled via sysctl */
  105 int     ipport_randomtime = 45; /* user controlled via sysctl */
  106 int     ipport_stoprandom = 0;  /* toggled by ipport_tick */
  107 int     ipport_tcpallocs;
  108 int     ipport_tcplastcount;
  109 
  110 #define RANGECHK(var, min, max) \
  111         if ((var) < (min)) { (var) = (min); } \
  112         else if ((var) > (max)) { (var) = (max); }
  113 
  114 static int
  115 sysctl_net_ipport_check(SYSCTL_HANDLER_ARGS)
  116 {
  117         int error;
  118 
  119         error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
  120         if (error == 0) {
  121                 RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
  122                 RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
  123                 RANGECHK(ipport_firstauto, IPPORT_RESERVED, IPPORT_MAX);
  124                 RANGECHK(ipport_lastauto, IPPORT_RESERVED, IPPORT_MAX);
  125                 RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, IPPORT_MAX);
  126                 RANGECHK(ipport_hilastauto, IPPORT_RESERVED, IPPORT_MAX);
  127         }
  128         return (error);
  129 }
  130 
  131 #undef RANGECHK
  132 
  133 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
  134 
  135 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
  136            &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
  137 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
  138            &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
  139 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
  140            &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
  141 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
  142            &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
  143 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
  144            &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
  145 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
  146            &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
  147 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedhigh,
  148            CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedhigh, 0, "");
  149 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedlow,
  150            CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedlow, 0, "");
  151 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomized, CTLFLAG_RW,
  152            &ipport_randomized, 0, "Enable random port allocation");
  153 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomcps, CTLFLAG_RW,
  154            &ipport_randomcps, 0, "Maximum number of random port "
  155            "allocations before switching to a sequental one");
  156 SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomtime, CTLFLAG_RW,
  157            &ipport_randomtime, 0, "Minimum time to keep sequental port "
  158            "allocation before switching to a random one");
  159 
  160 /*
  161  * in_pcb.c: manage the Protocol Control Blocks.
  162  *
  163  * NOTE: It is assumed that most of these functions will be called with
  164  * the pcbinfo lock held, and often, the inpcb lock held, as these utility
  165  * functions often modify hash chains or addresses in pcbs.
  166  */
  167 
  168 /*
  169  * Allocate a PCB and associate it with the socket.
  170  */
  171 int
  172 in_pcballoc(so, pcbinfo, type)
  173         struct socket *so;
  174         struct inpcbinfo *pcbinfo;
  175         const char *type;
  176 {
  177         register struct inpcb *inp;
  178         int error;
  179 
  180         INP_INFO_WLOCK_ASSERT(pcbinfo);
  181         error = 0;
  182         inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT | M_ZERO);
  183         if (inp == NULL)
  184                 return (ENOBUFS);
  185         inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
  186         inp->inp_pcbinfo = pcbinfo;
  187         inp->inp_socket = so;
  188 #ifdef MAC
  189         error = mac_init_inpcb(inp, M_NOWAIT);
  190         if (error != 0)
  191                 goto out;
  192         SOCK_LOCK(so);
  193         mac_create_inpcb_from_socket(so, inp);
  194         SOCK_UNLOCK(so);
  195 #endif
  196 #if defined(IPSEC) || defined(FAST_IPSEC)
  197 #ifdef FAST_IPSEC
  198         error = ipsec_init_policy(so, &inp->inp_sp);
  199 #else
  200         error = ipsec_init_pcbpolicy(so, &inp->inp_sp);
  201 #endif
  202         if (error != 0)
  203                 goto out;
  204 #endif /*IPSEC*/
  205 #if defined(INET6)
  206         if (INP_SOCKAF(so) == AF_INET6) {
  207                 inp->inp_vflag |= INP_IPV6PROTO;
  208                 if (ip6_v6only)
  209                         inp->inp_flags |= IN6P_IPV6_V6ONLY;
  210         }
  211 #endif
  212         LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
  213         pcbinfo->ipi_count++;
  214         so->so_pcb = (caddr_t)inp;
  215         INP_LOCK_INIT(inp, "inp", type);
  216 #ifdef INET6
  217         if (ip6_auto_flowlabel)
  218                 inp->inp_flags |= IN6P_AUTOFLOWLABEL;
  219 #endif
  220 #if defined(IPSEC) || defined(FAST_IPSEC) || defined(MAC)
  221 out:
  222         if (error != 0)
  223                 uma_zfree(pcbinfo->ipi_zone, inp);
  224 #endif
  225         return (error);
  226 }
  227 
  228 int
  229 in_pcbbind(inp, nam, cred)
  230         register struct inpcb *inp;
  231         struct sockaddr *nam;
  232         struct ucred *cred;
  233 {
  234         int anonport, error;
  235 
  236         INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
  237         INP_LOCK_ASSERT(inp);
  238 
  239         if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY)
  240                 return (EINVAL);
  241         anonport = inp->inp_lport == 0 && (nam == NULL ||
  242             ((struct sockaddr_in *)nam)->sin_port == 0);
  243         error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr,
  244             &inp->inp_lport, cred);
  245         if (error)
  246                 return (error);
  247         if (in_pcbinshash(inp) != 0) {
  248                 inp->inp_laddr.s_addr = INADDR_ANY;
  249                 inp->inp_lport = 0;
  250                 return (EAGAIN);
  251         }
  252         if (anonport)
  253                 inp->inp_flags |= INP_ANONPORT;
  254         return (0);
  255 }
  256 
  257 /*
  258  * Set up a bind operation on a PCB, performing port allocation
  259  * as required, but do not actually modify the PCB. Callers can
  260  * either complete the bind by setting inp_laddr/inp_lport and
  261  * calling in_pcbinshash(), or they can just use the resulting
  262  * port and address to authorise the sending of a once-off packet.
  263  *
  264  * On error, the values of *laddrp and *lportp are not changed.
  265  */
  266 int
  267 in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
  268         struct inpcb *inp;
  269         struct sockaddr *nam;
  270         in_addr_t *laddrp;
  271         u_short *lportp;
  272         struct ucred *cred;
  273 {
  274         struct socket *so = inp->inp_socket;
  275         unsigned short *lastport;
  276         struct sockaddr_in *sin;
  277         struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
  278         struct in_addr laddr;
  279         u_short lport = 0;
  280         int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
  281         int error, prison = 0;
  282         int dorandom;
  283 
  284         INP_INFO_WLOCK_ASSERT(pcbinfo);
  285         INP_LOCK_ASSERT(inp);
  286 
  287         if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
  288                 return (EADDRNOTAVAIL);
  289         laddr.s_addr = *laddrp;
  290         if (nam != NULL && laddr.s_addr != INADDR_ANY)
  291                 return (EINVAL);
  292         if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
  293                 wild = 1;
  294         if (nam) {
  295                 sin = (struct sockaddr_in *)nam;
  296                 if (nam->sa_len != sizeof (*sin))
  297                         return (EINVAL);
  298 #ifdef notdef
  299                 /*
  300                  * We should check the family, but old programs
  301                  * incorrectly fail to initialize it.
  302                  */
  303                 if (sin->sin_family != AF_INET)
  304                         return (EAFNOSUPPORT);
  305 #endif
  306                 if (sin->sin_addr.s_addr != INADDR_ANY)
  307                         if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
  308                                 return(EINVAL);
  309                 if (sin->sin_port != *lportp) {
  310                         /* Don't allow the port to change. */
  311                         if (*lportp != 0)
  312                                 return (EINVAL);
  313                         lport = sin->sin_port;
  314                 }
  315                 /* NB: lport is left as 0 if the port isn't being changed. */
  316                 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
  317                         /*
  318                          * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
  319                          * allow complete duplication of binding if
  320                          * SO_REUSEPORT is set, or if SO_REUSEADDR is set
  321                          * and a multicast address is bound on both
  322                          * new and duplicated sockets.
  323                          */
  324                         if (so->so_options & SO_REUSEADDR)
  325                                 reuseport = SO_REUSEADDR|SO_REUSEPORT;
  326                 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
  327                         sin->sin_port = 0;              /* yech... */
  328                         bzero(&sin->sin_zero, sizeof(sin->sin_zero));
  329                         if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
  330                                 return (EADDRNOTAVAIL);
  331                 }
  332                 laddr = sin->sin_addr;
  333                 if (lport) {
  334                         struct inpcb *t;
  335                         /* GROSS */
  336                         if (ntohs(lport) <= ipport_reservedhigh &&
  337                             ntohs(lport) >= ipport_reservedlow &&
  338                             suser_cred(cred, SUSER_ALLOWJAIL))
  339                                 return (EACCES);
  340                         if (jailed(cred))
  341                                 prison = 1;
  342                         if (so->so_cred->cr_uid != 0 &&
  343                             !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
  344                                 t = in_pcblookup_local(inp->inp_pcbinfo,
  345                                     sin->sin_addr, lport,
  346                                     prison ? 0 :  INPLOOKUP_WILDCARD);
  347         /*
  348          * XXX
  349          * This entire block sorely needs a rewrite.
  350          */
  351                                 if (t &&
  352                                     ((t->inp_vflag & INP_TIMEWAIT) == 0) &&
  353                                     (so->so_type != SOCK_STREAM ||
  354                                      ntohl(t->inp_faddr.s_addr) == INADDR_ANY) &&
  355                                     (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
  356                                      ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
  357                                      (t->inp_socket->so_options &
  358                                          SO_REUSEPORT) == 0) &&
  359                                     (so->so_cred->cr_uid !=
  360                                      t->inp_socket->so_cred->cr_uid))
  361                                         return (EADDRINUSE);
  362                         }
  363                         if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr))
  364                                 return (EADDRNOTAVAIL);
  365                         t = in_pcblookup_local(pcbinfo, sin->sin_addr,
  366                             lport, prison ? 0 : wild);
  367                         if (t && (t->inp_vflag & INP_TIMEWAIT)) {
  368                                 if ((reuseport & intotw(t)->tw_so_options) == 0)
  369                                         return (EADDRINUSE);
  370                         } else
  371                         if (t &&
  372                             (reuseport & t->inp_socket->so_options) == 0) {
  373 #if defined(INET6)
  374                                 if (ntohl(sin->sin_addr.s_addr) !=
  375                                     INADDR_ANY ||
  376                                     ntohl(t->inp_laddr.s_addr) !=
  377                                     INADDR_ANY ||
  378                                     INP_SOCKAF(so) ==
  379                                     INP_SOCKAF(t->inp_socket))
  380 #endif /* defined(INET6) */
  381                                 return (EADDRINUSE);
  382                         }
  383                 }
  384         }
  385         if (*lportp != 0)
  386                 lport = *lportp;
  387         if (lport == 0) {
  388                 u_short first, last;
  389                 int count;
  390 
  391                 if (laddr.s_addr != INADDR_ANY)
  392                         if (prison_ip(cred, 0, &laddr.s_addr))
  393                                 return (EINVAL);
  394 
  395                 if (inp->inp_flags & INP_HIGHPORT) {
  396                         first = ipport_hifirstauto;     /* sysctl */
  397                         last  = ipport_hilastauto;
  398                         lastport = &pcbinfo->lasthi;
  399                 } else if (inp->inp_flags & INP_LOWPORT) {
  400                         if ((error = suser_cred(cred, SUSER_ALLOWJAIL)) != 0)
  401                                 return error;
  402                         first = ipport_lowfirstauto;    /* 1023 */
  403                         last  = ipport_lowlastauto;     /* 600 */
  404                         lastport = &pcbinfo->lastlow;
  405                 } else {
  406                         first = ipport_firstauto;       /* sysctl */
  407                         last  = ipport_lastauto;
  408                         lastport = &pcbinfo->lastport;
  409                 }
  410                 /*
  411                  * For UDP, use random port allocation as long as the user
  412                  * allows it.  For TCP (and as of yet unknown) connections,
  413                  * use random port allocation only if the user allows it AND
  414                  * ipport_tick() allows it.
  415                  */
  416                 if (ipport_randomized &&
  417                         (!ipport_stoprandom || pcbinfo == &udbinfo))
  418                         dorandom = 1;
  419                 else
  420                         dorandom = 0;
  421                 /*
  422                  * It makes no sense to do random port allocation if
  423                  * we have the only port available.
  424                  */
  425                 if (first == last)
  426                         dorandom = 0;
  427                 /* Make sure to not include UDP packets in the count. */
  428                 if (pcbinfo != &udbinfo)
  429                         ipport_tcpallocs++;
  430                 /*
  431                  * Simple check to ensure all ports are not used up causing
  432                  * a deadlock here.
  433                  *
  434                  * We split the two cases (up and down) so that the direction
  435                  * is not being tested on each round of the loop.
  436                  */
  437                 if (first > last) {
  438                         /*
  439                          * counting down
  440                          */
  441                         if (dorandom)
  442                                 *lastport = first -
  443                                             (arc4random() % (first - last));
  444                         count = first - last;
  445 
  446                         do {
  447                                 if (count-- < 0)        /* completely used? */
  448                                         return (EADDRNOTAVAIL);
  449                                 --*lastport;
  450                                 if (*lastport > first || *lastport < last)
  451                                         *lastport = first;
  452                                 lport = htons(*lastport);
  453                         } while (in_pcblookup_local(pcbinfo, laddr, lport,
  454                             wild));
  455                 } else {
  456                         /*
  457                          * counting up
  458                          */
  459                         if (dorandom)
  460                                 *lastport = first +
  461                                             (arc4random() % (last - first));
  462                         count = last - first;
  463 
  464                         do {
  465                                 if (count-- < 0)        /* completely used? */
  466                                         return (EADDRNOTAVAIL);
  467                                 ++*lastport;
  468                                 if (*lastport < first || *lastport > last)
  469                                         *lastport = first;
  470                                 lport = htons(*lastport);
  471                         } while (in_pcblookup_local(pcbinfo, laddr, lport,
  472                             wild));
  473                 }
  474         }
  475         if (prison_ip(cred, 0, &laddr.s_addr))
  476                 return (EINVAL);
  477         *laddrp = laddr.s_addr;
  478         *lportp = lport;
  479         return (0);
  480 }
  481 
  482 /*
  483  * Connect from a socket to a specified address.
  484  * Both address and port must be specified in argument sin.
  485  * If don't have a local address for this socket yet,
  486  * then pick one.
  487  */
  488 int
  489 in_pcbconnect(inp, nam, cred)
  490         register struct inpcb *inp;
  491         struct sockaddr *nam;
  492         struct ucred *cred;
  493 {
  494         u_short lport, fport;
  495         in_addr_t laddr, faddr;
  496         int anonport, error;
  497 
  498         INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
  499         INP_LOCK_ASSERT(inp);
  500 
  501         lport = inp->inp_lport;
  502         laddr = inp->inp_laddr.s_addr;
  503         anonport = (lport == 0);
  504         error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport,
  505             NULL, cred);
  506         if (error)
  507                 return (error);
  508 
  509         /* Do the initial binding of the local address if required. */
  510         if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) {
  511                 inp->inp_lport = lport;
  512                 inp->inp_laddr.s_addr = laddr;
  513                 if (in_pcbinshash(inp) != 0) {
  514                         inp->inp_laddr.s_addr = INADDR_ANY;
  515                         inp->inp_lport = 0;
  516                         return (EAGAIN);
  517                 }
  518         }
  519 
  520         /* Commit the remaining changes. */
  521         inp->inp_lport = lport;
  522         inp->inp_laddr.s_addr = laddr;
  523         inp->inp_faddr.s_addr = faddr;
  524         inp->inp_fport = fport;
  525         in_pcbrehash(inp);
  526 #ifdef IPSEC
  527         if (inp->inp_socket->so_type == SOCK_STREAM)
  528                 ipsec_pcbconn(inp->inp_sp);
  529 #endif
  530         if (anonport)
  531                 inp->inp_flags |= INP_ANONPORT;
  532         return (0);
  533 }
  534 
  535 /*
  536  * Set up for a connect from a socket to the specified address.
  537  * On entry, *laddrp and *lportp should contain the current local
  538  * address and port for the PCB; these are updated to the values
  539  * that should be placed in inp_laddr and inp_lport to complete
  540  * the connect.
  541  *
  542  * On success, *faddrp and *fportp will be set to the remote address
  543  * and port. These are not updated in the error case.
  544  *
  545  * If the operation fails because the connection already exists,
  546  * *oinpp will be set to the PCB of that connection so that the
  547  * caller can decide to override it. In all other cases, *oinpp
  548  * is set to NULL.
  549  */
  550 int
  551 in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, cred)
  552         register struct inpcb *inp;
  553         struct sockaddr *nam;
  554         in_addr_t *laddrp;
  555         u_short *lportp;
  556         in_addr_t *faddrp;
  557         u_short *fportp;
  558         struct inpcb **oinpp;
  559         struct ucred *cred;
  560 {
  561         struct sockaddr_in *sin = (struct sockaddr_in *)nam;
  562         struct in_ifaddr *ia;
  563         struct sockaddr_in sa;
  564         struct ucred *socred;
  565         struct inpcb *oinp;
  566         struct in_addr laddr, faddr;
  567         u_short lport, fport;
  568         int error;
  569 
  570         INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
  571         INP_LOCK_ASSERT(inp);
  572 
  573         if (oinpp != NULL)
  574                 *oinpp = NULL;
  575         if (nam->sa_len != sizeof (*sin))
  576                 return (EINVAL);
  577         if (sin->sin_family != AF_INET)
  578                 return (EAFNOSUPPORT);
  579         if (sin->sin_port == 0)
  580                 return (EADDRNOTAVAIL);
  581         laddr.s_addr = *laddrp;
  582         lport = *lportp;
  583         faddr = sin->sin_addr;
  584         fport = sin->sin_port;
  585         socred = inp->inp_socket->so_cred;
  586         if (laddr.s_addr == INADDR_ANY && jailed(socred)) {
  587                 bzero(&sa, sizeof(sa));
  588                 sa.sin_addr.s_addr = htonl(prison_getip(socred));
  589                 sa.sin_len = sizeof(sa);
  590                 sa.sin_family = AF_INET;
  591                 error = in_pcbbind_setup(inp, (struct sockaddr *)&sa,
  592                     &laddr.s_addr, &lport, cred);
  593                 if (error)
  594                         return (error);
  595         }
  596         if (!TAILQ_EMPTY(&in_ifaddrhead)) {
  597                 /*
  598                  * If the destination address is INADDR_ANY,
  599                  * use the primary local address.
  600                  * If the supplied address is INADDR_BROADCAST,
  601                  * and the primary interface supports broadcast,
  602                  * choose the broadcast address for that interface.
  603                  */
  604                 if (faddr.s_addr == INADDR_ANY)
  605                         faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
  606                 else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
  607                     (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags &
  608                     IFF_BROADCAST))
  609                         faddr = satosin(&TAILQ_FIRST(
  610                             &in_ifaddrhead)->ia_broadaddr)->sin_addr;
  611         }
  612         if (laddr.s_addr == INADDR_ANY) {
  613                 struct route sro;
  614 
  615                 bzero(&sro, sizeof(sro));
  616                 ia = (struct in_ifaddr *)0;
  617                 /*
  618                  * If route is known our src addr is taken from the i/f,
  619                  * else punt.
  620                  */
  621                 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) {
  622                         /* Find out route to destination */
  623                         sro.ro_dst.sa_family = AF_INET;
  624                         sro.ro_dst.sa_len = sizeof(struct sockaddr_in);
  625                         ((struct sockaddr_in *)&sro.ro_dst)->sin_addr = faddr;
  626                         rtalloc_ign(&sro, RTF_CLONING);
  627                 }
  628                 /*
  629                  * If we found a route, use the address
  630                  * corresponding to the outgoing interface.
  631                  */
  632                 if (sro.ro_rt) {
  633                         ia = ifatoia(sro.ro_rt->rt_ifa);
  634                         RTFREE(sro.ro_rt);
  635                 }
  636                 if (ia == 0) {
  637                         bzero(&sa, sizeof(sa));
  638                         sa.sin_addr = faddr;
  639                         sa.sin_len = sizeof(sa);
  640                         sa.sin_family = AF_INET;
  641 
  642                         ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sa)));
  643                         if (ia == 0)
  644                                 ia = ifatoia(ifa_ifwithnet(sintosa(&sa)));
  645                         if (ia == 0)
  646                                 return (ENETUNREACH);
  647                 }
  648                 /*
  649                  * If the destination address is multicast and an outgoing
  650                  * interface has been set as a multicast option, use the
  651                  * address of that interface as our source address.
  652                  */
  653                 if (IN_MULTICAST(ntohl(faddr.s_addr)) &&
  654                     inp->inp_moptions != NULL) {
  655                         struct ip_moptions *imo;
  656                         struct ifnet *ifp;
  657 
  658                         imo = inp->inp_moptions;
  659                         if (imo->imo_multicast_ifp != NULL) {
  660                                 ifp = imo->imo_multicast_ifp;
  661                                 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
  662                                         if (ia->ia_ifp == ifp)
  663                                                 break;
  664                                 if (ia == 0)
  665                                         return (EADDRNOTAVAIL);
  666                         }
  667                 }
  668                 laddr = ia->ia_addr.sin_addr;
  669         }
  670 
  671         oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport,
  672             0, NULL);
  673         if (oinp != NULL) {
  674                 if (oinpp != NULL)
  675                         *oinpp = oinp;
  676                 return (EADDRINUSE);
  677         }
  678         if (lport == 0) {
  679                 error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport,
  680                     cred);
  681                 if (error)
  682                         return (error);
  683         }
  684         *laddrp = laddr.s_addr;
  685         *lportp = lport;
  686         *faddrp = faddr.s_addr;
  687         *fportp = fport;
  688         return (0);
  689 }
  690 
  691 void
  692 in_pcbdisconnect(inp)
  693         struct inpcb *inp;
  694 {
  695 
  696         INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
  697         INP_LOCK_ASSERT(inp);
  698 
  699         inp->inp_faddr.s_addr = INADDR_ANY;
  700         inp->inp_fport = 0;
  701         in_pcbrehash(inp);
  702 #ifdef IPSEC
  703         ipsec_pcbdisconn(inp->inp_sp);
  704 #endif
  705         if (inp->inp_socket->so_state & SS_NOFDREF)
  706                 in_pcbdetach(inp);
  707 }
  708 
  709 void
  710 in_pcbdetach(inp)
  711         struct inpcb *inp;
  712 {
  713         struct socket *so = inp->inp_socket;
  714         struct inpcbinfo *ipi = inp->inp_pcbinfo;
  715 
  716         INP_INFO_WLOCK_ASSERT(ipi);
  717         INP_LOCK_ASSERT(inp);
  718 
  719 #if defined(IPSEC) || defined(FAST_IPSEC)
  720         ipsec4_delete_pcbpolicy(inp);
  721 #endif /*IPSEC*/
  722         inp->inp_gencnt = ++ipi->ipi_gencnt;
  723         in_pcbremlists(inp);
  724         if (so) {
  725                 ACCEPT_LOCK();
  726                 SOCK_LOCK(so);
  727                 so->so_pcb = NULL;
  728                 sotryfree(so);
  729         }
  730         if (inp->inp_options)
  731                 (void)m_free(inp->inp_options);
  732         ip_freemoptions(inp->inp_moptions);
  733         inp->inp_vflag = 0;
  734         INP_LOCK_DESTROY(inp);
  735 #ifdef MAC
  736         mac_destroy_inpcb(inp);
  737 #endif
  738         uma_zfree(ipi->ipi_zone, inp);
  739 }
  740 
  741 struct sockaddr *
  742 in_sockaddr(port, addr_p)
  743         in_port_t port;
  744         struct in_addr *addr_p;
  745 {
  746         struct sockaddr_in *sin;
  747 
  748         MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
  749                 M_WAITOK | M_ZERO);
  750         sin->sin_family = AF_INET;
  751         sin->sin_len = sizeof(*sin);
  752         sin->sin_addr = *addr_p;
  753         sin->sin_port = port;
  754 
  755         return (struct sockaddr *)sin;
  756 }
  757 
  758 /*
  759  * The wrapper function will pass down the pcbinfo for this function to lock.
  760  * The socket must have a valid
  761  * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
  762  * except through a kernel programming error, so it is acceptable to panic
  763  * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
  764  * because there actually /is/ a programming error somewhere... XXX)
  765  */
  766 int
  767 in_setsockaddr(so, nam, pcbinfo)
  768         struct socket *so;
  769         struct sockaddr **nam;
  770         struct inpcbinfo *pcbinfo;
  771 {
  772         register struct inpcb *inp;
  773         struct in_addr addr;
  774         in_port_t port;
  775 
  776         INP_INFO_RLOCK(pcbinfo);
  777         inp = sotoinpcb(so);
  778         if (!inp) {
  779                 INP_INFO_RUNLOCK(pcbinfo);
  780                 return ECONNRESET;
  781         }
  782         INP_LOCK(inp);
  783         port = inp->inp_lport;
  784         addr = inp->inp_laddr;
  785         INP_UNLOCK(inp);
  786         INP_INFO_RUNLOCK(pcbinfo);
  787 
  788         *nam = in_sockaddr(port, &addr);
  789         return 0;
  790 }
  791 
  792 /*
  793  * The wrapper function will pass down the pcbinfo for this function to lock.
  794  */
  795 int
  796 in_setpeeraddr(so, nam, pcbinfo)
  797         struct socket *so;
  798         struct sockaddr **nam;
  799         struct inpcbinfo *pcbinfo;
  800 {
  801         register struct inpcb *inp;
  802         struct in_addr addr;
  803         in_port_t port;
  804 
  805         INP_INFO_RLOCK(pcbinfo);
  806         inp = sotoinpcb(so);
  807         if (!inp) {
  808                 INP_INFO_RUNLOCK(pcbinfo);
  809                 return ECONNRESET;
  810         }
  811         INP_LOCK(inp);
  812         port = inp->inp_fport;
  813         addr = inp->inp_faddr;
  814         INP_UNLOCK(inp);
  815         INP_INFO_RUNLOCK(pcbinfo);
  816 
  817         *nam = in_sockaddr(port, &addr);
  818         return 0;
  819 }
  820 
  821 void
  822 in_pcbnotifyall(pcbinfo, faddr, errno, notify)
  823         struct inpcbinfo *pcbinfo;
  824         struct in_addr faddr;
  825         int errno;
  826         struct inpcb *(*notify)(struct inpcb *, int);
  827 {
  828         struct inpcb *inp, *ninp;
  829         struct inpcbhead *head;
  830 
  831         INP_INFO_WLOCK(pcbinfo);
  832         head = pcbinfo->listhead;
  833         for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
  834                 INP_LOCK(inp);
  835                 ninp = LIST_NEXT(inp, inp_list);
  836 #ifdef INET6
  837                 if ((inp->inp_vflag & INP_IPV4) == 0) {
  838                         INP_UNLOCK(inp);
  839                         continue;
  840                 }
  841 #endif
  842                 if (inp->inp_faddr.s_addr != faddr.s_addr ||
  843                     inp->inp_socket == NULL) {
  844                         INP_UNLOCK(inp);
  845                         continue;
  846                 }
  847                 if ((*notify)(inp, errno))
  848                         INP_UNLOCK(inp);
  849         }
  850         INP_INFO_WUNLOCK(pcbinfo);
  851 }
  852 
  853 void
  854 in_pcbpurgeif0(pcbinfo, ifp)
  855         struct inpcbinfo *pcbinfo;
  856         struct ifnet *ifp;
  857 {
  858         struct inpcb *inp;
  859         struct ip_moptions *imo;
  860         int i, gap;
  861 
  862         INP_INFO_RLOCK(pcbinfo);
  863         LIST_FOREACH(inp, pcbinfo->listhead, inp_list) {
  864                 INP_LOCK(inp);
  865                 imo = inp->inp_moptions;
  866                 if ((inp->inp_vflag & INP_IPV4) &&
  867                     imo != NULL) {
  868                         /*
  869                          * Unselect the outgoing interface if it is being
  870                          * detached.
  871                          */
  872                         if (imo->imo_multicast_ifp == ifp)
  873                                 imo->imo_multicast_ifp = NULL;
  874 
  875                         /*
  876                          * Drop multicast group membership if we joined
  877                          * through the interface being detached.
  878                          */
  879                         for (i = 0, gap = 0; i < imo->imo_num_memberships;
  880                             i++) {
  881                                 if (imo->imo_membership[i]->inm_ifp == ifp) {
  882                                         in_delmulti(imo->imo_membership[i]);
  883                                         gap++;
  884                                 } else if (gap != 0)
  885                                         imo->imo_membership[i - gap] =
  886                                             imo->imo_membership[i];
  887                         }
  888                         imo->imo_num_memberships -= gap;
  889                 }
  890                 INP_UNLOCK(inp);
  891         }
  892         INP_INFO_RUNLOCK(pcbinfo);
  893 }
  894 
  895 /*
  896  * Lookup a PCB based on the local address and port.
  897  */
  898 struct inpcb *
  899 in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
  900         struct inpcbinfo *pcbinfo;
  901         struct in_addr laddr;
  902         u_int lport_arg;
  903         int wild_okay;
  904 {
  905         register struct inpcb *inp;
  906         int matchwild = 3, wildcard;
  907         u_short lport = lport_arg;
  908 
  909         INP_INFO_WLOCK_ASSERT(pcbinfo);
  910 
  911         if (!wild_okay) {
  912                 struct inpcbhead *head;
  913                 /*
  914                  * Look for an unconnected (wildcard foreign addr) PCB that
  915                  * matches the local address and port we're looking for.
  916                  */
  917                 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
  918                 LIST_FOREACH(inp, head, inp_hash) {
  919 #ifdef INET6
  920                         if ((inp->inp_vflag & INP_IPV4) == 0)
  921                                 continue;
  922 #endif
  923                         if (inp->inp_faddr.s_addr == INADDR_ANY &&
  924                             inp->inp_laddr.s_addr == laddr.s_addr &&
  925                             inp->inp_lport == lport) {
  926                                 /*
  927                                  * Found.
  928                                  */
  929                                 return (inp);
  930                         }
  931                 }
  932                 /*
  933                  * Not found.
  934                  */
  935                 return (NULL);
  936         } else {
  937                 struct inpcbporthead *porthash;
  938                 struct inpcbport *phd;
  939                 struct inpcb *match = NULL;
  940                 /*
  941                  * Best fit PCB lookup.
  942                  *
  943                  * First see if this local port is in use by looking on the
  944                  * port hash list.
  945                  */
  946                 retrylookup:
  947                 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
  948                     pcbinfo->porthashmask)];
  949                 LIST_FOREACH(phd, porthash, phd_hash) {
  950                         if (phd->phd_port == lport)
  951                                 break;
  952                 }
  953                 if (phd != NULL) {
  954                         /*
  955                          * Port is in use by one or more PCBs. Look for best
  956                          * fit.
  957                          */
  958                         LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
  959                                 wildcard = 0;
  960 #ifdef INET6
  961                                 if ((inp->inp_vflag & INP_IPV4) == 0)
  962                                         continue;
  963 #endif
  964                                 /*
  965                                  * Clean out old time_wait sockets if they
  966                                  * are clogging up needed local ports.
  967                                  */
  968                                 if ((inp->inp_vflag & INP_TIMEWAIT) != 0) {
  969                                         if (tcp_twrecycleable((struct tcptw *)inp->inp_ppcb)) {
  970                                                 INP_LOCK(inp);
  971                                                 tcp_twclose((struct tcptw *)inp->inp_ppcb, 0);
  972                                                 match = NULL;
  973                                                 goto retrylookup;
  974                                         }
  975                                 }
  976                                 if (inp->inp_faddr.s_addr != INADDR_ANY)
  977                                         wildcard++;
  978                                 if (inp->inp_laddr.s_addr != INADDR_ANY) {
  979                                         if (laddr.s_addr == INADDR_ANY)
  980                                                 wildcard++;
  981                                         else if (inp->inp_laddr.s_addr != laddr.s_addr)
  982                                                 continue;
  983                                 } else {
  984                                         if (laddr.s_addr != INADDR_ANY)
  985                                                 wildcard++;
  986                                 }
  987                                 if (wildcard < matchwild) {
  988                                         match = inp;
  989                                         matchwild = wildcard;
  990                                         if (matchwild == 0) {
  991                                                 break;
  992                                         }
  993                                 }
  994                         }
  995                 }
  996                 return (match);
  997         }
  998 }
  999 
 1000 /*
 1001  * Lookup PCB in hash list.
 1002  */
 1003 struct inpcb *
 1004 in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
 1005                   ifp)
 1006         struct inpcbinfo *pcbinfo;
 1007         struct in_addr faddr, laddr;
 1008         u_int fport_arg, lport_arg;
 1009         int wildcard;
 1010         struct ifnet *ifp;
 1011 {
 1012         struct inpcbhead *head;
 1013         register struct inpcb *inp;
 1014         u_short fport = fport_arg, lport = lport_arg;
 1015 
 1016         INP_INFO_RLOCK_ASSERT(pcbinfo);
 1017         /*
 1018          * First look for an exact match.
 1019          */
 1020         head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
 1021         LIST_FOREACH(inp, head, inp_hash) {
 1022 #ifdef INET6
 1023                 if ((inp->inp_vflag & INP_IPV4) == 0)
 1024                         continue;
 1025 #endif
 1026                 if (inp->inp_faddr.s_addr == faddr.s_addr &&
 1027                     inp->inp_laddr.s_addr == laddr.s_addr &&
 1028                     inp->inp_fport == fport &&
 1029                     inp->inp_lport == lport) {
 1030                         /*
 1031                          * Found.
 1032                          */
 1033                         return (inp);
 1034                 }
 1035         }
 1036         if (wildcard) {
 1037                 struct inpcb *local_wild = NULL;
 1038 #if defined(INET6)
 1039                 struct inpcb *local_wild_mapped = NULL;
 1040 #endif /* defined(INET6) */
 1041 
 1042                 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
 1043                 LIST_FOREACH(inp, head, inp_hash) {
 1044 #ifdef INET6
 1045                         if ((inp->inp_vflag & INP_IPV4) == 0)
 1046                                 continue;
 1047 #endif
 1048                         if (inp->inp_faddr.s_addr == INADDR_ANY &&
 1049                             inp->inp_lport == lport) {
 1050                                 if (ifp && ifp->if_type == IFT_FAITH &&
 1051                                     (inp->inp_flags & INP_FAITH) == 0)
 1052                                         continue;
 1053                                 if (inp->inp_laddr.s_addr == laddr.s_addr)
 1054                                         return (inp);
 1055                                 else if (inp->inp_laddr.s_addr == INADDR_ANY) {
 1056 #if defined(INET6)
 1057                                         if (INP_CHECK_SOCKAF(inp->inp_socket,
 1058                                                              AF_INET6))
 1059                                                 local_wild_mapped = inp;
 1060                                         else
 1061 #endif /* defined(INET6) */
 1062                                         local_wild = inp;
 1063                                 }
 1064                         }
 1065                 }
 1066 #if defined(INET6)
 1067                 if (local_wild == NULL)
 1068                         return (local_wild_mapped);
 1069 #endif /* defined(INET6) */
 1070                 return (local_wild);
 1071         }
 1072 
 1073         /*
 1074          * Not found.
 1075          */
 1076         return (NULL);
 1077 }
 1078 
 1079 /*
 1080  * Insert PCB onto various hash lists.
 1081  */
 1082 int
 1083 in_pcbinshash(inp)
 1084         struct inpcb *inp;
 1085 {
 1086         struct inpcbhead *pcbhash;
 1087         struct inpcbporthead *pcbporthash;
 1088         struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
 1089         struct inpcbport *phd;
 1090         u_int32_t hashkey_faddr;
 1091 
 1092         INP_INFO_WLOCK_ASSERT(pcbinfo);
 1093 #ifdef INET6
 1094         if (inp->inp_vflag & INP_IPV6)
 1095                 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
 1096         else
 1097 #endif /* INET6 */
 1098         hashkey_faddr = inp->inp_faddr.s_addr;
 1099 
 1100         pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
 1101                  inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
 1102 
 1103         pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
 1104             pcbinfo->porthashmask)];
 1105 
 1106         /*
 1107          * Go through port list and look for a head for this lport.
 1108          */
 1109         LIST_FOREACH(phd, pcbporthash, phd_hash) {
 1110                 if (phd->phd_port == inp->inp_lport)
 1111                         break;
 1112         }
 1113         /*
 1114          * If none exists, malloc one and tack it on.
 1115          */
 1116         if (phd == NULL) {
 1117                 MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
 1118                 if (phd == NULL) {
 1119                         return (ENOBUFS); /* XXX */
 1120                 }
 1121                 phd->phd_port = inp->inp_lport;
 1122                 LIST_INIT(&phd->phd_pcblist);
 1123                 LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
 1124         }
 1125         inp->inp_phd = phd;
 1126         LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
 1127         LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
 1128         return (0);
 1129 }
 1130 
 1131 /*
 1132  * Move PCB to the proper hash bucket when { faddr, fport } have  been
 1133  * changed. NOTE: This does not handle the case of the lport changing (the
 1134  * hashed port list would have to be updated as well), so the lport must
 1135  * not change after in_pcbinshash() has been called.
 1136  */
 1137 void
 1138 in_pcbrehash(inp)
 1139         struct inpcb *inp;
 1140 {
 1141         struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
 1142         struct inpcbhead *head;
 1143         u_int32_t hashkey_faddr;
 1144 
 1145         INP_INFO_WLOCK_ASSERT(pcbinfo);
 1146         INP_LOCK_ASSERT(inp);
 1147 #ifdef INET6
 1148         if (inp->inp_vflag & INP_IPV6)
 1149                 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
 1150         else
 1151 #endif /* INET6 */
 1152         hashkey_faddr = inp->inp_faddr.s_addr;
 1153 
 1154         head = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
 1155                 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
 1156 
 1157         LIST_REMOVE(inp, inp_hash);
 1158         LIST_INSERT_HEAD(head, inp, inp_hash);
 1159 }
 1160 
 1161 /*
 1162  * Remove PCB from various lists.
 1163  */
 1164 void
 1165 in_pcbremlists(inp)
 1166         struct inpcb *inp;
 1167 {
 1168         struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
 1169 
 1170         INP_INFO_WLOCK_ASSERT(pcbinfo);
 1171         INP_LOCK_ASSERT(inp);
 1172 
 1173         inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
 1174         if (inp->inp_lport) {
 1175                 struct inpcbport *phd = inp->inp_phd;
 1176 
 1177                 LIST_REMOVE(inp, inp_hash);
 1178                 LIST_REMOVE(inp, inp_portlist);
 1179                 if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
 1180                         LIST_REMOVE(phd, phd_hash);
 1181                         free(phd, M_PCB);
 1182                 }
 1183         }
 1184         LIST_REMOVE(inp, inp_list);
 1185         pcbinfo->ipi_count--;
 1186 }
 1187 
 1188 /*
 1189  * A set label operation has occurred at the socket layer, propagate the
 1190  * label change into the in_pcb for the socket.
 1191  */
 1192 void
 1193 in_pcbsosetlabel(so)
 1194         struct socket *so;
 1195 {
 1196 #ifdef MAC
 1197         struct inpcb *inp;
 1198 
 1199         inp = (struct inpcb *)so->so_pcb;
 1200         INP_LOCK(inp);
 1201         SOCK_LOCK(so);
 1202         mac_inpcb_sosetlabel(so, inp);
 1203         SOCK_UNLOCK(so);
 1204         INP_UNLOCK(inp);
 1205 #endif
 1206 }
 1207 
 1208 /*
 1209  * ipport_tick runs once per second, determining if random port
 1210  * allocation should be continued.  If more than ipport_randomcps
 1211  * ports have been allocated in the last second, then we return to
 1212  * sequential port allocation. We return to random allocation only
 1213  * once we drop below ipport_randomcps for at least ipport_randomtime
 1214  * seconds.
 1215  */
 1216 
 1217 void
 1218 ipport_tick(xtp)
 1219         void *xtp;
 1220 {
 1221         if (ipport_tcpallocs > ipport_tcplastcount + ipport_randomcps) {
 1222                 ipport_stoprandom = ipport_randomtime;
 1223         } else {
 1224                 if (ipport_stoprandom > 0)
 1225                         ipport_stoprandom--;
 1226         }
 1227         ipport_tcplastcount = ipport_tcpallocs;
 1228         callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL);
 1229 }

Cache object: 04adbe80339aa0317b7432e1a5b2d85b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.