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