summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/atm
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-10-24 07:39:11 +0000
committerharti <harti@FreeBSD.org>2003-10-24 07:39:11 +0000
commite43801eab1f3da0b4a906ce7f56652cc862468cf (patch)
treebcc0ce80b2a45814cf30f9294c8abbc8123fe50f /sys/netgraph/atm
parent44a38765ae4765b221807e39761da56596a171f8 (diff)
downloadFreeBSD-src-e43801eab1f3da0b4a906ce7f56652cc862468cf.zip
FreeBSD-src-e43801eab1f3da0b4a906ce7f56652cc862468cf.tar.gz
Netgraph part of the NgATM signalling AA layer. These nodes can
also be used as a general-purpose transport protocol above any packet layer (IP, UDP).
Diffstat (limited to 'sys/netgraph/atm')
-rw-r--r--sys/netgraph/atm/ng_sscfu.h68
-rw-r--r--sys/netgraph/atm/ng_sscop.h110
-rw-r--r--sys/netgraph/atm/ngatmbase.c500
-rw-r--r--sys/netgraph/atm/ngatmbase.h64
-rw-r--r--sys/netgraph/atm/sscfu/ng_sscfu.c611
-rw-r--r--sys/netgraph/atm/sscfu/ng_sscfu_cust.h131
-rw-r--r--sys/netgraph/atm/sscop/ng_sscop.c885
-rw-r--r--sys/netgraph/atm/sscop/ng_sscop_cust.h346
8 files changed, 2715 insertions, 0 deletions
diff --git a/sys/netgraph/atm/ng_sscfu.h b/sys/netgraph/atm/ng_sscfu.h
new file mode 100644
index 0000000..600d892
--- /dev/null
+++ b/sys/netgraph/atm/ng_sscfu.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti 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.
+ *
+ * $FreeBSD$
+ *
+ * Netgraph module for ITU-T Q.2120 UNI SSCF.
+ */
+#ifndef _NETGRAPH_ATM_NG_SSCFU_H_
+#define _NETGRAPH_ATM_NG_SSCFU_H_
+
+#define NG_SSCFU_NODE_TYPE "sscfu"
+#define NGM_SSCFU_COOKIE 980517963
+
+/* Netgraph control messages */
+enum {
+ NGM_SSCFU_GETDEFPARAM = 1, /* get default SSCOP parameters */
+ NGM_SSCFU_ENABLE, /* enable processing */
+ NGM_SSCFU_DISABLE, /* disable processing */
+ NGM_SSCFU_GETDEBUG, /* get debug flags */
+ NGM_SSCFU_SETDEBUG, /* set debug flags */
+ NGM_SSCFU_GETSTATE, /* get current state */
+};
+
+/* getdefparam return */
+struct ng_sscfu_getdefparam {
+ struct sscop_param param;
+ uint32_t mask;
+};
+#define NG_SSCFU_GETDEFPARAM_INFO \
+ { \
+ { "param", &ng_sscop_param_type }, \
+ { "mask", &ng_parse_uint32_type }, \
+ { NULL } \
+ }
+
+/*
+ * Upper interface
+ */
+struct sscfu_arg {
+ uint32_t sig;
+ u_char data[];
+};
+#endif
diff --git a/sys/netgraph/atm/ng_sscop.h b/sys/netgraph/atm/ng_sscop.h
new file mode 100644
index 0000000..26de7e2
--- /dev/null
+++ b/sys/netgraph/atm/ng_sscop.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti 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.
+ *
+ * $FreeBSD$
+ *
+ * Netgraph module for Q.2110 SSCOP
+ */
+#ifndef _NETGRAPH_ATM_NG_SSCOP_H
+#define _NETGRAPH_ATM_NG_SSCOP_H
+
+#define NG_SSCOP_NODE_TYPE "sscop"
+#define NGM_SSCOP_COOKIE 980175044
+
+/* Netgraph control messages */
+enum {
+ NGM_SSCOP_GETPARAM = 1, /* get parameters */
+ NGM_SSCOP_SETPARAM, /* set parameters */
+ NGM_SSCOP_ENABLE, /* enable processing */
+ NGM_SSCOP_DISABLE, /* disable and reset */
+ NGM_SSCOP_GETDEBUG, /* get debugging flags */
+ NGM_SSCOP_SETDEBUG, /* set debugging flags */
+ NGM_SSCOP_GETSTATE, /* get current SSCOP state */
+};
+
+/* This must be in-sync with the definition in sscopdef.h */
+#define NG_SSCOP_PARAM_INFO \
+ { \
+ { "timer_cc", &ng_parse_uint32_type }, \
+ { "timer_poll", &ng_parse_uint32_type }, \
+ { "timer_keep_alive", &ng_parse_uint32_type }, \
+ { "timer_no_response",&ng_parse_uint32_type }, \
+ { "timer_idle", &ng_parse_uint32_type }, \
+ { "maxk", &ng_parse_uint32_type }, \
+ { "maxj", &ng_parse_uint32_type }, \
+ { "maxcc", &ng_parse_uint32_type }, \
+ { "maxpd", &ng_parse_uint32_type }, \
+ { "maxstat", &ng_parse_uint32_type }, \
+ { "mr", &ng_parse_uint32_type }, \
+ { "flags", &ng_parse_uint32_type }, \
+ { NULL } \
+ }
+
+
+struct ng_sscop_setparam {
+ uint32_t mask;
+ struct sscop_param param;
+};
+#define NG_SSCOP_SETPARAM_INFO \
+ { \
+ { "mask", &ng_parse_uint32_type }, \
+ { "param", &ng_sscop_param_type }, \
+ { NULL } \
+ }
+
+struct ng_sscop_setparam_resp {
+ uint32_t mask;
+ int32_t error;
+};
+#define NG_SSCOP_SETPARAM_RESP_INFO \
+ { \
+ { "mask", &ng_parse_uint32_type }, \
+ { "error", &ng_parse_int32_type }, \
+ { NULL } \
+ }
+
+/*
+ * Upper interface
+ */
+struct sscop_arg {
+ uint32_t sig;
+ uint32_t arg; /* opt. sequence number or clear-buff */
+ u_char data[];
+};
+
+struct sscop_marg {
+ uint32_t sig;
+ u_char data[];
+};
+struct sscop_merr {
+ uint32_t sig;
+ uint32_t err; /* error code */
+ uint32_t cnt; /* error count */
+};
+
+#endif
diff --git a/sys/netgraph/atm/ngatmbase.c b/sys/netgraph/atm/ngatmbase.c
new file mode 100644
index 0000000..8a802c6
--- /dev/null
+++ b/sys/netgraph/atm/ngatmbase.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * 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.
+ *
+ * In-kernel UNI stack message functions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <machine/stdarg.h>
+#include <netnatm/unimsg.h>
+#include <netgraph/atm/ngatmbase.h>
+
+#define NGATMBASE_VERSION 1
+
+static int ngatm_handler(module_t, int, void *);
+
+static moduledata_t ngatm_data = {
+ "ngatmbase",
+ ngatm_handler,
+ 0
+};
+
+MODULE_VERSION(ngatmbase, NGATMBASE_VERSION);
+DECLARE_MODULE(ngatmbase, ngatm_data, SI_SUB_EXEC, SI_ORDER_ANY);
+
+/*********************************************************************/
+/*
+ * UNI Stack message handling functions
+ */
+MALLOC_DEFINE(M_UNIMSG, "unimsg", "uni message buffers");
+MALLOC_DEFINE(M_UNIMSGHDR, "unimsghdr", "uni message headers");
+
+#define EXTRA 128
+
+/* mutex to protect the free list (and the used list if debugging) */
+static struct mtx ngatm_unilist_mtx;
+
+/*
+ * Initialize UNI message subsystem
+ */
+static void
+uni_msg_init(void)
+{
+ mtx_init(&ngatm_unilist_mtx, "netgraph UNI msg header lists", NULL, 0);
+}
+
+/*
+ * Ensure, that the message can be extended by at least s bytes.
+ * Re-allocate the message (not the header). If that failes,
+ * free the entire message and return ENOMEM. Free space at the start of
+ * the message is retained.
+ */
+int
+uni_msg_extend(struct uni_msg *m, size_t s)
+{
+ u_char *b;
+ size_t len, lead;
+
+ lead = uni_msg_leading(m);
+ len = uni_msg_len(m);
+ s += lead + len + EXTRA;
+ if ((b = malloc(s, M_UNIMSG, M_NOWAIT)) == NULL) {
+ uni_msg_destroy(m);
+ return (ENOMEM);
+ }
+
+ bcopy(m->b_rptr, b + lead, len);
+ free(m->b_buf, M_UNIMSG);
+
+ m->b_buf = b;
+ m->b_rptr = m->b_buf + lead;
+ m->b_wptr = m->b_rptr + len;
+ m->b_lim = m->b_buf + s;
+
+ return (0);
+}
+
+/*
+ * Append a buffer to the message, making space if needed.
+ * If reallocation files, ENOMEM is returned and the message freed.
+ */
+int
+uni_msg_append(struct uni_msg *m, void *buf, size_t size)
+{
+ int error;
+
+ if ((error = uni_msg_ensure(m, size)))
+ return (error);
+ bcopy(buf, m->b_wptr, size);
+ m->b_wptr += size;
+
+ return (0);
+}
+
+/*
+ * Pack/unpack data from/into mbufs. Assume, that the (optional) header
+ * fits into the first mbuf, ie. hdrlen < MHLEN. Note, that the message
+ * can be NULL, but hdrlen should not be 0 in this case.
+ */
+struct mbuf *
+uni_msg_pack_mbuf(struct uni_msg *msg, void *hdr, size_t hdrlen)
+{
+ struct mbuf *m, *m0, *last;
+ size_t n;
+
+ MGETHDR(m0, M_NOWAIT, MT_DATA);
+ if (m0 == NULL)
+ return (NULL);
+
+ KASSERT(hdrlen <= MHLEN, ("uni_msg_pack_mbuf: hdrlen > MHLEN"));
+
+ if (hdrlen != 0) {
+ bcopy(hdr, m0->m_data, hdrlen);
+ m0->m_len = hdrlen;
+ m0->m_pkthdr.len = hdrlen;
+
+ } else {
+ if ((n = uni_msg_len(msg)) > MHLEN) {
+ MCLGET(m0, M_NOWAIT);
+ if (!(m0->m_flags & M_EXT))
+ goto drop;
+ if (n > MCLBYTES)
+ n = MCLBYTES;
+ }
+
+ bcopy(msg->b_rptr, m0->m_data, n);
+ msg->b_rptr += n;
+ m0->m_len = n;
+ m0->m_pkthdr.len = n;
+ }
+
+ last = m0;
+ while (msg != NULL && (n = uni_msg_len(msg)) != 0) {
+ MGET(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ goto drop;
+ last->m_next = m;
+ last = m;
+
+ if (n > MLEN) {
+ MCLGET(m, M_NOWAIT);
+ if (!(m->m_flags & M_EXT))
+ goto drop;
+ if (n > MCLBYTES)
+ n = MCLBYTES;
+ }
+
+ bcopy(msg->b_rptr, m->m_data, n);
+ msg->b_rptr += n;
+ m->m_len = n;
+ m0->m_pkthdr.len += n;
+ }
+
+ return (m0);
+
+ drop:
+ m_freem(m0);
+ return (NULL);
+}
+
+#ifdef NGATM_DEBUG
+
+/*
+ * Prepend a debugging header to each message
+ */
+struct ngatm_msg {
+ LIST_ENTRY(ngatm_msg) link;
+ const char *file;
+ int line;
+ struct uni_msg msg;
+};
+
+/*
+ * These are the lists of free and used message headers.
+ */
+static LIST_HEAD(, ngatm_msg) ngatm_freeuni =
+ LIST_HEAD_INITIALIZER(ngatm_freeuni);
+static LIST_HEAD(, ngatm_msg) ngatm_useduni =
+ LIST_HEAD_INITIALIZER(ngatm_useduni);
+
+/*
+ * Clean-up UNI message subsystem
+ */
+static void
+uni_msg_fini(void)
+{
+ struct ngatm_msg *h;
+
+ /* free all free message headers */
+ while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) {
+ LIST_REMOVE(h, link);
+ free(h, M_UNIMSGHDR);
+ }
+
+ /* forget about still used messages */
+ LIST_FOREACH(h, &ngatm_useduni, link)
+ printf("unimsg header in use: %p (%s, %d)\n",
+ &h->msg, h->file, h->line);
+
+ mtx_destroy(&ngatm_unilist_mtx);
+}
+
+/*
+ * Allocate a message, that can hold at least s bytes.
+ */
+struct uni_msg *
+_uni_msg_alloc(size_t s, const char *file, int line)
+{
+ struct ngatm_msg *m;
+
+ mtx_lock(&ngatm_unilist_mtx);
+ if ((m = LIST_FIRST(&ngatm_freeuni)) != NULL)
+ LIST_REMOVE(m, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+
+ if (m == NULL &&
+ (m = malloc(sizeof(*m), M_UNIMSGHDR, M_NOWAIT)) == NULL)
+ return (NULL);
+
+ s += EXTRA;
+ if((m->msg.b_buf = malloc(s, M_UNIMSG, M_NOWAIT | M_ZERO)) == NULL) {
+ mtx_lock(&ngatm_unilist_mtx);
+ LIST_INSERT_HEAD(&ngatm_freeuni, m, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+ return (NULL);
+ }
+ m->msg.b_rptr = m->msg.b_wptr = m->msg.b_buf;
+ m->msg.b_lim = m->msg.b_buf + s;
+ m->file = file;
+ m->line = line;
+
+ mtx_lock(&ngatm_unilist_mtx);
+ LIST_INSERT_HEAD(&ngatm_useduni, m, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+ return (&m->msg);
+}
+
+/*
+ * Destroy a UNI message.
+ * The header is inserted into the free header list.
+ */
+void
+_uni_msg_destroy(struct uni_msg *m, const char *file, int line)
+{
+ struct ngatm_msg *h, *d;
+
+ d = (struct ngatm_msg *)((char *)m - offsetof(struct ngatm_msg, msg));
+
+ mtx_lock(&ngatm_unilist_mtx);
+ LIST_FOREACH(h, &ngatm_useduni, link)
+ if (h == d)
+ break;
+
+ if (h == NULL) {
+ /*
+ * Not on used list. Ups.
+ */
+ LIST_FOREACH(h, &ngatm_freeuni, link)
+ if (h == d)
+ break;
+
+ if (h == NULL)
+ printf("uni_msg %p was never allocated; found "
+ "in %s:%u\n", m, file, line);
+ else
+ printf("uni_msg %p was already destroyed in %s,%d; "
+ "found in %s:%u\n", m, h->file, h->line,
+ file, line);
+ } else {
+ free(m->b_buf, M_UNIMSG);
+
+ LIST_REMOVE(d, link);
+ LIST_INSERT_HEAD(&ngatm_freeuni, d, link);
+
+ d->file = file;
+ d->line = line;
+ }
+
+ mtx_unlock(&ngatm_unilist_mtx);
+}
+
+#else /* !NGATM_DEBUG */
+
+/*
+ * This assumes, that sizeof(struct uni_msg) >= sizeof(struct ngatm_msg)
+ * and the alignment requirements of are the same.
+ */
+struct ngatm_msg {
+ LIST_ENTRY(ngatm_msg) link;
+};
+
+/* Lists of free message headers. */
+static LIST_HEAD(, ngatm_msg) ngatm_freeuni =
+ LIST_HEAD_INITIALIZER(ngatm_freeuni);
+
+/*
+ * Clean-up UNI message subsystem
+ */
+static void
+uni_msg_fini(void)
+{
+ struct ngatm_msg *h;
+
+ /* free all free message headers */
+ while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) {
+ LIST_REMOVE(h, link);
+ free(h, M_UNIMSGHDR);
+ }
+
+ mtx_destroy(&ngatm_unilist_mtx);
+}
+
+/*
+ * Allocate a message, that can hold at least s bytes.
+ */
+struct uni_msg *
+uni_msg_alloc(size_t s)
+{
+ struct ngatm_msg *a;
+ struct uni_msg *m;
+
+ mtx_lock(&ngatm_unilist_mtx);
+ if ((a = LIST_FIRST(&ngatm_freeuni)) != NULL)
+ LIST_REMOVE(a, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+
+ if (a == NULL) {
+ if ((m = malloc(sizeof(*m), M_UNIMSGHDR, M_NOWAIT)) == NULL)
+ return (NULL);
+ a = (struct ngatm_msg *)m;
+ } else
+ m = (struct uni_msg *)a;
+
+ s += EXTRA;
+ if((m->b_buf = malloc(s, M_UNIMSG, M_NOWAIT | M_ZERO)) == NULL) {
+ mtx_lock(&ngatm_unilist_mtx);
+ LIST_INSERT_HEAD(&ngatm_freeuni, a, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+ return (NULL);
+ }
+ m->b_rptr = m->b_wptr = m->b_buf;
+ m->b_lim = m->b_buf + s;
+
+ return (m);
+}
+
+/*
+ * Destroy a UNI message.
+ * The header is inserted into the free header list.
+ */
+void
+uni_msg_destroy(struct uni_msg *m)
+{
+ struct ngatm_msg *a;
+
+ a = (struct ngatm_msg *)m;
+
+ free(m->b_buf, M_UNIMSG);
+
+ mtx_lock(&ngatm_unilist_mtx);
+ LIST_INSERT_HEAD(&ngatm_freeuni, a, link);
+ mtx_unlock(&ngatm_unilist_mtx);
+}
+
+#endif
+
+/*
+ * Build a message from a number of buffers. Arguments are pairs
+ * of (void *, size_t) ending with a NULL pointer.
+ */
+#ifdef NGATM_DEBUG
+struct uni_msg *
+_uni_msg_build(const char *file, int line, void *ptr, ...)
+#else
+struct uni_msg *
+uni_msg_build(void *ptr, ...)
+#endif
+{
+ va_list ap;
+ struct uni_msg *m;
+ size_t len, n;
+ void *p1;
+
+ len = 0;
+ va_start(ap, ptr);
+ p1 = ptr;
+ while (p1 != NULL) {
+ n = va_arg(ap, size_t);
+ len += n;
+ p1 = va_arg(ap, void *);
+ }
+ va_end(ap);
+
+#ifdef NGATM_DEBUG
+ if ((m = _uni_msg_alloc(len, file, line)) == NULL)
+#else
+ if ((m = uni_msg_alloc(len)) == NULL)
+#endif
+ return (NULL);
+
+ va_start(ap, ptr);
+ p1 = ptr;
+ while (p1 != NULL) {
+ n = va_arg(ap, size_t);
+ bcopy(p1, m->b_wptr, n);
+ m->b_wptr += n;
+ p1 = va_arg(ap, void *);
+ }
+ va_end(ap);
+
+ return (m);
+}
+
+/*
+ * Unpack an mbuf chain into a uni_msg buffer.
+ */
+#ifdef NGATM_DEBUG
+int
+_uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg, const char *file,
+ int line)
+#else
+int
+uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg)
+#endif
+{
+ if (!(m->m_flags & M_PKTHDR)) {
+ printf("%s: bogus packet %p\n", __func__, m);
+ return (EINVAL);
+ }
+#ifdef NGATM_DEBUG
+ if ((*pmsg = _uni_msg_alloc(m->m_pkthdr.len, file, line)) == NULL)
+#else
+ if ((*pmsg = uni_msg_alloc(m->m_pkthdr.len)) == NULL)
+#endif
+ return (ENOMEM);
+
+ m_copydata(m, 0, m->m_pkthdr.len, (*pmsg)->b_wptr);
+ (*pmsg)->b_wptr += m->m_pkthdr.len;
+
+ return (0);
+}
+
+/*********************************************************************/
+
+static int
+ngatm_handler(module_t mod, int what, void *arg)
+{
+ int error = 0;
+
+ switch (what) {
+
+ case MOD_LOAD:
+ uni_msg_init();
+ break;
+
+ case MOD_UNLOAD:
+ uni_msg_fini();
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
diff --git a/sys/netgraph/atm/ngatmbase.h b/sys/netgraph/atm/ngatmbase.h
new file mode 100644
index 0000000..70dd275
--- /dev/null
+++ b/sys/netgraph/atm/ngatmbase.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * 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 FRAUNHOFER FOKUS
+ * 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
+ * FRAUNHOFER FOKUS 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$
+ *
+ * In-kernel UNI stack message functions.
+ */
+#ifndef _NETGRAPH_ATM_NGATMBASE_H
+#define _NETGRAPH_ATM_NGATMBASE_H
+
+/* forward declarations */
+struct mbuf;
+struct uni_msg;
+
+struct mbuf *uni_msg_pack_mbuf(struct uni_msg *, void *, size_t);
+
+#ifdef NGATM_DEBUG
+
+struct uni_msg *_uni_msg_alloc(size_t, const char *, int);
+struct uni_msg *_uni_msg_build(const char *, int, void *, ...);
+void _uni_msg_destroy(struct uni_msg *, const char *, int);
+int _uni_msg_unpack_mbuf(struct mbuf *, struct uni_msg **, const char *, int);
+
+#define uni_msg_alloc(S) _uni_msg_alloc((S), __FILE__, __LINE__)
+#define uni_msg_build(P...) _uni_msg_build(__FILE__, __LINE__, P)
+#define uni_msg_destroy(M) _uni_msg_destroy((M), __FILE__, __LINE__)
+#define uni_msg_unpack_mbuf(M, PP) \
+ _uni_msg_unpack_mbuf((M), (PP), __FILE__, __LINE__)
+
+#else /* !NGATM_DEBUG */
+
+struct uni_msg *uni_msg_alloc(size_t);
+struct uni_msg *uni_msg_build(void *, ...);
+void uni_msg_destroy(struct uni_msg *);
+int uni_msg_unpack_mbuf(struct mbuf *, struct uni_msg **);
+
+#endif
+#endif
diff --git a/sys/netgraph/atm/sscfu/ng_sscfu.c b/sys/netgraph/atm/sscfu/ng_sscfu.c
new file mode 100644
index 0000000..d15c503
--- /dev/null
+++ b/sys/netgraph/atm/sscfu/ng_sscfu.c
@@ -0,0 +1,611 @@
+/*
+ * 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 for ITU-T Q.2120 UNI SSCF.
+ */
+
+#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 <machine/stdarg.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+#include <netnatm/saal/sscopdef.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netgraph/atm/ng_sscop.h>
+#include <netgraph/atm/ng_sscfu.h>
+#include <netgraph/atm/sscfu/ng_sscfu_cust.h>
+#include <netnatm/saal/sscfu.h>
+
+MALLOC_DEFINE(M_NG_SSCFU, "netgraph_sscfu", "netgraph uni sscf node");
+
+MODULE_DEPEND(ng_sscfu, ngatmbase, 1, 1, 1);
+
+/*
+ * Private data
+ */
+struct priv {
+ hook_p upper; /* SAAL interface */
+ hook_p lower; /* SSCOP interface */
+ struct sscfu *sscf; /* the instance */
+ int enabled;
+};
+
+/*
+ * PARSING
+ */
+/*
+ * Parse PARAM type
+ */
+static const struct ng_parse_struct_field ng_sscop_param_type_info[] =
+ NG_SSCOP_PARAM_INFO;
+
+static const struct ng_parse_type ng_sscop_param_type = {
+ &ng_parse_struct_type,
+ ng_sscop_param_type_info
+};
+
+static const struct ng_parse_struct_field ng_sscfu_getdefparam_type_info[] =
+ NG_SSCFU_GETDEFPARAM_INFO;
+
+static const struct ng_parse_type ng_sscfu_getdefparam_type = {
+ &ng_parse_struct_type,
+ ng_sscfu_getdefparam_type_info
+};
+
+
+static const struct ng_cmdlist ng_sscfu_cmdlist[] = {
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_GETDEFPARAM,
+ "getdefparam",
+ NULL,
+ &ng_sscfu_getdefparam_type
+ },
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_ENABLE,
+ "enable",
+ NULL,
+ NULL
+ },
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_DISABLE,
+ "disable",
+ NULL,
+ NULL
+ },
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_GETDEBUG,
+ "getdebug",
+ NULL,
+ &ng_parse_hint32_type
+ },
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_SETDEBUG,
+ "setdebug",
+ &ng_parse_hint32_type,
+ NULL
+ },
+ {
+ NGM_SSCFU_COOKIE,
+ NGM_SSCFU_GETSTATE,
+ "getstate",
+ NULL,
+ &ng_parse_uint32_type
+ },
+ { 0 }
+};
+
+static ng_constructor_t ng_sscfu_constructor;
+static ng_shutdown_t ng_sscfu_shutdown;
+static ng_rcvmsg_t ng_sscfu_rcvmsg;
+static ng_newhook_t ng_sscfu_newhook;
+static ng_disconnect_t ng_sscfu_disconnect;
+static ng_rcvdata_t ng_sscfu_rcvupper;
+static ng_rcvdata_t ng_sscfu_rcvlower;
+
+static int ng_sscfu_mod_event(module_t, int, void *);
+
+static struct ng_type ng_sscfu_typestruct = {
+ NG_ABI_VERSION,
+ NG_SSCFU_NODE_TYPE,
+ ng_sscfu_mod_event, /* Module event handler (optional) */
+ ng_sscfu_constructor, /* Node constructor */
+ ng_sscfu_rcvmsg, /* control messages come here */
+ ng_sscfu_shutdown, /* reset, and free resources */
+ ng_sscfu_newhook, /* first notification of new hook */
+ NULL, /* findhook */
+ NULL, /* connect */
+ ng_sscfu_rcvupper, /* rcvdata */
+ ng_sscfu_disconnect, /* notify on disconnect */
+ ng_sscfu_cmdlist,
+};
+NETGRAPH_INIT(sscfu, &ng_sscfu_typestruct);
+
+static void sscfu_send_upper(struct sscfu *, void *, enum saal_sig,
+ struct mbuf *);
+static void sscfu_send_lower(struct sscfu *, void *, enum sscop_aasig,
+ struct mbuf *, u_int);
+static void sscfu_window(struct sscfu *, void *, u_int);
+static void sscfu_verbose(struct sscfu *, void *, const char *, ...)
+ __printflike(3, 4);
+
+static const struct sscfu_funcs sscfu_funcs = {
+ sscfu_send_upper,
+ sscfu_send_lower,
+ sscfu_window,
+ sscfu_verbose
+};
+
+/************************************************************/
+/*
+ * CONTROL MESSAGES
+ */
+static int
+text_status(node_p node, struct priv *priv, char *arg, u_int len)
+{
+ struct sbuf sbuf;
+
+ sbuf_new(&sbuf, arg, len, 0);
+
+ if (priv->upper)
+ sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
+ NG_HOOK_NAME(priv->upper),
+ NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
+ NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
+ else
+ sbuf_printf(&sbuf, "upper hook: <not connected>\n");
+
+ if (priv->lower)
+ sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
+ NG_HOOK_NAME(priv->lower),
+ NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
+ NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
+ else
+ sbuf_printf(&sbuf, "lower hook: <not connected>\n");
+
+ sbuf_printf(&sbuf, "sscf state: %s\n",
+ priv->enabled == NULL ? "<disabled>" :
+ sscfu_statename(sscfu_getstate(priv->sscf)));
+
+ sbuf_finish(&sbuf);
+ return (sbuf_len(&sbuf));
+}
+
+static int
+ng_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ng_mesg *resp = NULL;
+ struct ng_mesg *msg;
+ int error = 0;
+
+ NGI_GET_MSG(item, msg);
+
+ switch (msg->header.typecookie) {
+
+ case NGM_GENERIC_COOKIE:
+ switch (msg->header.cmd) {
+
+ case NGM_TEXT_STATUS:
+ NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ resp->header.arglen = text_status(node, priv,
+ (char *)resp->data, resp->header.arglen) + 1;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ case NGM_SSCFU_COOKIE:
+ switch (msg->header.cmd) {
+
+ case NGM_SSCFU_GETDEFPARAM:
+ {
+ struct ng_sscfu_getdefparam *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 ng_sscfu_getdefparam *)resp->data;
+ p->mask = sscfu_getdefparam(&p->param);
+ break;
+ }
+
+ case NGM_SSCFU_ENABLE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (priv->enabled) {
+ error = EISCONN;
+ break;
+ }
+ priv->enabled = 1;
+ break;
+
+ case NGM_SSCFU_DISABLE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (!priv->enabled) {
+ error = ENOTCONN;
+ break;
+ }
+ priv->enabled = 0;
+ sscfu_reset(priv->sscf);
+ break;
+
+ case NGM_SSCFU_GETSTATE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
+ if(resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *(uint32_t *)resp->data =
+ priv->enabled ? (sscfu_getstate(priv->sscf) + 1)
+ : 0;
+ break;
+
+ case NGM_SSCFU_GETDEBUG:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
+ if(resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *(uint32_t *)resp->data = sscfu_getdebug(priv->sscf);
+ break;
+
+ case NGM_SSCFU_SETDEBUG:
+ if (msg->header.arglen != sizeof(uint32_t)) {
+ error = EINVAL;
+ break;
+ }
+ sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ NG_RESPOND_MSG(error, node, item, resp);
+ NG_FREE_MSG(msg);
+
+ return (error);
+}
+
+/************************************************************/
+/*
+ * HOOK MANAGEMENT
+ */
+static int
+ng_sscfu_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if (strcmp(name, "upper") == 0)
+ priv->upper = hook;
+ else if (strcmp(name, "lower") == 0) {
+ priv->lower = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_sscfu_rcvlower);
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+static int
+ng_sscfu_disconnect(hook_p hook)
+{
+ node_p node = NG_HOOK_NODE(hook);
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if (hook == priv->upper)
+ priv->upper = NULL;
+ else if (hook == priv->lower)
+ priv->lower = NULL;
+ else {
+ log(LOG_ERR, "bogus hook");
+ return (EINVAL);
+ }
+
+ if (NG_NODE_NUMHOOKS(node) == 0) {
+ if (NG_NODE_IS_VALID(node))
+ ng_rmnode_self(node);
+ } else {
+ /*
+ * Because there are no timeouts reset the protocol
+ * if the lower layer is disconnected.
+ */
+ if (priv->lower == NULL &&
+ priv->enabled &&
+ sscfu_getstate(priv->sscf) != SSCFU_RELEASED)
+ sscfu_reset(priv->sscf);
+ }
+ return (0);
+}
+
+/************************************************************/
+/*
+ * DATA
+ */
+static int
+ng_sscfu_rcvupper(hook_p hook, item_p item)
+{
+ node_p node = NG_HOOK_NODE(hook);
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct mbuf *m;
+ struct sscfu_arg a;
+
+ if (!priv->enabled || priv->lower == NULL) {
+ NG_FREE_ITEM(item);
+ return (0);
+ }
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ if (!(m->m_flags & M_PKTHDR)) {
+ printf("no pkthdr\n");
+ m_freem(m);
+ return (EINVAL);
+ }
+ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
+ return (ENOMEM);
+ bcopy((caddr_t)mtod(m, struct sscfu_arg *), &a, sizeof(a));
+ m_adj(m, sizeof(a));
+
+ return (sscfu_saalsig(priv->sscf, a.sig, m));
+}
+
+static void
+sscfu_send_upper(struct sscfu *sscf, void *p, enum saal_sig sig, struct mbuf *m)
+{
+ node_p node = (node_p)p;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ int error;
+ struct sscfu_arg *a;
+
+ if (priv->upper == NULL) {
+ if (m != NULL)
+ m_freem(m);
+ return;
+ }
+ if (m == NULL) {
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ m->m_len = sizeof(struct sscfu_arg);
+ m->m_pkthdr.len = m->m_len;
+ } else {
+ M_PREPEND(m, sizeof(struct sscfu_arg), M_NOWAIT);
+ if (m == NULL)
+ return;
+ }
+ a = mtod(m, struct sscfu_arg *);
+ a->sig = sig;
+
+ NG_SEND_DATA_ONLY(error, priv->upper, m);
+}
+
+static int
+ng_sscfu_rcvlower(hook_p hook, item_p item)
+{
+ node_p node = NG_HOOK_NODE(hook);
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct mbuf *m;
+ struct sscop_arg a;
+
+ if (!priv->enabled || priv->upper == NULL) {
+ NG_FREE_ITEM(item);
+ return (0);
+ }
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ if (!(m->m_flags & M_PKTHDR)) {
+ printf("no pkthdr\n");
+ m_freem(m);
+ return (EINVAL);
+ }
+
+ /*
+ * Strip of the SSCOP header.
+ */
+ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
+ return (ENOMEM);
+ bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
+ m_adj(m, sizeof(a));
+
+ sscfu_input(priv->sscf, a.sig, m, a.arg);
+
+ return (0);
+}
+
+static void
+sscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig,
+ struct mbuf *m, u_int arg)
+{
+ node_p node = (node_p)p;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ int error;
+ struct sscop_arg *a;
+
+ if (priv->lower == NULL) {
+ if (m != NULL)
+ m_freem(m);
+ return;
+ }
+ if (m == NULL) {
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ m->m_len = sizeof(struct sscop_arg);
+ m->m_pkthdr.len = m->m_len;
+ } else {
+ M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
+ if (m == NULL)
+ return;
+ }
+ a = mtod(m, struct sscop_arg *);
+ a->sig = sig;
+ a->arg = arg;
+
+ NG_SEND_DATA_ONLY(error, priv->lower, m);
+}
+
+/*
+ * Window is handled by ng_sscop so make this a NOP.
+ */
+static void
+sscfu_window(struct sscfu *sscfu, void *arg, u_int w)
+{
+}
+
+/************************************************************/
+/*
+ * NODE MANAGEMENT
+ */
+static int
+ng_sscfu_constructor(node_p node)
+{
+ struct priv *priv;
+
+ if ((priv = malloc(sizeof(*priv), M_NG_SSCFU, M_NOWAIT|M_ZERO)) == NULL)
+ return (ENOMEM);
+
+ if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) {
+ free(priv, M_NG_SSCFU);
+ return (ENOMEM);
+ }
+
+ NG_NODE_SET_PRIVATE(node, priv);
+
+ return (0);
+}
+
+static int
+ng_sscfu_shutdown(node_p node)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ sscfu_destroy(priv->sscf);
+
+ free(priv, M_NG_SSCFU);
+ NG_NODE_SET_PRIVATE(node, NULL);
+
+ NG_NODE_UNREF(node);
+
+ return (0);
+}
+
+static void
+sscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ printf("sscfu(%p): ", sscfu);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+}
+
+/************************************************************/
+/*
+ * INITIALISATION
+ */
+/*
+ * Loading and unloading of node type
+ */
+static int
+ng_sscfu_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/sscfu/ng_sscfu_cust.h b/sys/netgraph/atm/sscfu/ng_sscfu_cust.h
new file mode 100644
index 0000000..dcc197a
--- /dev/null
+++ b/sys/netgraph/atm/sscfu/ng_sscfu_cust.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti 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 the SSCFU code to ng_sscfu.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/queue.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <machine/stdarg.h>
+
+/*
+ * Allocate zeroed or non-zeroed memory of some size and cast it.
+ * Return NULL on failure.
+ */
+#ifndef SSCFU_DEBUG
+
+#define MEMINIT() \
+ MALLOC_DECLARE(M_NG_SSCFU); \
+ DECL_SIGQ_GET
+
+#define MEMZALLOC(PTR, CAST, SIZE) \
+ ((PTR) = (CAST)malloc((SIZE), M_NG_SSCFU, M_NOWAIT | M_ZERO))
+#define MEMFREE(PTR) \
+ free(PTR, M_NG_SSCFU)
+
+#define SIG_ALLOC(PTR) \
+ MEMZALLOC(PTR, struct sscfu_sig *, sizeof(struct sscfu_sig))
+#define SIG_FREE(PTR) \
+ MEMFREE(PTR)
+
+#else
+
+#define MEMINIT() \
+ MALLOC_DEFINE(M_NG_SSCFU_INS, "sscfu_ins", "SSCFU instances"); \
+ MALLOC_DEFINE(M_NG_SSCFU_SIG, "sscfu_sig", "SSCFU signals"); \
+ DECL_SIGQ_GET
+
+#define MEMZALLOC(PTR, CAST, SIZE) \
+ ((PTR) = (CAST)malloc((SIZE), M_NG_SSCFU_INS, M_NOWAIT | M_ZERO))
+#define MEMFREE(PTR) \
+ FREE(PTR, M_NG_SSCFU_INS)
+
+#define SIG_ALLOC(PTR) \
+ ((PTR) = malloc(sizeof(struct sscfu_sig), \
+ M_NG_SSCFU_SIG, M_NOWAIT | M_ZERO))
+#define SIG_FREE(PTR) \
+ FREE(PTR, M_NG_SSCFU_SIG)
+
+#endif
+
+
+/*
+ * Signal queues
+ */
+typedef TAILQ_ENTRY(sscfu_sig) sscfu_sigq_link_t;
+typedef TAILQ_HEAD(sscfu_sigq, sscfu_sig) sscfu_sigq_head_t;
+#define SIGQ_INIT(Q) TAILQ_INIT(Q)
+#define SIGQ_APPEND(Q, S) TAILQ_INSERT_TAIL(Q, S, link)
+
+#define SIGQ_GET(Q) ng_sscfu_sigq_get((Q))
+
+#define DECL_SIGQ_GET \
+static __inline struct sscfu_sig * \
+ng_sscfu_sigq_get(struct sscfu_sigq *q) \
+{ \
+ struct sscfu_sig *s; \
+ \
+ s = TAILQ_FIRST(q); \
+ if (s != NULL) \
+ TAILQ_REMOVE(q, s, link); \
+ return (s); \
+}
+
+#define SIGQ_CLEAR(Q) \
+ do { \
+ struct sscfu_sig *_s1, *_s2; \
+ \
+ _s1 = TAILQ_FIRST(Q); \
+ while (_s1 != NULL) { \
+ _s2 = TAILQ_NEXT(_s1, link); \
+ if (_s1->m) \
+ MBUF_FREE(_s1->m); \
+ SIG_FREE(_s1); \
+ _s1 = _s2; \
+ } \
+ TAILQ_INIT(Q); \
+ } while (0)
+
+
+/*
+ * Message buffers
+ */
+#define MBUF_FREE(M) m_freem(M)
+
+#ifdef SSCFU_DEBUG
+#define ASSERT(S) KASSERT(S, (#S))
+#else
+#define ASSERT(S)
+#endif
diff --git a/sys/netgraph/atm/sscop/ng_sscop.c b/sys/netgraph/atm/sscop/ng_sscop.c
new file mode 100644
index 0000000..b87be7c
--- /dev/null
+++ b/sys/netgraph/atm/sscop/ng_sscop.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * 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 FRAUNHOFER FOKUS
+ * 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
+ * FRAUNHOFER FOKUS 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.
+ *
+ * Netgraph module for ITU-T Q.2110 SSCOP.
+ */
+
+#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/callout.h>
+#include <sys/sbuf.h>
+#include <sys/stdint.h>
+#include <machine/stdarg.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+#include <netnatm/saal/sscopdef.h>
+#include <netgraph/atm/ng_sscop.h>
+#include <netgraph/atm/sscop/ng_sscop_cust.h>
+#include <netnatm/saal/sscop.h>
+
+#define DDD printf("%s: %d\n", __FUNCTION__, __LINE__)
+
+#ifdef SSCOP_DEBUG
+#define VERBOSE(P,M,F) \
+ do { \
+ if (sscop_getdebug((P)->sscop) & (M)) \
+ sscop_verbose F ; \
+ } while(0)
+#else
+#define VERBOSE(P,M,F)
+#endif
+
+MALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node");
+
+MODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1);
+
+struct stats {
+ uint64_t in_packets;
+ uint64_t out_packets;
+ uint64_t aa_signals;
+ uint64_t errors;
+ uint64_t data_delivered;
+ uint64_t aa_dropped;
+ uint64_t maa_dropped;
+ uint64_t maa_signals;
+ uint64_t in_dropped;
+ uint64_t out_dropped;
+};
+
+/*
+ * Private data
+ */
+struct priv {
+ hook_p upper; /* SAAL interface */
+ hook_p lower; /* AAL5 interface */
+ hook_p manage; /* management interface */
+
+ struct sscop *sscop; /* sscop state */
+ int enabled; /* whether the protocol is enabled */
+ int flow; /* flow control states */
+ struct stats stats; /* sadistics */
+};
+
+/*
+ * Parse PARAM type
+ */
+static const struct ng_parse_struct_field ng_sscop_param_type_info[] =
+ NG_SSCOP_PARAM_INFO;
+
+static const struct ng_parse_type ng_sscop_param_type = {
+ &ng_parse_struct_type,
+ ng_sscop_param_type_info
+};
+
+/*
+ * Parse a SET PARAM type.
+ */
+static const struct ng_parse_struct_field ng_sscop_setparam_type_info[] =
+ NG_SSCOP_SETPARAM_INFO;
+
+static const struct ng_parse_type ng_sscop_setparam_type = {
+ &ng_parse_struct_type,
+ ng_sscop_setparam_type_info,
+};
+
+/*
+ * Parse a SET PARAM response
+ */
+static const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] =
+ NG_SSCOP_SETPARAM_RESP_INFO;
+
+static const struct ng_parse_type ng_sscop_setparam_resp_type = {
+ &ng_parse_struct_type,
+ ng_sscop_setparam_resp_type_info,
+};
+
+static const struct ng_cmdlist ng_sscop_cmdlist[] = {
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_GETPARAM,
+ "getparam",
+ NULL,
+ &ng_sscop_param_type
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_SETPARAM,
+ "setparam",
+ &ng_sscop_setparam_type,
+ &ng_sscop_setparam_resp_type
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_ENABLE,
+ "enable",
+ NULL,
+ NULL
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_DISABLE,
+ "disable",
+ NULL,
+ NULL
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_GETDEBUG,
+ "getdebug",
+ NULL,
+ &ng_parse_hint32_type
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_SETDEBUG,
+ "setdebug",
+ &ng_parse_hint32_type,
+ NULL
+ },
+ {
+ NGM_SSCOP_COOKIE,
+ NGM_SSCOP_GETSTATE,
+ "getstate",
+ NULL,
+ &ng_parse_uint32_type
+ },
+ { 0 }
+};
+
+static ng_constructor_t ng_sscop_constructor;
+static ng_shutdown_t ng_sscop_shutdown;
+static ng_rcvmsg_t ng_sscop_rcvmsg;
+static ng_newhook_t ng_sscop_newhook;
+static ng_disconnect_t ng_sscop_disconnect;
+static ng_rcvdata_t ng_sscop_rcvlower;
+static ng_rcvdata_t ng_sscop_rcvupper;
+static ng_rcvdata_t ng_sscop_rcvmanage;
+
+static int ng_sscop_mod_event(module_t, int, void *);
+
+static struct ng_type ng_sscop_typestruct = {
+ NG_ABI_VERSION,
+ NG_SSCOP_NODE_TYPE,
+ ng_sscop_mod_event, /* Module event handler (optional) */
+ ng_sscop_constructor, /* Node constructor */
+ ng_sscop_rcvmsg, /* control messages come here */
+ ng_sscop_shutdown, /* reset, and free resources */
+ ng_sscop_newhook, /* first notification of new hook */
+ NULL, /* findhook */
+ NULL, /* connect */
+ ng_sscop_rcvlower, /* rcvdata */
+ ng_sscop_disconnect, /* notify on disconnect */
+ ng_sscop_cmdlist,
+};
+NETGRAPH_INIT(sscop, &ng_sscop_typestruct);
+
+static void sscop_send_manage(struct sscop *, void *, enum sscop_maasig,
+ struct SSCOP_MBUF_T *, u_int, u_int);
+static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig,
+ struct SSCOP_MBUF_T *, u_int);
+static void sscop_send_lower(struct sscop *, void *,
+ struct SSCOP_MBUF_T *);
+static void sscop_verbose(struct sscop *, void *, const char *, ...)
+ __printflike(3, 4);
+
+static const struct sscop_funcs sscop_funcs = {
+ sscop_send_manage,
+ sscop_send_upper,
+ sscop_send_lower,
+ sscop_verbose
+};
+
+static void
+sscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ printf("sscop(%p): ", sscop);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+}
+
+/************************************************************/
+/*
+ * NODE MANAGEMENT
+ */
+static int
+ng_sscop_constructor(node_p node)
+{
+ struct priv *p;
+
+ if ((p = malloc(sizeof(*p), M_NG_SSCOP, M_NOWAIT | M_ZERO)) == NULL)
+ return (ENOMEM);
+
+ if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) {
+ free(p, M_NG_SSCOP);
+ return (ENOMEM);
+ }
+ NG_NODE_SET_PRIVATE(node, p);
+
+ /* All data message received by the node are expected to change the
+ * node's state. Therefor we must ensure, that we have a writer lock. */
+ NG_NODE_FORCE_WRITER(node);
+
+ return (0);
+}
+static int
+ng_sscop_shutdown(node_p node)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ sscop_destroy(priv->sscop);
+
+ free(priv, M_NG_SSCOP);
+ NG_NODE_SET_PRIVATE(node, NULL);
+
+ NG_NODE_UNREF(node);
+
+ return (0);
+}
+
+/************************************************************/
+/*
+ * CONTROL MESSAGES
+ */
+/*
+ * Flow control message from upper layer.
+ * This is very experimental:
+ * If we get a message from the upper layer, that somebody has passed its
+ * high water mark, we stop updating the receive window.
+ * If we get a low watermark passed, then we raise the window up
+ * to max - current.
+ * If we get a queue status and it indicates a current below the
+ * high watermark, we unstop window updates (if they are stopped) and
+ * raise the window to highwater - current.
+ */
+static int
+flow_upper(node_p node, struct ng_mesg *msg)
+{
+ struct ngm_queue_state *q;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ u_int window, space;
+
+ if (msg->header.arglen != sizeof(struct ngm_queue_state))
+ return (EINVAL);
+ q = (struct ngm_queue_state *)msg->data;
+
+ switch (msg->header.cmd) {
+
+ case NGM_HIGH_WATER_PASSED:
+ if (priv->flow) {
+ VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
+ "flow control stopped"));
+ priv->flow = 0;
+ }
+ break;
+
+ case NGM_LOW_WATER_PASSED:
+ window = sscop_window(priv->sscop, 0);
+ space = q->max_queuelen_packets - q->current;
+ if (space > window) {
+ VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
+ "flow control opened window by %u messages",
+ space - window));
+ (void)sscop_window(priv->sscop, space - window);
+ }
+ priv->flow = 1;
+ break;
+
+ case NGM_SYNC_QUEUE_STATE:
+ if (q->high_watermark <= q->current)
+ break;
+ window = sscop_window(priv->sscop, 0);
+ if (priv->flow)
+ space = q->max_queuelen_packets - q->current;
+ else
+ space = q->high_watermark - q->current;
+ if (space > window) {
+ VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
+ "flow control opened window by %u messages",
+ space - window));
+ (void)sscop_window(priv->sscop, space - window);
+ }
+ priv->flow = 1;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+flow_lower(node_p node, struct ng_mesg *msg)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if (msg->header.arglen != sizeof(struct ngm_queue_state))
+ return (EINVAL);
+
+ switch (msg->header.cmd) {
+
+ case NGM_HIGH_WATER_PASSED:
+ sscop_setbusy(priv->sscop, 1);
+ break;
+
+ case NGM_LOW_WATER_PASSED:
+ sscop_setbusy(priv->sscop, 1);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+/*
+ * Produce a readable status description
+ */
+static int
+text_status(node_p node, struct priv *priv, char *arg, u_int len)
+{
+ struct sbuf sbuf;
+
+ sbuf_new(&sbuf, arg, len, 0);
+
+ if (priv->upper)
+ sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
+ NG_HOOK_NAME(priv->upper),
+ NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
+ NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
+ else
+ sbuf_printf(&sbuf, "upper hook: <not connected>\n");
+
+ if (priv->lower)
+ sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
+ NG_HOOK_NAME(priv->lower),
+ NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
+ NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
+ else
+ sbuf_printf(&sbuf, "lower hook: <not connected>\n");
+
+ if (priv->manage)
+ sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n",
+ NG_HOOK_NAME(priv->manage),
+ NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))),
+ NG_HOOK_NAME(NG_HOOK_PEER(priv->manage)));
+ else
+ sbuf_printf(&sbuf, "manage hook: <not connected>\n");
+
+ sbuf_printf(&sbuf, "sscop state: %s\n",
+ !priv->enabled ? "<disabled>" :
+ sscop_statename(sscop_getstate(priv->sscop)));
+
+ sbuf_printf(&sbuf, "input packets: %ju\n",
+ (uintmax_t)priv->stats.in_packets);
+ sbuf_printf(&sbuf, "input dropped: %ju\n",
+ (uintmax_t)priv->stats.in_dropped);
+ sbuf_printf(&sbuf, "output packets: %ju\n",
+ (uintmax_t)priv->stats.out_packets);
+ sbuf_printf(&sbuf, "output dropped: %ju\n",
+ (uintmax_t)priv->stats.out_dropped);
+ sbuf_printf(&sbuf, "aa signals: %ju\n",
+ (uintmax_t)priv->stats.aa_signals);
+ sbuf_printf(&sbuf, "aa dropped: %ju\n",
+ (uintmax_t)priv->stats.aa_dropped);
+ sbuf_printf(&sbuf, "maa signals: %ju\n",
+ (uintmax_t)priv->stats.maa_signals);
+ sbuf_printf(&sbuf, "maa dropped: %ju\n",
+ (uintmax_t)priv->stats.maa_dropped);
+ sbuf_printf(&sbuf, "errors: %ju\n",
+ (uintmax_t)priv->stats.errors);
+ sbuf_printf(&sbuf, "data delivered: %ju\n",
+ (uintmax_t)priv->stats.data_delivered);
+ sbuf_printf(&sbuf, "window: %u\n",
+ sscop_window(priv->sscop, 0));
+
+ sbuf_finish(&sbuf);
+ return (sbuf_len(&sbuf));
+}
+
+
+/*
+ * Control message received.
+ */
+static int
+ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ struct ng_mesg *resp = NULL;
+ struct ng_mesg *msg;
+ int error = 0;
+
+ NGI_GET_MSG(item, msg);
+
+ switch (msg->header.typecookie) {
+
+ case NGM_GENERIC_COOKIE:
+ switch (msg->header.cmd) {
+
+ case NGM_TEXT_STATUS:
+ NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ resp->header.arglen = text_status(node, priv,
+ (char *)resp->data, resp->header.arglen) + 1;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ case NGM_FLOW_COOKIE:
+ if (priv->enabled && lasthook != NULL) {
+ if (lasthook == priv->upper)
+ error = flow_upper(node, msg);
+ else if (lasthook == priv->lower)
+ error = flow_lower(node, msg);
+ }
+ break;
+
+ case NGM_SSCOP_COOKIE:
+ switch (msg->header.cmd) {
+
+ case NGM_SSCOP_GETPARAM:
+ {
+ struct sscop_param *p;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ p = (struct sscop_param *)resp->data;
+ sscop_getparam(priv->sscop, p);
+ break;
+ }
+
+ case NGM_SSCOP_SETPARAM:
+ {
+ struct ng_sscop_setparam *arg;
+ struct ng_sscop_setparam_resp *p;
+
+ if (msg->header.arglen != sizeof(*arg)) {
+ error = EINVAL;
+ break;
+ }
+ if (priv->enabled) {
+ error = EISCONN;
+ break;
+ }
+ arg = (struct ng_sscop_setparam *)msg->data;
+ NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ p = (struct ng_sscop_setparam_resp *)resp->data;
+ p->mask = arg->mask;
+ p->error = sscop_setparam(priv->sscop,
+ &arg->param, &p->mask);
+ break;
+ }
+
+ case NGM_SSCOP_ENABLE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (priv->enabled) {
+ error = EBUSY;
+ break;
+ }
+ priv->enabled = 1;
+ priv->flow = 1;
+ memset(&priv->stats, 0, sizeof(priv->stats));
+ break;
+
+ case NGM_SSCOP_DISABLE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (!priv->enabled) {
+ error = ENOTCONN;
+ break;
+ }
+ priv->enabled = 0;
+ sscop_reset(priv->sscop);
+ break;
+
+ case NGM_SSCOP_GETDEBUG:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
+ if(resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop);
+ break;
+
+ case NGM_SSCOP_SETDEBUG:
+ if (msg->header.arglen != sizeof(u_int32_t)) {
+ error = EINVAL;
+ break;
+ }
+ sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data);
+ break;
+
+ case NGM_SSCOP_GETSTATE:
+ if (msg->header.arglen != 0) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
+ if(resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *(u_int32_t *)resp->data =
+ priv->enabled ? (sscop_getstate(priv->sscop) + 1)
+ : 0;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ NG_RESPOND_MSG(error, node, item, resp);
+ NG_FREE_MSG(msg);
+
+ return (error);
+}
+
+/************************************************************/
+/*
+ * HOOK MANAGEMENT
+ */
+static int
+ng_sscop_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if(strcmp(name, "upper") == 0) {
+ priv->upper = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper);
+ } else if(strcmp(name, "lower") == 0) {
+ priv->lower = hook;
+ } else if(strcmp(name, "manage") == 0) {
+ priv->manage = hook;
+ NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage);
+ } else
+ return EINVAL;
+
+ return 0;
+}
+static int
+ng_sscop_disconnect(hook_p hook)
+{
+ node_p node = NG_HOOK_NODE(hook);
+ struct priv *priv = NG_NODE_PRIVATE(node);
+
+ if(hook == priv->upper)
+ priv->upper = NULL;
+ else if(hook == priv->lower)
+ priv->lower = NULL;
+ else if(hook == priv->manage)
+ priv->manage = NULL;
+
+ if(NG_NODE_NUMHOOKS(node) == 0) {
+ if(NG_NODE_IS_VALID(node))
+ ng_rmnode_self(node);
+ } else {
+ /*
+ * Imply a release request, if the upper layer is
+ * disconnected.
+ */
+ if(priv->upper == NULL && priv->lower != NULL &&
+ priv->enabled &&
+ sscop_getstate(priv->sscop) != SSCOP_IDLE) {
+ sscop_aasig(priv->sscop, SSCOP_RELEASE_request,
+ NULL, 0);
+ }
+ }
+ return 0;
+}
+
+/************************************************************/
+/*
+ * DATA
+ */
+static int
+ng_sscop_rcvlower(hook_p hook, item_p item)
+{
+ struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ struct mbuf *m;
+
+ if (!priv->enabled) {
+ NG_FREE_ITEM(item);
+ return EINVAL;
+ }
+
+ /*
+ * If we are disconnected at the upper layer and in the IDLE
+ * state, drop any incoming packet.
+ */
+ if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) {
+ NGI_GET_M(item, m);
+ priv->stats.in_packets++;
+ sscop_input(priv->sscop, m);
+ } else {
+ priv->stats.in_dropped++;
+ }
+ NG_FREE_ITEM(item);
+
+ return (0);
+}
+
+static void
+sscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m)
+{
+ node_p node = (node_p)p;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ int error;
+
+ if (priv->lower == NULL) {
+ m_freem(m);
+ priv->stats.out_dropped++;
+ return;
+ }
+
+ priv->stats.out_packets++;
+ NG_SEND_DATA_ONLY(error, priv->lower, m);
+}
+
+static int
+ng_sscop_rcvupper(hook_p hook, item_p item)
+{
+ struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ struct sscop_arg a;
+ struct mbuf *m;
+
+ if (!priv->enabled) {
+ NG_FREE_ITEM(item);
+ return (EINVAL);
+ }
+
+ /*
+ * If the lower layer is not connected allow to proceed.
+ * The lower layer sending function will drop outgoing frames,
+ * and the sscop will timeout any establish requests.
+ */
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ if (!(m->m_flags & M_PKTHDR)) {
+ printf("no pkthdr\n");
+ m_freem(m);
+ return (EINVAL);
+ }
+ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
+ return (ENOBUFS);
+ bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
+ m_adj(m, sizeof(a));
+
+ return (sscop_aasig(priv->sscop, a.sig, m, a.arg));
+}
+
+static void
+sscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig,
+ struct SSCOP_MBUF_T *m, u_int arg)
+{
+ node_p node = (node_p)p;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ int error;
+ struct sscop_arg *a;
+
+ if (sig == SSCOP_DATA_indication && priv->flow)
+ sscop_window(priv->sscop, 1);
+
+ if (priv->upper == NULL) {
+ if (m != NULL)
+ m_freem(m);
+ priv->stats.aa_dropped++;
+ return;
+ }
+
+ priv->stats.aa_signals++;
+ if (sig == SSCOP_DATA_indication)
+ priv->stats.data_delivered++;
+
+ if (m == NULL) {
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ m->m_len = sizeof(struct sscop_arg);
+ m->m_pkthdr.len = m->m_len;
+ } else {
+ M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
+ if (m == NULL)
+ return;
+ }
+ a = mtod(m, struct sscop_arg *);
+ a->sig = sig;
+ a->arg = arg;
+
+ NG_SEND_DATA_ONLY(error, priv->upper, m);
+}
+
+static int
+ng_sscop_rcvmanage(hook_p hook, item_p item)
+{
+ struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+ struct sscop_marg a;
+ struct mbuf *m;
+
+ if (!priv->enabled) {
+ NG_FREE_ITEM(item);
+ return (EINVAL);
+ }
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
+ return (ENOBUFS);
+ bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
+ m_adj(m, sizeof(a));
+
+ return (sscop_maasig(priv->sscop, a.sig, m));
+}
+
+static void
+sscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig,
+ struct SSCOP_MBUF_T *m, u_int err, u_int cnt)
+{
+ node_p node = (node_p)p;
+ struct priv *priv = NG_NODE_PRIVATE(node);
+ int error;
+ struct sscop_merr *e;
+ struct sscop_marg *a;
+
+ if (priv->manage == NULL) {
+ if (m != NULL)
+ m_freem(m);
+ priv->stats.maa_dropped++;
+ return;
+ }
+
+ if (sig == SSCOP_MERROR_indication) {
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ m->m_len = sizeof(*e);
+ m->m_pkthdr.len = m->m_len;
+ e = mtod(m, struct sscop_merr *);
+ e->sig = sig;
+ e->err = err;
+ e->cnt = cnt;
+ priv->stats.errors++;
+ } else if (m == NULL) {
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ m->m_len = sizeof(*a);
+ m->m_pkthdr.len = m->m_len;
+ a = mtod(m, struct sscop_marg *);
+ a->sig = sig;
+ priv->stats.maa_signals++;
+ } else {
+ M_PREPEND(m, sizeof(*a), M_NOWAIT);
+ if (m == NULL)
+ return;
+ a = mtod(m, struct sscop_marg *);
+ a->sig = sig;
+ priv->stats.maa_signals++;
+ }
+
+ NG_SEND_DATA_ONLY(error, priv->manage, m);
+}
+
+/************************************************************/
+/*
+ * INITIALISATION
+ */
+
+/*
+ * Loading and unloading of node type
+ */
+static int
+ng_sscop_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/sscop/ng_sscop_cust.h b/sys/netgraph/atm/sscop/ng_sscop_cust.h
new file mode 100644
index 0000000..bf9dd8a
--- /dev/null
+++ b/sys/netgraph/atm/sscop/ng_sscop_cust.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti 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.
+ *
+ * $FreeBSD$
+ *
+ * Customisation of the SSCOP code to ng_sscop.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <machine/stdarg.h>
+
+#include <netnatm/saal/sscopdef.h>
+
+/*
+ * Allocate zeroed or non-zeroed memory of some size and cast it.
+ * Return NULL on failure.
+ */
+#ifndef SSCOP_DEBUG
+
+#define MEMINIT() \
+ MALLOC_DECLARE(M_NG_SSCOP); \
+ DECL_MSGQ_GET \
+ DECL_SIGQ_GET \
+ DECL_MBUF_ALLOC
+
+#define MEMZALLOC(PTR, CAST, SIZE) \
+ ((PTR) = (CAST)malloc((SIZE), M_NG_SSCOP, M_NOWAIT | M_ZERO))
+#define MEMFREE(PTR) \
+ free((PTR), M_NG_SSCOP)
+
+#define MSG_ALLOC(PTR) \
+ MEMZALLOC(PTR, struct sscop_msg *, sizeof(struct sscop_msg))
+#define MSG_FREE(PTR) \
+ MEMFREE(PTR)
+
+#define SIG_ALLOC(PTR) \
+ MEMZALLOC(PTR, struct sscop_sig *, sizeof(struct sscop_sig))
+#define SIG_FREE(PTR) \
+ MEMFREE(PTR)
+
+#else
+
+#define MEMINIT() \
+ MALLOC_DEFINE(M_NG_SSCOP_INS, "sscop_ins", "SSCOP instances"); \
+ MALLOC_DEFINE(M_NG_SSCOP_MSG, "sscop_msg", "SSCOP buffers"); \
+ MALLOC_DEFINE(M_NG_SSCOP_SIG, "sscop_sig", "SSCOP signals"); \
+ DECL_MSGQ_GET \
+ DECL_SIGQ_GET \
+ DECL_MBUF_ALLOC
+
+#define MEMZALLOC(PTR, CAST, SIZE) \
+ ((PTR) = (CAST)malloc((SIZE), M_NG_SSCOP_INS, M_NOWAIT | M_ZERO))
+#define MEMFREE(PTR) \
+ free((PTR), M_NG_SSCOP_INS)
+
+#define MSG_ALLOC(PTR) \
+ ((PTR) = malloc(sizeof(struct sscop_msg), \
+ M_NG_SSCOP_MSG, M_NOWAIT | M_ZERO))
+#define MSG_FREE(PTR) \
+ free((PTR), M_NG_SSCOP_MSG)
+
+#define SIG_ALLOC(PTR) \
+ ((PTR) = malloc(sizeof(struct sscop_sig), \
+ M_NG_SSCOP_SIG, M_NOWAIT | M_ZERO))
+#define SIG_FREE(PTR) \
+ free((PTR), M_NG_SSCOP_SIG)
+
+#endif
+
+/*
+ * Timer support.
+ */
+typedef struct callout_handle sscop_timer_t;
+#define TIMER_INIT(S, T) callout_handle_init(&(S)->t_##T)
+#define TIMER_STOP(S,T) do { \
+ ng_untimeout((S)->t_##T, (S)->aarg); \
+ callout_handle_init(&(S)->t_##T); \
+ } while (0)
+#define TIMER_RESTART(S, T) do { \
+ TIMER_STOP(S, T); \
+ (S)->t_##T = ng_timeout((S)->aarg, NULL, \
+ hz * (S)->timer##T / 1000, T##_func, (S), 0); \
+ } while (0)
+#define TIMER_ISACT(S, T) ((S)->t_##T.callout != NULL)
+
+/*
+ * This assumes, that the user argument is the node pointer.
+ */
+#define TIMER_FUNC(T,N) \
+static void \
+T##_func(node_p node, hook_p hook, void *arg1, int arg2) \
+{ \
+ struct sscop *sscop = arg1; \
+ \
+ callout_handle_init(&sscop->t_##T); \
+ VERBOSE(sscop, SSCOP_DBG_TIMER, (sscop, sscop->aarg, \
+ "timer_" #T " expired")); \
+ sscop_signal(sscop, SIG_T_##N, NULL); \
+}
+
+
+/*
+ * Message queues
+ */
+typedef TAILQ_ENTRY(sscop_msg) sscop_msgq_link_t;
+typedef TAILQ_HEAD(sscop_msgq, sscop_msg) sscop_msgq_head_t;
+#define MSGQ_EMPTY(Q) TAILQ_EMPTY(Q)
+#define MSGQ_INIT(Q) TAILQ_INIT(Q)
+#define MSGQ_FOREACH(P, Q) TAILQ_FOREACH(P, Q, link)
+#define MSGQ_REMOVE(Q, M) TAILQ_REMOVE(Q, M, link)
+#define MSGQ_INSERT_BEFORE(B, M) TAILQ_INSERT_BEFORE(B, M, link)
+#define MSGQ_APPEND(Q, M) TAILQ_INSERT_TAIL(Q, M, link)
+#define MSGQ_PEEK(Q) TAILQ_FIRST((Q))
+
+#define MSGQ_GET(Q) ng_sscop_msgq_get((Q))
+
+#define DECL_MSGQ_GET \
+static __inline struct sscop_msg * \
+ng_sscop_msgq_get(struct sscop_msgq *q) \
+{ \
+ struct sscop_msg *m; \
+ \
+ m = TAILQ_FIRST(q); \
+ if (m != NULL) \
+ TAILQ_REMOVE(q, m, link); \
+ return (m); \
+}
+
+#define MSGQ_CLEAR(Q) \
+ do { \
+ struct sscop_msg *_m1, *_m2; \
+ \
+ _m1 = TAILQ_FIRST(Q); \
+ while (_m1 != NULL) { \
+ _m2 = TAILQ_NEXT(_m1, link); \
+ SSCOP_MSG_FREE(_m1); \
+ _m1 = _m2; \
+ } \
+ TAILQ_INIT((Q)); \
+ } while (0)
+
+/*
+ * Signal queues
+ */
+typedef TAILQ_ENTRY(sscop_sig) sscop_sigq_link_t;
+typedef TAILQ_HEAD(sscop_sigq, sscop_sig) sscop_sigq_head_t;
+#define SIGQ_INIT(Q) TAILQ_INIT(Q)
+#define SIGQ_APPEND(Q, S) TAILQ_INSERT_TAIL(Q, S, link)
+#define SIGQ_EMPTY(Q) TAILQ_EMPTY(Q)
+
+#define SIGQ_GET(Q) ng_sscop_sigq_get((Q))
+#define DECL_SIGQ_GET \
+static __inline struct sscop_sig * \
+ng_sscop_sigq_get(struct sscop_sigq *q) \
+{ \
+ struct sscop_sig *s; \
+ \
+ s = TAILQ_FIRST(q); \
+ if (s != NULL) \
+ TAILQ_REMOVE(q, s, link); \
+ return (s); \
+}
+
+#define SIGQ_MOVE(F, T) \
+ do { \
+ struct sscop_sig *_s; \
+ \
+ while (!TAILQ_EMPTY(F)) { \
+ _s = TAILQ_FIRST(F); \
+ TAILQ_REMOVE(F, _s, link); \
+ TAILQ_INSERT_TAIL(T, _s, link); \
+ } \
+ } while (0)
+
+#define SIGQ_PREPEND(F, T) \
+ do { \
+ struct sscop_sig *_s; \
+ \
+ while (!TAILQ_EMPTY(F)) { \
+ _s = TAILQ_LAST(F, sscop_sigq); \
+ TAILQ_REMOVE(F, _s, link); \
+ TAILQ_INSERT_HEAD(T, _s, link); \
+ } \
+ } while (0)
+
+#define SIGQ_CLEAR(Q) \
+ do { \
+ struct sscop_sig *_s1, *_s2; \
+ \
+ _s1 = TAILQ_FIRST(Q); \
+ while (_s1 != NULL) { \
+ _s2 = TAILQ_NEXT(_s1, link); \
+ SSCOP_MSG_FREE(_s1->msg); \
+ SIG_FREE(_s1); \
+ _s1 = _s2; \
+ } \
+ TAILQ_INIT(Q); \
+ } while (0)
+
+/*
+ * Message buffers
+ */
+#define MBUF_FREE(M) do { if ((M)) m_freem((M)); } while(0)
+#define MBUF_DUP(M) m_copypacket((M), M_NOWAIT)
+#define MBUF_LEN(M) ((size_t)(M)->m_pkthdr.len)
+
+/*
+ * Return the i-th word counted from the end of the buffer.
+ * i=-1 will return the last 32bit word, i=-2 the 2nd last.
+ * Assumes that there is enough space.
+ */
+#define MBUF_TRAIL32(M ,I) ng_sscop_mbuf_trail32((M), (I))
+
+static uint32_t __inline
+ng_sscop_mbuf_trail32(const struct mbuf *m, int i)
+{
+ uint32_t w;
+
+ m_copydata(m, m->m_pkthdr.len + 4 * i, 4, (caddr_t)&w);
+ return (ntohl(w));
+}
+
+/*
+ * Strip 32bit value from the end
+ */
+#define MBUF_STRIP32(M) ng_sscop_mbuf_strip32((M))
+
+static uint32_t __inline
+ng_sscop_mbuf_strip32(struct mbuf *m)
+{
+ uint32_t w;
+
+ m_copydata(m, m->m_pkthdr.len - 4, 4, (caddr_t)&w);
+ m_adj(m, -4);
+ return (ntohl(w));
+}
+
+#define MBUF_GET32(M) ng_sscop_mbuf_get32((M))
+
+static uint32_t __inline
+ng_sscop_mbuf_get32(struct mbuf *m)
+{
+ uint32_t w;
+
+ m_copydata(m, 0, 4, (caddr_t)&w);
+ m_adj(m, 4);
+ return (ntohl(w));
+}
+
+/*
+ * Append a 32bit value to an mbuf. Failures are ignored.
+ */
+#define MBUF_APPEND32(M, W) \
+ do { \
+ uint32_t _w = (W); \
+ \
+ _w = htonl(_w); \
+ m_copyback((M), (M)->m_pkthdr.len, 4, (caddr_t)&_w); \
+ } while (0)
+
+/*
+ * Pad a message to a multiple of four byte and return the amount of padding
+ * Failures are ignored.
+ */
+#define MBUF_PAD4(M) ng_sscop_mbuf_pad4((M))
+
+static u_int __inline
+ng_sscop_mbuf_pad4(struct mbuf *m)
+{
+ static u_char pad[4] = { 0, 0, 0, 0 };
+ int len = m->m_pkthdr.len;
+ int npad = 3 - ((len + 3) & 3);
+
+ if (npad != 0)
+ m_copyback(m, len, npad, (caddr_t)pad);
+ return (npad);
+}
+
+#define MBUF_UNPAD(M, P) do { if( (P) > 0) m_adj((M), -(P)); } while (0)
+
+/*
+ * Allocate a message that will probably hold N bytes.
+ */
+#define MBUF_ALLOC(N) ng_sscop_mbuf_alloc((N))
+
+#define DECL_MBUF_ALLOC \
+static __inline struct mbuf * \
+ng_sscop_mbuf_alloc(size_t n) \
+{ \
+ struct mbuf *m; \
+ \
+ MGETHDR(m, M_NOWAIT, MT_DATA); \
+ if (m != NULL) { \
+ m->m_len = 0; \
+ m->m_pkthdr.len = 0; \
+ if (n > MHLEN) { \
+ MCLGET(m, M_NOWAIT); \
+ if (!(m->m_flags & M_EXT)){ \
+ m_free(m); \
+ m = NULL; \
+ } \
+ } \
+ } \
+ return (m); \
+}
+
+#ifdef SSCOP_DEBUG
+#define ASSERT(X) KASSERT(X, (#X))
+#else
+#define ASSERT(X)
+#endif
OpenPOWER on IntegriCloud