2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * Netgraph module for ATM-Forum UNI 4.0 signalling
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD: src/sys/netgraph/atm/uni/ng_uni.c,v 1.6 2005/10/31 15:41:26 rwatson Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.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>
46 #include <machine/stdarg.h>
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>
63 MALLOC_DEFINE(M_NG_UNI
, "netgraph_uni_node", "netgraph uni node");
64 MALLOC_DEFINE(M_UNI
, "netgraph_uni_data", "uni protocol data");
66 MODULE_DEPEND(ng_uni
, ngatmbase
, 1, 1, 1);
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
87 static const struct ng_parse_struct_field ng_uni_config_type_info
[] =
89 static const struct ng_parse_type ng_uni_config_type
= {
90 &ng_parse_struct_type
,
91 ng_uni_config_type_info
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
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
111 static const struct ng_parse_struct_field ng_uni_debug_type_info
[] =
113 static const struct ng_parse_type ng_uni_debug_type
= {
114 &ng_parse_struct_type
,
115 ng_uni_debug_type_info
121 static const struct ng_cmdlist ng_uni_cmdlist
[] = {
147 &ng_uni_set_config_type
,
148 &ng_uni_config_mask_type
,
169 &ng_parse_uint32_type
175 * Netgraph module data
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
;
185 static int ng_uni_mod_event(module_t
, int, void *);
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
,
199 NETGRAPH_INIT(uni
, &ng_uni_typestruct
);
201 static void uni_uni_output(struct uni
*, void *, enum uni_sig
, u_int32_t
,
203 static void uni_saal_output(struct uni
*, void *, enum saal_sig
,
205 static void uni_verbose(struct uni
*, void *, u_int
, const char *, ...)
207 static void uni_do_status(struct uni
*, void *, void *, const char *, ...)
210 static const struct uni_funcs uni_funcs
= {
217 /************************************************************/
222 ng_uni_constructor(node_p node
)
226 if ((priv
= malloc(sizeof(*priv
), M_NG_UNI
, M_NOWAIT
| M_ZERO
)) == NULL
)
229 if ((priv
->uni
= uni_create(node
, &uni_funcs
)) == NULL
) {
230 free(priv
, M_NG_UNI
);
234 NG_NODE_SET_PRIVATE(node
, priv
);
235 NG_NODE_FORCE_WRITER(node
);
241 ng_uni_shutdown(node_p node
)
243 struct priv
*priv
= NG_NODE_PRIVATE(node
);
245 uni_destroy(priv
->uni
);
247 free(priv
, M_NG_UNI
);
248 NG_NODE_SET_PRIVATE(node
, NULL
);
255 /************************************************************/
260 uni_do_status(struct uni
*uni
, void *uarg
, void *sbuf
, const char *fmt
, ...)
265 sbuf_printf(sbuf
, fmt
, ap
);
270 text_status(node_p node
, struct priv
*priv
, char *buf
, u_int len
)
275 sbuf_new(&sbuf
, buf
, len
, 0);
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
)));
282 sbuf_printf(&sbuf
, "lower hook: <not connected>\n");
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
)));
289 sbuf_printf(&sbuf
, "upper hook: <not connected>\n");
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");
299 uni_status(priv
->uni
, &sbuf
);
302 return (sbuf_len(&sbuf
));
306 ng_uni_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
308 struct priv
*priv
= NG_NODE_PRIVATE(node
);
309 struct ng_mesg
*resp
= NULL
;
314 NGI_GET_MSG(item
, msg
);
316 switch (msg
->header
.typecookie
) {
318 case NGM_GENERIC_COOKIE
:
319 switch (msg
->header
.cmd
) {
321 case NGM_TEXT_STATUS
:
322 NG_MKRESPONSE(resp
, msg
, NG_TEXTRESPONSE
, M_NOWAIT
);
328 resp
->header
.arglen
= text_status(node
, priv
,
329 (char *)resp
->data
, resp
->header
.arglen
) + 1;
339 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
);
567 * Upper layer signal from UNI
570 uni_uni_output(struct uni
*uni
, void *varg
, enum uni_sig sig
, u_int32_t cookie
,
573 node_p node
= (node_p
)varg
;
574 struct priv
*priv
= NG_NODE_PRIVATE(node
);
579 if (priv
->upper
== NULL
) {
581 uni_msg_destroy(msg
);
587 m
= uni_msg_pack_mbuf(msg
, &arg
, sizeof(arg
));
589 uni_msg_destroy(msg
);
593 NG_SEND_DATA_ONLY(error
, priv
->upper
, m
);
598 dump_uni_msg(struct uni_msg
*msg
)
602 for (pos
= 0; pos
< uni_msg_len(msg
); pos
++) {
604 printf("%06o ", pos
);
607 printf(" %02x", msg
->b_rptr
[pos
]);
617 * Dump a SAAL signal in either direction
620 dump_saal_signal(node_p node
, enum saal_sig sig
, struct uni_msg
*msg
, int to
)
622 struct priv
*priv
= NG_NODE_PRIVATE(node
);
624 printf("signal %s SAAL: ", to
? "to" : "from");
628 #define D(S) case S: printf("%s", #S); break
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
);
643 printf("sig=%d", sig
); break;
646 printf(" data=%zu\n", uni_msg_len(msg
));
647 if (uni_get_debug(priv
->uni
, UNI_FAC_SAAL
) > 1)
654 * Receive signal from SSCOP.
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
661 ng_uni_rcvlower(hook_p hook __unused
, item_p item
)
663 node_p node
= NG_HOOK_NODE(hook
);
664 struct priv
*priv
= NG_NODE_PRIVATE(node
);
666 struct sscfu_arg arg
;
670 if (!priv
->enabled
) {
678 if ((error
= uni_msg_unpack_mbuf(m
, &msg
)) != 0) {
684 if (uni_msg_len(msg
) < sizeof(arg
)) {
685 uni_msg_destroy(msg
);
686 printf("%s: packet too short\n", __func__
);
689 bcopy(msg
->b_rptr
, &arg
, sizeof(arg
));
690 msg
->b_rptr
+= sizeof(arg
);
692 if (arg
.sig
> SAAL_UDATA_indication
) {
693 uni_msg_destroy(msg
);
694 printf("%s: bogus signal\n", __func__
);
698 if (uni_get_debug(priv
->uni
, UNI_FAC_SAAL
) > 0)
699 dump_saal_signal(node
, arg
.sig
, msg
, 0);
701 uni_saal_input(priv
->uni
, arg
.sig
, msg
);
708 * Send signal to sscop.
709 * Pack the message into an mbuf chain.
712 uni_saal_output(struct uni
*uni
, void *varg
, enum saal_sig sig
, struct uni_msg
*msg
)
714 node_p node
= (node_p
)varg
;
715 struct priv
*priv
= NG_NODE_PRIVATE(node
);
717 struct sscfu_arg arg
;
720 if (uni_get_debug(priv
->uni
, UNI_FAC_SAAL
) > 0)
721 dump_saal_signal(node
, sig
, msg
, 1);
723 if (priv
->lower
== NULL
) {
725 uni_msg_destroy(msg
);
731 m
= uni_msg_pack_mbuf(msg
, &arg
, sizeof(arg
));
733 uni_msg_destroy(msg
);
737 NG_SEND_DATA_ONLY(error
, priv
->lower
, m
);
741 uni_verbose(struct uni
*uni
, void *varg
, u_int fac
, const char *fmt
, ...)
745 static char *facnames
[] = {
746 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] #D,
748 #undef UNI_DEBUG_DEFINE
751 printf("%s: ", facnames
[fac
]);
761 /************************************************************/
765 struct unimem_debug
{
768 LIST_ENTRY(unimem_debug
) link
;
771 LIST_HEAD(unimem_debug_list
, unimem_debug
);
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
),
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
),
788 static struct mtx nguni_unilist_mtx
;
790 static const char *unimem_names
[UNIMEM_TYPES
] = {
801 mtx_init(&nguni_unilist_mtx
, "netgraph UNI structure lists", NULL
,
809 struct unimem_debug
*h
;
811 for (type
= 0; type
< UNIMEM_TYPES
; type
++) {
812 while ((h
= LIST_FIRST(&nguni_freemem
[type
])) != NULL
) {
813 LIST_REMOVE(h
, link
);
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
,
826 mtx_destroy(&nguni_unilist_mtx
);
830 * Allocate a chunk of memory from a given type.
833 ng_uni_malloc(enum unimem type
, const char *file
, u_int lno
)
835 struct unimem_debug
*d
;
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
);
850 full
= unimem_sizes
[type
] + offsetof(struct unimem_debug
, data
);
851 if ((d
= malloc(full
, M_UNI
, M_NOWAIT
| M_ZERO
)) == NULL
)
854 bzero(d
->data
, unimem_sizes
[type
]);
859 mtx_lock(&nguni_unilist_mtx
);
860 LIST_INSERT_HEAD(&nguni_usedmem
[type
], d
, link
);
861 mtx_unlock(&nguni_unilist_mtx
);
866 ng_uni_free(enum unimem type
, void *ptr
, const char *file
, u_int lno
)
868 struct unimem_debug
*d
, *h
;
870 d
= (struct unimem_debug
*)
871 ((char *)ptr
- offsetof(struct unimem_debug
, data
));
873 mtx_lock(&nguni_unilist_mtx
);
875 LIST_FOREACH(h
, &nguni_usedmem
[type
], link
)
880 LIST_REMOVE(d
, link
);
881 LIST_INSERT_HEAD(&nguni_freemem
[type
], d
, link
);
884 * Not on used list - try free list.
886 LIST_FOREACH(h
, &nguni_freemem
[type
], link
)
890 printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
891 file
, lno
, ptr
, unimem_names
[type
]);
893 printf("ng_uni: %s,%u: %p(%s) was already destroyed "
895 file
, lno
, ptr
, unimem_names
[type
],
898 mtx_unlock(&nguni_unilist_mtx
);
900 /************************************************************/
906 * Loading and unloading of node type
909 ng_uni_mod_event(module_t mod
, int event
, void *data
)