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/netgraph/ng_device.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) 2002 Mark Santcroos <marks@ripe.net>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23  *
   24  * Netgraph "device" node
   25  *
   26  * This node presents a /dev/ngd%d device that interfaces to an other 
   27  * netgraph node.
   28  *
   29  * $FreeBSD: releng/5.3/sys/netgraph/ng_device.c 136588 2004-10-16 08:43:07Z cvs2svn $
   30  *
   31  */
   32 
   33 #include <sys/param.h>
   34 #include <sys/conf.h>
   35 #include <sys/ioccom.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/poll.h>
   40 #include <sys/queue.h>
   41 #include <sys/systm.h>
   42 #include <sys/uio.h>
   43 
   44 #include <netgraph/ng_message.h>
   45 #include <netgraph/netgraph.h>
   46 #include <netgraph/ng_device.h>
   47 
   48 /* turn this on for verbose messages */
   49 #define NGD_DEBUG
   50 
   51 #define ERROUT(x) do { error = (x); goto done; } while (0)
   52 
   53 /* Netgraph methods */
   54 static ng_constructor_t ng_device_cons;
   55 static ng_rcvmsg_t      ng_device_rcvmsg;
   56 static ng_newhook_t     ng_device_newhook;
   57 static ng_connect_t     ng_device_connect;
   58 static ng_rcvdata_t     ng_device_rcvdata;
   59 static ng_disconnect_t  ng_device_disconnect;
   60 static int              ng_device_mod_event(module_t mod, int event, void *data);
   61 
   62 static int ng_device_init(void);
   63 static int get_free_unit(void);
   64 
   65 /* Netgraph type */
   66 static struct ng_type typestruct = {
   67         .version =      NG_ABI_VERSION,
   68         .name =         NG_DEVICE_NODE_TYPE,
   69         .mod_event =    ng_device_mod_event,
   70         .constructor =  ng_device_cons,
   71         .rcvmsg =       ng_device_rcvmsg,
   72         .newhook =      ng_device_newhook,
   73         .connect =      ng_device_connect,
   74         .rcvdata =      ng_device_rcvdata,
   75         .disconnect =   ng_device_disconnect,
   76 };
   77 NETGRAPH_INIT(device, &typestruct);
   78 
   79 /* per hook data */
   80 struct ngd_connection {
   81         SLIST_ENTRY(ngd_connection) links;
   82 
   83         struct cdev *ngddev;
   84         struct  ng_hook *active_hook;
   85         char    *readq;
   86         int     loc;
   87         int     unit;
   88 };
   89 
   90 /* global data */
   91 struct ngd_softc {
   92         SLIST_HEAD(, ngd_connection) head;
   93 
   94         node_p node;
   95         char nodename[NG_NODESIZ];
   96 } ngd_softc;
   97 
   98 /* the per connection receiving queue maximum */
   99 #define NGD_QUEUE_SIZE (1024*10)
  100 
  101 /* Maximum number of NGD devices */
  102 #define MAX_NGD 25              /* should be more than enough for now */
  103 
  104 static d_close_t ngdclose;
  105 static d_open_t ngdopen;
  106 static d_read_t ngdread;
  107 static d_write_t ngdwrite;
  108 static d_ioctl_t ngdioctl;
  109 static d_poll_t ngdpoll;
  110 
  111 static struct cdevsw ngd_cdevsw = {
  112         .d_version =    D_VERSION,
  113         .d_flags =      D_NEEDGIANT,
  114         .d_open =       ngdopen,
  115         .d_close =      ngdclose,
  116         .d_read =       ngdread,
  117         .d_write =      ngdwrite,
  118         .d_ioctl =      ngdioctl,
  119         .d_poll =       ngdpoll,
  120         .d_name =       "ngd",
  121 };
  122 
  123 /* 
  124  * this holds all the stuff that should be done at load time 
  125  */
  126 static int
  127 ng_device_mod_event(module_t mod, int event, void *data)
  128 {
  129         int error = 0;
  130 
  131 #ifdef NGD_DEBUG
  132         printf("%s()\n",__func__);
  133 #endif /* NGD_DEBUG */
  134 
  135         switch (event) {
  136                 case MOD_LOAD:
  137 
  138                         ng_device_init();
  139                         break;
  140 
  141                 case MOD_UNLOAD:
  142                         /* XXX do we need to do something specific ? */
  143                         /* ng_device_breakdown */
  144                         break;
  145                 
  146                 default:
  147                         error = EOPNOTSUPP;
  148                         break;
  149         }
  150 
  151         return(error);
  152 }
  153 
  154 
  155 static int
  156 ng_device_init()
  157 {
  158         struct ngd_softc *sc = &ngd_softc;
  159         
  160 #ifdef NGD_DEBUG
  161         printf("%s()\n",__func__);
  162 #endif /* NGD_DEBUG */ 
  163 
  164         SLIST_INIT(&sc->head);
  165 
  166         if (ng_make_node_common(&typestruct, &sc->node) != 0) {
  167                 printf("%s(): ng_make_node_common failed\n",__func__);
  168                 return(ENXIO);
  169         }
  170         sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE);
  171         if (ng_name_node(sc->node, sc->nodename)) {
  172                 NG_NODE_UNREF(sc->node); /* make it go away again */
  173                 printf("%s(): ng_name_node failed\n",__func__);
  174                 return(ENXIO);
  175         }
  176         NG_NODE_SET_PRIVATE(sc->node, sc);
  177 
  178         return(0);
  179 }
  180 
  181 /* 
  182  * don't allow to be created, only the device can do that 
  183  */
  184 static int
  185 ng_device_cons(node_p node)
  186 {
  187 
  188 #ifdef NGD_DEBUG
  189         printf("%s()\n",__func__);
  190 #endif /* NGD_DEBUG */
  191         
  192         return(EINVAL);
  193 }
  194 
  195 /*
  196  * Receive control message. We just bounce it back as a reply.
  197  */
  198 static int
  199 ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
  200 {
  201         struct ngd_softc *sc = &ngd_softc;
  202         struct ng_mesg *msg;
  203         int error = 0;
  204         struct ngd_connection * connection = NULL;
  205         struct ngd_connection *tmp = NULL;
  206 
  207 #ifdef NGD_DEBUG
  208         printf("%s()\n",__func__);
  209 #endif /* NGD_DEBUG */
  210 
  211         NGI_GET_MSG(item, msg); 
  212 
  213         SLIST_FOREACH(tmp,&sc->head,links) {
  214                 if(tmp->active_hook == lasthook) {
  215                         connection = tmp;
  216                 }
  217         }
  218         if(connection == NULL) {
  219                 printf("%s(): connection is still NULL, no hook found\n",__func__);
  220                 return(-1);
  221         }
  222 
  223         return(error);
  224 }
  225 
  226 static int
  227 get_free_unit()
  228 {
  229         struct ngd_connection *tmp = NULL;
  230         struct ngd_softc *sc = &ngd_softc;
  231         int n = 0;
  232         int unit = -1;
  233 
  234 #ifdef NGD_DEBUG
  235         printf("%s()\n",__func__);
  236 #endif /* NGD_DEBUG */
  237 
  238         /* When there is no list yet, the first device unit is always 0. */
  239         if SLIST_EMPTY(&sc->head) {
  240                 unit = 0;
  241                 return(unit);
  242         }
  243 
  244         /* Just do a brute force loop to find the first free unit that is
  245          * smaller than MAX_NGD.
  246          * Set MAX_NGD to a large value, doesn't impact performance.
  247          */
  248         for(n = 0;n<MAX_NGD && unit == -1;n++) {
  249                 SLIST_FOREACH(tmp,&sc->head,links) {
  250 
  251                         if(tmp->unit == n) {
  252                                 unit = -1;
  253                                 break;
  254                         }
  255                         unit = n;
  256                 }
  257         }
  258 
  259         return(unit);
  260 }
  261 
  262 /*
  263  * incoming hook
  264  */
  265 static int
  266 ng_device_newhook(node_p node, hook_p hook, const char *name)
  267 {
  268         struct ngd_softc *sc = &ngd_softc;
  269         struct ngd_connection * new_connection = NULL;
  270 
  271 #ifdef NGD_DEBUG
  272         printf("%s()\n",__func__);
  273 #endif
  274 
  275         new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT);
  276         if(new_connection == NULL) {
  277                 printf("%s(): ERROR: new_connection == NULL\n",__func__);
  278                 return(ENOMEM);
  279         }
  280 
  281         new_connection->unit = get_free_unit();
  282         if(new_connection->unit<0) {
  283                 printf("%s: No free unit found by get_free_unit(), "
  284                                 "increase MAX_NGD\n",__func__);
  285                 free(new_connection, M_DEVBUF);
  286                 return(EINVAL);
  287         }
  288         new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit);
  289         if(new_connection->ngddev == NULL) {
  290                 printf("%s(): make_dev failed\n",__func__);
  291                 free(new_connection, M_DEVBUF);
  292                 return(EINVAL);
  293         }
  294 
  295         new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
  296         if(new_connection->readq == NULL) {
  297                 printf("%s(): readq malloc failed\n",__func__);
  298                 free(new_connection, M_DEVBUF);
  299                 return(ENOMEM);
  300         }
  301 
  302         /* point to begin of buffer */
  303         new_connection->loc = 0;
  304         new_connection->active_hook = hook;
  305 
  306         SLIST_INSERT_HEAD(&sc->head, new_connection, links);
  307 
  308         return(0);
  309 }
  310 
  311 /*
  312  * we gave ok to a new hook
  313  * now connect
  314  */
  315 static int
  316 ng_device_connect(hook_p hook)
  317 {
  318 
  319 #ifdef NGD_DEBUG
  320         printf("%s()\n",__func__);
  321 #endif /* NGD_DEBUG */
  322 
  323         return(0);
  324 }
  325 
  326 
  327 /*
  328  * Receive data from hook
  329  */
  330 static int
  331 ng_device_rcvdata(hook_p hook, item_p item)
  332 {
  333         struct mbuf *m;
  334         struct ngd_softc *sc = &ngd_softc;
  335         struct ngd_connection * connection = NULL;
  336         struct ngd_connection * tmp;
  337         char *buffer;
  338         int error = 0;
  339 
  340 #ifdef NGD_DEBUG
  341         printf("%s()\n",__func__);
  342 #endif
  343 
  344         NGI_GET_M(item, m);
  345         NG_FREE_ITEM(item);
  346 
  347         SLIST_FOREACH(tmp,&sc->head,links)
  348                 if(tmp->active_hook == hook)
  349                         connection = tmp;
  350 
  351         if (connection == NULL) {
  352                 printf("%s(): connection is still NULL, no hook found\n",__func__);
  353                 ERROUT(ENOTCONN);
  354         }
  355 
  356         if ((m = m_pullup(m,m->m_len)) == NULL) {
  357                 printf("%s(): ERROR: m_pullup failed\n",__func__);
  358                 ERROUT(ENOMEM);
  359         }
  360 
  361         buffer = mtod(m,char *);
  362 
  363         if ((connection->loc + m->m_len) < NGD_QUEUE_SIZE) {
  364                 memcpy(connection->readq + connection->loc, buffer, m->m_len);
  365                 connection->loc += m->m_len;
  366         } else {
  367                 printf("%s(): queue full, first read out a bit\n",__func__);
  368                 ERROUT(ENOSPC);
  369         }
  370 
  371 done:
  372         NG_FREE_M(m);
  373         return(error);
  374 }
  375 
  376 /*
  377  * Removal of the last link destroys the node
  378  */
  379 static int
  380 ng_device_disconnect(hook_p hook)
  381 {
  382         struct ngd_softc *sc = &ngd_softc;
  383         struct ngd_connection * connection = NULL;
  384         struct ngd_connection * tmp;
  385 
  386 #ifdef NGD_DEBUG
  387         printf("%s()\n",__func__);
  388 #endif
  389 
  390         SLIST_FOREACH(tmp,&sc->head,links)
  391                 if(tmp->active_hook == hook)
  392                         connection = tmp;
  393 
  394         if(connection == NULL) {
  395                 printf("%s(): connection is still NULL, no hook found\n",__func__);
  396                 return(ENOTCONN);
  397         }
  398 
  399         free(connection->readq, M_DEVBUF);
  400 
  401         destroy_dev(connection->ngddev);
  402 
  403         SLIST_REMOVE(&sc->head,connection,ngd_connection,links);
  404         free(connection, M_DEVBUF);
  405 
  406         return(0);
  407 }
  408 /*
  409  * the device is opened 
  410  */
  411 static int
  412 ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
  413 {
  414 
  415 #ifdef NGD_DEBUG
  416         printf("%s()\n",__func__);
  417 #endif /* NGD_DEBUG */
  418 
  419         return(0);
  420 }
  421 
  422 /*
  423  * the device is closed 
  424  */
  425 static int
  426 ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
  427 {
  428 
  429 #ifdef NGD_DEBUG
  430         printf("%s()\n",__func__);
  431 #endif
  432 
  433         return(0);
  434 }
  435 
  436 
  437 /*
  438  * process ioctl
  439  *
  440  * they are translated into netgraph messages and passed on
  441  * 
  442  */
  443 static int
  444 ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  445 {
  446         struct ngd_softc *sc = &ngd_softc;
  447         struct ngd_connection * connection = NULL;
  448         struct ngd_connection * tmp;
  449         int error = 0;
  450         struct ng_mesg *msg;
  451         struct ngd_param_s * datap;
  452 
  453 #ifdef NGD_DEBUG
  454         printf("%s()\n",__func__);
  455 #endif /* NGD_DEBUG */
  456 
  457         SLIST_FOREACH(tmp,&sc->head,links) {
  458                 if(tmp->ngddev == dev) {
  459                         connection = tmp;
  460                 }
  461         }
  462         if(connection == NULL) {
  463                 printf("%s(): connection is still NULL, no dev found\n",__func__);
  464                 return(-1);
  465         }
  466 
  467         /* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */
  468         NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s), 
  469                         M_NOWAIT);
  470         if (msg == NULL) {
  471                 printf("%s(): msg == NULL\n",__func__);
  472                 goto nomsg;
  473         }
  474 
  475         /* pass the ioctl data into the ->data area */
  476         datap = (struct ngd_param_s *)msg->data;
  477         datap->p = addr;
  478 
  479         NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
  480         if(error)
  481                 printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
  482 
  483 nomsg:
  484 
  485         return(0);
  486 }
  487 
  488 
  489 /*
  490  * This function is called when a read(2) is done to our device.
  491  * We pass the data available in kernelspace on into userland using
  492  * uiomove.
  493  */
  494 static int
  495 ngdread(struct cdev *dev, struct uio *uio, int flag)
  496 {
  497         int ret = 0, amnt;
  498         char buffer[uio->uio_resid+1];
  499         struct ngd_softc *sc = &ngd_softc;
  500         struct ngd_connection * connection = NULL;
  501         struct ngd_connection * tmp;
  502 
  503 #ifdef NGD_DEBUG
  504         printf("%s()\n",__func__);
  505 #endif /* NGD_DEBUG */
  506 
  507         SLIST_FOREACH(tmp,&sc->head,links) {
  508                 if(tmp->ngddev == dev) {
  509                         connection = tmp;
  510                 }
  511         }
  512         if(connection == NULL) {
  513                 printf("%s(): connection is still NULL, no dev found\n",__func__);
  514                 return(-1);
  515         }
  516 
  517         while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) {
  518                 amnt = MIN(uio->uio_resid,connection->loc);
  519 
  520                 memcpy(buffer,connection->readq, amnt);
  521                 memcpy(connection->readq, connection->readq+amnt,
  522                                 connection->loc-amnt);
  523                 connection->loc -= amnt;
  524 
  525                 ret = uiomove((caddr_t)buffer, amnt, uio);
  526                 if(ret != 0)
  527                         goto error;
  528 
  529         }
  530         return(0);
  531 
  532 error:
  533         printf("%s(): uiomove returns error %d\n",__func__,ret);
  534         /* do error cleanup here */
  535         return(ret);
  536 }
  537 
  538 
  539 /* 
  540  * This function is called when our device is written to.
  541  * We read the data from userland into our local buffer and pass it on
  542  * into the remote hook.
  543  *
  544  */
  545 static int
  546 ngdwrite(struct cdev *dev, struct uio *uio, int flag)
  547 {
  548         int ret;
  549         int error = 0;
  550         struct mbuf *m;
  551         char buffer[uio->uio_resid];
  552         int len = uio->uio_resid;
  553         struct ngd_softc *sc =& ngd_softc;
  554         struct ngd_connection * connection = NULL;
  555         struct ngd_connection * tmp;
  556 
  557 #ifdef NGD_DEBUG
  558         printf("%s()\n",__func__);
  559 #endif /* NGD_DEBUG */
  560 
  561         SLIST_FOREACH(tmp,&sc->head,links) {
  562                 if(tmp->ngddev == dev) {
  563                         connection = tmp;
  564                 }
  565         }
  566 
  567         if(connection == NULL) {
  568                 printf("%s(): connection is still NULL, no dev found\n",__func__);
  569                 return(-1);
  570         }
  571 
  572         if (len > 0) {
  573                 if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0)
  574                         goto error;
  575         } else
  576                 printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__);
  577 
  578         m = m_devget(buffer,len,0,NULL,NULL);
  579 
  580         NG_SEND_DATA_ONLY(error,connection->active_hook,m);
  581 
  582         return(0);
  583 
  584 error:
  585         /* do error cleanup here */
  586         printf("%s(): uiomove returned err: %d\n",__func__,ret);
  587 
  588         return(ret);
  589 }
  590 
  591 /*
  592  * we are being polled/selected
  593  * check if there is data available for read
  594  */
  595 static int
  596 ngdpoll(struct cdev *dev, int events, struct thread *td)
  597 {
  598         int revents = 0;
  599         struct ngd_softc *sc = &ngd_softc;
  600         struct ngd_connection * connection = NULL;
  601         struct ngd_connection * tmp;
  602 
  603 
  604         if (events & (POLLIN | POLLRDNORM)) {
  605                 /* get the connection we have to know the loc from */
  606                 SLIST_FOREACH(tmp,&sc->head,links) {
  607                         if(tmp->ngddev == dev) {
  608                                 connection = tmp;
  609                         }
  610                 }
  611                 if(connection == NULL) {
  612                         printf("%s(): ERROR: connection is still NULL,"
  613                                 "no dev found\n",__func__);
  614                         return(-1);
  615                 }
  616 
  617                 if (connection->loc > 0)
  618                         revents |= events & (POLLIN | POLLRDNORM);
  619         }
  620 
  621         return(revents);
  622 }

Cache object: b210a2bd6087af8beb3d218b69d41d06


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