]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/atm/uni/ng_uni.c
Merge llvm-project main llvmorg-12-init-17869-g8e464dd76bef
[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         priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
229
230         if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
231                 free(priv, M_NG_UNI);
232                 return (ENOMEM);
233         }
234
235         NG_NODE_SET_PRIVATE(node, priv);
236         NG_NODE_FORCE_WRITER(node);
237
238         return (0);
239 }
240
241 static int
242 ng_uni_shutdown(node_p node)
243 {
244         struct priv *priv = NG_NODE_PRIVATE(node);
245
246         uni_destroy(priv->uni);
247
248         free(priv, M_NG_UNI);
249         NG_NODE_SET_PRIVATE(node, NULL);
250
251         NG_NODE_UNREF(node);
252
253         return (0);
254 }
255
256 /************************************************************/
257 /*
258  * CONTROL MESSAGES
259  */
260 static void
261 uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
262 {
263         va_list ap;
264
265         va_start(ap, fmt);
266         sbuf_printf(sbuf, fmt, ap);
267         va_end(ap);
268 }
269
270 static int
271 text_status(node_p node, struct priv *priv, char *buf, u_int len)
272 {
273         struct sbuf sbuf;
274         u_int f;
275
276         sbuf_new(&sbuf, buf, len, 0);
277
278         if (priv->lower != NULL)
279                 sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
280                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
281                     NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
282         else
283                 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
284
285         if (priv->upper != NULL)
286                 sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
287                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
288                     NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
289         else
290                 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
291
292         sbuf_printf(&sbuf, "debugging:");
293         for (f = 0; f < UNI_MAXFACILITY; f++)
294                 if (uni_get_debug(priv->uni, f) != 0)
295                         sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
296                             uni_get_debug(priv->uni, f));
297         sbuf_printf(&sbuf, "\n");
298
299         if (priv->uni)
300                 uni_status(priv->uni, &sbuf);
301
302         sbuf_finish(&sbuf);
303         return (sbuf_len(&sbuf));
304 }
305
306 static int
307 ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
308 {
309         struct priv *priv = NG_NODE_PRIVATE(node);
310         struct ng_mesg *resp = NULL;
311         struct ng_mesg *msg;
312         int error = 0;
313         u_int i;
314
315         NGI_GET_MSG(item, msg);
316
317         switch (msg->header.typecookie) {
318           case NGM_GENERIC_COOKIE:
319                 switch (msg->header.cmd) {
320                   case NGM_TEXT_STATUS:
321                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
322                         if (resp == NULL) {
323                                 error = ENOMEM;
324                                 break;
325                         }
326
327                         resp->header.arglen = text_status(node, priv,
328                             (char *)resp->data, resp->header.arglen) + 1;
329                         break;
330
331                   default:
332                         error = EINVAL;
333                         break;
334                 }
335                 break;
336
337           case NGM_UNI_COOKIE:
338                 switch (msg->header.cmd) {
339                   case NGM_UNI_SETDEBUG:
340                     {
341                         struct ngm_uni_debug *arg;
342
343                         if (msg->header.arglen > sizeof(*arg)) {
344                                 error = EINVAL;
345                                 break;
346                         }
347                         arg = (struct ngm_uni_debug *)msg->data;
348                         for (i = 0; i < UNI_MAXFACILITY; i++)
349                                 uni_set_debug(priv->uni, i, arg->level[i]);
350                         break;
351                     }
352
353                   case NGM_UNI_GETDEBUG:
354                     {
355                         struct ngm_uni_debug *arg;
356
357                         NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
358                         if(resp == NULL) {
359                                 error = ENOMEM;
360                                 break;
361                         }
362                         arg = (struct ngm_uni_debug *)resp->data;
363                         for (i = 0; i < UNI_MAXFACILITY; i++)
364                                 arg->level[i] = uni_get_debug(priv->uni, i);
365                         break;
366                     }
367
368                   case NGM_UNI_GET_CONFIG:
369                     {
370                         struct uni_config *config;
371
372                         if (msg->header.arglen != 0) {
373                                 error = EINVAL;
374                                 break;
375                         }
376                         NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
377                         if (resp == NULL) {
378                                 error = ENOMEM;
379                                 break;
380                         }
381                         config = (struct uni_config *)resp->data;
382                         uni_get_config(priv->uni, config);
383
384                         break;
385                     }
386
387                   case NGM_UNI_SET_CONFIG:
388                     {
389                         struct ngm_uni_set_config *arg;
390                         struct ngm_uni_config_mask *mask;
391
392                         if (msg->header.arglen != sizeof(*arg)) {
393                                 error = EINVAL;
394                                 break;
395                         }
396                         arg = (struct ngm_uni_set_config *)msg->data;
397
398                         NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
399                         if (resp == NULL) {
400                                 error = ENOMEM;
401                                 break;
402                         }
403                         mask = (struct ngm_uni_config_mask *)resp->data;
404
405                         *mask = arg->mask;
406
407                         uni_set_config(priv->uni, &arg->config,
408                             &mask->mask, &mask->popt_mask, &mask->option_mask);
409
410                         break;
411                     }
412
413                   case NGM_UNI_ENABLE:
414                         if (msg->header.arglen != 0) {
415                                 error = EINVAL;
416                                 break;
417                         }
418                         if (priv->enabled) {
419                                 error = EISCONN;
420                                 break;
421                         }
422                         priv->enabled = 1;
423                         break;
424
425                   case NGM_UNI_DISABLE:
426                         if (msg->header.arglen != 0) {
427                                 error = EINVAL;
428                                 break;
429                         }
430                         if (!priv->enabled) {
431                                 error = ENOTCONN;
432                                 break;
433                         }
434                         priv->enabled = 0;
435                         uni_reset(priv->uni);
436                         break;
437
438                   case NGM_UNI_GETSTATE:
439                         if (msg->header.arglen != 0) {
440                                 error = EINVAL;
441                                 break;
442                         }
443                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
444                         if(resp == NULL) {
445                                 error = ENOMEM;
446                                 break;
447                         }
448                         *(u_int32_t *)resp->data =
449                             priv->enabled ? (uni_getcustate(priv->uni) + 1)
450                                           : 0;
451                         break;
452
453                   default:
454                         error = EINVAL;
455                         break;
456                 }
457                 break;
458
459           default:
460                 error = EINVAL;
461                 break;
462         }
463
464         NG_RESPOND_MSG(error, node, item, resp);
465         NG_FREE_MSG(msg);
466         return (error);
467 }
468
469 /************************************************************/
470 /*
471  * HOOK MANAGEMENT
472  */
473 static int
474 ng_uni_newhook(node_p node, hook_p hook, const char *name)
475 {
476         struct priv *priv = NG_NODE_PRIVATE(node);
477
478         if (strcmp(name, "lower") == 0) {
479                 priv->lower = hook;
480         } else if(strcmp(name, "upper") == 0) {
481                 priv->upper = hook;
482                 NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
483         } else
484                 return EINVAL;
485
486         return 0;
487 }
488
489 static int
490 ng_uni_disconnect(hook_p hook)
491 {
492         node_p node = NG_HOOK_NODE(hook);
493         struct priv *priv = NG_NODE_PRIVATE(node);
494
495         if(hook == priv->lower)
496                 priv->lower = NULL;
497         else if(hook == priv->upper)
498                 priv->upper = NULL;
499         else
500                 printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
501
502         if (NG_NODE_NUMHOOKS(node) == 0) {
503                 if (NG_NODE_IS_VALID(node))
504                         ng_rmnode_self(node);
505         }
506
507         return (0);
508 }
509
510 /************************************************************/
511 /*
512  * DATA
513  */
514 /*
515  * Receive signal from USER.
516  *
517  * Repackage the data into one large buffer.
518  */
519 static int
520 ng_uni_rcvupper(hook_p hook, item_p item)
521 {
522         node_p node = NG_HOOK_NODE(hook);
523         struct priv *priv = NG_NODE_PRIVATE(node);
524         struct mbuf *m;
525         struct uni_arg arg;
526         struct uni_msg *msg;
527         int error;
528
529         if (!priv->enabled) {
530                 NG_FREE_ITEM(item);
531                 return (ENOTCONN);
532         }
533
534         NGI_GET_M(item, m);
535         NG_FREE_ITEM(item);
536
537         if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
538                 m_freem(m);
539                 return (error);
540         }
541         m_freem(m);
542
543         if (uni_msg_len(msg) < sizeof(arg)) {
544                 printf("%s: packet too short\n", __func__);
545                 uni_msg_destroy(msg);
546                 return (EINVAL);
547         }
548
549         bcopy(msg->b_rptr, &arg, sizeof(arg));
550         msg->b_rptr += sizeof(arg);
551
552         if (arg.sig >= UNIAPI_MAXSIG) {
553                 printf("%s: bogus signal\n", __func__);
554                 uni_msg_destroy(msg);
555                 return (EINVAL);
556         }
557         uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
558         uni_work(priv->uni);
559
560         return (0);
561 }
562
563 /*
564  * Upper layer signal from UNI
565  */
566 static void
567 uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
568     struct uni_msg *msg)
569 {
570         node_p node = (node_p)varg;
571         struct priv *priv = NG_NODE_PRIVATE(node);
572         struct mbuf *m;
573         struct uni_arg arg;
574         int error;
575
576         if (priv->upper == NULL) {
577                 if (msg != NULL)
578                         uni_msg_destroy(msg);
579                 return;
580         }
581         arg.sig = sig;
582         arg.cookie = cookie;
583
584         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
585         if (msg != NULL)
586                 uni_msg_destroy(msg);
587         if (m == NULL)
588                 return;
589
590         NG_SEND_DATA_ONLY(error, priv->upper, m);
591 }
592
593 static void
594 dump_uni_msg(struct uni_msg *msg)
595 {
596         u_int pos;
597
598         for (pos = 0; pos < uni_msg_len(msg); pos++) {
599                 if (pos % 16 == 0)
600                         printf("%06o ", pos);
601                 if (pos % 16 == 8)
602                         printf("  ");
603                 printf(" %02x", msg->b_rptr[pos]);
604                 if (pos % 16 == 15)
605                         printf("\n");
606         }
607         if (pos % 16 != 0)
608                 printf("\n");
609 }
610
611 /*
612  * Dump a SAAL signal in either direction
613  */
614 static void
615 dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
616 {
617         struct priv *priv = NG_NODE_PRIVATE(node);
618
619         printf("signal %s SAAL: ", to ? "to" : "from");
620
621         switch (sig) {
622 #define D(S) case S: printf("%s", #S); break
623
624         D(SAAL_ESTABLISH_request);
625         D(SAAL_ESTABLISH_indication);
626         D(SAAL_ESTABLISH_confirm);
627         D(SAAL_RELEASE_request);
628         D(SAAL_RELEASE_confirm);
629         D(SAAL_RELEASE_indication);
630         D(SAAL_DATA_request);
631         D(SAAL_DATA_indication);
632         D(SAAL_UDATA_request);
633         D(SAAL_UDATA_indication);
634
635 #undef D
636           default:
637                 printf("sig=%d", sig); break;
638         }
639         if (msg != NULL) {
640                 printf(" data=%zu\n", uni_msg_len(msg));
641                 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
642                         dump_uni_msg(msg);
643         } else
644                 printf("\n");
645 }
646
647 /*
648  * Receive signal from SSCOP.
649  *
650  * If this is a data signal, repackage the data into one large buffer.
651  * UNI shouldn't be the bottleneck in a system and this greatly simplifies
652  * parsing in UNI.
653  */
654 static int
655 ng_uni_rcvlower(hook_p hook __unused, item_p item)
656 {
657         node_p node = NG_HOOK_NODE(hook);
658         struct priv *priv = NG_NODE_PRIVATE(node);
659         struct mbuf *m;
660         struct sscfu_arg arg;
661         struct uni_msg *msg;
662         int error;
663
664         if (!priv->enabled) {
665                 NG_FREE_ITEM(item);
666                 return (ENOTCONN);
667         }
668
669         NGI_GET_M(item, m);
670         NG_FREE_ITEM(item);
671
672         if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
673                 m_freem(m);
674                 return (error);
675         }
676         m_freem(m);
677
678         if (uni_msg_len(msg) < sizeof(arg)) {
679                 uni_msg_destroy(msg);
680                 printf("%s: packet too short\n", __func__);
681                 return (EINVAL);
682         }
683         bcopy(msg->b_rptr, &arg, sizeof(arg));
684         msg->b_rptr += sizeof(arg);
685
686         if (arg.sig > SAAL_UDATA_indication) {
687                 uni_msg_destroy(msg);
688                 printf("%s: bogus signal\n", __func__);
689                 return (EINVAL);
690         }
691
692         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
693                 dump_saal_signal(node, arg.sig, msg, 0);
694
695         uni_saal_input(priv->uni, arg.sig, msg);
696         uni_work(priv->uni);
697
698         return (0);
699 }
700
701 /*
702  * Send signal to sscop.
703  * Pack the message into an mbuf chain.
704  */
705 static void
706 uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
707 {
708         node_p node = (node_p)varg;
709         struct priv *priv = NG_NODE_PRIVATE(node);
710         struct mbuf *m;
711         struct sscfu_arg arg;
712         int error;
713
714         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
715                 dump_saal_signal(node, sig, msg, 1);
716
717         if (priv->lower == NULL) {
718                 if (msg != NULL)
719                         uni_msg_destroy(msg);
720                 return;
721         }
722
723         arg.sig = sig;
724
725         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
726         if (msg != NULL)
727                 uni_msg_destroy(msg);
728         if (m == NULL)
729                 return;
730
731         NG_SEND_DATA_ONLY(error, priv->lower, m);
732 }
733
734 static void
735 uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
736 {
737         va_list ap;
738
739         static char *facnames[] = {
740 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
741                 UNI_DEBUG_FACILITIES
742 #undef UNI_DEBUG_DEFINE
743         };
744
745         printf("%s: ", facnames[fac]);
746
747         va_start(ap, fmt);
748         vprintf(fmt, ap);
749         va_end(ap);
750
751         printf("\n");
752 }
753
754 /************************************************************/
755 /*
756  * Memory debugging
757  */
758 struct unimem_debug {
759         const char      *file;
760         u_int           lno;
761         LIST_ENTRY(unimem_debug) link;
762         char            data[0];
763 };
764 LIST_HEAD(unimem_debug_list, unimem_debug);
765
766 static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
767     LIST_HEAD_INITIALIZER(nguni_freemem[0]),
768     LIST_HEAD_INITIALIZER(nguni_freemem[1]),
769     LIST_HEAD_INITIALIZER(nguni_freemem[2]),
770     LIST_HEAD_INITIALIZER(nguni_freemem[3]),
771     LIST_HEAD_INITIALIZER(nguni_freemem[4]),
772 };
773 static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
774     LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
775     LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
776     LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
777     LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
778     LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
779 };
780
781 static struct mtx nguni_unilist_mtx;
782
783 static const char *unimem_names[UNIMEM_TYPES] = {
784         "instance",
785         "all",
786         "signal",
787         "call",
788         "party"
789 };
790
791 static void
792 uni_init(void)
793 {
794         mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
795             MTX_DEF);
796 }
797
798 static void
799 uni_fini(void)
800 {
801         u_int type;
802         struct unimem_debug *h;
803
804         for (type = 0; type < UNIMEM_TYPES; type++) {
805                 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
806                         LIST_REMOVE(h, link);
807                         free(h, M_UNI);
808                 }
809
810                 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
811                         LIST_REMOVE(h, link);
812                         printf("ng_uni: %s in use: %p (%s,%u)\n",
813                             unimem_names[type], (caddr_t)h->data,
814                             h->file, h->lno);
815                         free(h, M_UNI);
816                 }
817         }
818
819         mtx_destroy(&nguni_unilist_mtx);
820 }
821
822 /*
823  * Allocate a chunk of memory from a given type.
824  */
825 void *
826 ng_uni_malloc(enum unimem type, const char *file, u_int lno)
827 {
828         struct unimem_debug *d;
829         size_t full;
830
831         /*
832          * Try to allocate
833          */
834         mtx_lock(&nguni_unilist_mtx);
835         if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
836                 LIST_REMOVE(d, link);
837         mtx_unlock(&nguni_unilist_mtx);
838
839         if (d == NULL) {
840                 /*
841                  * allocate
842                  */
843                 full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
844                 if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
845                         return (NULL);
846         } else {
847                 bzero(d->data, unimem_sizes[type]);
848         }
849         d->file = file;
850         d->lno = lno;
851
852         mtx_lock(&nguni_unilist_mtx);
853         LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
854         mtx_unlock(&nguni_unilist_mtx);
855         return (d->data);
856 }
857
858 void
859 ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
860 {
861         struct unimem_debug *d, *h;
862
863         d = (struct unimem_debug *)
864             ((char *)ptr - offsetof(struct unimem_debug, data));
865
866         mtx_lock(&nguni_unilist_mtx);
867
868         LIST_FOREACH(h, &nguni_usedmem[type], link)
869                 if (d == h)
870                         break;
871
872         if (h != NULL) {
873                 LIST_REMOVE(d, link);
874                 LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
875         } else {
876                 /*
877                  * Not on used list - try free list.
878                  */
879                 LIST_FOREACH(h, &nguni_freemem[type], link)
880                         if (d == h)
881                                 break;
882                 if (h == NULL)
883                         printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
884                             file, lno, ptr, unimem_names[type]);
885                 else
886                         printf("ng_uni: %s,%u: %p(%s) was already destroyed "
887                             "in %s,%u\n",
888                             file, lno, ptr, unimem_names[type],
889                             h->file, h->lno);
890         }
891         mtx_unlock(&nguni_unilist_mtx);
892 }
893 /************************************************************/
894 /*
895  * INITIALISATION
896  */
897
898 /*
899  * Loading and unloading of node type
900  */
901 static int
902 ng_uni_mod_event(module_t mod, int event, void *data)
903 {
904         int error = 0;
905
906         switch(event) {
907           case MOD_LOAD:
908                 uni_init();
909                 break;
910
911           case MOD_UNLOAD:
912                 uni_fini();
913                 break;
914
915           default:
916                 error = EOPNOTSUPP;
917                 break;
918         }
919         return (error);
920 }