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

Cache object: bcee88caefc3a5903f075762d1b6e09c


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