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

Cache object: d13b6dc79b56a476d36a383b43288a54


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