The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_base.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5ec10afe0d8843f86e09de74fc57cd7e


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