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