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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: in_pcb.c,v 1.129.4.1 2009/05/10 20:45:45 snj Exp $     */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*-
   33  * Copyright (c) 1998 The NetBSD Foundation, Inc.
   34  * All rights reserved.
   35  *
   36  * This code is derived from software contributed to The NetBSD Foundation
   37  * by Public Access Networks Corporation ("Panix").  It was developed under
   38  * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
   39  *
   40  * Redistribution and use in source and binary forms, with or without
   41  * modification, are permitted provided that the following conditions
   42  * are met:
   43  * 1. Redistributions of source code must retain the above copyright
   44  *    notice, this list of conditions and the following disclaimer.
   45  * 2. Redistributions in binary form must reproduce the above copyright
   46  *    notice, this list of conditions and the following disclaimer in the
   47  *    documentation and/or other materials provided with the distribution.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   50  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   51  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   52  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   53  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   54  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   55  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   56  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   57  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   58  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   59  * POSSIBILITY OF SUCH DAMAGE.
   60  */
   61 
   62 /*
   63  * Copyright (c) 1982, 1986, 1991, 1993, 1995
   64  *      The Regents of the University of California.  All rights reserved.
   65  *
   66  * Redistribution and use in source and binary forms, with or without
   67  * modification, are permitted provided that the following conditions
   68  * are met:
   69  * 1. Redistributions of source code must retain the above copyright
   70  *    notice, this list of conditions and the following disclaimer.
   71  * 2. Redistributions in binary form must reproduce the above copyright
   72  *    notice, this list of conditions and the following disclaimer in the
   73  *    documentation and/or other materials provided with the distribution.
   74  * 3. Neither the name of the University nor the names of its contributors
   75  *    may be used to endorse or promote products derived from this software
   76  *    without specific prior written permission.
   77  *
   78  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   79  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   80  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   81  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   82  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   83  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   84  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   85  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   86  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   87  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   88  * SUCH DAMAGE.
   89  *
   90  *      @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
   91  */
   92 
   93 #include <sys/cdefs.h>
   94 __KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.129.4.1 2009/05/10 20:45:45 snj Exp $");
   95 
   96 #include "opt_inet.h"
   97 #include "opt_ipsec.h"
   98 
   99 #include <sys/param.h>
  100 #include <sys/systm.h>
  101 #include <sys/malloc.h>
  102 #include <sys/mbuf.h>
  103 #include <sys/protosw.h>
  104 #include <sys/socket.h>
  105 #include <sys/socketvar.h>
  106 #include <sys/ioctl.h>
  107 #include <sys/errno.h>
  108 #include <sys/time.h>
  109 #include <sys/once.h>
  110 #include <sys/pool.h>
  111 #include <sys/proc.h>
  112 #include <sys/kauth.h>
  113 #include <sys/uidinfo.h>
  114 
  115 #include <net/if.h>
  116 #include <net/route.h>
  117 
  118 #include <netinet/in.h>
  119 #include <netinet/in_systm.h>
  120 #include <netinet/ip.h>
  121 #include <netinet/in_pcb.h>
  122 #include <netinet/in_var.h>
  123 #include <netinet/ip_var.h>
  124 
  125 #ifdef INET6
  126 #include <netinet/ip6.h>
  127 #include <netinet6/ip6_var.h>
  128 #include <netinet6/in6_pcb.h>
  129 #endif
  130 
  131 #ifdef IPSEC
  132 #include <netinet6/ipsec.h>
  133 #include <netkey/key.h>
  134 #elif FAST_IPSEC
  135 #include <netipsec/ipsec.h>
  136 #include <netipsec/key.h>
  137 #endif /* IPSEC */
  138 
  139 struct  in_addr zeroin_addr;
  140 
  141 #define INPCBHASH_PORT(table, lport) \
  142         &(table)->inpt_porthashtbl[ntohs(lport) & (table)->inpt_porthash]
  143 #define INPCBHASH_BIND(table, laddr, lport) \
  144         &(table)->inpt_bindhashtbl[ \
  145             ((ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_bindhash]
  146 #define INPCBHASH_CONNECT(table, faddr, fport, laddr, lport) \
  147         &(table)->inpt_connecthashtbl[ \
  148             ((ntohl((faddr).s_addr) + ntohs(fport)) + \
  149              (ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_connecthash]
  150 
  151 int     anonportmin = IPPORT_ANONMIN;
  152 int     anonportmax = IPPORT_ANONMAX;
  153 int     lowportmin  = IPPORT_RESERVEDMIN;
  154 int     lowportmax  = IPPORT_RESERVEDMAX;
  155 
  156 static struct pool inpcb_pool;
  157 
  158 static int
  159 inpcb_poolinit(void)
  160 {
  161 
  162         pool_init(&inpcb_pool, sizeof(struct inpcb), 0, 0, 0, "inpcbpl", NULL,
  163             IPL_NET);
  164         return 0;
  165 }
  166 
  167 void
  168 in_pcbinit(struct inpcbtable *table, int bindhashsize, int connecthashsize)
  169 {
  170         static ONCE_DECL(control);
  171 
  172         CIRCLEQ_INIT(&table->inpt_queue);
  173         table->inpt_porthashtbl = hashinit(bindhashsize, HASH_LIST, true,
  174             &table->inpt_porthash);
  175         table->inpt_bindhashtbl = hashinit(bindhashsize, HASH_LIST, true,
  176             &table->inpt_bindhash);
  177         table->inpt_connecthashtbl = hashinit(connecthashsize, HASH_LIST, true,
  178             &table->inpt_connecthash);
  179         table->inpt_lastlow = IPPORT_RESERVEDMAX;
  180         table->inpt_lastport = (u_int16_t)anonportmax;
  181 
  182         RUN_ONCE(&control, inpcb_poolinit);
  183 }
  184 
  185 int
  186 in_pcballoc(struct socket *so, void *v)
  187 {
  188         struct inpcbtable *table = v;
  189         struct inpcb *inp;
  190         int s;
  191 #if defined(IPSEC) || defined(FAST_IPSEC)
  192         int error;
  193 #endif
  194 
  195         s = splnet();
  196         inp = pool_get(&inpcb_pool, PR_NOWAIT);
  197         splx(s);
  198         if (inp == NULL)
  199                 return (ENOBUFS);
  200         bzero((void *)inp, sizeof(*inp));
  201         inp->inp_af = AF_INET;
  202         inp->inp_table = table;
  203         inp->inp_socket = so;
  204         inp->inp_errormtu = -1;
  205 #if defined(IPSEC) || defined(FAST_IPSEC)
  206         error = ipsec_init_pcbpolicy(so, &inp->inp_sp);
  207         if (error != 0) {
  208                 s = splnet();
  209                 pool_put(&inpcb_pool, inp);
  210                 splx(s);
  211                 return error;
  212         }
  213 #endif
  214         so->so_pcb = inp;
  215         s = splnet();
  216         CIRCLEQ_INSERT_HEAD(&table->inpt_queue, &inp->inp_head,
  217             inph_queue);
  218         LIST_INSERT_HEAD(INPCBHASH_PORT(table, inp->inp_lport), &inp->inp_head,
  219             inph_lhash);
  220         in_pcbstate(inp, INP_ATTACHED);
  221         splx(s);
  222         return (0);
  223 }
  224 
  225 int
  226 in_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
  227 {
  228         struct in_ifaddr *ia = NULL;
  229         struct inpcb *inp = v;
  230         struct socket *so = inp->inp_socket;
  231         struct inpcbtable *table = inp->inp_table;
  232         struct sockaddr_in *sin = NULL; /* XXXGCC */
  233         u_int16_t lport = 0;
  234         int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
  235 #ifndef IPNOPRIVPORTS
  236         kauth_cred_t cred = l->l_cred;
  237 #endif
  238 
  239         if (inp->inp_af != AF_INET)
  240                 return (EINVAL);
  241 
  242         if (TAILQ_FIRST(&in_ifaddrhead) == 0)
  243                 return (EADDRNOTAVAIL);
  244         if (inp->inp_lport || !in_nullhost(inp->inp_laddr))
  245                 return (EINVAL);
  246         if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
  247                 wild = 1;
  248         if (nam == 0)
  249                 goto noname;
  250         sin = mtod(nam, struct sockaddr_in *);
  251         if (nam->m_len != sizeof (*sin))
  252                 return (EINVAL);
  253         if (sin->sin_family != AF_INET)
  254                 return (EAFNOSUPPORT);
  255         lport = sin->sin_port;
  256         if (IN_MULTICAST(sin->sin_addr.s_addr)) {
  257                 /*
  258                  * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
  259                  * allow complete duplication of binding if
  260                  * SO_REUSEPORT is set, or if SO_REUSEADDR is set
  261                  * and a multicast address is bound on both
  262                  * new and duplicated sockets.
  263                  */
  264                 if (so->so_options & SO_REUSEADDR)
  265                         reuseport = SO_REUSEADDR|SO_REUSEPORT;
  266         } else if (!in_nullhost(sin->sin_addr)) {
  267                 sin->sin_port = 0;              /* yech... */
  268                 INADDR_TO_IA(sin->sin_addr, ia);
  269                 /* check for broadcast addresses */
  270                 if (ia == NULL)
  271                         ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
  272                 if (ia == NULL)
  273                         return (EADDRNOTAVAIL);
  274         }
  275         if (lport) {
  276                 struct inpcb *t;
  277 #ifdef INET6
  278                 struct in6pcb *t6;
  279                 struct in6_addr mapped;
  280 #endif
  281 #ifndef IPNOPRIVPORTS
  282                 /* GROSS */
  283                 if (ntohs(lport) < IPPORT_RESERVED &&
  284                     kauth_authorize_network(cred,
  285                     KAUTH_NETWORK_BIND,
  286                     KAUTH_REQ_NETWORK_BIND_PRIVPORT, so, sin,
  287                     NULL))
  288                         return (EACCES);
  289 #endif
  290 #ifdef INET6
  291                 memset(&mapped, 0, sizeof(mapped));
  292                 mapped.s6_addr16[5] = 0xffff;
  293                 memcpy(&mapped.s6_addr32[3], &sin->sin_addr,
  294                     sizeof(mapped.s6_addr32[3]));
  295                 t6 = in6_pcblookup_port(table, &mapped, lport, wild);
  296                 if (t6 && (reuseport & t6->in6p_socket->so_options) == 0)
  297                         return (EADDRINUSE);
  298 #endif
  299                 if (so->so_uidinfo->ui_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
  300                         t = in_pcblookup_port(table, sin->sin_addr, lport, 1);
  301                 /*
  302                  * XXX: investigate ramifications of loosening this
  303                  *      restriction so that as long as both ports have
  304                  *      SO_REUSEPORT allow the bind
  305                  */
  306                         if (t &&
  307                             (!in_nullhost(sin->sin_addr) ||
  308                              !in_nullhost(t->inp_laddr) ||
  309                              (t->inp_socket->so_options & SO_REUSEPORT) == 0)
  310                             && (so->so_uidinfo->ui_uid != t->inp_socket->so_uidinfo->ui_uid)) {
  311                                 return (EADDRINUSE);
  312                         }
  313                 }
  314                 t = in_pcblookup_port(table, sin->sin_addr, lport, wild);
  315                 if (t && (reuseport & t->inp_socket->so_options) == 0)
  316                         return (EADDRINUSE);
  317         }
  318         inp->inp_laddr = sin->sin_addr;
  319 
  320 noname:
  321         if (lport == 0) {
  322                 int        cnt;
  323                 u_int16_t  mymin, mymax;
  324                 u_int16_t *lastport;
  325 
  326                 if (inp->inp_flags & INP_LOWPORT) {
  327 #ifndef IPNOPRIVPORTS
  328                         if (kauth_authorize_network(cred,
  329                             KAUTH_NETWORK_BIND,
  330                             KAUTH_REQ_NETWORK_BIND_PRIVPORT, so,
  331                             sin, NULL))
  332                                 return (EACCES);
  333 #endif
  334                         mymin = lowportmin;
  335                         mymax = lowportmax;
  336                         lastport = &table->inpt_lastlow;
  337                 } else {
  338                         mymin = anonportmin;
  339                         mymax = anonportmax;
  340                         lastport = &table->inpt_lastport;
  341                 }
  342                 if (mymin > mymax) {    /* sanity check */
  343                         u_int16_t swp;
  344 
  345                         swp = mymin;
  346                         mymin = mymax;
  347                         mymax = swp;
  348                 }
  349 
  350                 lport = *lastport - 1;
  351                 for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
  352                         if (lport < mymin || lport > mymax)
  353                                 lport = mymax;
  354                         if (!in_pcblookup_port(table, inp->inp_laddr,
  355                             htons(lport), 1))
  356                                 goto found;
  357                 }
  358                 if (!in_nullhost(inp->inp_laddr))
  359                         inp->inp_laddr.s_addr = INADDR_ANY;
  360                 return (EAGAIN);
  361         found:
  362                 inp->inp_flags |= INP_ANONPORT;
  363                 *lastport = lport;
  364                 lport = htons(lport);
  365         }
  366         inp->inp_lport = lport;
  367         LIST_REMOVE(&inp->inp_head, inph_lhash);
  368         LIST_INSERT_HEAD(INPCBHASH_PORT(table, inp->inp_lport), &inp->inp_head,
  369             inph_lhash);
  370         in_pcbstate(inp, INP_BOUND);
  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(void *v, struct mbuf *nam, struct lwp *l)
  382 {
  383         struct inpcb *inp = v;
  384         struct in_ifaddr *ia = NULL;
  385         struct sockaddr_in *ifaddr = NULL;
  386         struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  387         int error;
  388 
  389         if (inp->inp_af != AF_INET)
  390                 return (EINVAL);
  391 
  392         if (nam->m_len != sizeof (*sin))
  393                 return (EINVAL);
  394         if (sin->sin_family != AF_INET)
  395                 return (EAFNOSUPPORT);
  396         if (sin->sin_port == 0)
  397                 return (EADDRNOTAVAIL);
  398         if (TAILQ_FIRST(&in_ifaddrhead) != 0) {
  399                 /*
  400                  * If the destination address is INADDR_ANY,
  401                  * use any local address (likely loopback).
  402                  * If the supplied address is INADDR_BROADCAST,
  403                  * use the broadcast address of an interface
  404                  * which supports broadcast. (loopback does not)
  405                  */
  406 
  407                 if (in_nullhost(sin->sin_addr)) {
  408                         sin->sin_addr =
  409                             TAILQ_FIRST(&in_ifaddrhead)->ia_addr.sin_addr;
  410                 } else if (sin->sin_addr.s_addr == INADDR_BROADCAST) {
  411                         TAILQ_FOREACH(ia, &in_ifaddrhead, ia_list) {
  412                                 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
  413                                         sin->sin_addr =
  414                                             ia->ia_broadaddr.sin_addr;
  415                                         break;
  416                                 }
  417                         }
  418                 }
  419         }
  420         /*
  421          * If we haven't bound which network number to use as ours,
  422          * we will use the number of the outgoing interface.
  423          * This depends on having done a routing lookup, which
  424          * we will probably have to do anyway, so we might
  425          * as well do it now.  On the other hand if we are
  426          * sending to multiple destinations we may have already
  427          * done the lookup, so see if we can use the route
  428          * from before.  In any case, we only
  429          * chose a port number once, even if sending to multiple
  430          * destinations.
  431          */
  432         if (in_nullhost(inp->inp_laddr)) {
  433                 int xerror;
  434                 ifaddr = in_selectsrc(sin, &inp->inp_route,
  435                     inp->inp_socket->so_options, inp->inp_moptions, &xerror);
  436                 if (ifaddr == NULL) {
  437                         if (xerror == 0)
  438                                 xerror = EADDRNOTAVAIL;
  439                         return xerror;
  440                 }
  441                 INADDR_TO_IA(ifaddr->sin_addr, ia);
  442                 if (ia == NULL)
  443                         return (EADDRNOTAVAIL);
  444         }
  445         if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
  446             !in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
  447             inp->inp_lport) != 0)
  448                 return (EADDRINUSE);
  449         if (in_nullhost(inp->inp_laddr)) {
  450                 if (inp->inp_lport == 0) {
  451                         error = in_pcbbind(inp, NULL, l);
  452                         /*
  453                          * This used to ignore the return value
  454                          * completely, but we need to check for
  455                          * ephemeral port shortage.
  456                          * And attempts to request low ports if not root.
  457                          */
  458                         if (error != 0)
  459                                 return (error);
  460                 }
  461                 inp->inp_laddr = ifaddr->sin_addr;
  462         }
  463         inp->inp_faddr = sin->sin_addr;
  464         inp->inp_fport = sin->sin_port;
  465         in_pcbstate(inp, INP_CONNECTED);
  466 #if defined(IPSEC) || defined(FAST_IPSEC)
  467         if (inp->inp_socket->so_type == SOCK_STREAM)
  468                 ipsec_pcbconn(inp->inp_sp);
  469 #endif
  470         return (0);
  471 }
  472 
  473 void
  474 in_pcbdisconnect(void *v)
  475 {
  476         struct inpcb *inp = v;
  477 
  478         if (inp->inp_af != AF_INET)
  479                 return;
  480 
  481         inp->inp_faddr = zeroin_addr;
  482         inp->inp_fport = 0;
  483         in_pcbstate(inp, INP_BOUND);
  484 #if defined(IPSEC) || defined(FAST_IPSEC)
  485         ipsec_pcbdisconn(inp->inp_sp);
  486 #endif
  487         if (inp->inp_socket->so_state & SS_NOFDREF)
  488                 in_pcbdetach(inp);
  489 }
  490 
  491 void
  492 in_pcbdetach(void *v)
  493 {
  494         struct inpcb *inp = v;
  495         struct socket *so = inp->inp_socket;
  496         int s;
  497 
  498         if (inp->inp_af != AF_INET)
  499                 return;
  500 
  501 #if defined(IPSEC) || defined(FAST_IPSEC)
  502         ipsec4_delete_pcbpolicy(inp);
  503 #endif /*IPSEC*/
  504         so->so_pcb = 0;
  505         if (inp->inp_options)
  506                 (void)m_free(inp->inp_options);
  507         rtcache_free(&inp->inp_route);
  508         ip_freemoptions(inp->inp_moptions);
  509         s = splnet();
  510         in_pcbstate(inp, INP_ATTACHED);
  511         LIST_REMOVE(&inp->inp_head, inph_lhash);
  512         CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, &inp->inp_head,
  513             inph_queue);
  514         pool_put(&inpcb_pool, inp);
  515         splx(s);
  516         sofree(so);                     /* drops the socket's lock */
  517         mutex_enter(softnet_lock);      /* reacquire the softnet_lock */
  518 }
  519 
  520 void
  521 in_setsockaddr(struct inpcb *inp, struct mbuf *nam)
  522 {
  523         struct sockaddr_in *sin;
  524 
  525         if (inp->inp_af != AF_INET)
  526                 return;
  527 
  528         sin = mtod(nam, struct sockaddr_in *);
  529         sockaddr_in_init(sin, &inp->inp_laddr, inp->inp_lport);
  530         nam->m_len = sin->sin_len;
  531 }
  532 
  533 void
  534 in_setpeeraddr(struct inpcb *inp, struct mbuf *nam)
  535 {
  536         struct sockaddr_in *sin;
  537 
  538         if (inp->inp_af != AF_INET)
  539                 return;
  540 
  541         sin = mtod(nam, struct sockaddr_in *);
  542         sockaddr_in_init(sin, &inp->inp_faddr, inp->inp_fport);
  543         nam->m_len = sin->sin_len;
  544 }
  545 
  546 /*
  547  * Pass some notification to all connections of a protocol
  548  * associated with address dst.  The local address and/or port numbers
  549  * may be specified to limit the search.  The "usual action" will be
  550  * taken, depending on the ctlinput cmd.  The caller must filter any
  551  * cmds that are uninteresting (e.g., no error in the map).
  552  * Call the protocol specific routine (if any) to report
  553  * any errors for each matching socket.
  554  *
  555  * Must be called at splsoftnet.
  556  */
  557 int
  558 in_pcbnotify(struct inpcbtable *table, struct in_addr faddr, u_int fport_arg,
  559     struct in_addr laddr, u_int lport_arg, int errno,
  560     void (*notify)(struct inpcb *, int))
  561 {
  562         struct inpcbhead *head;
  563         struct inpcb *inp, *ninp;
  564         u_int16_t fport = fport_arg, lport = lport_arg;
  565         int nmatch;
  566 
  567         if (in_nullhost(faddr) || notify == 0)
  568                 return (0);
  569 
  570         nmatch = 0;
  571         head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
  572         for (inp = (struct inpcb *)LIST_FIRST(head); inp != NULL; inp = ninp) {
  573                 ninp = (struct inpcb *)LIST_NEXT(inp, inp_hash);
  574                 if (inp->inp_af != AF_INET)
  575                         continue;
  576                 if (in_hosteq(inp->inp_faddr, faddr) &&
  577                     inp->inp_fport == fport &&
  578                     inp->inp_lport == lport &&
  579                     in_hosteq(inp->inp_laddr, laddr)) {
  580                         (*notify)(inp, errno);
  581                         nmatch++;
  582                 }
  583         }
  584         return (nmatch);
  585 }
  586 
  587 void
  588 in_pcbnotifyall(struct inpcbtable *table, struct in_addr faddr, int errno,
  589     void (*notify)(struct inpcb *, int))
  590 {
  591         struct inpcb *inp, *ninp;
  592 
  593         if (in_nullhost(faddr) || notify == 0)
  594                 return;
  595 
  596         for (inp = (struct inpcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  597             inp != (void *)&table->inpt_queue;
  598             inp = ninp) {
  599                 ninp = (struct inpcb *)CIRCLEQ_NEXT(inp, inp_queue);
  600                 if (inp->inp_af != AF_INET)
  601                         continue;
  602                 if (in_hosteq(inp->inp_faddr, faddr))
  603                         (*notify)(inp, errno);
  604         }
  605 }
  606 
  607 void
  608 in_pcbpurgeif0(struct inpcbtable *table, struct ifnet *ifp)
  609 {
  610         struct inpcb *inp, *ninp;
  611         struct ip_moptions *imo;
  612         int i, gap;
  613 
  614         for (inp = (struct inpcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  615             inp != (void *)&table->inpt_queue;
  616             inp = ninp) {
  617                 ninp = (struct inpcb *)CIRCLEQ_NEXT(inp, inp_queue);
  618                 if (inp->inp_af != AF_INET)
  619                         continue;
  620                 imo = inp->inp_moptions;
  621                 if (imo != NULL) {
  622                         /*
  623                          * Unselect the outgoing interface if it is being
  624                          * detached.
  625                          */
  626                         if (imo->imo_multicast_ifp == ifp)
  627                                 imo->imo_multicast_ifp = NULL;
  628 
  629                         /*
  630                          * Drop multicast group membership if we joined
  631                          * through the interface being detached.
  632                          */
  633                         for (i = 0, gap = 0; i < imo->imo_num_memberships;
  634                             i++) {
  635                                 if (imo->imo_membership[i]->inm_ifp == ifp) {
  636                                         in_delmulti(imo->imo_membership[i]);
  637                                         gap++;
  638                                 } else if (gap != 0)
  639                                         imo->imo_membership[i - gap] =
  640                                             imo->imo_membership[i];
  641                         }
  642                         imo->imo_num_memberships -= gap;
  643                 }
  644         }
  645 }
  646 
  647 void
  648 in_pcbpurgeif(struct inpcbtable *table, struct ifnet *ifp)
  649 {
  650         struct rtentry *rt;
  651         struct inpcb *inp, *ninp;
  652 
  653         for (inp = (struct inpcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  654             inp != (void *)&table->inpt_queue;
  655             inp = ninp) {
  656                 ninp = (struct inpcb *)CIRCLEQ_NEXT(inp, inp_queue);
  657                 if (inp->inp_af != AF_INET)
  658                         continue;
  659                 if ((rt = rtcache_validate(&inp->inp_route)) != NULL &&
  660                     rt->rt_ifp == ifp)
  661                         in_rtchange(inp, 0);
  662         }
  663 }
  664 
  665 /*
  666  * Check for alternatives when higher level complains
  667  * about service problems.  For now, invalidate cached
  668  * routing information.  If the route was created dynamically
  669  * (by a redirect), time to try a default gateway again.
  670  */
  671 void
  672 in_losing(struct inpcb *inp)
  673 {
  674         struct rtentry *rt;
  675         struct rt_addrinfo info;
  676 
  677         if (inp->inp_af != AF_INET)
  678                 return;
  679 
  680         if ((rt = rtcache_validate(&inp->inp_route)) == NULL)
  681                 return;
  682 
  683         memset(&info, 0, sizeof(info));
  684         info.rti_info[RTAX_DST] = rtcache_getdst(&inp->inp_route);
  685         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
  686         info.rti_info[RTAX_NETMASK] = rt_mask(rt);
  687         rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
  688         if (rt->rt_flags & RTF_DYNAMIC)
  689                 (void) rtrequest(RTM_DELETE, rt_getkey(rt),
  690                         rt->rt_gateway, rt_mask(rt), rt->rt_flags,
  691                         NULL);
  692         /*
  693          * A new route can be allocated
  694          * the next time output is attempted.
  695          */
  696         rtcache_free(&inp->inp_route);
  697 }
  698 
  699 /*
  700  * After a routing change, flush old routing.  A new route can be
  701  * allocated the next time output is attempted.
  702  */
  703 void
  704 in_rtchange(struct inpcb *inp, int errno)
  705 {
  706 
  707         if (inp->inp_af != AF_INET)
  708                 return;
  709 
  710         rtcache_free(&inp->inp_route);
  711 
  712         /* XXX SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
  713 }
  714 
  715 struct inpcb *
  716 in_pcblookup_port(struct inpcbtable *table, struct in_addr laddr,
  717     u_int lport_arg, int lookup_wildcard)
  718 {
  719         struct inpcbhead *head;
  720         struct inpcb_hdr *inph;
  721         struct inpcb *inp, *match = 0;
  722         int matchwild = 3, wildcard;
  723         u_int16_t lport = lport_arg;
  724 
  725         head = INPCBHASH_PORT(table, lport);
  726         LIST_FOREACH(inph, head, inph_lhash) {
  727                 inp = (struct inpcb *)inph;
  728                 if (inp->inp_af != AF_INET)
  729                         continue;
  730 
  731                 if (inp->inp_lport != lport)
  732                         continue;
  733                 wildcard = 0;
  734                 if (!in_nullhost(inp->inp_faddr))
  735                         wildcard++;
  736                 if (in_nullhost(inp->inp_laddr)) {
  737                         if (!in_nullhost(laddr))
  738                                 wildcard++;
  739                 } else {
  740                         if (in_nullhost(laddr))
  741                                 wildcard++;
  742                         else {
  743                                 if (!in_hosteq(inp->inp_laddr, laddr))
  744                                         continue;
  745                         }
  746                 }
  747                 if (wildcard && !lookup_wildcard)
  748                         continue;
  749                 if (wildcard < matchwild) {
  750                         match = inp;
  751                         matchwild = wildcard;
  752                         if (matchwild == 0)
  753                                 break;
  754                 }
  755         }
  756         return (match);
  757 }
  758 
  759 #ifdef DIAGNOSTIC
  760 int     in_pcbnotifymiss = 0;
  761 #endif
  762 
  763 struct inpcb *
  764 in_pcblookup_connect(struct inpcbtable *table,
  765     struct in_addr faddr, u_int fport_arg,
  766     struct in_addr laddr, u_int lport_arg)
  767 {
  768         struct inpcbhead *head;
  769         struct inpcb_hdr *inph;
  770         struct inpcb *inp;
  771         u_int16_t fport = fport_arg, lport = lport_arg;
  772 
  773         head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
  774         LIST_FOREACH(inph, head, inph_hash) {
  775                 inp = (struct inpcb *)inph;
  776                 if (inp->inp_af != AF_INET)
  777                         continue;
  778 
  779                 if (in_hosteq(inp->inp_faddr, faddr) &&
  780                     inp->inp_fport == fport &&
  781                     inp->inp_lport == lport &&
  782                     in_hosteq(inp->inp_laddr, laddr))
  783                         goto out;
  784         }
  785 #ifdef DIAGNOSTIC
  786         if (in_pcbnotifymiss) {
  787                 printf("in_pcblookup_connect: faddr=%08x fport=%d laddr=%08x lport=%d\n",
  788                     ntohl(faddr.s_addr), ntohs(fport),
  789                     ntohl(laddr.s_addr), ntohs(lport));
  790         }
  791 #endif
  792         return (0);
  793 
  794 out:
  795         /* Move this PCB to the head of hash chain. */
  796         inph = &inp->inp_head;
  797         if (inph != LIST_FIRST(head)) {
  798                 LIST_REMOVE(inph, inph_hash);
  799                 LIST_INSERT_HEAD(head, inph, inph_hash);
  800         }
  801         return (inp);
  802 }
  803 
  804 struct inpcb *
  805 in_pcblookup_bind(struct inpcbtable *table,
  806     struct in_addr laddr, u_int lport_arg)
  807 {
  808         struct inpcbhead *head;
  809         struct inpcb_hdr *inph;
  810         struct inpcb *inp;
  811         u_int16_t lport = lport_arg;
  812 
  813         head = INPCBHASH_BIND(table, laddr, lport);
  814         LIST_FOREACH(inph, head, inph_hash) {
  815                 inp = (struct inpcb *)inph;
  816                 if (inp->inp_af != AF_INET)
  817                         continue;
  818 
  819                 if (inp->inp_lport == lport &&
  820                     in_hosteq(inp->inp_laddr, laddr))
  821                         goto out;
  822         }
  823         head = INPCBHASH_BIND(table, zeroin_addr, lport);
  824         LIST_FOREACH(inph, head, inph_hash) {
  825                 inp = (struct inpcb *)inph;
  826                 if (inp->inp_af != AF_INET)
  827                         continue;
  828 
  829                 if (inp->inp_lport == lport &&
  830                     in_hosteq(inp->inp_laddr, zeroin_addr))
  831                         goto out;
  832         }
  833 #ifdef DIAGNOSTIC
  834         if (in_pcbnotifymiss) {
  835                 printf("in_pcblookup_bind: laddr=%08x lport=%d\n",
  836                     ntohl(laddr.s_addr), ntohs(lport));
  837         }
  838 #endif
  839         return (0);
  840 
  841 out:
  842         /* Move this PCB to the head of hash chain. */
  843         inph = &inp->inp_head;
  844         if (inph != LIST_FIRST(head)) {
  845                 LIST_REMOVE(inph, inph_hash);
  846                 LIST_INSERT_HEAD(head, inph, inph_hash);
  847         }
  848         return (inp);
  849 }
  850 
  851 void
  852 in_pcbstate(struct inpcb *inp, int state)
  853 {
  854 
  855         if (inp->inp_af != AF_INET)
  856                 return;
  857 
  858         if (inp->inp_state > INP_ATTACHED)
  859                 LIST_REMOVE(&inp->inp_head, inph_hash);
  860 
  861         switch (state) {
  862         case INP_BOUND:
  863                 LIST_INSERT_HEAD(INPCBHASH_BIND(inp->inp_table,
  864                     inp->inp_laddr, inp->inp_lport), &inp->inp_head,
  865                     inph_hash);
  866                 break;
  867         case INP_CONNECTED:
  868                 LIST_INSERT_HEAD(INPCBHASH_CONNECT(inp->inp_table,
  869                     inp->inp_faddr, inp->inp_fport,
  870                     inp->inp_laddr, inp->inp_lport), &inp->inp_head,
  871                     inph_hash);
  872                 break;
  873         }
  874 
  875         inp->inp_state = state;
  876 }
  877 
  878 struct rtentry *
  879 in_pcbrtentry(struct inpcb *inp)
  880 {
  881         struct route *ro;
  882         union {
  883                 struct sockaddr         dst;
  884                 struct sockaddr_in      dst4;
  885         } u;
  886 
  887         if (inp->inp_af != AF_INET)
  888                 return (NULL);
  889 
  890         ro = &inp->inp_route;
  891 
  892         sockaddr_in_init(&u.dst4, &inp->inp_faddr, 0);
  893         return rtcache_lookup(ro, &u.dst);
  894 }
  895 
  896 struct sockaddr_in *
  897 in_selectsrc(struct sockaddr_in *sin, struct route *ro,
  898     int soopts, struct ip_moptions *mopts, int *errorp)
  899 {
  900         struct rtentry *rt = NULL;
  901         struct in_ifaddr *ia = NULL;
  902 
  903         /*
  904          * If route is known or can be allocated now, take the
  905          * source address from the interface.  Otherwise, punt.
  906          */
  907         if ((soopts & SO_DONTROUTE) != 0)
  908                 rtcache_free(ro);
  909         else {
  910                 union {
  911                         struct sockaddr         dst;
  912                         struct sockaddr_in      dst4;
  913                 } u;
  914 
  915                 sockaddr_in_init(&u.dst4, &sin->sin_addr, 0);
  916                 rt = rtcache_lookup(ro, &u.dst);
  917         }
  918         /*
  919          * If we found a route, use the address
  920          * corresponding to the outgoing interface
  921          * unless it is the loopback (in case a route
  922          * to our address on another net goes to loopback).
  923          *
  924          * XXX Is this still true?  Do we care?
  925          */
  926         if (rt != NULL && (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
  927                 ia = ifatoia(rt->rt_ifa);
  928         if (ia == NULL) {
  929                 u_int16_t fport = sin->sin_port;
  930 
  931                 sin->sin_port = 0;
  932                 ia = ifatoia(ifa_ifwithladdr(sintosa(sin)));
  933                 sin->sin_port = fport;
  934                 if (ia == NULL) {
  935                         /* Find 1st non-loopback AF_INET address */
  936                         TAILQ_FOREACH(ia, &in_ifaddrhead, ia_list) {
  937                                 if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
  938                                         break;
  939                         }
  940                 }
  941                 if (ia == NULL) {
  942                         *errorp = EADDRNOTAVAIL;
  943                         return NULL;
  944                 }
  945         }
  946         /*
  947          * If the destination address is multicast and an outgoing
  948          * interface has been set as a multicast option, use the
  949          * address of that interface as our source address.
  950          */
  951         if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
  952                 struct ip_moptions *imo;
  953                 struct ifnet *ifp;
  954 
  955                 imo = mopts;
  956                 if (imo->imo_multicast_ifp != NULL) {
  957                         ifp = imo->imo_multicast_ifp;
  958                         IFP_TO_IA(ifp, ia);             /* XXX */
  959                         if (ia == 0) {
  960                                 *errorp = EADDRNOTAVAIL;
  961                                 return NULL;
  962                         }
  963                 }
  964         }
  965         if (ia->ia_ifa.ifa_getifa != NULL) {
  966                 ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa,
  967                                                       sintosa(sin)));
  968         }
  969 #ifdef GETIFA_DEBUG
  970         else
  971                 printf("%s: missing ifa_getifa\n", __func__);
  972 #endif
  973         return satosin(&ia->ia_addr);
  974 }

Cache object: ae4a8e948cb0775be52cca0cdbee5e11


[ 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.