summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-06-25 13:20:19 +0000
committerharti <harti@FreeBSD.org>2003-06-25 13:20:19 +0000
commitad281045981ca6dfa9af7cd6bcbdb7df539ac573 (patch)
tree92669e2cca6d44a6af40d4143124bc62d98a5bb0
parent1bee454ec78e2a8d7b6588130b73367f45271d37 (diff)
downloadFreeBSD-src-ad281045981ca6dfa9af7cd6bcbdb7df539ac573.zip
FreeBSD-src-ad281045981ca6dfa9af7cd6bcbdb7df539ac573.tar.gz
This is a netgraph node to access ATM interfaces. It works with the
hatm(4) and fatm(4) drivers, en(4) will follow soon.
-rw-r--r--sys/modules/netgraph/Makefile1
-rw-r--r--sys/modules/netgraph/atm/Makefile7
-rw-r--r--sys/modules/netgraph/atm/Makefile.inc3
-rw-r--r--sys/modules/netgraph/atm/atm/Makefile11
-rw-r--r--sys/netgraph/atm/ng_atm.c1371
-rw-r--r--sys/netgraph/atm/ng_atm.h227
6 files changed, 1620 insertions, 0 deletions
diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile
index 12ebb58..49c1f47 100644
--- a/sys/modules/netgraph/Makefile
+++ b/sys/modules/netgraph/Makefile
@@ -3,6 +3,7 @@
SUBDIR= UI \
async \
+ atm \
bpf \
bridge \
cisco \
diff --git a/sys/modules/netgraph/atm/Makefile b/sys/modules/netgraph/atm/Makefile
new file mode 100644
index 0000000..54cc0af
--- /dev/null
+++ b/sys/modules/netgraph/atm/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+SUBDIR= \
+ atm
+
+.include <bsd.subdir.mk>
+
diff --git a/sys/modules/netgraph/atm/Makefile.inc b/sys/modules/netgraph/atm/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/sys/modules/netgraph/atm/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/sys/modules/netgraph/atm/atm/Makefile b/sys/modules/netgraph/atm/atm/Makefile
new file mode 100644
index 0000000..ebd94e1
--- /dev/null
+++ b/sys/modules/netgraph/atm/atm/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+#
+.PATH: ${.CURDIR}/../../../../netgraph/atm
+
+KMOD= ng_atm
+SRCS= ng_atm.c
+# CFLAGS+= -DNGATM_DEBUG
+
+.include <bsd.kmod.mk>
diff --git a/sys/netgraph/atm/ng_atm.c b/sys/netgraph/atm/ng_atm.c
new file mode 100644
index 0000000..4f40d17
--- /dev/null
+++ b/sys/netgraph/atm/ng_atm.c
@@ -0,0 +1,1371 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * Netgraph module to connect NATM interfaces to netgraph.
+ */
+
+#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/syslog.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sbuf.h>
+#include <sys/ioccom.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/if_var.h>
+#include <net/if_media.h>
+#include <net/if_atm.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+#include <netgraph/atm/ng_atm.h>
+
+/*
+ * Hooks in the NATM code
+ */
+extern void (*ng_atm_attach_p)(struct ifnet *);
+extern void (*ng_atm_detach_p)(struct ifnet *);
+extern int (*ng_atm_output_p)(struct ifnet *, struct mbuf **);
+extern void (*ng_atm_input_p)(struct ifnet *, struct mbuf **,
+ struct atm_pseudohdr *, void *);
+extern void (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
+ struct atm_pseudohdr *, void *);
+extern void (*ng_atm_message_p)(struct ifnet *, uint32_t, uint32_t);
+
+/*
+ * Sysctl stuff.
+ */
+SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0, "atm related stuff");
+
+#ifdef NGATM_DEBUG
+static int allow_shutdown;
+
+SYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
+ &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
+#endif
+
+/*
+ * Hook private data
+ */
+struct ngvcc {
+ uint16_t vpi; /* VPI of this hook */
+ uint16_t vci; /* VCI of this hook, 0 if none */
+ uint32_t flags; /* private flags */
+ hook_p hook; /* the connected hook */
+
+ LIST_ENTRY(ngvcc) link;
+};
+
+/*
+ * Node private data
+ */
+struct priv {
+ struct ifnet *ifp; /* the ATM interface */
+ hook_p input; /* raw input hook */
+ hook_p orphans; /* packets to nowhere */
+ hook_p output; /* catch output packets */
+ hook_p manage; /* has also entry in vccs */
+ uint64_t in_packets;
+ uint64_t in_errors;
+ uint64_t out_packets;
+ uint64_t out_errors;
+
+ LIST_HEAD(, ngvcc) vccs;
+};
+
+/*
+ * Parse carrier state
+ */
+static const struct ng_parse_struct_field ng_atm_carrier_change_info[] =
+ NGM_ATM_CARRIER_CHANGE_INFO;
+static const struct ng_parse_type ng_atm_carrier_change_type = {
+ &ng_parse_struct_type,
+ &ng_atm_carrier_change_info
+};
+
+/*
+ * Parse the configuration structure ng_atm_config
+ */
+static const struct ng_parse_struct_field ng_atm_config_type_info[] =
+ NGM_ATM_CONFIG_INFO;
+
+static const struct ng_parse_type ng_atm_config_type = {
+ &ng_parse_struct_type,
+ &ng_atm_config_type_info
+};
+
+/*
+ * Parse a single vcc structure and a variable array of these ng_atm_vccs
+ */
+static const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
+ NGM_ATM_TPARAM_INFO;
+static const struct ng_parse_type ng_atm_tparam_type = {
+ &ng_parse_struct_type,
+ &ng_atm_tparam_type_info
+};
+static const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
+ NGM_ATM_VCC_INFO;
+static const struct ng_parse_type ng_atm_vcc_type = {
+ &ng_parse_struct_type,
+ &ng_atm_vcc_type_info
+};
+
+
+static int
+ng_atm_vccarray_getlen(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ const struct atmio_vcctable *vp;
+
+ vp = (const struct atmio_vcctable *)
+ (buf - offsetof(struct atmio_vcctable, vccs));
+
+ return (vp->count);
+}
+static const struct ng_parse_array_info ng_atm_vccarray_info =
+ NGM_ATM_VCCARRAY_INFO;
+static const struct ng_parse_type ng_atm_vccarray_type = {
+ &ng_parse_array_type,
+ &ng_atm_vccarray_info
+};
+
+
+static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
+ NGM_ATM_VCCTABLE_INFO;
+
+static const struct ng_parse_type ng_atm_vcctable_type = {
+ &ng_parse_struct_type,
+ &ng_atm_vcctable_type_info
+};
+
+/*
+ * Parse CPCS INIT structure ng_atm_cpcs_init
+ */
+static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
+ NGM_ATM_CPCS_INIT_INFO;
+
+static const struct ng_parse_type ng_atm_cpcs_init_type = {
+ &ng_parse_struct_type,
+ &ng_atm_cpcs_init_type_info
+};
+
+/*
+ * Parse CPCS TERM structure ng_atm_cpcs_term
+ */
+static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
+ NGM_ATM_CPCS_TERM_INFO;
+
+static const struct ng_parse_type ng_atm_cpcs_term_type = {
+ &ng_parse_struct_type,
+ &ng_atm_cpcs_term_type_info
+};
+
+/*
+ * Parse statistic struct
+ */
+static const struct ng_parse_struct_field ng_atm_stats_type_info[] =
+ NGM_ATM_STATS_INFO;
+
+static const struct ng_parse_type ng_atm_stats_type = {
+ &ng_parse_struct_type,
+ &ng_atm_stats_type_info
+};
+
+static const struct ng_cmdlist ng_atm_cmdlist[] = {
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_IFNAME,
+ "getifname",
+ NULL,
+ &ng_parse_string_type
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_CONFIG,
+ "getconfig",
+ NULL,
+ &ng_atm_config_type
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_VCCS,
+ "getvccs",
+ NULL,
+ &ng_atm_vcctable_type
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_CPCS_INIT,
+ "cpcsinit",
+ &ng_atm_cpcs_init_type,
+ NULL
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_CPCS_TERM,
+ "cpcsterm",
+ &ng_atm_cpcs_term_type,
+ NULL
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_CARRIER_CHANGE,
+ "carrier",
+ &ng_atm_carrier_change_type,
+ &ng_atm_carrier_change_type,
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_VCC,
+ "getvcc",
+ &ng_parse_hookbuf_type,
+ &ng_atm_vcc_type
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_VCCID,
+ "getvccid",
+ &ng_atm_vcc_type,
+ &ng_atm_vcc_type
+ },
+ {
+ NGM_ATM_COOKIE,
+ NGM_ATM_GET_STATS,
+ "getstats",
+ NULL,
+ &ng_atm_stats_type
+ },
+ { 0 }
+};
+
+static int ng_atm_mod_event(module_t, int, void *);
+
+static ng_constructor_t ng_atm_constructor;
+static ng_shutdown_t ng_atm_shutdown;
+static ng_rcvmsg_t ng_atm_rcvmsg;
+static ng_newhook_t ng_atm_newhook;
+static ng_connect_t ng_atm_connect;
+static ng_disconnect_t ng_atm_disconnect;
+static ng_rcvdata_t ng_atm_rcvdata;
+static ng_rcvdata_t ng_atm_rcvdrop;
+
+static struct ng_type ng_atm_typestruct = {
+ NG_ABI_VERSION,
+ NG_ATM_NODE_TYPE,
+ ng_atm_mod_event, /* Module event handler (optional) */
+ ng_atm_constructor, /* Node constructor */
+ ng_atm_rcvmsg, /* control messages come here */
+ ng_atm_shutdown, /* reset, and free resources */
+ ng_atm_newhook, /* first notification of new hook */
+ NULL, /* findhook */
+ ng_atm_connect, /* connect */
+ ng_atm_rcvdata, /* rcvdata */
+ ng_atm_disconnect, /* notify on disconnect */
+ ng_atm_cmdlist,
+};
+NETGRAPH_INIT(atm, &ng_atm_typestruct);
+
+static const struct {
+ u_int media;
+ const char *name;
+} atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+
+#define IFP2NG(IFP) ((node_p)((struct ifatm *)(IFP))->ngpriv)
+
+#define IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
+ "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
+ "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
+ "\015LINK0\016LINK1\017LINK2\020MULTICAST"
+
+
+/************************************************************/
+/*
+ * INPUT
+ */
+/*
+ * A packet is received from an interface.
+ * If we have an input hook, prepend the pseudoheader to the data and
+ * deliver it out to that hook. If not, look whether it is destined for
+ * use. If so locate the appropriate hook, deliver the packet without the
+ * header and we are done. If it is not for us, leave it alone.
+ */
+static void
+ng_atm_input(struct ifnet *ifp, struct mbuf **mp,
+ struct atm_pseudohdr *ah, void *rxhand)
+{
+ node_p node = IFP2NG(ifp);
+ struct priv *priv;
+ const struct ngvcc *vcc;
+ int error;
+
+ if (node == NULL)
+ return;
+ priv = NG_NODE_PRIVATE(node);
+ if (priv->input != NULL) {
+ /*
+ * Prepend the atm_pseudoheader.
+ */
+ M_PREPEND(*mp, sizeof(*ah), M_DONTWAIT);
+ if (*mp == NULL)
+ return;
+ memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
+ NG_SEND_DATA_ONLY(error, priv->input, *mp);
+ if (error == 0) {
+ priv->in_packets++;
+ *mp = NULL;
+ } else {
+#ifdef NGATM_DEBUG
+ printf("%s: error=%d\n", __func__, error);
+#endif
+ priv->in_errors++;
+ }
+ return;
+ }
+ if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
+ return;
+
+ vcc = (struct ngvcc *)rxhand;
+
+ NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
+ if (error == 0) {
+ priv->in_packets++;
+ *mp = NULL;
+ } else {
+#ifdef NGATM_DEBUG
+ printf("%s: error=%d\n", __func__, error);
+#endif
+ priv->in_errors++;
+ }
+}
+
+/*
+ * ATM packet is about to be output. The atm_pseudohdr is already prepended.
+ * If the hook is set, reroute the packet to the hook.
+ */
+static int
+ng_atm_output(struct ifnet *ifp, struct mbuf **mp)
+{
+ const node_p node = IFP2NG(ifp);
+ const struct priv *priv;
+ int error = 0;
+
+ if (node == NULL)
+ return (0);
+ priv = NG_NODE_PRIVATE(node);
+ if (priv->output) {
+ NG_SEND_DATA_ONLY(error, priv->output, *mp);
+ *mp = NULL;
+ }
+
+ return (error);
+}
+
+/*
+ * Well, this doesn't make much sense for ATM.
+ */
+static void
+ng_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
+ struct atm_pseudohdr *ah, void *rxhand)
+{
+ node_p node = IFP2NG(ifp);
+ struct priv *priv;
+ int error;
+
+ if (node == NULL) {
+ m_freem(m);
+ return;
+ }
+ priv = NG_NODE_PRIVATE(node);
+ if (priv->orphans == NULL) {
+ m_freem(m);
+ return;
+ }
+ /*
+ * Prepend the atm_pseudoheader.
+ */
+ M_PREPEND(m, sizeof(*ah), M_DONTWAIT);
+ if (m == NULL)
+ return;
+ memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
+ NG_SEND_DATA_ONLY(error, priv->orphans, m);
+ if (error == 0)
+ priv->in_packets++;
+ else {
+ priv->in_errors++;
+#ifdef NGATM_DEBUG
+ printf("%s: error=%d\n", __func__, error);
+#endif
+ }
+}
+
+/************************************************************/
+/*
+ * OUTPUT
+ */
+static int
+ng_atm_rcvdata(hook_p hook, item_p item)
+{
+ node_p node = NG_HOOK_NODE(hook);
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ const struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
+ struct mbuf *m;
+ struct atm_pseudohdr *aph;
+ int error;
+
+ if (vcc->vci == 0) {
+ NG_FREE_ITEM(item);
+ return (ENOTCONN);
+ }
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /*
+ * Prepend pseudo-hdr. Drivers don't care about the flags.
+ */
+ M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
+ if (m == NULL) {
+ NG_FREE_M(m);
+ return (ENOMEM);
+ }
+ aph = mtod(m, struct atm_pseudohdr *);
+ ATM_PH_VPI(aph) = vcc->vpi;
+ ATM_PH_SETVCI(aph, vcc->vci);
+ ATM_PH_FLAGS(aph) = 0;
+
+ if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
+ priv->out_packets++;
+ else
+ priv->out_errors++;
+ return (error);
+}
+
+static int
+ng_atm_rcvdrop(hook_p hook, item_p item)
+{
+ NG_FREE_ITEM(item);
+ return (0);
+}
+
+
+/************************************************************
+ *
+ * Message from driver.
+ */
+#ifdef notyet
+static void
+ng_atm_message_func(node_p node, hook_p hook, void *arg1, int arg2)
+{
+ uint32_t msg = (uintptr_t)arg1;
+ uint32_t arg = (uint32_t)arg2;
+ const struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ngvcc *vcc;
+ u_int vci, vpi, state;
+ struct ng_mesg *mesg;
+ int error;
+
+ switch (msg) {
+
+ case ATM_MSG_FLOW_CONTROL:
+ {
+ struct ngm_queue_state *qstate;
+
+ /* find the connection */
+ vci = arg & 0xffff;
+ vpi = (arg >> 16) & 0xff;
+ state = (arg >> 24) & 1;
+ LIST_FOREACH(vcc, &priv->vccs, link)
+ if (vcc->vci == vci && vcc->vpi == vpi)
+ break;
+ if (vcc == NULL)
+ break;
+
+ /* convert into a flow control message */
+ NG_MKMESSAGE(mesg, NGM_FLOW_COOKIE,
+ state ? NGM_HIGH_WATER_PASSED : NGM_LOW_WATER_PASSED,
+ sizeof(struct ngm_queue_state), M_NOWAIT);
+ if (mesg == NULL)
+ break;
+ qstate = (struct ngm_queue_state *)mesg->data;
+
+ /* XXX have to figure out how to get that info */
+
+ NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, NULL);
+ break;
+ }
+
+ case ATM_MSG_VCC_CHANGED:
+ {
+ struct ngm_atm_vcc_change *chg;
+
+ if (priv->manage == NULL)
+ break;
+ NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
+ sizeof(struct ngm_atm_vcc_change), M_NOWAIT);
+ if (mesg == NULL)
+ break;
+ chg = (struct ngm_atm_vcc_change *)mesg->data;
+ chg->vci = arg & 0xffff;
+ chg->vpi = (arg >> 16) & 0xff;
+ chg->state = (arg >> 24) & 1;
+ chg->node = NG_NODE_ID(node);
+ NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, NULL);
+ break;
+ }
+
+ case ATM_MSG_CARRIER_CHANGE:
+ {
+ struct ngm_atm_carrier_change *chg;
+
+ if (priv->manage == NULL)
+ break;
+ NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_CARRIER_CHANGE,
+ sizeof(struct ngm_atm_carrier_change), M_NOWAIT);
+ if (mesg == NULL)
+ break;
+ chg = (struct ngm_atm_carrier_change *)mesg->data;
+ chg->state = arg & 1;
+ chg->node = NG_NODE_ID(node);
+ NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, NULL);
+ break;
+ }
+ }
+}
+#endif
+
+/*
+ * Use send_fn to get the right lock
+ */
+static void
+ng_atm_message(struct ifnet *ifp, uint32_t msg, uint32_t arg)
+{
+#ifdef notyet
+ const node_p node = IFP2NG(ifp);
+
+ (void)ng_send_fn(node, NULL, ng_atm_message_func,
+ (void *)(uintptr_t)msg, arg);
+#endif
+}
+
+/************************************************************
+ *
+ * CPCS
+ */
+/*
+ * Open a channel for the user
+ */
+static int
+ng_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ const struct ifatm_mib *mib;
+ struct ngvcc *vcc;
+ struct atmio_openvcc data;
+ int err;
+
+ if(priv->ifp->if_ioctl == NULL)
+ return (ENXIO);
+
+ mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
+
+ LIST_FOREACH(vcc, &priv->vccs, link)
+ if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
+ break;
+ if (vcc == NULL)
+ return (ENOTCONN);
+ if (vcc->vci != 0)
+ return (EISCONN);
+
+ /*
+ * Check user arguments and construct ioctl argument
+ */
+ memset(&data, 0, sizeof(data));
+
+ data.rxhand = vcc;
+
+ switch (data.param.aal = arg->aal) {
+
+ case ATMIO_AAL_5:
+ case ATMIO_AAL_0:
+ case ATMIO_AAL_RAW:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if (arg->vpi > 0xff)
+ return (EINVAL);
+ data.param.vpi = arg->vpi;
+
+ if (arg->vci == 0 || arg->vci > 0xffff)
+ return (EINVAL);
+ data.param.vci = arg->vci;
+
+ data.param.tparam.pcr = arg->pcr;
+
+ if (arg->mcr > arg->pcr)
+ return (EINVAL);
+ data.param.tparam.mcr = arg->mcr;
+
+ if (!(arg->flags & ATMIO_FLAG_NOTX)) {
+ if (arg->tmtu > (1 << 16) || arg->tmtu == 0)
+ return (EINVAL);
+ data.param.tmtu = arg->tmtu;
+ }
+ if (!(arg->flags & ATMIO_FLAG_NORX)) {
+ if (arg->rmtu > (1 << 16) || arg->rmtu == 0)
+ return (EINVAL);
+ data.param.rmtu = arg->rmtu;
+ }
+
+ switch (data.param.traffic = arg->traffic) {
+
+ case ATMIO_TRAFFIC_UBR:
+ case ATMIO_TRAFFIC_CBR:
+ break;
+
+ case ATMIO_TRAFFIC_VBR:
+ if (arg->scr > arg->pcr)
+ return (EINVAL);
+ data.param.tparam.scr = arg->scr;
+
+ if (arg->mbs > (1 << 24))
+ return (EINVAL);
+ data.param.tparam.mbs = arg->mbs;
+ break;
+
+ case ATMIO_TRAFFIC_ABR:
+ if (arg->icr > arg->pcr || arg->icr < arg->mcr)
+ return (EINVAL);
+ data.param.tparam.icr = arg->icr;
+
+ if (arg->tbe == 0 || arg->tbe > (1 << 24))
+ return (EINVAL);
+ data.param.tparam.tbe = arg->tbe;
+
+ if (arg->nrm > 0x7)
+ return (EINVAL);
+ data.param.tparam.nrm = arg->nrm;
+
+ if (arg->trm > 0x7)
+ return (EINVAL);
+ data.param.tparam.trm = arg->trm;
+
+ if (arg->adtf > 0x3ff)
+ return (EINVAL);
+ data.param.tparam.adtf = arg->adtf;
+
+ if (arg->rif > 0xf)
+ return (EINVAL);
+ data.param.tparam.rif = arg->rif;
+
+ if (arg->rdf > 0xf)
+ return (EINVAL);
+ data.param.tparam.rdf = arg->rdf;
+
+ if (arg->cdf > 0x7)
+ return (EINVAL);
+ data.param.tparam.cdf = arg->cdf;
+
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
+ return (EINVAL);
+
+ data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
+ data.param.flags |= ATMIO_FLAG_NG;
+
+ err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
+
+ if (err == 0) {
+ vcc->vci = data.param.vci;
+ vcc->vpi = data.param.vpi;
+ vcc->flags = arg->flags;
+ }
+
+ return (err);
+}
+
+/*
+ * Issue the close command to the driver
+ */
+static int
+cpcs_term(const struct priv *priv, u_int vpi, u_int vci)
+{
+ struct atmio_closevcc data;
+
+ if (priv->ifp->if_ioctl == NULL)
+ return ENXIO;
+
+ data.vpi = vpi;
+ data.vci = vci;
+
+ return ((*priv->ifp->if_ioctl)(priv->ifp,
+ SIOCATMCLOSEVCC, (caddr_t)&data));
+}
+
+
+/*
+ * Close a channel by request of the user
+ */
+static int
+ng_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ngvcc *vcc;
+ int error;
+
+ LIST_FOREACH(vcc, &priv->vccs, link)
+ if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
+ break;
+ if (vcc == NULL)
+ return (ENOTCONN);
+ if (vcc->vci == 0)
+ return (ENOTCONN);
+
+ error = cpcs_term(priv, vcc->vpi, vcc->vci);
+
+ vcc->vci = 0;
+ vcc->vpi = 0;
+ vcc->flags = 0;
+
+ return (error);
+}
+
+/************************************************************/
+/*
+ * CONTROL MESSAGES
+ */
+
+/*
+ * Produce a textual description of the current status
+ */
+static int
+text_status(node_p node, char *arg, u_int len)
+{
+ const struct priv *priv = NG_NODE_PRIVATE(node);
+ const struct ifatm_mib *mib;
+ struct sbuf sbuf;
+ u_int i;
+
+ static const struct {
+ const char *name;
+ const char *vendor;
+ } devices[] = {
+ ATM_DEVICE_NAMES
+ };
+
+ mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
+
+ sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
+ sbuf_printf(&sbuf, "interface: %s%d\n", priv->ifp->if_name,
+ priv->ifp->if_unit);
+
+ if (mib->device >= sizeof(devices) / sizeof(devices[0]))
+ sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
+ else
+ sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
+ devices[mib->device].name, devices[mib->device].vendor);
+
+ for (i = 0; atmmedia[i].name; i++)
+ if(mib->media == atmmedia[i].media) {
+ sbuf_printf(&sbuf, "media=%s\n", atmmedia[i].name);
+ break;
+ }
+ if(atmmedia[i].name == NULL)
+ sbuf_printf(&sbuf, "media=unknown\n");
+
+ sbuf_printf(&sbuf, "serial=%u esi=%6D hardware=%u software=%u\n",
+ mib->serial, mib->esi, ":", mib->hw_version, mib->sw_version);
+ sbuf_printf(&sbuf, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
+ "max_vccs=%u\n", mib->pcr, mib->vpi_bits, mib->vci_bits,
+ mib->max_vpcs, mib->max_vccs);
+ sbuf_printf(&sbuf, "ifflags=%b\n", priv->ifp->if_flags, IFFLAGS);
+
+ sbuf_finish(&sbuf);
+
+ return (sbuf_len(&sbuf));
+}
+
+/*
+ * Get control message
+ */
+static int
+ng_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
+{
+ const struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ng_mesg *resp = NULL;
+ struct ng_mesg *msg;
+ struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
+ int error = 0;
+
+ 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,
+ (char *)resp->data, resp->header.arglen) + 1;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ case NGM_ATM_COOKIE:
+ switch (msg->header.cmd) {
+
+ case NGM_ATM_GET_IFNAME:
+ NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ snprintf(resp->data, IFNAMSIZ + 1, "%s%d",
+ priv->ifp->if_name, priv->ifp->if_unit);
+ break;
+
+ case NGM_ATM_GET_CONFIG:
+ {
+ struct ngm_atm_config *config;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ config = (struct ngm_atm_config *)resp->data;
+ config->pcr = mib->pcr;
+ config->vpi_bits = mib->vpi_bits;
+ config->vci_bits = mib->vci_bits;
+ config->max_vpcs = mib->max_vpcs;
+ config->max_vccs = mib->max_vccs;
+ break;
+ }
+
+ case NGM_ATM_GET_VCCS:
+ {
+ struct atmio_vcctable *vccs;
+ size_t len;
+
+ if (priv->ifp->if_ioctl == NULL) {
+ error = ENXIO;
+ break;
+ }
+ error = (*priv->ifp->if_ioctl)(priv->ifp,
+ SIOCATMGETVCCS, (caddr_t)&vccs);
+ if (error)
+ break;
+
+ len = sizeof(*vccs) +
+ vccs->count * sizeof(vccs->vccs[0]);
+ NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ (void)memcpy(resp->data, vccs, len);
+ free(vccs, M_DEVBUF);
+
+ break;
+ }
+
+ case NGM_ATM_GET_VCC:
+ {
+ char hook[NG_HOOKLEN + 1];
+ struct atmio_vcctable *vccs;
+ struct ngvcc *vcc;
+ u_int i;
+
+ if (priv->ifp->if_ioctl == NULL) {
+ error = ENXIO;
+ break;
+ }
+ if (msg->header.arglen != NG_HOOKLEN + 1) {
+ error = EINVAL;
+ break;
+ }
+ strncpy(hook, msg->data, NG_HOOKLEN + 1);
+ hook[NG_HOOKLEN] = '\0';
+ LIST_FOREACH(vcc, &priv->vccs, link)
+ if (strcmp(NG_HOOK_NAME(vcc->hook), hook) == 0)
+ break;
+ if (vcc == NULL) {
+ error = ENOTCONN;
+ break;
+ }
+ error = (*priv->ifp->if_ioctl)(priv->ifp,
+ SIOCATMGETVCCS, (caddr_t)&vccs);
+ if (error)
+ break;
+
+ for (i = 0; i < vccs->count; i++)
+ if (vccs->vccs[i].vpi == vcc->vpi &&
+ vccs->vccs[i].vci == vcc->vci)
+ break;
+ if (i == vccs->count) {
+ error = ENOTCONN;
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
+ M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ *(struct atmio_vcc *)resp->data = vccs->vccs[i];
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ case NGM_ATM_GET_VCCID:
+ {
+ struct atmio_vcc *arg;
+ struct atmio_vcctable *vccs;
+ u_int i;
+
+ if (priv->ifp->if_ioctl == NULL) {
+ error = ENXIO;
+ break;
+ }
+ if (msg->header.arglen != sizeof(*arg)) {
+ error = EINVAL;
+ break;
+ }
+ arg = (struct atmio_vcc *)msg->data;
+
+ error = (*priv->ifp->if_ioctl)(priv->ifp,
+ SIOCATMGETVCCS, (caddr_t)&vccs);
+ if (error)
+ break;
+
+ for (i = 0; i < vccs->count; i++)
+ if (vccs->vccs[i].vpi == arg->vpi &&
+ vccs->vccs[i].vci == arg->vci)
+ break;
+ if (i == vccs->count) {
+ error = ENOTCONN;
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
+ M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ *(struct atmio_vcc *)resp->data = vccs->vccs[i];
+ free(vccs, M_DEVBUF);
+ break;
+ }
+
+ case NGM_ATM_CPCS_INIT:
+ if (msg->header.arglen !=
+ sizeof(struct ngm_atm_cpcs_init)) {
+ error = EINVAL;
+ break;
+ }
+ error = ng_atm_cpcs_init(node,
+ (struct ngm_atm_cpcs_init *)msg->data);
+ break;
+
+ case NGM_ATM_CPCS_TERM:
+ if (msg->header.arglen !=
+ sizeof(struct ngm_atm_cpcs_term)) {
+ error = EINVAL;
+ break;
+ }
+ error = ng_atm_cpcs_term(node,
+ (struct ngm_atm_cpcs_term *)msg->data);
+ break;
+
+ case NGM_ATM_GET_STATS:
+ {
+ struct ngm_atm_stats *p;
+
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ p = (struct ngm_atm_stats *)resp->data;
+ p->in_packets = priv->in_packets;
+ p->out_packets = priv->out_packets;
+ p->in_errors = priv->in_errors;
+ p->out_errors = priv->out_errors;
+
+ 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
+ */
+
+/*
+ * A new hook is create that will be connected to the node.
+ * Check, whether the name is one of the predefined ones.
+ * If not, create a new entry into the vcc list.
+ */
+static int
+ng_atm_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ngvcc *vcc;
+
+ if (strcmp(name, "input") == 0) {
+ priv->input = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
+ return (0);
+ }
+ if (strcmp(name, "output") == 0) {
+ priv->output = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
+ return (0);
+ }
+ if (strcmp(name, "orphans") == 0) {
+ priv->orphans = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
+ return (0);
+ }
+
+ /*
+ * Allocate a new entry
+ */
+ vcc = malloc(sizeof(*vcc), M_NETGRAPH, M_NOWAIT | M_ZERO);
+ if (vcc == NULL)
+ return (ENOMEM);
+
+ vcc->hook = hook;
+ NG_HOOK_SET_PRIVATE(hook, vcc);
+
+ LIST_INSERT_HEAD(&priv->vccs, vcc, link);
+
+ if (strcmp(name, "manage") == 0)
+ priv->manage = hook;
+
+ return (0);
+}
+
+/*
+ * Connect. Set the peer to queuing.
+ */
+static int
+ng_atm_connect(hook_p hook)
+{
+ if (NG_HOOK_PRIVATE(hook) != NULL)
+ NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
+
+ return (0);
+}
+
+/*
+ * Disconnect a HOOK
+ */
+static int
+ng_atm_disconnect(hook_p hook)
+{
+ struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
+
+ if (vcc == NULL) {
+ if (hook == priv->output) {
+ priv->output = NULL;
+ return (0);
+ }
+ if (hook == priv->input) {
+ priv->input = NULL;
+ return (0);
+ }
+ if (hook == priv->orphans) {
+ priv->orphans = NULL;
+ return (0);
+ }
+ log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
+ return (0);
+ }
+
+ /* don't terminate if we are detaching from the interface */
+ if (vcc->vci != 0 && priv->ifp != NULL)
+ (void)cpcs_term(priv, vcc->vpi, vcc->vci);
+
+ NG_HOOK_SET_PRIVATE(hook, NULL);
+
+ LIST_REMOVE(vcc, link);
+ free(vcc, M_NETGRAPH);
+
+ if (hook == priv->manage)
+ priv->manage = NULL;
+
+ return (0);
+}
+
+/************************************************************/
+/*
+ * NODE MANAGEMENT
+ */
+
+/*
+ * ATM interface attached - create a node and name it like the interface.
+ */
+static void
+ng_atm_attach(struct ifnet *ifp)
+{
+ char name[IFNAMSIZ+1];
+ node_p node;
+ struct priv *priv;
+
+ KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __FUNCTION__));
+
+ snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit);
+
+ if (ng_make_node_common(&ng_atm_typestruct, &node) != 0) {
+ log(LOG_ERR, "%s: can't create node for %s\n",
+ __FUNCTION__, name);
+ return;
+ }
+
+ priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
+ if (priv == NULL) {
+ log(LOG_ERR, "%s: can't allocate memory for %s\n",
+ __FUNCTION__, name);
+ NG_NODE_UNREF(node);
+ return;
+ }
+ NG_NODE_SET_PRIVATE(node, priv);
+ priv->ifp = ifp;
+ LIST_INIT(&priv->vccs);
+ IFP2NG(ifp) = node;
+
+ if (ng_name_node(node, name) != 0) {
+ log(LOG_WARNING, "%s: can't name node %s\n",
+ __FUNCTION__, name);
+ }
+}
+
+/*
+ * ATM interface detached - destroy node.
+ */
+static void
+ng_atm_detach(struct ifnet *ifp)
+{
+ const node_p node = IFP2NG(ifp);
+ struct priv *priv;
+
+ if(node == NULL)
+ return;
+
+ NG_NODE_REALLY_DIE(node);
+
+ priv = NG_NODE_PRIVATE(node);
+ IFP2NG(priv->ifp) = NULL;
+ priv->ifp = NULL;
+
+ ng_rmnode_self(node);
+}
+
+/*
+ * Shutdown the node. This is called from the shutdown message processing.
+ */
+static int
+ng_atm_shutdown(node_p node)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if (node->nd_flags & NG_REALLY_DIE) {
+ /*
+ * We are called from unloading the ATM driver. Really,
+ * really need to shutdown this node. The ifp was
+ * already handled in the detach routine.
+ */
+ NG_NODE_SET_PRIVATE(node, NULL);
+ free(priv, M_NETGRAPH);
+
+ NG_NODE_UNREF(node);
+ return (0);
+ }
+
+#ifdef NGATM_DEBUG
+ if (!allow_shutdown)
+ node->nd_flags &= ~NG_INVALID;
+ else {
+ IFP2NG(priv->ifp) = NULL;
+ NG_NODE_SET_PRIVATE(node, NULL);
+ free(priv, M_NETGRAPH);
+ NG_NODE_UNREF(node);
+ }
+#else
+ /*
+ * We are persistant - reinitialize
+ */
+ node->nd_flags &= ~NG_INVALID;
+#endif
+ return (0);
+}
+
+/*
+ * Nodes are constructed only via interface attaches.
+ */
+static int
+ng_atm_constructor(node_p nodep)
+{
+ return (EINVAL);
+}
+
+/************************************************************/
+/*
+ * INITIALISATION
+ */
+/*
+ * Loading and unloading of node type
+ *
+ * The assignments to the globals for the hooks should be ok without
+ * a special hook. The use pattern is generally: check that the pointer
+ * is not NULL, call the function. In the attach case this is no problem.
+ * In the detach case we can detach only when no ATM node exists. That
+ * means that there is no ATM interface anymore. So we are sure that
+ * we are not in the code path in if_atmsubr.c. To prevent someone
+ * from adding an interface after we have started to unload the node, we
+ * take the iflist lock so an if_attach will be blocked until we are done.
+ * XXX: perhaps the function pointers should be 'volatile' for this to work
+ * properly.
+ */
+static int
+ng_atm_mod_event(module_t mod, int event, void *data)
+{
+ struct ifnet *ifp;
+ int error = 0;
+
+ switch (event) {
+
+ case MOD_LOAD:
+ /*
+ * Register function hooks
+ */
+ if (ng_atm_attach_p != NULL) {
+ error = EEXIST;
+ break;
+ }
+ IFNET_RLOCK();
+
+ ng_atm_attach_p = ng_atm_attach;
+ ng_atm_detach_p = ng_atm_detach;
+ ng_atm_output_p = ng_atm_output;
+ ng_atm_input_p = ng_atm_input;
+ ng_atm_input_orphan_p = ng_atm_input_orphans;
+ ng_atm_message_p = ng_atm_message;
+
+ /* Create nodes for existing ATM interfaces */
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ if (ifp->if_type == IFT_ATM)
+ ng_atm_attach(ifp);
+ }
+ IFNET_RUNLOCK();
+ break;
+
+ case MOD_UNLOAD:
+ IFNET_RLOCK();
+
+ ng_atm_attach_p = NULL;
+ ng_atm_detach_p = NULL;
+ ng_atm_output_p = NULL;
+ ng_atm_input_p = NULL;
+ ng_atm_input_orphan_p = NULL;
+ ng_atm_message_p = NULL;
+
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ if (ifp->if_type == IFT_ATM)
+ ng_atm_detach(ifp);
+ }
+ IFNET_RUNLOCK();
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
diff --git a/sys/netgraph/atm/ng_atm.h b/sys/netgraph/atm/ng_atm.h
new file mode 100644
index 0000000..0878272
--- /dev/null
+++ b/sys/netgraph/atm/ng_atm.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * Author: Harti Brandt <harti@freebsd.org>
+ *
+ * Netgraph module to connect NATM interfaces to netgraph.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NETGRAPH_ATM_NG_ATM_H
+#define _NETGRAPH_ATM_NG_ATM_H
+
+#define NG_ATM_NODE_TYPE "atm"
+#define NGM_ATM_COOKIE 960802260
+
+/* Netgraph control messages */
+enum {
+ NGM_ATM_GET_IFNAME = 1, /* get the interface name */
+ NGM_ATM_GET_CONFIG, /* get configuration */
+ NGM_ATM_GET_VCCS, /* get a list of all active vccs */
+ NGM_ATM_CPCS_INIT, /* start the channel */
+ NGM_ATM_CPCS_TERM, /* stop the channel */
+ NGM_ATM_GET_VCC, /* get VCC config */
+ NGM_ATM_GET_VCCID, /* get VCC by VCI/VPI */
+ NGM_ATM_GET_STATS, /* get global statistics */
+
+ /* messages from the node */
+ NGM_ATM_CARRIER_CHANGE = 1000, /* carrier changed */
+ NGM_ATM_VCC_CHANGE, /* permanent VCC changed */
+};
+
+/*
+ * Hardware interface configuration
+ */
+struct ngm_atm_config {
+ uint32_t pcr; /* peak cell rate */
+ uint32_t vpi_bits; /* number of active VPI bits */
+ uint32_t vci_bits; /* number of active VCI bits */
+ uint32_t max_vpcs; /* maximum number of VPCs */
+ uint32_t max_vccs; /* maximum number of VCCs */
+};
+#define NGM_ATM_CONFIG_INFO \
+ { \
+ { "pcr", &ng_parse_uint32_type }, \
+ { "vpi_bits", &ng_parse_uint32_type }, \
+ { "vci_bits", &ng_parse_uint32_type }, \
+ { "max_vpcs", &ng_parse_uint32_type }, \
+ { "max_vccs", &ng_parse_uint32_type }, \
+ { NULL } \
+ }
+
+/*
+ * Information about an open VCC
+ * See net/if_atm.h. Keep in sync.
+ */
+#define NGM_ATM_TPARAM_INFO \
+ { \
+ { "pcr", &ng_parse_uint32_type }, \
+ { "scr", &ng_parse_uint32_type }, \
+ { "mbs", &ng_parse_uint32_type }, \
+ { "mcr", &ng_parse_uint32_type }, \
+ { "icr", &ng_parse_uint32_type }, \
+ { "tbe", &ng_parse_uint32_type }, \
+ { "nrm", &ng_parse_uint8_type }, \
+ { "trm", &ng_parse_uint8_type }, \
+ { "adtf", &ng_parse_uint16_type }, \
+ { "rif", &ng_parse_uint8_type }, \
+ { "rdf", &ng_parse_uint8_type }, \
+ { "cdf", &ng_parse_uint8_type }, \
+ { NULL } \
+ }
+
+#define NGM_ATM_VCC_INFO \
+ { \
+ { "flags", &ng_parse_hint16_type }, \
+ { "vpi", &ng_parse_uint16_type }, \
+ { "vci", &ng_parse_uint16_type }, \
+ { "rmtu", &ng_parse_uint16_type }, \
+ { "tmtu", &ng_parse_uint16_type }, \
+ { "aal", &ng_parse_uint8_type }, \
+ { "traffic", &ng_parse_uint8_type }, \
+ { "tparam", &ng_atm_tparam_type }, \
+ { NULL } \
+ }
+
+#define NGM_ATM_VCCARRAY_INFO \
+ { \
+ &ng_atm_vcc_type, \
+ ng_atm_vccarray_getlen, \
+ NULL \
+ }
+
+#define NGM_ATM_VCCTABLE_INFO \
+ { \
+ { "count", &ng_parse_uint32_type }, \
+ { "vccs", &ng_atm_vccarray_type }, \
+ { NULL } \
+ }
+
+/*
+ * Structure to open a VCC.
+ */
+struct ngm_atm_cpcs_init {
+ char name[NG_HOOKLEN + 1];
+ uint32_t flags; /* flags. (if_atm.h) */
+ uint16_t vci; /* VCI to open */
+ uint16_t vpi; /* VPI to open */
+ uint16_t rmtu; /* Receive maximum CPCS size */
+ uint16_t tmtu; /* Transmit maximum CPCS size */
+ uint8_t aal; /* AAL type (if_atm.h) */
+ uint8_t traffic; /* traffic type (if_atm.h) */
+ uint32_t pcr; /* Peak cell rate */
+ uint32_t scr; /* VBR: Sustainable cell rate */
+ uint32_t mbs; /* VBR: Maximum burst rate */
+ uint32_t mcr; /* UBR+: Minimum cell rate */
+ uint32_t icr; /* ABR: Initial cell rate */
+ uint32_t tbe; /* ABR: Transmit buffer exposure */
+ uint8_t nrm; /* ABR: Nrm */
+ uint8_t trm; /* ABR: Trm */
+ uint16_t adtf; /* ABR: ADTF */
+ uint8_t rif; /* ABR: RIF */
+ uint8_t rdf; /* ABR: RDF */
+ uint8_t cdf; /* ABR: CDF */
+};
+
+#define NGM_ATM_CPCS_INIT_INFO \
+ { \
+ { "name", &ng_parse_hookbuf_type }, \
+ { "flags", &ng_parse_hint32_type }, \
+ { "vci", &ng_parse_uint16_type }, \
+ { "vpi", &ng_parse_uint16_type }, \
+ { "rmtu", &ng_parse_uint16_type }, \
+ { "tmtu", &ng_parse_uint16_type }, \
+ { "aal", &ng_parse_uint8_type }, \
+ { "traffic", &ng_parse_uint8_type }, \
+ { "pcr", &ng_parse_uint32_type }, \
+ { "scr", &ng_parse_uint32_type }, \
+ { "mbs", &ng_parse_uint32_type }, \
+ { "mcr", &ng_parse_uint32_type }, \
+ { "icr", &ng_parse_uint32_type }, \
+ { "tbe", &ng_parse_uint32_type }, \
+ { "nrm", &ng_parse_uint8_type }, \
+ { "trm", &ng_parse_uint8_type }, \
+ { "adtf", &ng_parse_uint16_type }, \
+ { "rif", &ng_parse_uint8_type }, \
+ { "rdf", &ng_parse_uint8_type }, \
+ { "cdf", &ng_parse_uint8_type }, \
+ { NULL } \
+ }
+
+/*
+ * Structure to close a VCI without disconnecting the hook
+ */
+struct ngm_atm_cpcs_term {
+ char name[NG_HOOKLEN + 1];
+};
+#define NGM_ATM_CPCS_TERM_INFO \
+ { \
+ { "name", &ng_parse_hookbuf_type }, \
+ { NULL } \
+ }
+
+struct ngm_atm_stats {
+ uint64_t in_packets;
+ uint64_t in_errors;
+ uint64_t out_packets;
+ uint64_t out_errors;
+};
+#define NGM_ATM_STATS_INFO \
+ { \
+ { "in_packets", &ng_parse_uint64_type }, \
+ { "in_errors", &ng_parse_uint64_type }, \
+ { "out_packets", &ng_parse_uint64_type }, \
+ { "out_errors", &ng_parse_uint64_type }, \
+ { NULL } \
+ }
+
+struct ngm_atm_carrier_change {
+ uint32_t node;
+ uint32_t state;
+};
+#define NGM_ATM_CARRIER_CHANGE_INFO \
+ { \
+ { "node", &ng_parse_hint32_type }, \
+ { "state", &ng_parse_uint32_type }, \
+ { NULL } \
+ }
+
+struct ngm_atm_vcc_change {
+ uint32_t node;
+ uint16_t vci;
+ uint8_t vpi;
+ uint8_t state;
+};
+#define NGM_ATM_VCC_CHANGE_INFO \
+ { \
+ { "node", &ng_parse_hint32_type }, \
+ { "vci", &ng_parse_uint16_type }, \
+ { "vpi", &ng_parse_uint8_type }, \
+ { "state", &ng_parse_uint8_type }, \
+ { NULL } \
+ }
+
+#endif /* _NETGRAPH_ATM_NG_ATM_H */
OpenPOWER on IntegriCloud