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  * ng_base.c
    3  *
    4  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    5  * All rights reserved.
    6  *
    7  * Subject to the following obligations and disclaimer of warranty, use and
    8  * redistribution of this software, in source or object code forms, with or
    9  * without modifications are expressly permitted by Whistle Communications;
   10  * provided, however, that:
   11  * 1. Any and all reproductions of the source or object code must include the
   12  *    copyright notice above and the following disclaimer of warranties; and
   13  * 2. No rights are granted, in any manner or form, to use Whistle
   14  *    Communications, Inc. trademarks, including the mark "WHISTLE
   15  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   16  *    such appears in the above copyright notice or in the software.
   17  *
   18  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   19  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   20  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   21  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   23  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   24  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   25  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   26  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   27  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   28  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   29  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   30  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   33  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   34  * OF SUCH DAMAGE.
   35  *
   36  * Authors: Julian Elischer <julian@freebsd.org>
   37  *          Archie Cobbs <archie@freebsd.org>
   38  *
   39  * $FreeBSD: releng/5.3/sys/netgraph/ng_base.c 136588 2004-10-16 08:43:07Z cvs2svn $
   40  * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $
   41  */
   42 
   43 /*
   44  * This file implements the base netgraph code.
   45  */
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/errno.h>
   50 #include <sys/kdb.h>
   51 #include <sys/kernel.h>
   52 #include <sys/limits.h>
   53 #include <sys/malloc.h>
   54 #include <sys/syslog.h>
   55 #include <sys/sysctl.h>
   56 #include <sys/queue.h>
   57 #include <sys/mbuf.h>
   58 #include <sys/ctype.h>
   59 #include <sys/sysctl.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 MODULE_VERSION(netgraph, NG_ABI_VERSION);
   68 
   69 /* List of all active nodes */
   70 static LIST_HEAD(, ng_node) ng_nodelist;
   71 static struct mtx       ng_nodelist_mtx;
   72 
   73 /* Mutex that protects the free queue item list */
   74 static struct mtx       ngq_mtx;
   75 
   76 #ifdef  NETGRAPH_DEBUG
   77 
   78 static SLIST_HEAD(, ng_node) ng_allnodes;
   79 static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */
   80 static SLIST_HEAD(, ng_hook) ng_allhooks;
   81 static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */
   82 
   83 static void ng_dumpitems(void);
   84 static void ng_dumpnodes(void);
   85 static void ng_dumphooks(void);
   86 
   87 #endif  /* NETGRAPH_DEBUG */
   88 /*
   89  * DEAD versions of the structures. 
   90  * In order to avoid races, it is sometimes neccesary to point
   91  * at SOMETHING even though theoretically, the current entity is 
   92  * INVALID. Use these to avoid these races.
   93  */
   94 struct ng_type ng_deadtype = {
   95         NG_ABI_VERSION,
   96         "dead",
   97         NULL,   /* modevent */
   98         NULL,   /* constructor */
   99         NULL,   /* rcvmsg */
  100         NULL,   /* shutdown */
  101         NULL,   /* newhook */
  102         NULL,   /* findhook */
  103         NULL,   /* connect */
  104         NULL,   /* rcvdata */
  105         NULL,   /* disconnect */
  106         NULL,   /* cmdlist */
  107 };
  108 
  109 struct ng_node ng_deadnode = {
  110         "dead",
  111         &ng_deadtype,   
  112         NGF_INVALID,
  113         1,      /* refs */
  114         0,      /* numhooks */
  115         NULL,   /* private */
  116         0,      /* ID */
  117         LIST_HEAD_INITIALIZER(ng_deadnode.hooks),
  118         {},     /* all_nodes list entry */
  119         {},     /* id hashtable list entry */
  120         {},     /* workqueue entry */
  121         {       0,
  122                 {}, /* should never use! (should hang) */
  123                 NULL,
  124                 &ng_deadnode.nd_input_queue.queue,
  125                 &ng_deadnode
  126         },
  127 #ifdef  NETGRAPH_DEBUG
  128         ND_MAGIC,
  129         __FILE__,
  130         __LINE__,
  131         {NULL}
  132 #endif  /* NETGRAPH_DEBUG */
  133 };
  134 
  135 struct ng_hook ng_deadhook = {
  136         "dead",
  137         NULL,           /* private */
  138         HK_INVALID | HK_DEAD,
  139         1,              /* refs always >= 1 */
  140         &ng_deadhook,   /* Peer is self */
  141         &ng_deadnode,   /* attached to deadnode */
  142         {},             /* hooks list */
  143         NULL,           /* override rcvmsg() */
  144         NULL,           /* override rcvdata() */
  145 #ifdef  NETGRAPH_DEBUG
  146         HK_MAGIC,
  147         __FILE__,
  148         __LINE__,
  149         {NULL}
  150 #endif  /* NETGRAPH_DEBUG */
  151 };
  152 
  153 /*
  154  * END DEAD STRUCTURES
  155  */
  156 /* List nodes with unallocated work */
  157 static TAILQ_HEAD(, ng_node) ng_worklist = TAILQ_HEAD_INITIALIZER(ng_worklist);
  158 static struct mtx       ng_worklist_mtx;   /* MUST LOCK NODE FIRST */
  159 
  160 /* List of installed types */
  161 static LIST_HEAD(, ng_type) ng_typelist;
  162 static struct mtx       ng_typelist_mtx;
  163 
  164 /* Hash related definitions */
  165 /* XXX Don't need to initialise them because it's a LIST */
  166 #define NG_ID_HASH_SIZE 32 /* most systems wont need even this many */
  167 static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE];
  168 static struct mtx       ng_idhash_mtx;
  169 /* Method to find a node.. used twice so do it here */
  170 #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE))
  171 #define NG_IDHASH_FIND(ID, node)                                        \
  172         do {                                                            \
  173                 mtx_assert(&ng_idhash_mtx, MA_OWNED);                   \
  174                 LIST_FOREACH(node, &ng_ID_hash[NG_IDHASH_FN(ID)],       \
  175                                                 nd_idnodes) {           \
  176                         if (NG_NODE_IS_VALID(node)                      \
  177                         && (NG_NODE_ID(node) == ID)) {                  \
  178                                 break;                                  \
  179                         }                                               \
  180                 }                                                       \
  181         } while (0)
  182 
  183 
  184 /* Internal functions */
  185 static int      ng_add_hook(node_p node, const char *name, hook_p * hookp);
  186 static int      ng_generic_msg(node_p here, item_p item, hook_p lasthook);
  187 static ng_ID_t  ng_decodeidname(const char *name);
  188 static int      ngb_mod_event(module_t mod, int event, void *data);
  189 static void     ng_worklist_remove(node_p node);
  190 static void     ngintr(void);
  191 static int      ng_apply_item(node_p node, item_p item);
  192 static void     ng_flush_input_queue(struct ng_queue * ngq);
  193 static void     ng_setisr(node_p node);
  194 static node_p   ng_ID2noderef(ng_ID_t ID);
  195 static int      ng_con_nodes(node_p node, const char *name, node_p node2,
  196                                                         const char *name2);
  197 static void     ng_con_part2(node_p node, hook_p hook, void *arg1, int arg2);
  198 static void     ng_con_part3(node_p node, hook_p hook, void *arg1, int arg2);
  199 static int      ng_mkpeer(node_p node, const char *name,
  200                                                 const char *name2, char *type);
  201 
  202 /* imported , these used to be externally visible, some may go back */
  203 void    ng_destroy_hook(hook_p hook);
  204 node_p  ng_name2noderef(node_p node, const char *name);
  205 int     ng_path2noderef(node_p here, const char *path,
  206         node_p *dest, hook_p *lasthook);
  207 int     ng_make_node(const char *type, node_p *nodepp);
  208 int     ng_path_parse(char *addr, char **node, char **path, char **hook);
  209 void    ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3);
  210 void    ng_unname(node_p node);
  211 
  212 
  213 /* Our own netgraph malloc type */
  214 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
  215 MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures");
  216 MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures");
  217 MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures");
  218 MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage");
  219 
  220 /* Should not be visible outside this file */
  221 
  222 #define _NG_ALLOC_HOOK(hook) \
  223         MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO)
  224 #define _NG_ALLOC_NODE(node) \
  225         MALLOC(node, node_p, sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO)
  226 
  227 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/
  228 /*
  229  * In debug mode:
  230  * In an attempt to help track reference count screwups
  231  * we do not free objects back to the malloc system, but keep them
  232  * in a local cache where we can examine them and keep information safely
  233  * after they have been freed.
  234  * We use this scheme for nodes and hooks, and to some extent for items.
  235  */
  236 static __inline hook_p
  237 ng_alloc_hook(void)
  238 {
  239         hook_p hook;
  240         SLIST_ENTRY(ng_hook) temp;
  241         mtx_lock(&ng_nodelist_mtx);
  242         hook = LIST_FIRST(&ng_freehooks);
  243         if (hook) {
  244                 LIST_REMOVE(hook, hk_hooks);
  245                 bcopy(&hook->hk_all, &temp, sizeof(temp));
  246                 bzero(hook, sizeof(struct ng_hook));
  247                 bcopy(&temp, &hook->hk_all, sizeof(temp));
  248                 mtx_unlock(&ng_nodelist_mtx);
  249                 hook->hk_magic = HK_MAGIC;
  250         } else {
  251                 mtx_unlock(&ng_nodelist_mtx);
  252                 _NG_ALLOC_HOOK(hook);
  253                 if (hook) {
  254                         hook->hk_magic = HK_MAGIC;
  255                         mtx_lock(&ng_nodelist_mtx);
  256                         SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all);
  257                         mtx_unlock(&ng_nodelist_mtx);
  258                 }
  259         }
  260         return (hook);
  261 }
  262 
  263 static __inline node_p
  264 ng_alloc_node(void)
  265 {
  266         node_p node;
  267         SLIST_ENTRY(ng_node) temp;
  268         mtx_lock(&ng_nodelist_mtx);
  269         node = LIST_FIRST(&ng_freenodes);
  270         if (node) {
  271                 LIST_REMOVE(node, nd_nodes);
  272                 bcopy(&node->nd_all, &temp, sizeof(temp));
  273                 bzero(node, sizeof(struct ng_node));
  274                 bcopy(&temp, &node->nd_all, sizeof(temp));
  275                 mtx_unlock(&ng_nodelist_mtx);
  276                 node->nd_magic = ND_MAGIC;
  277         } else {
  278                 mtx_unlock(&ng_nodelist_mtx);
  279                 _NG_ALLOC_NODE(node);
  280                 if (node) {
  281                         node->nd_magic = ND_MAGIC;
  282                         mtx_lock(&ng_nodelist_mtx);
  283                         SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all);
  284                         mtx_unlock(&ng_nodelist_mtx);
  285                 }
  286         }
  287         return (node);
  288 }
  289 
  290 #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0)
  291 #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0)
  292 
  293 
  294 #define NG_FREE_HOOK(hook)                                              \
  295         do {                                                            \
  296                 mtx_lock(&ng_nodelist_mtx);                     \
  297                 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks);        \
  298                 hook->hk_magic = 0;                                     \
  299                 mtx_unlock(&ng_nodelist_mtx);                   \
  300         } while (0)
  301 
  302 #define NG_FREE_NODE(node)                                              \
  303         do {                                                            \
  304                 mtx_lock(&ng_nodelist_mtx);                     \
  305                 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes);        \
  306                 node->nd_magic = 0;                                     \
  307                 mtx_unlock(&ng_nodelist_mtx);                   \
  308         } while (0)
  309 
  310 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
  311 
  312 #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook)
  313 #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node)
  314 
  315 #define NG_FREE_HOOK(hook) do { FREE((hook), M_NETGRAPH_HOOK); } while (0)
  316 #define NG_FREE_NODE(node) do { FREE((node), M_NETGRAPH_NODE); } while (0)
  317 
  318 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
  319 
  320 /* Warning: Generally use NG_FREE_ITEM() instead */
  321 #define NG_FREE_ITEM_REAL(item) do { FREE((item), M_NETGRAPH_ITEM); } while (0)
  322 
  323 
  324 /* Set this to kdb_enter("X") to catch all errors as they occur */
  325 #ifndef TRAP_ERROR
  326 #define TRAP_ERROR()
  327 #endif
  328 
  329 static  ng_ID_t nextID = 1;
  330 
  331 #ifdef INVARIANTS
  332 #define CHECK_DATA_MBUF(m)      do {                                    \
  333                 struct mbuf *n;                                         \
  334                 int total;                                              \
  335                                                                         \
  336                 M_ASSERTPKTHDR(m);                                      \
  337                 for (total = 0, n = (m); n != NULL; n = n->m_next)      \
  338                         total += n->m_len;                              \
  339                 if ((m)->m_pkthdr.len != total) {                       \
  340                         panic("%s: %d != %d",                           \
  341                             __func__, (m)->m_pkthdr.len, total);        \
  342                 }                                                       \
  343         } while (0)
  344 #else
  345 #define CHECK_DATA_MBUF(m)
  346 #endif
  347 
  348 
  349 /************************************************************************
  350         Parse type definitions for generic messages
  351 ************************************************************************/
  352 
  353 /* Handy structure parse type defining macro */
  354 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args)                          \
  355 static const struct ng_parse_struct_field                               \
  356         ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args;  \
  357 static const struct ng_parse_type ng_generic_ ## lo ## _type = {        \
  358         &ng_parse_struct_type,                                          \
  359         &ng_ ## lo ## _type_fields                                      \
  360 }
  361 
  362 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
  363 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
  364 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
  365 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
  366 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
  367 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
  368 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
  369 
  370 /* Get length of an array when the length is stored as a 32 bit
  371    value immediately preceding the array -- as with struct namelist
  372    and struct typelist. */
  373 static int
  374 ng_generic_list_getLength(const struct ng_parse_type *type,
  375         const u_char *start, const u_char *buf)
  376 {
  377         return *((const u_int32_t *)(buf - 4));
  378 }
  379 
  380 /* Get length of the array of struct linkinfo inside a struct hooklist */
  381 static int
  382 ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
  383         const u_char *start, const u_char *buf)
  384 {
  385         const struct hooklist *hl = (const struct hooklist *)start;
  386 
  387         return hl->nodeinfo.hooks;
  388 }
  389 
  390 /* Array type for a variable length array of struct namelist */
  391 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
  392         &ng_generic_nodeinfo_type,
  393         &ng_generic_list_getLength
  394 };
  395 static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
  396         &ng_parse_array_type,
  397         &ng_nodeinfoarray_type_info
  398 };
  399 
  400 /* Array type for a variable length array of struct typelist */
  401 static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
  402         &ng_generic_typeinfo_type,
  403         &ng_generic_list_getLength
  404 };
  405 static const struct ng_parse_type ng_generic_typeinfoarray_type = {
  406         &ng_parse_array_type,
  407         &ng_typeinfoarray_type_info
  408 };
  409 
  410 /* Array type for array of struct linkinfo in struct hooklist */
  411 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
  412         &ng_generic_linkinfo_type,
  413         &ng_generic_linkinfo_getLength
  414 };
  415 static const struct ng_parse_type ng_generic_linkinfo_array_type = {
  416         &ng_parse_array_type,
  417         &ng_generic_linkinfo_array_type_info
  418 };
  419 
  420 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
  421 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
  422         (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
  423 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
  424         (&ng_generic_nodeinfoarray_type));
  425 
  426 /* List of commands and how to convert arguments to/from ASCII */
  427 static const struct ng_cmdlist ng_generic_cmds[] = {
  428         {
  429           NGM_GENERIC_COOKIE,
  430           NGM_SHUTDOWN,
  431           "shutdown",
  432           NULL,
  433           NULL
  434         },
  435         {
  436           NGM_GENERIC_COOKIE,
  437           NGM_MKPEER,
  438           "mkpeer",
  439           &ng_generic_mkpeer_type,
  440           NULL
  441         },
  442         {
  443           NGM_GENERIC_COOKIE,
  444           NGM_CONNECT,
  445           "connect",
  446           &ng_generic_connect_type,
  447           NULL
  448         },
  449         {
  450           NGM_GENERIC_COOKIE,
  451           NGM_NAME,
  452           "name",
  453           &ng_generic_name_type,
  454           NULL
  455         },
  456         {
  457           NGM_GENERIC_COOKIE,
  458           NGM_RMHOOK,
  459           "rmhook",
  460           &ng_generic_rmhook_type,
  461           NULL
  462         },
  463         {
  464           NGM_GENERIC_COOKIE,
  465           NGM_NODEINFO,
  466           "nodeinfo",
  467           NULL,
  468           &ng_generic_nodeinfo_type
  469         },
  470         {
  471           NGM_GENERIC_COOKIE,
  472           NGM_LISTHOOKS,
  473           "listhooks",
  474           NULL,
  475           &ng_generic_hooklist_type
  476         },
  477         {
  478           NGM_GENERIC_COOKIE,
  479           NGM_LISTNAMES,
  480           "listnames",
  481           NULL,
  482           &ng_generic_listnodes_type    /* same as NGM_LISTNODES */
  483         },
  484         {
  485           NGM_GENERIC_COOKIE,
  486           NGM_LISTNODES,
  487           "listnodes",
  488           NULL,
  489           &ng_generic_listnodes_type
  490         },
  491         {
  492           NGM_GENERIC_COOKIE,
  493           NGM_LISTTYPES,
  494           "listtypes",
  495           NULL,
  496           &ng_generic_typeinfo_type
  497         },
  498         {
  499           NGM_GENERIC_COOKIE,
  500           NGM_TEXT_CONFIG,
  501           "textconfig",
  502           NULL,
  503           &ng_parse_string_type
  504         },
  505         {
  506           NGM_GENERIC_COOKIE,
  507           NGM_TEXT_STATUS,
  508           "textstatus",
  509           NULL,
  510           &ng_parse_string_type
  511         },
  512         {
  513           NGM_GENERIC_COOKIE,
  514           NGM_ASCII2BINARY,
  515           "ascii2binary",
  516           &ng_parse_ng_mesg_type,
  517           &ng_parse_ng_mesg_type
  518         },
  519         {
  520           NGM_GENERIC_COOKIE,
  521           NGM_BINARY2ASCII,
  522           "binary2ascii",
  523           &ng_parse_ng_mesg_type,
  524           &ng_parse_ng_mesg_type
  525         },
  526         { 0 }
  527 };
  528 
  529 /************************************************************************
  530                         Node routines
  531 ************************************************************************/
  532 
  533 /*
  534  * Instantiate a node of the requested type
  535  */
  536 int
  537 ng_make_node(const char *typename, node_p *nodepp)
  538 {
  539         struct ng_type *type;
  540         int     error;
  541 
  542         /* Check that the type makes sense */
  543         if (typename == NULL) {
  544                 TRAP_ERROR();
  545                 return (EINVAL);
  546         }
  547 
  548         /* Locate the node type. If we fail we return. Do not try to load
  549          * module.
  550          */
  551         if ((type = ng_findtype(typename)) == NULL)
  552                 return (ENXIO);
  553 
  554         /*
  555          * If we have a constructor, then make the node and
  556          * call the constructor to do type specific initialisation.
  557          */
  558         if (type->constructor != NULL) {
  559                 if ((error = ng_make_node_common(type, nodepp)) == 0) {
  560                         if ((error = ((*type->constructor)(*nodepp)) != 0)) {
  561                                 NG_NODE_UNREF(*nodepp);
  562                         }
  563                 }
  564         } else {
  565                 /*
  566                  * Node has no constructor. We cannot ask for one
  567                  * to be made. It must be brought into existance by
  568                  * some external agency. The external agency should
  569                  * call ng_make_node_common() directly to get the
  570                  * netgraph part initialised.
  571                  */
  572                 TRAP_ERROR();
  573                 error = EINVAL;
  574         }
  575         return (error);
  576 }
  577 
  578 /*
  579  * Generic node creation. Called by node initialisation for externally
  580  * instantiated nodes (e.g. hardware, sockets, etc ).
  581  * The returned node has a reference count of 1.
  582  */
  583 int
  584 ng_make_node_common(struct ng_type *type, node_p *nodepp)
  585 {
  586         node_p node;
  587 
  588         /* Require the node type to have been already installed */
  589         if (ng_findtype(type->name) == NULL) {
  590                 TRAP_ERROR();
  591                 return (EINVAL);
  592         }
  593 
  594         /* Make a node and try attach it to the type */
  595         NG_ALLOC_NODE(node);
  596         if (node == NULL) {
  597                 TRAP_ERROR();
  598                 return (ENOMEM);
  599         }
  600         node->nd_type = type;
  601         NG_NODE_REF(node);                              /* note reference */
  602         type->refs++;
  603 
  604         mtx_init(&node->nd_input_queue.q_mtx, "ng_node", NULL, MTX_SPIN);
  605         node->nd_input_queue.queue = NULL;
  606         node->nd_input_queue.last = &node->nd_input_queue.queue;
  607         node->nd_input_queue.q_flags = 0;
  608         node->nd_input_queue.q_node = node;
  609 
  610         /* Initialize hook list for new node */
  611         LIST_INIT(&node->nd_hooks);
  612 
  613         /* Link us into the node linked list */
  614         mtx_lock(&ng_nodelist_mtx);
  615         LIST_INSERT_HEAD(&ng_nodelist, node, nd_nodes);
  616         mtx_unlock(&ng_nodelist_mtx);
  617 
  618 
  619         /* get an ID and put us in the hash chain */
  620         mtx_lock(&ng_idhash_mtx);
  621         for (;;) { /* wrap protection, even if silly */
  622                 node_p node2 = NULL;
  623                 node->nd_ID = nextID++; /* 137/second for 1 year before wrap */
  624 
  625                 /* Is there a problem with the new number? */
  626                 NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */
  627                 if ((node->nd_ID != 0) && (node2 == NULL)) {
  628                         break;
  629                 }
  630         }
  631         LIST_INSERT_HEAD(&ng_ID_hash[NG_IDHASH_FN(node->nd_ID)],
  632                                                         node, nd_idnodes);
  633         mtx_unlock(&ng_idhash_mtx);
  634 
  635         /* Done */
  636         *nodepp = node;
  637         return (0);
  638 }
  639 
  640 /*
  641  * Forceably start the shutdown process on a node. Either call
  642  * it's shutdown method, or do the default shutdown if there is
  643  * no type-specific method.
  644  *
  645  * We can only be called form a shutdown message, so we know we have
  646  * a writer lock, and therefore exclusive access. It also means
  647  * that we should not be on the work queue, but we check anyhow.
  648  *
  649  * Persistent node types must have a type-specific method which
  650  * Allocates a new node in which case, this one is irretrievably going away,
  651  * or cleans up anything it needs, and just makes the node valid again,
  652  * in which case we allow the node to survive. 
  653  *
  654  * XXX We need to think of how to tell a persistant node that we
  655  * REALLY need to go away because the hardware has gone or we
  656  * are rebooting.... etc.
  657  */
  658 void
  659 ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3)
  660 {
  661         hook_p hook;
  662 
  663         /* Check if it's already shutting down */
  664         if ((node->nd_flags & NGF_CLOSING) != 0)
  665                 return;
  666 
  667         if (node == &ng_deadnode) {
  668                 printf ("shutdown called on deadnode\n");
  669                 return;
  670         }
  671 
  672         /* Add an extra reference so it doesn't go away during this */
  673         NG_NODE_REF(node);
  674 
  675         /*
  676          * Mark it invalid so any newcomers know not to try use it
  677          * Also add our own mark so we can't recurse
  678          * note that NGF_INVALID does not do this as it's also set during
  679          * creation
  680          */
  681         node->nd_flags |= NGF_INVALID|NGF_CLOSING;
  682 
  683         /* If node has its pre-shutdown method, then call it first*/
  684         if (node->nd_type && node->nd_type->close)
  685                 (*node->nd_type->close)(node);
  686 
  687         /* Notify all remaining connected nodes to disconnect */
  688         while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL)
  689                 ng_destroy_hook(hook);
  690 
  691         /*
  692          * Drain the input queue forceably.
  693          * it has no hooks so what's it going to do, bleed on someone?
  694          * Theoretically we came here from a queue entry that was added
  695          * Just before the queue was closed, so it should be empty anyway.
  696          * Also removes us from worklist if needed.
  697          */
  698         ng_flush_input_queue(&node->nd_input_queue);
  699 
  700         /* Ask the type if it has anything to do in this case */
  701         if (node->nd_type && node->nd_type->shutdown) {
  702                 (*node->nd_type->shutdown)(node);
  703                 if (NG_NODE_IS_VALID(node)) {
  704                         /*
  705                          * Well, blow me down if the node code hasn't declared
  706                          * that it doesn't want to die.
  707                          * Presumably it is a persistant node.
  708                          * If we REALLY want it to go away,
  709                          *  e.g. hardware going away,
  710                          * Our caller should set NGF_REALLY_DIE in nd_flags.
  711                          */ 
  712                         node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING);
  713                         NG_NODE_UNREF(node); /* Assume they still have theirs */
  714                         return;
  715                 }
  716         } else {                                /* do the default thing */
  717                 NG_NODE_UNREF(node);
  718         }
  719 
  720         ng_unname(node); /* basically a NOP these days */
  721 
  722         /*
  723          * Remove extra reference, possibly the last
  724          * Possible other holders of references may include
  725          * timeout callouts, but theoretically the node's supposed to
  726          * have cancelled them. Possibly hardware dependencies may
  727          * force a driver to 'linger' with a reference.
  728          */
  729         NG_NODE_UNREF(node);
  730 }
  731 
  732 #ifdef  NETGRAPH_DEBUG
  733 void
  734 ng_ref_node(node_p node)
  735 {
  736         _NG_NODE_REF(node);
  737 }
  738 #endif
  739 
  740 /*
  741  * Remove a reference to the node, possibly the last.
  742  * deadnode always acts as it it were the last.
  743  */
  744 int
  745 ng_unref_node(node_p node)
  746 {
  747         int     v;
  748 
  749         if (node == &ng_deadnode) {
  750                 return (0);
  751         }
  752 
  753         do {
  754                 v = node->nd_refs - 1;
  755         } while (! atomic_cmpset_int(&node->nd_refs, v + 1, v));
  756 
  757         if (v == 0) { /* we were the last */
  758 
  759                 mtx_lock(&ng_nodelist_mtx);
  760                 node->nd_type->refs--; /* XXX maybe should get types lock? */
  761                 LIST_REMOVE(node, nd_nodes);
  762                 mtx_unlock(&ng_nodelist_mtx);
  763 
  764                 mtx_lock(&ng_idhash_mtx);
  765                 LIST_REMOVE(node, nd_idnodes);
  766                 mtx_unlock(&ng_idhash_mtx);
  767 
  768                 mtx_destroy(&node->nd_input_queue.q_mtx);
  769                 NG_FREE_NODE(node);
  770         }
  771         return (v);
  772 }
  773 
  774 /************************************************************************
  775                         Node ID handling
  776 ************************************************************************/
  777 static node_p
  778 ng_ID2noderef(ng_ID_t ID)
  779 {
  780         node_p node;
  781         mtx_lock(&ng_idhash_mtx);
  782         NG_IDHASH_FIND(ID, node);
  783         if(node)
  784                 NG_NODE_REF(node);
  785         mtx_unlock(&ng_idhash_mtx);
  786         return(node);
  787 }
  788 
  789 ng_ID_t
  790 ng_node2ID(node_p node)
  791 {
  792         return (node ? NG_NODE_ID(node) : 0);
  793 }
  794 
  795 /************************************************************************
  796                         Node name handling
  797 ************************************************************************/
  798 
  799 /*
  800  * Assign a node a name. Once assigned, the name cannot be changed.
  801  */
  802 int
  803 ng_name_node(node_p node, const char *name)
  804 {
  805         int i;
  806         node_p node2;
  807 
  808         /* Check the name is valid */
  809         for (i = 0; i < NG_NODESIZ; i++) {
  810                 if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
  811                         break;
  812         }
  813         if (i == 0 || name[i] != '\0') {
  814                 TRAP_ERROR();
  815                 return (EINVAL);
  816         }
  817         if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
  818                 TRAP_ERROR();
  819                 return (EINVAL);
  820         }
  821 
  822         /* Check the name isn't already being used */
  823         if ((node2 = ng_name2noderef(node, name)) != NULL) {
  824                 NG_NODE_UNREF(node2);
  825                 TRAP_ERROR();
  826                 return (EADDRINUSE);
  827         }
  828 
  829         /* copy it */
  830         strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ);
  831 
  832         return (0);
  833 }
  834 
  835 /*
  836  * Find a node by absolute name. The name should NOT end with ':'
  837  * The name "." means "this node" and "[xxx]" means "the node
  838  * with ID (ie, at address) xxx".
  839  *
  840  * Returns the node if found, else NULL.
  841  * Eventually should add something faster than a sequential search.
  842  * Note it aquires a reference on the node so you can be sure it's still there.
  843  */
  844 node_p
  845 ng_name2noderef(node_p here, const char *name)
  846 {
  847         node_p node;
  848         ng_ID_t temp;
  849 
  850         /* "." means "this node" */
  851         if (strcmp(name, ".") == 0) {
  852                 NG_NODE_REF(here);
  853                 return(here);
  854         }
  855 
  856         /* Check for name-by-ID */
  857         if ((temp = ng_decodeidname(name)) != 0) {
  858                 return (ng_ID2noderef(temp));
  859         }
  860 
  861         /* Find node by name */
  862         mtx_lock(&ng_nodelist_mtx);
  863         LIST_FOREACH(node, &ng_nodelist, nd_nodes) {
  864                 if (NG_NODE_IS_VALID(node)
  865                 && NG_NODE_HAS_NAME(node)
  866                 && (strcmp(NG_NODE_NAME(node), name) == 0)) {
  867                         break;
  868                 }
  869         }
  870         if (node)
  871                 NG_NODE_REF(node);
  872         mtx_unlock(&ng_nodelist_mtx);
  873         return (node);
  874 }
  875 
  876 /*
  877  * Decode an ID name, eg. "[f03034de]". Returns 0 if the
  878  * string is not valid, otherwise returns the value.
  879  */
  880 static ng_ID_t
  881 ng_decodeidname(const char *name)
  882 {
  883         const int len = strlen(name);
  884         char *eptr;
  885         u_long val;
  886 
  887         /* Check for proper length, brackets, no leading junk */
  888         if ((len < 3)
  889         || (name[0] != '[')
  890         || (name[len - 1] != ']')
  891         || (!isxdigit(name[1]))) {
  892                 return ((ng_ID_t)0);
  893         }
  894 
  895         /* Decode number */
  896         val = strtoul(name + 1, &eptr, 16);
  897         if ((eptr - name != len - 1)
  898         || (val == ULONG_MAX)
  899         || (val == 0)) {
  900                 return ((ng_ID_t)0);
  901         }
  902         return (ng_ID_t)val;
  903 }
  904 
  905 /*
  906  * Remove a name from a node. This should only be called
  907  * when shutting down and removing the node.
  908  * IF we allow name changing this may be more resurected.
  909  */
  910 void
  911 ng_unname(node_p node)
  912 {
  913 }
  914 
  915 /************************************************************************
  916                         Hook routines
  917  Names are not optional. Hooks are always connected, except for a
  918  brief moment within these routines. On invalidation or during creation
  919  they are connected to the 'dead' hook.
  920 ************************************************************************/
  921 
  922 /*
  923  * Remove a hook reference
  924  */
  925 void
  926 ng_unref_hook(hook_p hook)
  927 {
  928         int     v;
  929 
  930         if (hook == &ng_deadhook) {
  931                 return;
  932         }
  933         do {
  934                 v = hook->hk_refs;
  935         } while (! atomic_cmpset_int(&hook->hk_refs, v, v - 1));
  936 
  937         if (v == 1) { /* we were the last */
  938                 if (_NG_HOOK_NODE(hook)) { /* it'll probably be ng_deadnode */
  939                         _NG_NODE_UNREF((_NG_HOOK_NODE(hook)));
  940                         hook->hk_node = NULL;
  941                 }
  942                 NG_FREE_HOOK(hook);
  943         }
  944 }
  945 
  946 /*
  947  * Add an unconnected hook to a node. Only used internally.
  948  * Assumes node is locked. (XXX not yet true )
  949  */
  950 static int
  951 ng_add_hook(node_p node, const char *name, hook_p *hookp)
  952 {
  953         hook_p hook;
  954         int error = 0;
  955 
  956         /* Check that the given name is good */
  957         if (name == NULL) {
  958                 TRAP_ERROR();
  959                 return (EINVAL);
  960         }
  961         if (ng_findhook(node, name) != NULL) {
  962                 TRAP_ERROR();
  963                 return (EEXIST);
  964         }
  965 
  966         /* Allocate the hook and link it up */
  967         NG_ALLOC_HOOK(hook);
  968         if (hook == NULL) {
  969                 TRAP_ERROR();
  970                 return (ENOMEM);
  971         }
  972         hook->hk_refs = 1;              /* add a reference for us to return */
  973         hook->hk_flags = HK_INVALID;
  974         hook->hk_peer = &ng_deadhook;   /* start off this way */
  975         hook->hk_node = node;
  976         NG_NODE_REF(node);              /* each hook counts as a reference */
  977 
  978         /* Set hook name */
  979         strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ);
  980 
  981         /*
  982          * Check if the node type code has something to say about it
  983          * If it fails, the unref of the hook will also unref the node.
  984          */
  985         if (node->nd_type->newhook != NULL) {
  986                 if ((error = (*node->nd_type->newhook)(node, hook, name))) {
  987                         NG_HOOK_UNREF(hook);    /* this frees the hook */
  988                         return (error);
  989                 }
  990         }
  991         /*
  992          * The 'type' agrees so far, so go ahead and link it in.
  993          * We'll ask again later when we actually connect the hooks.
  994          */
  995         LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks);
  996         node->nd_numhooks++;
  997         NG_HOOK_REF(hook);      /* one for the node */
  998 
  999         if (hookp)
 1000                 *hookp = hook;
 1001         return (0);
 1002 }
 1003 
 1004 /*
 1005  * Find a hook
 1006  *
 1007  * Node types may supply their own optimized routines for finding
 1008  * hooks.  If none is supplied, we just do a linear search.
 1009  * XXX Possibly we should add a reference to the hook?
 1010  */
 1011 hook_p
 1012 ng_findhook(node_p node, const char *name)
 1013 {
 1014         hook_p hook;
 1015 
 1016         if (node->nd_type->findhook != NULL)
 1017                 return (*node->nd_type->findhook)(node, name);
 1018         LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
 1019                 if (NG_HOOK_IS_VALID(hook)
 1020                 && (strcmp(NG_HOOK_NAME(hook), name) == 0))
 1021                         return (hook);
 1022         }
 1023         return (NULL);
 1024 }
 1025 
 1026 /*
 1027  * Destroy a hook
 1028  *
 1029  * As hooks are always attached, this really destroys two hooks.
 1030  * The one given, and the one attached to it. Disconnect the hooks
 1031  * from each other first. We reconnect the peer hook to the 'dead'
 1032  * hook so that it can still exist after we depart. We then
 1033  * send the peer its own destroy message. This ensures that we only
 1034  * interact with the peer's structures when it is locked processing that 
 1035  * message. We hold a reference to the peer hook so we are guaranteed that
 1036  * the peer hook and node are still going to exist until
 1037  * we are finished there as the hook holds a ref on the node.
 1038  * We run this same code again on the peer hook, but that time it is already 
 1039  * attached to the 'dead' hook. 
 1040  *
 1041  * This routine is called at all stages of hook creation 
 1042  * on error detection and must be able to handle any such stage.
 1043  */
 1044 void
 1045 ng_destroy_hook(hook_p hook)
 1046 {
 1047         hook_p peer = NG_HOOK_PEER(hook);
 1048         node_p node = NG_HOOK_NODE(hook);
 1049 
 1050         if (hook == &ng_deadhook) {     /* better safe than sorry */
 1051                 printf("ng_destroy_hook called on deadhook\n");
 1052                 return;
 1053         }
 1054         hook->hk_flags |= HK_INVALID;           /* as soon as possible */
 1055         if (peer && (peer != &ng_deadhook)) {
 1056                 /*
 1057                  * Set the peer to point to ng_deadhook
 1058                  * from this moment on we are effectively independent it.
 1059                  * send it an rmhook message of it's own.
 1060                  */
 1061                 peer->hk_peer = &ng_deadhook;   /* They no longer know us */
 1062                 hook->hk_peer = &ng_deadhook;   /* Nor us, them */
 1063                 if (NG_HOOK_NODE(peer) == &ng_deadnode) {
 1064                         /* 
 1065                          * If it's already divorced from a node,
 1066                          * just free it.
 1067                          */
 1068                         /* nothing */
 1069                 } else {
 1070                         ng_rmhook_self(peer);   /* Send it a surprise */
 1071                 }
 1072                 NG_HOOK_UNREF(peer);            /* account for peer link */
 1073                 NG_HOOK_UNREF(hook);            /* account for peer link */
 1074         }
 1075 
 1076         /*
 1077          * Remove the hook from the node's list to avoid possible recursion
 1078          * in case the disconnection results in node shutdown.
 1079          */
 1080         if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */
 1081                 return;
 1082         }
 1083         LIST_REMOVE(hook, hk_hooks);
 1084         node->nd_numhooks--;
 1085         if (node->nd_type->disconnect) {
 1086                 /*
 1087                  * The type handler may elect to destroy the node so don't
 1088                  * trust its existance after this point. (except 
 1089                  * that we still hold a reference on it. (which we
 1090                  * inherrited from the hook we are destroying)
 1091                  */
 1092                 (*node->nd_type->disconnect) (hook);
 1093         }
 1094 
 1095         /*
 1096          * Note that because we will point to ng_deadnode, the original node
 1097          * is not decremented automatically so we do that manually.
 1098          */
 1099         _NG_HOOK_NODE(hook) = &ng_deadnode;
 1100         NG_NODE_UNREF(node);    /* We no longer point to it so adjust count */
 1101         NG_HOOK_UNREF(hook);    /* Account for linkage (in list) to node */
 1102 }
 1103 
 1104 /*
 1105  * Take two hooks on a node and merge the connection so that the given node
 1106  * is effectively bypassed.
 1107  */
 1108 int
 1109 ng_bypass(hook_p hook1, hook_p hook2)
 1110 {
 1111         if (hook1->hk_node != hook2->hk_node) {
 1112                 TRAP_ERROR();
 1113                 return (EINVAL);
 1114         }
 1115         hook1->hk_peer->hk_peer = hook2->hk_peer;
 1116         hook2->hk_peer->hk_peer = hook1->hk_peer;
 1117 
 1118         hook1->hk_peer = &ng_deadhook;
 1119         hook2->hk_peer = &ng_deadhook;
 1120 
 1121         /* XXX If we ever cache methods on hooks update them as well */
 1122         ng_destroy_hook(hook1);
 1123         ng_destroy_hook(hook2);
 1124         return (0);
 1125 }
 1126 
 1127 /*
 1128  * Install a new netgraph type
 1129  */
 1130 int
 1131 ng_newtype(struct ng_type *tp)
 1132 {
 1133         const size_t namelen = strlen(tp->name);
 1134 
 1135         /* Check version and type name fields */
 1136         if ((tp->version != NG_ABI_VERSION)
 1137         || (namelen == 0)
 1138         || (namelen >= NG_TYPESIZ)) {
 1139                 TRAP_ERROR();
 1140                 if (tp->version != NG_ABI_VERSION) {
 1141                         printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n");
 1142                 }
 1143                 return (EINVAL);
 1144         }
 1145 
 1146         /* Check for name collision */
 1147         if (ng_findtype(tp->name) != NULL) {
 1148                 TRAP_ERROR();
 1149                 return (EEXIST);
 1150         }
 1151 
 1152 
 1153         /* Link in new type */
 1154         mtx_lock(&ng_typelist_mtx);
 1155         LIST_INSERT_HEAD(&ng_typelist, tp, types);
 1156         tp->refs = 1;   /* first ref is linked list */
 1157         mtx_unlock(&ng_typelist_mtx);
 1158         return (0);
 1159 }
 1160 
 1161 /*
 1162  * unlink a netgraph type
 1163  * If no examples exist
 1164  */
 1165 int
 1166 ng_rmtype(struct ng_type *tp)
 1167 {
 1168         /* Check for name collision */
 1169         if (tp->refs != 1) {
 1170                 TRAP_ERROR();
 1171                 return (EBUSY);
 1172         }
 1173 
 1174         /* Unlink type */
 1175         mtx_lock(&ng_typelist_mtx);
 1176         LIST_REMOVE(tp, types);
 1177         mtx_unlock(&ng_typelist_mtx);
 1178         return (0);
 1179 }
 1180 
 1181 /*
 1182  * Look for a type of the name given
 1183  */
 1184 struct ng_type *
 1185 ng_findtype(const char *typename)
 1186 {
 1187         struct ng_type *type;
 1188 
 1189         mtx_lock(&ng_typelist_mtx);
 1190         LIST_FOREACH(type, &ng_typelist, types) {
 1191                 if (strcmp(type->name, typename) == 0)
 1192                         break;
 1193         }
 1194         mtx_unlock(&ng_typelist_mtx);
 1195         return (type);
 1196 }
 1197 
 1198 /************************************************************************
 1199                         Composite routines
 1200 ************************************************************************/
 1201 /*
 1202  * Connect two nodes using the specified hooks, using queued functions.
 1203  */
 1204 static void
 1205 ng_con_part3(node_p node, hook_p hook, void *arg1, int arg2)
 1206 {
 1207 
 1208         /*
 1209          * When we run, we know that the node 'node' is locked for us.
 1210          * Our caller has a reference on the hook.
 1211          * Our caller has a reference on the node.
 1212          * (In this case our caller is ng_apply_item() ).
 1213          * The peer hook has a reference on the hook.
 1214          * We are all set up except for the final call to the node, and
 1215          * the clearing of the INVALID flag.
 1216          */
 1217         if (NG_HOOK_NODE(hook) == &ng_deadnode) {
 1218                 /*
 1219                  * The node must have been freed again since we last visited
 1220                  * here. ng_destry_hook() has this effect but nothing else does.
 1221                  * We should just release our references and
 1222                  * free anything we can think of.
 1223                  * Since we know it's been destroyed, and it's our caller
 1224                  * that holds the references, just return.
 1225                  */
 1226                 return ;
 1227         }
 1228         if (hook->hk_node->nd_type->connect) {
 1229                 if ((*hook->hk_node->nd_type->connect) (hook)) {
 1230                         ng_destroy_hook(hook);  /* also zaps peer */
 1231                         printf("failed in ng_con_part3()\n");
 1232                         return ;
 1233                 }
 1234         }
 1235         /*
 1236          *  XXX this is wrong for SMP. Possibly we need
 1237          * to separate out 'create' and 'invalid' flags.
 1238          * should only set flags on hooks we have locked under our node.
 1239          */
 1240         hook->hk_flags &= ~HK_INVALID;
 1241         return ;
 1242 }
 1243 
 1244 static void
 1245 ng_con_part2(node_p node, hook_p hook, void *arg1, int arg2)
 1246 {
 1247 
 1248         /*
 1249          * When we run, we know that the node 'node' is locked for us.
 1250          * Our caller has a reference on the hook.
 1251          * Our caller has a reference on the node.
 1252          * (In this case our caller is ng_apply_item() ).
 1253          * The peer hook has a reference on the hook.
 1254          * our node pointer points to the 'dead' node.
 1255          * First check the hook name is unique.
 1256          * Should not happen because we checked before queueing this.
 1257          */
 1258         if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) {
 1259                 TRAP_ERROR();
 1260                 ng_destroy_hook(hook); /* should destroy peer too */
 1261                 printf("failed in ng_con_part2()\n");
 1262                 return ;
 1263         }
 1264         /*
 1265          * Check if the node type code has something to say about it
 1266          * If it fails, the unref of the hook will also unref the attached node,
 1267          * however since that node is 'ng_deadnode' this will do nothing.
 1268          * The peer hook will also be destroyed.
 1269          */
 1270         if (node->nd_type->newhook != NULL) {
 1271                 if ((*node->nd_type->newhook)(node, hook, hook->hk_name)) {
 1272                         ng_destroy_hook(hook); /* should destroy peer too */
 1273                         printf("failed in ng_con_part2()\n");
 1274                         return ;
 1275                 }
 1276         }
 1277 
 1278         /*
 1279          * The 'type' agrees so far, so go ahead and link it in.
 1280          * We'll ask again later when we actually connect the hooks.
 1281          */
 1282         hook->hk_node = node;           /* just overwrite ng_deadnode */
 1283         NG_NODE_REF(node);              /* each hook counts as a reference */
 1284         LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks);
 1285         node->nd_numhooks++;
 1286         NG_HOOK_REF(hook);      /* one for the node */
 1287         
 1288         /*
 1289          * We now have a symetrical situation, where both hooks have been
 1290          * linked to their nodes, the newhook methods have been called
 1291          * And the references are all correct. The hooks are still marked
 1292          * as invalid, as we have not called the 'connect' methods
 1293          * yet.
 1294          * We can call the local one immediatly as we have the 
 1295          * node locked, but we need to queue the remote one.
 1296          */
 1297         if (hook->hk_node->nd_type->connect) {
 1298                 if ((*hook->hk_node->nd_type->connect) (hook)) {
 1299                         ng_destroy_hook(hook);  /* also zaps peer */
 1300                         printf("failed in ng_con_part2(A)\n");
 1301                         return ;
 1302                 }
 1303         }
 1304         if (ng_send_fn(hook->hk_peer->hk_node, hook->hk_peer,
 1305                         &ng_con_part3, arg1, arg2)) {
 1306                 printf("failed in ng_con_part2(B)");
 1307                 ng_destroy_hook(hook);  /* also zaps peer */
 1308                 return ;
 1309         }
 1310         hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */
 1311         return ;
 1312 }
 1313 
 1314 /*
 1315  * Connect this node with another node. We assume that this node is 
 1316  * currently locked, as we are only called from an NGM_CONNECT message.
 1317  */
 1318 static int
 1319 ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2)
 1320 {
 1321         int     error;
 1322         hook_p  hook;
 1323         hook_p  hook2;
 1324 
 1325         if (ng_findhook(node2, name2) != NULL) {
 1326                 return(EEXIST);
 1327         }
 1328         if ((error = ng_add_hook(node, name, &hook)))  /* gives us a ref */
 1329                 return (error);
 1330         /* Allocate the other hook and link it up */
 1331         NG_ALLOC_HOOK(hook2);
 1332         if (hook == NULL) {
 1333                 TRAP_ERROR();
 1334                 ng_destroy_hook(hook);  /* XXX check ref counts so far */
 1335                 NG_HOOK_UNREF(hook);    /* including our ref */
 1336                 return (ENOMEM);
 1337         }
 1338         hook2->hk_refs = 1;             /* start with a reference for us. */
 1339         hook2->hk_flags = HK_INVALID;
 1340         hook2->hk_peer = hook;          /* Link the two together */
 1341         hook->hk_peer = hook2;  
 1342         NG_HOOK_REF(hook);              /* Add a ref for the peer to each*/
 1343         NG_HOOK_REF(hook2);
 1344         hook2->hk_node = &ng_deadnode;  
 1345         strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ);
 1346 
 1347         /*
 1348          * Queue the function above.
 1349          * Procesing continues in that function in the lock context of
 1350          * the other node.
 1351          */
 1352         ng_send_fn(node2, hook2, &ng_con_part2, NULL, 0);
 1353 
 1354         NG_HOOK_UNREF(hook);            /* Let each hook go if it wants to */
 1355         NG_HOOK_UNREF(hook2);
 1356         return (0);
 1357 }
 1358 
 1359 /*
 1360  * Make a peer and connect.
 1361  * We assume that the local node is locked.
 1362  * The new node probably doesn't need a lock until
 1363  * it has a hook, because it cannot really have any work until then,
 1364  * but we should think about it a bit more.
 1365  *
 1366  * The problem may come if the other node also fires up
 1367  * some hardware or a timer or some other source of activation,
 1368  * also it may already get a command msg via it's ID.
 1369  *
 1370  * We could use the same method as ng_con_nodes() but we'd have
 1371  * to add ability to remove the node when failing. (Not hard, just 
 1372  * make arg1 point to the node to remove).
 1373  * Unless of course we just ignore failure to connect and leave
 1374  * an unconnected node?
 1375  */
 1376 static int
 1377 ng_mkpeer(node_p node, const char *name, const char *name2, char *type)
 1378 {
 1379         node_p  node2;
 1380         hook_p  hook1;
 1381         hook_p  hook2;
 1382         int     error;
 1383 
 1384         if ((error = ng_make_node(type, &node2))) {
 1385                 return (error);
 1386         }
 1387 
 1388         if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */
 1389                 ng_rmnode(node2, NULL, NULL, 0);
 1390                 return (error);
 1391         }
 1392 
 1393         if ((error = ng_add_hook(node2, name2, &hook2))) {
 1394                 ng_rmnode(node2, NULL, NULL, 0);
 1395                 ng_destroy_hook(hook1);
 1396                 NG_HOOK_UNREF(hook1);
 1397                 return (error);
 1398         }
 1399 
 1400         /*
 1401          * Actually link the two hooks together.
 1402          */
 1403         hook1->hk_peer = hook2;
 1404         hook2->hk_peer = hook1;
 1405 
 1406         /* Each hook is referenced by the other */
 1407         NG_HOOK_REF(hook1);
 1408         NG_HOOK_REF(hook2);
 1409 
 1410         /* Give each node the opportunity to veto the pending connection */
 1411         if (hook1->hk_node->nd_type->connect) {
 1412                 error = (*hook1->hk_node->nd_type->connect) (hook1);
 1413         }
 1414 
 1415         if ((error == 0) && hook2->hk_node->nd_type->connect) {
 1416                 error = (*hook2->hk_node->nd_type->connect) (hook2);
 1417 
 1418         }
 1419 
 1420         /*
 1421          * drop the references we were holding on the two hooks.
 1422          */
 1423         if (error) {
 1424                 ng_destroy_hook(hook2); /* also zaps hook1 */
 1425                 ng_rmnode(node2, NULL, NULL, 0);
 1426         } else {
 1427                 /* As a last act, allow the hooks to be used */
 1428                 hook1->hk_flags &= ~HK_INVALID;
 1429                 hook2->hk_flags &= ~HK_INVALID;
 1430         }
 1431         NG_HOOK_UNREF(hook1);
 1432         NG_HOOK_UNREF(hook2);
 1433         return (error);
 1434 }
 1435 
 1436 /************************************************************************
 1437                 Utility routines to send self messages
 1438 ************************************************************************/
 1439         
 1440 /* Shut this node down as soon as everyone is clear of it */
 1441 /* Should add arg "immediatly" to jump the queue */
 1442 int
 1443 ng_rmnode_self(node_p node)
 1444 {
 1445         int             error;
 1446 
 1447         if (node == &ng_deadnode)
 1448                 return (0);
 1449         node->nd_flags |= NGF_INVALID;
 1450         if (node->nd_flags & NGF_CLOSING)
 1451                 return (0);
 1452 
 1453         error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0);
 1454         return (error);
 1455 }
 1456 
 1457 static void
 1458 ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2)
 1459 {
 1460         ng_destroy_hook(hook);
 1461         return ;
 1462 }
 1463 
 1464 int
 1465 ng_rmhook_self(hook_p hook)
 1466 {
 1467         int             error;
 1468         node_p node = NG_HOOK_NODE(hook);
 1469 
 1470         if (node == &ng_deadnode)
 1471                 return (0);
 1472 
 1473         error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0);
 1474         return (error);
 1475 }
 1476 
 1477 /***********************************************************************
 1478  * Parse and verify a string of the form:  <NODE:><PATH>
 1479  *
 1480  * Such a string can refer to a specific node or a specific hook
 1481  * on a specific node, depending on how you look at it. In the
 1482  * latter case, the PATH component must not end in a dot.
 1483  *
 1484  * Both <NODE:> and <PATH> are optional. The <PATH> is a string
 1485  * of hook names separated by dots. This breaks out the original
 1486  * string, setting *nodep to "NODE" (or NULL if none) and *pathp
 1487  * to "PATH" (or NULL if degenerate). Also, *hookp will point to
 1488  * the final hook component of <PATH>, if any, otherwise NULL.
 1489  *
 1490  * This returns -1 if the path is malformed. The char ** are optional.
 1491  ***********************************************************************/
 1492 int
 1493 ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp)
 1494 {
 1495         char   *node, *path, *hook;
 1496         int     k;
 1497 
 1498         /*
 1499          * Extract absolute NODE, if any
 1500          */
 1501         for (path = addr; *path && *path != ':'; path++);
 1502         if (*path) {
 1503                 node = addr;    /* Here's the NODE */
 1504                 *path++ = '\0'; /* Here's the PATH */
 1505 
 1506                 /* Node name must not be empty */
 1507                 if (!*node)
 1508                         return -1;
 1509 
 1510                 /* A name of "." is OK; otherwise '.' not allowed */
 1511                 if (strcmp(node, ".") != 0) {
 1512                         for (k = 0; node[k]; k++)
 1513                                 if (node[k] == '.')
 1514                                         return -1;
 1515                 }
 1516         } else {
 1517                 node = NULL;    /* No absolute NODE */
 1518                 path = addr;    /* Here's the PATH */
 1519         }
 1520 
 1521         /* Snoop for illegal characters in PATH */
 1522         for (k = 0; path[k]; k++)
 1523                 if (path[k] == ':')
 1524                         return -1;
 1525 
 1526         /* Check for no repeated dots in PATH */
 1527         for (k = 0; path[k]; k++)
 1528                 if (path[k] == '.' && path[k + 1] == '.')
 1529                         return -1;
 1530 
 1531         /* Remove extra (degenerate) dots from beginning or end of PATH */
 1532         if (path[0] == '.')
 1533                 path++;
 1534         if (*path && path[strlen(path) - 1] == '.')
 1535                 path[strlen(path) - 1] = 0;
 1536 
 1537         /* If PATH has a dot, then we're not talking about a hook */
 1538         if (*path) {
 1539                 for (hook = path, k = 0; path[k]; k++)
 1540                         if (path[k] == '.') {
 1541                                 hook = NULL;
 1542                                 break;
 1543                         }
 1544         } else
 1545                 path = hook = NULL;
 1546 
 1547         /* Done */
 1548         if (nodep)
 1549                 *nodep = node;
 1550         if (pathp)
 1551                 *pathp = path;
 1552         if (hookp)
 1553                 *hookp = hook;
 1554         return (0);
 1555 }
 1556 
 1557 /*
 1558  * Given a path, which may be absolute or relative, and a starting node,
 1559  * return the destination node.
 1560  */
 1561 int
 1562 ng_path2noderef(node_p here, const char *address,
 1563                                 node_p *destp, hook_p *lasthook)
 1564 {
 1565         char    fullpath[NG_PATHSIZ];
 1566         char   *nodename, *path, pbuf[2];
 1567         node_p  node, oldnode;
 1568         char   *cp;
 1569         hook_p hook = NULL;
 1570 
 1571         /* Initialize */
 1572         if (destp == NULL) {
 1573                 TRAP_ERROR();
 1574                 return EINVAL;
 1575         }
 1576         *destp = NULL;
 1577 
 1578         /* Make a writable copy of address for ng_path_parse() */
 1579         strncpy(fullpath, address, sizeof(fullpath) - 1);
 1580         fullpath[sizeof(fullpath) - 1] = '\0';
 1581 
 1582         /* Parse out node and sequence of hooks */
 1583         if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) {
 1584                 TRAP_ERROR();
 1585                 return EINVAL;
 1586         }
 1587         if (path == NULL) {
 1588                 pbuf[0] = '.';  /* Needs to be writable */
 1589                 pbuf[1] = '\0';
 1590                 path = pbuf;
 1591         }
 1592 
 1593         /*
 1594          * For an absolute address, jump to the starting node.
 1595          * Note that this holds a reference on the node for us.
 1596          * Don't forget to drop the reference if we don't need it.
 1597          */
 1598         if (nodename) {
 1599                 node = ng_name2noderef(here, nodename);
 1600                 if (node == NULL) {
 1601                         TRAP_ERROR();
 1602                         return (ENOENT);
 1603                 }
 1604         } else {
 1605                 if (here == NULL) {
 1606                         TRAP_ERROR();
 1607                         return (EINVAL);
 1608                 }
 1609                 node = here;
 1610                 NG_NODE_REF(node);
 1611         }
 1612 
 1613         /*
 1614          * Now follow the sequence of hooks 
 1615          * XXX
 1616          * We actually cannot guarantee that the sequence
 1617          * is not being demolished as we crawl along it
 1618          * without extra-ordinary locking etc.
 1619          * So this is a bit dodgy to say the least.
 1620          * We can probably hold up some things by holding
 1621          * the nodelist mutex for the time of this
 1622          * crawl if we wanted.. At least that way we wouldn't have to
 1623          * worry about the nodes dissappearing, but the hooks would still
 1624          * be a problem.
 1625          */
 1626         for (cp = path; node != NULL && *cp != '\0'; ) {
 1627                 char *segment;
 1628 
 1629                 /*
 1630                  * Break out the next path segment. Replace the dot we just
 1631                  * found with a NUL; "cp" points to the next segment (or the
 1632                  * NUL at the end).
 1633                  */
 1634                 for (segment = cp; *cp != '\0'; cp++) {
 1635                         if (*cp == '.') {
 1636                                 *cp++ = '\0';
 1637                                 break;
 1638                         }
 1639                 }
 1640 
 1641                 /* Empty segment */
 1642                 if (*segment == '\0')
 1643                         continue;
 1644 
 1645                 /* We have a segment, so look for a hook by that name */
 1646                 hook = ng_findhook(node, segment);
 1647 
 1648                 /* Can't get there from here... */
 1649                 if (hook == NULL
 1650                     || NG_HOOK_PEER(hook) == NULL
 1651                     || NG_HOOK_NOT_VALID(hook)
 1652                     || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) {
 1653                         TRAP_ERROR();
 1654                         NG_NODE_UNREF(node);
 1655 #if 0 
 1656                         printf("hooknotvalid %s %s %d %d %d %d ",
 1657                                         path,
 1658                                         segment,
 1659                                         hook == NULL,
 1660                                         NG_HOOK_PEER(hook) == NULL,
 1661                                         NG_HOOK_NOT_VALID(hook),
 1662                                         NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook)));
 1663 #endif
 1664                         return (ENOENT);
 1665                 }
 1666 
 1667                 /*
 1668                  * Hop on over to the next node 
 1669                  * XXX
 1670                  * Big race conditions here as hooks and nodes go away 
 1671                  * *** Idea.. store an ng_ID_t in each hook and use that
 1672                  * instead of the direct hook in this crawl?
 1673                  */
 1674                 oldnode = node;
 1675                 if ((node = NG_PEER_NODE(hook)))
 1676                         NG_NODE_REF(node);      /* XXX RACE */
 1677                 NG_NODE_UNREF(oldnode); /* XXX another race */
 1678                 if (NG_NODE_NOT_VALID(node)) {
 1679                         NG_NODE_UNREF(node);    /* XXX more races */
 1680                         node = NULL;
 1681                 }
 1682         }
 1683 
 1684         /* If node somehow missing, fail here (probably this is not needed) */
 1685         if (node == NULL) {
 1686                 TRAP_ERROR();
 1687                 return (ENXIO);
 1688         }
 1689 
 1690         /* Done */
 1691         *destp = node;
 1692         if (lasthook != NULL)
 1693                 *lasthook = (hook ? NG_HOOK_PEER(hook) : NULL);
 1694         return (0);
 1695 }
 1696 
 1697 /***************************************************************\
 1698 * Input queue handling.
 1699 * All activities are submitted to the node via the input queue
 1700 * which implements a multiple-reader/single-writer gate.
 1701 * Items which cannot be handled immeditly are queued.
 1702 *
 1703 * read-write queue locking inline functions                     *
 1704 \***************************************************************/
 1705 
 1706 static __inline item_p ng_dequeue(struct ng_queue * ngq);
 1707 static __inline item_p ng_acquire_read(struct ng_queue * ngq,
 1708                                         item_p  item);
 1709 static __inline item_p ng_acquire_write(struct ng_queue * ngq,
 1710                                         item_p  item);
 1711 static __inline void    ng_leave_read(struct ng_queue * ngq);
 1712 static __inline void    ng_leave_write(struct ng_queue * ngq);
 1713 static __inline void    ng_queue_rw(struct ng_queue * ngq,
 1714                                         item_p  item, int rw);
 1715 
 1716 /*
 1717  * Definition of the bits fields in the ng_queue flag word.
 1718  * Defined here rather than in netgraph.h because no-one should fiddle
 1719  * with them.
 1720  *
 1721  * The ordering here may be important! don't shuffle these.
 1722  */
 1723 /*-
 1724  Safety Barrier--------+ (adjustable to suit taste) (not used yet)
 1725                        |
 1726                        V
 1727 +-------+-------+-------+-------+-------+-------+-------+-------+
 1728 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
 1729 | |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |R|A|W|
 1730 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |P|W|P|
 1731 +-------+-------+-------+-------+-------+-------+-------+-------+
 1732 \___________________________ ____________________________/ | | |
 1733                             V                              | | |
 1734                   [active reader count]                    | | |
 1735                                                            | | |
 1736           Read Pending ------------------------------------+ | |
 1737                                                              | |
 1738           Active Writer -------------------------------------+ |
 1739                                                                |
 1740           Write Pending ---------------------------------------+
 1741 
 1742 
 1743 */
 1744 #define WRITE_PENDING   0x00000001
 1745 #define WRITER_ACTIVE   0x00000002
 1746 #define READ_PENDING    0x00000004
 1747 #define READER_INCREMENT 0x00000008
 1748 #define READER_MASK     0xfffffff0      /* Not valid if WRITER_ACTIVE is set */
 1749 #define SAFETY_BARRIER  0x00100000      /* 64K items queued should be enough */
 1750 
 1751 /* Defines of more elaborate states on the queue */
 1752 /* Mask of bits a read cares about */
 1753 #define NGQ_RMASK       (WRITE_PENDING|WRITER_ACTIVE|READ_PENDING)
 1754 
 1755 /* Mask of bits a write cares about */
 1756 #define NGQ_WMASK       (NGQ_RMASK|READER_MASK)
 1757 
 1758 /* tests to decide if we could get a read or write off the queue */
 1759 #define CAN_GET_READ(flag)      ((flag & NGQ_RMASK) == READ_PENDING)
 1760 #define CAN_GET_WRITE(flag)     ((flag & NGQ_WMASK) == WRITE_PENDING)
 1761 
 1762 /* Is there a chance of getting ANY work off the queue? */
 1763 #define CAN_GET_WORK(flag)      (CAN_GET_READ(flag) || CAN_GET_WRITE(flag))
 1764 
 1765 /*
 1766  * Taking into account the current state of the queue and node, possibly take
 1767  * the next entry off the queue and return it. Return NULL if there was
 1768  * nothing we could return, either because there really was nothing there, or
 1769  * because the node was in a state where it cannot yet process the next item
 1770  * on the queue.
 1771  *
 1772  * This MUST MUST MUST be called with the mutex held.
 1773  */
 1774 static __inline item_p
 1775 ng_dequeue(struct ng_queue *ngq)
 1776 {
 1777         item_p item;
 1778         u_int           add_arg;
 1779 
 1780         if (CAN_GET_READ(ngq->q_flags)) {
 1781                 /*
 1782                  * Head of queue is a reader and we have no write active.
 1783                  * We don't care how many readers are already active. 
 1784                  * Adjust the flags for the item we are about to dequeue.
 1785                  * Add the correct increment for the reader count as well.
 1786                  */
 1787                 add_arg = (READER_INCREMENT - READ_PENDING);
 1788         } else if (CAN_GET_WRITE(ngq->q_flags)) {
 1789                 /*
 1790                  * There is a pending write, no readers and no active writer.
 1791                  * This means we can go ahead with the pending writer. Note
 1792                  * the fact that we now have a writer, ready for when we take
 1793                  * it off the queue.
 1794                  *
 1795                  * We don't need to worry about a possible collision with the
 1796                  * fasttrack reader.
 1797                  *
 1798                  * The fasttrack thread may take a long time to discover that we
 1799                  * are running so we would have an inconsistent state in the
 1800                  * flags for a while. Since we ignore the reader count
 1801                  * entirely when the WRITER_ACTIVE flag is set, this should
 1802                  * not matter (in fact it is defined that way). If it tests
 1803                  * the flag before this operation, the WRITE_PENDING flag
 1804                  * will make it fail, and if it tests it later, the
 1805                  * WRITER_ACTIVE flag will do the same. If it is SO slow that
 1806                  * we have actually completed the operation, and neither flag
 1807                  * is set (nor the READ_PENDING) by the time that it tests
 1808                  * the flags, then it is actually ok for it to continue. If
 1809                  * it completes and we've finished and the read pending is
 1810                  * set it still fails.
 1811                  *
 1812                  * So we can just ignore it,  as long as we can ensure that the
 1813                  * transition from WRITE_PENDING state to the WRITER_ACTIVE
 1814                  * state is atomic.
 1815                  *
 1816                  * After failing, first it will be held back by the mutex, then
 1817                  * when it can proceed, it will queue its request, then it
 1818                  * would arrive at this function. Usually it will have to
 1819                  * leave empty handed because the ACTIVE WRITER bit will be
 1820                  * set.
 1821                  *
 1822                  * Adjust the flags for the item we are about to dequeue
 1823                  * and for the new active writer.
 1824                  */
 1825                 add_arg = (WRITER_ACTIVE - WRITE_PENDING);
 1826                 /*
 1827                  * We want to write "active writer, no readers " Now go make
 1828                  * it true. In fact there may be a number in the readers
 1829                  * count but we know it is not true and will be fixed soon.
 1830                  * We will fix the flags for the next pending entry in a
 1831                  * moment.
 1832                  */
 1833         } else {
 1834                 /*
 1835                  * We can't dequeue anything.. return and say so. Probably we
 1836                  * have a write pending and the readers count is non zero. If
 1837                  * we got here because a reader hit us just at the wrong
 1838                  * moment with the fasttrack code, and put us in a strange
 1839                  * state, then it will be through in just a moment, (as soon
 1840                  * as we release the mutex) and keep things moving.
 1841                  * Make sure we remove ourselves from the work queue.
 1842                  */
 1843                 ng_worklist_remove(ngq->q_node);
 1844                 return (0);
 1845         }
 1846 
 1847         /*
 1848          * Now we dequeue the request (whatever it may be) and correct the
 1849          * pending flags and the next and last pointers.
 1850          */
 1851         item = ngq->queue;
 1852         ngq->queue = item->el_next;
 1853         if (ngq->last == &(item->el_next)) {
 1854                 /*
 1855                  * that was the last entry in the queue so set the 'last
 1856                  * pointer up correctly and make sure the pending flags are
 1857                  * clear.
 1858                  */
 1859                 ngq->last = &(ngq->queue);
 1860                 /*
 1861                  * Whatever flag was set will be cleared and
 1862                  * the new acive field will be set by the add as well,
 1863                  * so we don't need to change add_arg.
 1864                  * But we know we don't need to be on the work list.
 1865                  */
 1866                 atomic_add_long(&ngq->q_flags, add_arg);
 1867                 ng_worklist_remove(ngq->q_node);
 1868         } else {
 1869                 /* 
 1870                  * Since there is something on the queue, note what it is
 1871                  * in the flags word.
 1872                  */
 1873                 if ((ngq->queue->el_flags & NGQF_RW) == NGQF_READER) {
 1874                         add_arg += READ_PENDING;
 1875                 } else {
 1876                         add_arg += WRITE_PENDING;
 1877                 }
 1878                 atomic_add_long(&ngq->q_flags, add_arg);
 1879                 /*
 1880                  * If we see more doable work, make sure we are
 1881                  * on the work queue.
 1882                  */
 1883                 if (CAN_GET_WORK(ngq->q_flags)) {
 1884                         ng_setisr(ngq->q_node);
 1885                 }
 1886         }
 1887         /*
 1888          * We have successfully cleared the old pending flag, set the new one
 1889          * if it is needed, and incremented the appropriate active field.
 1890          * (all in one atomic addition.. )
 1891          */
 1892         return (item);
 1893 }
 1894 
 1895 /*
 1896  * Queue a packet to be picked up by someone else.
 1897  * We really don't care who, but we can't or don't want to hang around
 1898  * to process it ourselves. We are probably an interrupt routine..
 1899  * 1 = writer, 0 = reader
 1900  */
 1901 #define NGQRW_R 0
 1902 #define NGQRW_W 1
 1903 static __inline void
 1904 ng_queue_rw(struct ng_queue * ngq, item_p  item, int rw)
 1905 {
 1906         item->el_next = NULL;   /* maybe not needed */
 1907         *ngq->last = item;
 1908         /*
 1909          * If it was the first item in the queue then we need to
 1910          * set the last pointer and the type flags.
 1911          */
 1912         if (ngq->last == &(ngq->queue)) {
 1913                 /*
 1914                  * When called with constants for rw, the optimiser will
 1915                  * remove the unneeded branch below.
 1916                  */
 1917                 if (rw == NGQRW_W) {
 1918                         atomic_add_long(&ngq->q_flags, WRITE_PENDING);
 1919                 } else {
 1920                         atomic_add_long(&ngq->q_flags, READ_PENDING);
 1921                 }
 1922         }
 1923         ngq->last = &(item->el_next);
 1924 }
 1925 
 1926 
 1927 /*
 1928  * This function 'cheats' in that it first tries to 'grab' the use of the
 1929  * node, without going through the mutex. We can do this becasue of the
 1930  * semantics of the lock. The semantics include a clause that says that the
 1931  * value of the readers count is invalid if the WRITER_ACTIVE flag is set. It
 1932  * also says that the WRITER_ACTIVE flag cannot be set if the readers count
 1933  * is not zero. Note that this talks about what is valid to SET the
 1934  * WRITER_ACTIVE flag, because from the moment it is set, the value if the
 1935  * reader count is immaterial, and not valid. The two 'pending' flags have a
 1936  * similar effect, in that If they are orthogonal to the two active fields in
 1937  * how they are set, but if either is set, the attempted 'grab' need to be
 1938  * backed out because there is earlier work, and we maintain ordering in the
 1939  * queue. The result of this is that the reader request can try obtain use of
 1940  * the node with only a single atomic addition, and without any of the mutex
 1941  * overhead. If this fails the operation degenerates to the same as for other
 1942  * cases.
 1943  *
 1944  */
 1945 static __inline item_p
 1946 ng_acquire_read(struct ng_queue *ngq, item_p item)
 1947 {
 1948 
 1949         /* ######### Hack alert ######### */
 1950         atomic_add_long(&ngq->q_flags, READER_INCREMENT);
 1951         if ((ngq->q_flags & NGQ_RMASK) == 0) {
 1952                 /* Successfully grabbed node */
 1953                 return (item);
 1954         }
 1955         /* undo the damage if we didn't succeed */
 1956         atomic_subtract_long(&ngq->q_flags, READER_INCREMENT);
 1957 
 1958         /* ######### End Hack alert ######### */
 1959         mtx_lock_spin((&ngq->q_mtx));
 1960         /*
 1961          * Try again. Another processor (or interrupt for that matter) may
 1962          * have removed the last queued item that was stopping us from
 1963          * running, between the previous test, and the moment that we took
 1964          * the mutex. (Or maybe a writer completed.)
 1965          */
 1966         if ((ngq->q_flags & NGQ_RMASK) == 0) {
 1967                 atomic_add_long(&ngq->q_flags, READER_INCREMENT);
 1968                 mtx_unlock_spin((&ngq->q_mtx));
 1969                 return (item);
 1970         }
 1971 
 1972         /*
 1973          * and queue the request for later.
 1974          */
 1975         item->el_flags |= NGQF_READER;
 1976         ng_queue_rw(ngq, item, NGQRW_R);
 1977 
 1978         /*
 1979          * Ok, so that's the item successfully queued for later. So now we
 1980          * see if we can dequeue something to run instead.
 1981          */
 1982         item = ng_dequeue(ngq);
 1983         mtx_unlock_spin(&(ngq->q_mtx));
 1984         return (item);
 1985 }
 1986 
 1987 static __inline item_p
 1988 ng_acquire_write(struct ng_queue *ngq, item_p item)
 1989 {
 1990 restart:
 1991         mtx_lock_spin(&(ngq->q_mtx));
 1992         /*
 1993          * If there are no readers, no writer, and no pending packets, then
 1994          * we can just go ahead. In all other situations we need to queue the
 1995          * request
 1996          */
 1997         if ((ngq->q_flags & NGQ_WMASK) == 0) {
 1998                 atomic_add_long(&ngq->q_flags, WRITER_ACTIVE);
 1999                 mtx_unlock_spin((&ngq->q_mtx));
 2000                 if (ngq->q_flags & READER_MASK) {
 2001                         /* Collision with fast-track reader */
 2002                         atomic_subtract_long(&ngq->q_flags, WRITER_ACTIVE);
 2003                         goto restart;
 2004                 }
 2005                 return (item);
 2006         }
 2007 
 2008         /*
 2009          * and queue the request for later.
 2010          */
 2011         item->el_flags &= ~NGQF_RW;
 2012         ng_queue_rw(ngq, item, NGQRW_W);
 2013 
 2014         /*
 2015          * Ok, so that's the item successfully queued for later. So now we
 2016          * see if we can dequeue something to run instead.
 2017          */
 2018         item = ng_dequeue(ngq);
 2019         mtx_unlock_spin(&(ngq->q_mtx));
 2020         return (item);
 2021 }
 2022 
 2023 static __inline void
 2024 ng_leave_read(struct ng_queue *ngq)
 2025 {
 2026         atomic_subtract_long(&ngq->q_flags, READER_INCREMENT);
 2027 }
 2028 
 2029 static __inline void
 2030 ng_leave_write(struct ng_queue *ngq)
 2031 {
 2032         atomic_subtract_long(&ngq->q_flags, WRITER_ACTIVE);
 2033 }
 2034 
 2035 static void
 2036 ng_flush_input_queue(struct ng_queue * ngq)
 2037 {
 2038         item_p item;
 2039         u_int           add_arg;
 2040         mtx_lock_spin(&ngq->q_mtx);
 2041         for (;;) {
 2042                 /* Now take a look at what's on the queue */
 2043                 if (ngq->q_flags & READ_PENDING) {
 2044                         add_arg = -READ_PENDING;
 2045                 } else if (ngq->q_flags & WRITE_PENDING) {
 2046                         add_arg = -WRITE_PENDING;
 2047                 } else {
 2048                         break;
 2049                 }
 2050 
 2051                 item = ngq->queue;
 2052                 ngq->queue = item->el_next;
 2053                 if (ngq->last == &(item->el_next)) {
 2054                         ngq->last = &(ngq->queue);
 2055                 } else {
 2056                         if ((ngq->queue->el_flags & NGQF_RW) == NGQF_READER) {
 2057                                 add_arg += READ_PENDING;
 2058                         } else {
 2059                                 add_arg += WRITE_PENDING;
 2060                         }
 2061                 }
 2062                 atomic_add_long(&ngq->q_flags, add_arg);
 2063 
 2064                 mtx_unlock_spin(&ngq->q_mtx);
 2065                 NG_FREE_ITEM(item);
 2066                 mtx_lock_spin(&ngq->q_mtx);
 2067         }
 2068         /*
 2069          * Take us off the work queue if we are there.
 2070          * We definatly have no work to be done.
 2071          */
 2072         ng_worklist_remove(ngq->q_node);
 2073         mtx_unlock_spin(&ngq->q_mtx);
 2074 }
 2075 
 2076 /***********************************************************************
 2077 * Externally visible method for sending or queueing messages or data.
 2078 ***********************************************************************/
 2079 
 2080 /*
 2081  * The module code should have filled out the item correctly by this stage:
 2082  * Common:
 2083  *    reference to destination node.
 2084  *    Reference to destination rcv hook if relevant.
 2085  * Data:
 2086  *    pointer to mbuf
 2087  * Control_Message:
 2088  *    pointer to msg.
 2089  *    ID of original sender node. (return address)
 2090  * Function:
 2091  *    Function pointer
 2092  *    void * argument
 2093  *    integer argument
 2094  *
 2095  * The nodes have several routines and macros to help with this task:
 2096  */
 2097 
 2098 int
 2099 ng_snd_item(item_p item, int queue)
 2100 {
 2101         hook_p hook = NGI_HOOK(item);
 2102         node_p node = NGI_NODE(item);
 2103         int rw;
 2104         int error = 0, ierror;
 2105         item_p  oitem;
 2106         struct ng_queue * ngq = &node->nd_input_queue;
 2107 
 2108 #ifdef  NETGRAPH_DEBUG
 2109         _ngi_check(item, __FILE__, __LINE__);
 2110 #endif
 2111 
 2112         if (item == NULL) {
 2113                 TRAP_ERROR();
 2114                 return (EINVAL);        /* failed to get queue element */
 2115         }
 2116         if (node == NULL) {
 2117                 NG_FREE_ITEM(item);
 2118                 TRAP_ERROR();
 2119                 return (EINVAL);        /* No address */
 2120         }
 2121         switch(item->el_flags & NGQF_TYPE) {
 2122         case NGQF_DATA:
 2123                 /*
 2124                  * DATA MESSAGE
 2125                  * Delivered to a node via a non-optional hook.
 2126                  * Both should be present in the item even though
 2127                  * the node is derivable from the hook.
 2128                  * References are held on both by the item.
 2129                  */
 2130 
 2131                 /* Protect nodes from sending NULL pointers
 2132                  * to each other
 2133                  */
 2134                 if (NGI_M(item) == NULL)
 2135                         return (EINVAL);
 2136 
 2137                 CHECK_DATA_MBUF(NGI_M(item));
 2138                 if (hook == NULL) {
 2139                         NG_FREE_ITEM(item);
 2140                         TRAP_ERROR();
 2141                         return(EINVAL);
 2142                 }
 2143                 if ((NG_HOOK_NOT_VALID(hook))
 2144                 || (NG_NODE_NOT_VALID(NG_HOOK_NODE(hook)))) {
 2145                         NG_FREE_ITEM(item);
 2146                         return (ENOTCONN);
 2147                 }
 2148                 if ((hook->hk_flags & HK_QUEUE)) {
 2149                         queue = 1;
 2150                 }
 2151                 /* By default data is a reader in the locking scheme */
 2152                 item->el_flags |= NGQF_READER;
 2153                 rw = NGQRW_R;
 2154                 break;
 2155         case NGQF_MESG:
 2156                 /*
 2157                  * CONTROL MESSAGE
 2158                  * Delivered to a node.
 2159                  * Hook is optional.
 2160                  * References are held by the item on the node and
 2161                  * the hook if it is present.
 2162                  */
 2163                 if (hook && (hook->hk_flags & HK_QUEUE)) {
 2164                         queue = 1;
 2165                 }
 2166                 /* Data messages count as writers unles explicitly exempted */
 2167                 if (NGI_MSG(item)->header.cmd & NGM_READONLY) {
 2168                         item->el_flags |= NGQF_READER;
 2169                         rw = NGQRW_R;
 2170                 } else {
 2171                         item->el_flags &= ~NGQF_RW;
 2172                         rw = NGQRW_W;
 2173                 }
 2174                 break;
 2175         case NGQF_FN:
 2176                 item->el_flags &= ~NGQF_RW;
 2177                 rw = NGQRW_W;
 2178                 break;
 2179         default:
 2180                 NG_FREE_ITEM(item);
 2181                 TRAP_ERROR();
 2182                 return (EINVAL);
 2183         }
 2184         /*
 2185          * If the node specifies single threading, force writer semantics
 2186          * Similarly the node may say one hook always produces writers.
 2187          * These are over-rides.
 2188          */
 2189         if ((node->nd_flags & NGF_FORCE_WRITER)
 2190         || (hook && (hook->hk_flags & HK_FORCE_WRITER))) {
 2191                         rw = NGQRW_W;
 2192                         item->el_flags &= ~NGQF_READER;
 2193         }
 2194         if (queue) {
 2195                 /* Put it on the queue for that node*/
 2196 #ifdef  NETGRAPH_DEBUG
 2197         _ngi_check(item, __FILE__, __LINE__);
 2198 #endif
 2199                 mtx_lock_spin(&(ngq->q_mtx));
 2200                 ng_queue_rw(ngq, item, rw);
 2201                 /*
 2202                  * If there are active elements then we can rely on
 2203                  * them. if not we should not rely on another packet
 2204                  * coming here by another path,
 2205                  * so it is best to put us in the netisr list.
 2206                  * We can take the worklist lock with the node locked
 2207                  * BUT NOT THE REVERSE!
 2208                  */
 2209                 if (CAN_GET_WORK(ngq->q_flags)) {
 2210                         ng_setisr(node);
 2211                 }
 2212                 mtx_unlock_spin(&(ngq->q_mtx));
 2213                 return (0);
 2214         }
 2215         /*
 2216          * Take a queue item and a node and see if we can apply the item to
 2217          * the node. We may end up getting a different item to apply instead.
 2218          * Will allow for a piggyback reply only in the case where
 2219          * there is no queueing.
 2220          */
 2221 
 2222         oitem = item;
 2223         /*
 2224          * We already decided how we will be queueud or treated.
 2225          * Try get the appropriate operating permission.
 2226          */
 2227         if (rw == NGQRW_R) {
 2228                 item = ng_acquire_read(ngq, item);
 2229         } else {
 2230                 item = ng_acquire_write(ngq, item);
 2231         }
 2232 
 2233         /*
 2234          * May have come back with a different item.
 2235          * or maybe none at all. The one we started with will
 2236          * have been queued in thises cases.
 2237          */
 2238         if (item == NULL) {
 2239                 return (0);
 2240         }
 2241 
 2242 #ifdef  NETGRAPH_DEBUG
 2243         _ngi_check(item, __FILE__, __LINE__);
 2244 #endif
 2245         /*
 2246          * Take over the reference frm the item.
 2247          * Hold it until the called function returns.
 2248          */
 2249         NGI_GET_NODE(item, node); /* zaps stored node */
 2250 
 2251         ierror = ng_apply_item(node, item); /* drops r/w lock when done */
 2252 
 2253         /* only return an error if it was our initial item.. (compat hack) */
 2254         if (oitem == item) {
 2255                 error = ierror;
 2256         }
 2257 
 2258         /*
 2259          * If the node goes away when we remove the reference, 
 2260          * whatever we just did caused it.. whatever we do, DO NOT
 2261          * access the node again!
 2262          */
 2263         if (NG_NODE_UNREF(node) == 0) {
 2264                 return (error);
 2265         }
 2266 
 2267         /*
 2268          * Now we've handled the packet we brought, (or a friend of it) let's
 2269          * look for any other packets that may have been queued up. We hold
 2270          * no locks, so if someone puts something in the queue after
 2271          * we check that it is empty, it is their problem
 2272          * to ensure it is processed. If we have the netisr thread cme in here
 2273          * while we still say we have stuff to do, we may get a boost
 2274          * in SMP systems. :-)
 2275          */
 2276         for (;;) {
 2277                 /*
 2278                  * dequeue acquires and adjusts the input_queue as it dequeues
 2279                  * packets. It acquires the rw lock as needed.
 2280                  */
 2281                 mtx_lock_spin(&ngq->q_mtx);
 2282                 item = ng_dequeue(ngq); /* fixes worklist too*/
 2283                 if (!item) {
 2284                         mtx_unlock_spin(&ngq->q_mtx);
 2285                         return (error);
 2286                 }
 2287                 mtx_unlock_spin(&ngq->q_mtx);
 2288 
 2289                 /*
 2290                  * Take over the reference frm the item.
 2291                  * Hold it until the called function returns.
 2292                  */
 2293 
 2294                 NGI_GET_NODE(item, node); /* zaps stored node */
 2295 
 2296                 /*
 2297                  * We have the appropriate lock, so run the item.
 2298                  * When finished it will drop the lock accordingly
 2299                  */
 2300                 ierror = ng_apply_item(node, item);
 2301 
 2302                 /*
 2303                  * only return an error if it was our initial
 2304                  * item.. (compat hack)
 2305                  */
 2306                 if (oitem == item) {
 2307                         error = ierror;
 2308                 }
 2309 
 2310                 /*
 2311                  * If the node goes away when we remove the reference, 
 2312                  * whatever we just did caused it.. whatever we do, DO NOT
 2313                  * access the node again!
 2314                  */
 2315                 if (NG_NODE_UNREF(node) == 0) {
 2316                         break;
 2317                 }
 2318         }
 2319         return (error);
 2320 }
 2321 
 2322 /*
 2323  * We have an item that was possibly queued somewhere.
 2324  * It should contain all the information needed
 2325  * to run it on the appropriate node/hook.
 2326  */
 2327 static int
 2328 ng_apply_item(node_p node, item_p item)
 2329 {
 2330         hook_p  hook;
 2331         int     was_reader = ((item->el_flags & NGQF_RW));
 2332         int     error = 0;
 2333         ng_rcvdata_t *rcvdata;
 2334         ng_rcvmsg_t *rcvmsg;
 2335 
 2336         NGI_GET_HOOK(item, hook); /* clears stored hook */
 2337 #ifdef  NETGRAPH_DEBUG
 2338         _ngi_check(item, __FILE__, __LINE__);
 2339 #endif
 2340         switch (item->el_flags & NGQF_TYPE) {
 2341         case NGQF_DATA:
 2342                 /*
 2343                  * Check things are still ok as when we were queued.
 2344                  */
 2345                 if ((hook == NULL)
 2346                 || NG_HOOK_NOT_VALID(hook)
 2347                 || NG_NODE_NOT_VALID(node) ) {
 2348                         error = EIO;
 2349                         NG_FREE_ITEM(item);
 2350                         break;
 2351                 }
 2352                 /*
 2353                  * If no receive method, just silently drop it.
 2354                  * Give preference to the hook over-ride method
 2355                  */
 2356                 if ((!(rcvdata = hook->hk_rcvdata)) 
 2357                 && (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) {
 2358                         error = 0;
 2359                         NG_FREE_ITEM(item);
 2360                         break;
 2361                 }
 2362                 error = (*rcvdata)(hook, item);
 2363                 break;
 2364         case NGQF_MESG:
 2365                 if (hook) {
 2366                         if (NG_HOOK_NOT_VALID(hook)) {
 2367                                 /*
 2368                                  * The hook has been zapped then we can't
 2369                                  * use it. Immediatly drop its reference.
 2370                                  * The message may not need it.
 2371                                  */
 2372                                 NG_HOOK_UNREF(hook);
 2373                                 hook = NULL;
 2374                         }
 2375                 }
 2376                 /*
 2377                  * Similarly, if the node is a zombie there is
 2378                  * nothing we can do with it, drop everything.
 2379                  */
 2380                 if (NG_NODE_NOT_VALID(node)) {
 2381                         TRAP_ERROR();
 2382                         error = EINVAL;
 2383                         NG_FREE_ITEM(item);
 2384                 } else {
 2385                         /*
 2386                          * Call the appropriate message handler for the object.
 2387                          * It is up to the message handler to free the message.
 2388                          * If it's a generic message, handle it generically,
 2389                          * otherwise call the type's message handler
 2390                          * (if it exists)
 2391                          * XXX (race). Remember that a queued message may
 2392                          * reference a node or hook that has just been
 2393                          * invalidated. It will exist as the queue code
 2394                          * is holding a reference, but..
 2395                          */
 2396 
 2397                         struct ng_mesg *msg = NGI_MSG(item);
 2398 
 2399                         /* 
 2400                          * check if the generic handler owns it.
 2401                          */
 2402                         if ((msg->header.typecookie == NGM_GENERIC_COOKIE)
 2403                         && ((msg->header.flags & NGF_RESP) == 0)) {
 2404                                 error = ng_generic_msg(node, item, hook);
 2405                                 break;
 2406                         }
 2407                         /*
 2408                          * Now see if there is a handler (hook or node specific)
 2409                          * in the target node. If none, silently discard.
 2410                          */
 2411                         if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg)))
 2412                         && (!(rcvmsg = node->nd_type->rcvmsg))) {
 2413                                 TRAP_ERROR();
 2414                                 error = 0; 
 2415                                 NG_FREE_ITEM(item);
 2416                                 break;
 2417                         }
 2418                         error = (*rcvmsg)(node, item, hook);
 2419                 }
 2420                 break;
 2421         case NGQF_FN:
 2422                 /*
 2423                  *  We have to implicitly trust the hook,
 2424                  * as some of these are used for system purposes
 2425                  * where the hook is invalid. In the case of
 2426                  * the shutdown message we allow it to hit
 2427                  * even if the node is invalid.
 2428                  */
 2429                 if ((NG_NODE_NOT_VALID(node)) 
 2430                 && (NGI_FN(item) != &ng_rmnode)) {
 2431                         TRAP_ERROR();
 2432                         error = EINVAL;
 2433                         break;
 2434                 }
 2435                 (*NGI_FN(item))(node, hook, NGI_ARG1(item), NGI_ARG2(item));
 2436                 NG_FREE_ITEM(item);
 2437                 break;
 2438                 
 2439         }
 2440         /*
 2441          * We held references on some of the resources
 2442          * that we took from the item. Now that we have
 2443          * finished doing everything, drop those references.
 2444          */
 2445         if (hook) {
 2446                 NG_HOOK_UNREF(hook);
 2447         }
 2448 
 2449         if (was_reader) {
 2450                 ng_leave_read(&node->nd_input_queue);
 2451         } else {
 2452                 ng_leave_write(&node->nd_input_queue);
 2453         }
 2454         return (error);
 2455 }
 2456 
 2457 /***********************************************************************
 2458  * Implement the 'generic' control messages
 2459  ***********************************************************************/
 2460 static int
 2461 ng_generic_msg(node_p here, item_p item, hook_p lasthook)
 2462 {
 2463         int error = 0;
 2464         struct ng_mesg *msg;
 2465         struct ng_mesg *resp = NULL;
 2466 
 2467         NGI_GET_MSG(item, msg);
 2468         if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
 2469                 TRAP_ERROR();
 2470                 error = EINVAL;
 2471                 goto out;
 2472         }
 2473         switch (msg->header.cmd) {
 2474         case NGM_SHUTDOWN:
 2475                 ng_rmnode(here, NULL, NULL, 0);
 2476                 break;
 2477         case NGM_MKPEER:
 2478             {
 2479                 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
 2480 
 2481                 if (msg->header.arglen != sizeof(*mkp)) {
 2482                         TRAP_ERROR();
 2483                         error = EINVAL;
 2484                         break;
 2485                 }
 2486                 mkp->type[sizeof(mkp->type) - 1] = '\0';
 2487                 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0';
 2488                 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0';
 2489                 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type);
 2490                 break;
 2491             }
 2492         case NGM_CONNECT:
 2493             {
 2494                 struct ngm_connect *const con =
 2495                         (struct ngm_connect *) msg->data;
 2496                 node_p node2;
 2497 
 2498                 if (msg->header.arglen != sizeof(*con)) {
 2499                         TRAP_ERROR();
 2500                         error = EINVAL;
 2501                         break;
 2502                 }
 2503                 con->path[sizeof(con->path) - 1] = '\0';
 2504                 con->ourhook[sizeof(con->ourhook) - 1] = '\0';
 2505                 con->peerhook[sizeof(con->peerhook) - 1] = '\0';
 2506                 /* Don't forget we get a reference.. */
 2507                 error = ng_path2noderef(here, con->path, &node2, NULL);
 2508                 if (error)
 2509                         break;
 2510                 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook);
 2511                 NG_NODE_UNREF(node2);
 2512                 break;
 2513             }
 2514         case NGM_NAME:
 2515             {
 2516                 struct ngm_name *const nam = (struct ngm_name *) msg->data;
 2517 
 2518                 if (msg->header.arglen != sizeof(*nam)) {
 2519                         TRAP_ERROR();
 2520                         error = EINVAL;
 2521                         break;
 2522                 }
 2523                 nam->name[sizeof(nam->name) - 1] = '\0';
 2524                 error = ng_name_node(here, nam->name);
 2525                 break;
 2526             }
 2527         case NGM_RMHOOK:
 2528             {
 2529                 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data;
 2530                 hook_p hook;
 2531 
 2532                 if (msg->header.arglen != sizeof(*rmh)) {
 2533                         TRAP_ERROR();
 2534                         error = EINVAL;
 2535                         break;
 2536                 }
 2537                 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0';
 2538                 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL)
 2539                         ng_destroy_hook(hook);
 2540                 break;
 2541             }
 2542         case NGM_NODEINFO:
 2543             {
 2544                 struct nodeinfo *ni;
 2545 
 2546                 NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT);
 2547                 if (resp == NULL) {
 2548                         error = ENOMEM;
 2549                         break;
 2550                 }
 2551 
 2552                 /* Fill in node info */
 2553                 ni = (struct nodeinfo *) resp->data;
 2554                 if (NG_NODE_HAS_NAME(here))
 2555                         strcpy(ni->name, NG_NODE_NAME(here));
 2556                 strcpy(ni->type, here->nd_type->name);
 2557                 ni->id = ng_node2ID(here);
 2558                 ni->hooks = here->nd_numhooks;
 2559                 break;
 2560             }
 2561         case NGM_LISTHOOKS:
 2562             {
 2563                 const int nhooks = here->nd_numhooks;
 2564                 struct hooklist *hl;
 2565                 struct nodeinfo *ni;
 2566                 hook_p hook;
 2567 
 2568                 /* Get response struct */
 2569                 NG_MKRESPONSE(resp, msg, sizeof(*hl)
 2570                     + (nhooks * sizeof(struct linkinfo)), M_NOWAIT);
 2571                 if (resp == NULL) {
 2572                         error = ENOMEM;
 2573                         break;
 2574                 }
 2575                 hl = (struct hooklist *) resp->data;
 2576                 ni = &hl->nodeinfo;
 2577 
 2578                 /* Fill in node info */
 2579                 if (NG_NODE_HAS_NAME(here))
 2580                         strcpy(ni->name, NG_NODE_NAME(here));
 2581                 strcpy(ni->type, here->nd_type->name);
 2582                 ni->id = ng_node2ID(here);
 2583 
 2584                 /* Cycle through the linked list of hooks */
 2585                 ni->hooks = 0;
 2586                 LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) {
 2587                         struct linkinfo *const link = &hl->link[ni->hooks];
 2588 
 2589                         if (ni->hooks >= nhooks) {
 2590                                 log(LOG_ERR, "%s: number of %s changed\n",
 2591                                     __func__, "hooks");
 2592                                 break;
 2593                         }
 2594                         if (NG_HOOK_NOT_VALID(hook))
 2595                                 continue;
 2596                         strcpy(link->ourhook, NG_HOOK_NAME(hook));
 2597                         strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook));
 2598                         if (NG_PEER_NODE_NAME(hook)[0] != '\0')
 2599                                 strcpy(link->nodeinfo.name,
 2600                                     NG_PEER_NODE_NAME(hook));
 2601                         strcpy(link->nodeinfo.type,
 2602                            NG_PEER_NODE(hook)->nd_type->name);
 2603                         link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook));
 2604                         link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks;
 2605                         ni->hooks++;
 2606                 }
 2607                 break;
 2608             }
 2609 
 2610         case NGM_LISTNAMES:
 2611         case NGM_LISTNODES:
 2612             {
 2613                 const int unnamed = (msg->header.cmd == NGM_LISTNODES);
 2614                 struct namelist *nl;
 2615                 node_p node;
 2616                 int num = 0;
 2617 
 2618                 mtx_lock(&ng_nodelist_mtx);
 2619                 /* Count number of nodes */
 2620                 LIST_FOREACH(node, &ng_nodelist, nd_nodes) {
 2621                         if (NG_NODE_IS_VALID(node)
 2622                         && (unnamed || NG_NODE_HAS_NAME(node))) {
 2623                                 num++;
 2624                         }
 2625                 }
 2626                 mtx_unlock(&ng_nodelist_mtx);
 2627 
 2628                 /* Get response struct */
 2629                 NG_MKRESPONSE(resp, msg, sizeof(*nl)
 2630                     + (num * sizeof(struct nodeinfo)), M_NOWAIT);
 2631                 if (resp == NULL) {
 2632                         error = ENOMEM;
 2633                         break;
 2634                 }
 2635                 nl = (struct namelist *) resp->data;
 2636 
 2637                 /* Cycle through the linked list of nodes */
 2638                 nl->numnames = 0;
 2639                 mtx_lock(&ng_nodelist_mtx);
 2640                 LIST_FOREACH(node, &ng_nodelist, nd_nodes) {
 2641                         struct nodeinfo *const np = &nl->nodeinfo[nl->numnames];
 2642 
 2643                         if (nl->numnames >= num) {
 2644                                 log(LOG_ERR, "%s: number of %s changed\n",
 2645                                     __func__, "nodes");
 2646                                 break;
 2647                         }
 2648                         if (NG_NODE_NOT_VALID(node))
 2649                                 continue;
 2650                         if (!unnamed && (! NG_NODE_HAS_NAME(node)))
 2651                                 continue;
 2652                         if (NG_NODE_HAS_NAME(node))
 2653                                 strcpy(np->name, NG_NODE_NAME(node));
 2654                         strcpy(np->type, node->nd_type->name);
 2655                         np->id = ng_node2ID(node);
 2656                         np->hooks = node->nd_numhooks;
 2657                         nl->numnames++;
 2658                 }
 2659                 mtx_unlock(&ng_nodelist_mtx);
 2660                 break;
 2661             }
 2662 
 2663         case NGM_LISTTYPES:
 2664             {
 2665                 struct typelist *tl;
 2666                 struct ng_type *type;
 2667                 int num = 0;
 2668 
 2669                 mtx_lock(&ng_typelist_mtx);
 2670                 /* Count number of types */
 2671                 LIST_FOREACH(type, &ng_typelist, types) {
 2672                         num++;
 2673                 }
 2674                 mtx_unlock(&ng_typelist_mtx);
 2675 
 2676                 /* Get response struct */
 2677                 NG_MKRESPONSE(resp, msg, sizeof(*tl)
 2678                     + (num * sizeof(struct typeinfo)), M_NOWAIT);
 2679                 if (resp == NULL) {
 2680                         error = ENOMEM;
 2681                         break;
 2682                 }
 2683                 tl = (struct typelist *) resp->data;
 2684 
 2685                 /* Cycle through the linked list of types */
 2686                 tl->numtypes = 0;
 2687                 mtx_lock(&ng_typelist_mtx);
 2688                 LIST_FOREACH(type, &ng_typelist, types) {
 2689                         struct typeinfo *const tp = &tl->typeinfo[tl->numtypes];
 2690 
 2691                         if (tl->numtypes >= num) {
 2692                                 log(LOG_ERR, "%s: number of %s changed\n",
 2693                                     __func__, "types");
 2694                                 break;
 2695                         }
 2696                         strcpy(tp->type_name, type->name);
 2697                         tp->numnodes = type->refs - 1; /* don't count list */
 2698                         tl->numtypes++;
 2699                 }
 2700                 mtx_unlock(&ng_typelist_mtx);
 2701                 break;
 2702             }
 2703 
 2704         case NGM_BINARY2ASCII:
 2705             {
 2706                 int bufSize = 20 * 1024;        /* XXX hard coded constant */
 2707                 const struct ng_parse_type *argstype;
 2708                 const struct ng_cmdlist *c;
 2709                 struct ng_mesg *binary, *ascii;
 2710 
 2711                 /* Data area must contain a valid netgraph message */
 2712                 binary = (struct ng_mesg *)msg->data;
 2713                 if (msg->header.arglen < sizeof(struct ng_mesg)
 2714                     || (msg->header.arglen - sizeof(struct ng_mesg)
 2715                       < binary->header.arglen)) {
 2716                         TRAP_ERROR();
 2717                         error = EINVAL;
 2718                         break;
 2719                 }
 2720 
 2721                 /* Get a response message with lots of room */
 2722                 NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT);
 2723                 if (resp == NULL) {
 2724                         error = ENOMEM;
 2725                         break;
 2726                 }
 2727                 ascii = (struct ng_mesg *)resp->data;
 2728 
 2729                 /* Copy binary message header to response message payload */
 2730                 bcopy(binary, ascii, sizeof(*binary));
 2731 
 2732                 /* Find command by matching typecookie and command number */
 2733                 for (c = here->nd_type->cmdlist;
 2734                     c != NULL && c->name != NULL; c++) {
 2735                         if (binary->header.typecookie == c->cookie
 2736                             && binary->header.cmd == c->cmd)
 2737                                 break;
 2738                 }
 2739                 if (c == NULL || c->name == NULL) {
 2740                         for (c = ng_generic_cmds; c->name != NULL; c++) {
 2741                                 if (binary->header.typecookie == c->cookie
 2742                                     && binary->header.cmd == c->cmd)
 2743                                         break;
 2744                         }
 2745                         if (c->name == NULL) {
 2746                                 NG_FREE_MSG(resp);
 2747                                 error = ENOSYS;
 2748                                 break;
 2749                         }
 2750                 }
 2751 
 2752                 /* Convert command name to ASCII */
 2753                 snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr),
 2754                     "%s", c->name);
 2755 
 2756                 /* Convert command arguments to ASCII */
 2757                 argstype = (binary->header.flags & NGF_RESP) ?
 2758                     c->respType : c->mesgType;
 2759                 if (argstype == NULL) {
 2760                         *ascii->data = '\0';
 2761                 } else {
 2762                         if ((error = ng_unparse(argstype,
 2763                             (u_char *)binary->data,
 2764                             ascii->data, bufSize)) != 0) {
 2765                                 NG_FREE_MSG(resp);
 2766                                 break;
 2767                         }
 2768                 }
 2769 
 2770                 /* Return the result as struct ng_mesg plus ASCII string */
 2771                 bufSize = strlen(ascii->data) + 1;
 2772                 ascii->header.arglen = bufSize;
 2773                 resp->header.arglen = sizeof(*ascii) + bufSize;
 2774                 break;
 2775             }
 2776 
 2777         case NGM_ASCII2BINARY:
 2778             {
 2779                 int bufSize = 2000;     /* XXX hard coded constant */
 2780                 const struct ng_cmdlist *c;
 2781                 const struct ng_parse_type *argstype;
 2782                 struct ng_mesg *ascii, *binary;
 2783                 int off = 0;
 2784 
 2785                 /* Data area must contain at least a struct ng_mesg + '\0' */
 2786                 ascii = (struct ng_mesg *)msg->data;
 2787                 if ((msg->header.arglen < sizeof(*ascii) + 1)
 2788                     || (ascii->header.arglen < 1)
 2789                     || (msg->header.arglen
 2790                       < sizeof(*ascii) + ascii->header.arglen)) {
 2791                         TRAP_ERROR();
 2792                         error = EINVAL;
 2793                         break;
 2794                 }
 2795                 ascii->data[ascii->header.arglen - 1] = '\0';
 2796 
 2797                 /* Get a response message with lots of room */
 2798                 NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT);
 2799                 if (resp == NULL) {
 2800                         error = ENOMEM;
 2801                         break;
 2802                 }
 2803                 binary = (struct ng_mesg *)resp->data;
 2804 
 2805                 /* Copy ASCII message header to response message payload */
 2806                 bcopy(ascii, binary, sizeof(*ascii));
 2807 
 2808                 /* Find command by matching ASCII command string */
 2809                 for (c = here->nd_type->cmdlist;
 2810                     c != NULL && c->name != NULL; c++) {
 2811                         if (strcmp(ascii->header.cmdstr, c->name) == 0)
 2812                                 break;
 2813                 }
 2814                 if (c == NULL || c->name == NULL) {
 2815                         for (c = ng_generic_cmds; c->name != NULL; c++) {
 2816                                 if (strcmp(ascii->header.cmdstr, c->name) == 0)
 2817                                         break;
 2818                         }
 2819                         if (c->name == NULL) {
 2820                                 NG_FREE_MSG(resp);
 2821                                 error = ENOSYS;
 2822                                 break;
 2823                         }
 2824                 }
 2825 
 2826                 /* Convert command name to binary */
 2827                 binary->header.cmd = c->cmd;
 2828                 binary->header.typecookie = c->cookie;
 2829 
 2830                 /* Convert command arguments to binary */
 2831                 argstype = (binary->header.flags & NGF_RESP) ?
 2832                     c->respType : c->mesgType;
 2833                 if (argstype == NULL) {
 2834                         bufSize = 0;
 2835                 } else {
 2836                         if ((error = ng_parse(argstype, ascii->data,
 2837                             &off, (u_char *)binary->data, &bufSize)) != 0) {
 2838                                 NG_FREE_MSG(resp);
 2839                                 break;
 2840                         }
 2841                 }
 2842 
 2843                 /* Return the result */
 2844                 binary->header.arglen = bufSize;
 2845                 resp->header.arglen = sizeof(*binary) + bufSize;
 2846                 break;
 2847             }
 2848 
 2849         case NGM_TEXT_CONFIG:
 2850         case NGM_TEXT_STATUS:
 2851                 /*
 2852                  * This one is tricky as it passes the command down to the
 2853                  * actual node, even though it is a generic type command.
 2854                  * This means we must assume that the item/msg is already freed
 2855                  * when control passes back to us.
 2856                  */
 2857                 if (here->nd_type->rcvmsg != NULL) {
 2858                         NGI_MSG(item) = msg; /* put it back as we found it */
 2859                         return((*here->nd_type->rcvmsg)(here, item, lasthook));
 2860                 }
 2861                 /* Fall through if rcvmsg not supported */
 2862         default:
 2863                 TRAP_ERROR();
 2864                 error = EINVAL;
 2865         }
 2866         /*
 2867          * Sometimes a generic message may be statically allocated
 2868          * to avoid problems with allocating when in tight memeory situations.
 2869          * Don't free it if it is so.
 2870          * I break them appart here, because erros may cause a free if the item
 2871          * in which case we'd be doing it twice.
 2872          * they are kept together above, to simplify freeing.
 2873          */
 2874 out:
 2875         NG_RESPOND_MSG(error, here, item, resp);
 2876         if (msg)
 2877                 NG_FREE_MSG(msg);
 2878         return (error);
 2879 }
 2880 
 2881 /************************************************************************
 2882                         Module routines
 2883 ************************************************************************/
 2884 
 2885 /*
 2886  * Handle the loading/unloading of a netgraph node type module
 2887  */
 2888 int
 2889 ng_mod_event(module_t mod, int event, void *data)
 2890 {
 2891         struct ng_type *const type = data;
 2892         int s, error = 0;
 2893 
 2894         switch (event) {
 2895         case MOD_LOAD:
 2896 
 2897                 /* Register new netgraph node type */
 2898                 s = splnet();
 2899                 if ((error = ng_newtype(type)) != 0) {
 2900                         splx(s);
 2901                         break;
 2902                 }
 2903 
 2904                 /* Call type specific code */
 2905                 if (type->mod_event != NULL)
 2906                         if ((error = (*type->mod_event)(mod, event, data))) {
 2907                                 mtx_lock(&ng_typelist_mtx);
 2908                                 type->refs--;   /* undo it */
 2909                                 LIST_REMOVE(type, types);
 2910                                 mtx_unlock(&ng_typelist_mtx);
 2911                         }
 2912                 splx(s);
 2913                 break;
 2914 
 2915         case MOD_UNLOAD:
 2916                 s = splnet();
 2917                 if (type->refs > 1) {           /* make sure no nodes exist! */
 2918                         error = EBUSY;
 2919                 } else {
 2920                         if (type->refs == 0) {
 2921                                 /* failed load, nothing to undo */
 2922                                 splx(s);
 2923                                 break;
 2924                         }
 2925                         if (type->mod_event != NULL) {  /* check with type */
 2926                                 error = (*type->mod_event)(mod, event, data);
 2927                                 if (error != 0) {       /* type refuses.. */
 2928                                         splx(s);
 2929                                         break;
 2930                                 }
 2931                         }
 2932                         mtx_lock(&ng_typelist_mtx);
 2933                         LIST_REMOVE(type, types);
 2934                         mtx_unlock(&ng_typelist_mtx);
 2935                 }
 2936                 splx(s);
 2937                 break;
 2938 
 2939         default:
 2940                 if (type->mod_event != NULL)
 2941                         error = (*type->mod_event)(mod, event, data);
 2942                 else
 2943                         error = EOPNOTSUPP;             /* XXX ? */
 2944                 break;
 2945         }
 2946         return (error);
 2947 }
 2948 
 2949 /*
 2950  * Handle loading and unloading for this code.
 2951  * The only thing we need to link into is the NETISR strucure.
 2952  */
 2953 static int
 2954 ngb_mod_event(module_t mod, int event, void *data)
 2955 {
 2956         int s, error = 0;
 2957 
 2958         switch (event) {
 2959         case MOD_LOAD:
 2960                 /* Register line discipline */
 2961                 mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_SPIN);
 2962                 mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL,
 2963                     MTX_DEF);
 2964                 mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL,
 2965                     MTX_DEF);
 2966                 mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL,
 2967                     MTX_DEF);
 2968                 mtx_init(&ngq_mtx, "netgraph free item list mutex", NULL,
 2969                     MTX_DEF);
 2970                 s = splimp();
 2971                 /* XXX could use NETISR_MPSAFE but need to verify code */
 2972                 netisr_register(NETISR_NETGRAPH, (netisr_t *)ngintr, NULL, 0);
 2973                 splx(s);
 2974                 break;
 2975         case MOD_UNLOAD:
 2976                 /* You cant unload it because an interface may be using it.  */
 2977                 error = EBUSY;
 2978                 break;
 2979         default:
 2980                 error = EOPNOTSUPP;
 2981                 break;
 2982         }
 2983         return (error);
 2984 }
 2985 
 2986 static moduledata_t netgraph_mod = {
 2987         "netgraph",
 2988         ngb_mod_event,
 2989         (NULL)
 2990 };
 2991 DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
 2992 SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family");
 2993 SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,"");
 2994 SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, "");
 2995 
 2996 /************************************************************************
 2997                         Queue element get/free routines
 2998 ************************************************************************/
 2999 
 3000 
 3001 static int                      allocated;      /* number of items malloc'd */
 3002 
 3003 static int                      maxalloc = 128; /* limit the damage of a leak */
 3004 static int                      ngqfreemax = 64;/* cache at most this many */
 3005 
 3006 TUNABLE_INT("net.graph.maxalloc", &maxalloc);
 3007 SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc,
 3008     0, "Maximum number of queue items to allocate");
 3009 
 3010 TUNABLE_INT("net.graph.ngqfreemax", &ngqfreemax);
 3011 SYSCTL_INT(_net_graph, OID_AUTO, ngqfreemax, CTLFLAG_RDTUN, &ngqfreemax,
 3012     0, "Maximum number of free queue items to cache");
 3013 
 3014 static const int                ngqfreelow = 4; /* try malloc if free < this */
 3015 static volatile int             ngqfreesize;    /* number of cached entries */
 3016 static volatile item_p          ngqfree;        /* free ones */
 3017 
 3018 #ifdef  NETGRAPH_DEBUG
 3019 static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist);
 3020 #endif
 3021 /*
 3022  * Get a queue entry
 3023  * This is usually called when a packet first enters netgraph.
 3024  * By definition, this is usually from an interrupt, or from a user.
 3025  * Users are not so important, but try be quick for the times that it's
 3026  * an interrupt.
 3027  * XXX If reserve is low, we should try to get 2 from malloc as this
 3028  * would indicate it often fails.
 3029  */
 3030 static item_p
 3031 ng_getqblk(void)
 3032 {
 3033         item_p item = NULL;
 3034 
 3035         /*
 3036          * Try get a cached queue block, or else allocate a new one
 3037          * If we are less than our reserve, try malloc. If malloc
 3038          * fails, then that's what the reserve is for...
 3039          * We have our little reserve
 3040          * because we use M_NOWAIT for malloc. This just helps us
 3041          * avoid dropping packets while not increasing the time
 3042          * we take to service the interrupt (on average) (I hope).
 3043          */
 3044         mtx_lock(&ngq_mtx);
 3045 
 3046         if ((ngqfreesize < ngqfreelow) || (ngqfree == NULL)) {
 3047                 if (allocated < maxalloc) {  /* don't leak forever */
 3048                         MALLOC(item, item_p ,
 3049                             sizeof(*item), M_NETGRAPH_ITEM,
 3050                             (M_NOWAIT | M_ZERO));
 3051                         if (item) {
 3052 #ifdef  NETGRAPH_DEBUG
 3053                                 TAILQ_INSERT_TAIL(&ng_itemlist, item, all);
 3054 #endif  /* NETGRAPH_DEBUG */
 3055                                 allocated++;
 3056                         }
 3057                 }
 3058         }
 3059 
 3060         /*
 3061          * We didn't or couldn't malloc.
 3062          * try get one from our cache.
 3063          */
 3064         if (item == NULL && (item = ngqfree) != NULL) {
 3065                 ngqfree = item->el_next;
 3066                 ngqfreesize--;
 3067                 item->el_flags &= ~NGQF_FREE;
 3068         }
 3069 
 3070         mtx_unlock(&ngq_mtx);
 3071         return (item);
 3072 }
 3073 
 3074 /*
 3075  * Release a queue entry
 3076  */
 3077 void
 3078 ng_free_item(item_p item)
 3079 {
 3080 
 3081         /*
 3082          * The item may hold resources on it's own. We need to free
 3083          * these before we can free the item. What they are depends upon
 3084          * what kind of item it is. it is important that nodes zero
 3085          * out pointers to resources that they remove from the item
 3086          * or we release them again here.
 3087          */
 3088         if (item->el_flags & NGQF_FREE) {
 3089                 panic(" Freeing free queue item");
 3090         }
 3091         switch (item->el_flags & NGQF_TYPE) {
 3092         case NGQF_DATA:
 3093                 /* If we have an mbuf still attached.. */
 3094                 NG_FREE_M(_NGI_M(item));
 3095                 break;
 3096         case NGQF_MESG:
 3097                 _NGI_RETADDR(item) = 0;
 3098                 NG_FREE_MSG(_NGI_MSG(item));
 3099                 break;
 3100         case NGQF_FN:
 3101                 /* nothing to free really, */
 3102                 _NGI_FN(item) = NULL;
 3103                 _NGI_ARG1(item) = NULL;
 3104                 _NGI_ARG2(item) = 0;
 3105         case NGQF_UNDEF:
 3106                 break;
 3107         }
 3108         /* If we still have a node or hook referenced... */
 3109         _NGI_CLR_NODE(item);
 3110         _NGI_CLR_HOOK(item);
 3111         item->el_flags |= NGQF_FREE;
 3112 
 3113         mtx_lock(&ngq_mtx);
 3114         if (ngqfreesize < ngqfreemax) {
 3115                 ngqfreesize++;
 3116                 item->el_next = ngqfree;
 3117                 ngqfree = item;
 3118         } else {
 3119 #ifdef  NETGRAPH_DEBUG
 3120                 TAILQ_REMOVE(&ng_itemlist, item, all);
 3121 #endif  /* NETGRAPH_DEBUG */
 3122                 NG_FREE_ITEM_REAL(item);
 3123                 allocated--;
 3124         }
 3125         mtx_unlock(&ngq_mtx);
 3126 }
 3127 
 3128 #ifdef  NETGRAPH_DEBUG
 3129 void
 3130 dumphook (hook_p hook, char *file, int line)
 3131 {
 3132         printf("hook: name %s, %d refs, Last touched:\n",
 3133                 _NG_HOOK_NAME(hook), hook->hk_refs);
 3134         printf("        Last active @ %s, line %d\n",
 3135                 hook->lastfile, hook->lastline);
 3136         if (line) {
 3137                 printf(" problem discovered at file %s, line %d\n", file, line);
 3138         }
 3139 }
 3140 
 3141 void
 3142 dumpnode(node_p node, char *file, int line)
 3143 {
 3144         printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n",
 3145                 _NG_NODE_ID(node), node->nd_type->name,
 3146                 node->nd_numhooks, node->nd_flags,
 3147                 node->nd_refs, node->nd_name);
 3148         printf("        Last active @ %s, line %d\n",
 3149                 node->lastfile, node->lastline);
 3150         if (line) {
 3151                 printf(" problem discovered at file %s, line %d\n", file, line);
 3152         }
 3153 }
 3154 
 3155 void
 3156 dumpitem(item_p item, char *file, int line)
 3157 {
 3158         if (item->el_flags & NGQF_FREE) {
 3159                 printf(" Free item, freed at %s, line %d\n",
 3160                         item->lastfile, item->lastline);
 3161         } else {
 3162                 printf(" ACTIVE item, last used at %s, line %d",
 3163                         item->lastfile, item->lastline);
 3164                 switch(item->el_flags & NGQF_TYPE) {
 3165                 case NGQF_DATA:
 3166                         printf(" - [data]\n");
 3167                         break;
 3168                 case NGQF_MESG:
 3169                         printf(" - retaddr[%d]:\n", _NGI_RETADDR(item));
 3170                         break;
 3171                 case NGQF_FN:
 3172                         printf(" - fn@%p (%p, %p, %p, %d (%x))\n",
 3173                                 item->body.fn.fn_fn,
 3174                                 NGI_NODE(item),
 3175                                 NGI_HOOK(item),
 3176                                 item->body.fn.fn_arg1,
 3177                                 item->body.fn.fn_arg2,
 3178                                 item->body.fn.fn_arg2);
 3179                         break;
 3180                 case NGQF_UNDEF:
 3181                         printf(" - UNDEFINED!\n");
 3182                 }
 3183         }
 3184         if (line) {
 3185                 printf(" problem discovered at file %s, line %d\n", file, line);
 3186                 if (NGI_NODE(item)) {
 3187                         printf("node %p ([%x])\n",
 3188                                 NGI_NODE(item), ng_node2ID(NGI_NODE(item)));
 3189                 }
 3190         }
 3191 }
 3192 
 3193 static void
 3194 ng_dumpitems(void)
 3195 {
 3196         item_p item;
 3197         int i = 1;
 3198         TAILQ_FOREACH(item, &ng_itemlist, all) {
 3199                 printf("[%d] ", i++);
 3200                 dumpitem(item, NULL, 0);
 3201         }
 3202 }
 3203 
 3204 static void
 3205 ng_dumpnodes(void)
 3206 {
 3207         node_p node;
 3208         int i = 1;
 3209         mtx_lock(&ng_nodelist_mtx);
 3210         SLIST_FOREACH(node, &ng_allnodes, nd_all) {
 3211                 printf("[%d] ", i++);
 3212                 dumpnode(node, NULL, 0);
 3213         }
 3214         mtx_unlock(&ng_nodelist_mtx);
 3215 }
 3216 
 3217 static void
 3218 ng_dumphooks(void)
 3219 {
 3220         hook_p hook;
 3221         int i = 1;
 3222         mtx_lock(&ng_nodelist_mtx);
 3223         SLIST_FOREACH(hook, &ng_allhooks, hk_all) {
 3224                 printf("[%d] ", i++);
 3225                 dumphook(hook, NULL, 0);
 3226         }
 3227         mtx_unlock(&ng_nodelist_mtx);
 3228 }
 3229 
 3230 static int
 3231 sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS)
 3232 {
 3233         int error;
 3234         int val;
 3235         int i;
 3236 
 3237         val = allocated;
 3238         i = 1;
 3239         error = sysctl_handle_int(oidp, &val, sizeof(int), req);
 3240         if (error != 0 || req->newptr == NULL)
 3241                 return (error);
 3242         if (val == 42) {
 3243                 ng_dumpitems();
 3244                 ng_dumpnodes();
 3245                 ng_dumphooks();
 3246         }
 3247         return (0);
 3248 }
 3249 
 3250 SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW,
 3251     0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items");
 3252 #endif  /* NETGRAPH_DEBUG */
 3253 
 3254 
 3255 /***********************************************************************
 3256 * Worklist routines
 3257 **********************************************************************/
 3258 /* NETISR thread enters here */
 3259 /*
 3260  * Pick a node off the list of nodes with work,
 3261  * try get an item to process off it.
 3262  * If there are no more, remove the node from the list.
 3263  */
 3264 static void
 3265 ngintr(void)
 3266 {
 3267         item_p item;
 3268         node_p  node = NULL;
 3269 
 3270         for (;;) {
 3271                 mtx_lock_spin(&ng_worklist_mtx);
 3272                 node = TAILQ_FIRST(&ng_worklist);
 3273                 if (!node) {
 3274                         mtx_unlock_spin(&ng_worklist_mtx);
 3275                         break;
 3276                 }
 3277                 node->nd_flags &= ~NGF_WORKQ;   
 3278                 TAILQ_REMOVE(&ng_worklist, node, nd_work);
 3279                 mtx_unlock_spin(&ng_worklist_mtx);
 3280                 /*
 3281                  * We have the node. We also take over the reference
 3282                  * that the list had on it.
 3283                  * Now process as much as you can, until it won't
 3284                  * let you have another item off the queue.
 3285                  * All this time, keep the reference
 3286                  * that lets us be sure that the node still exists.
 3287                  * Let the reference go at the last minute.
 3288                  * ng_dequeue will put us back on the worklist
 3289                  * if there is more too do. This may be of use if there
 3290                  * are Multiple Processors and multiple Net threads in the 
 3291                  * future.
 3292                  */
 3293                 for (;;) {
 3294                         mtx_lock_spin(&node->nd_input_queue.q_mtx);
 3295                         item = ng_dequeue(&node->nd_input_queue);
 3296                         if (item == NULL) {
 3297                                 mtx_unlock_spin(&node->nd_input_queue.q_mtx);
 3298                                 break; /* go look for another node */
 3299                         } else {
 3300                                 mtx_unlock_spin(&node->nd_input_queue.q_mtx);
 3301                                 NGI_GET_NODE(item, node); /* zaps stored node */
 3302                                 ng_apply_item(node, item);
 3303                                 NG_NODE_UNREF(node);
 3304                         }
 3305                 }
 3306                 NG_NODE_UNREF(node);
 3307         }
 3308 }
 3309 
 3310 static void
 3311 ng_worklist_remove(node_p node)
 3312 {
 3313         mtx_lock_spin(&ng_worklist_mtx);
 3314         if (node->nd_flags & NGF_WORKQ) {
 3315                 node->nd_flags &= ~NGF_WORKQ;
 3316                 TAILQ_REMOVE(&ng_worklist, node, nd_work);
 3317                 mtx_unlock_spin(&ng_worklist_mtx);
 3318                 NG_NODE_UNREF(node);
 3319         } else {
 3320                 mtx_unlock_spin(&ng_worklist_mtx);
 3321         }
 3322 }
 3323 
 3324 /*
 3325  * XXX
 3326  * It's posible that a debugging NG_NODE_REF may need
 3327  * to be outside the mutex zone
 3328  */
 3329 static void
 3330 ng_setisr(node_p node)
 3331 {
 3332         mtx_lock_spin(&ng_worklist_mtx);
 3333         if ((node->nd_flags & NGF_WORKQ) == 0) {
 3334                 /*
 3335                  * If we are not already on the work queue,
 3336                  * then put us on.
 3337                  */
 3338                 node->nd_flags |= NGF_WORKQ;
 3339                 TAILQ_INSERT_TAIL(&ng_worklist, node, nd_work);
 3340                 NG_NODE_REF(node); /* XXX fafe in mutex? */
 3341         }
 3342         mtx_unlock_spin(&ng_worklist_mtx);
 3343         schednetisr(NETISR_NETGRAPH);
 3344 }
 3345 
 3346 
 3347 /***********************************************************************
 3348 * Externally useable functions to set up a queue item ready for sending
 3349 ***********************************************************************/
 3350 
 3351 #ifdef  NETGRAPH_DEBUG
 3352 #define ITEM_DEBUG_CHECKS                                               \
 3353         do {                                                            \
 3354                 if (NGI_NODE(item) ) {                                  \
 3355                         printf("item already has node");                \
 3356                         kdb_enter("has node");                          \
 3357                         NGI_CLR_NODE(item);                             \
 3358                 }                                                       \
 3359                 if (NGI_HOOK(item) ) {                                  \
 3360                         printf("item already has hook");                \
 3361                         kdb_enter("has hook");                          \
 3362                         NGI_CLR_HOOK(item);                             \
 3363                 }                                                       \
 3364         } while (0)
 3365 #else
 3366 #define ITEM_DEBUG_CHECKS
 3367 #endif
 3368 
 3369 /*
 3370  * Put mbuf into the item.
 3371  * Hook and node references will be removed when the item is dequeued.
 3372  * (or equivalent)
 3373  * (XXX) Unsafe because no reference held by peer on remote node.
 3374  * remote node might go away in this timescale.
 3375  * We know the hooks can't go away because that would require getting
 3376  * a writer item on both nodes and we must have at least a  reader
 3377  * here to eb able to do this.
 3378  * Note that the hook loaded is the REMOTE hook.
 3379  *
 3380  * This is possibly in the critical path for new data.
 3381  */
 3382 item_p
 3383 ng_package_data(struct mbuf *m, void *dummy)
 3384 {
 3385         item_p item;
 3386 
 3387         if ((item = ng_getqblk()) == NULL) {
 3388                 NG_FREE_M(m);
 3389                 return (NULL);
 3390         }
 3391         ITEM_DEBUG_CHECKS;
 3392         item->el_flags = NGQF_DATA;
 3393         item->el_next = NULL;
 3394         NGI_M(item) = m;
 3395         return (item);
 3396 }
 3397 
 3398 /*
 3399  * Allocate a queue item and put items into it..
 3400  * Evaluate the address as this will be needed to queue it and
 3401  * to work out what some of the fields should be.
 3402  * Hook and node references will be removed when the item is dequeued.
 3403  * (or equivalent)
 3404  */
 3405 item_p
 3406 ng_package_msg(struct ng_mesg *msg)
 3407 {
 3408         item_p item;
 3409 
 3410         if ((item = ng_getqblk()) == NULL) {
 3411                 NG_FREE_MSG(msg);
 3412                 return (NULL);
 3413         }
 3414         ITEM_DEBUG_CHECKS;
 3415         item->el_flags = NGQF_MESG;
 3416         item->el_next = NULL;
 3417         /*
 3418          * Set the current lasthook into the queue item
 3419          */
 3420         NGI_MSG(item) = msg;
 3421         NGI_RETADDR(item) = 0;
 3422         return (item);
 3423 }
 3424 
 3425 
 3426 
 3427 #define SET_RETADDR(item, here, retaddr)                                \
 3428         do {    /* Data or fn items don't have retaddrs */              \
 3429                 if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) {        \
 3430                         if (retaddr) {                                  \
 3431                                 NGI_RETADDR(item) = retaddr;            \
 3432                         } else {                                        \
 3433                                 /*                                      \
 3434                                  * The old return address should be ok. \
 3435                                  * If there isn't one, use the address  \
 3436                                  * here.                                \
 3437                                  */                                     \
 3438                                 if (NGI_RETADDR(item) == 0) {           \
 3439                                         NGI_RETADDR(item)               \
 3440                                                 = ng_node2ID(here);     \
 3441                                 }                                       \
 3442                         }                                               \
 3443                 }                                                       \
 3444         } while (0)
 3445 
 3446 int
 3447 ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr)
 3448 {
 3449         hook_p peer;
 3450         node_p peernode;
 3451         ITEM_DEBUG_CHECKS;
 3452         /*
 3453          * Quick sanity check..
 3454          * Since a hook holds a reference on it's node, once we know
 3455          * that the peer is still connected (even if invalid,) we know
 3456          * that the peer node is present, though maybe invalid.
 3457          */
 3458         if ((hook == NULL)
 3459         || NG_HOOK_NOT_VALID(hook)
 3460         || (NG_HOOK_PEER(hook) == NULL)
 3461         || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))
 3462         || NG_NODE_NOT_VALID(NG_PEER_NODE(hook))) {
 3463                 NG_FREE_ITEM(item);
 3464                 TRAP_ERROR();
 3465                 return (ENETDOWN);
 3466         }
 3467 
 3468         /*
 3469          * Transfer our interest to the other (peer) end.
 3470          */
 3471         peer = NG_HOOK_PEER(hook);
 3472         NG_HOOK_REF(peer);
 3473         NGI_SET_HOOK(item, peer);
 3474         peernode = NG_PEER_NODE(hook);
 3475         NG_NODE_REF(peernode);
 3476         NGI_SET_NODE(item, peernode);
 3477         SET_RETADDR(item, here, retaddr);
 3478         return (0);
 3479 }
 3480 
 3481 int
 3482 ng_address_path(node_p here, item_p item, char *address, ng_ID_t retaddr) 
 3483 {
 3484         node_p  dest = NULL;
 3485         hook_p  hook = NULL;
 3486         int     error;
 3487 
 3488         ITEM_DEBUG_CHECKS;
 3489         /*
 3490          * Note that ng_path2noderef increments the reference count
 3491          * on the node for us if it finds one. So we don't have to.
 3492          */
 3493         error = ng_path2noderef(here, address, &dest, &hook);
 3494         if (error) {
 3495                 NG_FREE_ITEM(item);
 3496                 return (error);
 3497         }
 3498         NGI_SET_NODE(item, dest);
 3499         if ( hook) {
 3500                 NG_HOOK_REF(hook);      /* don't let it go while on the queue */
 3501                 NGI_SET_HOOK(item, hook);
 3502         }
 3503         SET_RETADDR(item, here, retaddr);
 3504         return (0);
 3505 }
 3506 
 3507 int
 3508 ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr)
 3509 {
 3510         node_p dest;
 3511 
 3512         ITEM_DEBUG_CHECKS;
 3513         /*
 3514          * Find the target node.
 3515          */
 3516         dest = ng_ID2noderef(ID); /* GETS REFERENCE! */
 3517         if (dest == NULL) {
 3518                 NG_FREE_ITEM(item);
 3519                 TRAP_ERROR();
 3520                 return(EINVAL);
 3521         }
 3522         /* Fill out the contents */
 3523         item->el_flags = NGQF_MESG;
 3524         item->el_next = NULL;
 3525         NGI_SET_NODE(item, dest);
 3526         NGI_CLR_HOOK(item);
 3527         SET_RETADDR(item, here, retaddr);
 3528         return (0);
 3529 }
 3530 
 3531 /*
 3532  * special case to send a message to self (e.g. destroy node)
 3533  * Possibly indicate an arrival hook too.
 3534  * Useful for removing that hook :-)
 3535  */
 3536 item_p
 3537 ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg)
 3538 {
 3539         item_p item;
 3540 
 3541         /*
 3542          * Find the target node.
 3543          * If there is a HOOK argument, then use that in preference
 3544          * to the address.
 3545          */
 3546         if ((item = ng_getqblk()) == NULL) {
 3547                 NG_FREE_MSG(msg);
 3548                 return (NULL);
 3549         }
 3550 
 3551         /* Fill out the contents */
 3552         item->el_flags = NGQF_MESG;
 3553         item->el_next = NULL;
 3554         NG_NODE_REF(here);
 3555         NGI_SET_NODE(item, here);
 3556         if (hook) {
 3557                 NG_HOOK_REF(hook);
 3558                 NGI_SET_HOOK(item, hook);
 3559         }
 3560         NGI_MSG(item) = msg;
 3561         NGI_RETADDR(item) = ng_node2ID(here);
 3562         return (item);
 3563 }
 3564 
 3565 int
 3566 ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2)
 3567 {
 3568         item_p item;
 3569 
 3570         if ((item = ng_getqblk()) == NULL) {
 3571                 return (ENOMEM);
 3572         }
 3573         item->el_flags = NGQF_FN | NGQF_WRITER;
 3574         NG_NODE_REF(node); /* and one for the item */
 3575         NGI_SET_NODE(item, node);
 3576         if (hook) {
 3577                 NG_HOOK_REF(hook);
 3578                 NGI_SET_HOOK(item, hook);
 3579         }
 3580         NGI_FN(item) = fn;
 3581         NGI_ARG1(item) = arg1;
 3582         NGI_ARG2(item) = arg2;
 3583         return(ng_snd_item(item, 0));
 3584 }
 3585 
 3586 /* 
 3587  * Official timeout routines for Netgraph nodes.
 3588  */
 3589 static void
 3590 ng_timeout_trapoline(void *arg)
 3591 {
 3592         item_p item = arg;
 3593 
 3594         ng_snd_item(item, 0);
 3595 }
 3596 
 3597 
 3598 struct callout_handle
 3599 ng_timeout(node_p node, hook_p hook, int ticks,
 3600     ng_item_fn *fn, void * arg1, int arg2)
 3601 {
 3602         item_p item;
 3603 
 3604         if ((item = ng_getqblk()) == NULL) {
 3605                 struct callout_handle handle;
 3606                 handle.callout = NULL;
 3607                 return (handle);
 3608         }
 3609         item->el_flags = NGQF_FN | NGQF_WRITER;
 3610         NG_NODE_REF(node);              /* and one for the item */
 3611         NGI_SET_NODE(item, node);
 3612         if (hook) {
 3613                 NG_HOOK_REF(hook);
 3614                 NGI_SET_HOOK(item, hook);
 3615         }
 3616         NGI_FN(item) = fn;
 3617         NGI_ARG1(item) = arg1;
 3618         NGI_ARG2(item) = arg2;
 3619         return (timeout(&ng_timeout_trapoline, item, ticks));
 3620 }
 3621 
 3622 /* A special modified version of untimeout() */
 3623 int 
 3624 ng_untimeout(struct callout_handle handle, node_p node)
 3625 {
 3626         item_p item;
 3627         
 3628         if (handle.callout == NULL)
 3629                 return (0);
 3630         mtx_lock_spin(&callout_lock);
 3631         item = handle.callout->c_arg; /* should be an official way to do this */
 3632         if ((handle.callout->c_func == &ng_timeout_trapoline) &&
 3633             (NGI_NODE(item) == node) &&
 3634             (callout_stop(handle.callout))) {
 3635                 /*
 3636                  * We successfully removed it from the queue before it ran
 3637                  * So now we need to unreference everything that was 
 3638                  * given extra references. (NG_FREE_ITEM does this).
 3639                  */
 3640                 mtx_unlock_spin(&callout_lock);
 3641                 NG_FREE_ITEM(item);
 3642                 return (1);
 3643         }
 3644         mtx_unlock_spin(&callout_lock);
 3645         return (0);
 3646 }
 3647 
 3648 /*
 3649  * Set the address, if none given, give the node here.
 3650  */
 3651 void
 3652 ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr)
 3653 {
 3654         if (retaddr) {
 3655                 NGI_RETADDR(item) = retaddr;
 3656         } else {
 3657                 /*
 3658                  * The old return address should be ok.
 3659                  * If there isn't one, use the address here.
 3660                  */
 3661                 NGI_RETADDR(item) = ng_node2ID(here);
 3662         }
 3663 }
 3664 
 3665 #define TESTING
 3666 #ifdef TESTING
 3667 /* just test all the macros */
 3668 void
 3669 ng_macro_test(item_p item);
 3670 void
 3671 ng_macro_test(item_p item)
 3672 {
 3673         node_p node = NULL;
 3674         hook_p hook = NULL;
 3675         struct mbuf *m;
 3676         struct ng_mesg *msg;
 3677         ng_ID_t retaddr;
 3678         int     error;
 3679 
 3680         NGI_GET_M(item, m);
 3681         NGI_GET_MSG(item, msg);
 3682         retaddr = NGI_RETADDR(item);
 3683         NG_SEND_DATA(error, hook, m, NULL);
 3684         NG_SEND_DATA_ONLY(error, hook, m);
 3685         NG_FWD_NEW_DATA(error, item, hook, m);
 3686         NG_FWD_ITEM_HOOK(error, item, hook);
 3687         NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr);
 3688         NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr);
 3689         NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr);
 3690         NG_FWD_MSG_HOOK(error, node, item, hook, retaddr);
 3691 }
 3692 #endif /* TESTING */
 3693 

Cache object: cf95785fb3a7bad5d0a277d9a9802c3f


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