2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2001-2003
5 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
8 * Author: Hartmut Brandt <harti@freebsd.org>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
31 * Netgraph module for ATM-Forum UNI 4.0 signalling
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.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>
48 #include <machine/stdarg.h>
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>
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");
68 MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
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
89 static const struct ng_parse_struct_field ng_uni_config_type_info[] =
91 static const struct ng_parse_type ng_uni_config_type = {
92 &ng_parse_struct_type,
93 ng_uni_config_type_info
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
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
113 static const struct ng_parse_struct_field ng_uni_debug_type_info[] =
115 static const struct ng_parse_type ng_uni_debug_type = {
116 &ng_parse_struct_type,
117 ng_uni_debug_type_info
123 static const struct ng_cmdlist ng_uni_cmdlist[] = {
149 &ng_uni_set_config_type,
150 &ng_uni_config_mask_type,
171 &ng_parse_uint32_type
177 * Netgraph module data
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;
187 static int ng_uni_mod_event(module_t, int, void *);
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,
201 NETGRAPH_INIT(uni, &ng_uni_typestruct);
203 static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
205 static void uni_saal_output(struct uni *, void *, enum saal_sig,
207 static void uni_verbose(struct uni *, void *, u_int, const char *, ...)
209 static void uni_do_status(struct uni *, void *, void *, const char *, ...)
212 static const struct uni_funcs uni_funcs = {
219 /************************************************************/
224 ng_uni_constructor(node_p node)
228 gone_in(14, "ng_uni: netgraph ATM modules");
230 priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
232 if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
233 free(priv, M_NG_UNI);
237 NG_NODE_SET_PRIVATE(node, priv);
238 NG_NODE_FORCE_WRITER(node);
244 ng_uni_shutdown(node_p node)
246 struct priv *priv = NG_NODE_PRIVATE(node);
248 uni_destroy(priv->uni);
250 free(priv, M_NG_UNI);
251 NG_NODE_SET_PRIVATE(node, NULL);
258 /************************************************************/
263 uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
268 sbuf_printf(sbuf, fmt, ap);
273 text_status(node_p node, struct priv *priv, char *buf, u_int len)
278 sbuf_new(&sbuf, buf, len, 0);
280 if (priv->lower != NULL)
281 sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
282 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
283 NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
285 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
287 if (priv->upper != NULL)
288 sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
289 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
290 NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
292 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
294 sbuf_printf(&sbuf, "debugging:");
295 for (f = 0; f < UNI_MAXFACILITY; f++)
296 if (uni_get_debug(priv->uni, f) != 0)
297 sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
298 uni_get_debug(priv->uni, f));
299 sbuf_printf(&sbuf, "\n");
302 uni_status(priv->uni, &sbuf);
305 return (sbuf_len(&sbuf));
309 ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
311 struct priv *priv = NG_NODE_PRIVATE(node);
312 struct ng_mesg *resp = NULL;
317 NGI_GET_MSG(item, msg);
319 switch (msg->header.typecookie) {
320 case NGM_GENERIC_COOKIE:
321 switch (msg->header.cmd) {
322 case NGM_TEXT_STATUS:
323 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
329 resp->header.arglen = text_status(node, priv,
330 (char *)resp->data, resp->header.arglen) + 1;
340 switch (msg->header.cmd) {
341 case NGM_UNI_SETDEBUG:
343 struct ngm_uni_debug *arg;
345 if (msg->header.arglen > sizeof(*arg)) {
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]);
355 case NGM_UNI_GETDEBUG:
357 struct ngm_uni_debug *arg;
359 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
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);
370 case NGM_UNI_GET_CONFIG:
372 struct uni_config *config;
374 if (msg->header.arglen != 0) {
378 NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
383 config = (struct uni_config *)resp->data;
384 uni_get_config(priv->uni, config);
389 case NGM_UNI_SET_CONFIG:
391 struct ngm_uni_set_config *arg;
392 struct ngm_uni_config_mask *mask;
394 if (msg->header.arglen != sizeof(*arg)) {
398 arg = (struct ngm_uni_set_config *)msg->data;
400 NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
405 mask = (struct ngm_uni_config_mask *)resp->data;
409 uni_set_config(priv->uni, &arg->config,
410 &mask->mask, &mask->popt_mask, &mask->option_mask);
416 if (msg->header.arglen != 0) {
427 case NGM_UNI_DISABLE:
428 if (msg->header.arglen != 0) {
432 if (!priv->enabled) {
437 uni_reset(priv->uni);
440 case NGM_UNI_GETSTATE:
441 if (msg->header.arglen != 0) {
445 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
450 *(u_int32_t *)resp->data =
451 priv->enabled ? (uni_getcustate(priv->uni) + 1)
466 NG_RESPOND_MSG(error, node, item, resp);
471 /************************************************************/
476 ng_uni_newhook(node_p node, hook_p hook, const char *name)
478 struct priv *priv = NG_NODE_PRIVATE(node);
480 if (strcmp(name, "lower") == 0) {
482 } else if(strcmp(name, "upper") == 0) {
484 NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
492 ng_uni_disconnect(hook_p hook)
494 node_p node = NG_HOOK_NODE(hook);
495 struct priv *priv = NG_NODE_PRIVATE(node);
497 if(hook == priv->lower)
499 else if(hook == priv->upper)
502 printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
504 if (NG_NODE_NUMHOOKS(node) == 0) {
505 if (NG_NODE_IS_VALID(node))
506 ng_rmnode_self(node);
512 /************************************************************/
517 * Receive signal from USER.
519 * Repackage the data into one large buffer.
522 ng_uni_rcvupper(hook_p hook, item_p item)
524 node_p node = NG_HOOK_NODE(hook);
525 struct priv *priv = NG_NODE_PRIVATE(node);
531 if (!priv->enabled) {
539 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
545 if (uni_msg_len(msg) < sizeof(arg)) {
546 printf("%s: packet too short\n", __func__);
547 uni_msg_destroy(msg);
551 bcopy(msg->b_rptr, &arg, sizeof(arg));
552 msg->b_rptr += sizeof(arg);
554 if (arg.sig >= UNIAPI_MAXSIG) {
555 printf("%s: bogus signal\n", __func__);
556 uni_msg_destroy(msg);
559 uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
566 * Upper layer signal from UNI
569 uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
572 node_p node = (node_p)varg;
573 struct priv *priv = NG_NODE_PRIVATE(node);
578 if (priv->upper == NULL) {
580 uni_msg_destroy(msg);
586 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
588 uni_msg_destroy(msg);
592 NG_SEND_DATA_ONLY(error, priv->upper, m);
596 dump_uni_msg(struct uni_msg *msg)
600 for (pos = 0; pos < uni_msg_len(msg); pos++) {
602 printf("%06o ", pos);
605 printf(" %02x", msg->b_rptr[pos]);
614 * Dump a SAAL signal in either direction
617 dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
619 struct priv *priv = NG_NODE_PRIVATE(node);
621 printf("signal %s SAAL: ", to ? "to" : "from");
624 #define D(S) case S: printf("%s", #S); break
626 D(SAAL_ESTABLISH_request);
627 D(SAAL_ESTABLISH_indication);
628 D(SAAL_ESTABLISH_confirm);
629 D(SAAL_RELEASE_request);
630 D(SAAL_RELEASE_confirm);
631 D(SAAL_RELEASE_indication);
632 D(SAAL_DATA_request);
633 D(SAAL_DATA_indication);
634 D(SAAL_UDATA_request);
635 D(SAAL_UDATA_indication);
639 printf("sig=%d", sig); break;
642 printf(" data=%zu\n", uni_msg_len(msg));
643 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
650 * Receive signal from SSCOP.
652 * If this is a data signal, repackage the data into one large buffer.
653 * UNI shouldn't be the bottleneck in a system and this greatly simplifies
657 ng_uni_rcvlower(hook_p hook __unused, item_p item)
659 node_p node = NG_HOOK_NODE(hook);
660 struct priv *priv = NG_NODE_PRIVATE(node);
662 struct sscfu_arg arg;
666 if (!priv->enabled) {
674 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
680 if (uni_msg_len(msg) < sizeof(arg)) {
681 uni_msg_destroy(msg);
682 printf("%s: packet too short\n", __func__);
685 bcopy(msg->b_rptr, &arg, sizeof(arg));
686 msg->b_rptr += sizeof(arg);
688 if (arg.sig > SAAL_UDATA_indication) {
689 uni_msg_destroy(msg);
690 printf("%s: bogus signal\n", __func__);
694 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
695 dump_saal_signal(node, arg.sig, msg, 0);
697 uni_saal_input(priv->uni, arg.sig, msg);
704 * Send signal to sscop.
705 * Pack the message into an mbuf chain.
708 uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
710 node_p node = (node_p)varg;
711 struct priv *priv = NG_NODE_PRIVATE(node);
713 struct sscfu_arg arg;
716 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
717 dump_saal_signal(node, sig, msg, 1);
719 if (priv->lower == NULL) {
721 uni_msg_destroy(msg);
727 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
729 uni_msg_destroy(msg);
733 NG_SEND_DATA_ONLY(error, priv->lower, m);
737 uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
741 static char *facnames[] = {
742 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
744 #undef UNI_DEBUG_DEFINE
747 printf("%s: ", facnames[fac]);
756 /************************************************************/
760 struct unimem_debug {
763 LIST_ENTRY(unimem_debug) link;
766 LIST_HEAD(unimem_debug_list, unimem_debug);
768 static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
769 LIST_HEAD_INITIALIZER(nguni_freemem[0]),
770 LIST_HEAD_INITIALIZER(nguni_freemem[1]),
771 LIST_HEAD_INITIALIZER(nguni_freemem[2]),
772 LIST_HEAD_INITIALIZER(nguni_freemem[3]),
773 LIST_HEAD_INITIALIZER(nguni_freemem[4]),
775 static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
776 LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
777 LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
778 LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
779 LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
780 LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
783 static struct mtx nguni_unilist_mtx;
785 static const char *unimem_names[UNIMEM_TYPES] = {
796 mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
804 struct unimem_debug *h;
806 for (type = 0; type < UNIMEM_TYPES; type++) {
807 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
808 LIST_REMOVE(h, link);
812 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
813 LIST_REMOVE(h, link);
814 printf("ng_uni: %s in use: %p (%s,%u)\n",
815 unimem_names[type], (caddr_t)h->data,
821 mtx_destroy(&nguni_unilist_mtx);
825 * Allocate a chunk of memory from a given type.
828 ng_uni_malloc(enum unimem type, const char *file, u_int lno)
830 struct unimem_debug *d;
836 mtx_lock(&nguni_unilist_mtx);
837 if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
838 LIST_REMOVE(d, link);
839 mtx_unlock(&nguni_unilist_mtx);
845 full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
846 if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
849 bzero(d->data, unimem_sizes[type]);
854 mtx_lock(&nguni_unilist_mtx);
855 LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
856 mtx_unlock(&nguni_unilist_mtx);
861 ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
863 struct unimem_debug *d, *h;
865 d = (struct unimem_debug *)
866 ((char *)ptr - offsetof(struct unimem_debug, data));
868 mtx_lock(&nguni_unilist_mtx);
870 LIST_FOREACH(h, &nguni_usedmem[type], link)
875 LIST_REMOVE(d, link);
876 LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
879 * Not on used list - try free list.
881 LIST_FOREACH(h, &nguni_freemem[type], link)
885 printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
886 file, lno, ptr, unimem_names[type]);
888 printf("ng_uni: %s,%u: %p(%s) was already destroyed "
890 file, lno, ptr, unimem_names[type],
893 mtx_unlock(&nguni_unilist_mtx);
895 /************************************************************/
901 * Loading and unloading of node type
904 ng_uni_mod_event(module_t mod, int event, void *data)