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

Cache object: 1939616fd55ce16fe01f7979281c1085


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