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