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

Cache object: d85bb176f3183e5f2f907b4fc0ee74d9


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