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