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