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