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:
parent
44a38765ae
commit
e43801eab1
68
sys/netgraph/atm/ng_sscfu.h
Normal file
68
sys/netgraph/atm/ng_sscfu.h
Normal 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
110
sys/netgraph/atm/ng_sscop.h
Normal 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
|
500
sys/netgraph/atm/ngatmbase.c
Normal file
500
sys/netgraph/atm/ngatmbase.c
Normal 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);
|
||||
}
|
64
sys/netgraph/atm/ngatmbase.h
Normal file
64
sys/netgraph/atm/ngatmbase.h
Normal 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
|
611
sys/netgraph/atm/sscfu/ng_sscfu.c
Normal file
611
sys/netgraph/atm/sscfu/ng_sscfu.c
Normal 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);
|
||||
}
|
131
sys/netgraph/atm/sscfu/ng_sscfu_cust.h
Normal file
131
sys/netgraph/atm/sscfu/ng_sscfu_cust.h
Normal 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
|
885
sys/netgraph/atm/sscop/ng_sscop.c
Normal file
885
sys/netgraph/atm/sscop/ng_sscop.c
Normal 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);
|
||||
}
|
346
sys/netgraph/atm/sscop/ng_sscop_cust.h
Normal file
346
sys/netgraph/atm/sscop/ng_sscop_cust.h
Normal 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
|
Loading…
Reference in New Issue
Block a user