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

Cache object: ce07bab56c53b6e2008549d2e40bc4df


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