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

Cache object: 58ee18d7a4d44cbb3ed4cc542463bead


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