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/netncp/ncp_mod.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 /*
    2  * Copyright (c) 1999, 2000, 2001 Boris Popov
    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. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *    This product includes software developed by Boris Popov.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  * $FreeBSD: releng/5.0/sys/netncp/ncp_mod.c 74647 2001-03-22 10:38:16Z bp $
   33  */
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/sysproto.h>
   37 #include <sys/sysent.h>
   38 #include <sys/proc.h>
   39 #include <sys/kernel.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/malloc.h>
   42 #include <sys/uio.h>
   43 
   44 #include <netncp/ncp.h>
   45 #include <netncp/ncp_conn.h>
   46 #include <netncp/ncp_subr.h>
   47 #include <netncp/ncp_ncp.h>
   48 #include <netncp/ncp_user.h>
   49 #include <netncp/ncp_rq.h>
   50 #include <netncp/ncp_nls.h>
   51 
   52 int ncp_version = NCP_VERSION;
   53 
   54 static int ncp_sysent;
   55 
   56 SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
   57 SYSCTL_INT(_net_ncp, OID_AUTO, sysent, CTLFLAG_RD, &ncp_sysent, 0, "");
   58 SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
   59 
   60 MODULE_VERSION(ncp, 1);
   61 MODULE_DEPEND(ncp, libmchain, 1, 1, 1);
   62 
   63 static int
   64 ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp);
   65 
   66 /*
   67  * Attach to NCP server
   68  */
   69 struct sncp_connect_args {
   70         struct ncp_conn_args *li;
   71         int *connHandle;
   72 };
   73 
   74 static int 
   75 sncp_connect(struct proc *p, struct sncp_connect_args *uap)
   76 {
   77         int connHandle = 0, error;
   78         struct ncp_conn *conn;
   79         struct ncp_handle *handle;
   80         struct ncp_conn_args li;
   81 
   82         checkbad(copyin(uap->li,&li,sizeof(li)));
   83         checkbad(copyout(&connHandle,uap->connHandle,sizeof(connHandle))); /* check before */
   84         li.password = li.user = NULL;
   85         error = ncp_conn_getattached(&li, p, p->p_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
   86         if (error) {
   87                 error = ncp_conn_alloc(&li, p, p->p_ucred, &conn);
   88                 if (error)
   89                         goto bad;
   90                 error = ncp_conn_reconnect(conn);
   91                 if (error)
   92                         ncp_conn_free(conn);
   93         }
   94         if (!error) {
   95                 error = ncp_conn_gethandle(conn, p, &handle);
   96                 copyout(&handle->nh_id, uap->connHandle, sizeof(uap->connHandle));
   97                 ncp_conn_unlock(conn,p);
   98         }
   99 bad:
  100         p->p_retval[0]=error;
  101         return error;
  102 }
  103 
  104 struct sncp_request_args {
  105         int connHandle;
  106         int fn;
  107         struct ncp_buf *ncpbuf;
  108 };
  109 
  110 static int ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
  111         struct ncp_conn *conn, struct ncp_handle *handle);
  112 
  113 static int
  114 sncp_request(struct proc *p, struct sncp_request_args *uap)
  115 {
  116         struct ncp_rq *rqp;
  117         struct ncp_conn *conn;
  118         struct ncp_handle *handle;
  119         int error = 0, rqsize;
  120 
  121         error = ncp_conn_findhandle(uap->connHandle,p,&handle);
  122         if (error)
  123                 return error;
  124         conn = handle->nh_conn;
  125         if (uap->fn == NCP_CONN)
  126                 return ncp_conn_handler(p, uap, conn, handle);
  127         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
  128         if (error)
  129                 return(error);
  130         error = ncp_rq_alloc(uap->fn, conn, p, p->p_ucred, &rqp);
  131         if (error)
  132                 return error;
  133         if (rqsize) {
  134                 error = mb_put_mem(&rqp->rq, (caddr_t)uap->ncpbuf->packet,
  135                     rqsize, MB_MUSER);
  136                 if (error)
  137                         goto bad;
  138         }
  139         rqp->nr_flags |= NCPR_DONTFREEONERR;
  140         error = ncp_request(rqp);
  141         if (error == 0 && rqp->nr_rpsize)
  142                 error = md_get_mem(&rqp->rp, (caddr_t)uap->ncpbuf->packet, 
  143                                 rqp->nr_rpsize, MB_MUSER);
  144         copyout(&rqp->nr_cs, &uap->ncpbuf->cs, sizeof(rqp->nr_cs));
  145         copyout(&rqp->nr_cc, &uap->ncpbuf->cc, sizeof(rqp->nr_cc));
  146         copyout(&rqp->nr_rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->nr_rpsize));
  147 bad:
  148         ncp_rq_done(rqp);
  149         return error;
  150 }
  151 
  152 static int
  153 ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password,
  154         struct proc *p, struct ucred *cred)
  155 {
  156         int error;
  157 
  158         if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid)
  159                 return EACCES;
  160         conn->li.user = ncp_str_dup(user);
  161         if (conn->li.user == NULL)
  162                 return ENOMEM;
  163         conn->li.password = ncp_str_dup(password);
  164         if (conn->li.password == NULL) {
  165                 error = ENOMEM;
  166                 goto bad;
  167         }
  168         ncp_str_upper(conn->li.user);
  169         if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0)
  170                 ncp_str_upper(conn->li.password);
  171         conn->li.objtype = objtype;
  172         error = ncp_conn_login(conn, p, cred);
  173         return error;
  174 bad:
  175         if (conn->li.user) {
  176                 free(conn->li.user, M_NCPDATA);
  177                 conn->li.user = NULL;
  178         }
  179         if (conn->li.password) {
  180                 free(conn->li.password, M_NCPDATA);
  181                 conn->li.password = NULL;
  182         }
  183         return error;
  184 }
  185 
  186 static int
  187 ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
  188         struct ncp_conn *conn, struct ncp_handle *hp)
  189 {
  190         int error=0, rqsize, subfn;
  191         struct ucred *cred;
  192         
  193         char *pdata;
  194 
  195         cred = p->p_ucred;
  196         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
  197         if (error) return(error);
  198         error = 0;
  199         pdata = uap->ncpbuf->packet;
  200         subfn = *(pdata++) & 0xff;
  201         rqsize--;
  202         switch (subfn) {
  203             case NCP_CONN_READ: case NCP_CONN_WRITE: {
  204                 struct ncp_rw rwrq;
  205                 struct uio auio;
  206                 struct iovec iov;
  207         
  208                 if (rqsize != sizeof(rwrq)) return (EBADRPC);   
  209                 error = copyin(pdata,&rwrq,rqsize);
  210                 if (error) return (error);
  211                 iov.iov_base = rwrq.nrw_base;
  212                 iov.iov_len = rwrq.nrw_cnt;
  213                 auio.uio_iov = &iov;
  214                 auio.uio_iovcnt = 1;
  215                 auio.uio_offset = rwrq.nrw_offset;
  216                 auio.uio_resid = rwrq.nrw_cnt;
  217                 auio.uio_segflg = UIO_USERSPACE;
  218                 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
  219                 auio.uio_procp = p;
  220                 if (subfn == NCP_CONN_READ)
  221                         error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
  222                 else
  223                         error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
  224                 rwrq.nrw_cnt -= auio.uio_resid;
  225                 p->p_retval[0] = rwrq.nrw_cnt;
  226                 break;
  227             } /* case int_read/write */
  228             case NCP_CONN_SETFLAGS: {
  229                 u_int16_t mask, flags;
  230 
  231                 error = copyin(pdata,&mask, sizeof(mask));
  232                 if (error) return error;
  233                 pdata += sizeof(mask);
  234                 error = copyin(pdata,&flags,sizeof(flags));
  235                 if (error) return error;
  236                 error = ncp_conn_lock(conn,p,cred,NCPM_WRITE);
  237                 if (error) return error;
  238                 if (mask & NCPFL_PERMANENT) {
  239                         conn->flags &= ~NCPFL_PERMANENT;
  240                         conn->flags |= (flags & NCPFL_PERMANENT);
  241                 }
  242                 if (mask & NCPFL_PRIMARY) {
  243                         error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
  244                         if (error) {
  245                                 ncp_conn_unlock(conn,p);
  246                                 break;
  247                         }
  248                 }
  249                 ncp_conn_unlock(conn,p);
  250                 break;
  251             }
  252             case NCP_CONN_LOGIN: {
  253                 struct ncp_conn_login la;
  254 
  255                 if (rqsize != sizeof(la))
  256                         return EBADRPC;
  257                 if (conn->flags & NCPFL_LOGGED)
  258                         return EALREADY;
  259                 if ((error = copyin(pdata,&la,rqsize)) != 0)
  260                         break;
  261                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE | NCPM_WRITE);
  262                 if (error) return error;
  263                 error = ncp_mod_login(conn, la.username, la.objtype, la.password, p, p->p_ucred);
  264                 ncp_conn_unlock(conn, p);
  265                 p->p_retval[0] = error;
  266                 break;
  267             }
  268             case NCP_CONN_GETINFO: {
  269                 struct ncp_conn_stat ncs;
  270                 int len = sizeof(ncs);
  271 
  272                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
  273                 if (error) return error;
  274                 ncp_conn_getinfo(conn, &ncs);
  275                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
  276                 error = copyout(&ncs, &uap->ncpbuf->packet, len);
  277                 ncp_conn_unlock(conn, p);
  278                 break;
  279             }
  280             case NCP_CONN_GETUSER: {
  281                 int len;
  282 
  283                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
  284                 if (error) return error;
  285                 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
  286                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
  287                 if (len) {
  288                         error = copyout(conn->li.user, &uap->ncpbuf->packet, len);
  289                 }
  290                 ncp_conn_unlock(conn, p);
  291                 break;
  292             }
  293             case NCP_CONN_CONN2REF: {
  294                 int len = sizeof(int);
  295 
  296                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
  297                 if (error) return error;
  298                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
  299                 if (len) {
  300                         error = copyout(&conn->nc_id, &uap->ncpbuf->packet, len);
  301                 }
  302                 ncp_conn_unlock(conn, p);
  303                 break;
  304             }
  305             case NCP_CONN_FRAG: {
  306                 struct ncp_conn_frag nf;
  307 
  308                 if (rqsize != sizeof(nf)) return (EBADRPC);     
  309                 if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
  310                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
  311                 if (error) return error;
  312                 error = ncp_conn_frag_rq(conn, p, &nf);
  313                 ncp_conn_unlock(conn, p);
  314                 copyout(&nf, &pdata, sizeof(nf));
  315                 p->p_retval[0] = error;
  316                 break;
  317             }
  318             case NCP_CONN_DUP: {
  319                 struct ncp_handle *newhp;
  320                 int len = sizeof(NWCONN_HANDLE);
  321 
  322                 error = ncp_conn_lock(conn, p, cred, NCPM_READ);
  323                 if (error) break;
  324                 copyout(&len, &uap->ncpbuf->rpsize, len);
  325                 error = ncp_conn_gethandle(conn, p, &newhp);
  326                 if (!error)
  327                         error = copyout(&newhp->nh_id, uap->ncpbuf->packet, len);
  328                 ncp_conn_unlock(conn,p);
  329                 break;
  330             }
  331             case NCP_CONN_CONNCLOSE: {
  332                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
  333                 if (error) break;
  334                 ncp_conn_puthandle(hp, p, 0);
  335                 error = ncp_conn_free(conn);
  336                 if (error)
  337                         ncp_conn_unlock(conn, p);
  338                 break;
  339             }
  340             default:
  341                     error = EOPNOTSUPP;
  342         }
  343         return error;
  344 }
  345 
  346 struct sncp_conn_scan_args {
  347         struct ncp_conn_args *li;
  348         int *connHandle;
  349 };
  350 
  351 static int 
  352 sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)
  353 {
  354         int connHandle = 0, error;
  355         struct ncp_conn_args li, *lip;
  356         struct ncp_conn *conn;
  357         struct ncp_handle *hp;
  358         char *user = NULL, *password = NULL;
  359 
  360         if (uap->li) {
  361                 if (copyin(uap->li,&li,sizeof(li))) return EFAULT;
  362                 lip = &li;
  363         } else {
  364                 lip = NULL;
  365         }
  366 
  367         if (lip != NULL) {
  368                 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
  369                 ncp_str_upper(lip->server);
  370                 if (lip->user) {
  371                         user = ncp_str_dup(lip->user);
  372                         if (user == NULL) return EINVAL;
  373                         ncp_str_upper(user);
  374                 }
  375                 if (lip->password) {
  376                         password = ncp_str_dup(lip->password);
  377                         if (password == NULL) {
  378                                 if (user)
  379                                         free(user, M_NCPDATA);
  380                                 return EINVAL;
  381                         }
  382                         ncp_str_upper(password);
  383                 }
  384                 lip->user = user;
  385                 lip->password = password;
  386         }
  387         error = ncp_conn_getbyli(lip,p,p->p_ucred,NCPM_EXECUTE,&conn);
  388         if (!error) {           /* already have this login */
  389                 ncp_conn_gethandle(conn, p, &hp);
  390                 connHandle = hp->nh_id;
  391                 ncp_conn_unlock(conn,p);
  392                 copyout(&connHandle,uap->connHandle,sizeof(connHandle));
  393         }
  394         if (user) free(user, M_NCPDATA);
  395         if (password) free(password, M_NCPDATA);
  396         p->p_retval[0] = error;
  397         return error;
  398 
  399 }
  400 
  401 int
  402 ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp)
  403 {
  404         NW_FRAGMENT *fp;
  405         struct ncp_rq *rqp;
  406         u_int32_t fsize;
  407         int error, i, rpsize;
  408 
  409         error = ncp_rq_alloc(nfp->fn, conn, p, p->p_ucred, &rqp);
  410         if (error)
  411                 return error;
  412         for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
  413                 error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER);
  414                 if (error)
  415                         goto bad;
  416         }
  417         rqp->nr_flags |= NCPR_DONTFREEONERR;
  418         error = ncp_request(rqp);
  419         if (error)
  420                 goto bad;
  421         rpsize = rqp->nr_rpsize;
  422         if (rpsize && nfp->rpfcnt) {
  423                 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
  424                         error = copyin(&fp->fragSize, &fsize, sizeof (fsize));
  425                         if (error)
  426                                 break;
  427                         fsize = min(fsize, rpsize);
  428                         error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER);
  429                         if (error)
  430                                 break;
  431                         rpsize -= fsize;
  432                         error = copyout(&fsize, &fp->fragSize, sizeof (fsize));
  433                         if (error)
  434                                 break;
  435                 }
  436         }
  437         nfp->cs = rqp->nr_cs;
  438         nfp->cc = rqp->nr_cc;
  439 bad:
  440         ncp_rq_done(rqp);
  441         return error;
  442 }
  443 
  444 /*
  445  * Internal functions, here should be all calls that do not require connection.
  446  * To simplify possible future movement to cdev, we use IOCTL macros.
  447  * Pretty much of this stolen from ioctl() function.
  448  */
  449 struct sncp_intfn_args {
  450         u_long  com;
  451         caddr_t data;
  452 };
  453 
  454 static int
  455 sncp_intfn(struct proc *p, struct sncp_intfn_args *uap)
  456 {
  457         return ENOSYS;
  458 }
  459 /*
  460  * define our new system calls
  461  */
  462 static struct sysent newent[] = {
  463         {2,     (sy_call_t*)sncp_conn_scan},
  464         {2,     (sy_call_t*)sncp_connect},
  465         {2,     (sy_call_t*)sncp_intfn},
  466         {3,     (sy_call_t*)sncp_request}
  467 };
  468 
  469 #define SC_SIZE sizeof(newent)/sizeof(struct sysent)
  470 /*
  471  * Miscellaneous modules must have their own save areas...
  472  */
  473 static struct sysent    oldent[SC_SIZE];        /* save are for old callslot entry*/
  474 
  475 /*
  476  * Number of syscall entries for a.out executables
  477  */
  478 /*#define nsysent SYS_MAXSYSCALL*/
  479 #define nsysent (aout_sysvec.sv_size)
  480 
  481 
  482 static int
  483 ncp_load(void) {
  484         int i, ff, scnt, err=0;
  485 
  486         while(1) {
  487                 /* Search the table looking for an enough number of slots... */
  488                 for (scnt=0, ff = -1, i = 0; i < nsysent; i++) {
  489                         if (sysent[i].sy_call == (sy_call_t *)lkmnosys) {
  490                                 if (ff == -1) {
  491                                     ff = i;
  492                                     scnt = 1;
  493                                 } else {
  494                                     scnt++;
  495                                     if (scnt == SC_SIZE) break;
  496                                 }
  497                         } else {
  498                                 ff = -1;
  499                         }
  500                 }
  501                 /* out of allocable slots?*/
  502                 if(i == nsysent || ff == -1) {
  503                         err = ENFILE;
  504                         break;
  505                 }
  506                 err = ncp_init();
  507                 if (err) break;
  508                 bcopy(&sysent[ff], &oldent, sizeof(struct sysent)*SC_SIZE);
  509                 bcopy(&newent, &sysent[ff], sizeof(struct sysent)*SC_SIZE);
  510                 ncp_sysent = ff;        /* slot in sysent[]*/
  511                 printf("ncp_load: [%d-%d]\n",ff,i);
  512                 break;
  513         }
  514 
  515         return( err);
  516 }
  517 
  518 static int
  519 ncp_unload(void)
  520 {
  521         int error;
  522 
  523         error = ncp_done();
  524         if (error)
  525                 return error;
  526         bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
  527         printf( "ncp_unload: unloaded\n");
  528         return 0;
  529 }
  530 
  531 static int
  532 ncp_mod_handler(module_t mod, int type, void *data)
  533 {
  534         int error;
  535 
  536         switch (type) {
  537             case MOD_LOAD:
  538                 error = ncp_load();
  539                 break;
  540             case MOD_UNLOAD:
  541                 error = ncp_unload();
  542                 break;
  543             default:
  544                 error = EINVAL;
  545         }
  546         return error;
  547 }
  548                                                                \
  549 static moduledata_t ncp_mod = {
  550         "ncp",
  551         ncp_mod_handler,
  552         NULL
  553 };
  554 DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);

Cache object: 81f5e0cd84ac5afb4b0e10f2de239610


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