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

Cache object: e5150167e8e41d4a4be3ca759e898c33


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