dad04926cfc75caab7738067e61ff71503072fbf
[dragonfly.git] / sys / netgraph / netgraph / ng_base.c
1
2 /*
3  * ng_base.c
4  *
5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6  * All rights reserved.
7  * 
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  * 
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Authors: Julian Elischer <julian@freebsd.org>
38  *          Archie Cobbs <archie@freebsd.org>
39  *
40  * $FreeBSD: src/sys/netgraph/ng_base.c,v 1.11.2.17 2002/07/02 23:44:02 archie Exp $
41  * $DragonFly: src/sys/netgraph/netgraph/ng_base.c,v 1.28 2008/09/24 14:26:39 sephe 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/errno.h>
52 #include <sys/kernel.h>
53 #include <sys/malloc.h>
54 #include <sys/syslog.h>
55 #include <sys/linker.h>
56 #include <sys/queue.h>
57 #include <sys/mbuf.h>
58 #include <sys/ctype.h>
59 #include <sys/sysctl.h>
60 #include <sys/vnode.h>
61 #include <machine/limits.h>
62
63 #include <sys/thread2.h>
64 #include <sys/msgport2.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
72 MODULE_VERSION(netgraph, NG_ABI_VERSION);
73
74 /* List of all nodes */
75 static LIST_HEAD(, ng_node) nodelist;
76
77 /* List of installed types */
78 static LIST_HEAD(, ng_type) typelist;
79
80 /* Hash releted definitions */
81 #define ID_HASH_SIZE 32 /* most systems wont need even this many */
82 static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE];
83 /* Don't nead to initialise them because it's a LIST */
84
85 /* Internal functions */
86 static int      ng_add_hook(node_p node, const char *name, hook_p * hookp);
87 static int      ng_connect(hook_p hook1, hook_p hook2);
88 static void     ng_disconnect_hook(hook_p hook);
89 static int      ng_generic_msg(node_p here, struct ng_mesg *msg,
90                         const char *retaddr, struct ng_mesg ** resp);
91 static ng_ID_t  ng_decodeidname(const char *name);
92 static int      ngb_mod_event(module_t mod, int event, void *data);
93 static void     ngintr(struct netmsg *);
94 static int      ng_load_module(const char *);
95 static int      ng_unload_module(const char *);
96
97 /* Our own netgraph malloc type */
98 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
99
100 /* Set this to Debugger("X") to catch all errors as they occur */
101 #ifndef TRAP_ERROR
102 #define TRAP_ERROR
103 #endif
104
105 static  ng_ID_t nextID = 1;
106
107 #ifdef INVARIANTS
108 #define CHECK_DATA_MBUF(m)      do {                                    \
109                 struct mbuf *n;                                         \
110                 int total;                                              \
111                                                                         \
112                 if (((m)->m_flags & M_PKTHDR) == 0)                     \
113                         panic("%s: !PKTHDR", __func__);         \
114                 for (total = 0, n = (m); n != NULL; n = n->m_next)      \
115                         total += n->m_len;                              \
116                 if ((m)->m_pkthdr.len != total) {                       \
117                         panic("%s: %d != %d",                           \
118                             __func__, (m)->m_pkthdr.len, total);        \
119                 }                                                       \
120         } while (0)
121 #else
122 #define CHECK_DATA_MBUF(m)
123 #endif
124
125
126 /************************************************************************
127         Parse type definitions for generic messages
128 ************************************************************************/
129
130 /* Handy structure parse type defining macro */
131 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args)                          \
132 static const struct ng_parse_struct_field                               \
133         ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args;  \
134 static const struct ng_parse_type ng_generic_ ## lo ## _type = {        \
135         &ng_parse_struct_type,                                          \
136         &ng_ ## lo ## _type_fields                                      \
137 }
138
139 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
140 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
141 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
142 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
143 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
144 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
145 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
146
147 /* Get length of an array when the length is stored as a 32 bit
148    value immediately preceeding the array -- as with struct namelist
149    and struct typelist. */
150 static int
151 ng_generic_list_getLength(const struct ng_parse_type *type,
152         const u_char *start, const u_char *buf)
153 {
154         return *((const u_int32_t *)(buf - 4));
155 }
156
157 /* Get length of the array of struct linkinfo inside a struct hooklist */
158 static int
159 ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
160         const u_char *start, const u_char *buf)
161 {
162         const struct hooklist *hl = (const struct hooklist *)start;
163
164         return hl->nodeinfo.hooks;
165 }
166
167 /* Array type for a variable length array of struct namelist */
168 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
169         &ng_generic_nodeinfo_type,
170         &ng_generic_list_getLength
171 };
172 static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
173         &ng_parse_array_type,
174         &ng_nodeinfoarray_type_info
175 };
176
177 /* Array type for a variable length array of struct typelist */
178 static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
179         &ng_generic_typeinfo_type,
180         &ng_generic_list_getLength
181 };
182 static const struct ng_parse_type ng_generic_typeinfoarray_type = {
183         &ng_parse_array_type,
184         &ng_typeinfoarray_type_info
185 };
186
187 /* Array type for array of struct linkinfo in struct hooklist */
188 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
189         &ng_generic_linkinfo_type,
190         &ng_generic_linkinfo_getLength
191 };
192 static const struct ng_parse_type ng_generic_linkinfo_array_type = {
193         &ng_parse_array_type,
194         &ng_generic_linkinfo_array_type_info
195 };
196
197 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
198 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
199         (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
200 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
201         (&ng_generic_nodeinfoarray_type));
202
203 /* List of commands and how to convert arguments to/from ASCII */
204 static const struct ng_cmdlist ng_generic_cmds[] = {
205         {
206           NGM_GENERIC_COOKIE,
207           NGM_SHUTDOWN,
208           "shutdown",
209           NULL,
210           NULL
211         },
212         {
213           NGM_GENERIC_COOKIE,
214           NGM_MKPEER,
215           "mkpeer",
216           &ng_generic_mkpeer_type,
217           NULL
218         },
219         {
220           NGM_GENERIC_COOKIE,
221           NGM_CONNECT,
222           "connect",
223           &ng_generic_connect_type,
224           NULL
225         },
226         {
227           NGM_GENERIC_COOKIE,
228           NGM_NAME,
229           "name",
230           &ng_generic_name_type,
231           NULL
232         },
233         {
234           NGM_GENERIC_COOKIE,
235           NGM_RMHOOK,
236           "rmhook",
237           &ng_generic_rmhook_type,
238           NULL
239         },
240         {
241           NGM_GENERIC_COOKIE,
242           NGM_NODEINFO,
243           "nodeinfo",
244           NULL,
245           &ng_generic_nodeinfo_type
246         },
247         {
248           NGM_GENERIC_COOKIE,
249           NGM_LISTHOOKS,
250           "listhooks",
251           NULL,
252           &ng_generic_hooklist_type
253         },
254         {
255           NGM_GENERIC_COOKIE,
256           NGM_LISTNAMES,
257           "listnames",
258           NULL,
259           &ng_generic_listnodes_type    /* same as NGM_LISTNODES */
260         },
261         {
262           NGM_GENERIC_COOKIE,
263           NGM_LISTNODES,
264           "listnodes",
265           NULL,
266           &ng_generic_listnodes_type
267         },
268         {
269           NGM_GENERIC_COOKIE,
270           NGM_LISTTYPES,
271           "listtypes",
272           NULL,
273           &ng_generic_typeinfo_type
274         },
275         {
276           NGM_GENERIC_COOKIE,
277           NGM_TEXT_CONFIG,
278           "textconfig",
279           NULL,
280           &ng_parse_string_type
281         },
282         {
283           NGM_GENERIC_COOKIE,
284           NGM_TEXT_STATUS,
285           "textstatus",
286           NULL,
287           &ng_parse_string_type
288         },
289         {
290           NGM_GENERIC_COOKIE,
291           NGM_ASCII2BINARY,
292           "ascii2binary",
293           &ng_parse_ng_mesg_type,
294           &ng_parse_ng_mesg_type
295         },
296         {
297           NGM_GENERIC_COOKIE,
298           NGM_BINARY2ASCII,
299           "binary2ascii",
300           &ng_parse_ng_mesg_type,
301           &ng_parse_ng_mesg_type
302         },
303         { 0 }
304 };
305
306 /************************************************************************
307                         Node routines
308 ************************************************************************/
309
310 static int
311 linker_api_available(void)
312 {
313         /* linker_* API won't work without a process context */
314         if (curproc == NULL)
315                 return 0;
316         /*
317          * nlookup_init() relies on namei_oc to be initialized,
318          * but it's not when the netgraph module is loaded during boot.
319          */
320         if (namei_oc == NULL)
321                 return 0;
322         return 1;
323 }
324
325 static int
326 ng_load_module(const char *name)
327 {
328         char *path, filename[NG_TYPESIZ + 3];
329         linker_file_t lf;
330         int error;
331
332         if (!linker_api_available())
333                 return (ENXIO);
334
335         /* Not found, try to load it as a loadable module */
336         ksnprintf(filename, sizeof(filename), "ng_%s.ko", name);
337         if ((path = linker_search_path(filename)) == NULL)
338                 return (ENXIO);
339         error = linker_load_file(path, &lf);
340         FREE(path, M_LINKER);
341         if (error == 0)
342                 lf->userrefs++;         /* pretend kldload'ed */
343         return (error);
344 }
345
346 static int
347 ng_unload_module(const char *name)
348 {
349         char filename[NG_TYPESIZ + 3];
350         linker_file_t lf;
351         int error;
352
353         if (!linker_api_available())
354                 return (ENXIO);
355
356         /* Not found, try to load it as a loadable module */
357         ksnprintf(filename, sizeof(filename), "ng_%s.ko", name);
358         if ((lf = linker_find_file_by_name(filename)) == NULL)
359                 return (ENXIO);
360         lf->userrefs--;         /* pretend kldunload'ed */
361         error = linker_file_unload(lf);
362         if (error)
363                 lf->userrefs++;
364
365         return (error);
366 }
367
368 /*
369  * Instantiate a node of the requested type
370  */
371 int
372 ng_make_node(const char *typename, node_p *nodepp)
373 {
374         struct ng_type *type;
375
376         /* Check that the type makes sense */
377         if (typename == NULL) {
378                 TRAP_ERROR;
379                 return (EINVAL);
380         }
381
382         /* Locate the node type */
383         if ((type = ng_findtype(typename)) == NULL)
384                 return (ENXIO);
385
386         /* Call the constructor */
387         if (type->constructor != NULL)
388                 return ((*type->constructor)(nodepp));
389         else
390                 return (ng_make_node_common(type, nodepp));
391 }
392
393 /*
394  * Generic node creation. Called by node constructors.
395  * The returned node has a reference count of 1.
396  */
397 int
398 ng_make_node_common(struct ng_type *type, node_p *nodepp)
399 {
400         node_p node;
401
402         /* Require the node type to have been already installed */
403         if (ng_findtype(type->name) == NULL) {
404                 TRAP_ERROR;
405                 return (EINVAL);
406         }
407
408         /* Make a node and try attach it to the type */
409         MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_NOWAIT | M_ZERO);
410         if (node == NULL) {
411                 TRAP_ERROR;
412                 return (ENOMEM);
413         }
414         node->type = type;
415         node->refs++;                           /* note reference */
416         type->refs++;
417
418         /* Link us into the node linked list */
419         LIST_INSERT_HEAD(&nodelist, node, nodes);
420
421         /* Initialize hook list for new node */
422         LIST_INIT(&node->hooks);
423
424         /* get an ID and put us in the hash chain */
425         node->ID = nextID++; /* 137 per second for 1 year before wrap */
426         LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes);
427
428         /* Done */
429         *nodepp = node;
430         return (0);
431 }
432
433 /*
434  * Forceably start the shutdown process on a node. Either call
435  * it's shutdown method, or do the default shutdown if there is
436  * no type-specific method.
437  *
438  * Persistent nodes must have a type-specific method which
439  * resets the NG_INVALID flag.
440  */
441 void
442 ng_rmnode(node_p node)
443 {
444         /* Check if it's already shutting down */
445         if ((node->flags & NG_INVALID) != 0)
446                 return;
447
448         /* Add an extra reference so it doesn't go away during this */
449         node->refs++;
450
451         /* Mark it invalid so any newcomers know not to try use it */
452         node->flags |= NG_INVALID;
453
454         /* Ask the type if it has anything to do in this case */
455         if (node->type && node->type->shutdown)
456                 (*node->type->shutdown)(node);
457         else {                          /* do the default thing */
458                 ng_unname(node);
459                 ng_cutlinks(node);
460                 ng_unref(node);
461         }
462
463         /* Remove extra reference, possibly the last */
464         ng_unref(node);
465 }
466
467 /*
468  * Called by the destructor to remove any STANDARD external references
469  */
470 void
471 ng_cutlinks(node_p node)
472 {
473         hook_p  hook;
474
475         /* Make sure that this is set to stop infinite loops */
476         node->flags |= NG_INVALID;
477
478         /* If we have sleepers, wake them up; they'll see NG_INVALID */
479         if (node->sleepers)
480                 wakeup(node);
481
482         /* Notify all remaining connected nodes to disconnect */
483         while ((hook = LIST_FIRST(&node->hooks)) != NULL)
484                 ng_destroy_hook(hook);
485 }
486
487 /*
488  * Remove a reference to the node, possibly the last
489  */
490 void
491 ng_unref(node_p node)
492 {
493         crit_enter();
494         if (--node->refs <= 0) {
495                 node->type->refs--;
496                 LIST_REMOVE(node, nodes);
497                 LIST_REMOVE(node, idnodes);
498                 FREE(node, M_NETGRAPH);
499         }
500         crit_exit();
501 }
502
503 /*
504  * Wait for a node to come ready. Returns a node with a reference count;
505  * don't forget to drop it when we are done with it using ng_release_node().
506  */
507 int
508 ng_wait_node(node_p node, char *msg)
509 {
510         int error = 0;
511
512         if (msg == NULL)
513                 msg = "netgraph";
514         crit_enter();
515         node->sleepers++;
516         node->refs++;           /* the sleeping process counts as a reference */
517         while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY)
518                 error = tsleep(node, PCATCH, msg, 0);
519         node->sleepers--;
520         if (node->flags & NG_INVALID) {
521                 TRAP_ERROR;
522                 error = ENXIO;
523         } else {
524                 KASSERT(node->refs > 1,
525                     ("%s: refs=%d", __func__, node->refs));
526                 node->flags |= NG_BUSY;
527         }
528         crit_exit();
529
530         /* Release the reference we had on it */
531         if (error != 0)
532                 ng_unref(node);
533         return error;
534 }
535
536 /*
537  * Release a node acquired via ng_wait_node()
538  */
539 void
540 ng_release_node(node_p node)
541 {
542         /* Declare that we don't want it */
543         node->flags &= ~NG_BUSY;
544
545         /* If we have sleepers, then wake them up */
546         if (node->sleepers)
547                 wakeup(node);
548
549         /* We also have a reference.. drop it too */
550         ng_unref(node);
551 }
552
553 /************************************************************************
554                         Node ID handling
555 ************************************************************************/
556 static node_p
557 ng_ID2node(ng_ID_t ID)
558 {
559         node_p np;
560         LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) {
561                 if ((np->flags & NG_INVALID) == 0 && np->ID == ID)
562                         break;
563         }
564         return(np);
565 }
566
567 ng_ID_t
568 ng_node2ID(node_p node)
569 {
570         return (node->ID);
571 }
572
573 /************************************************************************
574                         Node name handling
575 ************************************************************************/
576
577 /*
578  * Assign a node a name. Once assigned, the name cannot be changed.
579  */
580 int
581 ng_name_node(node_p node, const char *name)
582 {
583         int i;
584
585         /* Check the name is valid */
586         for (i = 0; i < NG_NODESIZ; i++) {
587                 if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
588                         break;
589         }
590         if (i == 0 || name[i] != '\0') {
591                 TRAP_ERROR;
592                 return (EINVAL);
593         }
594         if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
595                 TRAP_ERROR;
596                 return (EINVAL);
597         }
598
599         /* Check the node isn't already named */
600         if (node->name != NULL) {
601                 TRAP_ERROR;
602                 return (EISCONN);
603         }
604
605         /* Check the name isn't already being used */
606         if (ng_findname(node, name) != NULL) {
607                 TRAP_ERROR;
608                 return (EADDRINUSE);
609         }
610
611         /* Allocate space and copy it */
612         MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT);
613         if (node->name == NULL) {
614                 TRAP_ERROR;
615                 return (ENOMEM);
616         }
617         strcpy(node->name, name);
618
619         /* The name counts as a reference */
620         node->refs++;
621         return (0);
622 }
623
624 /*
625  * Find a node by absolute name. The name should NOT end with ':'
626  * The name "." means "this node" and "[xxx]" means "the node
627  * with ID (ie, at address) xxx".
628  *
629  * Returns the node if found, else NULL.
630  */
631 node_p
632 ng_findname(node_p this, const char *name)
633 {
634         node_p node;
635         ng_ID_t temp;
636
637         /* "." means "this node" */
638         if (strcmp(name, ".") == 0)
639                 return(this);
640
641         /* Check for name-by-ID */
642         if ((temp = ng_decodeidname(name)) != 0) {
643                 return (ng_ID2node(temp));
644         }
645
646         /* Find node by name */
647         LIST_FOREACH(node, &nodelist, nodes) {
648                 if ((node->name != NULL)
649                 && (strcmp(node->name, name) == 0)
650                 && ((node->flags & NG_INVALID) == 0))
651                         break;
652         }
653         return (node);
654 }
655
656 /*
657  * Decode a ID name, eg. "[f03034de]". Returns 0 if the
658  * string is not valid, otherwise returns the value.
659  */
660 static ng_ID_t
661 ng_decodeidname(const char *name)
662 {
663         const int len = strlen(name);
664         char *eptr;
665         u_long val;
666
667         /* Check for proper length, brackets, no leading junk */
668         if (len < 3 || name[0] != '[' || name[len - 1] != ']'
669             || !isxdigit(name[1]))
670                 return (0);
671
672         /* Decode number */
673         val = strtoul(name + 1, &eptr, 16);
674         if (eptr - name != len - 1 || val == ULONG_MAX || val == 0)
675                 return ((ng_ID_t)0);
676         return (ng_ID_t)val;
677 }
678
679 /*
680  * Remove a name from a node. This should only be called
681  * when shutting down and removing the node.
682  */
683 void
684 ng_unname(node_p node)
685 {
686         if (node->name) {
687                 FREE(node->name, M_NETGRAPH);
688                 node->name = NULL;
689                 ng_unref(node);
690         }
691 }
692
693 /************************************************************************
694                         Hook routines
695
696  Names are not optional. Hooks are always connected, except for a
697  brief moment within these routines.
698
699 ************************************************************************/
700
701 /*
702  * Remove a hook reference
703  */
704 void
705 ng_unref_hook(hook_p hook)
706 {
707         crit_enter();
708         if (--hook->refs == 0)
709                 FREE(hook, M_NETGRAPH);
710         crit_exit();
711 }
712
713 /*
714  * Add an unconnected hook to a node. Only used internally.
715  */
716 static int
717 ng_add_hook(node_p node, const char *name, hook_p *hookp)
718 {
719         hook_p hook;
720         int error = 0;
721
722         /* Check that the given name is good */
723         if (name == NULL) {
724                 TRAP_ERROR;
725                 return (EINVAL);
726         }
727         if (ng_findhook(node, name) != NULL) {
728                 TRAP_ERROR;
729                 return (EEXIST);
730         }
731
732         /* Allocate the hook and link it up */
733         MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_NOWAIT | M_ZERO);
734         if (hook == NULL) {
735                 TRAP_ERROR;
736                 return (ENOMEM);
737         }
738         hook->refs = 1;
739         hook->flags = HK_INVALID;
740         hook->node = node;
741         node->refs++;           /* each hook counts as a reference */
742
743         /* Check if the node type code has something to say about it */
744         if (node->type->newhook != NULL)
745                 if ((error = (*node->type->newhook)(node, hook, name)) != 0)
746                         goto fail;
747
748         /*
749          * The 'type' agrees so far, so go ahead and link it in.
750          * We'll ask again later when we actually connect the hooks.
751          */
752         LIST_INSERT_HEAD(&node->hooks, hook, hooks);
753         node->numhooks++;
754
755         /* Set hook name */
756         MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT);
757         if (hook->name == NULL) {
758                 error = ENOMEM;
759                 LIST_REMOVE(hook, hooks);
760                 node->numhooks--;
761 fail:
762                 hook->node = NULL;
763                 ng_unref(node);
764                 ng_unref_hook(hook);    /* this frees the hook */
765                 return (error);
766         }
767         strcpy(hook->name, name);
768         if (hookp)
769                 *hookp = hook;
770         return (error);
771 }
772
773 /*
774  * Connect a pair of hooks. Only used internally.
775  */
776 static int
777 ng_connect(hook_p hook1, hook_p hook2)
778 {
779         int     error;
780
781         hook1->peer = hook2;
782         hook2->peer = hook1;
783
784         /* Give each node the opportunity to veto the impending connection */
785         if (hook1->node->type->connect) {
786                 if ((error = (*hook1->node->type->connect) (hook1))) {
787                         ng_destroy_hook(hook1); /* also zaps hook2 */
788                         return (error);
789                 }
790         }
791         if (hook2->node->type->connect) {
792                 if ((error = (*hook2->node->type->connect) (hook2))) {
793                         ng_destroy_hook(hook2); /* also zaps hook1 */
794                         return (error);
795                 }
796         }
797         hook1->flags &= ~HK_INVALID;
798         hook2->flags &= ~HK_INVALID;
799         return (0);
800 }
801
802 /*
803  * Find a hook
804  *
805  * Node types may supply their own optimized routines for finding
806  * hooks.  If none is supplied, we just do a linear search.
807  */
808 hook_p
809 ng_findhook(node_p node, const char *name)
810 {
811         hook_p hook;
812
813         if (node->type->findhook != NULL)
814                 return (*node->type->findhook)(node, name);
815         LIST_FOREACH(hook, &node->hooks, hooks) {
816                 if (hook->name != NULL
817                     && strcmp(hook->name, name) == 0
818                     && (hook->flags & HK_INVALID) == 0)
819                         return (hook);
820         }
821         return (NULL);
822 }
823
824 /*
825  * Destroy a hook
826  *
827  * As hooks are always attached, this really destroys two hooks.
828  * The one given, and the one attached to it. Disconnect the hooks
829  * from each other first.
830  */
831 void
832 ng_destroy_hook(hook_p hook)
833 {
834         hook_p peer = hook->peer;
835
836         hook->flags |= HK_INVALID;              /* as soon as possible */
837         if (peer) {
838                 peer->flags |= HK_INVALID;      /* as soon as possible */
839                 hook->peer = NULL;
840                 peer->peer = NULL;
841                 ng_disconnect_hook(peer);
842         }
843         ng_disconnect_hook(hook);
844 }
845
846 /*
847  * Notify the node of the hook's demise. This may result in more actions
848  * (e.g. shutdown) but we don't do that ourselves and don't know what
849  * happens there. If there is no appropriate handler, then just remove it
850  * (and decrement the reference count of it's node which in turn might
851  * make something happen).
852  */
853 static void
854 ng_disconnect_hook(hook_p hook)
855 {
856         node_p node = hook->node;
857
858         /*
859          * Remove the hook from the node's list to avoid possible recursion
860          * in case the disconnection results in node shutdown.
861          */
862         LIST_REMOVE(hook, hooks);
863         node->numhooks--;
864         if (node->type->disconnect) {
865                 /*
866                  * The type handler may elect to destroy the peer so don't
867                  * trust its existance after this point.
868                  */
869                 (*node->type->disconnect) (hook);
870         }
871         ng_unref(node);         /* might be the last reference */
872         if (hook->name)
873                 FREE(hook->name, M_NETGRAPH);
874         hook->node = NULL;      /* may still be referenced elsewhere */
875         ng_unref_hook(hook);
876 }
877
878 /*
879  * Take two hooks on a node and merge the connection so that the given node
880  * is effectively bypassed.
881  */
882 int
883 ng_bypass(hook_p hook1, hook_p hook2)
884 {
885         if (hook1->node != hook2->node)
886                 return (EINVAL);
887         hook1->peer->peer = hook2->peer;
888         hook2->peer->peer = hook1->peer;
889
890         /* XXX If we ever cache methods on hooks update them as well */
891         hook1->peer = NULL;
892         hook2->peer = NULL;
893         ng_destroy_hook(hook1);
894         ng_destroy_hook(hook2);
895         return (0);
896 }
897
898 /*
899  * Install a new netgraph type
900  */
901 int
902 ng_newtype(struct ng_type *tp)
903 {
904         const size_t namelen = strlen(tp->name);
905
906         /* Check version and type name fields */
907         if (tp->version != NG_VERSION || namelen == 0 || namelen >= NG_TYPESIZ) {
908                 TRAP_ERROR;
909                 return (EINVAL);
910         }
911
912         /* Check for name collision */
913         if (ng_findtype(tp->name) != NULL) {
914                 TRAP_ERROR;
915                 return (EEXIST);
916         }
917
918         /* Link in new type */
919         LIST_INSERT_HEAD(&typelist, tp, types);
920         tp->refs = 1;   /* first ref is linked list */
921         return (0);
922 }
923
924 /*
925  * Look for a type of the name given
926  */
927 struct ng_type *
928 ng_findtype(const char *typename)
929 {
930         struct ng_type *type;
931
932         LIST_FOREACH(type, &typelist, types) {
933                 if (strcmp(type->name, typename) == 0)
934                         break;
935         }
936         return (type);
937 }
938
939
940 /************************************************************************
941                         Composite routines
942 ************************************************************************/
943
944 /*
945  * Make a peer and connect. The order is arranged to minimise
946  * the work needed to back out in case of error.
947  */
948 int
949 ng_mkpeer(node_p node, const char *name, const char *name2, char *type)
950 {
951         node_p  node2;
952         hook_p  hook;
953         hook_p  hook2;
954         int     error;
955
956         if ((error = ng_add_hook(node, name, &hook)))
957                 return (error);
958
959         /* make sure we have the module needed */
960         if (ng_findtype(type) == NULL) {
961                 /* Not found, try to load it as a loadable module */
962                 error = ng_load_module(type);
963                 if (error != 0) {
964                         kprintf("required netgraph module ng_%s not loaded\n",
965                             type);
966                         return (error);
967                 }
968         }
969         if ((error = ng_make_node(type, &node2))) {
970                 ng_destroy_hook(hook);
971                 return (error);
972         }
973         if ((error = ng_add_hook(node2, name2, &hook2))) {
974                 ng_rmnode(node2);
975                 ng_destroy_hook(hook);
976                 return (error);
977         }
978
979         /*
980          * Actually link the two hooks together.. on failure they are
981          * destroyed so we don't have to do that here.
982          */
983         if ((error = ng_connect(hook, hook2)))
984                 ng_rmnode(node2);
985         return (error);
986 }
987
988 /*
989  * Connect two nodes using the specified hooks
990  */
991 int
992 ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2)
993 {
994         int     error;
995         hook_p  hook;
996         hook_p  hook2;
997
998         if ((error = ng_add_hook(node, name, &hook)))
999                 return (error);
1000         if ((error = ng_add_hook(node2, name2, &hook2))) {
1001                 ng_destroy_hook(hook);
1002                 return (error);
1003         }
1004         return (ng_connect(hook, hook2));
1005 }
1006
1007 /*
1008  * Parse and verify a string of the form:  <NODE:><PATH>
1009  *
1010  * Such a string can refer to a specific node or a specific hook
1011  * on a specific node, depending on how you look at it. In the
1012  * latter case, the PATH component must not end in a dot.
1013  *
1014  * Both <NODE:> and <PATH> are optional. The <PATH> is a string
1015  * of hook names separated by dots. This breaks out the original
1016  * string, setting *nodep to "NODE" (or NULL if none) and *pathp
1017  * to "PATH" (or NULL if degenerate). Also, *hookp will point to
1018  * the final hook component of <PATH>, if any, otherwise NULL.
1019  *
1020  * This returns -1 if the path is malformed. The char ** are optional.
1021  */
1022
1023 int
1024 ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp)
1025 {
1026         char   *node, *path, *hook;
1027         int     k;
1028
1029         /*
1030          * Extract absolute NODE, if any
1031          */
1032         for (path = addr; *path && *path != ':'; path++);
1033         if (*path) {
1034                 node = addr;    /* Here's the NODE */
1035                 *path++ = '\0'; /* Here's the PATH */
1036
1037                 /* Node name must not be empty */
1038                 if (!*node)
1039                         return -1;
1040
1041                 /* A name of "." is OK; otherwise '.' not allowed */
1042                 if (strcmp(node, ".") != 0) {
1043                         for (k = 0; node[k]; k++)
1044                                 if (node[k] == '.')
1045                                         return -1;
1046                 }
1047         } else {
1048                 node = NULL;    /* No absolute NODE */
1049                 path = addr;    /* Here's the PATH */
1050         }
1051
1052         /* Snoop for illegal characters in PATH */
1053         for (k = 0; path[k]; k++)
1054                 if (path[k] == ':')
1055                         return -1;
1056
1057         /* Check for no repeated dots in PATH */
1058         for (k = 0; path[k]; k++)
1059                 if (path[k] == '.' && path[k + 1] == '.')
1060                         return -1;
1061
1062         /* Remove extra (degenerate) dots from beginning or end of PATH */
1063         if (path[0] == '.')
1064                 path++;
1065         if (*path && path[strlen(path) - 1] == '.')
1066                 path[strlen(path) - 1] = 0;
1067
1068         /* If PATH has a dot, then we're not talking about a hook */
1069         if (*path) {
1070                 for (hook = path, k = 0; path[k]; k++)
1071                         if (path[k] == '.') {
1072                                 hook = NULL;
1073                                 break;
1074                         }
1075         } else
1076                 path = hook = NULL;
1077
1078         /* Done */
1079         if (nodep)
1080                 *nodep = node;
1081         if (pathp)
1082                 *pathp = path;
1083         if (hookp)
1084                 *hookp = hook;
1085         return (0);
1086 }
1087
1088 /*
1089  * Given a path, which may be absolute or relative, and a starting node,
1090  * return the destination node. Compute the "return address" if desired.
1091  */
1092 int
1093 ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
1094 {
1095         const   node_p start = here;
1096         char    fullpath[NG_PATHSIZ];
1097         char   *nodename, *path, pbuf[2];
1098         node_p  node;
1099         char   *cp;
1100
1101         /* Initialize */
1102         if (rtnp)
1103                 *rtnp = NULL;
1104         if (destp == NULL)
1105                 return EINVAL;
1106         *destp = NULL;
1107
1108         /* Make a writable copy of address for ng_path_parse() */
1109         strncpy(fullpath, address, sizeof(fullpath) - 1);
1110         fullpath[sizeof(fullpath) - 1] = '\0';
1111
1112         /* Parse out node and sequence of hooks */
1113         if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) {
1114                 TRAP_ERROR;
1115                 return EINVAL;
1116         }
1117         if (path == NULL) {
1118                 pbuf[0] = '.';  /* Needs to be writable */
1119                 pbuf[1] = '\0';
1120                 path = pbuf;
1121         }
1122
1123         /* For an absolute address, jump to the starting node */
1124         if (nodename) {
1125                 node = ng_findname(here, nodename);
1126                 if (node == NULL) {
1127                         TRAP_ERROR;
1128                         return (ENOENT);
1129                 }
1130         } else
1131                 node = here;
1132
1133         /* Now follow the sequence of hooks */
1134         for (cp = path; node != NULL && *cp != '\0'; ) {
1135                 hook_p hook;
1136                 char *segment;
1137
1138                 /*
1139                  * Break out the next path segment. Replace the dot we just
1140                  * found with a NUL; "cp" points to the next segment (or the
1141                  * NUL at the end).
1142                  */
1143                 for (segment = cp; *cp != '\0'; cp++) {
1144                         if (*cp == '.') {
1145                                 *cp++ = '\0';
1146                                 break;
1147                         }
1148                 }
1149
1150                 /* Empty segment */
1151                 if (*segment == '\0')
1152                         continue;
1153
1154                 /* We have a segment, so look for a hook by that name */
1155                 hook = ng_findhook(node, segment);
1156
1157                 /* Can't get there from here... */
1158                 if (hook == NULL
1159                     || hook->peer == NULL
1160                     || (hook->flags & HK_INVALID) != 0) {
1161                         TRAP_ERROR;
1162                         return (ENOENT);
1163                 }
1164
1165                 /* Hop on over to the next node */
1166                 node = hook->peer->node;
1167         }
1168
1169         /* If node somehow missing, fail here (probably this is not needed) */
1170         if (node == NULL) {
1171                 TRAP_ERROR;
1172                 return (ENXIO);
1173         }
1174
1175         /* Now compute return address, i.e., the path to the sender */
1176         if (rtnp != NULL) {
1177                 MALLOC(*rtnp, char *, NG_NODESIZ + 1, M_NETGRAPH, M_NOWAIT);
1178                 if (*rtnp == NULL) {
1179                         TRAP_ERROR;
1180                         return (ENOMEM);
1181                 }
1182                 if (start->name != NULL)
1183                         ksprintf(*rtnp, "%s:", start->name);
1184                 else
1185                         ksprintf(*rtnp, "[%x]:", ng_node2ID(start));
1186         }
1187
1188         /* Done */
1189         *destp = node;
1190         return (0);
1191 }
1192
1193 /*
1194  * Call the appropriate message handler for the object.
1195  * It is up to the message handler to free the message.
1196  * If it's a generic message, handle it generically, otherwise
1197  * call the type's message handler (if it exists)
1198  * XXX (race). Remember that a queued message may reference a node
1199  * or hook that has just been invalidated. It will exist
1200  * as the queue code is holding a reference, but..
1201  */
1202
1203 #define CALL_MSG_HANDLER(error, node, msg, retaddr, resp)               \
1204 do {                                                                    \
1205         if((msg)->header.typecookie == NGM_GENERIC_COOKIE) {            \
1206                 (error) = ng_generic_msg((node), (msg),                 \
1207                                 (retaddr), (resp));                     \
1208         } else {                                                        \
1209                 if ((node)->type->rcvmsg != NULL) {                     \
1210                         (error) = (*(node)->type->rcvmsg)((node),       \
1211                                         (msg), (retaddr), (resp));      \
1212                 } else {                                                \
1213                         TRAP_ERROR;                                     \
1214                         FREE((msg), M_NETGRAPH);                        \
1215                         (error) = EINVAL;                               \
1216                 }                                                       \
1217         }                                                               \
1218 } while (0)
1219
1220
1221 /*
1222  * Send a control message to a node
1223  */
1224 int
1225 ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
1226             struct ng_mesg **rptr)
1227 {
1228         node_p  dest = NULL;
1229         char   *retaddr = NULL;
1230         int     error;
1231
1232         /* Find the target node */
1233         error = ng_path2node(here, address, &dest, &retaddr);
1234         if (error) {
1235                 FREE(msg, M_NETGRAPH);
1236                 return error;
1237         }
1238
1239         /* Make sure the resp field is null before we start */
1240         if (rptr != NULL)
1241                 *rptr = NULL;
1242
1243         CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr);
1244
1245         /* Make sure that if there is a response, it has the RESP bit set */
1246         if ((error == 0) && rptr && *rptr)
1247                 (*rptr)->header.flags |= NGF_RESP;
1248
1249         /*
1250          * If we had a return address it is up to us to free it. They should
1251          * have taken a copy if they needed to make a delayed response.
1252          */
1253         if (retaddr)
1254                 FREE(retaddr, M_NETGRAPH);
1255         return (error);
1256 }
1257
1258 /*
1259  * Implement the 'generic' control messages
1260  */
1261 static int
1262 ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
1263                struct ng_mesg **resp)
1264 {
1265         int error = 0;
1266
1267         if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
1268                 TRAP_ERROR;
1269                 FREE(msg, M_NETGRAPH);
1270                 return (EINVAL);
1271         }
1272         switch (msg->header.cmd) {
1273         case NGM_SHUTDOWN:
1274                 ng_rmnode(here);
1275                 break;
1276         case NGM_MKPEER:
1277             {
1278                 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
1279
1280                 if (msg->header.arglen != sizeof(*mkp)) {
1281                         TRAP_ERROR;
1282                         return (EINVAL);
1283                 }
1284                 mkp->type[sizeof(mkp->type) - 1] = '\0';
1285                 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0';
1286                 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0';
1287                 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type);
1288                 break;
1289             }
1290         case NGM_CONNECT:
1291             {
1292                 struct ngm_connect *const con =
1293                         (struct ngm_connect *) msg->data;
1294                 node_p node2;
1295
1296                 if (msg->header.arglen != sizeof(*con)) {
1297                         TRAP_ERROR;
1298                         return (EINVAL);
1299                 }
1300                 con->path[sizeof(con->path) - 1] = '\0';
1301                 con->ourhook[sizeof(con->ourhook) - 1] = '\0';
1302                 con->peerhook[sizeof(con->peerhook) - 1] = '\0';
1303                 error = ng_path2node(here, con->path, &node2, NULL);
1304                 if (error)
1305                         break;
1306                 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook);
1307                 break;
1308             }
1309         case NGM_NAME:
1310             {
1311                 struct ngm_name *const nam = (struct ngm_name *) msg->data;
1312
1313                 if (msg->header.arglen != sizeof(*nam)) {
1314                         TRAP_ERROR;
1315                         return (EINVAL);
1316                 }
1317                 nam->name[sizeof(nam->name) - 1] = '\0';
1318                 error = ng_name_node(here, nam->name);
1319                 break;
1320             }
1321         case NGM_RMHOOK:
1322             {
1323                 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data;
1324                 hook_p hook;
1325
1326                 if (msg->header.arglen != sizeof(*rmh)) {
1327                         TRAP_ERROR;
1328                         return (EINVAL);
1329                 }
1330                 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0';
1331                 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL)
1332                         ng_destroy_hook(hook);
1333                 break;
1334             }
1335         case NGM_NODEINFO:
1336             {
1337                 struct nodeinfo *ni;
1338                 struct ng_mesg *rp;
1339
1340                 /* Get response struct */
1341                 if (resp == NULL) {
1342                         error = EINVAL;
1343                         break;
1344                 }
1345                 NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT);
1346                 if (rp == NULL) {
1347                         error = ENOMEM;
1348                         break;
1349                 }
1350
1351                 /* Fill in node info */
1352                 ni = (struct nodeinfo *) rp->data;
1353                 if (here->name != NULL)
1354                         strlcpy(ni->name, here->name, NG_NODESIZ);
1355                 strlcpy(ni->type, here->type->name, NG_TYPESIZ);
1356                 ni->id = ng_node2ID(here);
1357                 ni->hooks = here->numhooks;
1358                 *resp = rp;
1359                 break;
1360             }
1361         case NGM_LISTHOOKS:
1362             {
1363                 const int nhooks = here->numhooks;
1364                 struct hooklist *hl;
1365                 struct nodeinfo *ni;
1366                 struct ng_mesg *rp;
1367                 hook_p hook;
1368
1369                 /* Get response struct */
1370                 if (resp == NULL) {
1371                         error = EINVAL;
1372                         break;
1373                 }
1374                 NG_MKRESPONSE(rp, msg, sizeof(*hl)
1375                     + (nhooks * sizeof(struct linkinfo)), M_NOWAIT);
1376                 if (rp == NULL) {
1377                         error = ENOMEM;
1378                         break;
1379                 }
1380                 hl = (struct hooklist *) rp->data;
1381                 ni = &hl->nodeinfo;
1382
1383                 /* Fill in node info */
1384                 if (here->name)
1385                         strlcpy(ni->name, here->name, NG_NODESIZ);
1386                 strlcpy(ni->type, here->type->name, NG_TYPESIZ);
1387                 ni->id = ng_node2ID(here);
1388
1389                 /* Cycle through the linked list of hooks */
1390                 ni->hooks = 0;
1391                 LIST_FOREACH(hook, &here->hooks, hooks) {
1392                         struct linkinfo *const link = &hl->link[ni->hooks];
1393
1394                         if (ni->hooks >= nhooks) {
1395                                 log(LOG_ERR, "%s: number of %s changed\n",
1396                                     __func__, "hooks");
1397                                 break;
1398                         }
1399                         if ((hook->flags & HK_INVALID) != 0)
1400                                 continue;
1401                         strlcpy(link->ourhook, hook->name, NG_HOOKSIZ);
1402                         strlcpy(link->peerhook, hook->peer->name, NG_HOOKSIZ);
1403                         if (hook->peer->node->name != NULL)
1404                                 strlcpy(link->nodeinfo.name,
1405                                     hook->peer->node->name, NG_NODESIZ);
1406                         strlcpy(link->nodeinfo.type,
1407                            hook->peer->node->type->name, NG_TYPESIZ);
1408                         link->nodeinfo.id = ng_node2ID(hook->peer->node);
1409                         link->nodeinfo.hooks = hook->peer->node->numhooks;
1410                         ni->hooks++;
1411                 }
1412                 *resp = rp;
1413                 break;
1414             }
1415
1416         case NGM_LISTNAMES:
1417         case NGM_LISTNODES:
1418             {
1419                 const int unnamed = (msg->header.cmd == NGM_LISTNODES);
1420                 struct namelist *nl;
1421                 struct ng_mesg *rp;
1422                 node_p node;
1423                 int num = 0;
1424
1425                 if (resp == NULL) {
1426                         error = EINVAL;
1427                         break;
1428                 }
1429
1430                 /* Count number of nodes */
1431                 LIST_FOREACH(node, &nodelist, nodes) {
1432                         if ((node->flags & NG_INVALID) == 0
1433                             && (unnamed || node->name != NULL))
1434                                 num++;
1435                 }
1436
1437                 /* Get response struct */
1438                 if (resp == NULL) {
1439                         error = EINVAL;
1440                         break;
1441                 }
1442                 NG_MKRESPONSE(rp, msg, sizeof(*nl)
1443                     + (num * sizeof(struct nodeinfo)), M_NOWAIT);
1444                 if (rp == NULL) {
1445                         error = ENOMEM;
1446                         break;
1447                 }
1448                 nl = (struct namelist *) rp->data;
1449
1450                 /* Cycle through the linked list of nodes */
1451                 nl->numnames = 0;
1452                 LIST_FOREACH(node, &nodelist, nodes) {
1453                         struct nodeinfo *const np = &nl->nodeinfo[nl->numnames];
1454
1455                         if (nl->numnames >= num) {
1456                                 log(LOG_ERR, "%s: number of %s changed\n",
1457                                     __func__, "nodes");
1458                                 break;
1459                         }
1460                         if ((node->flags & NG_INVALID) != 0)
1461                                 continue;
1462                         if (!unnamed && node->name == NULL)
1463                                 continue;
1464                         if (node->name != NULL)
1465                                 strlcpy(np->name, node->name, NG_NODESIZ);
1466                         strlcpy(np->type, node->type->name, NG_TYPESIZ);
1467                         np->id = ng_node2ID(node);
1468                         np->hooks = node->numhooks;
1469                         nl->numnames++;
1470                 }
1471                 *resp = rp;
1472                 break;
1473             }
1474
1475         case NGM_LISTTYPES:
1476             {
1477                 struct typelist *tl;
1478                 struct ng_mesg *rp;
1479                 struct ng_type *type;
1480                 int num = 0;
1481
1482                 if (resp == NULL) {
1483                         error = EINVAL;
1484                         break;
1485                 }
1486
1487                 /* Count number of types */
1488                 LIST_FOREACH(type, &typelist, types)
1489                         num++;
1490
1491                 /* Get response struct */
1492                 if (resp == NULL) {
1493                         error = EINVAL;
1494                         break;
1495                 }
1496                 NG_MKRESPONSE(rp, msg, sizeof(*tl)
1497                     + (num * sizeof(struct typeinfo)), M_NOWAIT);
1498                 if (rp == NULL) {
1499                         error = ENOMEM;
1500                         break;
1501                 }
1502                 tl = (struct typelist *) rp->data;
1503
1504                 /* Cycle through the linked list of types */
1505                 tl->numtypes = 0;
1506                 LIST_FOREACH(type, &typelist, types) {
1507                         struct typeinfo *const tp = &tl->typeinfo[tl->numtypes];
1508
1509                         if (tl->numtypes >= num) {
1510                                 log(LOG_ERR, "%s: number of %s changed\n",
1511                                     __func__, "types");
1512                                 break;
1513                         }
1514                         strlcpy(tp->type_name, type->name, NG_TYPESIZ);
1515                         tp->numnodes = type->refs - 1; /* don't count list */
1516                         tl->numtypes++;
1517                 }
1518                 *resp = rp;
1519                 break;
1520             }
1521
1522         case NGM_BINARY2ASCII:
1523             {
1524                 int bufSize = 20 * 1024;        /* XXX hard coded constant */
1525                 const struct ng_parse_type *argstype;
1526                 const struct ng_cmdlist *c;
1527                 struct ng_mesg *rp, *binary, *ascii;
1528
1529                 /* Data area must contain a valid netgraph message */
1530                 binary = (struct ng_mesg *)msg->data;
1531                 if (msg->header.arglen < sizeof(struct ng_mesg)
1532                     || msg->header.arglen - sizeof(struct ng_mesg) 
1533                       < binary->header.arglen) {
1534                         error = EINVAL;
1535                         break;
1536                 }
1537
1538                 /* Get a response message with lots of room */
1539                 NG_MKRESPONSE(rp, msg, sizeof(*ascii) + bufSize, M_NOWAIT);
1540                 if (rp == NULL) {
1541                         error = ENOMEM;
1542                         break;
1543                 }
1544                 ascii = (struct ng_mesg *)rp->data;
1545
1546                 /* Copy binary message header to response message payload */
1547                 bcopy(binary, ascii, sizeof(*binary));
1548
1549                 /* Find command by matching typecookie and command number */
1550                 for (c = here->type->cmdlist;
1551                     c != NULL && c->name != NULL; c++) {
1552                         if (binary->header.typecookie == c->cookie
1553                             && binary->header.cmd == c->cmd)
1554                                 break;
1555                 }
1556                 if (c == NULL || c->name == NULL) {
1557                         for (c = ng_generic_cmds; c->name != NULL; c++) {
1558                                 if (binary->header.typecookie == c->cookie
1559                                     && binary->header.cmd == c->cmd)
1560                                         break;
1561                         }
1562                         if (c->name == NULL) {
1563                                 FREE(rp, M_NETGRAPH);
1564                                 error = ENOSYS;
1565                                 break;
1566                         }
1567                 }
1568
1569                 /* Convert command name to ASCII */
1570                 ksnprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr),
1571                     "%s", c->name);
1572
1573                 /* Convert command arguments to ASCII */
1574                 argstype = (binary->header.flags & NGF_RESP) ?
1575                     c->respType : c->mesgType;
1576                 if (argstype == NULL)
1577                         *ascii->data = '\0';
1578                 else {
1579                         if ((error = ng_unparse(argstype,
1580                             (u_char *)binary->data,
1581                             ascii->data, bufSize)) != 0) {
1582                                 FREE(rp, M_NETGRAPH);
1583                                 break;
1584                         }
1585                 }
1586
1587                 /* Return the result as struct ng_mesg plus ASCII string */
1588                 bufSize = strlen(ascii->data) + 1;
1589                 ascii->header.arglen = bufSize;
1590                 rp->header.arglen = sizeof(*ascii) + bufSize;
1591                 *resp = rp;
1592                 break;
1593             }
1594
1595         case NGM_ASCII2BINARY:
1596             {
1597                 int bufSize = 2000;     /* XXX hard coded constant */
1598                 const struct ng_cmdlist *c;
1599                 const struct ng_parse_type *argstype;
1600                 struct ng_mesg *rp, *ascii, *binary;
1601                 int off = 0;
1602
1603                 /* Data area must contain at least a struct ng_mesg + '\0' */
1604                 ascii = (struct ng_mesg *)msg->data;
1605                 if (msg->header.arglen < sizeof(*ascii) + 1
1606                     || ascii->header.arglen < 1
1607                     || msg->header.arglen
1608                       < sizeof(*ascii) + ascii->header.arglen) {
1609                         error = EINVAL;
1610                         break;
1611                 }
1612                 ascii->data[ascii->header.arglen - 1] = '\0';
1613
1614                 /* Get a response message with lots of room */
1615                 NG_MKRESPONSE(rp, msg, sizeof(*binary) + bufSize, M_NOWAIT);
1616                 if (rp == NULL) {
1617                         error = ENOMEM;
1618                         break;
1619                 }
1620                 binary = (struct ng_mesg *)rp->data;
1621
1622                 /* Copy ASCII message header to response message payload */
1623                 bcopy(ascii, binary, sizeof(*ascii));
1624
1625                 /* Find command by matching ASCII command string */
1626                 for (c = here->type->cmdlist;
1627                     c != NULL && c->name != NULL; c++) {
1628                         if (strcmp(ascii->header.cmdstr, c->name) == 0)
1629                                 break;
1630                 }
1631                 if (c == NULL || c->name == NULL) {
1632                         for (c = ng_generic_cmds; c->name != NULL; c++) {
1633                                 if (strcmp(ascii->header.cmdstr, c->name) == 0)
1634                                         break;
1635                         }
1636                         if (c->name == NULL) {
1637                                 FREE(rp, M_NETGRAPH);
1638                                 error = ENOSYS;
1639                                 break;
1640                         }
1641                 }
1642
1643                 /* Convert command name to binary */
1644                 binary->header.cmd = c->cmd;
1645                 binary->header.typecookie = c->cookie;
1646
1647                 /* Convert command arguments to binary */
1648                 argstype = (binary->header.flags & NGF_RESP) ?
1649                     c->respType : c->mesgType;
1650                 if (argstype == NULL)
1651                         bufSize = 0;
1652                 else {
1653                         if ((error = ng_parse(argstype, ascii->data,
1654                             &off, (u_char *)binary->data, &bufSize)) != 0) {
1655                                 FREE(rp, M_NETGRAPH);
1656                                 break;
1657                         }
1658                 }
1659
1660                 /* Return the result */
1661                 binary->header.arglen = bufSize;
1662                 rp->header.arglen = sizeof(*binary) + bufSize;
1663                 *resp = rp;
1664                 break;
1665             }
1666
1667         case NGM_TEXT_CONFIG:
1668         case NGM_TEXT_STATUS:
1669                 /*
1670                  * This one is tricky as it passes the command down to the
1671                  * actual node, even though it is a generic type command.
1672                  * This means we must assume that the msg is already freed
1673                  * when control passes back to us.
1674                  */
1675                 if (resp == NULL) {
1676                         error = EINVAL;
1677                         break;
1678                 }
1679                 if (here->type->rcvmsg != NULL)
1680                         return((*here->type->rcvmsg)(here, msg, retaddr, resp));
1681                 /* Fall through if rcvmsg not supported */
1682         default:
1683                 TRAP_ERROR;
1684                 error = EINVAL;
1685         }
1686         FREE(msg, M_NETGRAPH);
1687         return (error);
1688 }
1689
1690 /*
1691  * Send a data packet to a node. If the recipient has no
1692  * 'receive data' method, then silently discard the packet.
1693  */
1694 int 
1695 ng_send_data(hook_p hook, struct mbuf *m, meta_p meta)
1696 {
1697         int (*rcvdata)(hook_p, struct mbuf *, meta_p);
1698         int error;
1699
1700         CHECK_DATA_MBUF(m);
1701         if (hook && (hook->flags & HK_INVALID) == 0) {
1702                 rcvdata = hook->peer->node->type->rcvdata;
1703                 if (rcvdata != NULL)
1704                         error = (*rcvdata)(hook->peer, m, meta);
1705                 else {
1706                         error = 0;
1707                         NG_FREE_DATA(m, meta);
1708                 }
1709         } else {
1710                 TRAP_ERROR;
1711                 error = ENOTCONN;
1712                 NG_FREE_DATA(m, meta);
1713         }
1714         return (error);
1715 }
1716
1717 /*
1718  * Send a queued data packet to a node. If the recipient has no
1719  * 'receive queued data' method, then try the 'receive data' method above.
1720  */
1721 int 
1722 ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta)
1723 {
1724         int (*rcvdataq)(hook_p, struct mbuf *, meta_p);
1725         int error;
1726
1727         CHECK_DATA_MBUF(m);
1728         if (hook && (hook->flags & HK_INVALID) == 0) {
1729                 rcvdataq = hook->peer->node->type->rcvdataq;
1730                 if (rcvdataq != NULL)
1731                         error = (*rcvdataq)(hook->peer, m, meta);
1732                 else {
1733                         error = ng_send_data(hook, m, meta);
1734                 }
1735         } else {
1736                 TRAP_ERROR;
1737                 error = ENOTCONN;
1738                 NG_FREE_DATA(m, meta);
1739         }
1740         return (error);
1741 }
1742
1743 /*
1744  * Copy a 'meta'.
1745  *
1746  * Returns new meta, or NULL if original meta is NULL or ENOMEM.
1747  */
1748 meta_p
1749 ng_copy_meta(meta_p meta)
1750 {
1751         meta_p meta2;
1752
1753         if (meta == NULL)
1754                 return (NULL);
1755         MALLOC(meta2, meta_p, meta->used_len, M_NETGRAPH, M_NOWAIT);
1756         if (meta2 == NULL)
1757                 return (NULL);
1758         meta2->allocated_len = meta->used_len;
1759         bcopy(meta, meta2, meta->used_len);
1760         return (meta2);
1761 }
1762
1763 /************************************************************************
1764                         Module routines
1765 ************************************************************************/
1766
1767 /*
1768  * Handle the loading/unloading of a netgraph node type module
1769  */
1770 int
1771 ng_mod_event(module_t mod, int event, void *data)
1772 {
1773         struct ng_type *const type = data;
1774         int error = 0;
1775
1776         switch (event) {
1777         case MOD_LOAD:
1778
1779                 /* Register new netgraph node type */
1780                 crit_enter();
1781                 if ((error = ng_newtype(type)) != 0) {
1782                         crit_exit();
1783                         break;
1784                 }
1785
1786                 /* Call type specific code */
1787                 if (type->mod_event != NULL)
1788                         if ((error = (*type->mod_event)(mod, event, data))) {
1789                                 type->refs--;   /* undo it */
1790                                 LIST_REMOVE(type, types);
1791                         }
1792                 crit_exit();
1793                 break;
1794
1795         case MOD_UNLOAD:
1796                 crit_enter();
1797                 if (type->refs > 1) {           /* make sure no nodes exist! */
1798                         error = EBUSY;
1799                 } else {
1800                         if (type->refs == 0) {
1801                                 /* failed load, nothing to undo */
1802                                 crit_exit();
1803                                 break;
1804                         }
1805                         if (type->mod_event != NULL) {  /* check with type */
1806                                 error = (*type->mod_event)(mod, event, data);
1807                                 if (error != 0) {       /* type refuses.. */
1808                                         crit_exit();
1809                                         break;
1810                                 }
1811                         }
1812                         LIST_REMOVE(type, types);
1813                 }
1814                 crit_exit();
1815                 break;
1816
1817         default:
1818                 if (type->mod_event != NULL)
1819                         error = (*type->mod_event)(mod, event, data);
1820                 else
1821                         error = 0;              /* XXX ? */
1822                 break;
1823         }
1824         return (error);
1825 }
1826
1827 /*
1828  * Handle loading and unloading for this code.
1829  * The only thing we need to link into is the NETISR strucure.
1830  */
1831 static int
1832 ngb_mod_event(module_t mod, int event, void *data)
1833 {
1834         int error = 0;
1835
1836         switch (event) {
1837         case MOD_LOAD:
1838                 /* Register line discipline */
1839                 crit_enter();
1840                 error = ng_load_module("ksocket");
1841                 if (error != 0) {
1842                         crit_exit();
1843                         break;
1844                 }
1845                 netisr_register(NETISR_NETGRAPH, ngintr, NULL);
1846                 error = 0;
1847                 crit_exit();
1848                 break;
1849         case MOD_UNLOAD:
1850                 ng_unload_module("ksocket");
1851                 /* You cant unload it because an interface may be using it.  */
1852                 error = EBUSY;
1853                 break;
1854         default:
1855                 error = EOPNOTSUPP;
1856                 break;
1857         }
1858         return (error);
1859 }
1860
1861 static moduledata_t netgraph_mod = {
1862         "netgraph",
1863         ngb_mod_event,
1864         (NULL)
1865 };
1866 DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1867 SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family");
1868 SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,"");
1869 SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, "");
1870
1871 /************************************************************************
1872                         Queueing routines
1873 ************************************************************************/
1874
1875 /* The structure for queueing across ISR switches */
1876 struct ng_queue_entry {
1877         u_long  flags;
1878         struct ng_queue_entry *next;
1879         union {
1880                 struct {
1881                         hook_p          da_hook;        /*  target hook */
1882                         struct mbuf     *da_m;
1883                         meta_p          da_meta;
1884                 } data;
1885                 struct {
1886                         struct ng_mesg  *msg_msg;
1887                         node_p          msg_node;
1888                         void            *msg_retaddr;
1889                 } msg;
1890         } body;
1891 };
1892 #define NGQF_DATA       0x01            /* the queue element is data */
1893 #define NGQF_MESG       0x02            /* the queue element is a message */
1894
1895 static struct ng_queue_entry   *ngqbase;        /* items to be unqueued */
1896 static struct ng_queue_entry   *ngqlast;        /* last item queued */
1897 static const int                ngqroom = 256;  /* max items to queue */
1898 static int                      ngqsize;        /* number of items in queue */
1899
1900 static struct ng_queue_entry   *ngqfree;        /* free ones */
1901 static const int                ngqfreemax = 256;/* cache at most this many */
1902 static int                      ngqfreesize;    /* number of cached entries */
1903
1904 /*
1905  * Get a queue entry
1906  */
1907 static struct ng_queue_entry *
1908 ng_getqblk(void)
1909 {
1910         struct ng_queue_entry *q;
1911
1912         /* Could be guarding against tty ints or whatever */
1913         crit_enter();
1914
1915         /* Try get a cached queue block, or else allocate a new one */
1916         if ((q = ngqfree) == NULL) {
1917                 crit_exit();
1918                 if (ngqsize < ngqroom) {        /* don't worry about races */
1919                         MALLOC(q, struct ng_queue_entry *,
1920                             sizeof(*q), M_NETGRAPH, M_NOWAIT);
1921                 }
1922         } else {
1923                 ngqfree = q->next;
1924                 ngqfreesize--;
1925                 crit_exit();
1926         }
1927         return (q);
1928 }
1929
1930 /*
1931  * Release a queue entry
1932  */
1933 #define RETURN_QBLK(q)                                                  \
1934 do {                                                                    \
1935         if (ngqfreesize < ngqfreemax) { /* don't worry about races */   \
1936                 crit_enter();                                           \
1937                 (q)->next = ngqfree;                                    \
1938                 ngqfree = (q);                                          \
1939                 ngqfreesize++;                                          \
1940                 crit_exit();                                            \
1941         } else {                                                        \
1942                 FREE((q), M_NETGRAPH);                                  \
1943         }                                                               \
1944 } while (0)
1945
1946 /*
1947  * Running at a raised (but we don't know which) processor priority level,
1948  * put the data onto a queue to be picked up by another PPL (probably splnet)
1949  */
1950 int
1951 ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta)
1952 {
1953         struct ng_queue_entry *q;
1954
1955         if (hook == NULL) {
1956                 NG_FREE_DATA(m, meta);
1957                 return (0);
1958         }
1959         if ((q = ng_getqblk()) == NULL) {
1960                 NG_FREE_DATA(m, meta);
1961                 return (ENOBUFS);
1962         }
1963
1964         /* Fill out the contents */
1965         q->flags = NGQF_DATA;
1966         q->next = NULL;
1967         q->body.data.da_hook = hook;
1968         q->body.data.da_m = m;
1969         q->body.data.da_meta = meta;
1970         crit_enter();           /* protect refs and queue */
1971         hook->refs++;           /* don't let it go away while on the queue */
1972
1973         /* Put it on the queue */
1974         if (ngqbase) {
1975                 ngqlast->next = q;
1976         } else {
1977                 ngqbase = q;
1978         }
1979         ngqlast = q;
1980         ngqsize++;
1981         crit_exit();
1982
1983         /* Schedule software interrupt to handle it later */
1984         schednetisr(NETISR_NETGRAPH);
1985         return (0);
1986 }
1987
1988 /*
1989  * Running at a raised (but we don't know which) processor priority level,
1990  * put the msg onto a queue to be picked up by another PPL (probably splnet)
1991  */
1992 int
1993 ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address)
1994 {
1995         struct ng_queue_entry *q;
1996         node_p  dest = NULL;
1997         char   *retaddr = NULL;
1998         int     error;
1999
2000         /* Find the target node. */
2001         error = ng_path2node(here, address, &dest, &retaddr);
2002         if (error) {
2003                 FREE(msg, M_NETGRAPH);
2004                 return (error);
2005         }
2006         if ((q = ng_getqblk()) == NULL) {
2007                 FREE(msg, M_NETGRAPH);
2008                 if (retaddr)
2009                         FREE(retaddr, M_NETGRAPH);
2010                 return (ENOBUFS);
2011         }
2012
2013         /* Fill out the contents */
2014         q->flags = NGQF_MESG;
2015         q->next = NULL;
2016         q->body.msg.msg_node = dest;
2017         q->body.msg.msg_msg = msg;
2018         q->body.msg.msg_retaddr = retaddr;
2019         crit_enter();           /* protect refs and queue */
2020         dest->refs++;           /* don't let it go away while on the queue */
2021
2022         /* Put it on the queue */
2023         if (ngqbase) {
2024                 ngqlast->next = q;
2025         } else {
2026                 ngqbase = q;
2027         }
2028         ngqlast = q;
2029         ngqsize++;
2030         crit_exit();
2031
2032         /* Schedule software interrupt to handle it later */
2033         schednetisr(NETISR_NETGRAPH);
2034         return (0);
2035 }
2036
2037 /*
2038  * Pick an item off the queue, process it, and dispose of the queue entry.
2039  */
2040 static void
2041 ngintr(struct netmsg *pmsg)
2042 {
2043         hook_p  hook;
2044         struct mbuf *m;
2045         struct ng_queue_entry *ngq;
2046         meta_p  meta;
2047         void   *retaddr;
2048         struct ng_mesg *msg;
2049         node_p  node;
2050         int     error = 0;
2051
2052         /*
2053          * Packets are never sent to this netisr so the message must always
2054          * be replied.  Interlock processing and notification by replying
2055          * the message first.
2056          */
2057         lwkt_replymsg(&pmsg->nm_lmsg, 0);
2058
2059         get_mplock();
2060
2061         while (1) {
2062                 crit_enter();
2063                 if ((ngq = ngqbase)) {
2064                         ngqbase = ngq->next;
2065                         ngqsize--;
2066                 }
2067                 crit_exit();
2068                 if (ngq == NULL)
2069                         goto out;
2070                 switch (ngq->flags) {
2071                 case NGQF_DATA:
2072                         hook = ngq->body.data.da_hook;
2073                         m = ngq->body.data.da_m;
2074                         meta = ngq->body.data.da_meta;
2075                         RETURN_QBLK(ngq);
2076                         NG_SEND_DATAQ(error, hook, m, meta);
2077                         ng_unref_hook(hook);
2078                         break;
2079                 case NGQF_MESG:
2080                         node = ngq->body.msg.msg_node;
2081                         msg = ngq->body.msg.msg_msg;
2082                         retaddr = ngq->body.msg.msg_retaddr;
2083                         RETURN_QBLK(ngq);
2084                         if (node->flags & NG_INVALID) {
2085                                 FREE(msg, M_NETGRAPH);
2086                         } else {
2087                                 CALL_MSG_HANDLER(error, node, msg,
2088                                                  retaddr, NULL);
2089                         }
2090                         ng_unref(node);
2091                         if (retaddr)
2092                                 FREE(retaddr, M_NETGRAPH);
2093                         break;
2094                 default:
2095                         RETURN_QBLK(ngq);
2096                 }
2097         }
2098 out:
2099         rel_mplock();
2100 }
2101
2102