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/netpfil/pf/pf_syncookies.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 /*      $OpenBSD: pf_syncookies.c,v 1.7 2018/09/10 15:54:28 henning Exp $ */
    2 
    3 /* Copyright (c) 2016,2017 Henning Brauer <henning@openbsd.org>
    4  * Copyright (c) 2016 Alexandr Nedvedicky <sashan@openbsd.org>
    5  *
    6  * syncookie parts based on FreeBSD sys/netinet/tcp_syncache.c
    7  *
    8  * Copyright (c) 2001 McAfee, Inc.
    9  * Copyright (c) 2006,2013 Andre Oppermann, Internet Business Solutions AG
   10  * All rights reserved.
   11  *
   12  * This software was developed for the FreeBSD Project by Jonathan Lemon
   13  * and McAfee Research, the Security Research Division of McAfee, Inc. under
   14  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
   15  * DARPA CHATS research program. [2001 McAfee, Inc.]
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * when we're under synflood, we use syncookies to prevent state table
   41  * exhaustion. Trigger for the synflood mode is the number of half-open
   42  * connections in the state table.
   43  * We leave synflood mode when the number of half-open states - including
   44  * in-flight syncookies - drops far enough again
   45  */
   46  
   47 /*
   48  * syncookie enabled Initial Sequence Number:
   49  *  24 bit MAC
   50  *   3 bit WSCALE index
   51  *   3 bit MSS index
   52  *   1 bit SACK permitted
   53  *   1 bit odd/even secret
   54  *
   55  * References:
   56  *  RFC4987 TCP SYN Flooding Attacks and Common Mitigations
   57  *  http://cr.yp.to/syncookies.html    (overview)
   58  *  http://cr.yp.to/syncookies/archive (details)
   59  */
   60 
   61 //#include "pflog.h"
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/mbuf.h>
   66 #include <sys/filio.h>
   67 #include <sys/socket.h>
   68 #include <sys/socketvar.h>
   69 #include <sys/kernel.h>
   70 #include <sys/time.h>
   71 #include <sys/proc.h>
   72 #include <sys/rwlock.h>
   73 #include <sys/syslog.h>
   74 
   75 #include <crypto/siphash/siphash.h>
   76 
   77 #include <net/if.h>
   78 #include <net/if_var.h>
   79 #include <net/if_types.h>
   80 #include <net/route.h>
   81 
   82 #include <netinet/in.h>
   83 #include <netinet/in_pcb.h>
   84 #include <netinet/ip.h>
   85 #include <netinet/tcp.h>
   86 #include <netinet/tcp_var.h>
   87 
   88 #include <net/pfvar.h>
   89 #include <netpfil/pf/pf_nv.h>
   90 
   91 #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
   92 
   93 union pf_syncookie {
   94         uint8_t         cookie;
   95         struct {
   96                 uint8_t oddeven:1,
   97                         sack_ok:1,
   98                         wscale_idx:3,
   99                         mss_idx:3;
  100         } flags;
  101 };
  102 
  103 #define PF_SYNCOOKIE_SECRET_SIZE        SIPHASH_KEY_LENGTH
  104 #define PF_SYNCOOKIE_SECRET_LIFETIME    15 /* seconds */
  105 
  106 /* Protected by PF_RULES_xLOCK. */
  107 struct pf_syncookie_status {
  108         struct callout  keytimeout;
  109         uint8_t         oddeven;
  110         uint8_t         key[2][SIPHASH_KEY_LENGTH];
  111         uint32_t        hiwat;  /* absolute; # of states */
  112         uint32_t        lowat;
  113 };
  114 VNET_DEFINE_STATIC(struct pf_syncookie_status, pf_syncookie_status);
  115 #define V_pf_syncookie_status   VNET(pf_syncookie_status)
  116 
  117 static int      pf_syncookies_setmode(u_int8_t);
  118 void            pf_syncookie_rotate(void *);
  119 void            pf_syncookie_newkey(void);
  120 uint32_t        pf_syncookie_mac(struct pf_pdesc *, union pf_syncookie,
  121                     uint32_t);
  122 uint32_t        pf_syncookie_generate(struct mbuf *m, int off, struct pf_pdesc *,
  123                     uint16_t);
  124 
  125 void
  126 pf_syncookies_init(void)
  127 {
  128         callout_init(&V_pf_syncookie_status.keytimeout, 1);
  129         PF_RULES_WLOCK();
  130 
  131         V_pf_syncookie_status.hiwat = PF_SYNCOOKIES_HIWATPCT *
  132             V_pf_limits[PF_LIMIT_STATES].limit / 100;
  133         V_pf_syncookie_status.lowat = PF_SYNCOOKIES_LOWATPCT *
  134             V_pf_limits[PF_LIMIT_STATES].limit / 100;
  135         pf_syncookies_setmode(PF_SYNCOOKIES_ADAPTIVE);
  136 
  137         PF_RULES_WUNLOCK();
  138 }
  139 
  140 void
  141 pf_syncookies_cleanup(void)
  142 {
  143         callout_stop(&V_pf_syncookie_status.keytimeout);
  144 }
  145 
  146 int
  147 pf_get_syncookies(struct pfioc_nv *nv)
  148 {
  149         nvlist_t        *nvl = NULL;
  150         void            *nvlpacked = NULL;
  151         int              error;
  152 
  153 #define ERROUT(x)       ERROUT_FUNCTION(errout, x)
  154 
  155         nvl = nvlist_create(0);
  156         if (nvl == NULL)
  157                 ERROUT(ENOMEM);
  158 
  159         nvlist_add_bool(nvl, "enabled",
  160             V_pf_status.syncookies_mode != PF_SYNCOOKIES_NEVER);
  161         nvlist_add_bool(nvl, "adaptive",
  162             V_pf_status.syncookies_mode == PF_SYNCOOKIES_ADAPTIVE);
  163         nvlist_add_number(nvl, "highwater", V_pf_syncookie_status.hiwat);
  164         nvlist_add_number(nvl, "lowwater", V_pf_syncookie_status.lowat);
  165 
  166         nvlpacked = nvlist_pack(nvl, &nv->len);
  167         if (nvlpacked == NULL)
  168                 ERROUT(ENOMEM);
  169 
  170         if (nv->size == 0) {
  171                 ERROUT(0);
  172         } else if (nv->size < nv->len) {
  173                 ERROUT(ENOSPC);
  174         }
  175 
  176         error = copyout(nvlpacked, nv->data, nv->len);
  177 
  178 #undef ERROUT
  179 errout:
  180         nvlist_destroy(nvl);
  181         free(nvlpacked, M_NVLIST);
  182 
  183         return (error);
  184 }
  185 
  186 int
  187 pf_set_syncookies(struct pfioc_nv *nv)
  188 {
  189         nvlist_t        *nvl = NULL;
  190         void            *nvlpacked = NULL;
  191         int              error;
  192         bool             enabled, adaptive;
  193         uint32_t         hiwat, lowat;
  194         uint8_t          newmode;
  195 
  196 #define ERROUT(x)       ERROUT_FUNCTION(errout, x)
  197 
  198         if (nv->len > pf_ioctl_maxcount)
  199                 return (ENOMEM);
  200 
  201         nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK);
  202         if (nvlpacked == NULL)
  203                 return (ENOMEM);
  204 
  205         error = copyin(nv->data, nvlpacked, nv->len);
  206         if (error)
  207                 ERROUT(error);
  208 
  209         nvl = nvlist_unpack(nvlpacked, nv->len, 0);
  210         if (nvl == NULL)
  211                 ERROUT(EBADMSG);
  212 
  213         if (! nvlist_exists_bool(nvl, "enabled")
  214             || ! nvlist_exists_bool(nvl, "adaptive"))
  215                 ERROUT(EBADMSG);
  216 
  217         enabled = nvlist_get_bool(nvl, "enabled");
  218         adaptive = nvlist_get_bool(nvl, "adaptive");
  219         PFNV_CHK(pf_nvuint32_opt(nvl, "highwater", &hiwat,
  220             V_pf_syncookie_status.hiwat));
  221         PFNV_CHK(pf_nvuint32_opt(nvl, "lowwater", &lowat,
  222             V_pf_syncookie_status.lowat));
  223 
  224         if (lowat >= hiwat)
  225                 ERROUT(EINVAL);
  226 
  227         newmode = PF_SYNCOOKIES_NEVER;
  228         if (enabled)
  229                 newmode = adaptive ? PF_SYNCOOKIES_ADAPTIVE : PF_SYNCOOKIES_ALWAYS;
  230 
  231         PF_RULES_WLOCK();
  232         error = pf_syncookies_setmode(newmode);
  233 
  234         V_pf_syncookie_status.lowat = lowat;
  235         V_pf_syncookie_status.hiwat = hiwat;
  236 
  237         PF_RULES_WUNLOCK();
  238 
  239 #undef ERROUT
  240 errout:
  241         nvlist_destroy(nvl);
  242         free(nvlpacked, M_NVLIST);
  243 
  244         return (error);
  245 }
  246 
  247 static int
  248 pf_syncookies_setmode(u_int8_t mode)
  249 {
  250         if (mode > PF_SYNCOOKIES_MODE_MAX)
  251                 return (EINVAL);
  252 
  253         if (V_pf_status.syncookies_mode == mode)
  254                 return (0);
  255 
  256         V_pf_status.syncookies_mode = mode;
  257         if (V_pf_status.syncookies_mode == PF_SYNCOOKIES_ALWAYS) {
  258                 pf_syncookie_newkey();
  259                 V_pf_status.syncookies_active = true;
  260         }
  261         return (0);
  262 }
  263 
  264 int
  265 pf_synflood_check(struct pf_pdesc *pd)
  266 {
  267         MPASS(pd->proto == IPPROTO_TCP);
  268         PF_RULES_RASSERT();
  269 
  270         if (pd->pf_mtag && (pd->pf_mtag->tag & PF_TAG_SYNCOOKIE_RECREATED))
  271                 return (0);
  272 
  273         if (V_pf_status.syncookies_mode != PF_SYNCOOKIES_ADAPTIVE)
  274                 return (V_pf_status.syncookies_mode);
  275 
  276         if (!V_pf_status.syncookies_active &&
  277             atomic_load_32(&V_pf_status.states_halfopen) >
  278             V_pf_syncookie_status.hiwat) {
  279                 /* We'd want to 'pf_syncookie_newkey()' here, but that requires
  280                  * the rules write lock, which we can't get with the read lock
  281                  * held. */
  282                 callout_reset(&V_pf_syncookie_status.keytimeout, 0,
  283                     pf_syncookie_rotate, curvnet);
  284                 V_pf_status.syncookies_active = true;
  285                 DPFPRINTF(LOG_WARNING,
  286                     ("synflood detected, enabling syncookies\n"));
  287                 // XXXTODO V_pf_status.lcounters[LCNT_SYNFLOODS]++;
  288         }
  289 
  290         return (V_pf_status.syncookies_active);
  291 }
  292 
  293 void
  294 pf_syncookie_send(struct mbuf *m, int off, struct pf_pdesc *pd)
  295 {
  296         uint16_t        mss;
  297         uint32_t        iss;
  298 
  299         mss = max(V_tcp_mssdflt, pf_get_mss(m, off, pd->hdr.tcp.th_off, pd->af));
  300         iss = pf_syncookie_generate(m, off, pd, mss);
  301         pf_send_tcp(NULL, pd->af, pd->dst, pd->src, *pd->dport, *pd->sport,
  302             iss, ntohl(pd->hdr.tcp.th_seq) + 1, TH_SYN|TH_ACK, 0, mss,
  303             0, 1, 0);
  304         counter_u64_add(V_pf_status.lcounters[KLCNT_SYNCOOKIES_SENT], 1);
  305         /* XXX Maybe only in adaptive mode? */
  306         atomic_add_64(&V_pf_status.syncookies_inflight[V_pf_syncookie_status.oddeven],
  307             1);
  308 }
  309 
  310 bool
  311 pf_syncookie_check(struct pf_pdesc *pd)
  312 {
  313         uint32_t                 hash, ack, seq;
  314         union pf_syncookie       cookie;
  315 
  316         MPASS(pd->proto == IPPROTO_TCP);
  317         PF_RULES_RASSERT();
  318 
  319         seq = ntohl(pd->hdr.tcp.th_seq) - 1;
  320         ack = ntohl(pd->hdr.tcp.th_ack) - 1;
  321         cookie.cookie = (ack & 0xff) ^ (ack >> 24);
  322 
  323         /* we don't know oddeven before setting the cookie (union) */
  324         if (atomic_load_64(&V_pf_status.syncookies_inflight[cookie.flags.oddeven])
  325             == 0)
  326                 return (0);
  327 
  328         hash = pf_syncookie_mac(pd, cookie, seq);
  329         if ((ack & ~0xff) != (hash & ~0xff))
  330                 return (false);
  331 
  332         return (true);
  333 }
  334 
  335 uint8_t
  336 pf_syncookie_validate(struct pf_pdesc *pd)
  337 {
  338         uint32_t                 ack;
  339         union pf_syncookie       cookie;
  340 
  341         if (! pf_syncookie_check(pd))
  342                 return (0);
  343 
  344         ack = ntohl(pd->hdr.tcp.th_ack) - 1;
  345         cookie.cookie = (ack & 0xff) ^ (ack >> 24);
  346 
  347         counter_u64_add(V_pf_status.lcounters[KLCNT_SYNCOOKIES_VALID], 1);
  348         atomic_add_64(&V_pf_status.syncookies_inflight[cookie.flags.oddeven], -1);
  349 
  350         return (1);
  351 }
  352 
  353 /*
  354  * all following functions private
  355  */
  356 void
  357 pf_syncookie_rotate(void *arg)
  358 {
  359         CURVNET_SET((struct vnet *)arg);
  360 
  361         /* do we want to disable syncookies? */
  362         if (V_pf_status.syncookies_active &&
  363             ((V_pf_status.syncookies_mode == PF_SYNCOOKIES_ADAPTIVE &&
  364             (atomic_load_32(&V_pf_status.states_halfopen) +
  365             atomic_load_64(&V_pf_status.syncookies_inflight[0]) +
  366             atomic_load_64(&V_pf_status.syncookies_inflight[1])) <
  367             V_pf_syncookie_status.lowat) ||
  368             V_pf_status.syncookies_mode == PF_SYNCOOKIES_NEVER)
  369                         ) {
  370                 V_pf_status.syncookies_active = false;
  371                 DPFPRINTF(PF_DEBUG_MISC, ("syncookies disabled\n"));
  372         }
  373 
  374         /* nothing in flight any more? delete keys and return */
  375         if (!V_pf_status.syncookies_active &&
  376             atomic_load_64(&V_pf_status.syncookies_inflight[0]) == 0 &&
  377             atomic_load_64(&V_pf_status.syncookies_inflight[1]) == 0) {
  378                 memset(V_pf_syncookie_status.key[0], 0,
  379                     PF_SYNCOOKIE_SECRET_SIZE);
  380                 memset(V_pf_syncookie_status.key[1], 0,
  381                     PF_SYNCOOKIE_SECRET_SIZE);
  382                 CURVNET_RESTORE();
  383                 return;
  384         }
  385 
  386         PF_RULES_WLOCK();
  387         /* new key, including timeout */
  388         pf_syncookie_newkey();
  389         PF_RULES_WUNLOCK();
  390 
  391         CURVNET_RESTORE();
  392 }
  393 
  394 void
  395 pf_syncookie_newkey(void)
  396 {
  397         PF_RULES_WASSERT();
  398 
  399         MPASS(V_pf_syncookie_status.oddeven < 2);
  400         V_pf_syncookie_status.oddeven = (V_pf_syncookie_status.oddeven + 1) & 0x1;
  401         atomic_store_64(&V_pf_status.syncookies_inflight[V_pf_syncookie_status.oddeven], 0);
  402         arc4random_buf(V_pf_syncookie_status.key[V_pf_syncookie_status.oddeven],
  403             PF_SYNCOOKIE_SECRET_SIZE);
  404         callout_reset(&V_pf_syncookie_status.keytimeout,
  405             PF_SYNCOOKIE_SECRET_LIFETIME * hz, pf_syncookie_rotate, curvnet);
  406 }
  407 
  408 /*
  409  * Distribution and probability of certain MSS values.  Those in between are
  410  * rounded down to the next lower one.
  411  * [An Analysis of TCP Maximum Segment Sizes, S. Alcock and R. Nelson, 2011]
  412  *   .2%  .3%   5%    7%    7%    20%   15%   45%
  413  */
  414 static int pf_syncookie_msstab[] =
  415     { 216, 536, 1200, 1360, 1400, 1440, 1452, 1460 };
  416 
  417 /*
  418  * Distribution and probability of certain WSCALE values.
  419  * The absence of the WSCALE option is encoded with index zero.
  420  * [WSCALE values histograms, Allman, 2012]
  421  *                                  X 10 10 35  5  6 14 10%   by host
  422  *                                  X 11  4  5  5 18 49  3%   by connections
  423  */
  424 static int pf_syncookie_wstab[] = { 0, 0, 1, 2, 4, 6, 7, 8 };
  425 
  426 uint32_t
  427 pf_syncookie_mac(struct pf_pdesc *pd, union pf_syncookie cookie, uint32_t seq)
  428 {
  429         SIPHASH_CTX     ctx;
  430         uint32_t        siphash[2];
  431 
  432         PF_RULES_RASSERT();
  433         MPASS(pd->proto == IPPROTO_TCP);
  434 
  435         SipHash24_Init(&ctx);
  436         SipHash_SetKey(&ctx, V_pf_syncookie_status.key[cookie.flags.oddeven]);
  437 
  438         switch (pd->af) {
  439         case AF_INET:
  440                 SipHash_Update(&ctx, pd->src, sizeof(pd->src->v4));
  441                 SipHash_Update(&ctx, pd->dst, sizeof(pd->dst->v4));
  442                 break;
  443         case AF_INET6:
  444                 SipHash_Update(&ctx, pd->src, sizeof(pd->src->v6));
  445                 SipHash_Update(&ctx, pd->dst, sizeof(pd->dst->v6));
  446                 break;
  447         default:
  448                 panic("unknown address family");
  449         }
  450 
  451         SipHash_Update(&ctx, pd->sport, sizeof(*pd->sport));
  452         SipHash_Update(&ctx, pd->dport, sizeof(*pd->dport));
  453         SipHash_Update(&ctx, &seq, sizeof(seq));
  454         SipHash_Update(&ctx, &cookie, sizeof(cookie));
  455         SipHash_Final((uint8_t *)&siphash, &ctx);
  456 
  457         return (siphash[0] ^ siphash[1]);
  458 }
  459 
  460 uint32_t
  461 pf_syncookie_generate(struct mbuf *m, int off, struct pf_pdesc *pd,
  462     uint16_t mss)
  463 {
  464         uint8_t                  i, wscale;
  465         uint32_t                 iss, hash;
  466         union pf_syncookie       cookie;
  467 
  468         PF_RULES_RASSERT();
  469 
  470         cookie.cookie = 0;
  471 
  472         /* map MSS */
  473         for (i = nitems(pf_syncookie_msstab) - 1;
  474             pf_syncookie_msstab[i] > mss && i > 0; i--)
  475                 /* nada */;
  476         cookie.flags.mss_idx = i;
  477 
  478         /* map WSCALE */
  479         wscale = pf_get_wscale(m, off, pd->hdr.tcp.th_off, pd->af);
  480         for (i = nitems(pf_syncookie_wstab) - 1;
  481             pf_syncookie_wstab[i] > wscale && i > 0; i--)
  482                 /* nada */;
  483         cookie.flags.wscale_idx = i;
  484         cookie.flags.sack_ok = 0;       /* XXX */
  485 
  486         cookie.flags.oddeven = V_pf_syncookie_status.oddeven;
  487         hash = pf_syncookie_mac(pd, cookie, ntohl(pd->hdr.tcp.th_seq));
  488 
  489         /*
  490          * Put the flags into the hash and XOR them to get better ISS number
  491          * variance.  This doesn't enhance the cryptographic strength and is
  492          * done to prevent the 8 cookie bits from showing up directly on the
  493          * wire.
  494          */
  495         iss = hash & ~0xff;
  496         iss |= cookie.cookie ^ (hash >> 24);
  497 
  498         return (iss);
  499 }
  500 
  501 struct mbuf *
  502 pf_syncookie_recreate_syn(uint8_t ttl, int off, struct pf_pdesc *pd)
  503 {
  504         uint8_t                  wscale;
  505         uint16_t                 mss;
  506         uint32_t                 ack, seq;
  507         union pf_syncookie       cookie;
  508 
  509         seq = ntohl(pd->hdr.tcp.th_seq) - 1;
  510         ack = ntohl(pd->hdr.tcp.th_ack) - 1;
  511         cookie.cookie = (ack & 0xff) ^ (ack >> 24);
  512 
  513         if (cookie.flags.mss_idx >= nitems(pf_syncookie_msstab) ||
  514             cookie.flags.wscale_idx >= nitems(pf_syncookie_wstab))
  515                 return (NULL);
  516 
  517         mss = pf_syncookie_msstab[cookie.flags.mss_idx];
  518         wscale = pf_syncookie_wstab[cookie.flags.wscale_idx];
  519 
  520         return (pf_build_tcp(NULL, pd->af, pd->src, pd->dst, *pd->sport,
  521             *pd->dport, seq, 0, TH_SYN, wscale, mss, ttl, 0,
  522             PF_TAG_SYNCOOKIE_RECREATED));
  523 }

Cache object: c2aaced17e25bee22d7128b6d3ee9f07


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