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