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


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

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

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

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

Cache object: bd259b01cd88d042dd763b0007f5cf6b


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