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).
This commit is contained in:
harti 2003-10-24 07:39:11 +00:00
parent 44a38765ae
commit e43801eab1
8 changed files with 2715 additions and 0 deletions

View File

@ -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

110
sys/netgraph/atm/ng_sscop.h Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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