diff --git a/sys/netgraph/atm/ng_sscfu.h b/sys/netgraph/atm/ng_sscfu.h new file mode 100644 index 000000000000..600d892f2c6c --- /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 + * + * 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 000000000000..26de7e210376 --- /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 + * + * 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 000000000000..8a802c667406 --- /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 + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 000000000000..70dd275800a8 --- /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 + * + * 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 000000000000..d15c503c9ad9 --- /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 + * + * Netgraph module for ITU-T Q.2120 UNI SSCF. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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: \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: \n"); + + sbuf_printf(&sbuf, "sscf state: %s\n", + priv->enabled == NULL ? "" : + 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 000000000000..dcc197acbd4d --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 000000000000..b87be7c85d64 --- /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 + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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: \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: \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: \n"); + + sbuf_printf(&sbuf, "sscop state: %s\n", + !priv->enabled ? "" : + 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 000000000000..bf9dd8a49b58 --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * 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