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