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