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

Cache object: f3c7e64d5072ccfb15a2b4ec70dc285d


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