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_base.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 /*
    3  * ng_base.c
    4  *
    5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    6  * All rights reserved.
    7  * 
    8  * Subject to the following obligations and disclaimer of warranty, use and
    9  * redistribution of this software, in source or object code forms, with or
   10  * without modifications are expressly permitted by Whistle Communications;
   11  * provided, however, that:
   12  * 1. Any and all reproductions of the source or object code must include the
   13  *    copyright notice above and the following disclaimer of warranties; and
   14  * 2. No rights are granted, in any manner or form, to use Whistle
   15  *    Communications, Inc. trademarks, including the mark "WHISTLE
   16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   17  *    such appears in the above copyright notice or in the software.
   18  * 
   19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   35  * OF SUCH DAMAGE.
   36  *
   37  * Authors: Julian Elischer <julian@freebsd.org>
   38  *          Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $FreeBSD$
   41  * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $
   42  */
   43 
   44 /*
   45  * This file implements the base netgraph code.
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/errno.h>
   51 #include <sys/kernel.h>
   52 #include <sys/malloc.h>
   53 #include <sys/syslog.h>
   54 #include <sys/linker.h>
   55 #include <sys/queue.h>
   56 #include <sys/mbuf.h>
   57 #include <sys/ctype.h>
   58 #include <sys/sysctl.h>
   59 #include <machine/limits.h>
   60 
   61 #include <net/netisr.h>
   62 
   63 #include <netgraph/ng_message.h>
   64 #include <netgraph/netgraph.h>
   65 #include <netgraph/ng_parse.h>
   66 
   67 /* List of all nodes */
   68 static LIST_HEAD(, ng_node) nodelist;
   69 
   70 /* List of installed types */
   71 static LIST_HEAD(, ng_type) typelist;
   72 
   73 /* Hash releted definitions */
   74 #define ID_HASH_SIZE 32 /* most systems wont need even this many */
   75 static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE];
   76 /* Don't nead to initialise them because it's a LIST */
   77 
   78 /* Internal functions */
   79 static int      ng_add_hook(node_p node, const char *name, hook_p * hookp);
   80 static int      ng_connect(hook_p hook1, hook_p hook2);
   81 static void     ng_disconnect_hook(hook_p hook);
   82 static int      ng_generic_msg(node_p here, struct ng_mesg *msg,
   83                         const char *retaddr, struct ng_mesg ** resp);
   84 static ng_ID_t  ng_decodeidname(const char *name);
   85 static int      ngb_mod_event(module_t mod, int event, void *data);
   86 static void     ngintr(void);
   87 
   88 /* Our own netgraph malloc type */
   89 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
   90 
   91 /* Set this to Debugger("X") to catch all errors as they occur */
   92 #ifndef TRAP_ERROR
   93 #define TRAP_ERROR
   94 #endif
   95 
   96 static  ng_ID_t nextID = 1;
   97 
   98 #ifdef INVARIANTS
   99 #define CHECK_DATA_MBUF(m)      do {                                    \
  100                 struct mbuf *n;                                         \
  101                 int total;                                              \
  102                                                                         \
  103                 if (((m)->m_flags & M_PKTHDR) == 0)                     \
  104                         panic("%s: !PKTHDR", __FUNCTION__);             \
  105                 for (total = 0, n = (m); n != NULL; n = n->m_next)      \
  106                         total += n->m_len;                              \
  107                 if ((m)->m_pkthdr.len != total) {                       \
  108                         panic("%s: %d != %d",                           \
  109                             __FUNCTION__, (m)->m_pkthdr.len, total);    \
  110                 }                                                       \
  111         } while (0)
  112 #else
  113 #define CHECK_DATA_MBUF(m)
  114 #endif
  115 
  116 
  117 /************************************************************************
  118         Parse type definitions for generic messages
  119 ************************************************************************/
  120 
  121 /* Handy structure parse type defining macro */
  122 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args)                          \
  123 static const struct ng_parse_struct_field                               \
  124         ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args;  \
  125 static const struct ng_parse_type ng_generic_ ## lo ## _type = {        \
  126         &ng_parse_struct_type,                                          \
  127         &ng_ ## lo ## _type_fields                                      \
  128 }
  129 
  130 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
  131 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
  132 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
  133 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
  134 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
  135 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
  136 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
  137 
  138 /* Get length of an array when the length is stored as a 32 bit
  139    value immediately preceeding the array -- as with struct namelist
  140    and struct typelist. */
  141 static int
  142 ng_generic_list_getLength(const struct ng_parse_type *type,
  143         const u_char *start, const u_char *buf)
  144 {
  145         return *((const u_int32_t *)(buf - 4));
  146 }
  147 
  148 /* Get length of the array of struct linkinfo inside a struct hooklist */
  149 static int
  150 ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
  151         const u_char *start, const u_char *buf)
  152 {
  153         const struct hooklist *hl = (const struct hooklist *)start;
  154 
  155         return hl->nodeinfo.hooks;
  156 }
  157 
  158 /* Array type for a variable length array of struct namelist */
  159 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
  160         &ng_generic_nodeinfo_type,
  161         &ng_generic_list_getLength
  162 };
  163 static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
  164         &ng_parse_array_type,
  165         &ng_nodeinfoarray_type_info
  166 };
  167 
  168 /* Array type for a variable length array of struct typelist */
  169 static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
  170         &ng_generic_typeinfo_type,
  171         &ng_generic_list_getLength
  172 };
  173 static const struct ng_parse_type ng_generic_typeinfoarray_type = {
  174         &ng_parse_array_type,
  175         &ng_typeinfoarray_type_info
  176 };
  177 
  178 /* Array type for array of struct linkinfo in struct hooklist */
  179 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
  180         &ng_generic_linkinfo_type,
  181         &ng_generic_linkinfo_getLength
  182 };
  183 static const struct ng_parse_type ng_generic_linkinfo_array_type = {
  184         &ng_parse_array_type,
  185         &ng_generic_linkinfo_array_type_info
  186 };
  187 
  188 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
  189 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
  190         (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
  191 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
  192         (&ng_generic_nodeinfoarray_type));
  193 
  194 /* List of commands and how to convert arguments to/from ASCII */
  195 static const struct ng_cmdlist ng_generic_cmds[] = {
  196         {
  197           NGM_GENERIC_COOKIE,
  198           NGM_SHUTDOWN,
  199           "shutdown",
  200           NULL,
  201           NULL
  202         },
  203         {
  204           NGM_GENERIC_COOKIE,
  205           NGM_MKPEER,
  206           "mkpeer",
  207           &ng_generic_mkpeer_type,
  208           NULL
  209         },
  210         {
  211           NGM_GENERIC_COOKIE,
  212           NGM_CONNECT,
  213           "connect",
  214           &ng_generic_connect_type,
  215           NULL
  216         },
  217         {
  218           NGM_GENERIC_COOKIE,
  219           NGM_NAME,
  220           "name",
  221           &ng_generic_name_type,
  222           NULL
  223         },
  224         {
  225           NGM_GENERIC_COOKIE,
  226           NGM_RMHOOK,
  227           "rmhook",
  228           &ng_generic_rmhook_type,
  229           NULL
  230         },
  231         {
  232           NGM_GENERIC_COOKIE,
  233           NGM_NODEINFO,
  234           "nodeinfo",
  235           NULL,
  236           &ng_generic_nodeinfo_type
  237         },
  238         {
  239           NGM_GENERIC_COOKIE,
  240           NGM_LISTHOOKS,
  241           "listhooks",
  242           NULL,
  243           &ng_generic_hooklist_type
  244         },
  245         {
  246           NGM_GENERIC_COOKIE,
  247           NGM_LISTNAMES,
  248           "listnames",
  249           NULL,
  250           &ng_generic_listnodes_type    /* same as NGM_LISTNODES */
  251         },
  252         {
  253           NGM_GENERIC_COOKIE,
  254           NGM_LISTNODES,
  255           "listnodes",
  256           NULL,
  257           &ng_generic_listnodes_type
  258         },
  259         {
  260           NGM_GENERIC_COOKIE,
  261           NGM_LISTTYPES,
  262           "listtypes",
  263           NULL,
  264           &ng_generic_typeinfo_type
  265         },
  266         {
  267           NGM_GENERIC_COOKIE,
  268           NGM_TEXT_CONFIG,
  269           "textconfig",
  270           NULL,
  271           &ng_parse_string_type
  272         },
  273         {
  274           NGM_GENERIC_COOKIE,
  275           NGM_TEXT_STATUS,
  276           "textstatus",
  277           NULL,
  278           &ng_parse_string_type
  279         },
  280         {
  281           NGM_GENERIC_COOKIE,
  282           NGM_ASCII2BINARY,
  283           "ascii2binary",
  284           &ng_parse_ng_mesg_type,
  285           &ng_parse_ng_mesg_type
  286         },
  287         {
  288           NGM_GENERIC_COOKIE,
  289           NGM_BINARY2ASCII,
  290           "binary2ascii",
  291           &ng_parse_ng_mesg_type,
  292           &ng_parse_ng_mesg_type
  293         },
  294         { 0 }
  295 };
  296 
  297 /************************************************************************
  298                         Node routines
  299 ************************************************************************/
  300 
  301 /*
  302  * Instantiate a node of the requested type
  303  */
  304 int
  305 ng_make_node(const char *typename, node_p *nodepp)
  306 {
  307         struct ng_type *type;
  308 
  309         /* Check that the type makes sense */
  310         if (typename == NULL) {
  311                 TRAP_ERROR;
  312                 return (EINVAL);
  313         }
  314 
  315         /* Locate the node type */
  316         if ((type = ng_findtype(typename)) == NULL) {
  317                 char *path, filename[NG_TYPELEN + 4];
  318                 linker_file_t lf;
  319                 int error;
  320 
  321                 /* Not found, try to load it as a loadable module */
  322                 snprintf(filename, sizeof(filename), "ng_%s.ko", typename);
  323                 if ((path = linker_search_path(filename)) == NULL)
  324                         return (ENXIO);
  325                 error = linker_load_file(path, &lf);
  326                 FREE(path, M_LINKER);
  327                 if (error != 0)
  328                         return (error);
  329                 lf->userrefs++;         /* pretend loaded by the syscall */
  330 
  331                 /* Try again, as now the type should have linked itself in */
  332                 if ((type = ng_findtype(typename)) == NULL)
  333                         return (ENXIO);
  334         }
  335 
  336         /* Call the constructor */
  337         if (type->constructor != NULL)
  338                 return ((*type->constructor)(nodepp));
  339         else
  340                 return (ng_make_node_common(type, nodepp));
  341 }
  342 
  343 /*
  344  * Generic node creation. Called by node constructors.
  345  * The returned node has a reference count of 1.
  346  */
  347 int
  348 ng_make_node_common(struct ng_type *type, node_p *nodepp)
  349 {
  350         node_p node;
  351 
  352         /* Require the node type to have been already installed */
  353         if (ng_findtype(type->name) == NULL) {
  354                 TRAP_ERROR;
  355                 return (EINVAL);
  356         }
  357 
  358         /* Make a node and try attach it to the type */
  359         MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_NOWAIT);
  360         if (node == NULL) {
  361                 TRAP_ERROR;
  362                 return (ENOMEM);
  363         }
  364         bzero(node, sizeof(*node));
  365         node->type = type;
  366         node->refs++;                           /* note reference */
  367         type->refs++;
  368 
  369         /* Link us into the node linked list */
  370         LIST_INSERT_HEAD(&nodelist, node, nodes);
  371 
  372         /* Initialize hook list for new node */
  373         LIST_INIT(&node->hooks);
  374 
  375         /* get an ID and put us in the hash chain */
  376         node->ID = nextID++; /* 137 per second for 1 year before wrap */
  377         LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes);
  378 
  379         /* Done */
  380         *nodepp = node;
  381         return (0);
  382 }
  383 
  384 /*
  385  * Forceably start the shutdown process on a node. Either call
  386  * it's shutdown method, or do the default shutdown if there is
  387  * no type-specific method.
  388  *
  389  * Persistent nodes must have a type-specific method which
  390  * resets the NG_INVALID flag.
  391  */
  392 void
  393 ng_rmnode(node_p node)
  394 {
  395         /* Check if it's already shutting down */
  396         if ((node->flags & NG_INVALID) != 0)
  397                 return;
  398 
  399         /* Add an extra reference so it doesn't go away during this */
  400         node->refs++;
  401 
  402         /* Mark it invalid so any newcomers know not to try use it */
  403         node->flags |= NG_INVALID;
  404 
  405         /* Ask the type if it has anything to do in this case */
  406         if (node->type && node->type->shutdown)
  407                 (*node->type->shutdown)(node);
  408         else {                          /* do the default thing */
  409                 ng_unname(node);
  410                 ng_cutlinks(node);
  411                 ng_unref(node);
  412         }
  413 
  414         /* Remove extra reference, possibly the last */
  415         ng_unref(node);
  416 }
  417 
  418 /*
  419  * Called by the destructor to remove any STANDARD external references
  420  */
  421 void
  422 ng_cutlinks(node_p node)
  423 {
  424         hook_p  hook;
  425 
  426         /* Make sure that this is set to stop infinite loops */
  427         node->flags |= NG_INVALID;
  428 
  429         /* If we have sleepers, wake them up; they'll see NG_INVALID */
  430         if (node->sleepers)
  431                 wakeup(node);
  432 
  433         /* Notify all remaining connected nodes to disconnect */
  434         while ((hook = LIST_FIRST(&node->hooks)) != NULL)
  435                 ng_destroy_hook(hook);
  436 }
  437 
  438 /*
  439  * Remove a reference to the node, possibly the last
  440  */
  441 void
  442 ng_unref(node_p node)
  443 {
  444         int     s;
  445 
  446         s = splhigh();
  447         if (--node->refs <= 0) {
  448                 node->type->refs--;
  449                 LIST_REMOVE(node, nodes);
  450                 LIST_REMOVE(node, idnodes);
  451                 FREE(node, M_NETGRAPH);
  452         }
  453         splx(s);
  454 }
  455 
  456 /*
  457  * Wait for a node to come ready. Returns a node with a reference count;
  458  * don't forget to drop it when we are done with it using ng_release_node().
  459  */
  460 int
  461 ng_wait_node(node_p node, char *msg)
  462 {
  463         int s, error = 0;
  464 
  465         if (msg == NULL)
  466                 msg = "netgraph";
  467         s = splnet();
  468         node->sleepers++;
  469         node->refs++;           /* the sleeping process counts as a reference */
  470         while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY)
  471                 error = tsleep(node, (PZERO + 1) | PCATCH, msg, 0);
  472         node->sleepers--;
  473         if (node->flags & NG_INVALID) {
  474                 TRAP_ERROR;
  475                 error = ENXIO;
  476         } else {
  477                 KASSERT(node->refs > 1,
  478                     ("%s: refs=%d", __FUNCTION__, node->refs));
  479                 node->flags |= NG_BUSY;
  480         }
  481         splx(s);
  482 
  483         /* Release the reference we had on it */
  484         if (error != 0)
  485                 ng_unref(node);
  486         return error;
  487 }
  488 
  489 /*
  490  * Release a node acquired via ng_wait_node()
  491  */
  492 void
  493 ng_release_node(node_p node)
  494 {
  495         /* Declare that we don't want it */
  496         node->flags &= ~NG_BUSY;
  497 
  498         /* If we have sleepers, then wake them up */
  499         if (node->sleepers)
  500                 wakeup(node);
  501 
  502         /* We also have a reference.. drop it too */
  503         ng_unref(node);
  504 }
  505 
  506 /************************************************************************
  507                         Node ID handling
  508 ************************************************************************/
  509 static node_p
  510 ng_ID2node(ng_ID_t ID)
  511 {
  512         node_p np;
  513         LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) {
  514                 if ((np->flags & NG_INVALID) == 0 && np->ID == ID)
  515                         break;
  516         }
  517         return(np);
  518 }
  519 
  520 ng_ID_t
  521 ng_node2ID(node_p node)
  522 {
  523         return (node->ID);
  524 }
  525 
  526 /************************************************************************
  527                         Node name handling
  528 ************************************************************************/
  529 
  530 /*
  531  * Assign a node a name. Once assigned, the name cannot be changed.
  532  */
  533 int
  534 ng_name_node(node_p node, const char *name)
  535 {
  536         int i;
  537 
  538         /* Check the name is valid */
  539         for (i = 0; i < NG_NODELEN + 1; i++) {
  540                 if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
  541                         break;
  542         }
  543         if (i == 0 || name[i] != '\0') {
  544                 TRAP_ERROR;
  545                 return (EINVAL);
  546         }
  547         if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
  548                 TRAP_ERROR;
  549                 return (EINVAL);
  550         }
  551 
  552         /* Check the node isn't already named */
  553         if (node->name != NULL) {
  554                 TRAP_ERROR;
  555                 return (EISCONN);
  556         }
  557 
  558         /* Check the name isn't already being used */
  559         if (ng_findname(node, name) != NULL) {
  560                 TRAP_ERROR;
  561                 return (EADDRINUSE);
  562         }
  563 
  564         /* Allocate space and copy it */
  565         MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT);
  566         if (node->name == NULL) {
  567                 TRAP_ERROR;
  568                 return (ENOMEM);
  569         }
  570         strcpy(node->name, name);
  571 
  572         /* The name counts as a reference */
  573         node->refs++;
  574         return (0);
  575 }
  576 
  577 /*
  578  * Find a node by absolute name. The name should NOT end with ':'
  579  * The name "." means "this node" and "[xxx]" means "the node
  580  * with ID (ie, at address) xxx".
  581  *
  582  * Returns the node if found, else NULL.
  583  */
  584 node_p
  585 ng_findname(node_p this, const char *name)
  586 {
  587         node_p node;
  588         ng_ID_t temp;
  589 
  590         /* "." means "this node" */
  591         if (strcmp(name, ".") == 0)
  592                 return(this);
  593 
  594         /* Check for name-by-ID */
  595         if ((temp = ng_decodeidname(name)) != 0) {
  596                 return (ng_ID2node(temp));
  597         }
  598 
  599         /* Find node by name */
  600         LIST_FOREACH(node, &nodelist, nodes) {
  601                 if ((node->name != NULL)
  602                 && (strcmp(node->name, name) == 0)
  603                 && ((node->flags & NG_INVALID) == 0))
  604                         break;
  605         }
  606         return (node);
  607 }
  608 
  609 /*
  610  * Decode a ID name, eg. "[f03034de]". Returns 0 if the
  611  * string is not valid, otherwise returns the value.
  612  */
  613 static ng_ID_t
  614 ng_decodeidname(const char *name)
  615 {
  616         const int len = strlen(name);
  617         char *eptr;
  618         u_long val;
  619 
  620         /* Check for proper length, brackets, no leading junk */
  621         if (len < 3 || name[0] != '[' || name[len - 1] != ']'
  622             || !isxdigit(name[1]))
  623                 return (0);
  624 
  625         /* Decode number */
  626         val = strtoul(name + 1, &eptr, 16);
  627         if (eptr - name != len - 1 || val == ULONG_MAX || val == 0)
  628                 return ((ng_ID_t)0);
  629         return (ng_ID_t)val;
  630 }
  631 
  632 /*
  633  * Remove a name from a node. This should only be called
  634  * when shutting down and removing the node.
  635  */
  636 void
  637 ng_unname(node_p node)
  638 {
  639         if (node->name) {
  640                 FREE(node->name, M_NETGRAPH);
  641                 node->name = NULL;
  642                 ng_unref(node);
  643         }
  644 }
  645 
  646 /************************************************************************
  647                         Hook routines
  648 
  649  Names are not optional. Hooks are always connected, except for a
  650  brief moment within these routines.
  651 
  652 ************************************************************************/
  653 
  654 /*
  655  * Remove a hook reference
  656  */
  657 void
  658 ng_unref_hook(hook_p hook)
  659 {
  660         int     s;
  661 
  662         s = splhigh();
  663         if (--hook->refs == 0)
  664                 FREE(hook, M_NETGRAPH);
  665         splx(s);
  666 }
  667 
  668 /*
  669  * Add an unconnected hook to a node. Only used internally.
  670  */
  671 static int
  672 ng_add_hook(node_p node, const char *name, hook_p *hookp)
  673 {
  674         hook_p hook;
  675         int error = 0;
  676 
  677         /* Check that the given name is good */
  678         if (name == NULL) {
  679                 TRAP_ERROR;
  680                 return (EINVAL);
  681         }
  682         if (ng_findhook(node, name) != NULL) {
  683                 TRAP_ERROR;
  684                 return (EEXIST);
  685         }
  686 
  687         /* Allocate the hook and link it up */
  688         MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_NOWAIT);
  689         if (hook == NULL) {
  690                 TRAP_ERROR;
  691                 return (ENOMEM);
  692         }
  693         bzero(hook, sizeof(*hook));
  694         hook->refs = 1;
  695         hook->flags = HK_INVALID;
  696         hook->node = node;
  697         node->refs++;           /* each hook counts as a reference */
  698 
  699         /* Check if the node type code has something to say about it */
  700         if (node->type->newhook != NULL)
  701                 if ((error = (*node->type->newhook)(node, hook, name)) != 0)
  702                         goto fail;
  703 
  704         /*
  705          * The 'type' agrees so far, so go ahead and link it in.
  706          * We'll ask again later when we actually connect the hooks.
  707          */
  708         LIST_INSERT_HEAD(&node->hooks, hook, hooks);
  709         node->numhooks++;
  710 
  711         /* Set hook name */
  712         MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT);
  713         if (hook->name == NULL) {
  714                 error = ENOMEM;
  715                 LIST_REMOVE(hook, hooks);
  716                 node->numhooks--;
  717 fail:
  718                 hook->node = NULL;
  719                 ng_unref(node);
  720                 ng_unref_hook(hook);    /* this frees the hook */
  721                 return (error);
  722         }
  723         strcpy(hook->name, name);
  724         if (hookp)
  725                 *hookp = hook;
  726         return (error);
  727 }
  728 
  729 /*
  730  * Connect a pair of hooks. Only used internally.
  731  */
  732 static int
  733 ng_connect(hook_p hook1, hook_p hook2)
  734 {
  735         int     error;
  736 
  737         hook1->peer = hook2;
  738         hook2->peer = hook1;
  739 
  740         /* Give each node the opportunity to veto the impending connection */
  741         if (hook1->node->type->connect) {
  742                 if ((error = (*hook1->node->type->connect) (hook1))) {
  743                         ng_destroy_hook(hook1); /* also zaps hook2 */
  744                         return (error);
  745                 }
  746         }
  747         if (hook2->node->type->connect) {
  748                 if ((error = (*hook2->node->type->connect) (hook2))) {
  749                         ng_destroy_hook(hook2); /* also zaps hook1 */
  750                         return (error);
  751                 }
  752         }
  753         hook1->flags &= ~HK_INVALID;
  754         hook2->flags &= ~HK_INVALID;
  755         return (0);
  756 }
  757 
  758 /*
  759  * Find a hook
  760  *
  761  * Node types may supply their own optimized routines for finding
  762  * hooks.  If none is supplied, we just do a linear search.
  763  */
  764 hook_p
  765 ng_findhook(node_p node, const char *name)
  766 {
  767         hook_p hook;
  768 
  769         if (node->type->findhook != NULL)
  770                 return (*node->type->findhook)(node, name);
  771         LIST_FOREACH(hook, &node->hooks, hooks) {
  772                 if (hook->name != NULL
  773                     && strcmp(hook->name, name) == 0
  774                     && (hook->flags & HK_INVALID) == 0)
  775                         return (hook);
  776         }
  777         return (NULL);
  778 }
  779 
  780 /*
  781  * Destroy a hook
  782  *
  783  * As hooks are always attached, this really destroys two hooks.
  784  * The one given, and the one attached to it. Disconnect the hooks
  785  * from each other first.
  786  */
  787 void
  788 ng_destroy_hook(hook_p hook)
  789 {
  790         hook_p peer = hook->peer;
  791 
  792         hook->flags |= HK_INVALID;              /* as soon as possible */
  793         if (peer) {
  794                 peer->flags |= HK_INVALID;      /* as soon as possible */
  795                 hook->peer = NULL;
  796                 peer->peer = NULL;
  797                 ng_disconnect_hook(peer);
  798         }
  799         ng_disconnect_hook(hook);
  800 }
  801 
  802 /*
  803  * Notify the node of the hook's demise. This may result in more actions
  804  * (e.g. shutdown) but we don't do that ourselves and don't know what
  805  * happens there. If there is no appropriate handler, then just remove it
  806  * (and decrement the reference count of it's node which in turn might
  807  * make something happen).
  808  */
  809 static void
  810 ng_disconnect_hook(hook_p hook)
  811 {
  812         node_p node = hook->node;
  813 
  814         /*
  815          * Remove the hook from the node's list to avoid possible recursion
  816          * in case the disconnection results in node shutdown.
  817          */
  818         LIST_REMOVE(hook, hooks);
  819         node->numhooks--;
  820         if (node->type->disconnect) {
  821                 /*
  822                  * The type handler may elect to destroy the peer so don't
  823                  * trust its existance after this point.
  824                  */
  825                 (*node->type->disconnect) (hook);
  826         }
  827         ng_unref(node);         /* might be the last reference */
  828         if (hook->name)
  829                 FREE(hook->name, M_NETGRAPH);
  830         hook->node = NULL;      /* may still be referenced elsewhere */
  831         ng_unref_hook(hook);
  832 }
  833 
  834 /*
  835  * Take two hooks on a node and merge the connection so that the given node
  836  * is effectively bypassed.
  837  */
  838 int
  839 ng_bypass(hook_p hook1, hook_p hook2)
  840 {
  841         if (hook1->node != hook2->node)
  842                 return (EINVAL);
  843         hook1->peer->peer = hook2->peer;
  844         hook2->peer->peer = hook1->peer;
  845 
  846         /* XXX If we ever cache methods on hooks update them as well */
  847         hook1->peer = NULL;
  848         hook2->peer = NULL;
  849         ng_destroy_hook(hook1);
  850         ng_destroy_hook(hook2);
  851         return (0);
  852 }
  853 
  854 /*
  855  * Install a new netgraph type
  856  */
  857 int
  858 ng_newtype(struct ng_type *tp)
  859 {
  860         const size_t namelen = strlen(tp->name);
  861 
  862         /* Check version and type name fields */
  863         if (tp->version != NG_VERSION || namelen == 0 || namelen > NG_TYPELEN) {
  864                 TRAP_ERROR;
  865                 return (EINVAL);
  866         }
  867 
  868         /* Check for name collision */
  869         if (ng_findtype(tp->name) != NULL) {
  870                 TRAP_ERROR;
  871                 return (EEXIST);
  872         }
  873 
  874         /* Link in new type */
  875         LIST_INSERT_HEAD(&typelist, tp, types);
  876         tp->refs = 1;   /* first ref is linked list */
  877         return (0);
  878 }
  879 
  880 /*
  881  * Look for a type of the name given
  882  */
  883 struct ng_type *
  884 ng_findtype(const char *typename)
  885 {
  886         struct ng_type *type;
  887 
  888         LIST_FOREACH(type, &typelist, types) {
  889                 if (strcmp(type->name, typename) == 0)
  890                         break;
  891         }
  892         return (type);
  893 }
  894 
  895 
  896 /************************************************************************
  897                         Composite routines
  898 ************************************************************************/
  899 
  900 /*
  901  * Make a peer and connect. The order is arranged to minimise
  902  * the work needed to back out in case of error.
  903  */
  904 int
  905 ng_mkpeer(node_p node, const char *name, const char *name2, char *type)
  906 {
  907         node_p  node2;
  908         hook_p  hook;
  909         hook_p  hook2;
  910         int     error;
  911 
  912         if ((error = ng_add_hook(node, name, &hook)))
  913                 return (error);
  914         if ((error = ng_make_node(type, &node2))) {
  915                 ng_destroy_hook(hook);
  916                 return (error);
  917         }
  918         if ((error = ng_add_hook(node2, name2, &hook2))) {
  919                 ng_rmnode(node2);
  920                 ng_destroy_hook(hook);
  921                 return (error);
  922         }
  923 
  924         /*
  925          * Actually link the two hooks together.. on failure they are
  926          * destroyed so we don't have to do that here.
  927          */
  928         if ((error = ng_connect(hook, hook2)))
  929                 ng_rmnode(node2);
  930         return (error);
  931 }
  932 
  933 /*
  934  * Connect two nodes using the specified hooks
  935  */
  936 int
  937 ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2)
  938 {
  939         int     error;
  940         hook_p  hook;
  941         hook_p  hook2;
  942 
  943         if ((error = ng_add_hook(node, name, &hook)))
  944                 return (error);
  945         if ((error = ng_add_hook(node2, name2, &hook2))) {
  946                 ng_destroy_hook(hook);
  947                 return (error);
  948         }
  949         return (ng_connect(hook, hook2));
  950 }
  951 
  952 /*
  953  * Parse and verify a string of the form:  <NODE:><PATH>
  954  *
  955  * Such a string can refer to a specific node or a specific hook
  956  * on a specific node, depending on how you look at it. In the
  957  * latter case, the PATH component must not end in a dot.
  958  *
  959  * Both <NODE:> and <PATH> are optional. The <PATH> is a string
  960  * of hook names separated by dots. This breaks out the original
  961  * string, setting *nodep to "NODE" (or NULL if none) and *pathp
  962  * to "PATH" (or NULL if degenerate). Also, *hookp will point to
  963  * the final hook component of <PATH>, if any, otherwise NULL.
  964  *
  965  * This returns -1 if the path is malformed. The char ** are optional.
  966  */
  967 
  968 int
  969 ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp)
  970 {
  971         char   *node, *path, *hook;
  972         int     k;
  973 
  974         /*
  975          * Extract absolute NODE, if any
  976          */
  977         for (path = addr; *path && *path != ':'; path++);
  978         if (*path) {
  979                 node = addr;    /* Here's the NODE */
  980                 *path++ = '\0'; /* Here's the PATH */
  981 
  982                 /* Node name must not be empty */
  983                 if (!*node)
  984                         return -1;
  985 
  986                 /* A name of "." is OK; otherwise '.' not allowed */
  987                 if (strcmp(node, ".") != 0) {
  988                         for (k = 0; node[k]; k++)
  989                                 if (node[k] == '.')
  990                                         return -1;
  991                 }
  992         } else {
  993                 node = NULL;    /* No absolute NODE */
  994                 path = addr;    /* Here's the PATH */
  995         }
  996 
  997         /* Snoop for illegal characters in PATH */
  998         for (k = 0; path[k]; k++)
  999                 if (path[k] == ':')
 1000                         return -1;
 1001 
 1002         /* Check for no repeated dots in PATH */
 1003         for (k = 0; path[k]; k++)
 1004                 if (path[k] == '.' && path[k + 1] == '.')
 1005                         return -1;
 1006 
 1007         /* Remove extra (degenerate) dots from beginning or end of PATH */
 1008         if (path[0] == '.')
 1009                 path++;
 1010         if (*path && path[strlen(path) - 1] == '.')
 1011                 path[strlen(path) - 1] = 0;
 1012 
 1013         /* If PATH has a dot, then we're not talking about a hook */
 1014         if (*path) {
 1015                 for (hook = path, k = 0; path[k]; k++)
 1016                         if (path[k] == '.') {
 1017                                 hook = NULL;
 1018                                 break;
 1019                         }
 1020         } else
 1021                 path = hook = NULL;
 1022 
 1023         /* Done */
 1024         if (nodep)
 1025                 *nodep = node;
 1026         if (pathp)
 1027                 *pathp = path;
 1028         if (hookp)
 1029                 *hookp = hook;
 1030         return (0);
 1031 }
 1032 
 1033 /*
 1034  * Given a path, which may be absolute or relative, and a starting node,
 1035  * return the destination node. Compute the "return address" if desired.
 1036  */
 1037 int
 1038 ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
 1039 {
 1040         const   node_p start = here;
 1041         char    fullpath[NG_PATHLEN + 1];
 1042         char   *nodename, *path, pbuf[2];
 1043         node_p  node;
 1044         char   *cp;
 1045 
 1046         /* Initialize */
 1047         if (rtnp)
 1048                 *rtnp = NULL;
 1049         if (destp == NULL)
 1050                 return EINVAL;
 1051         *destp = NULL;
 1052 
 1053         /* Make a writable copy of address for ng_path_parse() */
 1054         strncpy(fullpath, address, sizeof(fullpath) - 1);
 1055         fullpath[sizeof(fullpath) - 1] = '\0';
 1056 
 1057         /* Parse out node and sequence of hooks */
 1058         if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) {
 1059                 TRAP_ERROR;
 1060                 return EINVAL;
 1061         }
 1062         if (path == NULL) {
 1063                 pbuf[0] = '.';  /* Needs to be writable */
 1064                 pbuf[1] = '\0';
 1065                 path = pbuf;
 1066         }
 1067 
 1068         /* For an absolute address, jump to the starting node */
 1069         if (nodename) {
 1070                 node = ng_findname(here, nodename);
 1071                 if (node == NULL) {
 1072                         TRAP_ERROR;
 1073                         return (ENOENT);
 1074                 }
 1075         } else
 1076                 node = here;
 1077 
 1078         /* Now follow the sequence of hooks */
 1079         for (cp = path; node != NULL && *cp != '\0'; ) {
 1080                 hook_p hook;
 1081                 char *segment;
 1082 
 1083                 /*
 1084                  * Break out the next path segment. Replace the dot we just
 1085                  * found with a NUL; "cp" points to the next segment (or the
 1086                  * NUL at the end).
 1087                  */
 1088                 for (segment = cp; *cp != '\0'; cp++) {
 1089                         if (*cp == '.') {
 1090                                 *cp++ = '\0';
 1091                                 break;
 1092                         }
 1093                 }
 1094 
 1095                 /* Empty segment */
 1096                 if (*segment == '\0')
 1097                         continue;
 1098 
 1099                 /* We have a segment, so look for a hook by that name */
 1100                 hook = ng_findhook(node, segment);
 1101 
 1102                 /* Can't get there from here... */
 1103                 if (hook == NULL
 1104                     || hook->peer == NULL
 1105                     || (hook->flags & HK_INVALID) != 0) {
 1106                         TRAP_ERROR;
 1107                         return (ENOENT);
 1108                 }
 1109 
 1110                 /* Hop on over to the next node */
 1111                 node = hook->peer->node;
 1112         }
 1113 
 1114         /* If node somehow missing, fail here (probably this is not needed) */
 1115         if (node == NULL) {
 1116                 TRAP_ERROR;
 1117                 return (ENXIO);
 1118         }
 1119 
 1120         /* Now compute return address, i.e., the path to the sender */
 1121         if (rtnp != NULL) {
 1122                 MALLOC(*rtnp, char *, NG_NODELEN + 2, M_NETGRAPH, M_NOWAIT);
 1123                 if (*rtnp == NULL) {
 1124                         TRAP_ERROR;
 1125                         return (ENOMEM);
 1126                 }
 1127                 if (start->name != NULL)
 1128                         sprintf(*rtnp, "%s:", start->name);
 1129                 else
 1130                         sprintf(*rtnp, "[%x]:", ng_node2ID(start));
 1131         }
 1132 
 1133         /* Done */
 1134         *destp = node;
 1135         return (0);
 1136 }
 1137 
 1138 /*
 1139  * Call the appropriate message handler for the object.
 1140  * It is up to the message handler to free the message.
 1141  * If it's a generic message, handle it generically, otherwise
 1142  * call the type's message handler (if it exists)
 1143  * XXX (race). Remember that a queued message may reference a node
 1144  * or hook that has just been invalidated. It will exist
 1145  * as the queue code is holding a reference, but..
 1146  */
 1147 
 1148 #define CALL_MSG_HANDLER(error, node, msg, retaddr, resp)               \
 1149 do {                                                                    \
 1150         if((msg)->header.typecookie == NGM_GENERIC_COOKIE) {            \
 1151                 (error) = ng_generic_msg((node), (msg),                 \
 1152                                 (retaddr), (resp));                     \
 1153         } else {                                                        \
 1154                 if ((node)->type->rcvmsg != NULL) {                     \
 1155                         (error) = (*(node)->type->rcvmsg)((node),       \
 1156                                         (msg), (retaddr), (resp));      \
 1157                 } else {                                                \
 1158                         TRAP_ERROR;                                     \
 1159                         FREE((msg), M_NETGRAPH);                        \
 1160                         (error) = EINVAL;                               \
 1161                 }                                                       \
 1162         }                                                               \
 1163 } while (0)
 1164 
 1165 
 1166 /*
 1167  * Send a control message to a node
 1168  */
 1169 int
 1170 ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
 1171             struct ng_mesg **rptr)
 1172 {
 1173         node_p  dest = NULL;
 1174         char   *retaddr = NULL;
 1175         int     error;
 1176 
 1177         /* Find the target node */
 1178         error = ng_path2node(here, address, &dest, &retaddr);
 1179         if (error) {
 1180                 FREE(msg, M_NETGRAPH);
 1181                 return error;
 1182         }
 1183 
 1184         /* Make sure the resp field is null before we start */
 1185         if (rptr != NULL)
 1186                 *rptr = NULL;
 1187 
 1188         CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr);
 1189 
 1190         /* Make sure that if there is a response, it has the RESP bit set */
 1191         if ((error == 0) && rptr && *rptr)
 1192                 (*rptr)->header.flags |= NGF_RESP;
 1193 
 1194         /*
 1195          * If we had a return address it is up to us to free it. They should
 1196          * have taken a copy if they needed to make a delayed response.
 1197          */
 1198         if (retaddr)
 1199                 FREE(retaddr, M_NETGRAPH);
 1200         return (error);
 1201 }
 1202 
 1203 /*
 1204  * Implement the 'generic' control messages
 1205  */
 1206 static int
 1207 ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
 1208                struct ng_mesg **resp)
 1209 {
 1210         int error = 0;
 1211 
 1212         if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
 1213                 TRAP_ERROR;
 1214                 FREE(msg, M_NETGRAPH);
 1215                 return (EINVAL);
 1216         }
 1217         switch (msg->header.cmd) {
 1218         case NGM_SHUTDOWN:
 1219                 ng_rmnode(here);
 1220                 break;
 1221         case NGM_MKPEER:
 1222             {
 1223                 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
 1224 
 1225                 if (msg->header.arglen != sizeof(*mkp)) {
 1226                         TRAP_ERROR;
 1227                         return (EINVAL);
 1228                 }
 1229                 mkp->type[sizeof(mkp->type) - 1] = '\0';
 1230                 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0';
 1231                 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0';
 1232                 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type);
 1233                 break;
 1234             }
 1235         case NGM_CONNECT:
 1236             {
 1237                 struct ngm_connect *const con =
 1238                         (struct ngm_connect *) msg->data;
 1239                 node_p node2;
 1240 
 1241                 if (msg->header.arglen != sizeof(*con)) {
 1242                         TRAP_ERROR;
 1243                         return (EINVAL);
 1244                 }
 1245                 con->path[sizeof(con->path) - 1] = '\0';
 1246                 con->ourhook[sizeof(con->ourhook) - 1] = '\0';
 1247                 con->peerhook[sizeof(con->peerhook) - 1] = '\0';
 1248                 error = ng_path2node(here, con->path, &node2, NULL);
 1249                 if (error)
 1250                         break;
 1251                 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook);
 1252                 break;
 1253             }
 1254         case NGM_NAME:
 1255             {
 1256                 struct ngm_name *const nam = (struct ngm_name *) msg->data;
 1257 
 1258                 if (msg->header.arglen != sizeof(*nam)) {
 1259                         TRAP_ERROR;
 1260                         return (EINVAL);
 1261                 }
 1262                 nam->name[sizeof(nam->name) - 1] = '\0';
 1263                 error = ng_name_node(here, nam->name);
 1264                 break;
 1265             }
 1266         case NGM_RMHOOK:
 1267             {
 1268                 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data;
 1269                 hook_p hook;
 1270 
 1271                 if (msg->header.arglen != sizeof(*rmh)) {
 1272                         TRAP_ERROR;
 1273                         return (EINVAL);
 1274                 }
 1275                 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0';
 1276                 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL)
 1277                         ng_destroy_hook(hook);
 1278                 break;
 1279             }
 1280         case NGM_NODEINFO:
 1281             {
 1282                 struct nodeinfo *ni;
 1283                 struct ng_mesg *rp;
 1284 
 1285                 /* Get response struct */
 1286                 if (resp == NULL) {
 1287                         error = EINVAL;
 1288                         break;
 1289                 }
 1290                 NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT);
 1291                 if (rp == NULL) {
 1292                         error = ENOMEM;
 1293                         break;
 1294                 }
 1295 
 1296                 /* Fill in node info */
 1297                 ni = (struct nodeinfo *) rp->data;
 1298                 if (here->name != NULL)
 1299                         strncpy(ni->name, here->name, NG_NODELEN);
 1300                 strncpy(ni->type, here->type->name, NG_TYPELEN);
 1301                 ni->id = ng_node2ID(here);
 1302                 ni->hooks = here->numhooks;
 1303                 *resp = rp;
 1304                 break;
 1305             }
 1306         case NGM_LISTHOOKS:
 1307             {
 1308                 const int nhooks = here->numhooks;
 1309                 struct hooklist *hl;
 1310                 struct nodeinfo *ni;
 1311                 struct ng_mesg *rp;
 1312                 hook_p hook;
 1313 
 1314                 /* Get response struct */
 1315                 if (resp == NULL) {
 1316                         error = EINVAL;
 1317                         break;
 1318                 }
 1319                 NG_MKRESPONSE(rp, msg, sizeof(*hl)
 1320                     + (nhooks * sizeof(struct linkinfo)), M_NOWAIT);
 1321                 if (rp == NULL) {
 1322                         error = ENOMEM;
 1323                         break;
 1324                 }
 1325                 hl = (struct hooklist *) rp->data;
 1326                 ni = &hl->nodeinfo;
 1327 
 1328                 /* Fill in node info */
 1329                 if (here->name)
 1330                         strncpy(ni->name, here->name, NG_NODELEN);
 1331                 strncpy(ni->type, here->type->name, NG_TYPELEN);
 1332                 ni->id = ng_node2ID(here);
 1333 
 1334                 /* Cycle through the linked list of hooks */
 1335                 ni->hooks = 0;
 1336                 LIST_FOREACH(hook, &here->hooks, hooks) {
 1337                         struct linkinfo *const link = &hl->link[ni->hooks];
 1338 
 1339                         if (ni->hooks >= nhooks) {
 1340                                 log(LOG_ERR, "%s: number of %s changed\n",
 1341                                     __FUNCTION__, "hooks");
 1342                                 break;
 1343                         }
 1344                         if ((hook->flags & HK_INVALID) != 0)
 1345                                 continue;
 1346                         strncpy(link->ourhook, hook->name, NG_HOOKLEN);
 1347                         strncpy(link->peerhook, hook->peer->name, NG_HOOKLEN);
 1348                         if (hook->peer->node->name != NULL)
 1349                                 strncpy(link->nodeinfo.name,
 1350                                     hook->peer->node->name, NG_NODELEN);
 1351                         strncpy(link->nodeinfo.type,
 1352                            hook->peer->node->type->name, NG_TYPELEN);
 1353                         link->nodeinfo.id = ng_node2ID(hook->peer->node);
 1354                         link->nodeinfo.hooks = hook->peer->node->numhooks;
 1355                         ni->hooks++;
 1356                 }
 1357                 *resp = rp;
 1358                 break;
 1359             }
 1360 
 1361         case NGM_LISTNAMES:
 1362         case NGM_LISTNODES:
 1363             {
 1364                 const int unnamed = (msg->header.cmd == NGM_LISTNODES);
 1365                 struct namelist *nl;
 1366                 struct ng_mesg *rp;
 1367                 node_p node;
 1368                 int num = 0;
 1369 
 1370                 if (resp == NULL) {
 1371                         error = EINVAL;
 1372                         break;
 1373                 }
 1374 
 1375                 /* Count number of nodes */
 1376                 LIST_FOREACH(node, &nodelist, nodes) {
 1377                         if ((node->flags & NG_INVALID) == 0
 1378                             && (unnamed || node->name != NULL))
 1379                                 num++;
 1380                 }
 1381 
 1382                 /* Get response struct */
 1383                 if (resp == NULL) {
 1384                         error = EINVAL;
 1385                         break;
 1386                 }
 1387                 NG_MKRESPONSE(rp, msg, sizeof(*nl)
 1388                     + (num * sizeof(struct nodeinfo)), M_NOWAIT);
 1389                 if (rp == NULL) {
 1390                         error = ENOMEM;
 1391                         break;
 1392                 }
 1393                 nl = (struct namelist *) rp->data;
 1394 
 1395                 /* Cycle through the linked list of nodes */
 1396                 nl->numnames = 0;
 1397                 LIST_FOREACH(node, &nodelist, nodes) {
 1398                         struct nodeinfo *const np = &nl->nodeinfo[nl->numnames];
 1399 
 1400                         if (nl->numnames >= num) {
 1401                                 log(LOG_ERR, "%s: number of %s changed\n",
 1402                                     __FUNCTION__, "nodes");
 1403                                 break;
 1404                         }
 1405                         if ((node->flags & NG_INVALID) != 0)
 1406                                 continue;
 1407                         if (!unnamed && node->name == NULL)
 1408                                 continue;
 1409                         if (node->name != NULL)
 1410                                 strncpy(np->name, node->name, NG_NODELEN);
 1411                         strncpy(np->type, node->type->name, NG_TYPELEN);
 1412                         np->id = ng_node2ID(node);
 1413                         np->hooks = node->numhooks;
 1414                         nl->numnames++;
 1415                 }
 1416                 *resp = rp;
 1417                 break;
 1418             }
 1419 
 1420         case NGM_LISTTYPES:
 1421             {
 1422                 struct typelist *tl;
 1423                 struct ng_mesg *rp;
 1424                 struct ng_type *type;
 1425                 int num = 0;
 1426 
 1427                 if (resp == NULL) {
 1428                         error = EINVAL;
 1429                         break;
 1430                 }
 1431 
 1432                 /* Count number of types */
 1433                 LIST_FOREACH(type, &typelist, types)
 1434                         num++;
 1435 
 1436                 /* Get response struct */
 1437                 if (resp == NULL) {
 1438                         error = EINVAL;
 1439                         break;
 1440                 }
 1441                 NG_MKRESPONSE(rp, msg, sizeof(*tl)
 1442                     + (num * sizeof(struct typeinfo)), M_NOWAIT);
 1443                 if (rp == NULL) {
 1444                         error = ENOMEM;
 1445                         break;
 1446                 }
 1447                 tl = (struct typelist *) rp->data;
 1448 
 1449                 /* Cycle through the linked list of types */
 1450                 tl->numtypes = 0;
 1451                 LIST_FOREACH(type, &typelist, types) {
 1452                         struct typeinfo *const tp = &tl->typeinfo[tl->numtypes];
 1453 
 1454                         if (tl->numtypes >= num) {
 1455                                 log(LOG_ERR, "%s: number of %s changed\n",
 1456                                     __FUNCTION__, "types");
 1457                                 break;
 1458                         }
 1459                         strncpy(tp->type_name, type->name, NG_TYPELEN);
 1460                         tp->numnodes = type->refs - 1; /* don't count list */
 1461                         tl->numtypes++;
 1462                 }
 1463                 *resp = rp;
 1464                 break;
 1465             }
 1466 
 1467         case NGM_BINARY2ASCII:
 1468             {
 1469                 int bufSize = 20 * 1024;        /* XXX hard coded constant */
 1470                 const struct ng_parse_type *argstype;
 1471                 const struct ng_cmdlist *c;
 1472                 struct ng_mesg *rp, *binary, *ascii;
 1473 
 1474                 /* Data area must contain a valid netgraph message */
 1475                 binary = (struct ng_mesg *)msg->data;
 1476                 if (msg->header.arglen < sizeof(struct ng_mesg)
 1477                     || msg->header.arglen - sizeof(struct ng_mesg) 
 1478                       < binary->header.arglen) {
 1479                         error = EINVAL;
 1480                         break;
 1481                 }
 1482 
 1483                 /* Get a response message with lots of room */
 1484                 NG_MKRESPONSE(rp, msg, sizeof(*ascii) + bufSize, M_NOWAIT);
 1485                 if (rp == NULL) {
 1486                         error = ENOMEM;
 1487                         break;
 1488                 }
 1489                 ascii = (struct ng_mesg *)rp->data;
 1490 
 1491                 /* Copy binary message header to response message payload */
 1492                 bcopy(binary, ascii, sizeof(*binary));
 1493 
 1494                 /* Find command by matching typecookie and command number */
 1495                 for (c = here->type->cmdlist;
 1496                     c != NULL && c->name != NULL; c++) {
 1497                         if (binary->header.typecookie == c->cookie
 1498                             && binary->header.cmd == c->cmd)
 1499                                 break;
 1500                 }
 1501                 if (c == NULL || c->name == NULL) {
 1502                         for (c = ng_generic_cmds; c->name != NULL; c++) {
 1503                                 if (binary->header.typecookie == c->cookie
 1504                                     && binary->header.cmd == c->cmd)
 1505                                         break;
 1506                         }
 1507                         if (c->name == NULL) {
 1508                                 FREE(rp, M_NETGRAPH);
 1509                                 error = ENOSYS;
 1510                                 break;
 1511                         }
 1512                 }
 1513 
 1514                 /* Convert command name to ASCII */
 1515                 snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr),
 1516                     "%s", c->name);
 1517 
 1518                 /* Convert command arguments to ASCII */
 1519                 argstype = (binary->header.flags & NGF_RESP) ?
 1520                     c->respType : c->mesgType;
 1521                 if (argstype == NULL)
 1522                         *ascii->data = '\0';
 1523                 else {
 1524                         if ((error = ng_unparse(argstype,
 1525                             (u_char *)binary->data,
 1526                             ascii->data, bufSize)) != 0) {
 1527                                 FREE(rp, M_NETGRAPH);
 1528                                 break;
 1529                         }
 1530                 }
 1531 
 1532                 /* Return the result as struct ng_mesg plus ASCII string */
 1533                 bufSize = strlen(ascii->data) + 1;
 1534                 ascii->header.arglen = bufSize;
 1535                 rp->header.arglen = sizeof(*ascii) + bufSize;
 1536                 *resp = rp;
 1537                 break;
 1538             }
 1539 
 1540         case NGM_ASCII2BINARY:
 1541             {
 1542                 int bufSize = 2000;     /* XXX hard coded constant */
 1543                 const struct ng_cmdlist *c;
 1544                 const struct ng_parse_type *argstype;
 1545                 struct ng_mesg *rp, *ascii, *binary;
 1546                 int off = 0;
 1547 
 1548                 /* Data area must contain at least a struct ng_mesg + '\0' */
 1549                 ascii = (struct ng_mesg *)msg->data;
 1550                 if (msg->header.arglen < sizeof(*ascii) + 1
 1551                     || ascii->header.arglen < 1
 1552                     || msg->header.arglen
 1553                       < sizeof(*ascii) + ascii->header.arglen) {
 1554                         error = EINVAL;
 1555                         break;
 1556                 }
 1557                 ascii->data[ascii->header.arglen - 1] = '\0';
 1558 
 1559                 /* Get a response message with lots of room */
 1560                 NG_MKRESPONSE(rp, msg, sizeof(*binary) + bufSize, M_NOWAIT);
 1561                 if (rp == NULL) {
 1562                         error = ENOMEM;
 1563                         break;
 1564                 }
 1565                 binary = (struct ng_mesg *)rp->data;
 1566 
 1567                 /* Copy ASCII message header to response message payload */
 1568                 bcopy(ascii, binary, sizeof(*ascii));
 1569 
 1570                 /* Find command by matching ASCII command string */
 1571                 for (c = here->type->cmdlist;
 1572                     c != NULL && c->name != NULL; c++) {
 1573                         if (strcmp(ascii->header.cmdstr, c->name) == 0)
 1574                                 break;
 1575                 }
 1576                 if (c == NULL || c->name == NULL) {
 1577                         for (c = ng_generic_cmds; c->name != NULL; c++) {
 1578                                 if (strcmp(ascii->header.cmdstr, c->name) == 0)
 1579                                         break;
 1580                         }
 1581                         if (c->name == NULL) {
 1582                                 FREE(rp, M_NETGRAPH);
 1583                                 error = ENOSYS;
 1584                                 break;
 1585                         }
 1586                 }
 1587 
 1588                 /* Convert command name to binary */
 1589                 binary->header.cmd = c->cmd;
 1590                 binary->header.typecookie = c->cookie;
 1591 
 1592                 /* Convert command arguments to binary */
 1593                 argstype = (binary->header.flags & NGF_RESP) ?
 1594                     c->respType : c->mesgType;
 1595                 if (argstype == NULL)
 1596                         bufSize = 0;
 1597                 else {
 1598                         if ((error = ng_parse(argstype, ascii->data,
 1599                             &off, (u_char *)binary->data, &bufSize)) != 0) {
 1600                                 FREE(rp, M_NETGRAPH);
 1601                                 break;
 1602                         }
 1603                 }
 1604 
 1605                 /* Return the result */
 1606                 binary->header.arglen = bufSize;
 1607                 rp->header.arglen = sizeof(*binary) + bufSize;
 1608                 *resp = rp;
 1609                 break;
 1610             }
 1611 
 1612         case NGM_TEXT_CONFIG:
 1613         case NGM_TEXT_STATUS:
 1614                 /*
 1615                  * This one is tricky as it passes the command down to the
 1616                  * actual node, even though it is a generic type command.
 1617                  * This means we must assume that the msg is already freed
 1618                  * when control passes back to us.
 1619                  */
 1620                 if (resp == NULL) {
 1621                         error = EINVAL;
 1622                         break;
 1623                 }
 1624                 if (here->type->rcvmsg != NULL)
 1625                         return((*here->type->rcvmsg)(here, msg, retaddr, resp));
 1626                 /* Fall through if rcvmsg not supported */
 1627         default:
 1628                 TRAP_ERROR;
 1629                 error = EINVAL;
 1630         }
 1631         FREE(msg, M_NETGRAPH);
 1632         return (error);
 1633 }
 1634 
 1635 /*
 1636  * Send a data packet to a node. If the recipient has no
 1637  * 'receive data' method, then silently discard the packet.
 1638  */
 1639 int 
 1640 ng_send_data(hook_p hook, struct mbuf *m, meta_p meta)
 1641 {
 1642         int (*rcvdata)(hook_p, struct mbuf *, meta_p);
 1643         int error;
 1644 
 1645         CHECK_DATA_MBUF(m);
 1646         if (hook && (hook->flags & HK_INVALID) == 0) {
 1647                 rcvdata = hook->peer->node->type->rcvdata;
 1648                 if (rcvdata != NULL)
 1649                         error = (*rcvdata)(hook->peer, m, meta);
 1650                 else {
 1651                         error = 0;
 1652                         NG_FREE_DATA(m, meta);
 1653                 }
 1654         } else {
 1655                 TRAP_ERROR;
 1656                 error = ENOTCONN;
 1657                 NG_FREE_DATA(m, meta);
 1658         }
 1659         return (error);
 1660 }
 1661 
 1662 /*
 1663  * Send a queued data packet to a node. If the recipient has no
 1664  * 'receive queued data' method, then try the 'receive data' method above.
 1665  */
 1666 int 
 1667 ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta)
 1668 {
 1669         int (*rcvdataq)(hook_p, struct mbuf *, meta_p);
 1670         int error;
 1671 
 1672         CHECK_DATA_MBUF(m);
 1673         if (hook && (hook->flags & HK_INVALID) == 0) {
 1674                 rcvdataq = hook->peer->node->type->rcvdataq;
 1675                 if (rcvdataq != NULL)
 1676                         error = (*rcvdataq)(hook->peer, m, meta);
 1677                 else {
 1678                         error = ng_send_data(hook, m, meta);
 1679                 }
 1680         } else {
 1681                 TRAP_ERROR;
 1682                 error = ENOTCONN;
 1683                 NG_FREE_DATA(m, meta);
 1684         }
 1685         return (error);
 1686 }
 1687 
 1688 /*
 1689  * Copy a 'meta'.
 1690  *
 1691  * Returns new meta, or NULL if original meta is NULL or ENOMEM.
 1692  */
 1693 meta_p
 1694 ng_copy_meta(meta_p meta)
 1695 {
 1696         meta_p meta2;
 1697 
 1698         if (meta == NULL)
 1699                 return (NULL);
 1700         MALLOC(meta2, meta_p, meta->used_len, M_NETGRAPH, M_NOWAIT);
 1701         if (meta2 == NULL)
 1702                 return (NULL);
 1703         meta2->allocated_len = meta->used_len;
 1704         bcopy(meta, meta2, meta->used_len);
 1705         return (meta2);
 1706 }
 1707 
 1708 /************************************************************************
 1709                         Module routines
 1710 ************************************************************************/
 1711 
 1712 /*
 1713  * Handle the loading/unloading of a netgraph node type module
 1714  */
 1715 int
 1716 ng_mod_event(module_t mod, int event, void *data)
 1717 {
 1718         struct ng_type *const type = data;
 1719         int s, error = 0;
 1720 
 1721         switch (event) {
 1722         case MOD_LOAD:
 1723 
 1724                 /* Register new netgraph node type */
 1725                 s = splnet();
 1726                 if ((error = ng_newtype(type)) != 0) {
 1727                         splx(s);
 1728                         break;
 1729                 }
 1730 
 1731                 /* Call type specific code */
 1732                 if (type->mod_event != NULL)
 1733                         if ((error = (*type->mod_event)(mod, event, data))) {
 1734                                 type->refs--;   /* undo it */
 1735                                 LIST_REMOVE(type, types);
 1736                         }
 1737                 splx(s);
 1738                 break;
 1739 
 1740         case MOD_UNLOAD:
 1741                 s = splnet();
 1742                 if (type->refs > 1) {           /* make sure no nodes exist! */
 1743                         error = EBUSY;
 1744                 } else {
 1745                         if (type->refs == 0) {
 1746                                 /* failed load, nothing to undo */
 1747                                 splx(s);
 1748                                 break;
 1749                         }
 1750                         if (type->mod_event != NULL) {  /* check with type */
 1751                                 error = (*type->mod_event)(mod, event, data);
 1752                                 if (error != 0) {       /* type refuses.. */
 1753                                         splx(s);
 1754                                         break;
 1755                                 }
 1756                         }
 1757                         LIST_REMOVE(type, types);
 1758                 }
 1759                 splx(s);
 1760                 break;
 1761 
 1762         default:
 1763                 if (type->mod_event != NULL)
 1764                         error = (*type->mod_event)(mod, event, data);
 1765                 else
 1766                         error = 0;              /* XXX ? */
 1767                 break;
 1768         }
 1769         return (error);
 1770 }
 1771 
 1772 /*
 1773  * Handle loading and unloading for this code.
 1774  * The only thing we need to link into is the NETISR strucure.
 1775  */
 1776 static int
 1777 ngb_mod_event(module_t mod, int event, void *data)
 1778 {
 1779         int s, error = 0;
 1780 
 1781         switch (event) {
 1782         case MOD_LOAD:
 1783                 /* Register line discipline */
 1784                 s = splimp();
 1785                 error = register_netisr(NETISR_NETGRAPH, ngintr);
 1786                 splx(s);
 1787                 break;
 1788         case MOD_UNLOAD:
 1789                 /* You cant unload it because an interface may be using it.  */
 1790                 error = EBUSY;
 1791                 break;
 1792         default:
 1793                 error = EOPNOTSUPP;
 1794                 break;
 1795         }
 1796         return (error);
 1797 }
 1798 
 1799 static moduledata_t netgraph_mod = {
 1800         "netgraph",
 1801         ngb_mod_event,
 1802         (NULL)
 1803 };
 1804 DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
 1805 SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family");
 1806 SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,"");
 1807 SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, "");
 1808 
 1809 /************************************************************************
 1810                         Queueing routines
 1811 ************************************************************************/
 1812 
 1813 /* The structure for queueing across ISR switches */
 1814 struct ng_queue_entry {
 1815         u_long  flags;
 1816         struct ng_queue_entry *next;
 1817         union {
 1818                 struct {
 1819                         hook_p          da_hook;        /*  target hook */
 1820                         struct mbuf     *da_m;
 1821                         meta_p          da_meta;
 1822                 } data;
 1823                 struct {
 1824                         struct ng_mesg  *msg_msg;
 1825                         node_p          msg_node;
 1826                         void            *msg_retaddr;
 1827                 } msg;
 1828         } body;
 1829 };
 1830 #define NGQF_DATA       0x01            /* the queue element is data */
 1831 #define NGQF_MESG       0x02            /* the queue element is a message */
 1832 
 1833 static struct ng_queue_entry   *ngqbase;        /* items to be unqueued */
 1834 static struct ng_queue_entry   *ngqlast;        /* last item queued */
 1835 static const int                ngqroom = 256;  /* max items to queue */
 1836 static int                      ngqsize;        /* number of items in queue */
 1837 
 1838 static struct ng_queue_entry   *ngqfree;        /* free ones */
 1839 static const int                ngqfreemax = 256;/* cache at most this many */
 1840 static int                      ngqfreesize;    /* number of cached entries */
 1841 
 1842 /*
 1843  * Get a queue entry
 1844  */
 1845 static struct ng_queue_entry *
 1846 ng_getqblk(void)
 1847 {
 1848         register struct ng_queue_entry *q;
 1849         int s;
 1850 
 1851         /* Could be guarding against tty ints or whatever */
 1852         s = splhigh();
 1853 
 1854         /* Try get a cached queue block, or else allocate a new one */
 1855         if ((q = ngqfree) == NULL) {
 1856                 splx(s);
 1857                 if (ngqsize < ngqroom) {        /* don't worry about races */
 1858                         MALLOC(q, struct ng_queue_entry *,
 1859                             sizeof(*q), M_NETGRAPH, M_NOWAIT);
 1860                 }
 1861         } else {
 1862                 ngqfree = q->next;
 1863                 ngqfreesize--;
 1864                 splx(s);
 1865         }
 1866         return (q);
 1867 }
 1868 
 1869 /*
 1870  * Release a queue entry
 1871  */
 1872 #define RETURN_QBLK(q)                                                  \
 1873 do {                                                                    \
 1874         int s;                                                          \
 1875         if (ngqfreesize < ngqfreemax) { /* don't worry about races */   \
 1876                 s = splhigh();                                          \
 1877                 (q)->next = ngqfree;                                    \
 1878                 ngqfree = (q);                                          \
 1879                 ngqfreesize++;                                          \
 1880                 splx(s);                                                \
 1881         } else {                                                        \
 1882                 FREE((q), M_NETGRAPH);                                  \
 1883         }                                                               \
 1884 } while (0)
 1885 
 1886 /*
 1887  * Running at a raised (but we don't know which) processor priority level,
 1888  * put the data onto a queue to be picked up by another PPL (probably splnet)
 1889  */
 1890 int
 1891 ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta)
 1892 {
 1893         struct ng_queue_entry *q;
 1894         int s;
 1895 
 1896         if (hook == NULL) {
 1897                 NG_FREE_DATA(m, meta);
 1898                 return (0);
 1899         }
 1900         if ((q = ng_getqblk()) == NULL) {
 1901                 NG_FREE_DATA(m, meta);
 1902                 return (ENOBUFS);
 1903         }
 1904 
 1905         /* Fill out the contents */
 1906         q->flags = NGQF_DATA;
 1907         q->next = NULL;
 1908         q->body.data.da_hook = hook;
 1909         q->body.data.da_m = m;
 1910         q->body.data.da_meta = meta;
 1911         s = splhigh();          /* protect refs and queue */
 1912         hook->refs++;           /* don't let it go away while on the queue */
 1913 
 1914         /* Put it on the queue */
 1915         if (ngqbase) {
 1916                 ngqlast->next = q;
 1917         } else {
 1918                 ngqbase = q;
 1919         }
 1920         ngqlast = q;
 1921         ngqsize++;
 1922         splx(s);
 1923 
 1924         /* Schedule software interrupt to handle it later */
 1925         schednetisr(NETISR_NETGRAPH);
 1926         return (0);
 1927 }
 1928 
 1929 /*
 1930  * Running at a raised (but we don't know which) processor priority level,
 1931  * put the msg onto a queue to be picked up by another PPL (probably splnet)
 1932  */
 1933 int
 1934 ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address)
 1935 {
 1936         register struct ng_queue_entry *q;
 1937         int     s;
 1938         node_p  dest = NULL;
 1939         char   *retaddr = NULL;
 1940         int     error;
 1941 
 1942         /* Find the target node. */
 1943         error = ng_path2node(here, address, &dest, &retaddr);
 1944         if (error) {
 1945                 FREE(msg, M_NETGRAPH);
 1946                 return (error);
 1947         }
 1948         if ((q = ng_getqblk()) == NULL) {
 1949                 FREE(msg, M_NETGRAPH);
 1950                 if (retaddr)
 1951                         FREE(retaddr, M_NETGRAPH);
 1952                 return (ENOBUFS);
 1953         }
 1954 
 1955         /* Fill out the contents */
 1956         q->flags = NGQF_MESG;
 1957         q->next = NULL;
 1958         q->body.msg.msg_node = dest;
 1959         q->body.msg.msg_msg = msg;
 1960         q->body.msg.msg_retaddr = retaddr;
 1961         s = splhigh();          /* protect refs and queue */
 1962         dest->refs++;           /* don't let it go away while on the queue */
 1963 
 1964         /* Put it on the queue */
 1965         if (ngqbase) {
 1966                 ngqlast->next = q;
 1967         } else {
 1968                 ngqbase = q;
 1969         }
 1970         ngqlast = q;
 1971         ngqsize++;
 1972         splx(s);
 1973 
 1974         /* Schedule software interrupt to handle it later */
 1975         schednetisr(NETISR_NETGRAPH);
 1976         return (0);
 1977 }
 1978 
 1979 /*
 1980  * Pick an item off the queue, process it, and dispose of the queue entry.
 1981  * Should be running at splnet.
 1982  */
 1983 static void
 1984 ngintr(void)
 1985 {
 1986         hook_p  hook;
 1987         struct ng_queue_entry *ngq;
 1988         struct mbuf *m;
 1989         meta_p  meta;
 1990         void   *retaddr;
 1991         struct ng_mesg *msg;
 1992         node_p  node;
 1993         int     error = 0;
 1994         int     s;
 1995 
 1996         while (1) {
 1997                 s = splhigh();
 1998                 if ((ngq = ngqbase)) {
 1999                         ngqbase = ngq->next;
 2000                         ngqsize--;
 2001                 }
 2002                 splx(s);
 2003                 if (ngq == NULL)
 2004                         return;
 2005                 switch (ngq->flags) {
 2006                 case NGQF_DATA:
 2007                         hook = ngq->body.data.da_hook;
 2008                         m = ngq->body.data.da_m;
 2009                         meta = ngq->body.data.da_meta;
 2010                         RETURN_QBLK(ngq);
 2011                         NG_SEND_DATAQ(error, hook, m, meta);
 2012                         ng_unref_hook(hook);
 2013                         break;
 2014                 case NGQF_MESG:
 2015                         node = ngq->body.msg.msg_node;
 2016                         msg = ngq->body.msg.msg_msg;
 2017                         retaddr = ngq->body.msg.msg_retaddr;
 2018                         RETURN_QBLK(ngq);
 2019                         if (node->flags & NG_INVALID) {
 2020                                 FREE(msg, M_NETGRAPH);
 2021                         } else {
 2022                                 CALL_MSG_HANDLER(error, node, msg,
 2023                                                  retaddr, NULL);
 2024                         }
 2025                         ng_unref(node);
 2026                         if (retaddr)
 2027                                 FREE(retaddr, M_NETGRAPH);
 2028                         break;
 2029                 default:
 2030                         RETURN_QBLK(ngq);
 2031                 }
 2032         }
 2033 }
 2034 
 2035 

Cache object: eebaa91575c260e6a2d0c2fee26c0802


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