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