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