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


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

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

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

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

Cache object: 19f0972b14620d08a14b0556527454b6


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