From bc878862fbc4798e04c8409847d74f17bcdc12b3 Mon Sep 17 00:00:00 2001 From: harti Date: Fri, 7 Nov 2003 09:15:14 +0000 Subject: The layer 3 (signalling) of NgATM netgraph node: ng_uni. This node handles user and network side signaling and partly PNNI. --- sys/netgraph/atm/ng_uni.h | 119 +++++ sys/netgraph/atm/uni/ng_uni.c | 932 +++++++++++++++++++++++++++++++++++++ sys/netgraph/atm/uni/ng_uni_cust.h | 152 ++++++ 3 files changed, 1203 insertions(+) create mode 100644 sys/netgraph/atm/ng_uni.h create mode 100644 sys/netgraph/atm/uni/ng_uni.c create mode 100644 sys/netgraph/atm/uni/ng_uni_cust.h (limited to 'sys/netgraph') diff --git a/sys/netgraph/atm/ng_uni.h b/sys/netgraph/atm/ng_uni.h new file mode 100644 index 0000000..957f3ad --- /dev/null +++ b/sys/netgraph/atm/ng_uni.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * Netgraph module for UNI 4.0 + */ +#ifndef _NETGRAPH_ATM_NG_UNI_H_ +#define _NETGRAPH_ATM_NG_UNI_H_ + +#define NG_UNI_NODE_TYPE "uni" +#define NGM_UNI_COOKIE 981112392 + +enum { + NGM_UNI_GETDEBUG, /* get debug flags */ + NGM_UNI_SETDEBUG, /* set debug flags */ + NGM_UNI_GET_CONFIG, /* get configuration */ + NGM_UNI_SET_CONFIG, /* set configuration */ + NGM_UNI_ENABLE, /* enable processing */ + NGM_UNI_DISABLE, /* free resources and disable */ + NGM_UNI_GETSTATE, /* retrieve coord state */ +}; + +struct ngm_uni_debug { + uint32_t level[UNI_MAXFACILITY]; +}; +#define NGM_UNI_DEBUGLEVEL_INFO { \ + &ng_parse_uint32_type, \ + UNI_MAXFACILITY \ +} +#define NGM_UNI_DEBUG_INFO \ + { \ + { "level", &ng_uni_debuglevel_type }, \ + { NULL } \ + } + +#define NGM_UNI_CONFIG_INFO \ + { \ + { "proto", &ng_parse_uint32_type }, \ + { "popt", &ng_parse_uint32_type }, \ + { "option", &ng_parse_uint32_type }, \ + { "timer301", &ng_parse_uint32_type }, \ + { "timer303", &ng_parse_uint32_type }, \ + { "init303", &ng_parse_uint32_type }, \ + { "timer308", &ng_parse_uint32_type }, \ + { "init308", &ng_parse_uint32_type }, \ + { "timer309", &ng_parse_uint32_type }, \ + { "timer310", &ng_parse_uint32_type }, \ + { "timer313", &ng_parse_uint32_type }, \ + { "timer316", &ng_parse_uint32_type }, \ + { "init316", &ng_parse_uint32_type }, \ + { "timer317", &ng_parse_uint32_type }, \ + { "timer322", &ng_parse_uint32_type }, \ + { "init322", &ng_parse_uint32_type }, \ + { "timer397", &ng_parse_uint32_type }, \ + { "timer398", &ng_parse_uint32_type }, \ + { "timer399", &ng_parse_uint32_type }, \ + { NULL } \ + } + +struct ngm_uni_config_mask { + uint32_t mask; + uint32_t popt_mask; + uint32_t option_mask; +}; +#define NGM_UNI_CONFIG_MASK_INFO \ + { \ + { "mask", &ng_parse_hint32_type }, \ + { "popt_mask", &ng_parse_hint32_type }, \ + { "option_mask", &ng_parse_hint32_type }, \ + { NULL } \ + } + +struct ngm_uni_set_config { + struct uni_config config; + struct ngm_uni_config_mask mask; +}; +#define NGM_UNI_SET_CONFIG_INFO \ + { \ + { "config", &ng_uni_config_type }, \ + { "mask", &ng_uni_config_mask_type }, \ + { NULL } \ + } + +/* + * API message + */ +struct uni_arg { + uint32_t sig; + uint32_t cookie; + u_char data[]; +}; + +#endif diff --git a/sys/netgraph/atm/uni/ng_uni.c b/sys/netgraph/atm/uni/ng_uni.c new file mode 100644 index 0000000..c6b6113 --- /dev/null +++ b/sys/netgraph/atm/uni/ng_uni.c @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Netgraph module for ATM-Forum UNI 4.0 signalling + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MALLOC_DEFINE(M_NG_UNI, "netgraph_uni", "netgraph uni node"); +MALLOC_DEFINE(M_UNI, "netgraph uni", "uni protocol data"); + +MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1); + +/* + * Private node data + */ +struct priv { + hook_p upper; + hook_p lower; + struct uni *uni; + int enabled; +}; + +/* UNI CONFIG MASK */ +static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] = + NGM_UNI_CONFIG_MASK_INFO; +static const struct ng_parse_type ng_uni_config_mask_type = { + &ng_parse_struct_type, + ng_uni_config_mask_type_info +}; + +/* UNI_CONFIG */ +static const struct ng_parse_struct_field ng_uni_config_type_info[] = + NGM_UNI_CONFIG_INFO; +static const struct ng_parse_type ng_uni_config_type = { + &ng_parse_struct_type, + ng_uni_config_type_info +}; + +/* SET CONFIG */ +static const struct ng_parse_struct_field ng_uni_set_config_type_info[] = + NGM_UNI_SET_CONFIG_INFO; +static const struct ng_parse_type ng_uni_set_config_type = { + &ng_parse_struct_type, + ng_uni_set_config_type_info +}; + +/* + * Parse DEBUG + */ +static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info = + NGM_UNI_DEBUGLEVEL_INFO; +static const struct ng_parse_type ng_uni_debuglevel_type = { + &ng_parse_fixedarray_type, + &ng_uni_debuglevel_type_info +}; +static const struct ng_parse_struct_field ng_uni_debug_type_info[] = + NGM_UNI_DEBUG_INFO; +static const struct ng_parse_type ng_uni_debug_type = { + &ng_parse_struct_type, + ng_uni_debug_type_info +}; + +/* + * Command list + */ +static const struct ng_cmdlist ng_uni_cmdlist[] = { + { + NGM_UNI_COOKIE, + NGM_UNI_GETDEBUG, + "getdebug", + NULL, + &ng_uni_debug_type + }, + { + NGM_UNI_COOKIE, + NGM_UNI_SETDEBUG, + "setdebug", + &ng_uni_debug_type, + NULL + }, + { + NGM_UNI_COOKIE, + NGM_UNI_GET_CONFIG, + "get_config", + NULL, + &ng_uni_config_type + }, + { + NGM_UNI_COOKIE, + NGM_UNI_SET_CONFIG, + "set_config", + &ng_uni_set_config_type, + &ng_uni_config_mask_type, + }, + { + NGM_UNI_COOKIE, + NGM_UNI_ENABLE, + "enable", + NULL, + NULL, + }, + { + NGM_UNI_COOKIE, + NGM_UNI_DISABLE, + "disable", + NULL, + NULL, + }, + { + NGM_UNI_COOKIE, + NGM_UNI_GETSTATE, + "getstate", + NULL, + &ng_parse_uint32_type + }, + { 0 } +}; + +/* + * Netgraph module data + */ +static ng_constructor_t ng_uni_constructor; +static ng_shutdown_t ng_uni_shutdown; +static ng_rcvmsg_t ng_uni_rcvmsg; +static ng_newhook_t ng_uni_newhook; +static ng_disconnect_t ng_uni_disconnect; +static ng_rcvdata_t ng_uni_rcvlower; +static ng_rcvdata_t ng_uni_rcvupper; + +static int ng_uni_mod_event(module_t, int, void *); + +static struct ng_type ng_uni_typestruct = { + NG_ABI_VERSION, + NG_UNI_NODE_TYPE, + ng_uni_mod_event, /* Module event handler (optional) */ + ng_uni_constructor, /* Node constructor */ + ng_uni_rcvmsg, /* control messages come here */ + ng_uni_shutdown, /* reset, and free resources */ + ng_uni_newhook, /* first notification of new hook */ + NULL, /* findhook */ + NULL, /* connect */ + ng_uni_rcvlower, /* rcvdata */ + ng_uni_disconnect, /* notify on disconnect */ + ng_uni_cmdlist, +}; +NETGRAPH_INIT(uni, &ng_uni_typestruct); + +static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t, + struct uni_msg *); +static void uni_saal_output(struct uni *, void *, enum saal_sig, + struct uni_msg *); +static void uni_verbose(struct uni *, void *, u_int, const char *, ...) + __printflike(4, 5); +static void uni_do_status(struct uni *, void *, void *, const char *, ...) + __printflike(4, 5); + +static const struct uni_funcs uni_funcs = { + uni_uni_output, + uni_saal_output, + uni_verbose, + uni_do_status +}; + +/************************************************************/ +/* + * NODE MANAGEMENT + */ +static int +ng_uni_constructor(node_p node) +{ + struct priv *priv; + + if ((priv = malloc(sizeof(*priv), M_NG_UNI, M_NOWAIT | M_ZERO)) == NULL) + return (ENOMEM); + + if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) { + free(priv, M_NG_UNI); + return (ENOMEM); + } + + NG_NODE_SET_PRIVATE(node, priv); + NG_NODE_FORCE_WRITER(node); + + return (0); +} + +static int +ng_uni_shutdown(node_p node) +{ + struct priv *priv = NG_NODE_PRIVATE(node); + + uni_destroy(priv->uni); + + free(priv, M_NG_UNI); + NG_NODE_SET_PRIVATE(node, NULL); + + NG_NODE_UNREF(node); + + return (0); +} + +/************************************************************/ +/* + * CONTROL MESSAGES + */ +static void +uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sbuf_printf(sbuf, fmt, ap); + va_end(ap); +} + +static int +text_status(node_p node, struct priv *priv, char *buf, u_int len) +{ + struct sbuf sbuf; + u_int f; + + sbuf_new(&sbuf, buf, len, 0); + + if (priv->lower != NULL) + sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n", + NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), + NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); + else + sbuf_printf(&sbuf, "lower hook: \n"); + + if (priv->upper != NULL) + sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n", + NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), + NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); + else + sbuf_printf(&sbuf, "upper hook: \n"); + + sbuf_printf(&sbuf, "debugging:"); + for (f = 0; f < UNI_MAXFACILITY; f++) + if (uni_get_debug(priv->uni, f) != 0) + sbuf_printf(&sbuf, " %s=%u", uni_facname(f), + uni_get_debug(priv->uni, f)); + sbuf_printf(&sbuf, "\n"); + + if (priv->uni) + uni_status(priv->uni, &sbuf); + + sbuf_finish(&sbuf); + return (sbuf_len(&sbuf)); +} + +static int +ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook) +{ + struct priv *priv = NG_NODE_PRIVATE(node); + struct ng_mesg *resp = NULL; + struct ng_mesg *msg; + int error = 0; + u_int i; + + NGI_GET_MSG(item, msg); + + switch (msg->header.typecookie) { + + case NGM_GENERIC_COOKIE: + switch (msg->header.cmd) { + + case NGM_TEXT_STATUS: + NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + + resp->header.arglen = text_status(node, priv, + (char *)resp->data, resp->header.arglen) + 1; + break; + + default: + error = EINVAL; + break; + } + break; + + case NGM_UNI_COOKIE: + switch (msg->header.cmd) { + + case NGM_UNI_SETDEBUG: + { + struct ngm_uni_debug *arg; + + if (msg->header.arglen > sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_uni_debug *)msg->data; + for (i = 0; i < UNI_MAXFACILITY; i++) + uni_set_debug(priv->uni, i, arg->level[i]); + break; + } + + case NGM_UNI_GETDEBUG: + { + struct ngm_uni_debug *arg; + + NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); + if(resp == NULL) { + error = ENOMEM; + break; + } + arg = (struct ngm_uni_debug *)resp->data; + for (i = 0; i < UNI_MAXFACILITY; i++) + arg->level[i] = uni_get_debug(priv->uni, i); + break; + } + + case NGM_UNI_GET_CONFIG: + { + struct uni_config *config; + + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + config = (struct uni_config *)resp->data; + uni_get_config(priv->uni, config); + + break; + } + + case NGM_UNI_SET_CONFIG: + { + struct ngm_uni_set_config *arg; + struct ngm_uni_config_mask *mask; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_uni_set_config *)msg->data; + + NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + mask = (struct ngm_uni_config_mask *)resp->data; + + *mask = arg->mask; + + uni_set_config(priv->uni, &arg->config, + &mask->mask, &mask->popt_mask, &mask->option_mask); + + break; + } + + case NGM_UNI_ENABLE: + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + if (priv->enabled) { + error = EISCONN; + break; + } + priv->enabled = 1; + break; + + case NGM_UNI_DISABLE: + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + if (!priv->enabled) { + error = ENOTCONN; + break; + } + priv->enabled = 0; + uni_reset(priv->uni); + break; + + case NGM_UNI_GETSTATE: + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); + if(resp == NULL) { + error = ENOMEM; + break; + } + *(u_int32_t *)resp->data = + priv->enabled ? (uni_getcustate(priv->uni) + 1) + : 0; + break; + + default: + error = EINVAL; + break; + } + break; + + default: + error = EINVAL; + break; + } + + NG_RESPOND_MSG(error, node, item, resp); + NG_FREE_MSG(msg); + return (error); +} + +/************************************************************/ +/* + * HOOK MANAGEMENT + */ +static int +ng_uni_newhook(node_p node, hook_p hook, const char *name) +{ + struct priv *priv = NG_NODE_PRIVATE(node); + + if (strcmp(name, "lower") == 0) { + priv->lower = hook; + } else if(strcmp(name, "upper") == 0) { + priv->upper = hook; + NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper); + } else + return EINVAL; + + return 0; +} + +static int +ng_uni_disconnect(hook_p hook) +{ + node_p node = NG_HOOK_NODE(hook); + struct priv *priv = NG_NODE_PRIVATE(node); + + if(hook == priv->lower) + priv->lower = NULL; + else if(hook == priv->upper) + priv->upper = NULL; + else + printf("%s: bogus hook %s\n", __FUNCTION__, NG_HOOK_NAME(hook)); + + if (NG_NODE_NUMHOOKS(node) == 0) { + if (NG_NODE_IS_VALID(node)) + ng_rmnode_self(node); + } + + return (0); +} + +/************************************************************/ +/* + * DATA + */ +/* + * Receive signal from USER. + * + * Repackage the data into one large buffer. + */ +static int +ng_uni_rcvupper(hook_p hook, item_p item) +{ + node_p node = NG_HOOK_NODE(hook); + struct priv *priv = NG_NODE_PRIVATE(node); + struct mbuf *m; + struct uni_arg arg; + struct uni_msg *msg; + int error; + + if (!priv->enabled) { + NG_FREE_ITEM(item); + return (ENOTCONN); + } + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { + m_freem(m); + return (error); + } + m_freem(m); + + if (uni_msg_len(msg) < sizeof(arg)) { + printf("%s: packet too short\n", __FUNCTION__); + uni_msg_destroy(msg); + return (EINVAL); + } + + bcopy(msg->b_rptr, &arg, sizeof(arg)); + msg->b_rptr += sizeof(arg); + + if (arg.sig >= UNIAPI_MAXSIG) { + printf("%s: bogus signal\n", __FUNCTION__); + uni_msg_destroy(msg); + return (EINVAL); + } + uni_uni_input(priv->uni, arg.sig, arg.cookie, msg); + uni_work(priv->uni); + + return (0); +} + + +/* + * Upper layer signal from UNI + */ +static void +uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie, + struct uni_msg *msg) +{ + node_p node = (node_p)varg; + struct priv *priv = NG_NODE_PRIVATE(node); + struct mbuf *m; + struct uni_arg arg; + int error; + + if (priv->upper == NULL) { + if (msg != NULL) + uni_msg_destroy(msg); + return; + } + arg.sig = sig; + arg.cookie = cookie; + + m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); + if (msg != NULL) + uni_msg_destroy(msg); + if (m == NULL) + return; + + NG_SEND_DATA_ONLY(error, priv->upper, m); +} + + +static void +dump_uni_msg(struct uni_msg *msg) +{ + u_int pos; + + for (pos = 0; pos < uni_msg_len(msg); pos++) { + if (pos % 16 == 0) + printf("%06o ", pos); + if (pos % 16 == 8) + printf(" "); + printf(" %02x", msg->b_rptr[pos]); + if (pos % 16 == 15) + printf("\n"); + } + if (pos % 16 != 0) + printf("\n"); +} + + +/* + * Dump a SAAL signal in either direction + */ +static void +dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to) +{ + struct priv *priv = NG_NODE_PRIVATE(node); + + printf("signal %s SAAL: ", to ? "to" : "from"); + + switch (sig) { + +#define D(S) case S: printf("%s", #S); break + + D(SAAL_ESTABLISH_request); + D(SAAL_ESTABLISH_indication); + D(SAAL_ESTABLISH_confirm); + D(SAAL_RELEASE_request); + D(SAAL_RELEASE_confirm); + D(SAAL_RELEASE_indication); + D(SAAL_DATA_request); + D(SAAL_DATA_indication); + D(SAAL_UDATA_request); + D(SAAL_UDATA_indication); + +#undef D + default: + printf("sig=%d", sig); break; + } + if (msg != NULL) { + printf(" data=%zu\n", uni_msg_len(msg)); + if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1) + dump_uni_msg(msg); + } else + printf("\n"); +} + +/* + * Receive signal from SSCOP. + * + * If this is a data signal, repackage the data into one large buffer. + * UNI shouldn't be the bottleneck in a system and this greatly simplifies + * parsing in UNI. + */ +static int +ng_uni_rcvlower(hook_p hook __unused, item_p item) +{ + node_p node = NG_HOOK_NODE(hook); + struct priv *priv = NG_NODE_PRIVATE(node); + struct mbuf *m; + struct sscfu_arg arg; + struct uni_msg *msg; + int error; + + if (!priv->enabled) { + NG_FREE_ITEM(item); + return (ENOTCONN); + } + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { + m_freem(m); + return (error); + } + m_freem(m); + + if (uni_msg_len(msg) < sizeof(arg)) { + uni_msg_destroy(msg); + printf("%s: packet too short\n", __FUNCTION__); + return (EINVAL); + } + bcopy(msg->b_rptr, &arg, sizeof(arg)); + msg->b_rptr += sizeof(arg); + + if (arg.sig > SAAL_UDATA_indication) { + uni_msg_destroy(msg); + printf("%s: bogus signal\n", __FUNCTION__); + return (EINVAL); + } + + if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) + dump_saal_signal(node, arg.sig, msg, 0); + + uni_saal_input(priv->uni, arg.sig, msg); + uni_work(priv->uni); + + return (0); +} + +/* + * Send signal to sscop. + * Pack the message into an mbuf chain. + */ +static void +uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg) +{ + node_p node = (node_p)varg; + struct priv *priv = NG_NODE_PRIVATE(node); + struct mbuf *m; + struct sscfu_arg arg; + int error; + + if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) + dump_saal_signal(node, sig, msg, 1); + + if (priv->lower == NULL) { + if (msg != NULL) + uni_msg_destroy(msg); + return; + } + + arg.sig = sig; + + m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); + if (msg != NULL) + uni_msg_destroy(msg); + if (m == NULL) + return; + + NG_SEND_DATA_ONLY(error, priv->lower, m); +} + +static void +uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...) +{ + va_list ap; + + static char *facnames[] = { +#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] #D, + UNI_DEBUG_FACILITIES +#undef UNI_DEBUG_DEFINE + }; + + printf("%s: ", facnames[fac]); + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + printf("\n"); +} + + +/************************************************************/ +/* + * Memory debugging + */ +struct unimem_debug { + const char *file; + u_int lno; + LIST_ENTRY(unimem_debug) link; + char data[0]; +}; +LIST_HEAD(unimem_debug_list, unimem_debug); + +static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = { + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), +}; +static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = { + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), + LIST_HEAD_INITIALIZER(unimem_debug), +}; + +static struct mtx nguni_unilist_mtx; + +static const char *unimem_names[UNIMEM_TYPES] = { + "instance", + "all", + "signal", + "call", + "party" +}; + +static void +uni_init(void) +{ + mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL, 0); +} + +static void +uni_fini(void) +{ + u_int type; + struct unimem_debug *h; + + for (type = 0; type < UNIMEM_TYPES; type++) { + while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) { + LIST_REMOVE(h, link); + free(h, M_UNI); + } + + while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) { + LIST_REMOVE(h, link); + printf("ng_uni: %s in use: %p (%s,%u)\n", + unimem_names[type], (caddr_t)h->data, + h->file, h->lno); + free(h, M_UNI); + } + } + + mtx_destroy(&nguni_unilist_mtx); +} + +/* + * Allocate a chunk of memory from a given type. + */ +void * +ng_uni_malloc(enum unimem type, const char *file, u_int lno) +{ + struct unimem_debug *d; + size_t full; + + /* + * Try to allocate + */ + mtx_lock(&nguni_unilist_mtx); + if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL) + LIST_REMOVE(d, link); + mtx_unlock(&nguni_unilist_mtx); + + if (d == NULL) { + /* + * allocate + */ + full = unimem_sizes[type] + offsetof(struct unimem_debug, data); + if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL) + return (NULL); + } else { + bzero(d->data, unimem_sizes[type]); + } + d->file = file; + d->lno = lno; + + mtx_lock(&nguni_unilist_mtx); + LIST_INSERT_HEAD(&nguni_usedmem[type], d, link); + mtx_unlock(&nguni_unilist_mtx); + return (d->data); +} + +void +ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno) +{ + struct unimem_debug *d, *h; + + d = (struct unimem_debug *) + ((char *)ptr - offsetof(struct unimem_debug, data)); + + mtx_lock(&nguni_unilist_mtx); + + LIST_FOREACH(h, &nguni_usedmem[type], link) + if (d == h) + break; + + if (h != NULL) { + LIST_REMOVE(d, link); + LIST_INSERT_HEAD(&nguni_freemem[type], d, link); + } else { + /* + * Not on used list - try free list. + */ + LIST_FOREACH(h, &nguni_freemem[type], link) + if (d == h) + break; + if (h == NULL) + printf("ng_uni: %s,%u: %p(%s) was never allocated\n", + file, lno, ptr, unimem_names[type]); + else + printf("ng_uni: %s,%u: %p(%s) was already destroyed " + "in %s,%u\n", + file, lno, ptr, unimem_names[type], + h->file, h->lno); + } + mtx_unlock(&nguni_unilist_mtx); +} +/************************************************************/ +/* + * INITIALISATION + */ + +/* + * Loading and unloading of node type + */ +static int +ng_uni_mod_event(module_t mod, int event, void *data) +{ + int s; + int error = 0; + + s = splnet(); + switch(event) { + + case MOD_LOAD: + uni_init(); + break; + + case MOD_UNLOAD: + uni_fini(); + break; + + default: + error = EOPNOTSUPP; + break; + } + splx(s); + return (error); +} diff --git a/sys/netgraph/atm/uni/ng_uni_cust.h b/sys/netgraph/atm/uni/ng_uni_cust.h new file mode 100644 index 0000000..84e63e8 --- /dev/null +++ b/sys/netgraph/atm/uni/ng_uni_cust.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Customisation of signalling source to the NG environment. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASSERT(E, M) KASSERT(E,M) + +/* + * Memory + */ +enum unimem { + UNIMEM_INS = 0, + UNIMEM_ALL, + UNIMEM_SIG, + UNIMEM_CALL, + UNIMEM_PARTY, +}; +#define UNIMEM_TYPES 5 + +void *ng_uni_malloc(enum unimem, const char *, u_int); +void ng_uni_free(enum unimem, void *, const char *, u_int); + +#define INS_ALLOC() ng_uni_malloc(UNIMEM_INS, __FILE__, __LINE__) +#define INS_FREE(P) ng_uni_free(UNIMEM_INS, P, __FILE__, __LINE__) + +#define UNI_ALLOC() ng_uni_malloc(UNIMEM_ALL, __FILE__, __LINE__) +#define UNI_FREE(P) ng_uni_free(UNIMEM_ALL, P, __FILE__, __LINE__) + +#define SIG_ALLOC() ng_uni_malloc(UNIMEM_SIG, __FILE__, __LINE__) +#define SIG_FREE(P) ng_uni_free(UNIMEM_SIG, P, __FILE__, __LINE__) + +#define CALL_ALLOC() ng_uni_malloc(UNIMEM_CALL, __FILE__, __LINE__) +#define CALL_FREE(P) ng_uni_free(UNIMEM_CALL, P, __FILE__, __LINE__) + +#define PARTY_ALLOC() ng_uni_malloc(UNIMEM_PARTY, __FILE__, __LINE__) +#define PARTY_FREE(P) ng_uni_free(UNIMEM_PARTY, P, __FILE__, __LINE__) + +/* + * Timers + */ +struct uni_timer { + struct callout_handle c; +}; + +#define _TIMER_INIT(X,T) callout_handle_init(&(X)->T.c) +#define _TIMER_DESTROY(UNI,FIELD) _TIMER_STOP(UNI,FIELD) +#define _TIMER_STOP(UNI,FIELD) do { \ + ng_untimeout(FIELD.c, (UNI)->arg); \ + callout_handle_init(&FIELD.c); \ + } while (0) +#define TIMER_ISACT(UNI,T) ((UNI)->T.c.callout != NULL) +#define _TIMER_START(UNI,ARG,FIELD,DUE,FUNC) do { \ + _TIMER_STOP(UNI, FIELD); \ + FIELD.c = ng_timeout((UNI)->arg, NULL, \ + hz * (DUE) / 1000, FUNC, (ARG), 0); \ + } while (0) + +#define TIMER_FUNC_UNI(T,F) \ +static void F(struct uni *); \ +static void \ +_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \ +{ \ + struct uni *uni = (struct uni *)arg1; \ + \ + callout_handle_init(&uni->T.c); \ + (F)(uni); \ + uni_work(uni); \ +} + +/* + * Be careful: call may be invalid after the call to F + */ +#define TIMER_FUNC_CALL(T,F) \ +static void F(struct call *); \ +static void \ +_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \ +{ \ + struct call *call = (struct call *)arg1; \ + struct uni *uni = call->uni; \ + \ + callout_handle_init(&call->T.c); \ + (F)(call); \ + uni_work(uni); \ +} + +/* + * Be careful: call/party may be invalid after the call to F + */ +#define TIMER_FUNC_PARTY(T,F) \ +static void F(struct party *); \ +static void \ +_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \ +{ \ + struct party *party = (struct party *)arg1; \ + struct uni *uni = party->call->uni; \ + \ + callout_handle_init(&party->T.c); \ + (F)(party); \ + uni_work(uni); \ +} + +extern size_t unimem_sizes[UNIMEM_TYPES]; + +#define UNICORE \ +size_t unimem_sizes[UNIMEM_TYPES] = { \ + [UNIMEM_INS] sizeof(struct uni), \ + [UNIMEM_ALL] sizeof(struct uni_all), \ + [UNIMEM_SIG] sizeof(struct sig), \ + [UNIMEM_CALL] sizeof(struct call), \ + [UNIMEM_PARTY] sizeof(struct party) \ +}; + +#define memmove(T, F, L) bcopy((F), (T), (L)) -- cgit v1.1