[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_base.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/netgraph/ng_base.c,v 1.168 2008/11/28 23:30:51 zec Exp $
 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 <sys/vimage.h>
 65 #include <machine/cpu.h>
 66 
 67 #include <net/netisr.h>
 68 
 69 #include <netgraph/ng_message.h>
 70 #include <netgraph/netgraph.h>
 71 #include <netgraph/ng_parse.h>
 72 
 73 MODULE_VERSION(netgraph, NG_ABI_VERSION);
 74 
 75 /* Mutex to protect topology events. */
 76 static struct mtx       ng_topo_mtx;
 77 
 78 #ifdef  NETGRAPH_DEBUG
 79 static struct mtx       ng_nodelist_mtx; /* protects global node/hook lists */
 80 static struct mtx       ngq_mtx;        /* protects the queue item list */
 81 
 82 static SLIST_HEAD(, ng_node) ng_allnodes;
 83 static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */
 84 static SLIST_HEAD(, ng_hook) ng_allhooks;
 85 static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */
 86 
 87 static void ng_dumpitems(void);
 88 static void ng_dumpnodes(void);
 89 static void ng_dumphooks(void);
 90 
 91 #endif  /* NETGRAPH_DEBUG */
 92 /*
 93  * DEAD versions of the structures.
 94  * In order to avoid races, it is sometimes neccesary to point
 95  * at SOMETHING even though theoretically, the current entity is
 96  * INVALID. Use these to avoid these races.
 97  */
 98 struct ng_type ng_deadtype = {
 99         NG_ABI_VERSION,
100         "dead",
101         NULL,   /* modevent */
102         NULL,   /* constructor */
103         NULL,   /* rcvmsg */
104         NULL,   /* shutdown */
105         NULL,   /* newhook */
106         NULL,   /* findhook */
107         NULL,   /* connect */
108         NULL,   /* rcvdata */
109         NULL,   /* disconnect */
110         NULL,   /* cmdlist */
111 };
112 
113 struct ng_node ng_deadnode = {
114         "dead",
115         &ng_deadtype,   
116         NGF_INVALID,
117         0,      /* numhooks */
118         NULL,   /* private */
119         0,      /* ID */
120         LIST_HEAD_INITIALIZER(ng_deadnode.hooks),
121         {},     /* all_nodes list entry */
122         {},     /* id hashtable list entry */
123         {       0,
124                 0,
125                 {}, /* should never use! (should hang) */
126                 {}, /* workqueue entry */
127                 STAILQ_HEAD_INITIALIZER(ng_deadnode.nd_input_queue.queue),
128         },
129         1,      /* refs */
130 #ifdef  NETGRAPH_DEBUG
131         ND_MAGIC,
132         __FILE__,
133         __LINE__,
134         {NULL}
135 #endif  /* NETGRAPH_DEBUG */
136 };
137 
138 struct ng_hook ng_deadhook = {
139         "dead",
140         NULL,           /* private */
141         HK_INVALID | HK_DEAD,
142         0,              /* undefined data link type */
143         &ng_deadhook,   /* Peer is self */
144         &ng_deadnode,   /* attached to deadnode */
145         {},             /* hooks list */
146         NULL,           /* override rcvmsg() */
147         NULL,           /* override rcvdata() */
148         1,              /* refs always >= 1 */
149 #ifdef  NETGRAPH_DEBUG
150         HK_MAGIC,
151         __FILE__,
152         __LINE__,
153         {NULL}
154 #endif  /* NETGRAPH_DEBUG */
155 };
156 
157 /*
158  * END DEAD STRUCTURES
159  */
160 /* List nodes with unallocated work */
161 static STAILQ_HEAD(, ng_node) ng_worklist = STAILQ_HEAD_INITIALIZER(ng_worklist);
162 static struct mtx       ng_worklist_mtx;   /* MUST LOCK NODE FIRST */
163 
164 /* List of installed types */
165 static LIST_HEAD(, ng_type) ng_typelist;
166 static struct mtx       ng_typelist_mtx;
167 
168 /* Hash related definitions */
169 /* XXX Don't need to initialise them because it's a LIST */
170 static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE];
171 static struct mtx       ng_idhash_mtx;
172 /* Method to find a node.. used twice so do it here */
173 #define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE))
174 #define NG_IDHASH_FIND(ID, node)                                        \
175         do {                                                            \
176                 mtx_assert(&ng_idhash_mtx, MA_OWNED);                   \
177                 LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)],     \
178                                                 nd_idnodes) {           \
179                         if (NG_NODE_IS_VALID(node)                      \
180                         && (NG_NODE_ID(node) == ID)) {                  \
181                                 break;                                  \
182                         }                                               \
183                 }                                                       \
184         } while (0)
185 
186 static LIST_HEAD(, ng_node) ng_name_hash[NG_NAME_HASH_SIZE];
187 static struct mtx       ng_namehash_mtx;
188 #define NG_NAMEHASH(NAME, HASH)                         \
189         do {                                            \
190                 u_char  h = 0;                          \
191                 const u_char    *c;                     \
192                 for (c = (const u_char*)(NAME); *c; c++)\
193                         h += *c;                        \
194                 (HASH) = h % (NG_NAME_HASH_SIZE);       \
195         } while (0)
196 
197 
198 /* Internal functions */
199 static int      ng_add_hook(node_p node, const char *name, hook_p * hookp);
200 static int      ng_generic_msg(node_p here, item_p item, hook_p lasthook);
201 static ng_ID_t  ng_decodeidname(const char *name);
202 static int      ngb_mod_event(module_t mod, int event, void *data);
203 static void     ng_worklist_add(node_p node);
204 static void     ngintr(void);
205 static int      ng_apply_item(node_p node, item_p item, int rw);
206 static void     ng_flush_input_queue(node_p node);
207 static node_p   ng_ID2noderef(ng_ID_t ID);
208 static int      ng_con_nodes(item_p item, node_p node, const char *name,
209                     node_p node2, const char *name2);
210 static int      ng_con_part2(node_p node, item_p item, hook_p hook);
211 static int      ng_con_part3(node_p node, item_p item, hook_p hook);
212 static int      ng_mkpeer(node_p node, const char *name,
213                                                 const char *name2, char *type);
214 
215 /* Imported, these used to be externally visible, some may go back. */
216 void    ng_destroy_hook(hook_p hook);
217 node_p  ng_name2noderef(node_p node, const char *name);
218 int     ng_path2noderef(node_p here, const char *path,
219         node_p *dest, hook_p *lasthook);
220 int     ng_make_node(const char *type, node_p *nodepp);
221 int     ng_path_parse(char *addr, char **node, char **path, char **hook);
222 void    ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3);
223 void    ng_unname(node_p node);
224 
225 
226 /* Our own netgraph malloc type */
227 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
228 MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures");
229 MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures");
230 MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures");
231 MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage");
232 
233 /* Should not be visible outside this file */
234 
235 #define _NG_ALLOC_HOOK(hook) \
236         hook = malloc(sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO)
237 #define _NG_ALLOC_NODE(node) \
238         node = malloc(sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO)
239 
240 #define NG_QUEUE_LOCK_INIT(n)                   \
241         mtx_init(&(n)->q_mtx, "ng_node", NULL, MTX_DEF)
242 #define NG_QUEUE_LOCK(n)                        \
243         mtx_lock(&(n)->q_mtx)
244 #define NG_QUEUE_UNLOCK(n)                      \
245         mtx_unlock(&(n)->q_mtx)
246 #define NG_WORKLIST_LOCK_INIT()                 \
247         mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_DEF)
248 #define NG_WORKLIST_LOCK()                      \
249         mtx_lock(&ng_worklist_mtx)
250 #define NG_WORKLIST_UNLOCK()                    \
251         mtx_unlock(&ng_worklist_mtx)
252 
253 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/
254 /*
255  * In debug mode:
256  * In an attempt to help track reference count screwups
257  * we do not free objects back to the malloc system, but keep them
258  * in a local cache where we can examine them and keep information safely
259  * after they have been freed.
260  * We use this scheme for nodes and hooks, and to some extent for items.
261  */
262 static __inline hook_p
263 ng_alloc_hook(void)
264 {
265         hook_p hook;
266         SLIST_ENTRY(ng_hook) temp;
267         mtx_lock(&ng_nodelist_mtx);
268         hook = LIST_FIRST(&ng_freehooks);
269         if (hook) {
270                 LIST_REMOVE(hook, hk_hooks);
271                 bcopy(&hook->hk_all, &temp, sizeof(temp));
272                 bzero(hook, sizeof(struct ng_hook));
273                 bcopy(&temp, &hook->hk_all, sizeof(temp));
274                 mtx_unlock(&ng_nodelist_mtx);
275                 hook->hk_magic = HK_MAGIC;
276         } else {
277                 mtx_unlock(&ng_nodelist_mtx);
278                 _NG_ALLOC_HOOK(hook);
279                 if (hook) {
280                         hook->hk_magic = HK_MAGIC;
281                         mtx_lock(&ng_nodelist_mtx);
282                         SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all);
283                         mtx_unlock(&ng_nodelist_mtx);
284                 }
285         }
286         return (hook);
287 }
288 
289 static __inline node_p
290 ng_alloc_node(void)
291 {
292         node_p node;
293         SLIST_ENTRY(ng_node) temp;
294         mtx_lock(&ng_nodelist_mtx);
295         node = LIST_FIRST(&ng_freenodes);
296         if (node) {
297                 LIST_REMOVE(node, nd_nodes);
298                 bcopy(&node->nd_all, &temp, sizeof(temp));
299                 bzero(node, sizeof(struct ng_node));
300                 bcopy(&temp, &node->nd_all, sizeof(temp));
301                 mtx_unlock(&ng_nodelist_mtx);
302                 node->nd_magic = ND_MAGIC;
303         } else {
304                 mtx_unlock(&ng_nodelist_mtx);
305                 _NG_ALLOC_NODE(node);
306                 if (node) {
307                         node->nd_magic = ND_MAGIC;
308                         mtx_lock(&ng_nodelist_mtx);
309                         SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all);
310                         mtx_unlock(&ng_nodelist_mtx);
311                 }
312         }
313         return (node);
314 }
315 
316 #define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0)
317 #define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0)
318 
319 
320 #define NG_FREE_HOOK(hook)                                              \
321         do {                                                            \
322                 mtx_lock(&ng_nodelist_mtx);                     \
323                 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks);        \
324                 hook->hk_magic = 0;                                     \
325                 mtx_unlock(&ng_nodelist_mtx);                   \
326         } while (0)
327 
328 #define NG_FREE_NODE(node)                                              \
329         do {                                                            \
330                 mtx_lock(&ng_nodelist_mtx);                     \
331                 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes);        \
332                 node->nd_magic = 0;                                     \
333                 mtx_unlock(&ng_nodelist_mtx);                   \
334         } while (0)
335 
336 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
337 
338 #define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook)
339 #define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node)
340 
341 #define NG_FREE_HOOK(hook) do { free((hook), M_NETGRAPH_HOOK); } while (0)
342 #define NG_FREE_NODE(node) do { free((node), M_NETGRAPH_NODE); } while (0)
343 
344 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/
345 
346 /* Set this to kdb_enter("X") to catch all errors as they occur */
347 #ifndef TRAP_ERROR
348 #define TRAP_ERROR()
349 #endif
350 
351 static  ng_ID_t nextID = 1;
352 
353 #ifdef INVARIANTS
354 #define CHECK_DATA_MBUF(m)      do {                                    \
355                 struct mbuf *n;                                         \
356                 int total;                                              \
357                                                                         \
358                 M_ASSERTPKTHDR(m);                                      \
359                 for (total = 0, n = (m); n != NULL; n = n->m_next) {    \
360                         total += n->m_len;                              \
361                         if (n->m_nextpkt != NULL)                       \
362                                 panic("%s: m_nextpkt", __func__);       \
363                 }                                                       \
364                                                                         \
365                 if ((m)->m_pkthdr.len != total) {                       \
366                         panic("%s: %d != %d",                           \
367                             __func__, (m)->m_pkthdr.len, total);        \
368                 }                                                       \
369         } while (0)
370 #else
371 #define CHECK_DATA_MBUF(m)
372 #endif
373 
374 #define ERROUT(x)       do { error = (x); goto done; } while (0)
375 
376 /************************************************************************
377         Parse type definitions for generic messages
378 ************************************************************************/
379 
380 /* Handy structure parse type defining macro */
381 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args)                          \
382 static const struct ng_parse_struct_field                               \
383         ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args;  \
384 static const struct ng_parse_type ng_generic_ ## lo ## _type = {        \
385         &ng_parse_struct_type,                                          \
386         &ng_ ## lo ## _type_fields                                      \
387 }
388 
389 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
390 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
391 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
392 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
393 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
394 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
395 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
396 
397 /* Get length of an array when the length is stored as a 32 bit
398    value immediately preceding the array -- as with struct namelist
399    and struct typelist. */
400 static int
401 ng_generic_list_getLength(const struct ng_parse_type *type,
402         const u_char *start, const u_char *buf)
403 {
404         return *((const u_int32_t *)(buf - 4));
405 }
406 
407 /* Get length of the array of struct linkinfo inside a struct hooklist */
408 static int
409 ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
410         const u_char *start, const u_char *buf)
411 {
412         const struct hooklist *hl = (const struct hooklist *)start;
413 
414         return hl->nodeinfo.hooks;
415 }
416 
417 /* Array type for a variable length array of struct namelist */
418 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
419         &ng_generic_nodeinfo_type,
420         &ng_generic_list_getLength
421 };
422 static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
423         &ng_parse_array_type,
424         &ng_nodeinfoarray_type_info
425 };
426 
427 /* Array type for a variable length array of struct typelist */
428 static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
429         &ng_generic_typeinfo_type,
430         &ng_generic_list_getLength
431 };
432 static const struct ng_parse_type ng_generic_typeinfoarray_type = {
433         &ng_parse_array_type,
434         &ng_typeinfoarray_type_info
435 };
436 
437 /* Array type for array of struct linkinfo in struct hooklist */
438 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
439         &ng_generic_linkinfo_type,
440         &ng_generic_linkinfo_getLength
441 };
442 static const struct ng_parse_type ng_generic_linkinfo_array_type = {
443         &ng_parse_array_type,
444         &ng_generic_linkinfo_array_type_info
445 };
446 
447 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
448 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
449         (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
450 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
451         (&ng_generic_nodeinfoarray_type));
452 
453 /* List of commands and how to convert arguments to/from ASCII */
454 static const struct ng_cmdlist ng_generic_cmds[] = {
455         {
456           NGM_GENERIC_COOKIE,
457           NGM_SHUTDOWN,
458           "shutdown",
459           NULL,
460           NULL
461         },
462         {
463           NGM_GENERIC_COOKIE,
464           NGM_MKPEER,
465           "mkpeer",
466           &ng_generic_mkpeer_type,
467           NULL
468         },
469         {
470           NGM_GENERIC_COOKIE,
471           NGM_CONNECT,
472           "connect",
473           &ng_generic_connect_type,
474           NULL
475         },
476         {
477           NGM_GENERIC_COOKIE,
478           NGM_NAME,
479           "name",
480           &ng_generic_name_type,
481           NULL
482         },
483         {
484           NGM_GENERIC_COOKIE,
485           NGM_RMHOOK,
486           "rmhook",
487           &ng_generic_rmhook_type,
488           NULL
489         },
490         {
491           NGM_GENERIC_COOKIE,
492           NGM_NODEINFO,
493           "nodeinfo",
494           NULL,
495           &ng_generic_nodeinfo_type
496         },
497         {
498           NGM_GENERIC_COOKIE,
499           NGM_LISTHOOKS,
500           "listhooks",
501           NULL,
502           &ng_generic_hooklist_type
503         },
504         {
505           NGM_GENERIC_COOKIE,
506           NGM_LISTNAMES,
507           "listnames",
508           NULL,
509           &ng_generic_listnodes_type    /* same as NGM_LISTNODES */
510         },
511         {
512           NGM_GENERIC_COOKIE,
513           NGM_LISTNODES,
514           "listnodes",
515           NULL,
516           &ng_generic_listnodes_type
517         },
518         {
519           NGM_GENERIC_COOKIE,
520           NGM_LISTTYPES,
521           "listtypes",
522           NULL,
523           &ng_generic_typeinfo_type
524         },
525         {
526           NGM_GENERIC_COOKIE,
527           NGM_TEXT_CONFIG,
528           "textconfig",
529           NULL,
530           &ng_parse_string_type
531         },
532         {
533           NGM_GENERIC_COOKIE,
534           NGM_TEXT_STATUS,
535           "textstatus",
536           NULL,
537           &ng_parse_string_type
538         },
539         {
540           NGM_GENERIC_COOKIE,
541           NGM_ASCII2BINARY,
542           "ascii2binary",
543           &ng_parse_ng_mesg_type,
544           &ng_parse_ng_mesg_type
545         },
546         {
547           NGM_GENERIC_COOKIE,
548           NGM_BINARY2ASCII,
549           "binary2ascii",
550           &ng_parse_ng_mesg_type,
551           &ng_parse_ng_mesg_type
552         },
553         { 0 }
554 };
555 
556 /************************************************************************
557                         Node routines
558 ************************************************************************/
559 
560 /*
561  * Instantiate a node of the requested type
562  */
563 int
564 ng_make_node(const char *typename, node_p *nodepp)
565 {
566         struct ng_type *type;
567         int     error;
568 
569         /* Check that the type makes sense */
570         if (typename == NULL) {
571                 TRAP_ERROR();
572                 return (EINVAL);
573         }
574 
575         /* Locate the node type. If we fail we return. Do not try to load
576          * module.
577          */
578         if ((type = ng_findtype(typename)) == NULL)
579                 return (ENXIO);
580 
581         /*
582          * If we have a constructor, then make the node and
583          * call the constructor to do type specific initialisation.
584          */
585         if (type->constructor != NULL) {
586                 if ((error = ng_make_node_common(type, nodepp)) == 0) {
587                         if ((error = ((*type->constructor)(*nodepp)) != 0)) {
588                                 NG_NODE_UNREF(*nodepp);
589                         }
590                 }
591         } else {
592                 /*
593                  * Node has no constructor. We cannot ask for one
594                  * to be made. It must be brought into existence by
595                  * some external agency. The external agency should
596                  * call ng_make_node_common() directly to get the
597                  * netgraph part initialised.
598                  */
599                 TRAP_ERROR();
600                 error = EINVAL;
601         }
602         return (error);
603 }
604 
605 /*
606  * Generic node creation. Called by node initialisation for externally
607  * instantiated nodes (e.g. hardware, sockets, etc ).
608  * The returned node has a reference count of 1.
609  */
610 int
611 ng_make_node_common(struct ng_type *type, node_p *nodepp)
612 {
613         INIT_VNET_NETGRAPH(curvnet);
614         node_p node;
615 
616         /* Require the node type to have been already installed */
617         if (ng_findtype(type->name) == NULL) {
618                 TRAP_ERROR();
619                 return (EINVAL);
620         }
621 
622         /* Make a node and try attach it to the type */
623         NG_ALLOC_NODE(node);
624         if (node == NULL) {
625                 TRAP_ERROR();
626                 return (ENOMEM);
627         }
628         node->nd_type = type;
629         NG_NODE_REF(node);                              /* note reference */
630         type->refs++;
631 
632         NG_QUEUE_LOCK_INIT(&node->nd_input_queue);
633         STAILQ_INIT(&node->nd_input_queue.queue);
634         node->nd_input_queue.q_flags = 0;
635 
636         /* Initialize hook list for new node */
637         LIST_INIT(&node->nd_hooks);
638 
639         /* Link us into the name hash. */
640         mtx_lock(&ng_namehash_mtx);
641         LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes);
642         mtx_unlock(&ng_namehash_mtx);
643 
644         /* get an ID and put us in the hash chain */
645         mtx_lock(&ng_idhash_mtx);
646         for (;;) { /* wrap protection, even if silly */
647                 node_p node2 = NULL;
648                 node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */
649 
650                 /* Is there a problem with the new number? */
651                 NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */
652                 if ((node->nd_ID != 0) && (node2 == NULL)) {
653                         break;
654                 }
655         }
656         LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)],
657                                                         node, nd_idnodes);
658         mtx_unlock(&ng_idhash_mtx);
659 
660         /* Done */
661         *nodepp = node;
662         return (0);
663 }
664 
665 /*
666  * Forceably start the shutdown process on a node. Either call
667  * its shutdown method, or do the default shutdown if there is
668  * no type-specific method.
669  *
670  * We can only be called from a shutdown message, so we know we have
671  * a writer lock, and therefore exclusive access. It also means
672  * that we should not be on the work queue, but we check anyhow.
673  *
674  * Persistent node types must have a type-specific method which
675  * allocates a new node in which case, this one is irretrievably going away,
676  * or cleans up anything it needs, and just makes the node valid again,
677  * in which case we allow the node to survive.
678  *
679  * XXX We need to think of how to tell a persistent node that we
680  * REALLY need to go away because the hardware has gone or we
681  * are rebooting.... etc.
682  */
683 void
684 ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3)
685 {
686         hook_p hook;
687 
688         /* Check if it's already shutting down */
689         if ((node->nd_flags & NGF_CLOSING) != 0)
690                 return;
691 
692         if (node == &ng_deadnode) {
693                 printf ("shutdown called on deadnode\n");
694                 return;
695         }
696 
697         /* Add an extra reference so it doesn't go away during this */
698         NG_NODE_REF(node);
699 
700         /*
701          * Mark it invalid so any newcomers know not to try use it
702          * Also add our own mark so we can't recurse
703          * note that NGF_INVALID does not do this as it's also set during
704          * creation
705          */
706         node->nd_flags |= NGF_INVALID|NGF_CLOSING;
707 
708         /* If node has its pre-shutdown method, then call it first*/
709         if (node->nd_type && node->nd_type->close)
710                 (*node->nd_type->close)(node);
711 
712         /* Notify all remaining connected nodes to disconnect */
713         while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL)
714                 ng_destroy_hook(hook);
715 
716         /*
717          * Drain the input queue forceably.
718          * it has no hooks so what's it going to do, bleed on someone?
719          * Theoretically we came here from a queue entry that was added
720          * Just before the queue was closed, so it should be empty anyway.
721          * Also removes us from worklist if needed.
722          */
723         ng_flush_input_queue(node);
724 
725         /* Ask the type if it has anything to do in this case */
726         if (node->nd_type && node->nd_type->shutdown) {
727                 (*node->nd_type->shutdown)(node);
728                 if (NG_NODE_IS_VALID(node)) {
729                         /*
730                          * Well, blow me down if the node code hasn't declared
731                          * that it doesn't want to die.
732                          * Presumably it is a persistant node.
733                          * If we REALLY want it to go away,
734                          *  e.g. hardware going away,
735                          * Our caller should set NGF_REALLY_DIE in nd_flags.
736                          */
737                         node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING);
738                         NG_NODE_UNREF(node); /* Assume they still have theirs */
739                         return;
740                 }
741         } else {                                /* do the default thing */
742                 NG_NODE_UNREF(node);
743         }
744 
745         ng_unname(node); /* basically a NOP these days */
746 
747         /*
748          * Remove extra reference, possibly the last
749          * Possible other holders of references may include
750          * timeout callouts, but theoretically the node's supposed to
751          * have cancelled them. Possibly hardware dependencies may
752          * force a driver to 'linger' with a reference.
753          */
754         NG_NODE_UNREF(node);
755 }
756 
757 /*
758  * Remove a reference to the node, possibly the last.
759  * deadnode always acts as it it were the last.
760  */
761 int
762 ng_unref_node(node_p node)
763 {
764         int v;
765 
766         if (node == &ng_deadnode) {
767                 return (0);
768         }
769 
770         v = atomic_fetchadd_int(&node->nd_refs, -1);
771 
772         if (v == 1) { /* we were the last */
773 
774                 mtx_lock(&ng_namehash_mtx);
775                 node->nd_type->refs--; /* XXX maybe should get types lock? */
776                 LIST_REMOVE(node, nd_nodes);
777                 mtx_unlock(&ng_namehash_mtx);
778 
779                 mtx_lock(&ng_idhash_mtx);
780                 LIST_REMOVE(node, nd_idnodes);
781                 mtx_unlock(&ng_idhash_mtx);
782 
783                 mtx_destroy(&node->nd_input_queue.q_mtx);
784                 NG_FREE_NODE(node);
785         }
786         return (v - 1);
787 }
788 
789 /************************************************************************
790                         Node ID handling
791 ************************************************************************/
792 static node_p
793 ng_ID2noderef(ng_ID_t ID)
794 {
795         INIT_VNET_NETGRAPH(curvnet);
796         node_p node;
797         mtx_lock(&ng_idhash_mtx);
798         NG_IDHASH_FIND(ID, node);
799         if(node)
800                 NG_NODE_REF(node);
801         mtx_unlock(&ng_idhash_mtx);
802         return(node);
803 }
804 
805 ng_ID_t
806 ng_node2ID(node_p node)
807 {
808         return (node ? NG_NODE_ID(node) : 0);
809 }
810 
811 /************************************************************************
812                         Node name handling
813 ************************************************************************/
814 
815 /*
816  * Assign a node a name. Once assigned, the name cannot be changed.
817  */
818 int
819 ng_name_node(node_p node, const char *name)
820 {
821         INIT_VNET_NETGRAPH(curvnet);
822         int i, hash;
823         node_p node2;
824 
825         /* Check the name is valid */
826         for (i = 0; i < NG_NODESIZ; i++) {
827                 if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
828                         break;
829         }
830         if (i == 0 || name[i] != '\0') {
831                 TRAP_ERROR();
832                 return (EINVAL);
833         }
834         if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
835                 TRAP_ERROR();
836                 return (EINVAL);
837         }
838 
839         /* Check the name isn't already being used */
840         if ((node2 = ng_name2noderef(node, name)) != NULL) {
841                 NG_NODE_UNREF(node2);
842                 TRAP_ERROR();
843                 return (EADDRINUSE);
844         }
845 
846         /* copy it */
847         strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ);
848 
849         /* Update name hash. */
850         NG_NAMEHASH(name, hash);
851         mtx_lock(&ng_namehash_mtx);
852         LIST_REMOVE(node, nd_nodes);
853         LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes);
854         mtx_unlock(&ng_namehash_mtx);
855 
856         return (0);
857 }
858 
859 /*
860  * Find a node by absolute name. The name should NOT end with ':'
861  * The name "." means "this node" and "[xxx]" means "the node
862  * with ID (ie, at address) xxx".
863  *
864  * Returns the node if found, else NULL.
865  * Eventually should add something faster than a sequential search.
866  * Note it acquires a reference on the node so you can be sure it's still
867  * there.
868  */
869 node_p
870 ng_name2noderef(node_p here, const char *name)
871 {
872         INIT_VNET_NETGRAPH(curvnet);
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, &V_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  */
907 static ng_ID_t
908 ng_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  */
937 void
938 ng_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  */
952 void
953 ng_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  */
974 static int
975 ng_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