summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/atm
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2004-08-12 14:22:00 +0000
committerharti <harti@FreeBSD.org>2004-08-12 14:22:00 +0000
commit2e8091dd5b60ab5b07fcfca6063ddbae4b3c895e (patch)
treefeded7e7d1a7eddad56044f002711319debd873c /sys/netgraph/atm
parent939573c38dbfc0f16e52d1fbc7592aa5c72b4843 (diff)
downloadFreeBSD-src-2e8091dd5b60ab5b07fcfca6063ddbae4b3c895e.zip
FreeBSD-src-2e8091dd5b60ab5b07fcfca6063ddbae4b3c895e.tar.gz
This is the netgraph node framework for the user side call control
node for ATM. This node implements the API to the signalling services.
Diffstat (limited to 'sys/netgraph/atm')
-rw-r--r--sys/netgraph/atm/ccatm/ng_ccatm.c1198
-rw-r--r--sys/netgraph/atm/ccatm/ng_ccatm_cust.h54
-rw-r--r--sys/netgraph/atm/ng_ccatm.h170
3 files changed, 1422 insertions, 0 deletions
diff --git a/sys/netgraph/atm/ccatm/ng_ccatm.c b/sys/netgraph/atm/ccatm/ng_ccatm.c
new file mode 100644
index 0000000..3f85a60
--- /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 <harti@freebsd.org>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sbuf.h>
+#include <machine/stdarg.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+#include <netnatm/unimsg.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/api/unisap.h>
+#include <netnatm/sig/unidef.h>
+#include <netgraph/atm/ngatmbase.h>
+#include <netgraph/atm/ng_uni.h>
+#include <netnatm/api/atmapi.h>
+#include <netgraph/atm/ng_ccatm.h>
+#include <netnatm/api/ccatm.h>
+
+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 0000000..5720e8b
--- /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 <harti@freebsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/atm/ngatmbase.h>
+
+#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 0000000..ecc0738
--- /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 <harti@freebsd.org>
+ *
+ * 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
OpenPOWER on IntegriCloud