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/udp6_usrreq.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the project nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $
   30  *      $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $
   31  */
   32 
   33 /*-
   34  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
   35  *      The Regents of the University of California.
   36  * All rights reserved.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD: stable/8/sys/netinet6/udp6_usrreq.c 249478 2013-04-14 16:25:37Z rwatson $");
   67 
   68 #include "opt_inet.h"
   69 #include "opt_inet6.h"
   70 #include "opt_ipsec.h"
   71 
   72 #include <sys/param.h>
   73 #include <sys/jail.h>
   74 #include <sys/kernel.h>
   75 #include <sys/lock.h>
   76 #include <sys/mbuf.h>
   77 #include <sys/priv.h>
   78 #include <sys/proc.h>
   79 #include <sys/protosw.h>
   80 #include <sys/signalvar.h>
   81 #include <sys/socket.h>
   82 #include <sys/socketvar.h>
   83 #include <sys/sx.h>
   84 #include <sys/sysctl.h>
   85 #include <sys/syslog.h>
   86 #include <sys/systm.h>
   87 
   88 #include <net/if.h>
   89 #include <net/if_types.h>
   90 #include <net/route.h>
   91 
   92 #include <netinet/in.h>
   93 #include <netinet/in_pcb.h>
   94 #include <netinet/in_systm.h>
   95 #include <netinet/in_var.h>
   96 #include <netinet/ip.h>
   97 #include <netinet/ip_icmp.h>
   98 #include <netinet/ip6.h>
   99 #include <netinet/icmp_var.h>
  100 #include <netinet/icmp6.h>
  101 #include <netinet/ip_var.h>
  102 #include <netinet/udp.h>
  103 #include <netinet/udp_var.h>
  104 
  105 #include <netinet6/ip6protosw.h>
  106 #include <netinet6/ip6_var.h>
  107 #include <netinet6/in6_pcb.h>
  108 #include <netinet6/udp6_var.h>
  109 #include <netinet6/scope6_var.h>
  110 
  111 #ifdef IPSEC
  112 #include <netipsec/ipsec.h>
  113 #include <netipsec/ipsec6.h>
  114 #endif /* IPSEC */
  115 
  116 #include <security/mac/mac_framework.h>
  117 
  118 /*
  119  * UDP protocol implementation.
  120  * Per RFC 768, August, 1980.
  121  */
  122 
  123 extern struct protosw   inetsw[];
  124 static void             udp6_detach(struct socket *so);
  125 
  126 static void
  127 udp6_append(struct inpcb *inp, struct mbuf *n, int off,
  128     struct sockaddr_in6 *fromsa)
  129 {
  130         struct socket *so;
  131         struct mbuf *opts;
  132 
  133         INP_LOCK_ASSERT(inp);
  134 
  135 #ifdef IPSEC
  136         /* Check AH/ESP integrity. */
  137         if (ipsec6_in_reject(n, inp)) {
  138                 m_freem(n);
  139                 V_ipsec6stat.in_polvio++;
  140                 return;
  141         }
  142 #endif /* IPSEC */
  143 #ifdef MAC
  144         if (mac_inpcb_check_deliver(inp, n) != 0) {
  145                 m_freem(n);
  146                 return;
  147         }
  148 #endif
  149         opts = NULL;
  150         if (inp->inp_flags & INP_CONTROLOPTS ||
  151             inp->inp_socket->so_options & SO_TIMESTAMP)
  152                 ip6_savecontrol(inp, n, &opts);
  153         m_adj(n, off + sizeof(struct udphdr));
  154 
  155         so = inp->inp_socket;
  156         SOCKBUF_LOCK(&so->so_rcv);
  157         if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n,
  158             opts) == 0) {
  159                 SOCKBUF_UNLOCK(&so->so_rcv);
  160                 m_freem(n);
  161                 if (opts)
  162                         m_freem(opts);
  163                 UDPSTAT_INC(udps_fullsock);
  164         } else
  165                 sorwakeup_locked(so);
  166 }
  167 
  168 int
  169 udp6_input(struct mbuf **mp, int *offp, int proto)
  170 {
  171         struct mbuf *m = *mp;
  172         struct ifnet *ifp;
  173         struct ip6_hdr *ip6;
  174         struct udphdr *uh;
  175         struct inpcb *inp;
  176         struct udpcb *up;
  177         int off = *offp;
  178         int plen, ulen;
  179         struct sockaddr_in6 fromsa;
  180 
  181         ifp = m->m_pkthdr.rcvif;
  182         ip6 = mtod(m, struct ip6_hdr *);
  183 
  184         if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
  185                 /* XXX send icmp6 host/port unreach? */
  186                 m_freem(m);
  187                 return (IPPROTO_DONE);
  188         }
  189 
  190 #ifndef PULLDOWN_TEST
  191         IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
  192         ip6 = mtod(m, struct ip6_hdr *);
  193         uh = (struct udphdr *)((caddr_t)ip6 + off);
  194 #else
  195         IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh));
  196         if (!uh)
  197                 return (IPPROTO_DONE);
  198 #endif
  199 
  200         UDPSTAT_INC(udps_ipackets);
  201 
  202         /*
  203          * Destination port of 0 is illegal, based on RFC768.
  204          */
  205         if (uh->uh_dport == 0)
  206                 goto badunlocked;
  207 
  208         plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
  209         ulen = ntohs((u_short)uh->uh_ulen);
  210 
  211         if (plen != ulen) {
  212                 UDPSTAT_INC(udps_badlen);
  213                 goto badunlocked;
  214         }
  215 
  216         /*
  217          * Checksum extended UDP header and data.
  218          */
  219         if (uh->uh_sum == 0) {
  220                 UDPSTAT_INC(udps_nosum);
  221                 goto badunlocked;
  222         }
  223         if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
  224                 UDPSTAT_INC(udps_badsum);
  225                 goto badunlocked;
  226         }
  227 
  228         /*
  229          * Construct sockaddr format source address.
  230          */
  231         init_sin6(&fromsa, m);
  232         fromsa.sin6_port = uh->uh_sport;
  233 
  234         INP_INFO_RLOCK(&V_udbinfo);
  235         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  236                 struct inpcb *last;
  237                 struct ip6_moptions *imo;
  238 
  239                 /*
  240                  * In the event that laddr should be set to the link-local
  241                  * address (this happens in RIPng), the multicast address
  242                  * specified in the received packet will not match laddr.  To
  243                  * handle this situation, matching is relaxed if the
  244                  * receiving interface is the same as one specified in the
  245                  * socket and if the destination multicast address matches
  246                  * one of the multicast groups specified in the socket.
  247                  */
  248 
  249                 /*
  250                  * KAME note: traditionally we dropped udpiphdr from mbuf
  251                  * here.  We need udphdr for IPsec processing so we do that
  252                  * later.
  253                  */
  254                 last = NULL;
  255                 LIST_FOREACH(inp, &V_udb, inp_list) {
  256                         if ((inp->inp_vflag & INP_IPV6) == 0)
  257                                 continue;
  258                         if (inp->inp_lport != uh->uh_dport)
  259                                 continue;
  260                         if (inp->inp_fport != 0 &&
  261                             inp->inp_fport != uh->uh_sport)
  262                                 continue;
  263                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
  264                                 if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
  265                                                         &ip6->ip6_dst))
  266                                         continue;
  267                         }
  268                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  269                                 if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
  270                                                         &ip6->ip6_src) ||
  271                                     inp->inp_fport != uh->uh_sport)
  272                                         continue;
  273                         }
  274 
  275                         /*
  276                          * Detached PCBs can linger in the list if someone
  277                          * holds a reference. (e.g. udp_pcblist)
  278                          */
  279                         if (inp->inp_socket == NULL)
  280                                 continue;
  281 
  282                         /*
  283                          * Handle socket delivery policy for any-source
  284                          * and source-specific multicast. [RFC3678]
  285                          */
  286                         imo = inp->in6p_moptions;
  287                         if (imo && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  288                                 struct sockaddr_in6      mcaddr;
  289                                 int                      blocked;
  290 
  291                                 INP_RLOCK(inp);
  292 
  293                                 bzero(&mcaddr, sizeof(struct sockaddr_in6));
  294                                 mcaddr.sin6_len = sizeof(struct sockaddr_in6);
  295                                 mcaddr.sin6_family = AF_INET6;
  296                                 mcaddr.sin6_addr = ip6->ip6_dst;
  297 
  298                                 blocked = im6o_mc_filter(imo, ifp,
  299                                         (struct sockaddr *)&mcaddr,
  300                                         (struct sockaddr *)&fromsa);
  301                                 if (blocked != MCAST_PASS) {
  302                                         if (blocked == MCAST_NOTGMEMBER)
  303                                                 IP6STAT_INC(ip6s_notmember);
  304                                         if (blocked == MCAST_NOTSMEMBER ||
  305                                             blocked == MCAST_MUTED)
  306                                                 UDPSTAT_INC(udps_filtermcast);
  307                                         INP_RUNLOCK(inp); /* XXX */
  308                                         continue;
  309                                 }
  310 
  311                                 INP_RUNLOCK(inp);
  312                         }
  313                         if (last != NULL) {
  314                                 struct mbuf *n;
  315 
  316                                 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
  317                                         INP_RLOCK(last);
  318                                         up = intoudpcb(last);
  319                                         if (up->u_tun_func == NULL) {
  320                                                 udp6_append(last, n, off, &fromsa);
  321                                         } else {
  322                                                 /*
  323                                                  * Engage the tunneling
  324                                                  * protocol we will have to
  325                                                  * leave the info_lock up,
  326                                                  * since we are hunting
  327                                                  * through multiple UDP's.
  328                                                  * 
  329                                                  */
  330                                                 (*up->u_tun_func)(n, off, last);
  331                                         }
  332                                         INP_RUNLOCK(last);
  333                                 }
  334                         }
  335                         last = inp;
  336                         /*
  337                          * Don't look for additional matches if this one does
  338                          * not have either the SO_REUSEPORT or SO_REUSEADDR
  339                          * socket options set.  This heuristic avoids
  340                          * searching through all pcbs in the common case of a
  341                          * non-shared port.  It assumes that an application
  342                          * will never clear these options after setting them.
  343                          */
  344                         if ((last->inp_socket->so_options &
  345                              (SO_REUSEPORT|SO_REUSEADDR)) == 0)
  346                                 break;
  347                 }
  348 
  349                 if (last == NULL) {
  350                         /*
  351                          * No matching pcb found; discard datagram.  (No need
  352                          * to send an ICMP Port Unreachable for a broadcast
  353                          * or multicast datgram.)
  354                          */
  355                         UDPSTAT_INC(udps_noport);
  356                         UDPSTAT_INC(udps_noportmcast);
  357                         goto badheadlocked;
  358                 }
  359                 INP_RLOCK(last);
  360                 INP_INFO_RUNLOCK(&V_udbinfo);
  361                 up = intoudpcb(last);
  362                 if (up->u_tun_func == NULL) {
  363                         udp6_append(last, m, off, &fromsa);
  364                 } else {
  365                         /*
  366                          * Engage the tunneling protocol.
  367                          */
  368                         (*up->u_tun_func)(m, off, last);
  369                 }
  370                 INP_RUNLOCK(last);
  371                 return (IPPROTO_DONE);
  372         }
  373         /*
  374          * Locate pcb for datagram.
  375          */
  376         inp = in6_pcblookup_hash(&V_udbinfo, &ip6->ip6_src, uh->uh_sport,
  377             &ip6->ip6_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
  378         if (inp == NULL) {
  379                 if (udp_log_in_vain) {
  380                         char ip6bufs[INET6_ADDRSTRLEN];
  381                         char ip6bufd[INET6_ADDRSTRLEN];
  382 
  383                         log(LOG_INFO,
  384                             "Connection attempt to UDP [%s]:%d from [%s]:%d\n",
  385                             ip6_sprintf(ip6bufd, &ip6->ip6_dst),
  386                             ntohs(uh->uh_dport),
  387                             ip6_sprintf(ip6bufs, &ip6->ip6_src),
  388                             ntohs(uh->uh_sport));
  389                 }
  390                 UDPSTAT_INC(udps_noport);
  391                 if (m->m_flags & M_MCAST) {
  392                         printf("UDP6: M_MCAST is set in a unicast packet.\n");
  393                         UDPSTAT_INC(udps_noportmcast);
  394                         goto badheadlocked;
  395                 }
  396                 INP_INFO_RUNLOCK(&V_udbinfo);
  397                 if (V_udp_blackhole)
  398                         goto badunlocked;
  399                 if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0)
  400                         goto badunlocked;
  401                 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
  402                 return (IPPROTO_DONE);
  403         }
  404         INP_RLOCK(inp);
  405         INP_INFO_RUNLOCK(&V_udbinfo);
  406 
  407         /*
  408          * Detached PCBs can linger in the hash table if someone holds a
  409          * reference. (e.g. udp_pcblist)
  410          */
  411         if (inp->inp_socket == NULL) {
  412                 INP_RUNLOCK(inp);
  413                 goto badunlocked;
  414         }
  415         up = intoudpcb(inp);
  416         if (up->u_tun_func == NULL) {
  417                 udp6_append(inp, m, off, &fromsa);
  418         } else {
  419                 /*
  420                  * Engage the tunneling protocol.
  421                  */
  422 
  423                 (*up->u_tun_func)(m, off, inp);
  424         }
  425         INP_RUNLOCK(inp);
  426         return (IPPROTO_DONE);
  427 
  428 badheadlocked:
  429         INP_INFO_RUNLOCK(&V_udbinfo);
  430 badunlocked:
  431         if (m)
  432                 m_freem(m);
  433         return (IPPROTO_DONE);
  434 }
  435 
  436 void
  437 udp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
  438 {
  439         struct udphdr uh;
  440         struct ip6_hdr *ip6;
  441         struct mbuf *m;
  442         int off = 0;
  443         struct ip6ctlparam *ip6cp = NULL;
  444         const struct sockaddr_in6 *sa6_src = NULL;
  445         void *cmdarg;
  446         struct inpcb *(*notify)(struct inpcb *, int) = udp_notify;
  447         struct udp_portonly {
  448                 u_int16_t uh_sport;
  449                 u_int16_t uh_dport;
  450         } *uhp;
  451 
  452         if (sa->sa_family != AF_INET6 ||
  453             sa->sa_len != sizeof(struct sockaddr_in6))
  454                 return;
  455 
  456         if ((unsigned)cmd >= PRC_NCMDS)
  457                 return;
  458         if (PRC_IS_REDIRECT(cmd))
  459                 notify = in6_rtchange, d = NULL;
  460         else if (cmd == PRC_HOSTDEAD)
  461                 d = NULL;
  462         else if (inet6ctlerrmap[cmd] == 0)
  463                 return;
  464 
  465         /* if the parameter is from icmp6, decode it. */
  466         if (d != NULL) {
  467                 ip6cp = (struct ip6ctlparam *)d;
  468                 m = ip6cp->ip6c_m;
  469                 ip6 = ip6cp->ip6c_ip6;
  470                 off = ip6cp->ip6c_off;
  471                 cmdarg = ip6cp->ip6c_cmdarg;
  472                 sa6_src = ip6cp->ip6c_src;
  473         } else {
  474                 m = NULL;
  475                 ip6 = NULL;
  476                 cmdarg = NULL;
  477                 sa6_src = &sa6_any;
  478         }
  479 
  480         if (ip6) {
  481                 /*
  482                  * XXX: We assume that when IPV6 is non NULL,
  483                  * M and OFF are valid.
  484                  */
  485 
  486                 /* Check if we can safely examine src and dst ports. */
  487                 if (m->m_pkthdr.len < off + sizeof(*uhp))
  488                         return;
  489 
  490                 bzero(&uh, sizeof(uh));
  491                 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
  492 
  493                 (void) in6_pcbnotify(&V_udbinfo, sa, uh.uh_dport,
  494                     (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd,
  495                     cmdarg, notify);
  496         } else
  497                 (void) in6_pcbnotify(&V_udbinfo, sa, 0,
  498                     (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
  499 }
  500 
  501 static int
  502 udp6_getcred(SYSCTL_HANDLER_ARGS)
  503 {
  504         struct xucred xuc;
  505         struct sockaddr_in6 addrs[2];
  506         struct inpcb *inp;
  507         int error;
  508 
  509         error = priv_check(req->td, PRIV_NETINET_GETCRED);
  510         if (error)
  511                 return (error);
  512 
  513         if (req->newlen != sizeof(addrs))
  514                 return (EINVAL);
  515         if (req->oldlen != sizeof(struct xucred))
  516                 return (EINVAL);
  517         error = SYSCTL_IN(req, addrs, sizeof(addrs));
  518         if (error)
  519                 return (error);
  520         if ((error = sa6_embedscope(&addrs[0], V_ip6_use_defzone)) != 0 ||
  521             (error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) {
  522                 return (error);
  523         }
  524         INP_INFO_RLOCK(&V_udbinfo);
  525         inp = in6_pcblookup_hash(&V_udbinfo, &addrs[1].sin6_addr,
  526             addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1,
  527             NULL);
  528         if (inp != NULL) {
  529                 INP_RLOCK(inp);
  530                 INP_INFO_RUNLOCK(&V_udbinfo);
  531                 if (inp->inp_socket == NULL)
  532                         error = ENOENT;
  533                 if (error == 0)
  534                         error = cr_canseesocket(req->td->td_ucred,
  535                             inp->inp_socket);
  536                 if (error == 0)
  537                         cru2x(inp->inp_cred, &xuc);
  538                 INP_RUNLOCK(inp);
  539         } else {
  540                 INP_INFO_RUNLOCK(&V_udbinfo);
  541                 error = ENOENT;
  542         }
  543         if (error == 0)
  544                 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
  545         return (error);
  546 }
  547 
  548 SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0,
  549     0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection");
  550 
  551 static int
  552 udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
  553     struct mbuf *control, struct thread *td)
  554 {
  555         u_int32_t ulen = m->m_pkthdr.len;
  556         u_int32_t plen = sizeof(struct udphdr) + ulen;
  557         struct ip6_hdr *ip6;
  558         struct udphdr *udp6;
  559         struct in6_addr *laddr, *faddr, in6a;
  560         struct sockaddr_in6 *sin6 = NULL;
  561         struct ifnet *oifp = NULL;
  562         int scope_ambiguous = 0;
  563         u_short fport;
  564         int error = 0;
  565         struct ip6_pktopts *optp, opt;
  566         int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
  567         int flags;
  568         struct sockaddr_in6 tmp;
  569 
  570         INP_WLOCK_ASSERT(inp);
  571 
  572         if (addr6) {
  573                 /* addr6 has been validated in udp6_send(). */
  574                 sin6 = (struct sockaddr_in6 *)addr6;
  575 
  576                 /* protect *sin6 from overwrites */
  577                 tmp = *sin6;
  578                 sin6 = &tmp;
  579 
  580                 /*
  581                  * Application should provide a proper zone ID or the use of
  582                  * default zone IDs should be enabled.  Unfortunately, some
  583                  * applications do not behave as it should, so we need a
  584                  * workaround.  Even if an appropriate ID is not determined,
  585                  * we'll see if we can determine the outgoing interface.  If we
  586                  * can, determine the zone ID based on the interface below.
  587                  */
  588                 if (sin6->sin6_scope_id == 0 && !V_ip6_use_defzone)
  589                         scope_ambiguous = 1;
  590                 if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0)
  591                         return (error);
  592         }
  593 
  594         if (control) {
  595                 if ((error = ip6_setpktopts(control, &opt,
  596                     inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0)
  597                         goto release;
  598                 optp = &opt;
  599         } else
  600                 optp = inp->in6p_outputopts;
  601 
  602         if (sin6) {
  603                 faddr = &sin6->sin6_addr;
  604 
  605                 /*
  606                  * IPv4 version of udp_output calls in_pcbconnect in this case,
  607                  * which needs splnet and affects performance.
  608                  * Since we saw no essential reason for calling in_pcbconnect,
  609                  * we get rid of such kind of logic, and call in6_selectsrc
  610                  * and in6_pcbsetport in order to fill in the local address
  611                  * and the local port.
  612                  */
  613                 if (sin6->sin6_port == 0) {
  614                         error = EADDRNOTAVAIL;
  615                         goto release;
  616                 }
  617 
  618                 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  619                         /* how about ::ffff:0.0.0.0 case? */
  620                         error = EISCONN;
  621                         goto release;
  622                 }
  623 
  624                 fport = sin6->sin6_port; /* allow 0 port */
  625 
  626                 if (IN6_IS_ADDR_V4MAPPED(faddr)) {
  627                         if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) {
  628                                 /*
  629                                  * I believe we should explicitly discard the
  630                                  * packet when mapped addresses are disabled,
  631                                  * rather than send the packet as an IPv6 one.
  632                                  * If we chose the latter approach, the packet
  633                                  * might be sent out on the wire based on the
  634                                  * default route, the situation which we'd
  635                                  * probably want to avoid.
  636                                  * (20010421 jinmei@kame.net)
  637                                  */
  638                                 error = EINVAL;
  639                                 goto release;
  640                         }
  641                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
  642                             !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) {
  643                                 /*
  644                                  * when remote addr is an IPv4-mapped address,
  645                                  * local addr should not be an IPv6 address,
  646                                  * since you cannot determine how to map IPv6
  647                                  * source address to IPv4.
  648                                  */
  649                                 error = EINVAL;
  650                                 goto release;
  651                         }
  652 
  653                         af = AF_INET;
  654                 }
  655 
  656                 if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
  657                         error = in6_selectsrc(sin6, optp, inp, NULL,
  658                             td->td_ucred, &oifp, &in6a);
  659                         if (error)
  660                                 goto release;
  661                         if (oifp && scope_ambiguous &&
  662                             (error = in6_setscope(&sin6->sin6_addr,
  663                             oifp, NULL))) {
  664                                 goto release;
  665                         }
  666                         laddr = &in6a;
  667                 } else
  668                         laddr = &inp->in6p_laddr;       /* XXX */
  669                 if (laddr == NULL) {
  670                         if (error == 0)
  671                                 error = EADDRNOTAVAIL;
  672                         goto release;
  673                 }
  674                 if (inp->inp_lport == 0 &&
  675                     (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) {
  676                         /* Undo an address bind that may have occurred. */
  677                         inp->in6p_laddr = in6addr_any;
  678                         goto release;
  679                 }
  680         } else {
  681                 if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  682                         error = ENOTCONN;
  683                         goto release;
  684                 }
  685                 if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) {
  686                         if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) {
  687                                 /*
  688                                  * XXX: this case would happen when the
  689                                  * application sets the V6ONLY flag after
  690                                  * connecting the foreign address.
  691                                  * Such applications should be fixed,
  692                                  * so we bark here.
  693                                  */
  694                                 log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
  695                                     "option was set for a connected socket\n");
  696                                 error = EINVAL;
  697                                 goto release;
  698                         } else
  699                                 af = AF_INET;
  700                 }
  701                 laddr = &inp->in6p_laddr;
  702                 faddr = &inp->in6p_faddr;
  703                 fport = inp->inp_fport;
  704         }
  705 
  706         if (af == AF_INET)
  707                 hlen = sizeof(struct ip);
  708 
  709         /*
  710          * Calculate data length and get a mbuf
  711          * for UDP and IP6 headers.
  712          */
  713         M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
  714         if (m == 0) {
  715                 error = ENOBUFS;
  716                 goto release;
  717         }
  718 
  719         /*
  720          * Stuff checksum and output datagram.
  721          */
  722         udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
  723         udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */
  724         udp6->uh_dport = fport;
  725         if (plen <= 0xffff)
  726                 udp6->uh_ulen = htons((u_short)plen);
  727         else
  728                 udp6->uh_ulen = 0;
  729         udp6->uh_sum = 0;
  730 
  731         switch (af) {
  732         case AF_INET6:
  733                 ip6 = mtod(m, struct ip6_hdr *);
  734                 ip6->ip6_flow   = inp->inp_flow & IPV6_FLOWINFO_MASK;
  735                 ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
  736                 ip6->ip6_vfc    |= IPV6_VERSION;
  737 #if 0                           /* ip6_plen will be filled in ip6_output. */
  738                 ip6->ip6_plen   = htons((u_short)plen);
  739 #endif
  740                 ip6->ip6_nxt    = IPPROTO_UDP;
  741                 ip6->ip6_hlim   = in6_selecthlim(inp, NULL);
  742                 ip6->ip6_src    = *laddr;
  743                 ip6->ip6_dst    = *faddr;
  744 
  745                 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
  746                                 sizeof(struct ip6_hdr), plen)) == 0) {
  747                         udp6->uh_sum = 0xffff;
  748                 }
  749 
  750                 flags = 0;
  751 
  752                 UDPSTAT_INC(udps_opackets);
  753                 error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions,
  754                     NULL, inp);
  755                 break;
  756         case AF_INET:
  757                 error = EAFNOSUPPORT;
  758                 goto release;
  759         }
  760         goto releaseopt;
  761 
  762 release:
  763         m_freem(m);
  764 
  765 releaseopt:
  766         if (control) {
  767                 ip6_clearpktopts(&opt, -1);
  768                 m_freem(control);
  769         }
  770         return (error);
  771 }
  772 
  773 static void
  774 udp6_abort(struct socket *so)
  775 {
  776         struct inpcb *inp;
  777 
  778         inp = sotoinpcb(so);
  779         KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
  780 
  781 #ifdef INET
  782         if (inp->inp_vflag & INP_IPV4) {
  783                 struct pr_usrreqs *pru;
  784 
  785                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  786                 (*pru->pru_abort)(so);
  787                 return;
  788         }
  789 #endif
  790 
  791         INP_INFO_WLOCK(&V_udbinfo);
  792         INP_WLOCK(inp);
  793         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  794                 in6_pcbdisconnect(inp);
  795                 inp->in6p_laddr = in6addr_any;
  796                 soisdisconnected(so);
  797         }
  798         INP_WUNLOCK(inp);
  799         INP_INFO_WUNLOCK(&V_udbinfo);
  800 }
  801 
  802 static int
  803 udp6_attach(struct socket *so, int proto, struct thread *td)
  804 {
  805         struct inpcb *inp;
  806         int error;
  807 
  808         inp = sotoinpcb(so);
  809         KASSERT(inp == NULL, ("udp6_attach: inp != NULL"));
  810 
  811         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  812                 error = soreserve(so, udp_sendspace, udp_recvspace);
  813                 if (error)
  814                         return (error);
  815         }
  816         INP_INFO_WLOCK(&V_udbinfo);
  817         error = in_pcballoc(so, &V_udbinfo);
  818         if (error) {
  819                 INP_INFO_WUNLOCK(&V_udbinfo);
  820                 return (error);
  821         }
  822         inp = (struct inpcb *)so->so_pcb;
  823         inp->inp_vflag |= INP_IPV6;
  824         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
  825                 inp->inp_vflag |= INP_IPV4;
  826         inp->in6p_hops = -1;    /* use kernel default */
  827         inp->in6p_cksum = -1;   /* just to be sure */
  828         /*
  829          * XXX: ugly!!
  830          * IPv4 TTL initialization is necessary for an IPv6 socket as well,
  831          * because the socket may be bound to an IPv6 wildcard address,
  832          * which may match an IPv4-mapped IPv6 address.
  833          */
  834         inp->inp_ip_ttl = V_ip_defttl;
  835 
  836         error = udp_newudpcb(inp);
  837         if (error) {
  838                 in_pcbdetach(inp);
  839                 in_pcbfree(inp);
  840                 INP_INFO_WUNLOCK(&V_udbinfo);
  841                 return (error);
  842         }
  843         INP_WUNLOCK(inp);
  844         INP_INFO_WUNLOCK(&V_udbinfo);
  845         return (0);
  846 }
  847 
  848 static int
  849 udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  850 {
  851         struct inpcb *inp;
  852         int error;
  853 
  854         inp = sotoinpcb(so);
  855         KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
  856 
  857         INP_INFO_WLOCK(&V_udbinfo);
  858         INP_WLOCK(inp);
  859         inp->inp_vflag &= ~INP_IPV4;
  860         inp->inp_vflag |= INP_IPV6;
  861         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  862                 struct sockaddr_in6 *sin6_p;
  863 
  864                 sin6_p = (struct sockaddr_in6 *)nam;
  865 
  866                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
  867                         inp->inp_vflag |= INP_IPV4;
  868                 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  869                         struct sockaddr_in sin;
  870 
  871                         in6_sin6_2_sin(&sin, sin6_p);
  872                         inp->inp_vflag |= INP_IPV4;
  873                         inp->inp_vflag &= ~INP_IPV6;
  874                         error = in_pcbbind(inp, (struct sockaddr *)&sin,
  875                             td->td_ucred);
  876                         goto out;
  877                 }
  878         }
  879 
  880         error = in6_pcbbind(inp, nam, td->td_ucred);
  881 out:
  882         INP_WUNLOCK(inp);
  883         INP_INFO_WUNLOCK(&V_udbinfo);
  884         return (error);
  885 }
  886 
  887 static void
  888 udp6_close(struct socket *so)
  889 {
  890         struct inpcb *inp;
  891 
  892         inp = sotoinpcb(so);
  893         KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
  894 
  895 #ifdef INET
  896         if (inp->inp_vflag & INP_IPV4) {
  897                 struct pr_usrreqs *pru;
  898 
  899                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  900                 (*pru->pru_disconnect)(so);
  901                 return;
  902         }
  903 #endif
  904         INP_INFO_WLOCK(&V_udbinfo);
  905         INP_WLOCK(inp);
  906         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  907                 in6_pcbdisconnect(inp);
  908                 inp->in6p_laddr = in6addr_any;
  909                 soisdisconnected(so);
  910         }
  911         INP_WUNLOCK(inp);
  912         INP_INFO_WUNLOCK(&V_udbinfo);
  913 }
  914 
  915 static int
  916 udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  917 {
  918         struct inpcb *inp;
  919         struct sockaddr_in6 *sin6;
  920         int error;
  921 
  922         inp = sotoinpcb(so);
  923         sin6 = (struct sockaddr_in6 *)nam;
  924         KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
  925 
  926         INP_INFO_WLOCK(&V_udbinfo);
  927         INP_WLOCK(inp);
  928         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  929                 struct sockaddr_in sin;
  930 
  931                 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
  932                         error = EINVAL;
  933                         goto out;
  934                 }
  935                 if (inp->inp_faddr.s_addr != INADDR_ANY) {
  936                         error = EISCONN;
  937                         goto out;
  938                 }
  939                 in6_sin6_2_sin(&sin, sin6);
  940                 inp->inp_vflag |= INP_IPV4;
  941                 inp->inp_vflag &= ~INP_IPV6;
  942                 error = prison_remote_ip4(td->td_ucred, &sin.sin_addr);
  943                 if (error != 0)
  944                         goto out;
  945                 error = in_pcbconnect(inp, (struct sockaddr *)&sin,
  946                     td->td_ucred);
  947                 if (error == 0)
  948                         soisconnected(so);
  949                 goto out;
  950         }
  951         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  952                 error = EISCONN;
  953                 goto out;
  954         }
  955         inp->inp_vflag &= ~INP_IPV4;
  956         inp->inp_vflag |= INP_IPV6;
  957         error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr);
  958         if (error != 0)
  959                 goto out;
  960         error = in6_pcbconnect(inp, nam, td->td_ucred);
  961         if (error == 0)
  962                 soisconnected(so);
  963 out:
  964         INP_WUNLOCK(inp);
  965         INP_INFO_WUNLOCK(&V_udbinfo);
  966         return (error);
  967 }
  968 
  969 static void
  970 udp6_detach(struct socket *so)
  971 {
  972         struct inpcb *inp;
  973         struct udpcb *up;
  974 
  975         inp = sotoinpcb(so);
  976         KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
  977 
  978         INP_INFO_WLOCK(&V_udbinfo);
  979         INP_WLOCK(inp);
  980         up = intoudpcb(inp);
  981         KASSERT(up != NULL, ("%s: up == NULL", __func__));
  982         in_pcbdetach(inp);
  983         in_pcbfree(inp);
  984         INP_INFO_WUNLOCK(&V_udbinfo);
  985         udp_discardcb(up);
  986 }
  987 
  988 static int
  989 udp6_disconnect(struct socket *so)
  990 {
  991         struct inpcb *inp;
  992         int error;
  993 
  994         inp = sotoinpcb(so);
  995         KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
  996 
  997         INP_INFO_WLOCK(&V_udbinfo);
  998         INP_WLOCK(inp);
  999 
 1000 #ifdef INET
 1001         if (inp->inp_vflag & INP_IPV4) {
 1002                 struct pr_usrreqs *pru;
 1003 
 1004                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
 1005                 error = (*pru->pru_disconnect)(so);
 1006                 goto out;
 1007         }
 1008 #endif
 1009 
 1010         if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
 1011                 error = ENOTCONN;
 1012                 goto out;
 1013         }
 1014 
 1015         in6_pcbdisconnect(inp);
 1016         inp->in6p_laddr = in6addr_any;
 1017         SOCK_LOCK(so);
 1018         so->so_state &= ~SS_ISCONNECTED;                /* XXX */
 1019         SOCK_UNLOCK(so);
 1020 out:
 1021         INP_WUNLOCK(inp);
 1022         INP_INFO_WUNLOCK(&V_udbinfo);
 1023         return (0);
 1024 }
 1025 
 1026 static int
 1027 udp6_send(struct socket *so, int flags, struct mbuf *m,
 1028     struct sockaddr *addr, struct mbuf *control, struct thread *td)
 1029 {
 1030         struct inpcb *inp;
 1031         int error = 0;
 1032 
 1033         inp = sotoinpcb(so);
 1034         KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
 1035 
 1036         INP_INFO_WLOCK(&V_udbinfo);
 1037         INP_WLOCK(inp);
 1038         if (addr) {
 1039                 if (addr->sa_len != sizeof(struct sockaddr_in6)) {
 1040                         error = EINVAL;
 1041                         goto bad;
 1042                 }
 1043                 if (addr->sa_family != AF_INET6) {
 1044                         error = EAFNOSUPPORT;
 1045                         goto bad;
 1046                 }
 1047         }
 1048 
 1049 #ifdef INET
 1050         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
 1051                 int hasv4addr;
 1052                 struct sockaddr_in6 *sin6 = 0;
 1053 
 1054                 if (addr == 0)
 1055                         hasv4addr = (inp->inp_vflag & INP_IPV4);
 1056                 else {
 1057                         sin6 = (struct sockaddr_in6 *)addr;
 1058                         hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
 1059                             ? 1 : 0;
 1060                 }
 1061                 if (hasv4addr) {
 1062                         struct pr_usrreqs *pru;
 1063 
 1064                         /*
 1065                          * XXXRW: We release UDP-layer locks before calling
 1066                          * udp_send() in order to avoid recursion.  However,
 1067                          * this does mean there is a short window where inp's
 1068                          * fields are unstable.  Could this lead to a
 1069                          * potential race in which the factors causing us to
 1070                          * select the UDPv4 output routine are invalidated?
 1071                          */
 1072                         INP_WUNLOCK(inp);
 1073                         INP_INFO_WUNLOCK(&V_udbinfo);
 1074                         if (sin6)
 1075                                 in6_sin6_2_sin_in_sock(addr);
 1076                         pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
 1077                         /* addr will just be freed in sendit(). */
 1078                         return ((*pru->pru_send)(so, flags, m, addr, control,
 1079                             td));
 1080                 }
 1081         }
 1082 #endif
 1083 #ifdef MAC
 1084         mac_inpcb_create_mbuf(inp, m);
 1085 #endif
 1086         error = udp6_output(inp, m, addr, control, td);
 1087         INP_WUNLOCK(inp);
 1088         INP_INFO_WUNLOCK(&V_udbinfo);
 1089         return (error);
 1090 
 1091 bad:
 1092         INP_WUNLOCK(inp);
 1093         INP_INFO_WUNLOCK(&V_udbinfo);
 1094         m_freem(m);
 1095         return (error);
 1096 }
 1097 
 1098 struct pr_usrreqs udp6_usrreqs = {
 1099         .pru_abort =            udp6_abort,
 1100         .pru_attach =           udp6_attach,
 1101         .pru_bind =             udp6_bind,
 1102         .pru_connect =          udp6_connect,
 1103         .pru_control =          in6_control,
 1104         .pru_detach =           udp6_detach,
 1105         .pru_disconnect =       udp6_disconnect,
 1106         .pru_peeraddr =         in6_mapped_peeraddr,
 1107         .pru_send =             udp6_send,
 1108         .pru_shutdown =         udp_shutdown,
 1109         .pru_sockaddr =         in6_mapped_sockaddr,
 1110         .pru_soreceive =        soreceive_dgram,
 1111         .pru_sosend =           sosend_dgram,
 1112         .pru_sosetlabel =       in_pcbsosetlabel,
 1113         .pru_close =            udp6_close
 1114 };

Cache object: a1c15391f9dc2ff60e87d6cebaa1ce10


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