Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / netgraph7 / 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  * $FreeBSD: src/sys/netgraph/atm/uni/ng_uni.c,v 1.6 2005/10/31 15:41:26 rwatson Exp $
32  * $DragonFly: src/sys/netgraph7/atm/uni/ng_uni.c,v 1.2 2008/06/26 23:05:39 dillon Exp $
33  * $DragonFly: src/sys/netgraph7/atm/uni/ng_uni.c,v 1.2 2008/06/26 23:05:39 dillon Exp $
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 "ng_message.h"
49 #include "netgraph.h"
50 #include "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 "atm/ng_sscop.h"
60 #include "atm/ng_sscfu.h"
61 #include "atm/ng_uni.h"
62
63 MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
64 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         if ((priv = kmalloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_NULLOK | M_ZERO)) == NULL)
227                 return (ENOMEM);
228
229         if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
230                 kfree(priv, M_NG_UNI);
231                 return (ENOMEM);
232         }
233
234         NG_NODE_SET_PRIVATE(node, priv);
235         NG_NODE_FORCE_WRITER(node);
236
237         return (0);
238 }
239
240 static int
241 ng_uni_shutdown(node_p node)
242 {
243         struct priv *priv = NG_NODE_PRIVATE(node);
244
245         uni_destroy(priv->uni);
246
247         kfree(priv, M_NG_UNI);
248         NG_NODE_SET_PRIVATE(node, NULL);
249
250         NG_NODE_UNREF(node);
251
252         return (0);
253 }
254
255 /************************************************************/
256 /*
257  * CONTROL MESSAGES
258  */
259 static void
260 uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
261 {
262         va_list ap;
263
264         va_start(ap, fmt);
265         sbuf_printf(sbuf, fmt, ap);
266         va_end(ap);
267 }
268
269 static int
270 text_status(node_p node, struct priv *priv, char *buf, u_int len)
271 {
272         struct sbuf sbuf;
273         u_int f;
274
275         sbuf_new(&sbuf, buf, len, 0);
276
277         if (priv->lower != NULL)
278                 sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
279                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
280                     NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
281         else
282                 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
283
284         if (priv->upper != NULL)
285                 sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
286                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
287                     NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
288         else
289                 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
290
291         sbuf_printf(&sbuf, "debugging:");
292         for (f = 0; f < UNI_MAXFACILITY; f++)
293                 if (uni_get_debug(priv->uni, f) != 0)
294                         sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
295                             uni_get_debug(priv->uni, f));
296         sbuf_printf(&sbuf, "\n");
297
298         if (priv->uni)
299                 uni_status(priv->uni, &sbuf);
300
301         sbuf_finish(&sbuf);
302         return (sbuf_len(&sbuf));
303 }
304
305 static int
306 ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
307 {
308         struct priv *priv = NG_NODE_PRIVATE(node);
309         struct ng_mesg *resp = NULL;
310         struct ng_mesg *msg;
311         int error = 0;
312         u_int i;
313
314         NGI_GET_MSG(item, msg);
315
316         switch (msg->header.typecookie) {
317
318           case NGM_GENERIC_COOKIE:
319                 switch (msg->header.cmd) {
320
321                   case NGM_TEXT_STATUS:
322                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK);
323                         if (resp == NULL) {
324                                 error = ENOMEM;
325                                 break;
326                         }
327
328                         resp->header.arglen = text_status(node, priv,
329                             (char *)resp->data, resp->header.arglen) + 1;
330                         break;
331
332                   default:
333                         error = EINVAL;
334                         break;
335                 }
336                 break;
337
338           case NGM_UNI_COOKIE:
339                 switch (msg->header.cmd) {
340
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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 /*
567  * Upper layer signal from UNI
568  */
569 static void
570 uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
571     struct uni_msg *msg)
572 {
573         node_p node = (node_p)varg;
574         struct priv *priv = NG_NODE_PRIVATE(node);
575         struct mbuf *m;
576         struct uni_arg arg;
577         int error;
578
579         if (priv->upper == NULL) {
580                 if (msg != NULL)
581                         uni_msg_destroy(msg);
582                 return;
583         }
584         arg.sig = sig;
585         arg.cookie = cookie;
586
587         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
588         if (msg != NULL)
589                 uni_msg_destroy(msg);
590         if (m == NULL)
591                 return;
592
593         NG_SEND_DATA_ONLY(error, priv->upper, m);
594 }
595
596
597 static void
598 dump_uni_msg(struct uni_msg *msg)
599 {
600         u_int pos;
601
602         for (pos = 0; pos < uni_msg_len(msg); pos++) {
603                 if (pos % 16 == 0)
604                         printf("%06o ", pos);
605                 if (pos % 16 == 8)
606                         printf("  ");
607                 printf(" %02x", msg->b_rptr[pos]);
608                 if (pos % 16 == 15)
609                         printf("\n");
610         }
611         if (pos % 16 != 0)
612                 printf("\n");
613 }
614
615
616 /*
617  * Dump a SAAL signal in either direction
618  */
619 static void
620 dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
621 {
622         struct priv *priv = NG_NODE_PRIVATE(node);
623
624         printf("signal %s SAAL: ", to ? "to" : "from");
625
626         switch (sig) {
627
628 #define D(S) case S: printf("%s", #S); break
629
630         D(SAAL_ESTABLISH_request);
631         D(SAAL_ESTABLISH_indication);
632         D(SAAL_ESTABLISH_confirm);
633         D(SAAL_RELEASE_request);
634         D(SAAL_RELEASE_confirm);
635         D(SAAL_RELEASE_indication);
636         D(SAAL_DATA_request);
637         D(SAAL_DATA_indication);
638         D(SAAL_UDATA_request);
639         D(SAAL_UDATA_indication);
640
641 #undef D
642           default:
643                 printf("sig=%d", sig); break;
644         }
645         if (msg != NULL) {
646                 printf(" data=%zu\n", uni_msg_len(msg));
647                 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
648                         dump_uni_msg(msg);
649         } else
650                 printf("\n");
651 }
652
653 /*
654  * Receive signal from SSCOP.
655  *
656  * If this is a data signal, repackage the data into one large buffer.
657  * UNI shouldn't be the bottleneck in a system and this greatly simplifies
658  * parsing in UNI.
659  */
660 static int
661 ng_uni_rcvlower(hook_p hook __unused, item_p item)
662 {
663         node_p node = NG_HOOK_NODE(hook);
664         struct priv *priv = NG_NODE_PRIVATE(node);
665         struct mbuf *m;
666         struct sscfu_arg arg;
667         struct uni_msg *msg;
668         int error;
669
670         if (!priv->enabled) {
671                 NG_FREE_ITEM(item);
672                 return (ENOTCONN);
673         }
674
675         NGI_GET_M(item, m);
676         NG_FREE_ITEM(item);
677
678         if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
679                 m_freem(m);
680                 return (error);
681         }
682         m_freem(m);
683
684         if (uni_msg_len(msg) < sizeof(arg)) {
685                 uni_msg_destroy(msg);
686                 printf("%s: packet too short\n", __func__);
687                 return (EINVAL);
688         }
689         bcopy(msg->b_rptr, &arg, sizeof(arg));
690         msg->b_rptr += sizeof(arg);
691
692         if (arg.sig > SAAL_UDATA_indication) {
693                 uni_msg_destroy(msg);
694                 printf("%s: bogus signal\n", __func__);
695                 return (EINVAL);
696         }
697
698         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
699                 dump_saal_signal(node, arg.sig, msg, 0);
700
701         uni_saal_input(priv->uni, arg.sig, msg);
702         uni_work(priv->uni);
703
704         return (0);
705 }
706
707 /*
708  * Send signal to sscop.
709  * Pack the message into an mbuf chain.
710  */
711 static void
712 uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
713 {
714         node_p node = (node_p)varg;
715         struct priv *priv = NG_NODE_PRIVATE(node);
716         struct mbuf *m;
717         struct sscfu_arg arg;
718         int error;
719
720         if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
721                 dump_saal_signal(node, sig, msg, 1);
722
723         if (priv->lower == NULL) {
724                 if (msg != NULL)
725                         uni_msg_destroy(msg);
726                 return;
727         }
728
729         arg.sig = sig;
730
731         m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
732         if (msg != NULL)
733                 uni_msg_destroy(msg);
734         if (m == NULL)
735                 return;
736
737         NG_SEND_DATA_ONLY(error, priv->lower, m);
738 }
739
740 static void
741 uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
742 {
743         va_list ap;
744
745         static char *facnames[] = {
746 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] #D,
747                 UNI_DEBUG_FACILITIES
748 #undef UNI_DEBUG_DEFINE
749         };
750
751         printf("%s: ", facnames[fac]);
752
753         va_start(ap, fmt);
754         vprintf(fmt, ap);
755         va_end(ap);
756
757         printf("\n");
758 }
759
760
761 /************************************************************/
762 /*
763  * Memory debugging
764  */
765 struct unimem_debug {
766         const char      *file;
767         u_int           lno;
768         LIST_ENTRY(unimem_debug) link;
769         char            data[0];
770 };
771 LIST_HEAD(unimem_debug_list, unimem_debug);
772
773 static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
774     LIST_HEAD_INITIALIZER(unimem_debug),
775     LIST_HEAD_INITIALIZER(unimem_debug),
776     LIST_HEAD_INITIALIZER(unimem_debug),
777     LIST_HEAD_INITIALIZER(unimem_debug),
778     LIST_HEAD_INITIALIZER(unimem_debug),
779 };
780 static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
781     LIST_HEAD_INITIALIZER(unimem_debug),
782     LIST_HEAD_INITIALIZER(unimem_debug),
783     LIST_HEAD_INITIALIZER(unimem_debug),
784     LIST_HEAD_INITIALIZER(unimem_debug),
785     LIST_HEAD_INITIALIZER(unimem_debug),
786 };
787
788 static struct mtx nguni_unilist_mtx;
789
790 static const char *unimem_names[UNIMEM_TYPES] = {
791         "instance",
792         "all",
793         "signal",
794         "call",
795         "party"
796 };
797
798 static void
799 uni_init(void)
800 {
801         mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
802             MTX_DEF);
803 }
804
805 static void
806 uni_fini(void)
807 {
808         u_int type;
809         struct unimem_debug *h;
810
811         for (type = 0; type < UNIMEM_TYPES; type++) {
812                 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
813                         LIST_REMOVE(h, link);
814                         kfree(h, M_UNI);
815                 }
816
817                 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
818                         LIST_REMOVE(h, link);
819                         printf("ng_uni: %s in use: %p (%s,%u)\n",
820                             unimem_names[type], (caddr_t)h->data,
821                             h->file, h->lno);
822                         kfree(h, M_UNI);
823                 }
824         }
825
826         mtx_destroy(&nguni_unilist_mtx);
827 }
828
829 /*
830  * Allocate a chunk of memory from a given type.
831  */
832 void *
833 ng_uni_malloc(enum unimem type, const char *file, u_int lno)
834 {
835         struct unimem_debug *d;
836         size_t full;
837
838         /*
839          * Try to allocate
840          */
841         mtx_lock(&nguni_unilist_mtx);
842         if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
843                 LIST_REMOVE(d, link);
844         mtx_unlock(&nguni_unilist_mtx);
845
846         if (d == NULL) {
847                 /*
848                  * allocate
849                  */
850                 full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
851                 if ((d = kmalloc(full, M_UNI, M_WAITOK | M_NULLOK | M_ZERO)) == NULL)
852                         return (NULL);
853         } else {
854                 bzero(d->data, unimem_sizes[type]);
855         }
856         d->file = file;
857         d->lno = lno;
858
859         mtx_lock(&nguni_unilist_mtx);
860         LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
861         mtx_unlock(&nguni_unilist_mtx);
862         return (d->data);
863 }
864
865 void
866 ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
867 {
868         struct unimem_debug *d, *h;
869
870         d = (struct unimem_debug *)
871             ((char *)ptr - offsetof(struct unimem_debug, data));
872
873         mtx_lock(&nguni_unilist_mtx);
874
875         LIST_FOREACH(h, &nguni_usedmem[type], link)
876                 if (d == h)
877                         break;
878
879         if (h != NULL) {
880                 LIST_REMOVE(d, link);
881                 LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
882         } else {
883                 /*
884                  * Not on used list - try free list.
885                  */
886                 LIST_FOREACH(h, &nguni_freemem[type], link)
887                         if (d == h)
888                                 break;
889                 if (h == NULL)
890                         printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
891                             file, lno, ptr, unimem_names[type]);
892                 else
893                         printf("ng_uni: %s,%u: %p(%s) was already destroyed "
894                             "in %s,%u\n",
895                             file, lno, ptr, unimem_names[type],
896                             h->file, h->lno);
897         }
898         mtx_unlock(&nguni_unilist_mtx);
899 }
900 /************************************************************/
901 /*
902  * INITIALISATION
903  */
904
905 /*
906  * Loading and unloading of node type
907  */
908 static int
909 ng_uni_mod_event(module_t mod, int event, void *data)
910 {
911         int s;
912         int error = 0;
913
914         s = splnet();
915         switch(event) {
916
917           case MOD_LOAD:
918                 uni_init();
919                 break;
920
921           case MOD_UNLOAD:
922                 uni_fini();
923                 break;
924
925           default:
926                 error = EOPNOTSUPP;
927                 break;
928         }
929         splx(s);
930         return (error);
931 }