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