diff --git a/sys/netgraph/atm/ccatm/ng_ccatm.c b/sys/netgraph/atm/ccatm/ng_ccatm.c new file mode 100644 index 000000000000..3f85a6048d0e --- /dev/null +++ b/sys/netgraph/atm/ccatm/ng_ccatm.c @@ -0,0 +1,1198 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2003-2004 + * Hartmut Brandt + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY THE AUTHOR + * AND ITS 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 ITS 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$ + * + * ATM call control and API + */ + +#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 + +MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1); + +MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node"); + +/* + * Command structure parsing + */ + +/* ESI */ +static const struct ng_parse_fixedarray_info ng_ccatm_esi_type_info = + NGM_CCATM_ESI_INFO; +static const struct ng_parse_type ng_ccatm_esi_type = { + &ng_parse_fixedarray_type, + &ng_ccatm_esi_type_info +}; + +/* PORT PARAMETERS */ +static const struct ng_parse_struct_field ng_ccatm_atm_port_type_info[] = + NGM_CCATM_ATM_PORT_INFO; +static const struct ng_parse_type ng_ccatm_atm_port_type = { + &ng_parse_struct_type, + ng_ccatm_atm_port_type_info +}; + +/* PORT structure */ +static const struct ng_parse_struct_field ng_ccatm_port_type_info[] = + NGM_CCATM_PORT_INFO; +static const struct ng_parse_type ng_ccatm_port_type = { + &ng_parse_struct_type, + ng_ccatm_port_type_info +}; + +/* the ADDRESS array itself */ +static const struct ng_parse_fixedarray_info ng_ccatm_addr_array_type_info = + NGM_CCATM_ADDR_ARRAY_INFO; +static const struct ng_parse_type ng_ccatm_addr_array_type = { + &ng_parse_fixedarray_type, + &ng_ccatm_addr_array_type_info +}; + +/* one ADDRESS */ +static const struct ng_parse_struct_field ng_ccatm_uni_addr_type_info[] = + NGM_CCATM_UNI_ADDR_INFO; +static const struct ng_parse_type ng_ccatm_uni_addr_type = { + &ng_parse_struct_type, + ng_ccatm_uni_addr_type_info +}; + +/* ADDRESS request */ +static const struct ng_parse_struct_field ng_ccatm_addr_req_type_info[] = + NGM_CCATM_ADDR_REQ_INFO; +static const struct ng_parse_type ng_ccatm_addr_req_type = { + &ng_parse_struct_type, + ng_ccatm_addr_req_type_info +}; + +/* ADDRESS var-array */ +static int +ng_ccatm_addr_req_array_getlen(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) +{ + const struct ngm_ccatm_get_addresses *p; + + p = (const struct ngm_ccatm_get_addresses *) + (buf - offsetof(struct ngm_ccatm_get_addresses, addr)); + return (p->count); +} +static const struct ng_parse_array_info ng_ccatm_addr_req_array_type_info = + NGM_CCATM_ADDR_REQ_ARRAY_INFO; +static const struct ng_parse_type ng_ccatm_addr_req_array_type = { + &ng_parse_array_type, + &ng_ccatm_addr_req_array_type_info +}; + +/* Outer get_ADDRESSes structure */ +static const struct ng_parse_struct_field ng_ccatm_get_addresses_type_info[] = + NGM_CCATM_GET_ADDRESSES_INFO; +static const struct ng_parse_type ng_ccatm_get_addresses_type = { + &ng_parse_struct_type, + ng_ccatm_get_addresses_type_info +}; + +/* Port array */ +static int +ng_ccatm_port_array_getlen(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) +{ + const struct ngm_ccatm_portlist *p; + + p = (const struct ngm_ccatm_portlist *) + (buf - offsetof(struct ngm_ccatm_portlist, ports)); + return (p->nports); +} +static const struct ng_parse_array_info ng_ccatm_port_array_type_info = + NGM_CCATM_PORT_ARRAY_INFO; +static const struct ng_parse_type ng_ccatm_port_array_type = { + &ng_parse_array_type, + &ng_ccatm_port_array_type_info +}; + +/* Portlist structure */ +static const struct ng_parse_struct_field ng_ccatm_portlist_type_info[] = + NGM_CCATM_PORTLIST_INFO; +static const struct ng_parse_type ng_ccatm_portlist_type = { + &ng_parse_struct_type, + ng_ccatm_portlist_type_info +}; + +/* + * Command list + */ +static const struct ng_cmdlist ng_ccatm_cmdlist[] = { + { + NGM_CCATM_COOKIE, + NGM_CCATM_DUMP, + "dump", + NULL, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_STOP, + "stop", + &ng_ccatm_port_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_START, + "start", + &ng_ccatm_port_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_GETSTATE, + "getstate", + &ng_ccatm_port_type, + &ng_parse_uint32_type + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_GET_ADDRESSES, + "get_addresses", + &ng_ccatm_port_type, + &ng_ccatm_get_addresses_type + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_CLEAR, + "clear", + &ng_ccatm_port_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_ADDRESS_REGISTERED, + "address_reg", + &ng_ccatm_addr_req_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_ADDRESS_UNREGISTERED, + "address_unreg", + &ng_ccatm_addr_req_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_SET_PORT_PARAM, + "set_port_param", + &ng_ccatm_atm_port_type, + NULL + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_GET_PORT_PARAM, + "get_port_param", + &ng_ccatm_port_type, + &ng_ccatm_atm_port_type, + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_GET_PORTLIST, + "get_portlist", + NULL, + &ng_ccatm_portlist_type, + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_SETLOG, + "setlog", + &ng_parse_hint32_type, + &ng_parse_hint32_type, + }, + { + NGM_CCATM_COOKIE, + NGM_CCATM_RESET, + "reset", + NULL, + NULL, + }, + { 0 } +}; + +/* + * Module data + */ +static ng_constructor_t ng_ccatm_constructor; +static ng_rcvmsg_t ng_ccatm_rcvmsg; +static ng_shutdown_t ng_ccatm_shutdown; +static ng_newhook_t ng_ccatm_newhook; +static ng_rcvdata_t ng_ccatm_rcvdata; +static ng_disconnect_t ng_ccatm_disconnect; +static int ng_ccatm_mod_event(module_t, int, void *); + +static struct ng_type ng_ccatm_typestruct = { + .version = NG_ABI_VERSION, + .name = NG_CCATM_NODE_TYPE, + .mod_event = ng_ccatm_mod_event, + .constructor = ng_ccatm_constructor, /* Node constructor */ + .rcvmsg = ng_ccatm_rcvmsg, /* Control messages */ + .shutdown = ng_ccatm_shutdown, /* Node destructor */ + .newhook = ng_ccatm_newhook, /* Arrival of new hook */ + .rcvdata = ng_ccatm_rcvdata, /* receive data */ + .disconnect = ng_ccatm_disconnect, /* disconnect a hook */ + .cmdlist = ng_ccatm_cmdlist, +}; +NETGRAPH_INIT(ccatm, &ng_ccatm_typestruct); + +static ng_rcvdata_t ng_ccatm_rcvuni; +static ng_rcvdata_t ng_ccatm_rcvdump; +static ng_rcvdata_t ng_ccatm_rcvmanage; + +/* + * Private node data. + */ +struct ccnode { + node_p node; /* the owning node */ + hook_p dump; /* dump hook */ + hook_p manage; /* hook to ILMI */ + + struct ccdata *data; + struct mbuf *dump_first; + struct mbuf *dump_last; /* first and last mbuf when dumping */ + + u_int hook_cnt; /* count user and port hooks */ +}; + +/* + * Private UNI hook data + */ +struct cchook { + int is_uni; /* true if uni hook, user otherwise */ + struct ccnode *node; /* the owning node */ + hook_p hook; + void *inst; /* port or user */ +}; + +static void ng_ccatm_send_user(struct ccuser *, void *, u_int, void *, size_t); +static void ng_ccatm_respond_user(struct ccuser *, void *, int, u_int, + void *, size_t); +static void ng_ccatm_send_uni(struct ccconn *, void *, u_int, u_int, + struct uni_msg *); +static void ng_ccatm_send_uni_glob(struct ccport *, void *, u_int, u_int, + struct uni_msg *); +static void ng_ccatm_log(const char *, ...) __printflike(1, 2); + +static const struct cc_funcs cc_funcs = { + .send_user = ng_ccatm_send_user, + .respond_user = ng_ccatm_respond_user, + .send_uni = ng_ccatm_send_uni, + .send_uni_glob = ng_ccatm_send_uni_glob, + .log = ng_ccatm_log, +}; + +/************************************************************ + * + * Create a new node + */ +static int +ng_ccatm_constructor(node_p node) +{ + struct ccnode *priv; + + priv = malloc(sizeof(*priv), M_NG_CCATM, M_NOWAIT | M_ZERO); + if (priv == NULL) + return (ENOMEM); + + priv->node = node; + priv->data = cc_create(&cc_funcs); + if (priv->data == NULL) { + free(priv, M_NG_CCATM); + return (ENOMEM); + } + + NG_NODE_SET_PRIVATE(node, priv); + + return (0); +} + +/* + * Destroy a node. The user list is empty here, because all hooks are + * previously disconnected. The connection lists may not be empty, because + * connections may be waiting for responses from the stack. This also means, + * that no orphaned connections will be made by the port_destroy routine. + */ +static int +ng_ccatm_shutdown(node_p node) +{ + struct ccnode *priv = NG_NODE_PRIVATE(node); + + cc_destroy(priv->data); + + free(priv, M_NG_CCATM); + NG_NODE_SET_PRIVATE(node, NULL); + + NG_NODE_UNREF(node); + + return (0); +} + +/* + * Retrieve the registered addresses for one port or all ports. + * Returns an error code or 0 on success. + */ +static int +ng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg, + struct ng_mesg **resp) +{ + struct ccnode *priv = NG_NODE_PRIVATE(node); + struct uni_addr *addrs; + u_int *ports; + struct ngm_ccatm_get_addresses *list; + u_int count, i; + size_t len; + int err; + + err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count); + if (err != 0) + return (err); + + len = sizeof(*list) + count * sizeof(list->addr[0]); + NG_MKRESPONSE(*resp, msg, len, M_NOWAIT); + if (*resp == NULL) { + free(addrs, M_NG_CCATM); + free(ports, M_NG_CCATM); + return (ENOMEM); + } + list = (struct ngm_ccatm_get_addresses *)(*resp)->data; + + list->count = count; + for (i = 0; i < count; i++) { + list->addr[i].port = ports[i]; + list->addr[i].addr = addrs[i]; + } + + free(addrs, M_NG_CCATM); + free(ports, M_NG_CCATM); + + return (0); +} + +/* + * Dumper function. Pack the data into an mbuf chain. + */ +static int +send_dump(struct ccdata *data, void *uarg, const char *buf) +{ + struct mbuf *m; + struct ccnode *priv = uarg; + + if (priv->dump == NULL) { + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOBUFS); + priv->dump_first = priv->dump_last = m; + m->m_pkthdr.len = 0; + } else { + m = m_getcl(M_DONTWAIT, MT_DATA, 0); + if (m == 0) { + m_freem(priv->dump_first); + return (ENOBUFS); + } + priv->dump_last->m_next = m; + priv->dump_last = m; + } + + strcpy(m->m_data, buf); + priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf)); + + return (0); +} + +/* + * Dump current status to dump hook + */ +static int +ng_ccatm_dump(node_p node) +{ + struct ccnode *priv = NG_NODE_PRIVATE(node); + struct mbuf *m; + int error; + + priv->dump_first = priv->dump_last = NULL; + error = cc_dump(priv->data, MCLBYTES, send_dump, priv); + if (error != 0) + return (error); + + if ((m = priv->dump_first) != NULL) { + priv->dump_first = priv->dump_last = NULL; + NG_SEND_DATA_ONLY(error, priv->dump, m); + return (error); + } + return (0); +} + +/* + * Control message + */ +static int +ng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook) +{ + struct ng_mesg *resp = NULL; + struct ng_mesg *msg; + struct ccnode *priv = NG_NODE_PRIVATE(node); + int error = 0; + + NGI_GET_MSG(item, msg); + + switch (msg->header.typecookie) { + + case NGM_CCATM_COOKIE: + switch (msg->header.cmd) { + + case NGM_CCATM_DUMP: + if (priv->dump) + error = ng_ccatm_dump(node); + else + error = ENOTCONN; + break; + + case NGM_CCATM_STOP: + { + struct ngm_ccatm_port *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + error = cc_port_stop(priv->data, arg->port); + break; + } + + case NGM_CCATM_START: + { + struct ngm_ccatm_port *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + error = cc_port_start(priv->data, arg->port); + break; + } + + case NGM_CCATM_GETSTATE: + { + struct ngm_ccatm_port *arg; + int state; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + error = cc_port_isrunning(priv->data, arg->port, + &state); + if (error == 0) { + NG_MKRESPONSE(resp, msg, sizeof(uint32_t), + M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + *(uint32_t *)resp->data = state; + } + break; + } + + case NGM_CCATM_GET_ADDRESSES: + { + struct ngm_ccatm_port *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + error = ng_ccatm_get_addresses(node, arg->port, msg, + &resp); + break; + } + + case NGM_CCATM_CLEAR: + { + struct ngm_ccatm_port *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + error = cc_port_clear(priv->data, arg->port); + break; + } + + case NGM_CCATM_ADDRESS_REGISTERED: + { + struct ngm_ccatm_addr_req *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_addr_req *)msg->data; + error = cc_addr_register(priv->data, arg->port, + &arg->addr); + break; + } + + case NGM_CCATM_ADDRESS_UNREGISTERED: + { + struct ngm_ccatm_addr_req *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_addr_req *)msg->data; + error = cc_addr_unregister(priv->data, arg->port, + &arg->addr); + break; + } + + case NGM_CCATM_GET_PORT_PARAM: + { + struct ngm_ccatm_port *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct ngm_ccatm_port *)msg->data; + NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info), + M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + error = cc_port_get_param(priv->data, arg->port, + (struct atm_port_info *)resp->data); + if (error != 0) { + free(resp, M_NETGRAPH_MSG); + resp = NULL; + } + break; + } + + case NGM_CCATM_SET_PORT_PARAM: + { + struct atm_port_info *arg; + + if (msg->header.arglen != sizeof(*arg)) { + error = EINVAL; + break; + } + arg = (struct atm_port_info *)msg->data; + error = cc_port_set_param(priv->data, arg); + break; + } + + case NGM_CCATM_GET_PORTLIST: + { + struct ngm_ccatm_portlist *arg; + u_int n, *ports; + + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + error = cc_port_getlist(priv->data, &n, &ports); + if (error != 0) + break; + + NG_MKRESPONSE(resp, msg, sizeof(*arg) + + n * sizeof(arg->ports[0]), M_NOWAIT); + if (resp == NULL) { + free(ports, M_NG_CCATM); + error = ENOMEM; + break; + } + arg = (struct ngm_ccatm_portlist *)resp->data; + + arg->nports = 0; + for (arg->nports = 0; arg->nports < n; arg->nports++) + arg->ports[arg->nports] = ports[arg->nports]; + free(ports, M_NG_CCATM); + break; + } + + case NGM_CCATM_SETLOG: + { + uint32_t log_level; + + log_level = cc_get_log(priv->data); + if (msg->header.arglen != 0) { + if (msg->header.arglen != sizeof(log_level)) { + error = EINVAL; + break; + } + cc_set_log(priv->data, *(uint32_t *)msg->data); + } + + NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + if (msg->header.arglen != 0) + cc_set_log(priv->data, log_level); + break; + } + *(uint32_t *)resp->data = log_level; + break; + } + + case NGM_CCATM_RESET: + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + + if (priv->hook_cnt != 0) { + error = EBUSY; + break; + } + cc_reset(priv->data); + break; + + case NGM_CCATM_GET_EXSTAT: + { + struct atm_exstatus s; + struct atm_exstatus_ep *eps; + struct atm_exstatus_port *ports; + struct atm_exstatus_conn *conns; + struct atm_exstatus_party *parties; + size_t offs; + + if (msg->header.arglen != 0) { + error = EINVAL; + break; + } + error = cc_get_extended_status(priv->data, + &s, &eps, &ports, &conns, &parties); + if (error != 0) + break; + + offs = sizeof(s) + s.neps * sizeof(*eps) + + s.nports * sizeof(*ports) + + s.nconns * sizeof(*conns) + + s.nparties * sizeof(*parties); + + NG_MKRESPONSE(resp, msg, offs, M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + + memcpy(resp->data, &s, sizeof(s)); + offs = sizeof(s); + + memcpy(resp->data + offs, eps, + sizeof(*eps) * s.neps); + offs += sizeof(*eps) * s.neps; + + memcpy(resp->data + offs, ports, + sizeof(*ports) * s.nports); + offs += sizeof(*ports) * s.nports; + + memcpy(resp->data + offs, conns, + sizeof(*conns) * s.nconns); + offs += sizeof(*conns) * s.nconns; + + memcpy(resp->data + offs, parties, + sizeof(*parties) * s.nparties); + offs += sizeof(*parties) * s.nparties; + + free(eps, M_NG_CCATM); + free(ports, M_NG_CCATM); + free(conns, M_NG_CCATM); + free(parties, M_NG_CCATM); + break; + } + + default: + error = EINVAL; + break; + + } + break; + + default: + error = EINVAL; + break; + + } + + NG_RESPOND_MSG(error, node, item, resp); + NG_FREE_MSG(msg); + return (error); +} + +/************************************************************ + * + * New hook arrival + */ +static int +ng_ccatm_newhook(node_p node, hook_p hook, const char *name) +{ + struct ccnode *priv = NG_NODE_PRIVATE(node); + struct ccport *port; + struct ccuser *user; + struct cchook *hd; + u_long lport; + char *end; + + if (strncmp(name, "uni", 3) == 0) { + /* + * This is a UNI hook. Should be a new port. + */ + if (name[3] == '\0') + return (EINVAL); + lport = strtoul(name + 3, &end, 10); + if (*end != '\0' || lport == 0 || lport > 0xffffffff) + return (EINVAL); + + hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT); + if (hd == NULL) + return (ENOMEM); + hd->is_uni = 1; + hd->node = priv; + hd->hook = hook; + + port = cc_port_create(priv->data, hd, (u_int)lport); + if (port == NULL) { + free(hd, M_NG_CCATM); + return (ENOMEM); + } + hd->inst = port; + + NG_HOOK_SET_PRIVATE(hook, hd); + NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni); + NG_HOOK_FORCE_QUEUE(hook); + + priv->hook_cnt++; + + return (0); + } + + if (strcmp(name, "dump") == 0) { + priv->dump = hook; + NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump); + return (0); + } + + if (strcmp(name, "manage") == 0) { + priv->manage = hook; + NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage); + return (0); + } + + /* + * User hook + */ + hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT); + if (hd == NULL) + return (ENOMEM); + hd->is_uni = 0; + hd->node = priv; + hd->hook = hook; + + user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook)); + if (user == NULL) { + free(hd, M_NG_CCATM); + return (ENOMEM); + } + + hd->inst = user; + NG_HOOK_SET_PRIVATE(hook, hd); + NG_HOOK_FORCE_QUEUE(hook); + + priv->hook_cnt++; + + return (0); +} + +/* + * Disconnect a hook + */ +static int +ng_ccatm_disconnect(hook_p hook) +{ + node_p node = NG_HOOK_NODE(hook); + struct ccnode *priv = NG_NODE_PRIVATE(node); + struct cchook *hd = NG_HOOK_PRIVATE(hook); + + if (hook == priv->dump) { + priv->dump = NULL; + + } else if (hook == priv->manage) { + priv->manage = NULL; + cc_unmanage(priv->data); + + } else { + if (hd->is_uni) + cc_port_destroy(hd->inst, 0); + else + cc_user_destroy(hd->inst); + + free(hd, M_NG_CCATM); + NG_HOOK_SET_PRIVATE(hook, NULL); + + priv->hook_cnt--; + + cc_work(hd->node->data); + } + + /* + * When the number of hooks drops to zero, delete the node. + */ + if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) + ng_rmnode_self(node); + + return (0); +} + +/************************************************************ + * + * Receive data from user hook + */ +static int +ng_ccatm_rcvdata(hook_p hook, item_p item) +{ + struct cchook *hd = NG_HOOK_PRIVATE(hook); + struct uni_msg *msg; + struct mbuf *m; + struct ccatm_op op; + int err; + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) { + m_freem(m); + return (err); + } + m_freem(m); + + if (uni_msg_len(msg) < sizeof(op)) { + printf("%s: packet too short\n", __func__); + uni_msg_destroy(msg); + return (EINVAL); + } + + bcopy(msg->b_rptr, &op, sizeof(op)); + msg->b_rptr += sizeof(op); + + err = cc_user_signal(hd->inst, op.op, msg); + cc_work(hd->node->data); + return (err); +} + +/* + * Pack a header and a data area into an mbuf chain + */ +static struct mbuf * +pack_buf(void *h, size_t hlen, void *t, size_t tlen) +{ + struct mbuf *m, *m0, *last; + u_char *buf = (u_char *)t; + size_t n; + + /* header should fit into a normal mbuf */ + MGETHDR(m0, M_NOWAIT, MT_DATA); + if (m0 == NULL) + return NULL; + + KASSERT(hlen <= MHLEN, ("hlen > MHLEN")); + + bcopy(h, m0->m_data, hlen); + m0->m_len = hlen; + m0->m_pkthdr.len = hlen; + + last = m0; + while ((n = tlen) != 0) { + if (n > MLEN) { + m = m_getcl(M_NOWAIT, MT_DATA, 0); + if (n > MCLBYTES) + n = MCLBYTES; + } else + MGET(m, M_NOWAIT, MT_DATA); + + if(m == NULL) + goto drop; + + last->m_next = m; + last = m; + + bcopy(buf, m->m_data, n); + buf += n; + tlen -= n; + m->m_len = n; + m0->m_pkthdr.len += n; + } + + return (m0); + + drop: + m_freem(m0); + return NULL; +} + +/* + * Send an indication to the user. + */ +static void +ng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op, + void *val, size_t len) +{ + struct cchook *hd = uarg; + struct mbuf *m; + struct ccatm_op h; + int error; + + h.op = op; + m = pack_buf(&h, sizeof(h), val, len); + if (m == NULL) + return; + + NG_SEND_DATA_ONLY(error, hd->hook, m); + if (error != 0) + printf("%s: error=%d\n", __func__, error); +} + +/* + * Send a response to the user. + */ +static void +ng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data, + void *val, size_t len) +{ + struct cchook *hd = uarg; + struct mbuf *m; + struct { + struct ccatm_op op; + struct atm_resp resp; + } resp; + int error; + + resp.op.op = ATMOP_RESP; + resp.resp.resp = err; + resp.resp.data = data; + m = pack_buf(&resp, sizeof(resp), val, len); + if (m == NULL) + return; + + NG_SEND_DATA_ONLY(error, hd->hook, m); + if (error != 0) + printf("%s: error=%d\n", __func__, error); +} + +/* + * Receive data from UNI. + */ +static int +ng_ccatm_rcvuni(hook_p hook, item_p item) +{ + struct cchook *hd = NG_HOOK_PRIVATE(hook); + struct uni_msg *msg; + struct uni_arg arg; + struct mbuf *m; + int err; + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) { + m_freem(m); + return (err); + } + m_freem(m); + + if (uni_msg_len(msg) < sizeof(arg)) { + printf("%s: packet too short\n", __func__); + uni_msg_destroy(msg); + return (EINVAL); + } + + bcopy(msg->b_rptr, &arg, sizeof(arg)); + msg->b_rptr += sizeof(arg); + + if (arg.sig == UNIAPI_ERROR) { + if (uni_msg_len(msg) != sizeof(struct uniapi_error)) { + printf("%s: bad UNIAPI_ERROR size %zu\n", __func__, + uni_msg_len(msg)); + uni_msg_destroy(msg); + return (EINVAL); + } + err = cc_uni_response(hd->inst, arg.cookie, + ((struct uniapi_error *)msg->b_rptr)->reason, + ((struct uniapi_error *)msg->b_rptr)->state); + uni_msg_destroy(msg); + } else + err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg); + + cc_work(hd->node->data); + return (err); +} + +/* + * Uarg is the port's uarg. + */ +static void +ng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie, + struct uni_msg *msg) +{ + struct cchook *hd = uarg; + struct uni_arg arg; + struct mbuf *m; + int error; + + arg.sig = op; + arg.cookie = cookie; + + m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); + uni_msg_destroy(msg); + if (m == NULL) + return; + + NG_SEND_DATA_ONLY(error, hd->hook, m); + if (error != 0) + printf("%s: error=%d\n", __func__, error); +} + +/* + * Send a global message to the UNI + */ +static void +ng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie, + struct uni_msg *msg) +{ + struct cchook *hd = uarg; + struct uni_arg arg; + struct mbuf *m; + int error; + + arg.sig = op; + 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, hd->hook, m); + if (error != 0) + printf("%s: error=%d\n", __func__, error); +} +/* + * Receive from ILMID + */ +static int +ng_ccatm_rcvmanage(hook_p hook, item_p item) +{ + NG_FREE_ITEM(item); + return (0); +} + +static int +ng_ccatm_rcvdump(hook_p hook, item_p item) +{ + NG_FREE_ITEM(item); + return (0); +} + +static void +ng_ccatm_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); +} + +/* + * Loading and unloading of node type + */ +static int +ng_ccatm_mod_event(module_t mod, int event, void *data) +{ + int s; + int error = 0; + + s = splnet(); + switch (event) { + + case MOD_LOAD: + break; + + case MOD_UNLOAD: + break; + + default: + error = EOPNOTSUPP; + break; + } + splx(s); + return (error); +} diff --git a/sys/netgraph/atm/ccatm/ng_ccatm_cust.h b/sys/netgraph/atm/ccatm/ng_ccatm_cust.h new file mode 100644 index 000000000000..5720e8bd2805 --- /dev/null +++ b/sys/netgraph/atm/ccatm/ng_ccatm_cust.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003-2004 + * Hartmut Brandt + * 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 call control source to the NG environment. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CCASSERT(E, M) KASSERT(E, M) + +MALLOC_DECLARE(M_NG_CCATM); + +#define CCMALLOC(S) (malloc((S), M_NG_CCATM, M_NOWAIT)) +#define CCZALLOC(S) (malloc((S), M_NG_CCATM, M_NOWAIT | M_ZERO)) +#define CCFREE(P) do { free((P), M_NG_CCATM); } while (0) + +#define CCGETERRNO() (ENOMEM) diff --git a/sys/netgraph/atm/ng_ccatm.h b/sys/netgraph/atm/ng_ccatm.h new file mode 100644 index 000000000000..ecc0738a47be --- /dev/null +++ b/sys/netgraph/atm/ng_ccatm.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2003-2004 + * Hartmut Brandt + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution of this software and documentation 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 or documentation 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$ + * + * Interface to ng_ccatm + */ +#ifndef _NETGRAPH_ATM_NG_CCATM_H_ +#define _NETGRAPH_ATM_NG_CCATM_H_ + +#define NG_CCATM_NODE_TYPE "ccatm" +#define NGM_CCATM_COOKIE 984046139 + +enum { + NGM_CCATM_DUMP, /* dump internal status */ + NGM_CCATM_STOP, /* stop all processing, close all */ + NGM_CCATM_START, /* start processing */ + NGM_CCATM_CLEAR, /* clear prefix/address table */ + NGM_CCATM_GET_ADDRESSES, /* get list of all addresses */ + NGM_CCATM_ADDRESS_REGISTERED, /* registration ok */ + NGM_CCATM_ADDRESS_UNREGISTERED, /* unregistration ok */ + NGM_CCATM_SET_PORT_PARAM, /* set port parameters */ + NGM_CCATM_GET_PORT_PARAM, /* get port parameters */ + NGM_CCATM_GET_PORTLIST, /* get list of port numbers */ + NGM_CCATM_GETSTATE, /* get port status */ + NGM_CCATM_SETLOG, /* set/get loglevel */ + NGM_CCATM_RESET, /* reset everything */ + NGM_CCATM_GET_EXSTAT, /* get extended status */ +}; + +/* + * This must be synchronized with unistruct.h::struct uni_addr + */ +#define NGM_CCATM_ADDR_ARRAY_INFO \ + { \ + &ng_parse_hint8_type, \ + UNI_ADDR_MAXLEN \ + } + +#define NGM_CCATM_UNI_ADDR_INFO \ + { \ + { "type", &ng_parse_uint32_type }, \ + { "plan", &ng_parse_uint32_type }, \ + { "len", &ng_parse_uint32_type }, \ + { "addr", &ng_ccatm_addr_array_type }, \ + { NULL } \ + } + +/* + * Address request + */ +struct ngm_ccatm_addr_req { + uint32_t port; + struct uni_addr addr; +}; +#define NGM_CCATM_ADDR_REQ_INFO \ + { \ + { "port", &ng_parse_uint32_type }, \ + { "addr", &ng_ccatm_uni_addr_type }, \ + { NULL }, \ + } + +/* + * Get current address list + */ +struct ngm_ccatm_get_addresses { + uint32_t count; + struct ngm_ccatm_addr_req addr[]; +}; +#define NGM_CCATM_ADDR_REQ_ARRAY_INFO \ + { \ + &ng_ccatm_addr_req_type, \ + ng_ccatm_addr_req_array_getlen \ + } +#define NGM_CCATM_GET_ADDRESSES_INFO \ + { \ + { "count", &ng_parse_uint32_type }, \ + { "addr", &ng_ccatm_addr_req_array_type }, \ + { NULL } \ + } + +/* + * Port as parameter + */ +struct ngm_ccatm_port { + uint32_t port; +}; +#define NGM_CCATM_PORT_INFO \ + { \ + { "port", &ng_parse_uint32_type }, \ + { NULL } \ + } + +/* + * Port parameters. + * This must be synchronized with atmapi.h::struct atm_port_info. + */ +#define NGM_CCATM_ESI_INFO \ + { \ + &ng_parse_hint8_type, \ + 6 \ + } +#define NGM_CCATM_ATM_PORT_INFO \ + { \ + { "port", &ng_parse_uint32_type }, \ + { "pcr", &ng_parse_uint32_type }, \ + { "max_vpi_bits", &ng_parse_uint32_type }, \ + { "max_vci_bits", &ng_parse_uint32_type }, \ + { "max_svpc_vpi", &ng_parse_uint32_type }, \ + { "max_svcc_vpi", &ng_parse_uint32_type }, \ + { "min_svcc_vci", &ng_parse_uint32_type }, \ + { "esi", &ng_ccatm_esi_type }, \ + { "num_addr", &ng_parse_uint32_type }, \ + { NULL } \ + } + +/* + * List of port numbers + */ +struct ngm_ccatm_portlist { + uint32_t nports; + uint32_t ports[]; +}; +#define NGM_CCATM_PORT_ARRAY_INFO \ + { \ + &ng_parse_uint32_type, \ + ng_ccatm_port_array_getlen \ + } +#define NGM_CCATM_PORTLIST_INFO \ + { \ + { "nports", &ng_parse_uint32_type }, \ + { "ports", &ng_ccatm_port_array_type }, \ + { NULL } \ + } + +struct ccatm_op { + uint32_t op; /* request code */ + u_char data[]; +}; + +#endif