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/netinet6/in6_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: in6_pcb.c,v 1.61.2.1 2004/04/28 05:56:07 jmc Exp $     */
    2 /*      $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $        */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Copyright (c) 1982, 1986, 1991, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. Neither the name of the University nor the names of its contributors
   46  *    may be used to endorse or promote products derived from this software
   47  *    without specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  *
   61  *      @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
   62  */
   63 
   64 #include <sys/cdefs.h>
   65 __KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.61.2.1 2004/04/28 05:56:07 jmc Exp $");
   66 
   67 #include "opt_inet.h"
   68 #include "opt_ipsec.h"
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/malloc.h>
   73 #include <sys/mbuf.h>
   74 #include <sys/protosw.h>
   75 #include <sys/socket.h>
   76 #include <sys/socketvar.h>
   77 #include <sys/ioctl.h>
   78 #include <sys/errno.h>
   79 #include <sys/time.h>
   80 #include <sys/proc.h>
   81 
   82 #include <net/if.h>
   83 #include <net/route.h>
   84 
   85 #include <netinet/in.h>
   86 #include <netinet/in_var.h>
   87 #include <netinet/in_systm.h>
   88 #include <netinet/ip.h>
   89 #include <netinet/in_pcb.h>
   90 #include <netinet/ip6.h>
   91 #include <netinet6/ip6_var.h>
   92 #include <netinet6/in6_pcb.h>
   93 #include <netinet6/nd6.h>
   94 
   95 #include "loop.h"
   96 extern struct ifnet loif[NLOOP];
   97 #include "faith.h"
   98 
   99 #ifdef IPSEC
  100 #include <netinet6/ipsec.h>
  101 #include <netkey/key.h>
  102 #endif /* IPSEC */
  103 
  104 #ifdef FAST_IPSEC
  105 #include <netipsec/ipsec.h>
  106 #include <netipsec/ipsec6.h>
  107 #include <netipsec/key.h>
  108 #endif /* FAST_IPSEC */
  109 
  110 struct in6_addr zeroin6_addr;
  111 
  112 #define IN6PCBHASH_PORT(table, lport) \
  113         &(table)->inpt_porthashtbl[ntohs(lport) & (table)->inpt_porthash]
  114 #define IN6PCBHASH_BIND(table, laddr, lport) \
  115         &(table)->inpt_bindhashtbl[ \
  116             (((laddr)->s6_addr32[0] ^ (laddr)->s6_addr32[1] ^ \
  117               (laddr)->s6_addr32[2] ^ (laddr)->s6_addr32[3]) + ntohs(lport)) & \
  118             (table)->inpt_bindhash]
  119 #define IN6PCBHASH_CONNECT(table, faddr, fport, laddr, lport) \
  120         &(table)->inpt_bindhashtbl[ \
  121             ((((faddr)->s6_addr32[0] ^ (faddr)->s6_addr32[1] ^ \
  122               (faddr)->s6_addr32[2] ^ (faddr)->s6_addr32[3]) + ntohs(fport)) + \
  123              (((laddr)->s6_addr32[0] ^ (laddr)->s6_addr32[1] ^ \
  124               (laddr)->s6_addr32[2] ^ (laddr)->s6_addr32[3]) + \
  125               ntohs(lport))) & (table)->inpt_bindhash]
  126 
  127 int ip6_anonportmin = IPV6PORT_ANONMIN;
  128 int ip6_anonportmax = IPV6PORT_ANONMAX;
  129 int ip6_lowportmin  = IPV6PORT_RESERVEDMIN;
  130 int ip6_lowportmax  = IPV6PORT_RESERVEDMAX;
  131 
  132 struct pool in6pcb_pool;
  133 
  134 void
  135 in6_pcbinit(table, bindhashsize, connecthashsize)
  136         struct inpcbtable *table;
  137         int bindhashsize, connecthashsize;
  138 {
  139         static int in6pcb_pool_initialized;
  140 
  141         if (in6pcb_pool_initialized == 0) {
  142                 pool_init(&in6pcb_pool, sizeof(struct in6pcb), 0, 0, 0,
  143                     "in6pcbpl", NULL);
  144                 in6pcb_pool_initialized = 1;
  145         }
  146 
  147         in_pcbinit(table, bindhashsize, connecthashsize);
  148         table->inpt_lastport = (u_int16_t)ip6_anonportmax;
  149 }
  150 
  151 int
  152 in6_pcballoc(so, v)
  153         struct socket *so;
  154         void *v;
  155 {
  156         struct inpcbtable *table = v;
  157         struct in6pcb *in6p;
  158         int s;
  159 #if defined(IPSEC) || defined(FAST_IPSEC)
  160         int error;
  161 #endif
  162 
  163         in6p = pool_get(&in6pcb_pool, PR_NOWAIT);
  164         if (in6p == NULL)
  165                 return (ENOBUFS);
  166         bzero((caddr_t)in6p, sizeof(*in6p));
  167         in6p->in6p_af = AF_INET6;
  168         in6p->in6p_table = table;
  169         in6p->in6p_socket = so;
  170         in6p->in6p_hops = -1;   /* use kernel default */
  171         in6p->in6p_icmp6filt = NULL;
  172 #if defined(IPSEC) || defined(FAST_IPSEC)
  173         error = ipsec_init_pcbpolicy(so, &in6p->in6p_sp);
  174         if (error != 0) {
  175                 pool_put(&in6pcb_pool, in6p);
  176                 return error;
  177         }
  178 #endif /* IPSEC */
  179         s = splnet();
  180         CIRCLEQ_INSERT_HEAD(&table->inpt_queue, (struct inpcb_hdr*)in6p,
  181             inph_queue);
  182         LIST_INSERT_HEAD(IN6PCBHASH_PORT(table, in6p->in6p_lport),
  183             &in6p->in6p_head, inph_lhash);
  184         in6_pcbstate(in6p, IN6P_ATTACHED);
  185         splx(s);
  186         if (ip6_v6only)
  187                 in6p->in6p_flags |= IN6P_IPV6_V6ONLY;
  188         so->so_pcb = (caddr_t)in6p;
  189         return (0);
  190 }
  191 
  192 int
  193 in6_pcbbind(v, nam, p)
  194         void *v;
  195         struct mbuf *nam;
  196         struct proc *p;
  197 {
  198         struct in6pcb *in6p = v;
  199         struct socket *so = in6p->in6p_socket;
  200         struct inpcbtable *table = in6p->in6p_table;
  201         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
  202         u_int16_t lport = 0;
  203         int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
  204 
  205         if (in6p->in6p_af != AF_INET6)
  206                 return (EINVAL);
  207 
  208         if (in6p->in6p_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
  209                 return (EINVAL);
  210         if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
  211            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
  212             (so->so_options & SO_ACCEPTCONN) == 0))
  213                 wild = 1;
  214         if (nam) {
  215                 sin6 = mtod(nam, struct sockaddr_in6 *);
  216                 if (nam->m_len != sizeof(*sin6))
  217                         return (EINVAL);
  218                 /*
  219                  * We should check the family, but old programs
  220                  * incorrectly fail to intialize it.
  221                  */
  222                 if (sin6->sin6_family != AF_INET6)
  223                         return (EAFNOSUPPORT);
  224 
  225 #ifndef INET
  226                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
  227                         return (EADDRNOTAVAIL);
  228 #endif
  229 
  230                 /* KAME hack: embed scopeid */
  231                 if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0)
  232                         return EINVAL;
  233                 /* this must be cleared for ifa_ifwithaddr() */
  234                 sin6->sin6_scope_id = 0;
  235 
  236                 lport = sin6->sin6_port;
  237                 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
  238                         /*
  239                          * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
  240                          * allow compepte duplication of binding if
  241                          * SO_REUSEPORT is set, or if SO_REUSEADDR is set
  242                          * and a multicast address is bound on both
  243                          * new and duplicated sockets.
  244                          */
  245                         if (so->so_options & SO_REUSEADDR)
  246                                 reuseport = SO_REUSEADDR|SO_REUSEPORT;
  247                 }
  248                 else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  249                         if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  250                                 return (EINVAL);
  251                         if (sin6->sin6_addr.s6_addr32[3]) {
  252                                 struct sockaddr_in sin;
  253 
  254                                 bzero(&sin, sizeof(sin));
  255                                 sin.sin_len = sizeof(sin);
  256                                 sin.sin_family = AF_INET;
  257                                 bcopy(&sin6->sin6_addr.s6_addr32[3],
  258                                     &sin.sin_addr, sizeof(sin.sin_addr));
  259                                 if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0)
  260                                         return EADDRNOTAVAIL;
  261                         }
  262                 }
  263                 else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  264                         struct ifaddr *ia = NULL;
  265 
  266                         sin6->sin6_port = 0;            /* yech... */
  267                         if ((in6p->in6p_flags & IN6P_FAITH) == 0 &&
  268                             (ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
  269                                 return (EADDRNOTAVAIL);
  270 
  271                         /*
  272                          * bind to an anycast address might accidentally
  273                          * cause sending a packet with an anycast source
  274                          * address, so we forbid it.
  275                          *
  276                          * We should allow to bind to a deprecated address,
  277                          * since the application dare to use it.
  278                          * But, can we assume that they are careful enough
  279                          * to check if the address is deprecated or not?
  280                          * Maybe, as a safeguard, we should have a setsockopt
  281                          * flag to control the bind(2) behavior against
  282                          * deprecated addresses (default: forbid bind(2)).
  283                          */
  284                         if (ia &&
  285                             ((struct in6_ifaddr *)ia)->ia6_flags &
  286                             (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
  287                                 return (EADDRNOTAVAIL);
  288                 }
  289                 if (lport) {
  290 #ifndef IPNOPRIVPORTS
  291                         int priv;
  292 
  293                         /*
  294                          * NOTE: all operating systems use suser() for
  295                          * privilege check!  do not rewrite it into SS_PRIV.
  296                          */
  297                         priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
  298                         /* GROSS */
  299                         if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
  300                                 return (EACCES);
  301 #endif
  302 
  303                         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  304 #ifdef INET
  305                                 struct inpcb *t;
  306 
  307                                 t = in_pcblookup_port(table,
  308                                     *(struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
  309                                     lport, wild);
  310                                 if (t && (reuseport & t->inp_socket->so_options) == 0)
  311                                         return (EADDRINUSE);
  312 #else
  313                                 return (EADDRNOTAVAIL);
  314 #endif
  315                         }
  316 
  317                         {
  318                                 struct in6pcb *t;
  319 
  320                                 t = in6_pcblookup_port(table, &sin6->sin6_addr,
  321                                     lport, wild);
  322                                 if (t && (reuseport & t->in6p_socket->so_options) == 0)
  323                                         return (EADDRINUSE);
  324                         }
  325                 }
  326                 in6p->in6p_laddr = sin6->sin6_addr;
  327         }
  328 
  329         if (lport == 0) {
  330                 int e;
  331                 e = in6_pcbsetport(&in6p->in6p_laddr, in6p, p);
  332                 if (e != 0)
  333                         return (e);
  334         } else {
  335                 in6p->in6p_lport = lport;
  336                 in6_pcbstate(in6p, IN6P_BOUND);
  337         }
  338 
  339         LIST_REMOVE(&in6p->in6p_head, inph_lhash);
  340         LIST_INSERT_HEAD(IN6PCBHASH_PORT(table, in6p->in6p_lport),
  341             &in6p->in6p_head, inph_lhash);
  342 
  343 #if 0
  344         in6p->in6p_flowinfo = 0;        /* XXX */
  345 #endif
  346         return (0);
  347 }
  348 
  349 /*
  350  * Connect from a socket to a specified address.
  351  * Both address and port must be specified in argument sin6.
  352  * If don't have a local address for this socket yet,
  353  * then pick one.
  354  */
  355 int
  356 in6_pcbconnect(v, nam)
  357         void *v;
  358         struct mbuf *nam;
  359 {
  360         struct in6pcb *in6p = v;
  361         struct in6_addr *in6a = NULL;
  362         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
  363         struct ifnet *ifp = NULL;       /* outgoing interface */
  364         int error = 0;
  365 #ifdef INET
  366         struct in6_addr mapped;
  367 #endif
  368         struct sockaddr_in6 tmp;
  369 
  370         (void)&in6a;                            /* XXX fool gcc */
  371 
  372         if (in6p->in6p_af != AF_INET6)
  373                 return (EINVAL);
  374 
  375         if (nam->m_len != sizeof(*sin6))
  376                 return (EINVAL);
  377         if (sin6->sin6_family != AF_INET6)
  378                 return (EAFNOSUPPORT);
  379         if (sin6->sin6_port == 0)
  380                 return (EADDRNOTAVAIL);
  381 
  382         /* sanity check for mapped address case */
  383         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  384                 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  385                         return EINVAL;
  386                 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
  387                         in6p->in6p_laddr.s6_addr16[5] = htons(0xffff);
  388                 if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
  389                         return EINVAL;
  390         } else
  391         {
  392                 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
  393                         return EINVAL;
  394         }
  395 
  396         /* protect *sin6 from overwrites */
  397         tmp = *sin6;
  398         sin6 = &tmp;
  399 
  400         /* KAME hack: embed scopeid */
  401         if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, &ifp) != 0)
  402                 return EINVAL;
  403 
  404         /* Source address selection. */
  405         if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
  406             in6p->in6p_laddr.s6_addr32[3] == 0) {
  407 #ifdef INET
  408                 struct sockaddr_in sin, *sinp;
  409 
  410                 bzero(&sin, sizeof(sin));
  411                 sin.sin_len = sizeof(sin);
  412                 sin.sin_family = AF_INET;
  413                 bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
  414                         sizeof(sin.sin_addr));
  415                 sinp = in_selectsrc(&sin, (struct route *)&in6p->in6p_route,
  416                         in6p->in6p_socket->so_options, NULL, &error);
  417                 if (sinp == 0) {
  418                         if (error == 0)
  419                                 error = EADDRNOTAVAIL;
  420                         return (error);
  421                 }
  422                 bzero(&mapped, sizeof(mapped));
  423                 mapped.s6_addr16[5] = htons(0xffff);
  424                 bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr));
  425                 in6a = &mapped;
  426 #else
  427                 return EADDRNOTAVAIL;
  428 #endif
  429         } else
  430         {
  431                 /*
  432                  * XXX: in6_selectsrc might replace the bound local address
  433                  * with the address specified by setsockopt(IPV6_PKTINFO).
  434                  * Is it the intended behavior?
  435                  */
  436                 in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
  437                                      in6p->in6p_moptions,
  438                                      &in6p->in6p_route,
  439                                      &in6p->in6p_laddr, &error);
  440                 if (in6a == 0) {
  441                         if (error == 0)
  442                                 error = EADDRNOTAVAIL;
  443                         return (error);
  444                 }
  445         }
  446         if (in6p->in6p_route.ro_rt)
  447                 ifp = in6p->in6p_route.ro_rt->rt_ifp;
  448 
  449         in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim(in6p, ifp);
  450 
  451         if (in6_pcblookup_connect(in6p->in6p_table, &sin6->sin6_addr,
  452             sin6->sin6_port,
  453             IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) ? in6a : &in6p->in6p_laddr,
  454             in6p->in6p_lport, 0))
  455                 return (EADDRINUSE);
  456         if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) ||
  457             (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
  458              in6p->in6p_laddr.s6_addr32[3] == 0))
  459         {
  460                 if (in6p->in6p_lport == 0) {
  461                         (void)in6_pcbbind(in6p, (struct mbuf *)0,
  462                             (struct proc *)0);
  463                 }
  464                 in6p->in6p_laddr = *in6a;
  465         }
  466         in6p->in6p_faddr = sin6->sin6_addr;
  467         in6p->in6p_fport = sin6->sin6_port;
  468         in6_pcbstate(in6p, IN6P_CONNECTED);
  469         in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
  470         if (ip6_auto_flowlabel)
  471                 in6p->in6p_flowinfo |=
  472                     (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
  473 #if defined(IPSEC) || defined(FAST_IPSEC)
  474         if (in6p->in6p_socket->so_type == SOCK_STREAM)
  475                 ipsec_pcbconn(in6p->in6p_sp);
  476 #endif
  477         return (0);
  478 }
  479 
  480 void
  481 in6_pcbdisconnect(in6p)
  482         struct in6pcb *in6p;
  483 {
  484         bzero((caddr_t)&in6p->in6p_faddr, sizeof(in6p->in6p_faddr));
  485         in6p->in6p_fport = 0;
  486         in6_pcbstate(in6p, IN6P_BOUND);
  487         in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
  488 #if defined(IPSEC) || defined(FAST_IPSEC)
  489         ipsec_pcbdisconn(in6p->in6p_sp);
  490 #endif
  491         if (in6p->in6p_socket->so_state & SS_NOFDREF)
  492                 in6_pcbdetach(in6p);
  493 }
  494 
  495 void
  496 in6_pcbdetach(in6p)
  497         struct in6pcb *in6p;
  498 {
  499         struct socket *so = in6p->in6p_socket;
  500         int s;
  501 
  502         if (in6p->in6p_af != AF_INET6)
  503                 return;
  504 
  505 #if defined(IPSEC) || defined(FAST_IPSEC)
  506         ipsec6_delete_pcbpolicy(in6p);
  507 #endif /* IPSEC */
  508         sotoin6pcb(so) = 0;
  509         sofree(so);
  510         if (in6p->in6p_options)
  511                 m_freem(in6p->in6p_options);
  512         if (in6p->in6p_outputopts) {
  513                 if (in6p->in6p_outputopts->ip6po_rthdr &&
  514                     in6p->in6p_outputopts->ip6po_route.ro_rt)
  515                         RTFREE(in6p->in6p_outputopts->ip6po_route.ro_rt);
  516                 if (in6p->in6p_outputopts->ip6po_m)
  517                         (void)m_free(in6p->in6p_outputopts->ip6po_m);
  518                 free(in6p->in6p_outputopts, M_IP6OPT);
  519         }
  520         if (in6p->in6p_route.ro_rt)
  521                 rtfree(in6p->in6p_route.ro_rt);
  522         ip6_freemoptions(in6p->in6p_moptions);
  523         s = splnet();
  524         in6_pcbstate(in6p, IN6P_ATTACHED);
  525         LIST_REMOVE(&in6p->in6p_head, inph_lhash);
  526         CIRCLEQ_REMOVE(&in6p->in6p_table->inpt_queue, &in6p->in6p_head,
  527             inph_queue);
  528         splx(s);
  529         pool_put(&in6pcb_pool, in6p);
  530 }
  531 
  532 void
  533 in6_setsockaddr(in6p, nam)
  534         struct in6pcb *in6p;
  535         struct mbuf *nam;
  536 {
  537         struct sockaddr_in6 *sin6;
  538 
  539         if (in6p->in6p_af != AF_INET6)
  540                 return;
  541 
  542         nam->m_len = sizeof(*sin6);
  543         sin6 = mtod(nam, struct sockaddr_in6 *);
  544         bzero((caddr_t)sin6, sizeof(*sin6));
  545         sin6->sin6_family = AF_INET6;
  546         sin6->sin6_len = sizeof(struct sockaddr_in6);
  547         sin6->sin6_port = in6p->in6p_lport;
  548         /* KAME hack: recover scopeid */
  549         (void)in6_recoverscope(sin6, &in6p->in6p_laddr, NULL);
  550 }
  551 
  552 void
  553 in6_setpeeraddr(in6p, nam)
  554         struct in6pcb *in6p;
  555         struct mbuf *nam;
  556 {
  557         struct sockaddr_in6 *sin6;
  558 
  559         if (in6p->in6p_af != AF_INET6)
  560                 return;
  561 
  562         nam->m_len = sizeof(*sin6);
  563         sin6 = mtod(nam, struct sockaddr_in6 *);
  564         bzero((caddr_t)sin6, sizeof(*sin6));
  565         sin6->sin6_family = AF_INET6;
  566         sin6->sin6_len = sizeof(struct sockaddr_in6);
  567         sin6->sin6_port = in6p->in6p_fport;
  568         /* KAME hack: recover scopeid */
  569         (void)in6_recoverscope(sin6, &in6p->in6p_faddr, NULL);
  570 }
  571 
  572 /*
  573  * Pass some notification to all connections of a protocol
  574  * associated with address dst.  The local address and/or port numbers
  575  * may be specified to limit the search.  The "usual action" will be
  576  * taken, depending on the ctlinput cmd.  The caller must filter any
  577  * cmds that are uninteresting (e.g., no error in the map).
  578  * Call the protocol specific routine (if any) to report
  579  * any errors for each matching socket.
  580  *
  581  * Must be called at splsoftnet.
  582  *
  583  * Note: src (4th arg) carries the flowlabel value on the original IPv6
  584  * header, in sin6_flowinfo member.
  585  */
  586 int
  587 in6_pcbnotify(table, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
  588         struct inpcbtable *table;
  589         struct sockaddr *dst, *src;
  590         u_int fport_arg, lport_arg;
  591         int cmd;
  592         void *cmdarg;
  593         void (*notify) __P((struct in6pcb *, int));
  594 {
  595         struct in6pcb *in6p, *nin6p;
  596         struct sockaddr_in6 sa6_src, *sa6_dst;
  597         u_int16_t fport = fport_arg, lport = lport_arg;
  598         int errno;
  599         int nmatch = 0;
  600         u_int32_t flowinfo;
  601 
  602         if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
  603                 return 0;
  604 
  605         sa6_dst = (struct sockaddr_in6 *)dst;
  606         if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
  607                 return 0;
  608 
  609         /*
  610          * note that src can be NULL when we get notify by local fragmentation.
  611          */
  612         sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
  613         flowinfo = sa6_src.sin6_flowinfo;
  614 
  615         /*
  616          * Redirects go to all references to the destination,
  617          * and use in6_rtchange to invalidate the route cache.
  618          * Dead host indications: also use in6_rtchange to invalidate
  619          * the cache, and deliver the error to all the sockets.
  620          * Otherwise, if we have knowledge of the local port and address,
  621          * deliver only to that socket.
  622          */
  623         if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
  624                 fport = 0;
  625                 lport = 0;
  626                 bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));
  627 
  628                 if (cmd != PRC_HOSTDEAD)
  629                         notify = in6_rtchange;
  630         }
  631 
  632         errno = inet6ctlerrmap[cmd];
  633         for (in6p = (struct in6pcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  634             in6p != (void *)&table->inpt_queue;
  635             in6p = nin6p) {
  636                 nin6p = (struct in6pcb *)CIRCLEQ_NEXT(in6p, in6p_queue);
  637 
  638                 if (in6p->in6p_af != AF_INET6)
  639                         continue;
  640 
  641                 /*
  642                  * Under the following condition, notify of redirects
  643                  * to the pcb, without making address matches against inpcb.
  644                  * - redirect notification is arrived.
  645                  * - the inpcb is unconnected.
  646                  * - the inpcb is caching !RTF_HOST routing entry.
  647                  * - the ICMPv6 notification is from the gateway cached in the
  648                  *   inpcb.  i.e. ICMPv6 notification is from nexthop gateway
  649                  *   the inpcb used very recently.
  650                  *
  651                  * This is to improve interaction between netbsd/openbsd
  652                  * redirect handling code, and inpcb route cache code.
  653                  * without the clause, !RTF_HOST routing entry (which carries
  654                  * gateway used by inpcb right before the ICMPv6 redirect)
  655                  * will be cached forever in unconnected inpcb.
  656                  *
  657                  * There still is a question regarding to what is TRT:
  658                  * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
  659                  *   generated on packet output.  inpcb will always cache
  660                  *   RTF_HOST routing entry so there's no need for the clause
  661                  *   (ICMPv6 redirect will update RTF_HOST routing entry,
  662                  *   and inpcb is caching it already).
  663                  *   However, bsdi/freebsd are vulnerable to local DoS attacks
  664                  *   due to the cloned routing entries.
  665                  * - Specwise, "destination cache" is mentioned in RFC2461.
  666                  *   Jinmei says that it implies bsdi/freebsd behavior, itojun
  667                  *   is not really convinced.
  668                  * - Having hiwat/lowat on # of cloned host route (redirect/
  669                  *   pmtud) may be a good idea.  netbsd/openbsd has it.  see
  670                  *   icmp6_mtudisc_update().
  671                  */
  672                 if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
  673                     IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
  674                     in6p->in6p_route.ro_rt &&
  675                     !(in6p->in6p_route.ro_rt->rt_flags & RTF_HOST)) {
  676                         struct sockaddr_in6 *dst6;
  677 
  678                         dst6 = (struct sockaddr_in6 *)&in6p->in6p_route.ro_dst;
  679                         if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
  680                             &sa6_dst->sin6_addr))
  681                                 goto do_notify;
  682                 }
  683 
  684                 /*
  685                  * Detect if we should notify the error. If no source and
  686                  * destination ports are specified, but non-zero flowinfo and
  687                  * local address match, notify the error. This is the case
  688                  * when the error is delivered with an encrypted buffer
  689                  * by ESP. Otherwise, just compare addresses and ports
  690                  * as usual.
  691                  */
  692                 if (lport == 0 && fport == 0 && flowinfo &&
  693                     in6p->in6p_socket != NULL &&
  694                     flowinfo == (in6p->in6p_flowinfo & IPV6_FLOWLABEL_MASK) &&
  695                     IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &sa6_src.sin6_addr))
  696                         goto do_notify;
  697                 else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
  698                                              &sa6_dst->sin6_addr) ||
  699                     in6p->in6p_socket == 0 ||
  700                     (lport && in6p->in6p_lport != lport) ||
  701                     (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
  702                      !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
  703                                          &sa6_src.sin6_addr)) ||
  704                     (fport && in6p->in6p_fport != fport))
  705                         continue;
  706 
  707           do_notify:
  708                 if (notify)
  709                         (*notify)(in6p, errno);
  710                 nmatch++;
  711         }
  712         return nmatch;
  713 }
  714 
  715 void
  716 in6_pcbpurgeif0(table, ifp)
  717         struct inpcbtable *table;
  718         struct ifnet *ifp;
  719 {
  720         struct in6pcb *in6p, *nin6p;
  721         struct ip6_moptions *im6o;
  722         struct in6_multi_mship *imm, *nimm;
  723 
  724         for (in6p = (struct in6pcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  725             in6p != (void *)&table->inpt_queue;
  726             in6p = nin6p) {
  727                 nin6p = (struct in6pcb *)CIRCLEQ_NEXT(in6p, in6p_queue);
  728                 if (in6p->in6p_af != AF_INET6)
  729                         continue;
  730 
  731                 im6o = in6p->in6p_moptions;
  732                 if (im6o) {
  733                         /*
  734                          * Unselect the outgoing interface if it is being
  735                          * detached.
  736                          */
  737                         if (im6o->im6o_multicast_ifp == ifp)
  738                                 im6o->im6o_multicast_ifp = NULL;
  739 
  740                         /*
  741                          * Drop multicast group membership if we joined
  742                          * through the interface being detached.
  743                          * XXX controversial - is it really legal for kernel
  744                          * to force this?
  745                          */
  746                         for (imm = im6o->im6o_memberships.lh_first;
  747                              imm != NULL; imm = nimm) {
  748                                 nimm = imm->i6mm_chain.le_next;
  749                                 if (imm->i6mm_maddr->in6m_ifp == ifp) {
  750                                         LIST_REMOVE(imm, i6mm_chain);
  751                                         in6_leavegroup(imm);
  752                                 }
  753                         }
  754                 }
  755         }
  756 }
  757 
  758 void
  759 in6_pcbpurgeif(table, ifp)
  760         struct inpcbtable *table;
  761         struct ifnet *ifp;
  762 {
  763         struct in6pcb *in6p, *nin6p;
  764 
  765         for (in6p = (struct in6pcb *)CIRCLEQ_FIRST(&table->inpt_queue);
  766             in6p != (void *)&table->inpt_queue;
  767             in6p = nin6p) {
  768                 nin6p = (struct in6pcb *)CIRCLEQ_NEXT(in6p, in6p_queue);
  769                 if (in6p->in6p_af != AF_INET6)
  770                         continue;
  771                 if (in6p->in6p_route.ro_rt != NULL &&
  772                     in6p->in6p_route.ro_rt->rt_ifp == ifp)
  773                         in6_rtchange(in6p, 0);
  774         }
  775 }
  776 
  777 /*
  778  * Check for alternatives when higher level complains
  779  * about service problems.  For now, invalidate cached
  780  * routing information.  If the route was created dynamically
  781  * (by a redirect), time to try a default gateway again.
  782  */
  783 void
  784 in6_losing(in6p)
  785         struct in6pcb *in6p;
  786 {
  787         struct rtentry *rt;
  788         struct rt_addrinfo info;
  789 
  790         if (in6p->in6p_af != AF_INET6)
  791                 return;
  792 
  793         if ((rt = in6p->in6p_route.ro_rt) != NULL) {
  794                 in6p->in6p_route.ro_rt = 0;
  795                 bzero((caddr_t)&info, sizeof(info));
  796                 info.rti_info[RTAX_DST] =
  797                         (struct sockaddr *)&in6p->in6p_route.ro_dst;
  798                 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
  799                 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
  800                 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
  801                 if (rt->rt_flags & RTF_DYNAMIC) {
  802                         (void)rtrequest(RTM_DELETE, rt_key(rt),
  803                                         rt->rt_gateway, rt_mask(rt), rt->rt_flags,
  804                                         (struct rtentry **)0);
  805                 } else {
  806                         /*
  807                          * A new route can be allocated
  808                          * the next time output is attempted.
  809                          */
  810                         rtfree(rt);
  811                 }
  812         }
  813 }
  814 
  815 /*
  816  * After a routing change, flush old routing
  817  * and allocate a (hopefully) better one.
  818  */
  819 void
  820 in6_rtchange(in6p, errno)
  821         struct in6pcb *in6p;
  822         int errno;
  823 {
  824         if (in6p->in6p_af != AF_INET6)
  825                 return;
  826 
  827         if (in6p->in6p_route.ro_rt) {
  828                 rtfree(in6p->in6p_route.ro_rt);
  829                 in6p->in6p_route.ro_rt = 0;
  830                 /*
  831                  * A new route can be allocated the next time
  832                  * output is attempted.
  833                  */
  834         }
  835 }
  836 
  837 struct in6pcb *
  838 in6_pcblookup_port(table, laddr6, lport_arg, lookup_wildcard)
  839         struct inpcbtable *table;
  840         struct in6_addr *laddr6;
  841         u_int lport_arg;
  842         int lookup_wildcard;
  843 {
  844         struct inpcbhead *head;
  845         struct inpcb_hdr *inph;
  846         struct in6pcb *in6p, *match = 0;
  847         int matchwild = 3, wildcard;
  848         u_int16_t lport = lport_arg;
  849 
  850         head = IN6PCBHASH_PORT(table, lport);
  851         LIST_FOREACH(inph, head, inph_lhash) {
  852                 in6p = (struct in6pcb *)inph;
  853                 if (in6p->in6p_af != AF_INET6)
  854                         continue;
  855 
  856                 if (in6p->in6p_lport != lport)
  857                         continue;
  858                 wildcard = 0;
  859                 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
  860                         if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  861                                 continue;
  862                 }
  863                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
  864                         wildcard++;
  865                 if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) {
  866                         if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  867                                 continue;
  868                         if (!IN6_IS_ADDR_V4MAPPED(laddr6))
  869                                 continue;
  870 
  871                         /* duplicate of IPv4 logic */
  872                         wildcard = 0;
  873                         if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr) &&
  874                             in6p->in6p_faddr.s6_addr32[3])
  875                                 wildcard++;
  876                         if (!in6p->in6p_laddr.s6_addr32[3]) {
  877                                 if (laddr6->s6_addr32[3])
  878                                         wildcard++;
  879                         } else {
  880                                 if (!laddr6->s6_addr32[3])
  881                                         wildcard++;
  882                                 else {
  883                                         if (in6p->in6p_laddr.s6_addr32[3] !=
  884                                             laddr6->s6_addr32[3])
  885                                                 continue;
  886                                 }
  887                         }
  888                 } else if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
  889                         if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
  890                                 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  891                                         continue;
  892                         }
  893                         if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
  894                                 wildcard++;
  895                 } else {
  896                         if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
  897                                 if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
  898                                         continue;
  899                         }
  900                         if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
  901                                 wildcard++;
  902                         else {
  903                                 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
  904                                     laddr6))
  905                                         continue;
  906                         }
  907                 }
  908                 if (wildcard && !lookup_wildcard)
  909                         continue;
  910                 if (wildcard < matchwild) {
  911                         match = in6p;
  912                         matchwild = wildcard;
  913                         if (matchwild == 0)
  914                                 break;
  915                 }
  916         }
  917         return (match);
  918 }
  919 #undef continue
  920 
  921 /*
  922  * WARNING: return value (rtentry) could be IPv4 one if in6pcb is connected to
  923  * IPv4 mapped address.
  924  */
  925 struct rtentry *
  926 in6_pcbrtentry(in6p)
  927         struct in6pcb *in6p;
  928 {
  929         struct route_in6 *ro;
  930         struct sockaddr_in6 *dst6;
  931 
  932         ro = &in6p->in6p_route;
  933         dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
  934 
  935         if (in6p->in6p_af != AF_INET6)
  936                 return (NULL);
  937 
  938         if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
  939             !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &in6p->in6p_faddr))) {
  940                 RTFREE(ro->ro_rt);
  941                 ro->ro_rt = (struct rtentry *)NULL;
  942         }
  943 #ifdef INET
  944         if (ro->ro_rt == (struct rtentry *)NULL &&
  945             IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
  946                 struct sockaddr_in *dst = (struct sockaddr_in *)&ro->ro_dst;
  947 
  948                 bzero(dst, sizeof(*dst));
  949                 dst->sin_family = AF_INET;
  950                 dst->sin_len = sizeof(struct sockaddr_in);
  951                 bcopy(&in6p->in6p_faddr.s6_addr32[3], &dst->sin_addr,
  952                     sizeof(dst->sin_addr));
  953                 rtalloc((struct route *)ro);
  954         } else
  955 #endif
  956         if (ro->ro_rt == (struct rtentry *)NULL &&
  957             !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
  958                 bzero(dst6, sizeof(*dst6));
  959                 dst6->sin6_family = AF_INET6;
  960                 dst6->sin6_len = sizeof(struct sockaddr_in6);
  961                 dst6->sin6_addr = in6p->in6p_faddr;
  962                 rtalloc((struct route *)ro);
  963         }
  964         return (ro->ro_rt);
  965 }
  966 
  967 struct in6pcb *
  968 in6_pcblookup_connect(table, faddr6, fport_arg, laddr6, lport_arg, faith)
  969         struct inpcbtable *table;
  970         struct in6_addr *faddr6, *laddr6;
  971         u_int fport_arg, lport_arg;
  972         int faith;
  973 {
  974         struct inpcbhead *head;
  975         struct inpcb_hdr *inph;
  976         struct in6pcb *in6p;
  977         u_int16_t fport = fport_arg, lport = lport_arg;
  978 
  979         head = IN6PCBHASH_CONNECT(table, faddr6, fport, laddr6, lport);
  980         LIST_FOREACH(inph, head, inph_hash) {
  981                 in6p = (struct in6pcb *)inph;
  982                 if (in6p->in6p_af != AF_INET6)
  983                         continue;
  984 
  985                 /* find exact match on both source and dest */
  986                 if (in6p->in6p_fport != fport)
  987                         continue;
  988                 if (in6p->in6p_lport != lport)
  989                         continue;
  990                 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
  991                         continue;
  992                 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6))
  993                         continue;
  994                 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
  995                         continue;
  996                 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
  997                         continue;
  998                 if ((IN6_IS_ADDR_V4MAPPED(laddr6) ||
  999                      IN6_IS_ADDR_V4MAPPED(faddr6)) &&
 1000                     (in6p->in6p_flags & IN6P_IPV6_V6ONLY))
 1001                         continue;
 1002                 return in6p;
 1003         }
 1004         return NULL;
 1005 }
 1006 
 1007 struct in6pcb *
 1008 in6_pcblookup_bind(table, laddr6, lport_arg, faith)
 1009         struct inpcbtable *table;
 1010         struct in6_addr *laddr6;
 1011         u_int lport_arg;
 1012         int faith;
 1013 {
 1014         struct inpcbhead *head;
 1015         struct inpcb_hdr *inph;
 1016         struct in6pcb *in6p;
 1017         u_int16_t lport = lport_arg;
 1018 #ifdef INET6
 1019         struct in6_addr zero_mapped;
 1020 #endif
 1021 
 1022         head = IN6PCBHASH_BIND(table, laddr6, lport);
 1023         LIST_FOREACH(inph, head, inph_hash) {
 1024                 in6p = (struct in6pcb *)inph;
 1025                 if (in6p->in6p_af != AF_INET6)
 1026                         continue;
 1027 
 1028                 if (faith && (in6p->in6p_flags & IN6P_FAITH) == 0)
 1029                         continue;
 1030                 if (in6p->in6p_fport != 0)
 1031                         continue;
 1032                 if (in6p->in6p_lport != lport)
 1033                         continue;
 1034                 if (IN6_IS_ADDR_V4MAPPED(laddr6) &&
 1035                     (in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
 1036                         continue;
 1037                 if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
 1038                         goto out;
 1039         }
 1040 #ifdef INET
 1041         if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
 1042                 memset(&zero_mapped, 0, sizeof(zero_mapped));
 1043                 zero_mapped.s6_addr16[5] = 0xffff;
 1044                 head = IN6PCBHASH_BIND(table, &zero_mapped, lport);
 1045                 LIST_FOREACH(inph, head, inph_hash) {
 1046                         in6p = (struct in6pcb *)inph;
 1047                         if (in6p->in6p_af != AF_INET6)
 1048                                 continue;
 1049 
 1050                         if (faith && (in6p->in6p_flags & IN6P_FAITH) == 0)
 1051                                 continue;
 1052                         if (in6p->in6p_fport != 0)
 1053                                 continue;
 1054                         if (in6p->in6p_lport != lport)
 1055                                 continue;
 1056                         if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
 1057                                 continue;
 1058                         if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &zero_mapped))
 1059                                 goto out;
 1060                 }
 1061         }
 1062 #endif
 1063         head = IN6PCBHASH_BIND(table, &zeroin6_addr, lport);
 1064         LIST_FOREACH(inph, head, inph_hash) {
 1065                 in6p = (struct in6pcb *)inph;
 1066                 if (in6p->in6p_af != AF_INET6)
 1067                         continue;
 1068 
 1069                 if (faith && (in6p->in6p_flags & IN6P_FAITH) == 0)
 1070                         continue;
 1071                 if (in6p->in6p_fport != 0)
 1072                         continue;
 1073                 if (in6p->in6p_lport != lport)
 1074                         continue;
 1075                 if (IN6_IS_ADDR_V4MAPPED(laddr6) &&
 1076                     (in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
 1077                         continue;
 1078                 if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &zeroin6_addr))
 1079                         goto out;
 1080         }
 1081         return (NULL);
 1082 
 1083 out:
 1084         inph = &in6p->in6p_head;
 1085         if (inph != LIST_FIRST(head)) {
 1086                 LIST_REMOVE(inph, inph_hash);
 1087                 LIST_INSERT_HEAD(head, inph, inph_hash);
 1088         }
 1089         return in6p;
 1090 }
 1091 
 1092 void
 1093 in6_pcbstate(in6p, state)
 1094         struct in6pcb *in6p;
 1095         int state;
 1096 {
 1097 
 1098         if (in6p->in6p_af != AF_INET6)
 1099                 return;
 1100 
 1101         if (in6p->in6p_state > IN6P_ATTACHED)
 1102                 LIST_REMOVE(&in6p->in6p_head, inph_hash);
 1103 
 1104         switch (state) {
 1105         case IN6P_BOUND:
 1106                 LIST_INSERT_HEAD(IN6PCBHASH_BIND(in6p->in6p_table,
 1107                     &in6p->in6p_laddr, in6p->in6p_lport), &in6p->in6p_head,
 1108                     inph_hash);
 1109                 break;
 1110         case IN6P_CONNECTED:
 1111                 LIST_INSERT_HEAD(IN6PCBHASH_CONNECT(in6p->in6p_table,
 1112                     &in6p->in6p_faddr, in6p->in6p_fport,
 1113                     &in6p->in6p_laddr, in6p->in6p_lport), &in6p->in6p_head,
 1114                     inph_hash);
 1115                 break;
 1116         }
 1117 
 1118         in6p->in6p_state = state;
 1119 }

Cache object: befa4af4dfe93a95ee67e85201fb6cf8


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