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

Cache object: 8f8c4c6682051ab63204a0b6a3392f53


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