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/netiso/clnp_options.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: clnp_options.c,v 1.18 2007/03/04 06:03:31 christos Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)clnp_options.c      8.1 (Berkeley) 6/10/93
   32  */
   33 
   34 /***********************************************************
   35                 Copyright IBM Corporation 1987
   36 
   37                       All Rights Reserved
   38 
   39 Permission to use, copy, modify, and distribute this software and its
   40 documentation for any purpose and without fee is hereby granted,
   41 provided that the above copyright notice appear in all copies and that
   42 both that copyright notice and this permission notice appear in
   43 supporting documentation, and that the name of IBM not be
   44 used in advertising or publicity pertaining to distribution of the
   45 software without specific, written prior permission.
   46 
   47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   53 SOFTWARE.
   54 
   55 ******************************************************************/
   56 
   57 /*
   58  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __KERNEL_RCSID(0, "$NetBSD: clnp_options.c,v 1.18 2007/03/04 06:03:31 christos Exp $");
   63 
   64 #include "opt_iso.h"
   65 #ifdef ISO
   66 
   67 #include <sys/param.h>
   68 #include <sys/mbuf.h>
   69 #include <sys/domain.h>
   70 #include <sys/protosw.h>
   71 #include <sys/socket.h>
   72 #include <sys/socketvar.h>
   73 #include <sys/errno.h>
   74 #include <sys/systm.h>
   75 
   76 #include <net/if.h>
   77 #include <net/route.h>
   78 
   79 #include <netiso/iso.h>
   80 #include <netiso/clnp.h>
   81 #include <netiso/clnp_stat.h>
   82 #include <netiso/argo_debug.h>
   83 
   84 /*
   85  * FUNCTION:            clnp_update_srcrt
   86  *
   87  * PURPOSE:             Process src rt option accompanying a clnp datagram.
   88  *                      - bump src route ptr if src routing and
   89  *                      we appear current in src route list.
   90  *
   91  * RETURNS:             none
   92  *
   93  * SIDE EFFECTS:
   94  *
   95  * NOTES:               If source routing has been terminated, do nothing.
   96  */
   97 void
   98 clnp_update_srcrt(
   99         struct mbuf *options,           /* ptr to options mbuf */
  100         struct clnp_optidx *oidx)       /* ptr to option index */
  101 {
  102         u_char          len;    /* length of current address */
  103         struct iso_addr isoa;   /* copy current address into here */
  104 
  105         if (CLNPSRCRT_TERM(oidx, options)) {
  106 #ifdef ARGO_DEBUG
  107                 if (argo_debug[D_OPTIONS]) {
  108                         printf("clnp_update_srcrt: src rt terminated\n");
  109                 }
  110 #endif
  111                 return;
  112         }
  113         len = CLNPSRCRT_CLEN(oidx, options);
  114         memcpy(&isoa, CLNPSRCRT_CADDR(oidx, options), len);
  115         isoa.isoa_len = len;
  116 
  117 #ifdef ARGO_DEBUG
  118         if (argo_debug[D_OPTIONS]) {
  119                 printf("clnp_update_srcrt: current src rt: %s\n",
  120                     clnp_iso_addrp(&isoa));
  121         }
  122 #endif
  123 
  124         if (clnp_ours(&isoa)) {
  125 #ifdef ARGO_DEBUG
  126                 if (argo_debug[D_OPTIONS]) {
  127                         printf("clnp_update_srcrt: updating src rt\n");
  128                 }
  129 #endif
  130 
  131                 /* update pointer to next src route */
  132                 len++;          /* count length byte too! */
  133                 CLNPSRCRT_OFF(oidx, options) += len;
  134         }
  135 }
  136 
  137 /*
  138  * FUNCTION:            clnp_dooptions
  139  *
  140  * PURPOSE:             Process options accompanying a clnp datagram.
  141  *                      Processing includes
  142  *                      - log our address if recording route
  143  *
  144  * RETURNS:                     none
  145  *
  146  * SIDE EFFECTS:
  147  *
  148  * NOTES:
  149  */
  150 void
  151 clnp_dooptions(
  152     struct mbuf *options,               /* ptr to options mbuf */
  153     struct clnp_optidx *oidx,           /* ptr to option index */
  154     struct ifnet *ifp,          /* ptr to interface pkt is leaving on */
  155     struct iso_addr *isoa)              /* ptr to our address for this ifp */
  156 {
  157         /*
  158          *      If record route is specified, move all
  159          *      existing records over, and insert the address of
  160          *      interface passed
  161          */
  162         if (oidx->cni_recrtp) {
  163                 char           *opt;    /* ptr to beginning of recrt option */
  164                 u_char          off;    /* offset from opt of first free byte */
  165                 char           *rec_start;      /* beginning of new rt
  166                                                  * recorded */
  167 
  168                 opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp);
  169                 off = *(opt + 1);
  170                 rec_start = opt + off - 1;
  171 
  172 #ifdef ARGO_DEBUG
  173                 if (argo_debug[D_OPTIONS]) {
  174                         printf("clnp_dooptions: record route: option %p for %d bytes\n",
  175                             opt, oidx->cni_recrt_len);
  176                         printf("\tfree slot offset x%x\n", off);
  177                         printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa));
  178                         printf("clnp_dooptions: option dump:\n");
  179                         dump_buf(opt, oidx->cni_recrt_len);
  180                 }
  181 #endif
  182 
  183                 /* proceed only if recording has not been terminated */
  184                 if (off != 0xff) {
  185                         int             new_addrlen = isoa->isoa_len + 1;
  186                         /*
  187                          * if there is insufficient room to store the next
  188                          * address, then terminate recording. Plus 1 on
  189                          * isoa_len is for the length byte itself
  190                          */
  191                         if (oidx->cni_recrt_len - (off - 1) < new_addrlen) {
  192                                 *(opt + 1) = 0xff;      /* terminate recording */
  193                         } else {
  194 #ifdef ARGO_DEBUG
  195                                 if (argo_debug[D_OPTIONS]) {
  196                                         printf("clnp_dooptions: new addr at %p for %d\n",
  197                                                rec_start, new_addrlen);
  198                                 }
  199 #endif
  200 
  201                                 bcopy((void *) isoa, rec_start, new_addrlen);
  202 
  203                                 /* update offset field */
  204                                 *(opt + 1) += new_addrlen;
  205 
  206 #ifdef ARGO_DEBUG
  207                                 if (argo_debug[D_OPTIONS]) {
  208                                         printf("clnp_dooptions: new option dump:\n");
  209                                         dump_buf(opt, oidx->cni_recrt_len);
  210                                 }
  211 #endif
  212                         }
  213                 }
  214         }
  215 }
  216 
  217 /*
  218  * FUNCTION:            clnp_set_opts
  219  *
  220  * PURPOSE:             Check the data mbuf passed for option sanity. If it is
  221  *                      ok, then set the options ptr to address the data mbuf.
  222  *                      If an options mbuf exists, free it. This implies that
  223  *                      any old options will be lost. If data is NULL, simply
  224  *                      free any old options.
  225  *
  226  * RETURNS:             unix error code
  227  *
  228  * SIDE EFFECTS:
  229  *
  230  * NOTES:
  231  */
  232 int
  233 clnp_set_opts(
  234         struct mbuf **options,  /* target for option information */
  235         struct mbuf **data)     /* source of option information */
  236 {
  237         int             error = 0;      /* error return value */
  238         struct clnp_optidx dummy;       /* dummy index - not used */
  239 
  240         /*
  241          *      remove any existing options
  242          */
  243         if (*options != NULL) {
  244                 m_freem(*options);
  245                 *options = NULL;
  246         }
  247         if (*data != NULL) {
  248                 /*
  249                  *      Insure that the options are reasonable.
  250                  *
  251                  *      Also, we do not support security, priority,
  252                  *      nor do we allow one to send an ER option
  253                  *
  254                  *      The QOS parameter is checked for the DECBIT.
  255                  */
  256                 if ((clnp_opt_sanity(*data, mtod(*data, void *), (*data)->m_len,
  257                                      &dummy) != 0) ||
  258                     (dummy.cni_securep) ||
  259                     (dummy.cni_priorp) ||
  260                     (dummy.cni_er_reason != ER_INVALREAS)) {
  261                         error = EINVAL;
  262                 } else {
  263                         *options = *data;
  264                         *data = NULL;   /* so caller won't free mbuf @ *data */
  265                 }
  266         }
  267         return error;
  268 }
  269 
  270 /*
  271  * FUNCTION:            clnp_opt_sanity
  272  *
  273  * PURPOSE:             Check the options (beginning at opts for len bytes) for
  274  *                      sanity. In addition, fill in the option index structure
  275  *                      in with information about each option discovered.
  276  *
  277  * RETURNS:             success (options check out) - 0
  278  *                      failure - an ER pdu error code describing failure
  279  *
  280  * SIDE EFFECTS:
  281  *
  282  * NOTES:               Each pointer field of the option index is filled in with
  283  *                      the offset from the beginning of the mbuf data, not the
  284  *                      actual address.
  285  */
  286 int
  287 clnp_opt_sanity(
  288         struct mbuf    *m,      /* mbuf options reside in */
  289         void *        optsv,    /* ptr to buffer containing options */
  290         int             len,    /* length of buffer */
  291         struct clnp_optidx *oidx)       /* RETURN: filled in with option idx
  292                                          * info */
  293 {
  294         char *opts = optsv;
  295         u_char          opcode = 0;     /* code of particular option */
  296         u_char          oplen;  /* length of a particular option */
  297         char *opts_end; /* ptr to end of options */
  298         u_char          pad = 0, secure = 0, srcrt = 0, recrt = 0,
  299                         qos = 0, prior = 0;
  300         /* flags for catching duplicate options */
  301 
  302 #ifdef ARGO_DEBUG
  303         if (argo_debug[D_OPTIONS]) {
  304                 printf("clnp_opt_sanity: checking %d bytes of data:\n", len);
  305                 dump_buf(opts, len);
  306         }
  307 #endif
  308 
  309         /* clear option index field if passed */
  310         memset(oidx, 0, sizeof(struct clnp_optidx));
  311 
  312         /*
  313          *      We need to indicate whether the ER option is present. This is done
  314          *      by overloading the er_reason field to also indicate presence of
  315          *      the option along with the option value. I would like ER_INVALREAS
  316          *      to have value 0, but alas, 0 is a valid er reason...
  317          */
  318         oidx->cni_er_reason = ER_INVALREAS;
  319 
  320         opts_end = opts + len;
  321         while (opts < opts_end) {
  322                 /* must have at least 2 bytes per option (opcode and len) */
  323                 if (opts + 2 > opts_end)
  324                         return (GEN_INCOMPLETE);
  325 
  326                 opcode = *opts++;
  327                 oplen = *opts++;
  328 #ifdef ARGO_DEBUG
  329                 if (argo_debug[D_OPTIONS]) {
  330                         printf("clnp_opt_sanity: opcode is %x and oplen %d\n",
  331                             opcode, oplen);
  332                         printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT);
  333 
  334                         switch (opcode) {
  335                         case CLNPOVAL_PAD:
  336                                 printf("CLNPOVAL_PAD\n");
  337                                 break;
  338                         case CLNPOVAL_SECURE:
  339                                 printf("CLNPOVAL_SECURE\n");
  340                                 break;
  341                         case CLNPOVAL_SRCRT:
  342                                 printf("CLNPOVAL_SRCRT\n");
  343                                 break;
  344                         case CLNPOVAL_RECRT:
  345                                 printf("CLNPOVAL_RECRT\n");
  346                                 break;
  347                         case CLNPOVAL_QOS:
  348                                 printf("CLNPOVAL_QOS\n");
  349                                 break;
  350                         case CLNPOVAL_PRIOR:
  351                                 printf("CLNPOVAL_PRIOR\n");
  352                                 break;
  353                         case CLNPOVAL_ERREAS:
  354                                 printf("CLNPOVAL_ERREAS\n");
  355                                 break;
  356                         default:
  357                                 printf("UNKNOWN option %x\n", opcode);
  358                                 break;
  359                         }
  360                 }
  361 #endif
  362 
  363                 /* don't allow crazy length values */
  364                 if (opts + oplen > opts_end)
  365                         return (GEN_INCOMPLETE);
  366 
  367                 switch (opcode) {
  368                 case CLNPOVAL_PAD:
  369                         /*
  370                          *      Padding: increment pointer by length of padding
  371                          */
  372                         if (pad++)      /* duplicate ? */
  373                                 return (GEN_DUPOPT);
  374                         opts += oplen;
  375                         break;
  376 
  377                 case CLNPOVAL_SECURE:{
  378                                 u_char          format = *opts;
  379 
  380                                 if (secure++)   /* duplicate ? */
  381                                         return (GEN_DUPOPT);
  382                                 /*
  383                                  *      Security: high 2 bits of first octet indicate format
  384                                  *      (00 in high bits is reserved).
  385                                  *      Remaining bits must be 0. Remaining octets indicate
  386                                  *      actual security
  387                                  */
  388                                 if (((format & 0x3f) > 0) ||    /* low 6 bits set ? */
  389                                     ((format & 0xc0) == 0))     /* high 2 bits zero ? */
  390                                         return (GEN_HDRSYNTAX);
  391 
  392                                 oidx->cni_securep = CLNP_OPTTOOFF(m, opts);
  393                                 oidx->cni_secure_len = oplen;
  394                                 opts += oplen;
  395                         } break;
  396 
  397                 case CLNPOVAL_SRCRT:{
  398                                 u_char          type, offset;   /* type of rt, offset of
  399                                                                  * start */
  400                                 char *         route_end;       /* address of end of
  401                                                                  * route option */
  402 
  403 #ifdef ARGO_DEBUG
  404                                 if (argo_debug[D_OPTIONS]) {
  405                                         printf("clnp_opt_sanity: SRC RT\n");
  406                                 }
  407 #endif
  408 
  409                                 if (srcrt++)    /* duplicate ? */
  410                                         return (GEN_DUPOPT);
  411                                 /*
  412                                  * source route: There must be 2 bytes
  413                                  * following the length field: type and
  414                                  * offset. The type must be either partial
  415                                  * route or complete route. The offset field
  416                                  * must be within the option. A single
  417                                  * exception is made, however. The offset may
  418                                  * be 1 greater than the length. This case
  419                                  * occurs when the last source route record
  420                                  * is consumed. In this case, we ignore the
  421                                  * source route option. RAH? You should be
  422                                  * able to set offset to 'ff' like in record
  423                                  * route! Following this is a series of
  424                                  * address fields. Each address field is
  425                                  * composed of a (length, address) pair.
  426                                  * Insure that the offset and each address
  427                                  * length is reasonable
  428                                  */
  429                                 route_end = opts + oplen;
  430 
  431                                 if (opts + 2 > route_end)
  432                                         return (SRCRT_SYNTAX);
  433 
  434                                 type = *opts;
  435                                 offset = *(opts + 1);
  436 
  437 
  438                                 /* type must be partial or complete */
  439                                 if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
  440                                         return (SRCRT_SYNTAX);
  441 
  442                                 oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts);
  443                                 oidx->cni_srcrt_len = oplen;
  444 
  445                                 opts += offset - 1;     /* set opts to first
  446                                                          * addr in rt */
  447 
  448                                 /*
  449                                  * Offset must be reasonable: less than end
  450                                  * of options, or equal to end of options
  451                                  */
  452                                 if (opts >= route_end) {
  453                                         if (opts == route_end) {
  454 #ifdef ARGO_DEBUG
  455                                                 if (argo_debug[D_OPTIONS]) {
  456                                                         printf("clnp_opt_sanity: end of src route info\n");
  457                                                 }
  458 #endif
  459                                                 break;
  460                                         } else
  461                                                 return (SRCRT_SYNTAX);
  462                                 }
  463                                 while (opts < route_end) {
  464                                         u_char          addrlen = *opts++;
  465                                         if (opts + addrlen > route_end)
  466                                                 return (SRCRT_SYNTAX);
  467                                         opts += addrlen;
  468                                 }
  469                         } break;
  470                 case CLNPOVAL_RECRT:{
  471                                 u_char          type, offset;   /* type of rt, offset of
  472                                                                  * start */
  473                                 char *         record_end;      /* address of end of
  474                                                                  * record option */
  475 
  476                                 if (recrt++)    /* duplicate ? */
  477                                         return (GEN_DUPOPT);
  478                                 /*
  479                                  *      record route: after the length field, expect a
  480                                  *      type and offset. Type must be partial or complete.
  481                                  *      Offset indicates where to start recording. Insure it
  482                                  *      is within the option. All ones for offset means
  483                                  *      recording is terminated.
  484                                  */
  485                                 record_end = opts + oplen;
  486 
  487                                 oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts);
  488                                 oidx->cni_recrt_len = oplen;
  489 
  490                                 if (opts + 2 > record_end)
  491                                         return (GEN_INCOMPLETE);
  492 
  493                                 type = *opts;
  494                                 offset = *(opts + 1);
  495 
  496                                 /* type must be partial or complete */
  497                                 if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
  498                                         return (GEN_HDRSYNTAX);
  499 
  500                                 /* offset must be reasonable */
  501                                 if ((offset < 0xff) && (opts + offset > record_end))
  502                                         return (GEN_HDRSYNTAX);
  503                                 opts += oplen;
  504                         } break;
  505                 case CLNPOVAL_QOS:{
  506                                 u_char          format = *opts;
  507 
  508                                 if (qos++)      /* duplicate ? */
  509                                         return (GEN_DUPOPT);
  510                                 /*
  511                                  *      qos: high 2 bits of first octet indicate format
  512                                  *      (00 in high bits is reserved).
  513                                  *      Remaining bits must be 0 (unless format indicates
  514                                  *      globally unique qos, in which case remaining bits indicate
  515                                  *      qos (except bit 6 which is reserved)).  Otherwise,
  516                                  *      remaining octets indicate actual qos.
  517                                  */
  518                                 if (((format & 0xc0) == 0) ||   /* high 2 bits zero ? */
  519                                     (((format & 0xc0) != CLNPOVAL_GLOBAL) &&
  520                                      ((format & 0x3f) > 0)))    /* not global,low bits
  521                                                                  * used ? */
  522                                         return (GEN_HDRSYNTAX);
  523 
  524                                 oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts);
  525                                 oidx->cni_qos_len = oplen;
  526 
  527                                 opts += oplen;
  528                         } break;
  529 
  530                 case CLNPOVAL_PRIOR:{
  531                                 if (prior++)    /* duplicate ? */
  532                                         return (GEN_DUPOPT);
  533                                 /*
  534                                  *      priority: value must be one byte long
  535                                  */
  536                                 if (oplen != 1)
  537                                         return (GEN_HDRSYNTAX);
  538 
  539                                 oidx->cni_priorp = CLNP_OPTTOOFF(m, opts);
  540 
  541                                 opts += oplen;
  542                         } break;
  543 
  544                 case CLNPOVAL_ERREAS:{
  545                                 /*
  546                                  *      er reason: value must be two bytes long
  547                                  */
  548                                 if (oplen != 2)
  549                                         return (GEN_HDRSYNTAX);
  550 
  551                                 oidx->cni_er_reason = *opts;
  552 
  553                                 opts += oplen;
  554                         } break;
  555 
  556                 default:{
  557 #ifdef ARGO_DEBUG
  558                                 if (argo_debug[D_OPTIONS]) {
  559                                         printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode);
  560                                 }
  561 #endif
  562                                 return (DISC_UNSUPPOPT);
  563                         }
  564                 }
  565         }
  566 #ifdef ARGO_DEBUG
  567         if (argo_debug[D_OPTIONS]) {
  568                 printf("clnp_opt_sanity: return(0)\n");
  569         }
  570 #endif
  571         return (0);
  572 }
  573 #endif /* ISO */

Cache object: b1ff4205818907eb8a6e62657b2d097c


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