]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/atm/uni/ng_uni.c
NgATM: deprecate
[FreeBSD/FreeBSD.git] / sys / netgraph / atm / uni / ng_uni.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001-2003
5  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6  *      All rights reserved.
7  *
8  * Author: Hartmut Brandt <harti@freebsd.org>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * Netgraph module for ATM-Forum UNI 4.0 signalling
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/errno.h>
43 #include <sys/syslog.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/callout.h>
47 #include <sys/sbuf.h>
48 #include <machine/stdarg.h>
49
50 #include <netgraph/ng_message.h>
51 #include <netgraph/netgraph.h>
52 #include <netgraph/ng_parse.h>
53 #include <netnatm/unimsg.h>
54 #include <netnatm/msg/unistruct.h>
55 #include <netgraph/atm/ngatmbase.h>
56 #include <netnatm/saal/sscopdef.h>
57 #include <netnatm/saal/sscfudef.h>
58 #include <netgraph/atm/uni/ng_uni_cust.h>
59 #include <netnatm/sig/uni.h>
60 #include <netnatm/sig/unisig.h>
61 #include <netgraph/atm/ng_sscop.h>
62 #include <netgraph/atm/ng_sscfu.h>
63 #include <netgraph/atm/ng_uni.h>
64
65 static MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
66 static MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data");
67
68 MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
69
70 /*
71  * Private node data
72  */
73 struct priv {
74         hook_p  upper;
75         hook_p  lower;
76         struct uni *uni;
77         int     enabled;
78 };
79
80 /* UNI CONFIG MASK */
81 static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] =
82         NGM_UNI_CONFIG_MASK_INFO;
83 static const struct ng_parse_type ng_uni_config_mask_type = {
84         &ng_parse_struct_type,
85         ng_uni_config_mask_type_info
86 };
87
88 /* UNI_CONFIG */
89 static const struct ng_parse_struct_field ng_uni_config_type_info[] =
90         NGM_UNI_CONFIG_INFO;
91 static const struct ng_parse_type ng_uni_config_type = {
92         &ng_parse_struct_type,
93         ng_uni_config_type_info
94 };
95
96 /* SET CONFIG */
97 static const struct ng_parse_struct_field ng_uni_set_config_type_info[] =
98         NGM_UNI_SET_CONFIG_INFO;
99 static const struct ng_parse_type ng_uni_set_config_type = {
100         &ng_parse_struct_type,
101         ng_uni_set_config_type_info
102 };
103
104 /*
105  * Parse DEBUG
106  */
107 static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info =
108     NGM_UNI_DEBUGLEVEL_INFO;
109 static const struct ng_parse_type ng_uni_debuglevel_type = {
110         &ng_parse_fixedarray_type,
111         &ng_uni_debuglevel_type_info
112 };
113 static const struct ng_parse_struct_field ng_uni_debug_type_info[] =
114     NGM_UNI_DEBUG_INFO;
115 static const struct ng_parse_type ng_uni_debug_type = {
116         &ng_parse_struct_type,
117         ng_uni_debug_type_info
118 };
119
120 /*
121  * Command list
122  */
123 static const struct ng_cmdlist ng_uni_cmdlist[] = {
124         {
125           NGM_UNI_COOKIE,
126           NGM_UNI_GETDEBUG,
127           "getdebug",
128           NULL,
129           &ng_uni_debug_type
130         },
131         {
132           NGM_UNI_COOKIE,
133           NGM_UNI_SETDEBUG,
134           "setdebug",
135           &ng_uni_debug_type,
136           NULL
137         },
138         {
139           NGM_UNI_COOKIE,
140           NGM_UNI_GET_CONFIG,
141           "get_config",
142           NULL,
143           &ng_uni_config_type
144         },
145         {
146           NGM_UNI_COOKIE,
147           NGM_UNI_SET_CONFIG,
148           "set_config",
149           &ng_uni_set_config_type,
150           &ng_uni_config_mask_type,
151         },
152         {
153           NGM_UNI_COOKIE,
154           NGM_UNI_ENABLE,
155           "enable",
156           NULL,
157           NULL,
158         },
159         {
160           NGM_UNI_COOKIE,
161           NGM_UNI_DISABLE,
162           "disable",
163           NULL,
164           NULL,
165         },
166         {
167           NGM_UNI_COOKIE,
168           NGM_UNI_GETSTATE,
169           "getstate",
170           NULL,
171           &ng_parse_uint32_type
172         },
173         { 0 }
174 };
175
176 /*
177  * Netgraph module data
178  */
179 static ng_constructor_t ng_uni_constructor;
180 static ng_shutdown_t    ng_uni_shutdown;
181 static ng_rcvmsg_t      ng_uni_rcvmsg;
182 static ng_newhook_t     ng_uni_newhook;
183 static ng_disconnect_t  ng_uni_disconnect;
184 static ng_rcvdata_t     ng_uni_rcvlower;
185 static ng_rcvdata_t     ng_uni_rcvupper;
186
187 static int ng_uni_mod_event(module_t, int, void *);
188
189 static struct ng_type ng_uni_typestruct = {
190         .version =      NG_ABI_VERSION,
191         .name =         NG_UNI_NODE_TYPE,
192         .mod_event =    ng_uni_mod_event,
193         .constructor =  ng_uni_constructor,
194         .rcvmsg =       ng_uni_rcvmsg,
195         .shutdown =     ng_uni_shutdown,
196         .newhook =      ng_uni_newhook,
197         .rcvdata =      ng_uni_rcvlower,
198         .disconnect =   ng_uni_disconnect,
199         .cmdlist =      ng_uni_cmdlist,
200 };
201 NETGRAPH_INIT(uni, &ng_uni_typestruct);
202
203 static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
204     struct uni_msg *);
205 static void uni_saal_output(struct uni *, void *, enum saal_sig,
206     struct uni_msg *);
207 static void uni_verbose(struct uni *, void *, u_int, const char *, ...)
208     __printflike(4, 5);
209 static void uni_do_status(struct uni *, void *, void *, const char *, ...)
210     __printflike(4, 5);
211
212 static const struct uni_funcs uni_funcs = {
213         uni_uni_output,
214         uni_saal_output,
215         uni_verbose,
216         uni_do_status
217 };
218
219 /************************************************************/
220 /*
221  * NODE MANAGEMENT
222  */
223 static int
224 ng_uni_constructor(node_p node)
225 {
226         struct priv *priv;
227
228         gone_in(14, "ng_uni: netgraph ATM modules");
229
230         priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
231
232         if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
233                 free(priv, M_NG_UNI);
234                 return (ENOMEM);
235         }
236
237         NG_NODE_SET_PRIVATE(node, priv);
238         NG_NODE_FORCE_WRITER(node);
239
240         return (0);
241 }
242
243 static int
244 ng_uni_shutdown(node_p node)
245 {
246         struct priv *priv = NG_NODE_PRIVATE(node);
247
248         uni_destroy(priv->uni);
249
250         free(priv, M_NG_UNI);
251         NG_NODE_SET_PRIVATE(node, NULL);
252
253         NG_NODE_UNREF(node);
254
255         return (0);
256 }
257
258 /************************************************************/
259 /*
260  * CONTROL MESSAGES
261  */
262 static void
263 uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
264 {
265         va_list ap;
266
267         va_start(ap, fmt);
268         sbuf_printf(sbuf, fmt, ap);
269         va_end(ap);
270 }
271
272 static int
273 text_status(node_p node, struct priv *priv, char *buf, u_int len)
274 {
275         struct sbuf sbuf;
276         u_int f;
277
278         sbuf_new(&sbuf, buf, len, 0);
279
280         if (priv->lower != NULL)
281                 sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
282                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
283                     NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
284         else
285                 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
286
287         if (priv->upper != NULL)
288                 sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
289                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
290                     NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
291         else
292                 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
293
294         sbuf_printf(&sbuf, "debugging:");
295         for (f = 0; f < UNI_MAXFACILITY; f++)
296                 if (uni_get_debug(priv->uni, f) != 0)
297                         sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
298                             uni_get_debug(priv->uni, f));
299         sbuf_printf(&sbuf, "\n");
300
301         if (priv->uni)
302                 uni_status(priv->uni, &sbuf);
303
304         sbuf_finish(&sbuf);
305         return (sbuf_len(&sbuf));
306 }
307
308 static int
309 ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
310 {
311         struct priv *priv = NG_NODE_PRIVATE(node);
312         struct ng_mesg *resp = NULL;
313         struct ng_mesg *msg;
314         int error = 0;
315         u_int i;
316
317         NGI_GET_MSG(item, msg);
318
319         switch (msg->header.typecookie) {
320           case NGM_GENERIC_COOKIE:
321                 switch (msg->header.cmd) {
322                   case NGM_TEXT_STATUS:
323                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
324                         if (resp == NULL) {
325                                 error = ENOMEM;
326                                 break;
327                         }
328
329                         resp->header.arglen = text_status(node, priv,
330                             (char *)resp->data, resp->header.arglen) + 1;
331                         break;
332
333                   default:
334                         error = EINVAL;
335                         break;
336                 }
337                 break;
338
339           case NGM_UNI_COOKIE:
340                 switch (msg->header.cmd) {
341                   case NGM_UNI_SETDEBUG:
342                     {
343                         struct ngm_uni_debug *arg;
344
345                         if (msg->header.arglen > sizeof(*arg)) {
346                                 error = EINVAL;
347                                 break;
348                         }
349                         arg = (struct ngm_uni_debug *)msg->data;
350                         for (i = 0; i < UNI_MAXFACILITY; i++)
351                                 uni_set_debug(priv->uni, i, arg->level[i]);
352                         break;
353                     }
354
355                   case NGM_UNI_GETDEBUG:
356                     {
357                         struct ngm_uni_debug *arg;
358
359                         NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
360                         if(resp == NULL) {
361                                 error = ENOMEM;
362                                 break;
363                         }
364                         arg = (struct ngm_uni_debug *)resp->data;
365                         for (i = 0; i < UNI_MAXFACILITY; i++)
366                                 arg->level[i] = uni_get_debug(priv->uni, i);
367                         break;
368                     }
369
370                   case NGM_UNI_GET_CONFIG:
371                     {
372                         struct uni_config *config;
373
374                         if (msg->header.arglen != 0) {
375                                 error = EINVAL;
376                                 break;
377                         }
378                         NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
379                         if (resp == NULL) {
380                                 error = ENOMEM;
381                                 break;
382                         }
383                         config = (struct uni_config *)resp->data;
384                         uni_get_config(priv->uni, config);
385
386                         break;
387                     }
388
389                   case NGM_UNI_SET_CONFIG:
390                     {
391                         struct ngm_uni_set_config *arg;
392                         struct ngm_uni_config_mask *mask;
393
394                         if (msg->header.arglen != sizeof(*arg)) {
395                                 error = EINVAL;
396                                 break;
397                         }
398                         arg = (struct ngm_uni_set_config *)msg->data;
399
400                         NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
401                         if (resp == NULL) {
402                                 error = ENOMEM;
403                                 break;
404                         }
405                         mask = (struct ngm_uni_config_mask *)resp->data;
406
407                         *mask = arg->mask;
408
409                         uni_set_config(priv->uni, &arg->config,
410                             &mask->mask, &mask->popt_mask, &mask->option_mask);
411
412                         break;
413                     }
414
415                   case NGM_UNI_ENABLE:
416                         if (msg->header.arglen != 0) {
417                                 error = EINVAL;
418                                 break;
419                         }
420                         if (priv->enabled) {
421                                 error = EISCONN;
422                                 break;
423                         }
424                         priv->enabled = 1;
425                         break;
426
427                   case NGM_UNI_DISABLE:
428                         if (msg->header.arglen != 0) {
429                                 error = EINVAL;
430                                 break;
431                         }
432                         if (!priv->enabled) {
433                                 error = ENOTCONN;
434                                 break;
435                         }
436                         priv->enabled = 0;
437                         uni_reset(priv->uni);
438                         break;
439
440                   case NGM_UNI_GETSTATE:
441                         if (msg->header.arglen != 0) {
442                                 error = EINVAL;
443                                 break;
444                         }
445                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
446                         if(resp == NULL) {
447                                 error = ENOMEM;
448                                 break;
449                         }
450                         *(u_int32_t *)resp->data =
451                             priv->enabled ? (uni_getcustate(priv->uni) + 1)
452                                           : 0;
453                         break;
454
455                   default:
456                         error = EINVAL;
457                         break;
458                 }
459                 break;
460
461           default:
462                 error = EINVAL;
463                 break;
464         }
465
466         NG_RESPOND_MSG(error, node, item, resp);
467         NG_FREE_MSG(msg);
468         return (error);
469 }
470
471 /************************************************************/
472 /*
473  * HOOK MANAGEMENT
474  */
475 static int
476 ng_uni_newhook(node_p node, hook_p hook, const char *name)
477 {
478         struct priv *priv = NG_NODE_PRIVATE(node);
479
480         if (strcmp(name, "lower") == 0) {
481                 priv->lower = hook;
482         } else if(strcmp(name, "upper") == 0) {
483                 priv->upper = hook;
484                 NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
485         } else
486                 return EINVAL;
487
488         return 0;
489 }
490
491 static int
492 ng_uni_disconnect(hook_p hook)
493 {
494         node_p node = NG_HOOK_NODE(hook);
495         struct priv *priv = NG_NODE_PRIVATE(node);
496
497         if(hook == priv->lower)
498                 priv->lower = NULL;
499         else if(hook == priv->upper)
500                 priv->upper = NULL;
501         else
502                 printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
503
504         if (NG_NODE_NUMHOOKS(node) == 0) {
505                 if (NG_NODE_IS_VALID(node))
506                         ng_rmnode_self(node);
507         }
508
509         return (0);
510 }
511
512 /************************************************************/
513 /*
514  * DATA
515  */
516 /*
517  * Receive signal from USER.
518  *
519  * Repackage the data into one large buffer.
520  */
521 static int
522 ng_uni_rcvupper(hook_p hook, item_p item)
523 {
524         node_p node = NG_HOOK_NODE(hook);
525         struct priv *priv = NG_NODE_PRIVATE(node);
526         struct mbuf *m;
527         struct uni_arg arg;
528         struct uni_msg *msg;
529         int error;
530
531         if (!priv->enabled) {
532                 NG_FREE_ITEM(item);
533                 return (ENOTCONN);
534         }
535
536         NGI_GET_M(item, m);
537         NG_FREE_ITEM(item);
538
539         if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
540                 m_freem(m);
541                 return (error);
542         }
543         m_freem(m);
544
545         if (uni_msg_len(msg) < sizeof(arg)) {
546                 printf("%s: packet too short\n", __func__);
547                 uni_msg_destroy(msg);
548                 return (EINVAL);
549         }
550
551         bcopy(msg->b_rptr, &arg, sizeof(arg));
552         msg->b_rptr += sizeof(arg);
553
554         if (arg.sig >= UNIAPI_MAXSIG) {
555                 printf("%s: bogus signal\n", __func__);
556                 uni_msg_destroy(msg);
557                 return (EINVAL);
558         }
559         uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
560         uni_work(priv->uni);
561
562         return (0);
563 }
564
565 /*
566  * Upper layer signal from UNI
567  */
568 static void
569 uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
570     struct uni_msg *msg)
571 {
572         node_p node = (node_p)varg;
573         struct priv *priv = NG_NODE_PRIVATE(node);
574         struct mbuf *m;
575         struct uni_arg arg;
576         int error;
577
578         if (priv->upper == NULL) {
579                 if (msg != NULL)
580                         uni_msg_destroy(msg);
581                 return;
582         }
583         arg.sig = sig;
584         arg.cookie = cookie;
585
586         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
587         if (msg != NULL)
588                 uni_msg_destroy(msg);
589         if (m == NULL)
590                 return;
591
592         NG_SEND_DATA_ONLY(error, priv->upper, m);
593 }
594
595 static void
596 dump_uni_msg(struct uni_msg *msg)
597 {
598         u_int pos;
599
600         for (pos = 0; pos < uni_msg_len(msg); pos++) {
601                 if (pos % 16 == 0)
602                         printf("%06o ", pos);
603                 if (pos % 16 == 8)
604                         printf("  ");
605                 printf(" %02x", msg->b_rptr[pos]);
606                 if (pos % 16 == 15)
607                         printf("\n");
608         }
609         if (pos % 16 != 0)
610                 printf("\n");
611 }
612
613 /*
614  * Dump a SAAL signal in either direction
615  */
616 static void
617 dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
618 {
619         struct priv *priv = NG_NODE_PRIVATE(node);
620
621         printf("signal %s SAAL: ", to ? "to" : "from");
622
623         switch (sig) {
624 #define D(S) case S: printf("%s", #S); break
625
626         D(SAAL_ESTABLISH_request);
627         D(SAAL_ESTABLISH_indication);
628         D(SAAL_ESTABLISH_confirm);
629         D(SAAL_RELEASE_request);
630         D(SAAL_RELEASE_confirm);
631         D(SAAL_RELEASE_indication);
632         D(SAAL_DATA_request);
633         D(SAAL_DATA_indication);
634         D(SAAL_UDATA_request);
635         D(SAAL_UDATA_indication);
636
637 #undef D
638           default:
639                 printf("sig=%d", sig); break;
640         }
641         if (msg != NULL) {
642                 printf(" data=%zu\n", uni_msg_len(msg));
643                 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
644                         dump_uni_msg(msg);
645         } else
646                 printf("\n");
647 }
648
649 /*
650  * Receive signal from SSCOP.
651  *
652  * If this is a data signal, repackage the data into one large buffer.
653  * UNI shouldn't be the bottleneck in a system and this greatly simplifies
654  * parsing in UNI.
655  */
656 static int
657 ng_uni_rcvlower(hook_p hook __unused, item_p item)
658 {
659         node_p node = NG_HOOK_NODE(hook);
660         struct priv *priv = NG_NODE_PRIVATE(node);
661         struct mbuf *m;
662         struct sscfu_arg arg;
663         struct uni_msg *msg;
664         int error;
665
666         if (!priv->enabled) {
667                 NG_FREE_ITEM(item);
668                 return (ENOTCONN);
669         }
670
671         NGI_GET_M(item, m);
672         NG_FREE_ITEM(item);
673
674         if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
675                 m_freem(m);
676                 return (error);
677         }
678         m_freem(m);
679
680         if (uni_msg_len(msg) < sizeof(arg)) {
681                 uni_msg_destroy(msg);
682                 printf("%s: packet too short\n", __func__);
683                 return (EINVAL);
684         }
685         bcopy(msg->b_rptr, &arg, sizeof(arg));
686         msg->b_rptr += sizeof(arg);
687
688         if (arg.sig > SAAL_UDATA_indication) {
689                 uni_msg_destroy(msg);
690                 printf("%s: bogus signal\n", __func__);
691                 return (EINVAL);
692         }
693
694         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
695                 dump_saal_signal(node, arg.sig, msg, 0);
696
697         uni_saal_input(priv->uni, arg.sig, msg);
698         uni_work(priv->uni);
699
700         return (0);
701 }
702
703 /*
704  * Send signal to sscop.
705  * Pack the message into an mbuf chain.
706  */
707 static void
708 uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
709 {
710         node_p node = (node_p)varg;
711         struct priv *priv = NG_NODE_PRIVATE(node);
712         struct mbuf *m;
713         struct sscfu_arg arg;
714         int error;
715
716         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
717                 dump_saal_signal(node, sig, msg, 1);
718
719         if (priv->lower == NULL) {
720                 if (msg != NULL)
721                         uni_msg_destroy(msg);
722                 return;
723         }
724
725         arg.sig = sig;
726
727         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
728         if (msg != NULL)
729                 uni_msg_destroy(msg);
730         if (m == NULL)
731                 return;
732
733         NG_SEND_DATA_ONLY(error, priv->lower, m);
734 }
735
736 static void
737 uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
738 {
739         va_list ap;
740
741         static char *facnames[] = {
742 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
743                 UNI_DEBUG_FACILITIES
744 #undef UNI_DEBUG_DEFINE
745         };
746
747         printf("%s: ", facnames[fac]);
748
749         va_start(ap, fmt);
750         vprintf(fmt, ap);
751         va_end(ap);
752
753         printf("\n");
754 }
755
756 /************************************************************/
757 /*
758  * Memory debugging
759  */
760 struct unimem_debug {
761         const char      *file;
762         u_int           lno;
763         LIST_ENTRY(unimem_debug) link;
764         char            data[0];
765 };
766 LIST_HEAD(unimem_debug_list, unimem_debug);
767
768 static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
769     LIST_HEAD_INITIALIZER(nguni_freemem[0]),
770     LIST_HEAD_INITIALIZER(nguni_freemem[1]),
771     LIST_HEAD_INITIALIZER(nguni_freemem[2]),
772     LIST_HEAD_INITIALIZER(nguni_freemem[3]),
773     LIST_HEAD_INITIALIZER(nguni_freemem[4]),
774 };
775 static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
776     LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
777     LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
778     LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
779     LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
780     LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
781 };
782
783 static struct mtx nguni_unilist_mtx;
784
785 static const char *unimem_names[UNIMEM_TYPES] = {
786         "instance",
787         "all",
788         "signal",
789         "call",
790         "party"
791 };
792
793 static void
794 uni_init(void)
795 {
796         mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
797             MTX_DEF);
798 }
799
800 static void
801 uni_fini(void)
802 {
803         u_int type;
804         struct unimem_debug *h;
805
806         for (type = 0; type < UNIMEM_TYPES; type++) {
807                 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
808                         LIST_REMOVE(h, link);
809                         free(h, M_UNI);
810                 }
811
812                 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
813                         LIST_REMOVE(h, link);
814                         printf("ng_uni: %s in use: %p (%s,%u)\n",
815                             unimem_names[type], (caddr_t)h->data,
816                             h->file, h->lno);
817                         free(h, M_UNI);
818                 }
819         }
820
821         mtx_destroy(&nguni_unilist_mtx);
822 }
823
824 /*
825  * Allocate a chunk of memory from a given type.
826  */
827 void *
828 ng_uni_malloc(enum unimem type, const char *file, u_int lno)
829 {
830         struct unimem_debug *d;
831         size_t full;
832
833         /*
834          * Try to allocate
835          */
836         mtx_lock(&nguni_unilist_mtx);
837         if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
838                 LIST_REMOVE(d, link);
839         mtx_unlock(&nguni_unilist_mtx);
840
841         if (d == NULL) {
842                 /*
843                  * allocate
844                  */
845                 full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
846                 if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
847                         return (NULL);
848         } else {
849                 bzero(d->data, unimem_sizes[type]);
850         }
851         d->file = file;
852         d->lno = lno;
853
854         mtx_lock(&nguni_unilist_mtx);
855         LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
856         mtx_unlock(&nguni_unilist_mtx);
857         return (d->data);
858 }
859
860 void
861 ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
862 {
863         struct unimem_debug *d, *h;
864
865         d = (struct unimem_debug *)
866             ((char *)ptr - offsetof(struct unimem_debug, data));
867
868         mtx_lock(&nguni_unilist_mtx);
869
870         LIST_FOREACH(h, &nguni_usedmem[type], link)
871                 if (d == h)
872                         break;
873
874         if (h != NULL) {
875                 LIST_REMOVE(d, link);
876                 LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
877         } else {
878                 /*
879                  * Not on used list - try free list.
880                  */
881                 LIST_FOREACH(h, &nguni_freemem[type], link)
882                         if (d == h)
883                                 break;
884                 if (h == NULL)
885                         printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
886                             file, lno, ptr, unimem_names[type]);
887                 else
888                         printf("ng_uni: %s,%u: %p(%s) was already destroyed "
889                             "in %s,%u\n",
890                             file, lno, ptr, unimem_names[type],
891                             h->file, h->lno);
892         }
893         mtx_unlock(&nguni_unilist_mtx);
894 }
895 /************************************************************/
896 /*
897  * INITIALISATION
898  */
899
900 /*
901  * Loading and unloading of node type
902  */
903 static int
904 ng_uni_mod_event(module_t mod, int event, void *data)
905 {
906         int error = 0;
907
908         switch(event) {
909           case MOD_LOAD:
910                 uni_init();
911                 break;
912
913           case MOD_UNLOAD:
914                 uni_fini();
915                 break;
916
917           default:
918                 error = EOPNOTSUPP;
919                 break;
920         }
921         return (error);
922 }