FreeBSD: add module netgraph.

dev
logwang 2017-10-25 14:38:15 +08:00
parent 20be49f608
commit a1fd9364a9
178 changed files with 90495 additions and 110 deletions

View File

@ -5370,8 +5370,10 @@ sppp_proto_name(u_short proto)
static void
sppp_print_bytes(const u_char *p, u_short len)
{
#ifndef FSTACK
if (len)
log(-1, " %*D", len, p, "-");
#endif
}
static void

103
freebsd/netgraph/NOTES Normal file
View File

@ -0,0 +1,103 @@
$FreeBSD$
Development ideas..
Archie's suggestions... :-)
- There should be a new malloc type: M_NETGRAPH
[DONE]
- all mallocs/frees now changed to use this.. JRE
- might further split them out some time.
- Use MALLOC and FREE macros instead of direct function calls
[DONE]
- They allow conditional compilation which keeps
statistics & counters on various memory allocation
(or so it seems)
- Now tend to have NG_FREE_XX() macros. they
allow better debugging
- In struct ng_mesg: at least make "header" into "hdr", if not
getting rid of it altogether. It doesn't seem necessary and
makes all my C code lines too long.
- I understand.. one thought however.. consider..
if char data[0] were not legal, so that data[1] needed to be
used instead, then the only way to get the size of the header
would be sizeof(msg.header) as sizeof(msg) would include the dummy
following bytes. this is a portability issue and I hope
it will be ported eventually :)
- Baloney! you can use sizeof(msg) - 1 then.. or just
make it a macro, then its always portable:
#ifdef __GNU_C__
#define NG_MSG_HDR_SIZE (sizeof(struct ng_message))
#else
#define NG_MSG_HDR_SIZE (sizeof(struct ng_message) - 1)
#endif
- inertia rules :-b
- Have a user level program to print out and manipulate nodes, etc.
- [DONE]
see ngctl, nghook
- "Netgraph global" flags to turn on tracing, etc.
- ngctl needs to be rewritten using libnetgraph. Also it needs a
command to list all existing nodes (in case you don't know the
name of what you're looking for).
[DONE]
- Need a way to get a list of ALL nodes.
[DONE]
- see NGM_LISTNODES
- Enhance "netstat" to display all netgraph nodes -- or at least
all netgraph socket nodes.
[DONE]
- BUG FIX: bind() on a socket should neither require nor allow a
colon character at the end of the name. Note ngctl allows you
to do it either way!
[DONE] (I think)
- bind on a control socket has been disabled
it was a bad idea.
- Need to implement passing meta information through socket nodes
using sendmsg() and recvmsg().
- Stuff needing to be added to manual:
- Awareness of SPL level, use ng_queue*() functions when necessary.
- Malloc all memory with type M_NETGRAPH. -DONE
- Write code so it can be an LKM or built into the kernel.. this means
be careful with things like #ifdef INET.
- All nodes assume that all data mbufs have the M_PKTHDR flag set!
The ng_send_data() and related functions should have an
#ifdef DIAGNOSTIC check to check this assumption for every mbuf.
-DONE with INVARIANTS. Framework should test this more.
- More generally, netgraph code should make liberal use of the
#ifdef DIAGNOSTIC definition.
-INVARIANTS.
- Since data and messages are sent functionally, programmers need
to watch out for infinite feedback loops. Should ng_base.c detect
this automatically?
- I've been thinking about this. each node could have a 'colour'
which is set to the colour of the packet as you pass through.
hitting a node already of your colour would abort. Each packet
has another (incremented) colour.
-new 'item' type can hold a hopcount...
NEW in 2001
All piggyback responses have gone away.
use the node ID in the return address field for quick response delivery.
Every node has a queue, plus there is a list of nodes that have queued work.
Extensive use of Mutexes. Getting in shape for SMP.
Messages and data are deliverd in a new form. An Item now has
all information needed to queue such a request and deliver it later, so
it is now the basis of all data transfer since any transfer may need to
be queued.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2004
* Hartmut Brandt
* 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.
*
* Customisation of call control source to the NG environment.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/atm/ngatmbase.h>
#define CCASSERT(E, M) KASSERT(E, M)
MALLOC_DECLARE(M_NG_CCATM);
#define CCMALLOC(S) (malloc((S), M_NG_CCATM, M_NOWAIT))
#define CCZALLOC(S) (malloc((S), M_NG_CCATM, M_NOWAIT | M_ZERO))
#define CCFREE(P) do { free((P), M_NG_CCATM); } while (0)
#define CCGETERRNO() (ENOMEM)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
/*-
* Copyright (c) 2001-2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Author: Harti Brandt <harti@freebsd.org>
*/
/*
* Netgraph module to connect NATM interfaces to netgraph.
*
* $FreeBSD$
*/
#ifndef _NETGRAPH_ATM_NG_ATM_H_
#define _NETGRAPH_ATM_NG_ATM_H_
#define NG_ATM_NODE_TYPE "atm"
#define NGM_ATM_COOKIE 960802260
/* Netgraph control messages */
enum {
NGM_ATM_GET_IFNAME = 1, /* get the interface name */
NGM_ATM_GET_CONFIG, /* get configuration */
NGM_ATM_GET_VCCS, /* get a list of all active vccs */
NGM_ATM_CPCS_INIT, /* start the channel */
NGM_ATM_CPCS_TERM, /* stop the channel */
NGM_ATM_GET_VCC, /* get VCC config */
NGM_ATM_GET_VCCID, /* get VCC by VCI/VPI */
NGM_ATM_GET_STATS, /* get global statistics */
/* messages from the node */
NGM_ATM_CARRIER_CHANGE = 1000, /* UNUSED: carrier changed */
NGM_ATM_VCC_CHANGE, /* permanent VCC changed */
NGM_ATM_ACR_CHANGE, /* ABR ACR has changed */
NGM_ATM_IF_CHANGE, /* interface state change */
};
/*
* Hardware interface configuration
*/
struct ngm_atm_config {
uint32_t pcr; /* peak cell rate */
uint32_t vpi_bits; /* number of active VPI bits */
uint32_t vci_bits; /* number of active VCI bits */
uint32_t max_vpcs; /* maximum number of VPCs */
uint32_t max_vccs; /* maximum number of VCCs */
};
#define NGM_ATM_CONFIG_INFO \
{ \
{ "pcr", &ng_parse_uint32_type }, \
{ "vpi_bits", &ng_parse_uint32_type }, \
{ "vci_bits", &ng_parse_uint32_type }, \
{ "max_vpcs", &ng_parse_uint32_type }, \
{ "max_vccs", &ng_parse_uint32_type }, \
{ NULL } \
}
/*
* Information about an open VCC
* See net/if_atm.h. Keep in sync.
*/
#define NGM_ATM_TPARAM_INFO \
{ \
{ "pcr", &ng_parse_uint32_type }, \
{ "scr", &ng_parse_uint32_type }, \
{ "mbs", &ng_parse_uint32_type }, \
{ "mcr", &ng_parse_uint32_type }, \
{ "icr", &ng_parse_uint32_type }, \
{ "tbe", &ng_parse_uint32_type }, \
{ "nrm", &ng_parse_uint8_type }, \
{ "trm", &ng_parse_uint8_type }, \
{ "adtf", &ng_parse_uint16_type }, \
{ "rif", &ng_parse_uint8_type }, \
{ "rdf", &ng_parse_uint8_type }, \
{ "cdf", &ng_parse_uint8_type }, \
{ NULL } \
}
#define NGM_ATM_VCC_INFO \
{ \
{ "flags", &ng_parse_hint16_type }, \
{ "vpi", &ng_parse_uint16_type }, \
{ "vci", &ng_parse_uint16_type }, \
{ "rmtu", &ng_parse_uint16_type }, \
{ "tmtu", &ng_parse_uint16_type }, \
{ "aal", &ng_parse_uint8_type }, \
{ "traffic", &ng_parse_uint8_type }, \
{ "tparam", &ng_atm_tparam_type }, \
{ NULL } \
}
#define NGM_ATM_VCCARRAY_INFO \
{ \
&ng_atm_vcc_type, \
ng_atm_vccarray_getlen, \
NULL \
}
#define NGM_ATM_VCCTABLE_INFO \
{ \
{ "count", &ng_parse_uint32_type }, \
{ "vccs", &ng_atm_vccarray_type }, \
{ NULL } \
}
/*
* Structure to open a VCC.
*/
struct ngm_atm_cpcs_init {
char name[NG_HOOKSIZ];
uint32_t flags; /* flags. (if_atm.h) */
uint16_t vci; /* VCI to open */
uint16_t vpi; /* VPI to open */
uint16_t rmtu; /* Receive maximum CPCS size */
uint16_t tmtu; /* Transmit maximum CPCS size */
uint8_t aal; /* AAL type (if_atm.h) */
uint8_t traffic; /* traffic type (if_atm.h) */
uint32_t pcr; /* Peak cell rate */
uint32_t scr; /* VBR: Sustainable cell rate */
uint32_t mbs; /* VBR: Maximum burst rate */
uint32_t mcr; /* UBR+: Minimum cell rate */
uint32_t icr; /* ABR: Initial cell rate */
uint32_t tbe; /* ABR: Transmit buffer exposure */
uint8_t nrm; /* ABR: Nrm */
uint8_t trm; /* ABR: Trm */
uint16_t adtf; /* ABR: ADTF */
uint8_t rif; /* ABR: RIF */
uint8_t rdf; /* ABR: RDF */
uint8_t cdf; /* ABR: CDF */
};
#define NGM_ATM_CPCS_INIT_INFO \
{ \
{ "name", &ng_parse_hookbuf_type }, \
{ "flags", &ng_parse_hint32_type }, \
{ "vci", &ng_parse_uint16_type }, \
{ "vpi", &ng_parse_uint16_type }, \
{ "rmtu", &ng_parse_uint16_type }, \
{ "tmtu", &ng_parse_uint16_type }, \
{ "aal", &ng_parse_uint8_type }, \
{ "traffic", &ng_parse_uint8_type }, \
{ "pcr", &ng_parse_uint32_type }, \
{ "scr", &ng_parse_uint32_type }, \
{ "mbs", &ng_parse_uint32_type }, \
{ "mcr", &ng_parse_uint32_type }, \
{ "icr", &ng_parse_uint32_type }, \
{ "tbe", &ng_parse_uint32_type }, \
{ "nrm", &ng_parse_uint8_type }, \
{ "trm", &ng_parse_uint8_type }, \
{ "adtf", &ng_parse_uint16_type }, \
{ "rif", &ng_parse_uint8_type }, \
{ "rdf", &ng_parse_uint8_type }, \
{ "cdf", &ng_parse_uint8_type }, \
{ NULL } \
}
/*
* Structure to close a VCI without disconnecting the hook
*/
struct ngm_atm_cpcs_term {
char name[NG_HOOKSIZ];
};
#define NGM_ATM_CPCS_TERM_INFO \
{ \
{ "name", &ng_parse_hookbuf_type }, \
{ NULL } \
}
struct ngm_atm_stats {
uint64_t in_packets;
uint64_t in_errors;
uint64_t out_packets;
uint64_t out_errors;
};
#define NGM_ATM_STATS_INFO \
{ \
{ "in_packets", &ng_parse_uint64_type }, \
{ "in_errors", &ng_parse_uint64_type }, \
{ "out_packets", &ng_parse_uint64_type }, \
{ "out_errors", &ng_parse_uint64_type }, \
{ NULL } \
}
struct ngm_atm_if_change {
uint32_t node;
uint8_t carrier;
uint8_t running;
};
#define NGM_ATM_IF_CHANGE_INFO \
{ \
{ "node", &ng_parse_hint32_type }, \
{ "carrier", &ng_parse_uint8_type }, \
{ "running", &ng_parse_uint8_type }, \
{ NULL } \
}
struct ngm_atm_vcc_change {
uint32_t node;
uint16_t vci;
uint8_t vpi;
uint8_t state;
};
#define NGM_ATM_VCC_CHANGE_INFO \
{ \
{ "node", &ng_parse_hint32_type }, \
{ "vci", &ng_parse_uint16_type }, \
{ "vpi", &ng_parse_uint8_type }, \
{ "state", &ng_parse_uint8_type }, \
{ NULL } \
}
struct ngm_atm_acr_change {
uint32_t node;
uint16_t vci;
uint8_t vpi;
uint32_t acr;
};
#define NGM_ATM_ACR_CHANGE_INFO \
{ \
{ "node", &ng_parse_hint32_type }, \
{ "vci", &ng_parse_uint16_type }, \
{ "vpi", &ng_parse_uint8_type }, \
{ "acr", &ng_parse_uint32_type }, \
{ NULL } \
}
#endif /* _NETGRAPH_ATM_NG_ATM_H */

View File

@ -0,0 +1,171 @@
/*-
* Copyright (c) 2001-2002
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* All rights reserved.
* Copyright (c) 2003-2004
* Hartmut Brandt
* 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 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$
*/
/*
* Interface to ng_ccatm
*/
#ifndef _NETGRAPH_ATM_NG_CCATM_H_
#define _NETGRAPH_ATM_NG_CCATM_H_
#define NG_CCATM_NODE_TYPE "ccatm"
#define NGM_CCATM_COOKIE 984046139
enum {
NGM_CCATM_DUMP, /* dump internal status */
NGM_CCATM_STOP, /* stop all processing, close all */
NGM_CCATM_START, /* start processing */
NGM_CCATM_CLEAR, /* clear prefix/address table */
NGM_CCATM_GET_ADDRESSES, /* get list of all addresses */
NGM_CCATM_ADDRESS_REGISTERED, /* registration ok */
NGM_CCATM_ADDRESS_UNREGISTERED, /* unregistration ok */
NGM_CCATM_SET_PORT_PARAM, /* set port parameters */
NGM_CCATM_GET_PORT_PARAM, /* get port parameters */
NGM_CCATM_GET_PORTLIST, /* get list of port numbers */
NGM_CCATM_GETSTATE, /* get port status */
NGM_CCATM_SETLOG, /* set/get loglevel */
NGM_CCATM_RESET, /* reset everything */
NGM_CCATM_GET_EXSTAT, /* get extended status */
};
/*
* This must be synchronized with unistruct.h::struct uni_addr
*/
#define NGM_CCATM_ADDR_ARRAY_INFO \
{ \
&ng_parse_hint8_type, \
UNI_ADDR_MAXLEN \
}
#define NGM_CCATM_UNI_ADDR_INFO \
{ \
{ "type", &ng_parse_uint32_type }, \
{ "plan", &ng_parse_uint32_type }, \
{ "len", &ng_parse_uint32_type }, \
{ "addr", &ng_ccatm_addr_array_type }, \
{ NULL } \
}
/*
* Address request
*/
struct ngm_ccatm_addr_req {
uint32_t port;
struct uni_addr addr;
};
#define NGM_CCATM_ADDR_REQ_INFO \
{ \
{ "port", &ng_parse_uint32_type }, \
{ "addr", &ng_ccatm_uni_addr_type }, \
{ NULL }, \
}
/*
* Get current address list
*/
struct ngm_ccatm_get_addresses {
uint32_t count;
struct ngm_ccatm_addr_req addr[];
};
#define NGM_CCATM_ADDR_REQ_ARRAY_INFO \
{ \
&ng_ccatm_addr_req_type, \
ng_ccatm_addr_req_array_getlen \
}
#define NGM_CCATM_GET_ADDRESSES_INFO \
{ \
{ "count", &ng_parse_uint32_type }, \
{ "addr", &ng_ccatm_addr_req_array_type }, \
{ NULL } \
}
/*
* Port as parameter
*/
struct ngm_ccatm_port {
uint32_t port;
};
#define NGM_CCATM_PORT_INFO \
{ \
{ "port", &ng_parse_uint32_type }, \
{ NULL } \
}
/*
* Port parameters.
* This must be synchronized with atmapi.h::struct atm_port_info.
*/
#define NGM_CCATM_ESI_INFO \
{ \
&ng_parse_hint8_type, \
6 \
}
#define NGM_CCATM_ATM_PORT_INFO \
{ \
{ "port", &ng_parse_uint32_type }, \
{ "pcr", &ng_parse_uint32_type }, \
{ "max_vpi_bits", &ng_parse_uint32_type }, \
{ "max_vci_bits", &ng_parse_uint32_type }, \
{ "max_svpc_vpi", &ng_parse_uint32_type }, \
{ "max_svcc_vpi", &ng_parse_uint32_type }, \
{ "min_svcc_vci", &ng_parse_uint32_type }, \
{ "esi", &ng_ccatm_esi_type }, \
{ "num_addr", &ng_parse_uint32_type }, \
{ NULL } \
}
/*
* List of port numbers
*/
struct ngm_ccatm_portlist {
uint32_t nports;
uint32_t ports[];
};
#define NGM_CCATM_PORT_ARRAY_INFO \
{ \
&ng_parse_uint32_type, \
ng_ccatm_port_array_getlen \
}
#define NGM_CCATM_PORTLIST_INFO \
{ \
{ "nports", &ng_parse_uint32_type }, \
{ "ports", &ng_ccatm_port_array_type }, \
{ NULL } \
}
struct ccatm_op {
uint32_t op; /* request code */
};
#endif

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

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,119 @@
/*-
* 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.
*
* $FreeBSD$
*
* Netgraph module for UNI 4.0
*/
#ifndef _NETGRAPH_ATM_NG_UNI_H_
#define _NETGRAPH_ATM_NG_UNI_H_
#define NG_UNI_NODE_TYPE "uni"
#define NGM_UNI_COOKIE 981112392
enum {
NGM_UNI_GETDEBUG, /* get debug flags */
NGM_UNI_SETDEBUG, /* set debug flags */
NGM_UNI_GET_CONFIG, /* get configuration */
NGM_UNI_SET_CONFIG, /* set configuration */
NGM_UNI_ENABLE, /* enable processing */
NGM_UNI_DISABLE, /* free resources and disable */
NGM_UNI_GETSTATE, /* retrieve coord state */
};
struct ngm_uni_debug {
uint32_t level[UNI_MAXFACILITY];
};
#define NGM_UNI_DEBUGLEVEL_INFO { \
&ng_parse_uint32_type, \
UNI_MAXFACILITY \
}
#define NGM_UNI_DEBUG_INFO \
{ \
{ "level", &ng_uni_debuglevel_type }, \
{ NULL } \
}
#define NGM_UNI_CONFIG_INFO \
{ \
{ "proto", &ng_parse_uint32_type }, \
{ "popt", &ng_parse_uint32_type }, \
{ "option", &ng_parse_uint32_type }, \
{ "timer301", &ng_parse_uint32_type }, \
{ "timer303", &ng_parse_uint32_type }, \
{ "init303", &ng_parse_uint32_type }, \
{ "timer308", &ng_parse_uint32_type }, \
{ "init308", &ng_parse_uint32_type }, \
{ "timer309", &ng_parse_uint32_type }, \
{ "timer310", &ng_parse_uint32_type }, \
{ "timer313", &ng_parse_uint32_type }, \
{ "timer316", &ng_parse_uint32_type }, \
{ "init316", &ng_parse_uint32_type }, \
{ "timer317", &ng_parse_uint32_type }, \
{ "timer322", &ng_parse_uint32_type }, \
{ "init322", &ng_parse_uint32_type }, \
{ "timer397", &ng_parse_uint32_type }, \
{ "timer398", &ng_parse_uint32_type }, \
{ "timer399", &ng_parse_uint32_type }, \
{ NULL } \
}
struct ngm_uni_config_mask {
uint32_t mask;
uint32_t popt_mask;
uint32_t option_mask;
};
#define NGM_UNI_CONFIG_MASK_INFO \
{ \
{ "mask", &ng_parse_hint32_type }, \
{ "popt_mask", &ng_parse_hint32_type }, \
{ "option_mask", &ng_parse_hint32_type }, \
{ NULL } \
}
struct ngm_uni_set_config {
struct uni_config config;
struct ngm_uni_config_mask mask;
};
#define NGM_UNI_SET_CONFIG_INFO \
{ \
{ "config", &ng_uni_config_type }, \
{ "mask", &ng_uni_config_mask_type }, \
{ NULL } \
}
/*
* API message
*/
struct uni_arg {
uint32_t sig;
uint32_t cookie;
u_char data[];
};
#endif

View File

@ -0,0 +1,499 @@
/*-
* 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
*/
static MALLOC_DEFINE(M_UNIMSG, "unimsg", "uni message buffers");
static 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,
MTX_DEF);
}
/*
* 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) {
if (!(MCLGET(m0, M_NOWAIT)))
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) {
if (!(MCLGET(m, M_NOWAIT)))
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,605 @@
/*-
* 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 = {
.version = NG_ABI_VERSION,
.name = NG_SSCFU_NODE_TYPE,
.mod_event = ng_sscfu_mod_event,
.constructor = ng_sscfu_constructor,
.rcvmsg = ng_sscfu_rcvmsg,
.shutdown = ng_sscfu_shutdown,
.newhook = ng_sscfu_newhook,
.rcvdata = ng_sscfu_rcvupper,
.disconnect = ng_sscfu_disconnect,
.cmdlist = 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 == 0 ? "<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;
priv = malloc(sizeof(*priv), M_NG_SSCFU, M_WAITOK | M_ZERO);
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 error = 0;
switch (event) {
case MOD_LOAD:
break;
case MOD_UNLOAD:
break;
default:
error = EOPNOTSUPP;
break;
}
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,879 @@
/*-
* 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", __func__, __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 = {
.version = NG_ABI_VERSION,
.name = NG_SSCOP_NODE_TYPE,
.mod_event = ng_sscop_mod_event,
.constructor = ng_sscop_constructor,
.rcvmsg = ng_sscop_rcvmsg,
.shutdown = ng_sscop_shutdown,
.newhook = ng_sscop_newhook,
.rcvdata = ng_sscop_rcvlower,
.disconnect = ng_sscop_disconnect,
.cmdlist = 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;
p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO);
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 error = 0;
switch (event) {
case MOD_LOAD:
break;
case MOD_UNLOAD:
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}

View File

@ -0,0 +1,343 @@
/*-
* 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 sscop_timer_t;
#define TIMER_INIT(S, T) ng_callout_init(&(S)->t_##T)
#define TIMER_STOP(S,T) do { \
ng_uncallout(&(S)->t_##T, (S)->aarg); \
} while (0)
#define TIMER_RESTART(S, T) do { \
TIMER_STOP(S, T); \
ng_callout(&(S)->t_##T, (S)->aarg, NULL, \
hz * (S)->timer##T / 1000, T##_func, (S), 0); \
} while (0)
#define TIMER_ISACT(S, T) (callout_pending(&(S)->t_##T))
/*
* 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; \
\
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) { \
if (!(MCLGET(m, M_NOWAIT))){ \
m_free(m); \
m = NULL; \
} \
} \
} \
return (m); \
}
#ifdef SSCOP_DEBUG
#define ASSERT(X) KASSERT(X, (#X))
#else
#define ASSERT(X)
#endif

View File

@ -0,0 +1,927 @@
/*-
* 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.
*
* Netgraph module for ATM-Forum UNI 4.0 signalling
*/
#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 <machine/stdarg.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netnatm/unimsg.h>
#include <netnatm/msg/unistruct.h>
#include <netgraph/atm/ngatmbase.h>
#include <netnatm/saal/sscopdef.h>
#include <netnatm/saal/sscfudef.h>
#include <netgraph/atm/uni/ng_uni_cust.h>
#include <netnatm/sig/uni.h>
#include <netnatm/sig/unisig.h>
#include <netgraph/atm/ng_sscop.h>
#include <netgraph/atm/ng_sscfu.h>
#include <netgraph/atm/ng_uni.h>
static MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
static MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data");
MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
/*
* Private node data
*/
struct priv {
hook_p upper;
hook_p lower;
struct uni *uni;
int enabled;
};
/* UNI CONFIG MASK */
static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] =
NGM_UNI_CONFIG_MASK_INFO;
static const struct ng_parse_type ng_uni_config_mask_type = {
&ng_parse_struct_type,
ng_uni_config_mask_type_info
};
/* UNI_CONFIG */
static const struct ng_parse_struct_field ng_uni_config_type_info[] =
NGM_UNI_CONFIG_INFO;
static const struct ng_parse_type ng_uni_config_type = {
&ng_parse_struct_type,
ng_uni_config_type_info
};
/* SET CONFIG */
static const struct ng_parse_struct_field ng_uni_set_config_type_info[] =
NGM_UNI_SET_CONFIG_INFO;
static const struct ng_parse_type ng_uni_set_config_type = {
&ng_parse_struct_type,
ng_uni_set_config_type_info
};
/*
* Parse DEBUG
*/
static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info =
NGM_UNI_DEBUGLEVEL_INFO;
static const struct ng_parse_type ng_uni_debuglevel_type = {
&ng_parse_fixedarray_type,
&ng_uni_debuglevel_type_info
};
static const struct ng_parse_struct_field ng_uni_debug_type_info[] =
NGM_UNI_DEBUG_INFO;
static const struct ng_parse_type ng_uni_debug_type = {
&ng_parse_struct_type,
ng_uni_debug_type_info
};
/*
* Command list
*/
static const struct ng_cmdlist ng_uni_cmdlist[] = {
{
NGM_UNI_COOKIE,
NGM_UNI_GETDEBUG,
"getdebug",
NULL,
&ng_uni_debug_type
},
{
NGM_UNI_COOKIE,
NGM_UNI_SETDEBUG,
"setdebug",
&ng_uni_debug_type,
NULL
},
{
NGM_UNI_COOKIE,
NGM_UNI_GET_CONFIG,
"get_config",
NULL,
&ng_uni_config_type
},
{
NGM_UNI_COOKIE,
NGM_UNI_SET_CONFIG,
"set_config",
&ng_uni_set_config_type,
&ng_uni_config_mask_type,
},
{
NGM_UNI_COOKIE,
NGM_UNI_ENABLE,
"enable",
NULL,
NULL,
},
{
NGM_UNI_COOKIE,
NGM_UNI_DISABLE,
"disable",
NULL,
NULL,
},
{
NGM_UNI_COOKIE,
NGM_UNI_GETSTATE,
"getstate",
NULL,
&ng_parse_uint32_type
},
{ 0 }
};
/*
* Netgraph module data
*/
static ng_constructor_t ng_uni_constructor;
static ng_shutdown_t ng_uni_shutdown;
static ng_rcvmsg_t ng_uni_rcvmsg;
static ng_newhook_t ng_uni_newhook;
static ng_disconnect_t ng_uni_disconnect;
static ng_rcvdata_t ng_uni_rcvlower;
static ng_rcvdata_t ng_uni_rcvupper;
static int ng_uni_mod_event(module_t, int, void *);
static struct ng_type ng_uni_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_UNI_NODE_TYPE,
.mod_event = ng_uni_mod_event,
.constructor = ng_uni_constructor,
.rcvmsg = ng_uni_rcvmsg,
.shutdown = ng_uni_shutdown,
.newhook = ng_uni_newhook,
.rcvdata = ng_uni_rcvlower,
.disconnect = ng_uni_disconnect,
.cmdlist = ng_uni_cmdlist,
};
NETGRAPH_INIT(uni, &ng_uni_typestruct);
static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
struct uni_msg *);
static void uni_saal_output(struct uni *, void *, enum saal_sig,
struct uni_msg *);
static void uni_verbose(struct uni *, void *, u_int, const char *, ...)
__printflike(4, 5);
static void uni_do_status(struct uni *, void *, void *, const char *, ...)
__printflike(4, 5);
static const struct uni_funcs uni_funcs = {
uni_uni_output,
uni_saal_output,
uni_verbose,
uni_do_status
};
/************************************************************/
/*
* NODE MANAGEMENT
*/
static int
ng_uni_constructor(node_p node)
{
struct priv *priv;
priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
free(priv, M_NG_UNI);
return (ENOMEM);
}
NG_NODE_SET_PRIVATE(node, priv);
NG_NODE_FORCE_WRITER(node);
return (0);
}
static int
ng_uni_shutdown(node_p node)
{
struct priv *priv = NG_NODE_PRIVATE(node);
uni_destroy(priv->uni);
free(priv, M_NG_UNI);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
return (0);
}
/************************************************************/
/*
* CONTROL MESSAGES
*/
static void
uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
sbuf_printf(sbuf, fmt, ap);
va_end(ap);
}
static int
text_status(node_p node, struct priv *priv, char *buf, u_int len)
{
struct sbuf sbuf;
u_int f;
sbuf_new(&sbuf, buf, len, 0);
if (priv->lower != NULL)
sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
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->upper != NULL)
sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
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");
sbuf_printf(&sbuf, "debugging:");
for (f = 0; f < UNI_MAXFACILITY; f++)
if (uni_get_debug(priv->uni, f) != 0)
sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
uni_get_debug(priv->uni, f));
sbuf_printf(&sbuf, "\n");
if (priv->uni)
uni_status(priv->uni, &sbuf);
sbuf_finish(&sbuf);
return (sbuf_len(&sbuf));
}
static int
ng_uni_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;
u_int i;
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_UNI_COOKIE:
switch (msg->header.cmd) {
case NGM_UNI_SETDEBUG:
{
struct ngm_uni_debug *arg;
if (msg->header.arglen > sizeof(*arg)) {
error = EINVAL;
break;
}
arg = (struct ngm_uni_debug *)msg->data;
for (i = 0; i < UNI_MAXFACILITY; i++)
uni_set_debug(priv->uni, i, arg->level[i]);
break;
}
case NGM_UNI_GETDEBUG:
{
struct ngm_uni_debug *arg;
NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
if(resp == NULL) {
error = ENOMEM;
break;
}
arg = (struct ngm_uni_debug *)resp->data;
for (i = 0; i < UNI_MAXFACILITY; i++)
arg->level[i] = uni_get_debug(priv->uni, i);
break;
}
case NGM_UNI_GET_CONFIG:
{
struct uni_config *config;
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
config = (struct uni_config *)resp->data;
uni_get_config(priv->uni, config);
break;
}
case NGM_UNI_SET_CONFIG:
{
struct ngm_uni_set_config *arg;
struct ngm_uni_config_mask *mask;
if (msg->header.arglen != sizeof(*arg)) {
error = EINVAL;
break;
}
arg = (struct ngm_uni_set_config *)msg->data;
NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
mask = (struct ngm_uni_config_mask *)resp->data;
*mask = arg->mask;
uni_set_config(priv->uni, &arg->config,
&mask->mask, &mask->popt_mask, &mask->option_mask);
break;
}
case NGM_UNI_ENABLE:
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
if (priv->enabled) {
error = EISCONN;
break;
}
priv->enabled = 1;
break;
case NGM_UNI_DISABLE:
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
if (!priv->enabled) {
error = ENOTCONN;
break;
}
priv->enabled = 0;
uni_reset(priv->uni);
break;
case NGM_UNI_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 ? (uni_getcustate(priv->uni) + 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_uni_newhook(node_p node, hook_p hook, const char *name)
{
struct priv *priv = NG_NODE_PRIVATE(node);
if (strcmp(name, "lower") == 0) {
priv->lower = hook;
} else if(strcmp(name, "upper") == 0) {
priv->upper = hook;
NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
} else
return EINVAL;
return 0;
}
static int
ng_uni_disconnect(hook_p hook)
{
node_p node = NG_HOOK_NODE(hook);
struct priv *priv = NG_NODE_PRIVATE(node);
if(hook == priv->lower)
priv->lower = NULL;
else if(hook == priv->upper)
priv->upper = NULL;
else
printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
if (NG_NODE_NUMHOOKS(node) == 0) {
if (NG_NODE_IS_VALID(node))
ng_rmnode_self(node);
}
return (0);
}
/************************************************************/
/*
* DATA
*/
/*
* Receive signal from USER.
*
* Repackage the data into one large buffer.
*/
static int
ng_uni_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 uni_arg arg;
struct uni_msg *msg;
int error;
if (!priv->enabled) {
NG_FREE_ITEM(item);
return (ENOTCONN);
}
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
m_freem(m);
return (error);
}
m_freem(m);
if (uni_msg_len(msg) < sizeof(arg)) {
printf("%s: packet too short\n", __func__);
uni_msg_destroy(msg);
return (EINVAL);
}
bcopy(msg->b_rptr, &arg, sizeof(arg));
msg->b_rptr += sizeof(arg);
if (arg.sig >= UNIAPI_MAXSIG) {
printf("%s: bogus signal\n", __func__);
uni_msg_destroy(msg);
return (EINVAL);
}
uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
uni_work(priv->uni);
return (0);
}
/*
* Upper layer signal from UNI
*/
static void
uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
struct uni_msg *msg)
{
node_p node = (node_p)varg;
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct uni_arg arg;
int error;
if (priv->upper == NULL) {
if (msg != NULL)
uni_msg_destroy(msg);
return;
}
arg.sig = sig;
arg.cookie = cookie;
m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
if (msg != NULL)
uni_msg_destroy(msg);
if (m == NULL)
return;
NG_SEND_DATA_ONLY(error, priv->upper, m);
}
static void
dump_uni_msg(struct uni_msg *msg)
{
u_int pos;
for (pos = 0; pos < uni_msg_len(msg); pos++) {
if (pos % 16 == 0)
printf("%06o ", pos);
if (pos % 16 == 8)
printf(" ");
printf(" %02x", msg->b_rptr[pos]);
if (pos % 16 == 15)
printf("\n");
}
if (pos % 16 != 0)
printf("\n");
}
/*
* Dump a SAAL signal in either direction
*/
static void
dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
{
struct priv *priv = NG_NODE_PRIVATE(node);
printf("signal %s SAAL: ", to ? "to" : "from");
switch (sig) {
#define D(S) case S: printf("%s", #S); break
D(SAAL_ESTABLISH_request);
D(SAAL_ESTABLISH_indication);
D(SAAL_ESTABLISH_confirm);
D(SAAL_RELEASE_request);
D(SAAL_RELEASE_confirm);
D(SAAL_RELEASE_indication);
D(SAAL_DATA_request);
D(SAAL_DATA_indication);
D(SAAL_UDATA_request);
D(SAAL_UDATA_indication);
#undef D
default:
printf("sig=%d", sig); break;
}
if (msg != NULL) {
printf(" data=%zu\n", uni_msg_len(msg));
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
dump_uni_msg(msg);
} else
printf("\n");
}
/*
* Receive signal from SSCOP.
*
* If this is a data signal, repackage the data into one large buffer.
* UNI shouldn't be the bottleneck in a system and this greatly simplifies
* parsing in UNI.
*/
static int
ng_uni_rcvlower(hook_p hook __unused, item_p item)
{
node_p node = NG_HOOK_NODE(hook);
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct sscfu_arg arg;
struct uni_msg *msg;
int error;
if (!priv->enabled) {
NG_FREE_ITEM(item);
return (ENOTCONN);
}
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
m_freem(m);
return (error);
}
m_freem(m);
if (uni_msg_len(msg) < sizeof(arg)) {
uni_msg_destroy(msg);
printf("%s: packet too short\n", __func__);
return (EINVAL);
}
bcopy(msg->b_rptr, &arg, sizeof(arg));
msg->b_rptr += sizeof(arg);
if (arg.sig > SAAL_UDATA_indication) {
uni_msg_destroy(msg);
printf("%s: bogus signal\n", __func__);
return (EINVAL);
}
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
dump_saal_signal(node, arg.sig, msg, 0);
uni_saal_input(priv->uni, arg.sig, msg);
uni_work(priv->uni);
return (0);
}
/*
* Send signal to sscop.
* Pack the message into an mbuf chain.
*/
static void
uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
{
node_p node = (node_p)varg;
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct sscfu_arg arg;
int error;
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
dump_saal_signal(node, sig, msg, 1);
if (priv->lower == NULL) {
if (msg != NULL)
uni_msg_destroy(msg);
return;
}
arg.sig = sig;
m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
if (msg != NULL)
uni_msg_destroy(msg);
if (m == NULL)
return;
NG_SEND_DATA_ONLY(error, priv->lower, m);
}
static void
uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
{
va_list ap;
static char *facnames[] = {
#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
UNI_DEBUG_FACILITIES
#undef UNI_DEBUG_DEFINE
};
printf("%s: ", facnames[fac]);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
}
/************************************************************/
/*
* Memory debugging
*/
struct unimem_debug {
const char *file;
u_int lno;
LIST_ENTRY(unimem_debug) link;
char data[0];
};
LIST_HEAD(unimem_debug_list, unimem_debug);
static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
LIST_HEAD_INITIALIZER(nguni_freemem[0]),
LIST_HEAD_INITIALIZER(nguni_freemem[1]),
LIST_HEAD_INITIALIZER(nguni_freemem[2]),
LIST_HEAD_INITIALIZER(nguni_freemem[3]),
LIST_HEAD_INITIALIZER(nguni_freemem[4]),
};
static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
};
static struct mtx nguni_unilist_mtx;
static const char *unimem_names[UNIMEM_TYPES] = {
"instance",
"all",
"signal",
"call",
"party"
};
static void
uni_init(void)
{
mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
MTX_DEF);
}
static void
uni_fini(void)
{
u_int type;
struct unimem_debug *h;
for (type = 0; type < UNIMEM_TYPES; type++) {
while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
LIST_REMOVE(h, link);
free(h, M_UNI);
}
while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
LIST_REMOVE(h, link);
printf("ng_uni: %s in use: %p (%s,%u)\n",
unimem_names[type], (caddr_t)h->data,
h->file, h->lno);
free(h, M_UNI);
}
}
mtx_destroy(&nguni_unilist_mtx);
}
/*
* Allocate a chunk of memory from a given type.
*/
void *
ng_uni_malloc(enum unimem type, const char *file, u_int lno)
{
struct unimem_debug *d;
size_t full;
/*
* Try to allocate
*/
mtx_lock(&nguni_unilist_mtx);
if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
LIST_REMOVE(d, link);
mtx_unlock(&nguni_unilist_mtx);
if (d == NULL) {
/*
* allocate
*/
full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
return (NULL);
} else {
bzero(d->data, unimem_sizes[type]);
}
d->file = file;
d->lno = lno;
mtx_lock(&nguni_unilist_mtx);
LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
mtx_unlock(&nguni_unilist_mtx);
return (d->data);
}
void
ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
{
struct unimem_debug *d, *h;
d = (struct unimem_debug *)
((char *)ptr - offsetof(struct unimem_debug, data));
mtx_lock(&nguni_unilist_mtx);
LIST_FOREACH(h, &nguni_usedmem[type], link)
if (d == h)
break;
if (h != NULL) {
LIST_REMOVE(d, link);
LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
} else {
/*
* Not on used list - try free list.
*/
LIST_FOREACH(h, &nguni_freemem[type], link)
if (d == h)
break;
if (h == NULL)
printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
file, lno, ptr, unimem_names[type]);
else
printf("ng_uni: %s,%u: %p(%s) was already destroyed "
"in %s,%u\n",
file, lno, ptr, unimem_names[type],
h->file, h->lno);
}
mtx_unlock(&nguni_unilist_mtx);
}
/************************************************************/
/*
* INITIALISATION
*/
/*
* Loading and unloading of node type
*/
static int
ng_uni_mod_event(module_t mod, int event, void *data)
{
int error = 0;
switch(event) {
case MOD_LOAD:
uni_init();
break;
case MOD_UNLOAD:
uni_fini();
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}

View File

@ -0,0 +1,148 @@
/*-
* 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.
*
* Customisation of signalling source to the NG environment.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/atm/ngatmbase.h>
#define ASSERT(E, M) KASSERT(E,M)
/*
* Memory
*/
enum unimem {
UNIMEM_INS = 0,
UNIMEM_ALL,
UNIMEM_SIG,
UNIMEM_CALL,
UNIMEM_PARTY,
};
#define UNIMEM_TYPES 5
void *ng_uni_malloc(enum unimem, const char *, u_int);
void ng_uni_free(enum unimem, void *, const char *, u_int);
#define INS_ALLOC() ng_uni_malloc(UNIMEM_INS, __FILE__, __LINE__)
#define INS_FREE(P) ng_uni_free(UNIMEM_INS, P, __FILE__, __LINE__)
#define UNI_ALLOC() ng_uni_malloc(UNIMEM_ALL, __FILE__, __LINE__)
#define UNI_FREE(P) ng_uni_free(UNIMEM_ALL, P, __FILE__, __LINE__)
#define SIG_ALLOC() ng_uni_malloc(UNIMEM_SIG, __FILE__, __LINE__)
#define SIG_FREE(P) ng_uni_free(UNIMEM_SIG, P, __FILE__, __LINE__)
#define CALL_ALLOC() ng_uni_malloc(UNIMEM_CALL, __FILE__, __LINE__)
#define CALL_FREE(P) ng_uni_free(UNIMEM_CALL, P, __FILE__, __LINE__)
#define PARTY_ALLOC() ng_uni_malloc(UNIMEM_PARTY, __FILE__, __LINE__)
#define PARTY_FREE(P) ng_uni_free(UNIMEM_PARTY, P, __FILE__, __LINE__)
/*
* Timers
*/
struct uni_timer {
struct callout c;
};
#define _TIMER_INIT(X,T) ng_callout_init(&(X)->T.c)
#define _TIMER_DESTROY(UNI,FIELD) _TIMER_STOP(UNI,FIELD)
#define _TIMER_STOP(UNI,FIELD) do { \
ng_uncallout(&FIELD.c, (UNI)->arg); \
} while (0)
#define TIMER_ISACT(UNI,T) (callout_active(&(UNI)->T.c) || \
callout_pending(&(UNI)->T.c))
#define _TIMER_START(UNI,ARG,FIELD,DUE,FUNC) do { \
_TIMER_STOP(UNI, FIELD); \
ng_callout(&FIELD.c, (UNI)->arg, NULL, \
hz * (DUE) / 1000, FUNC, (ARG), 0); \
} while (0)
#define TIMER_FUNC_UNI(T,F) \
static void F(struct uni *); \
static void \
_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \
{ \
struct uni *uni = (struct uni *)arg1; \
\
(F)(uni); \
uni_work(uni); \
}
/*
* Be careful: call may be invalid after the call to F
*/
#define TIMER_FUNC_CALL(T,F) \
static void F(struct call *); \
static void \
_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \
{ \
struct call *call = (struct call *)arg1; \
struct uni *uni = call->uni; \
\
(F)(call); \
uni_work(uni); \
}
/*
* Be careful: call/party may be invalid after the call to F
*/
#define TIMER_FUNC_PARTY(T,F) \
static void F(struct party *); \
static void \
_##T##_func(node_p node, hook_p hook, void *arg1, int arg2) \
{ \
struct party *party = (struct party *)arg1; \
struct uni *uni = party->call->uni; \
\
(F)(party); \
uni_work(uni); \
}
extern size_t unimem_sizes[UNIMEM_TYPES];
#define UNICORE \
size_t unimem_sizes[UNIMEM_TYPES] = { \
[UNIMEM_INS] = sizeof(struct uni), \
[UNIMEM_ALL] = sizeof(struct uni_all), \
[UNIMEM_SIG] = sizeof(struct sig), \
[UNIMEM_CALL] = sizeof(struct call), \
[UNIMEM_PARTY] = sizeof(struct party) \
};

View File

@ -0,0 +1,291 @@
/*
* bluetooth.c
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_bluetooth.c,v 1.3 2003/04/26 22:37:31 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
/*
* Bluetooth stack sysctl globals
*/
static u_int32_t bluetooth_hci_command_timeout_value = 5; /* sec */
static u_int32_t bluetooth_hci_connect_timeout_value = 60; /* sec */
static u_int32_t bluetooth_hci_max_neighbor_age_value = 600; /* sec */
static u_int32_t bluetooth_l2cap_rtx_timeout_value = 60; /* sec */
static u_int32_t bluetooth_l2cap_ertx_timeout_value = 300; /* sec */
static u_int32_t bluetooth_sco_rtx_timeout_value = 60; /* sec */
/*
* Define sysctl tree that shared by other parts of Bluetooth stack
*/
SYSCTL_NODE(_net, OID_AUTO, bluetooth, CTLFLAG_RW, 0, "Bluetooth family");
SYSCTL_INT(_net_bluetooth, OID_AUTO, version,
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, NG_BLUETOOTH_VERSION, "Version of the stack");
/*
* HCI
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, hci, CTLFLAG_RW,
0, "Bluetooth HCI family");
static int
bluetooth_set_hci_command_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_hci_command_timeout_value;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error == 0 && req->newptr != NULL) {
if (value > 0)
bluetooth_hci_command_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_hci_command_timeout_value */
SYSCTL_PROC(_net_bluetooth_hci, OID_AUTO, command_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_hci_command_timeout_value, 5,
bluetooth_set_hci_command_timeout_value,
"I", "HCI command timeout (sec)");
static int
bluetooth_set_hci_connect_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_hci_connect_timeout_value;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error == 0 && req->newptr != NULL) {
if (0 < value && value <= bluetooth_l2cap_rtx_timeout_value)
bluetooth_hci_connect_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_hci_connect_timeout_value */
SYSCTL_PROC(_net_bluetooth_hci, OID_AUTO, connection_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_hci_connect_timeout_value, 60,
bluetooth_set_hci_connect_timeout_value,
"I", "HCI connect timeout (sec)");
SYSCTL_UINT(_net_bluetooth_hci, OID_AUTO, max_neighbor_age, CTLFLAG_RW,
&bluetooth_hci_max_neighbor_age_value, 600,
"Maximal HCI neighbor cache entry age (sec)");
/*
* L2CAP
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, l2cap, CTLFLAG_RW,
0, "Bluetooth L2CAP family");
static int
bluetooth_set_l2cap_rtx_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_l2cap_rtx_timeout_value;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error == 0 && req->newptr != NULL) {
if (bluetooth_hci_connect_timeout_value <= value &&
value <= bluetooth_l2cap_ertx_timeout_value)
bluetooth_l2cap_rtx_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_l2cap_rtx_timeout_value */
SYSCTL_PROC(_net_bluetooth_l2cap, OID_AUTO, rtx_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_l2cap_rtx_timeout_value, 60,
bluetooth_set_l2cap_rtx_timeout_value,
"I", "L2CAP RTX timeout (sec)");
static int
bluetooth_set_l2cap_ertx_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_l2cap_ertx_timeout_value;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error == 0 && req->newptr != NULL) {
if (value >= bluetooth_l2cap_rtx_timeout_value)
bluetooth_l2cap_ertx_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_l2cap_ertx_timeout_value */
SYSCTL_PROC(_net_bluetooth_l2cap, OID_AUTO, ertx_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_l2cap_ertx_timeout_value, 300,
bluetooth_set_l2cap_ertx_timeout_value,
"I", "L2CAP ERTX timeout (sec)");
/*
* Return various sysctl values
*/
u_int32_t
bluetooth_hci_command_timeout(void)
{
return (bluetooth_hci_command_timeout_value * hz);
} /* bluetooth_hci_command_timeout */
u_int32_t
bluetooth_hci_connect_timeout(void)
{
return (bluetooth_hci_connect_timeout_value * hz);
} /* bluetooth_hci_connect_timeout */
u_int32_t
bluetooth_hci_max_neighbor_age(void)
{
return (bluetooth_hci_max_neighbor_age_value);
} /* bluetooth_hci_max_neighbor_age */
u_int32_t
bluetooth_l2cap_rtx_timeout(void)
{
return (bluetooth_l2cap_rtx_timeout_value * hz);
} /* bluetooth_l2cap_rtx_timeout */
u_int32_t
bluetooth_l2cap_ertx_timeout(void)
{
return (bluetooth_l2cap_ertx_timeout_value * hz);
} /* bluetooth_l2cap_ertx_timeout */
u_int32_t
bluetooth_sco_rtx_timeout(void)
{
return (bluetooth_sco_rtx_timeout_value * hz);
} /* bluetooth_sco_rtx_timeout */
/*
* RFCOMM
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, rfcomm, CTLFLAG_RW,
0, "Bluetooth RFCOMM family");
/*
* SCO
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, sco, CTLFLAG_RW,
0, "Bluetooth SCO family");
static int
bluetooth_set_sco_rtx_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_sco_rtx_timeout_value;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error == 0 && req->newptr != NULL) {
if (bluetooth_hci_connect_timeout_value <= value)
bluetooth_sco_rtx_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_sco_rtx_timeout_value */
SYSCTL_PROC(_net_bluetooth_sco, OID_AUTO, rtx_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_sco_rtx_timeout_value, 60,
bluetooth_set_sco_rtx_timeout_value,
"I", "SCO RTX timeout (sec)");
/*
* Handle loading and unloading for this code.
*/
static int
bluetooth_modevent(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
break;
case MOD_UNLOAD:
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
} /* bluetooth_modevent */
/*
* Module
*/
static moduledata_t bluetooth_mod = {
"ng_bluetooth",
bluetooth_modevent,
NULL
};
DECLARE_MODULE(ng_bluetooth, bluetooth_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(ng_bluetooth, NG_BLUETOOTH_VERSION);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
/*
* ng_bt3c_var.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_bt3c_var.h,v 1.1 2002/11/24 19:46:54 max Exp $
* $FreeBSD$
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
* Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
* and disassembled w2k driver.
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
*/
#ifndef _NG_BT3C_VAR_H_
#define _NG_BT3C_VAR_H_
/* Debug printf's */
#define NG_BT3C_ALERT if (sc->debug >= NG_BT3C_ALERT_LEVEL) device_printf
#define NG_BT3C_ERR if (sc->debug >= NG_BT3C_ERR_LEVEL) device_printf
#define NG_BT3C_WARN if (sc->debug >= NG_BT3C_WARN_LEVEL) device_printf
#define NG_BT3C_INFO if (sc->debug >= NG_BT3C_INFO_LEVEL) device_printf
/* Device registers */
#define BT3C_DATA_L 0x00 /* data low byte */
#define BT3C_DATA_H 0x01 /* high byte */
#define BT3C_ADDR_L 0x02 /* address low byte */
#define BT3C_ADDR_H 0x03 /* high byte */
#define BT3C_CONTROL 0x04 /* control */
#define BT3C_FIFO_SIZE 256
/* Device softc structure */
struct bt3c_softc {
/* Device specific */
device_t dev; /* pointer back to device */
int iobase_rid; /* iobase RID */
struct resource *iobase; /* iobase */
bus_space_tag_t iot; /* I/O tag */
bus_space_handle_t ioh; /* I/O handle */
int irq_rid; /* irq RID */
struct resource *irq; /* irq */
void *irq_cookie; /* irq cookie */
/* Netgraph specific */
node_p node; /* pointer back to node */
hook_p hook; /* hook */
ng_bt3c_node_debug_ep debug; /* debug level */
u_int16_t flags; /* device flags */
#define BT3C_ANTENNA_OUT (1 << 0) /* antena is out */
#define BT3C_XMIT (1 << 1) /* xmit in progress */
ng_bt3c_node_state_ep state; /* receiving state */
ng_bt3c_node_stat_ep stat; /* statistic */
#define NG_BT3C_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_BT3C_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_BT3C_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_BT3C_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_BT3C_STAT_OERROR(s) (s).oerrors ++
#define NG_BT3C_STAT_IERROR(s) (s).ierrors ++
#define NG_BT3C_STAT_RESET(s) bzero(&(s), sizeof((s)))
u_int32_t status; /* from ISR */
void *ith; /* ithread handler */
struct mbuf *m; /* current frame */
u_int32_t want; /* # of chars we want */
struct ifqueue inq; /* queue of incoming mbuf's */
struct ifqueue outq; /* queue of outgoing mbuf's */
#define BT3C_DEFAULTQLEN 12 /* XXX max. size of out queue */
};
typedef struct bt3c_softc bt3c_softc_t;
typedef struct bt3c_softc * bt3c_softc_p;
#endif /* ndef _NG_BT3C_VAR_H_ */

View File

@ -0,0 +1,13 @@
$Id: TODO,v 1.2 2004/08/23 18:08:15 max Exp $
$FreeBSD$
FIXME/TODO list
This is a list of open issues for H4 node
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, but
i still use splXXX to lock tty level. this is wrong and should be
fixed!

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
/*
* ng_h4_prse.h
*/
/*-
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_h4_prse.h,v 1.4 2005/10/31 17:57:43 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the H4 node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_H4_PRSE_H_
#define _NETGRAPH_H4_PRSE_H_
/*
* H4 node command list
*/
/* Stat info */
static const struct ng_parse_struct_field ng_h4_stat_type_fields[] =
{
{ "pckts_recv", &ng_parse_uint32_type, },
{ "bytes_recv", &ng_parse_uint32_type, },
{ "pckts_sent", &ng_parse_uint32_type, },
{ "bytes_sent", &ng_parse_uint32_type, },
{ "oerrors", &ng_parse_uint32_type, },
{ "ierrors", &ng_parse_uint32_type, },
{ NULL, }
};
static const struct ng_parse_type ng_h4_stat_type = {
&ng_parse_struct_type,
&ng_h4_stat_type_fields
};
static const struct ng_cmdlist ng_h4_cmdlist[] = {
{
NGM_H4_COOKIE,
NGM_H4_NODE_RESET,
"reset",
NULL,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_STATE,
"get_state",
NULL,
&ng_parse_uint16_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_QLEN,
"get_qlen",
NULL,
&ng_parse_int32_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_SET_QLEN,
"set_qlen",
&ng_parse_int32_type,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_STAT,
"get_stat",
NULL,
&ng_h4_stat_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_RESET_STAT,
"reset_stat",
NULL,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_H4_PRSE_H_ */

View File

@ -0,0 +1,103 @@
/*
* ng_h4_var.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_h4_var.h,v 1.5 2005/10/31 17:57:43 max Exp $
* $FreeBSD$
*
* Based on:
* ---------
*
* FreeBSD: src/sys/netgraph/ng_tty.h
* Author: Archie Cobbs <archie@freebsd.org>
*/
#ifndef _NETGRAPH_H4_VAR_H_
#define _NETGRAPH_H4_VAR_H_
/*
* Malloc declaration
*/
#ifndef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_H4);
#else
#define M_NETGRAPH_H4 M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/*
* Debug
*/
#define NG_H4_ALERT if (sc->debug >= NG_H4_ALERT_LEVEL) printf
#define NG_H4_ERR if (sc->debug >= NG_H4_ERR_LEVEL) printf
#define NG_H4_WARN if (sc->debug >= NG_H4_WARN_LEVEL) printf
#define NG_H4_INFO if (sc->debug >= NG_H4_INFO_LEVEL) printf
#define NG_H4_HIWATER 256 /* High water mark on output */
/*
* Per-node private info
*/
typedef struct ng_h4_info {
struct tty *tp; /* Terminal device */
node_p node; /* Netgraph node */
ng_h4_node_debug_ep debug; /* Debug level */
ng_h4_node_state_ep state; /* State */
ng_h4_node_stat_ep stat;
#define NG_H4_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_H4_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_H4_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_H4_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_H4_STAT_OERROR(s) (s).oerrors ++
#define NG_H4_STAT_IERROR(s) (s).ierrors ++
#define NG_H4_STAT_RESET(s) bzero(&(s), sizeof((s)))
struct ifqueue outq; /* Queue of outgoing mbuf's */
#define NG_H4_DEFAULTQLEN 12 /* XXX max number of mbuf's in outq */
#define NG_H4_LOCK(sc) IF_LOCK(&sc->outq)
#define NG_H4_UNLOCK(sc) IF_UNLOCK(&sc->outq)
#define NG_H4_IBUF_SIZE 1024 /* XXX must be big enough to hold full
frame */
u_int8_t ibuf[NG_H4_IBUF_SIZE]; /* Incoming data */
u_int32_t got; /* Number of bytes we have received */
u_int32_t want; /* Number of bytes we want to receive */
hook_p hook; /* Upstream hook */
struct callout timo; /* See man timeout(9) */
u_int8_t dying; /* are we dying? */
} ng_h4_info_t;
typedef ng_h4_info_t * ng_h4_info_p;
#endif /* _NETGRAPH_H4_VAR_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,131 @@
/*
* ng_ubt_var.h
*/
/*-
* Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_ubt_var.h,v 1.2 2003/03/22 23:44:36 max Exp $
* $FreeBSD$
*/
#ifndef _NG_UBT_VAR_H_
#define _NG_UBT_VAR_H_ 1
/* Debug printf's */
#define UBT_DEBUG(level, sc, fmt, ...) \
do { \
if ((sc)->sc_debug >= (level)) \
device_printf((sc)->sc_dev, "%s:%d: " fmt, \
__FUNCTION__, __LINE__,## __VA_ARGS__); \
} while (0)
#define UBT_ALERT(...) UBT_DEBUG(NG_UBT_ALERT_LEVEL, __VA_ARGS__)
#define UBT_ERR(...) UBT_DEBUG(NG_UBT_ERR_LEVEL, __VA_ARGS__)
#define UBT_WARN(...) UBT_DEBUG(NG_UBT_WARN_LEVEL, __VA_ARGS__)
#define UBT_INFO(...) UBT_DEBUG(NG_UBT_INFO_LEVEL, __VA_ARGS__)
#define UBT_NG_LOCK(sc) mtx_lock(&(sc)->sc_ng_mtx)
#define UBT_NG_UNLOCK(sc) mtx_unlock(&(sc)->sc_ng_mtx)
/* Bluetooth USB control request type */
#define UBT_HCI_REQUEST 0x20
#define UBT_DEFAULT_QLEN 64
#define UBT_ISOC_NFRAMES 32 /* should be factor of 8 */
/* Bluetooth USB defines */
enum {
/* Interface #0 transfers */
UBT_IF_0_BULK_DT_WR = 0,
UBT_IF_0_BULK_DT_RD,
UBT_IF_0_INTR_DT_RD,
UBT_IF_0_CTRL_DT_WR,
/* Interface #1 transfers */
UBT_IF_1_ISOC_DT_RD1,
UBT_IF_1_ISOC_DT_RD2,
UBT_IF_1_ISOC_DT_WR1,
UBT_IF_1_ISOC_DT_WR2,
UBT_N_TRANSFER, /* total number of transfers */
};
/* USB device softc structure */
struct ubt_softc {
device_t sc_dev; /* for debug printf */
/* State */
ng_ubt_node_debug_ep sc_debug; /* debug level */
ng_ubt_node_stat_ep sc_stat; /* statistic */
#define UBT_STAT_PCKTS_SENT(sc) (sc)->sc_stat.pckts_sent ++
#define UBT_STAT_BYTES_SENT(sc, n) (sc)->sc_stat.bytes_sent += (n)
#define UBT_STAT_PCKTS_RECV(sc) (sc)->sc_stat.pckts_recv ++
#define UBT_STAT_BYTES_RECV(sc, n) (sc)->sc_stat.bytes_recv += (n)
#define UBT_STAT_OERROR(sc) (sc)->sc_stat.oerrors ++
#define UBT_STAT_IERROR(sc) (sc)->sc_stat.ierrors ++
#define UBT_STAT_RESET(sc) bzero(&(sc)->sc_stat, sizeof((sc)->sc_stat))
/* USB device specific */
struct mtx sc_if_mtx; /* interfaces lock */
struct usb_xfer *sc_xfer[UBT_N_TRANSFER];
struct mtx sc_ng_mtx; /* lock for shared NG data */
/* HCI commands */
struct ng_bt_mbufq sc_cmdq; /* HCI command queue */
#define UBT_CTRL_BUFFER_SIZE (sizeof(struct usb_device_request) + \
sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE)
#define UBT_INTR_BUFFER_SIZE (MCLBYTES-1) /* reserve 1 byte for ID-tag */
/* ACL data */
struct ng_bt_mbufq sc_aclq; /* ACL data queue */
#define UBT_BULK_READ_BUFFER_SIZE (MCLBYTES-1) /* reserve 1 byte for ID-tag */
#define UBT_BULK_WRITE_BUFFER_SIZE (MCLBYTES)
/* SCO data */
struct ng_bt_mbufq sc_scoq; /* SCO data queue */
struct mbuf *sc_isoc_in_buffer; /* SCO reassembly buffer */
/* Netgraph specific */
node_p sc_node; /* pointer back to node */
hook_p sc_hook; /* upstream hook */
/* Glue */
int sc_task_flags; /* task flags */
#define UBT_FLAG_T_PENDING (1 << 0) /* task pending */
#define UBT_FLAG_T_STOP_ALL (1 << 1) /* stop all xfers */
#define UBT_FLAG_T_START_ALL (1 << 2) /* start all read and isoc
write xfers */
#define UBT_FLAG_T_START_CTRL (1 << 3) /* start control xfer (write) */
#define UBT_FLAG_T_START_BULK (1 << 4) /* start bulk xfer (write) */
struct task sc_task;
};
typedef struct ubt_softc ubt_softc_t;
typedef struct ubt_softc * ubt_softc_p;
#endif /* ndef _NG_UBT_VAR_H_ */

View File

@ -0,0 +1,449 @@
/*
* ubtbcmfw.c
*/
/*-
* Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $
* $FreeBSD$
*/
#include <sys/stdint.h>
#include <sys/stddef.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include "usbdevs.h"
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usb_ioctl.h>
#define USB_DEBUG_VAR usb_debug
#include <dev/usb/usb_debug.h>
#include <dev/usb/usb_dev.h>
/*
* Download firmware to BCM2033.
*/
#define UBTBCMFW_CONFIG_NO 1 /* Config number */
#define UBTBCMFW_IFACE_IDX 0 /* Control interface */
#define UBTBCMFW_BSIZE 1024
#define UBTBCMFW_IFQ_MAXLEN 2
enum {
UBTBCMFW_BULK_DT_WR = 0,
UBTBCMFW_INTR_DT_RD,
UBTBCMFW_N_TRANSFER,
};
struct ubtbcmfw_softc {
struct usb_device *sc_udev;
struct mtx sc_mtx;
struct usb_xfer *sc_xfer[UBTBCMFW_N_TRANSFER];
struct usb_fifo_sc sc_fifo;
};
/*
* Prototypes
*/
static device_probe_t ubtbcmfw_probe;
static device_attach_t ubtbcmfw_attach;
static device_detach_t ubtbcmfw_detach;
static usb_callback_t ubtbcmfw_write_callback;
static usb_callback_t ubtbcmfw_read_callback;
static usb_fifo_close_t ubtbcmfw_close;
static usb_fifo_cmd_t ubtbcmfw_start_read;
static usb_fifo_cmd_t ubtbcmfw_start_write;
static usb_fifo_cmd_t ubtbcmfw_stop_read;
static usb_fifo_cmd_t ubtbcmfw_stop_write;
static usb_fifo_ioctl_t ubtbcmfw_ioctl;
static usb_fifo_open_t ubtbcmfw_open;
static struct usb_fifo_methods ubtbcmfw_fifo_methods =
{
.f_close = &ubtbcmfw_close,
.f_ioctl = &ubtbcmfw_ioctl,
.f_open = &ubtbcmfw_open,
.f_start_read = &ubtbcmfw_start_read,
.f_start_write = &ubtbcmfw_start_write,
.f_stop_read = &ubtbcmfw_stop_read,
.f_stop_write = &ubtbcmfw_stop_write,
.basename[0] = "ubtbcmfw",
.basename[1] = "ubtbcmfw",
.basename[2] = "ubtbcmfw",
.postfix[0] = "",
.postfix[1] = ".1",
.postfix[2] = ".2",
};
/*
* Device's config structure
*/
static const struct usb_config ubtbcmfw_config[UBTBCMFW_N_TRANSFER] =
{
[UBTBCMFW_BULK_DT_WR] = {
.type = UE_BULK,
.endpoint = 0x02, /* fixed */
.direction = UE_DIR_OUT,
.if_index = UBTBCMFW_IFACE_IDX,
.bufsize = UBTBCMFW_BSIZE,
.flags = { .pipe_bof = 1, .force_short_xfer = 1,
.proxy_buffer = 1, },
.callback = &ubtbcmfw_write_callback,
},
[UBTBCMFW_INTR_DT_RD] = {
.type = UE_INTERRUPT,
.endpoint = 0x01, /* fixed */
.direction = UE_DIR_IN,
.if_index = UBTBCMFW_IFACE_IDX,
.bufsize = UBTBCMFW_BSIZE,
.flags = { .pipe_bof = 1, .short_xfer_ok = 1,
.proxy_buffer = 1, },
.callback = &ubtbcmfw_read_callback,
},
};
/*
* Module
*/
static devclass_t ubtbcmfw_devclass;
static device_method_t ubtbcmfw_methods[] =
{
DEVMETHOD(device_probe, ubtbcmfw_probe),
DEVMETHOD(device_attach, ubtbcmfw_attach),
DEVMETHOD(device_detach, ubtbcmfw_detach),
{0, 0}
};
static driver_t ubtbcmfw_driver =
{
.name = "ubtbcmfw",
.methods = ubtbcmfw_methods,
.size = sizeof(struct ubtbcmfw_softc),
};
static const STRUCT_USB_HOST_ID ubtbcmfw_devs[] = {
/* Broadcom BCM2033 devices only */
{ USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) },
};
DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0);
MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1);
USB_PNP_HOST_INFO(ubtbcmfw_devs);
/*
* Probe for a USB Bluetooth device
*/
static int
ubtbcmfw_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
if (uaa->info.bIfaceIndex != 0)
return (ENXIO);
return (usbd_lookup_id_by_uaa(ubtbcmfw_devs, sizeof(ubtbcmfw_devs), uaa));
} /* ubtbcmfw_probe */
/*
* Attach the device
*/
static int
ubtbcmfw_attach(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
struct ubtbcmfw_softc *sc = device_get_softc(dev);
uint8_t iface_index;
int error;
sc->sc_udev = uaa->device;
device_set_usb_desc(dev);
mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE);
iface_index = UBTBCMFW_IFACE_IDX;
error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
ubtbcmfw_config, UBTBCMFW_N_TRANSFER,
sc, &sc->sc_mtx);
if (error != 0) {
device_printf(dev, "allocating USB transfers failed. %s\n",
usbd_errstr(error));
goto detach;
}
error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
&ubtbcmfw_fifo_methods, &sc->sc_fifo,
device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex,
UID_ROOT, GID_OPERATOR, 0644);
if (error != 0) {
device_printf(dev, "could not attach fifo. %s\n",
usbd_errstr(error));
goto detach;
}
return (0); /* success */
detach:
ubtbcmfw_detach(dev);
return (ENXIO); /* failure */
} /* ubtbcmfw_attach */
/*
* Detach the device
*/
static int
ubtbcmfw_detach(device_t dev)
{
struct ubtbcmfw_softc *sc = device_get_softc(dev);
usb_fifo_detach(&sc->sc_fifo);
usbd_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER);
mtx_destroy(&sc->sc_mtx);
return (0);
} /* ubtbcmfw_detach */
/*
* USB write callback
*/
static void
ubtbcmfw_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct ubtbcmfw_softc *sc = usbd_xfer_softc(xfer);
struct usb_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX];
struct usb_page_cache *pc;
uint32_t actlen;
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
case USB_ST_TRANSFERRED:
setup_next:
pc = usbd_xfer_get_frame(xfer, 0);
if (usb_fifo_get_data(f, pc, 0, usbd_xfer_max_len(xfer),
&actlen, 0)) {
usbd_xfer_set_frame_len(xfer, 0, actlen);
usbd_transfer_submit(xfer);
}
break;
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* try to clear stall first */
usbd_xfer_set_stall(xfer);
goto setup_next;
}
break;
}
} /* ubtbcmfw_write_callback */
/*
* USB read callback
*/
static void
ubtbcmfw_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct ubtbcmfw_softc *sc = usbd_xfer_softc(xfer);
struct usb_fifo *fifo = sc->sc_fifo.fp[USB_FIFO_RX];
struct usb_page_cache *pc;
int actlen;
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
pc = usbd_xfer_get_frame(xfer, 0);
usb_fifo_put_data(fifo, pc, 0, actlen, 1);
/* FALLTHROUGH */
case USB_ST_SETUP:
setup_next:
if (usb_fifo_put_bytes_max(fifo) > 0) {
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
usbd_transfer_submit(xfer);
}
break;
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* try to clear stall first */
usbd_xfer_set_stall(xfer);
goto setup_next;
}
break;
}
} /* ubtbcmfw_read_callback */
/*
* Called when we about to start read()ing from the device
*/
static void
ubtbcmfw_start_read(struct usb_fifo *fifo)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
usbd_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
} /* ubtbcmfw_start_read */
/*
* Called when we about to stop reading (i.e. closing fifo)
*/
static void
ubtbcmfw_stop_read(struct usb_fifo *fifo)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
} /* ubtbcmfw_stop_read */
/*
* Called when we about to start write()ing to the device, poll()ing
* for write or flushing fifo
*/
static void
ubtbcmfw_start_write(struct usb_fifo *fifo)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
usbd_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
} /* ubtbcmfw_start_write */
/*
* Called when we about to stop writing (i.e. closing fifo)
*/
static void
ubtbcmfw_stop_write(struct usb_fifo *fifo)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
} /* ubtbcmfw_stop_write */
/*
* Called when fifo is open
*/
static int
ubtbcmfw_open(struct usb_fifo *fifo, int fflags)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
struct usb_xfer *xfer;
/*
* f_open fifo method can only be called with either FREAD
* or FWRITE flag set at one time.
*/
if (fflags & FREAD)
xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD];
else if (fflags & FWRITE)
xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR];
else
return (EINVAL); /* should not happen */
if (usb_fifo_alloc_buffer(fifo, usbd_xfer_max_len(xfer),
UBTBCMFW_IFQ_MAXLEN) != 0)
return (ENOMEM);
return (0);
} /* ubtbcmfw_open */
/*
* Called when fifo is closed
*/
static void
ubtbcmfw_close(struct usb_fifo *fifo, int fflags)
{
if (fflags & (FREAD | FWRITE))
usb_fifo_free_buffer(fifo);
} /* ubtbcmfw_close */
/*
* Process ioctl() on USB device
*/
static int
ubtbcmfw_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
int fflags)
{
struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
int error = 0;
switch (cmd) {
case USB_GET_DEVICE_DESC:
memcpy(data, usbd_get_device_descriptor(sc->sc_udev),
sizeof(struct usb_device_descriptor));
break;
default:
error = EINVAL;
break;
}
return (error);
} /* ubtbcmfw_ioctl */

View File

@ -0,0 +1,29 @@
$Id: TODO,v 1.2 2003/04/26 22:36:29 max Exp $
$FreeBSD$
FIXME/TODO list
This is a list of open issues for HCI node
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, so
it should be fine as long as Netgraph is SMP safe. Just need to
verify it.
2) HCI QoS handling
Some code exists, but i have no idea how it should work. Will
understand and fix later. I only have CSR based hardware and
it does not support QoS.
3) Add proper handling for some HCI commands
HCI testing commands is one example. Also might implement Host to
Host Controller flow control (not sure if it is required).
4) Code cleanup
Verify return codes from functions
Remove some waringns/errors

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
/*
* ng_hci_cmds.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_cmds.h,v 1.1 2002/11/24 19:46:58 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_CMDS_H_
#define _NETGRAPH_HCI_CMDS_H_
/*
* HCI command return parameters processing routines
*/
int ng_hci_send_command (ng_hci_unit_p);
int ng_hci_process_command_complete (ng_hci_unit_p, struct mbuf *);
int ng_hci_process_command_status (ng_hci_unit_p, struct mbuf *);
void ng_hci_process_command_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_HCI_CMDS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
/*
* ng_hci_evnt.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_evnt.h,v 1.1 2002/11/24 19:46:58 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_EVNT_H_
#define _NETGRAPH_HCI_EVNT_H_
/*
* HCI events processing routines
*/
int ng_hci_process_event (ng_hci_unit_p, struct mbuf *);
void ng_hci_send_data (ng_hci_unit_p);
#endif /* ndef _NETGRAPH_HCI_EVNT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,499 @@
/*
* ng_hci_misc.c
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_misc.c,v 1.5 2003/09/08 18:57:51 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/hci/ng_hci_var.h>
#include <netgraph/bluetooth/hci/ng_hci_cmds.h>
#include <netgraph/bluetooth/hci/ng_hci_evnt.h>
#include <netgraph/bluetooth/hci/ng_hci_ulpi.h>
#include <netgraph/bluetooth/hci/ng_hci_misc.h>
/******************************************************************************
******************************************************************************
** Utility routines
******************************************************************************
******************************************************************************/
/*
* Give packet to RAW hook
* Assumes input mbuf is read only.
*/
void
ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
{
struct mbuf *m = NULL;
int error = 0;
if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
m = m_dup(m0, M_NOWAIT);
if (m != NULL)
NG_SEND_DATA_ONLY(error, unit->raw, m);
if (error != 0)
NG_HCI_INFO(
"%s: %s - Could not forward packet, error=%d\n",
__func__, NG_NODE_NAME(unit->node), error);
}
} /* ng_hci_mtap */
/*
* Send notification to the upper layer's
*/
void
ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_hci_unit_p unit = NULL;
struct ng_mesg *msg = NULL;
ng_hci_node_up_ep *ep = NULL;
int error;
if (node == NULL || NG_NODE_NOT_VALID(node) ||
hook == NULL || NG_HOOK_NOT_VALID(hook))
return;
unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
return;
if (hook != unit->acl && hook != unit->sco)
return;
NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
if (msg != NULL) {
ep = (ng_hci_node_up_ep *)(msg->data);
if (hook == unit->acl) {
NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
} else {
NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
}
bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
} else
error = ENOMEM;
if (error != 0)
NG_HCI_INFO(
"%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
__func__, NG_NODE_NAME(unit->node),
NG_HOOK_NAME(hook), error);
} /* ng_hci_node_is_up */
/*
* Clean unit (helper)
*/
void
ng_hci_unit_clean(ng_hci_unit_p unit, int reason)
{
int size;
/* Drain command queue */
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
ng_hci_command_untimeout(unit);
NG_BT_MBUFQ_DRAIN(&unit->cmdq);
NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
/* Clean up connection list */
while (!LIST_EMPTY(&unit->con_list)) {
ng_hci_unit_con_p con = LIST_FIRST(&unit->con_list);
/* Remove all timeouts (if any) */
if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
ng_hci_con_untimeout(con);
/*
* Notify upper layer protocol and destroy connection
* descriptor. Do not really care about the result.
*/
ng_hci_lp_discon_ind(con, reason);
ng_hci_free_con(con);
}
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
/* Clean up neighbors list */
ng_hci_flush_neighbor_cache(unit);
} /* ng_hci_unit_clean */
/*
* Allocate and link new unit neighbor cache entry
*/
ng_hci_neighbor_p
ng_hci_new_neighbor(ng_hci_unit_p unit)
{
ng_hci_neighbor_p n = NULL;
n = malloc(sizeof(*n), M_NETGRAPH_HCI,
M_NOWAIT | M_ZERO);
if (n != NULL) {
getmicrotime(&n->updated);
LIST_INSERT_HEAD(&unit->neighbors, n, next);
}
return (n);
} /* ng_hci_new_neighbor */
/*
* Free unit neighbor cache entry
*/
void
ng_hci_free_neighbor(ng_hci_neighbor_p n)
{
LIST_REMOVE(n, next);
bzero(n, sizeof(*n));
free(n, M_NETGRAPH_HCI);
} /* ng_hci_free_neighbor */
/*
* Flush neighbor cache
*/
void
ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
{
while (!LIST_EMPTY(&unit->neighbors))
ng_hci_free_neighbor(LIST_FIRST(&unit->neighbors));
} /* ng_hci_flush_neighbor_cache */
/*
* Lookup unit in neighbor cache
*/
ng_hci_neighbor_p
ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr,int link_type)
{
ng_hci_neighbor_p n = NULL;
for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) {
ng_hci_neighbor_p nn = LIST_NEXT(n, next);
if (!ng_hci_neighbor_stale(n)) {
if (n->addrtype == link_type &&
bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
break;
} else
ng_hci_free_neighbor(n); /* remove old entry */
n = nn;
}
return (n);
} /* ng_hci_get_neighbor */
/*
* Check if neighbor entry is stale
*/
int
ng_hci_neighbor_stale(ng_hci_neighbor_p n)
{
struct timeval now;
getmicrotime(&now);
return (now.tv_sec - n->updated.tv_sec > bluetooth_hci_max_neighbor_age());
} /* ng_hci_neighbor_stale */
/*
* Allocate and link new connection descriptor
*/
ng_hci_unit_con_p
ng_hci_new_con(ng_hci_unit_p unit, int link_type)
{
ng_hci_unit_con_p con = NULL;
int num_pkts;
static int fake_con_handle = 0x0f00;
con = malloc(sizeof(*con), M_NETGRAPH_HCI,
M_NOWAIT | M_ZERO);
if (con != NULL) {
con->unit = unit;
con->state = NG_HCI_CON_CLOSED;
/*
* XXX
*
* Assign fake connection handle to the connection descriptor.
* Bluetooth specification marks 0x0f00 - 0x0fff connection
* handles as reserved. We need this fake connection handles
* for timeouts. Connection handle will be passed as argument
* to timeout so when timeout happens we can find the right
* connection descriptor. We can not pass pointers, because
* timeouts are external (to Netgraph) events and there might
* be a race when node/hook goes down and timeout event already
* went into node's queue
*/
con->con_handle = fake_con_handle ++;
if (fake_con_handle > 0x0fff)
fake_con_handle = 0x0f00;
con->link_type = link_type;
if (con->link_type != NG_HCI_LINK_SCO)
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
else
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
ng_callout_init(&con->con_timo);
LIST_INSERT_HEAD(&unit->con_list, con, next);
}
return (con);
} /* ng_hci_new_con */
/*
* Free connection descriptor
*/
void
ng_hci_free_con(ng_hci_unit_con_p con)
{
LIST_REMOVE(con, next);
/*
* If we have pending packets then assume that Host Controller has
* flushed these packets and we can free them too
*/
if (con->link_type != NG_HCI_LINK_SCO)
NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
else
NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
NG_BT_ITEMQ_DESTROY(&con->conq);
bzero(con, sizeof(*con));
free(con, M_NETGRAPH_HCI);
} /* ng_hci_free_con */
/*
* Lookup connection for given unit and connection handle.
*/
ng_hci_unit_con_p
ng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
{
ng_hci_unit_con_p con = NULL;
LIST_FOREACH(con, &unit->con_list, next)
if (con->con_handle == con_handle)
break;
return (con);
} /* ng_hci_con_by_handle */
/*
* Lookup connection for given unit, link type and remove unit address
*/
ng_hci_unit_con_p
ng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
{
ng_hci_unit_con_p con = NULL;
LIST_FOREACH(con, &unit->con_list, next)
if (con->link_type == link_type &&
bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
break;
return (con);
} /* ng_hci_con_by_bdaddr */
/*
* Set HCI command timeout
* XXX FIXME: check return code from ng_callout
*/
int
ng_hci_command_timeout(ng_hci_unit_p unit)
{
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
panic(
"%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node));
unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
ng_callout(&unit->cmd_timo, unit->node, NULL,
bluetooth_hci_command_timeout(),
ng_hci_process_command_timeout, NULL, 0);
return (0);
} /* ng_hci_command_timeout */
/*
* Unset HCI command timeout
*/
int
ng_hci_command_untimeout(ng_hci_unit_p unit)
{
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
panic(
"%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node));
if (ng_uncallout(&unit->cmd_timo, unit->node) == 0)
return (ETIMEDOUT);
unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
return (0);
} /* ng_hci_command_untimeout */
/*
* Set HCI connection timeout
* XXX FIXME: check return code from ng_callout
*/
int
ng_hci_con_timeout(ng_hci_unit_con_p con)
{
if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
panic(
"%s: %s - Duplicated connection timeout!\n",
__func__, NG_NODE_NAME(con->unit->node));
con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
ng_callout(&con->con_timo, con->unit->node, NULL,
bluetooth_hci_connect_timeout(),
ng_hci_process_con_timeout, NULL,
con->con_handle);
return (0);
} /* ng_hci_con_timeout */
/*
* Unset HCI connection timeout
*/
int
ng_hci_con_untimeout(ng_hci_unit_con_p con)
{
if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING))
panic(
"%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node));
if (ng_uncallout(&con->con_timo, con->unit->node) == 0)
return (ETIMEDOUT);
con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
return (0);
} /* ng_hci_con_untimeout */
#if 0
/*
* Convert numeric error code/reason to a string
*/
char const * const
ng_hci_str_error(u_int16_t code)
{
#define LAST_ERROR_CODE ((sizeof(s)/sizeof(s[0]))-1)
static char const * const s[] = {
/* 0x00 */ "No error",
/* 0x01 */ "Unknown HCI command",
/* 0x02 */ "No connection",
/* 0x03 */ "Hardware failure",
/* 0x04 */ "Page timeout",
/* 0x05 */ "Authentication failure",
/* 0x06 */ "Key missing",
/* 0x07 */ "Memory full",
/* 0x08 */ "Connection timeout",
/* 0x09 */ "Max number of connections",
/* 0x0a */ "Max number of SCO connections to a unit",
/* 0x0b */ "ACL connection already exists",
/* 0x0c */ "Command disallowed",
/* 0x0d */ "Host rejected due to limited resources",
/* 0x0e */ "Host rejected due to securiity reasons",
/* 0x0f */ "Host rejected due to remote unit is a personal unit",
/* 0x10 */ "Host timeout",
/* 0x11 */ "Unsupported feature or parameter value",
/* 0x12 */ "Invalid HCI command parameter",
/* 0x13 */ "Other end terminated connection: User ended connection",
/* 0x14 */ "Other end terminated connection: Low resources",
/* 0x15 */ "Other end terminated connection: About to power off",
/* 0x16 */ "Connection terminated by local host",
/* 0x17 */ "Repeated attempts",
/* 0x18 */ "Pairing not allowed",
/* 0x19 */ "Unknown LMP PDU",
/* 0x1a */ "Unsupported remote feature",
/* 0x1b */ "SCO offset rejected",
/* 0x1c */ "SCO interval rejected",
/* 0x1d */ "SCO air mode rejected",
/* 0x1e */ "Invalid LMP parameters",
/* 0x1f */ "Unspecified error",
/* 0x20 */ "Unsupported LMP parameter value",
/* 0x21 */ "Role change not allowed",
/* 0x22 */ "LMP response timeout",
/* 0x23 */ "LMP error transaction collision",
/* 0x24 */ "LMP PSU not allowed",
/* 0x25 */ "Encryption mode not acceptable",
/* 0x26 */ "Unit key used",
/* 0x27 */ "QoS is not supported",
/* 0x28 */ "Instant passed",
/* 0x29 */ "Paring with unit key not supported",
/* SHOULD ALWAYS BE LAST */ "Unknown error"
};
return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
} /* ng_hci_str_error */
#endif

View File

@ -0,0 +1,58 @@
/*
* ng_hci_misc.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_misc.h,v 1.3 2003/09/08 18:57:51 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_MISC_H_
#define _NETGRAPH_HCI_MISC_H_
void ng_hci_mtap (ng_hci_unit_p, struct mbuf *);
void ng_hci_node_is_up (node_p, hook_p, void *, int);
void ng_hci_unit_clean (ng_hci_unit_p, int);
ng_hci_neighbor_p ng_hci_new_neighbor (ng_hci_unit_p);
void ng_hci_free_neighbor (ng_hci_neighbor_p);
void ng_hci_flush_neighbor_cache (ng_hci_unit_p);
ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p, int);
int ng_hci_neighbor_stale (ng_hci_neighbor_p);
ng_hci_unit_con_p ng_hci_new_con (ng_hci_unit_p, int);
void ng_hci_free_con (ng_hci_unit_con_p);
ng_hci_unit_con_p ng_hci_con_by_handle (ng_hci_unit_p, int);
ng_hci_unit_con_p ng_hci_con_by_bdaddr (ng_hci_unit_p, bdaddr_p, int);
int ng_hci_command_timeout (ng_hci_unit_p);
int ng_hci_command_untimeout (ng_hci_unit_p);
int ng_hci_con_timeout (ng_hci_unit_con_p);
int ng_hci_con_untimeout (ng_hci_unit_con_p);
#endif /* ndef _NETGRAPH_HCI_MISC_H_ */

View File

@ -0,0 +1,219 @@
/*
* ng_hci_prse.h
*/
/*-
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_prse.h,v 1.2 2003/03/18 00:09:36 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the HCI node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_HCI_PRSE_H_
#define _NETGRAPH_HCI_PRSE_H_
/* BDADDR */
static const struct ng_parse_fixedarray_info ng_hci_bdaddr_type_info = {
&ng_parse_uint8_type,
NG_HCI_BDADDR_SIZE
};
static const struct ng_parse_type ng_hci_bdaddr_type = {
&ng_parse_fixedarray_type,
&ng_hci_bdaddr_type_info
};
/* Features */
static const struct ng_parse_fixedarray_info ng_hci_features_type_info = {
&ng_parse_uint8_type,
NG_HCI_FEATURES_SIZE
};
static const struct ng_parse_type ng_hci_features_type = {
&ng_parse_fixedarray_type,
&ng_hci_features_type_info
};
/* Buffer info */
static const struct ng_parse_struct_field ng_hci_buffer_type_fields[] =
{
{ "cmd_free", &ng_parse_uint8_type, },
{ "sco_size", &ng_parse_uint8_type, },
{ "sco_pkts", &ng_parse_uint16_type, },
{ "sco_free", &ng_parse_uint16_type, },
{ "acl_size", &ng_parse_uint16_type, },
{ "acl_pkts", &ng_parse_uint16_type, },
{ "acl_free", &ng_parse_uint16_type, },
{ NULL, }
};
static const struct ng_parse_type ng_hci_buffer_type = {
&ng_parse_struct_type,
&ng_hci_buffer_type_fields
};
/* Stat info */
static const struct ng_parse_struct_field ng_hci_stat_type_fields[] =
{
{ "cmd_sent", &ng_parse_uint32_type, },
{ "evnt_recv", &ng_parse_uint32_type, },
{ "acl_recv", &ng_parse_uint32_type, },
{ "acl_sent", &ng_parse_uint32_type, },
{ "sco_recv", &ng_parse_uint32_type, },
{ "sco_sent", &ng_parse_uint32_type, },
{ "bytes_recv", &ng_parse_uint32_type, },
{ "bytes_sent", &ng_parse_uint32_type, },
{ NULL, }
};
static const struct ng_parse_type ng_hci_stat_type = {
&ng_parse_struct_type,
&ng_hci_stat_type_fields
};
/*
* HCI node command list
*/
static const struct ng_cmdlist ng_hci_cmdlist[] = {
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_STATE,
"get_state",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_INIT,
"init",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_BUFFER,
"get_buff_info",
NULL,
&ng_hci_buffer_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_BDADDR,
"get_bdaddr",
NULL,
&ng_hci_bdaddr_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_FEATURES,
"get_features",
NULL,
&ng_hci_features_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_STAT,
"get_stat",
NULL,
&ng_hci_stat_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_RESET_STAT,
"reset_stat",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE,
"flush_ncache",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
"get_lm_mask",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
"set_lm_mask",
&ng_parse_uint16_type,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_PACKET_MASK,
"get_pkt_mask",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_PACKET_MASK,
"set_pkt_mask",
&ng_parse_uint16_type,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_ROLE_SWITCH,
"get_role_sw",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_ROLE_SWITCH,
"set_role_sw",
&ng_parse_uint16_type,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_HCI_PRSE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
/*
* ng_hci_ulpi.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_ulpi.h,v 1.2 2003/04/26 22:35:21 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_ULPI_H_
#define _NETGRAPH_HCI_ULPI_H_
/*
* LP_xxx event handlers
*/
int ng_hci_lp_con_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_discon_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_con_cfm (ng_hci_unit_con_p, int);
int ng_hci_lp_con_ind (ng_hci_unit_con_p, u_int8_t *);
int ng_hci_lp_con_rsp (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_discon_ind (ng_hci_unit_con_p, int);
int ng_hci_lp_qos_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_qos_cfm (ng_hci_unit_con_p, int);
int ng_hci_lp_qos_ind (ng_hci_unit_con_p);
int ng_hci_lp_enc_change (ng_hci_unit_con_p, int);
void ng_hci_process_con_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_HCI_ULPI_H_ */

View File

@ -0,0 +1,219 @@
/*
* ng_hci_var.h
*/
/*-
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_hci_var.h,v 1.3 2003/04/26 22:35:21 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_VAR_H_
#define _NETGRAPH_HCI_VAR_H_
/* MALLOC decalation */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_HCI);
#else
#define M_NETGRAPH_HCI M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Debug */
#define NG_HCI_ALERT if (unit->debug >= NG_HCI_ALERT_LEVEL) printf
#define NG_HCI_ERR if (unit->debug >= NG_HCI_ERR_LEVEL) printf
#define NG_HCI_WARN if (unit->debug >= NG_HCI_WARN_LEVEL) printf
#define NG_HCI_INFO if (unit->debug >= NG_HCI_INFO_LEVEL) printf
/* Wrapper around m_pullup */
#define NG_HCI_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) \
NG_HCI_ALERT("%s: %s - m_pullup(%zd) failed\n", \
__func__, NG_NODE_NAME(unit->node), (s)); \
} while (0)
/*
* Unit hardware buffer descriptor
*/
typedef struct ng_hci_unit_buff {
u_int8_t cmd_free; /* space available (cmds) */
u_int8_t sco_size; /* max. size of one packet */
u_int16_t sco_pkts; /* size of buffer (packets) */
u_int16_t sco_free; /* space available (packets)*/
u_int16_t acl_size; /* max. size of one packet */
u_int16_t acl_pkts; /* size of buffer (packets) */
u_int16_t acl_free; /* space available (packets)*/
} ng_hci_unit_buff_t;
/*
* These macro's must be used everywhere in the code. So if extra locking
* is required later, it can be added without much troubles.
*/
#define NG_HCI_BUFF_CMD_SET(b, v) (b).cmd_free = (v)
#define NG_HCI_BUFF_CMD_GET(b, v) (v) = (b).cmd_free
#define NG_HCI_BUFF_CMD_USE(b, v) (b).cmd_free -= (v)
#define NG_HCI_BUFF_ACL_USE(b, v) (b).acl_free -= (v)
#define NG_HCI_BUFF_ACL_FREE(b, v) \
do { \
(b).acl_free += (v); \
if ((b).acl_free > (b).acl_pkts) \
(b).acl_free = (b).acl_pkts; \
} while (0)
#define NG_HCI_BUFF_ACL_AVAIL(b, v) (v) = (b).acl_free
#define NG_HCI_BUFF_ACL_TOTAL(b, v) (v) = (b).acl_pkts
#define NG_HCI_BUFF_ACL_SIZE(b, v) (v) = (b).acl_size
#define NG_HCI_BUFF_ACL_SET(b, n, s, f) \
do { \
(b).acl_free = (f); \
(b).acl_size = (s); \
(b).acl_pkts = (n); \
} while (0)
#define NG_HCI_BUFF_SCO_USE(b, v) (b).sco_free -= (v)
#define NG_HCI_BUFF_SCO_FREE(b, v) \
do { \
(b).sco_free += (v); \
if ((b).sco_free > (b).sco_pkts) \
(b).sco_free = (b).sco_pkts; \
} while (0)
#define NG_HCI_BUFF_SCO_AVAIL(b, v) (v) = (b).sco_free
#define NG_HCI_BUFF_SCO_TOTAL(b, v) (v) = (b).sco_pkts
#define NG_HCI_BUFF_SCO_SIZE(b, v) (v) = (b).sco_size
#define NG_HCI_BUFF_SCO_SET(b, n, s, f) \
do { \
(b).sco_free = (f); \
(b).sco_size = (s); \
(b).sco_pkts = (n); \
} while (0)
/*
* Unit (Node private)
*/
struct ng_hci_unit_con;
struct ng_hci_neighbor;
typedef struct ng_hci_unit {
node_p node; /* node ptr */
ng_hci_node_debug_ep debug; /* debug level */
ng_hci_node_state_ep state; /* unit state */
bdaddr_t bdaddr; /* unit address */
u_int8_t features[NG_HCI_FEATURES_SIZE];
/* LMP features */
ng_hci_node_link_policy_mask_ep link_policy_mask; /* link policy mask */
ng_hci_node_packet_mask_ep packet_mask; /* packet mask */
ng_hci_node_role_switch_ep role_switch; /* role switch */
ng_hci_node_stat_ep stat; /* statistic */
#define NG_HCI_STAT_CMD_SENT(s) (s).cmd_sent ++
#define NG_HCI_STAT_EVNT_RECV(s) (s).evnt_recv ++
#define NG_HCI_STAT_ACL_SENT(s, n) (s).acl_sent += (n)
#define NG_HCI_STAT_ACL_RECV(s) (s).acl_recv ++
#define NG_HCI_STAT_SCO_SENT(s, n) (s).sco_sent += (n)
#define NG_HCI_STAT_SCO_RECV(s) (s).sco_recv ++
#define NG_HCI_STAT_BYTES_SENT(s, b) (s).bytes_sent += (b)
#define NG_HCI_STAT_BYTES_RECV(s, b) (s).bytes_recv += (b)
#define NG_HCI_STAT_RESET(s) bzero(&(s), sizeof((s)))
ng_hci_unit_buff_t buffer; /* buffer info */
struct callout cmd_timo; /* command timeout */
ng_bt_mbufq_t cmdq; /* command queue */
#define NG_HCI_CMD_QUEUE_LEN 12 /* max. size of cmd q */
hook_p drv; /* driver hook */
hook_p acl; /* upstream hook */
hook_p sco; /* upstream hook */
hook_p raw; /* upstream hook */
LIST_HEAD(, ng_hci_unit_con) con_list; /* connections */
LIST_HEAD(, ng_hci_neighbor) neighbors; /* unit neighbors */
} ng_hci_unit_t;
typedef ng_hci_unit_t * ng_hci_unit_p;
/*
* Unit connection descriptor
*/
typedef struct ng_hci_unit_con {
ng_hci_unit_p unit; /* pointer back */
u_int16_t state; /* con. state */
u_int16_t flags; /* con. flags */
#define NG_HCI_CON_TIMEOUT_PENDING (1 << 0)
#define NG_HCI_CON_NOTIFY_ACL (1 << 1)
#define NG_HCI_CON_NOTIFY_SCO (1 << 2)
bdaddr_t bdaddr; /* remote address */
u_int16_t con_handle; /* con. handle */
u_int8_t link_type; /* ACL or SCO */
u_int8_t encryption_mode; /* none, p2p, ... */
u_int8_t mode; /* ACTIVE, HOLD ... */
u_int8_t role; /* MASTER/SLAVE */
struct callout con_timo; /* con. timeout */
int pending; /* # of data pkts */
ng_bt_itemq_t conq; /* con. queue */
LIST_ENTRY(ng_hci_unit_con) next; /* next */
} ng_hci_unit_con_t;
typedef ng_hci_unit_con_t * ng_hci_unit_con_p;
/*
* Unit's neighbor descriptor.
* Neighbor is a remote unit that responded to our inquiry.
*/
typedef struct ng_hci_neighbor {
struct timeval updated; /* entry was updated */
bdaddr_t bdaddr; /* address */
u_int8_t features[NG_HCI_FEATURES_SIZE];
/* LMP features */
u_int8_t addrtype; /*Address Type*/
u_int8_t page_scan_rep_mode; /* PS rep. mode */
u_int8_t page_scan_mode; /* page scan mode */
u_int16_t clock_offset; /* clock offset */
LIST_ENTRY(ng_hci_neighbor) next;
} ng_hci_neighbor_t;
typedef ng_hci_neighbor_t * ng_hci_neighbor_p;
#endif /* ndef _NETGRAPH_HCI_VAR_H_ */

View File

@ -0,0 +1,228 @@
/*
* bluetooth.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_bluetooth.h,v 1.4 2003/04/26 22:32:34 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BLUETOOTH_H_
#define _NETGRAPH_BLUETOOTH_H_
#include <sys/queue.h>
/*
* Version of the stack
*/
#define NG_BLUETOOTH_VERSION 1
/*
* Declare the base of the Bluetooth sysctl hierarchy,
* but only if this file cares about sysctl's
*/
#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_bluetooth);
SYSCTL_DECL(_net_bluetooth_hci);
SYSCTL_DECL(_net_bluetooth_l2cap);
SYSCTL_DECL(_net_bluetooth_rfcomm);
SYSCTL_DECL(_net_bluetooth_sco);
#endif /* SYSCTL_DECL */
/*
* Mbuf qeueue and useful mbufq macros. We do not use ifqueue because we
* do not need mutex and other locking stuff
*/
struct mbuf;
struct ng_bt_mbufq {
struct mbuf *head; /* first item in the queue */
struct mbuf *tail; /* last item in the queue */
u_int32_t len; /* number of items in the queue */
u_int32_t maxlen; /* maximal number of items in the queue */
u_int32_t drops; /* number if dropped items */
};
typedef struct ng_bt_mbufq ng_bt_mbufq_t;
typedef struct ng_bt_mbufq * ng_bt_mbufq_p;
#define NG_BT_MBUFQ_INIT(q, _maxlen) \
do { \
(q)->head = NULL; \
(q)->tail = NULL; \
(q)->len = 0; \
(q)->maxlen = (_maxlen); \
(q)->drops = 0; \
} while (0)
#define NG_BT_MBUFQ_DESTROY(q) \
do { \
NG_BT_MBUFQ_DRAIN((q)); \
} while (0)
#define NG_BT_MBUFQ_FIRST(q) (q)->head
#define NG_BT_MBUFQ_LEN(q) (q)->len
#define NG_BT_MBUFQ_FULL(q) ((q)->len >= (q)->maxlen)
#define NG_BT_MBUFQ_DROP(q) (q)->drops ++
#define NG_BT_MBUFQ_ENQUEUE(q, i) \
do { \
(i)->m_nextpkt = NULL; \
\
if ((q)->tail == NULL) \
(q)->head = (i); \
else \
(q)->tail->m_nextpkt = (i); \
\
(q)->tail = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_MBUFQ_DEQUEUE(q, i) \
do { \
(i) = (q)->head; \
if ((i) != NULL) { \
(q)->head = (q)->head->m_nextpkt; \
if ((q)->head == NULL) \
(q)->tail = NULL; \
\
(q)->len --; \
(i)->m_nextpkt = NULL; \
} \
} while (0)
#define NG_BT_MBUFQ_PREPEND(q, i) \
do { \
(i)->m_nextpkt = (q)->head; \
if ((q)->tail == NULL) \
(q)->tail = (i); \
\
(q)->head = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_MBUFQ_DRAIN(q) \
do { \
struct mbuf *m = NULL; \
\
for (;;) { \
NG_BT_MBUFQ_DEQUEUE((q), m); \
if (m == NULL) \
break; \
\
NG_FREE_M(m); \
} \
} while (0)
/*
* Netgraph item queue and useful itemq macros
*/
struct ng_item;
struct ng_bt_itemq {
STAILQ_HEAD(, ng_item) queue; /* actually items queue */
u_int32_t len; /* number of items in the queue */
u_int32_t maxlen; /* maximal number of items in the queue */
u_int32_t drops; /* number if dropped items */
};
typedef struct ng_bt_itemq ng_bt_itemq_t;
typedef struct ng_bt_itemq * ng_bt_itemq_p;
#define NG_BT_ITEMQ_INIT(q, _maxlen) \
do { \
STAILQ_INIT(&(q)->queue); \
(q)->len = 0; \
(q)->maxlen = (_maxlen); \
(q)->drops = 0; \
} while (0)
#define NG_BT_ITEMQ_DESTROY(q) \
do { \
NG_BT_ITEMQ_DRAIN((q)); \
} while (0)
#define NG_BT_ITEMQ_FIRST(q) STAILQ_FIRST(&(q)->queue)
#define NG_BT_ITEMQ_LEN(q) NG_BT_MBUFQ_LEN((q))
#define NG_BT_ITEMQ_FULL(q) NG_BT_MBUFQ_FULL((q))
#define NG_BT_ITEMQ_DROP(q) NG_BT_MBUFQ_DROP((q))
#define NG_BT_ITEMQ_ENQUEUE(q, i) \
do { \
STAILQ_INSERT_TAIL(&(q)->queue, (i), el_next); \
(q)->len ++; \
} while (0)
#define NG_BT_ITEMQ_DEQUEUE(q, i) \
do { \
(i) = STAILQ_FIRST(&(q)->queue); \
if ((i) != NULL) { \
STAILQ_REMOVE_HEAD(&(q)->queue, el_next); \
(q)->len --; \
} \
} while (0)
#define NG_BT_ITEMQ_PREPEND(q, i) \
do { \
STAILQ_INSERT_HEAD(&(q)->queue, (i), el_next); \
(q)->len ++; \
} while (0)
#define NG_BT_ITEMQ_DRAIN(q) \
do { \
struct ng_item *i = NULL; \
\
for (;;) { \
NG_BT_ITEMQ_DEQUEUE((q), i); \
if (i == NULL) \
break; \
\
NG_FREE_ITEM(i); \
} \
} while (0)
/*
* Get Bluetooth stack sysctl globals
*/
u_int32_t bluetooth_hci_command_timeout (void);
u_int32_t bluetooth_hci_connect_timeout (void);
u_int32_t bluetooth_hci_max_neighbor_age (void);
u_int32_t bluetooth_l2cap_rtx_timeout (void);
u_int32_t bluetooth_l2cap_ertx_timeout (void);
u_int32_t bluetooth_sco_rtx_timeout (void);
#endif /* _NETGRAPH_BLUETOOTH_H_ */

View File

@ -0,0 +1,111 @@
/*
* ng_bt3c.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_bt3c.h,v 1.1 2002/11/24 19:47:05 max Exp $
* $FreeBSD$
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
* Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
* and disassembled w2k driver.
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
*/
#ifndef _NG_BT3C_H_
#define _NG_BT3C_H_
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
#define NG_BT3C_NODE_TYPE "btccc" /* XXX can't use bt3c in pccard.conf */
#define NG_BT3C_HOOK "hook"
#define NGM_BT3C_COOKIE 1014752016
/* Debug levels */
#define NG_BT3C_ALERT_LEVEL 1
#define NG_BT3C_ERR_LEVEL 2
#define NG_BT3C_WARN_LEVEL 3
#define NG_BT3C_INFO_LEVEL 4
/* Node states */
#define NG_BT3C_W4_PKT_IND 1 /* wait for packet indicator */
#define NG_BT3C_W4_PKT_HDR 2 /* wait for packet header */
#define NG_BT3C_W4_PKT_DATA 3 /* wait for packet data */
/**************************************************************************
**************************************************************************
** BT3C node command/event parameters
**************************************************************************
**************************************************************************/
#define NGM_BT3C_NODE_GET_STATE 1 /* get node state */
typedef u_int16_t ng_bt3c_node_state_ep;
#define NGM_BT3C_NODE_SET_DEBUG 2 /* set debug level */
#define NGM_BT3C_NODE_GET_DEBUG 3 /* get debug level */
typedef u_int16_t ng_bt3c_node_debug_ep;
#define NGM_BT3C_NODE_GET_QLEN 4 /* get queue length */
#define NGM_BT3C_NODE_SET_QLEN 5 /* set queue length */
typedef struct {
int32_t queue; /* queue index */
#define NGM_BT3C_NODE_IN_QUEUE 1 /* incoming queue */
#define NGM_BT3C_NODE_OUT_QUEUE 2 /* outgoing queue */
int32_t qlen; /* queue length */
} ng_bt3c_node_qlen_ep;
#define NGM_BT3C_NODE_GET_STAT 6 /* get statistic */
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_bt3c_node_stat_ep;
#define NGM_BT3C_NODE_RESET_STAT 7 /* reset statistic */
#define NGM_BT3C_NODE_DOWNLOAD_FIRMWARE 8 /* download firmware */
typedef struct {
u_int32_t block_address;
u_int16_t block_size; /* in words */
u_int16_t block_alignment; /* in bytes */
} ng_bt3c_firmware_block_ep;
#endif /* ndef _NG_BT3C_H_ */

View File

@ -0,0 +1,380 @@
/*
* ng_btsocket.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket.h,v 1.8 2003/04/26 22:32:10 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_H_
#define _NETGRAPH_BTSOCKET_H_
/*
* Bluetooth protocols
*/
#define BLUETOOTH_PROTO_HCI 134 /* HCI protocol number */
#define BLUETOOTH_PROTO_L2CAP 135 /* L2CAP protocol number */
#define BLUETOOTH_PROTO_RFCOMM 136 /* RFCOMM protocol number */
#define BLUETOOTH_PROTO_SCO 137 /* SCO protocol number */
/*
* Bluetooth version of struct sockaddr for raw HCI sockets
*/
struct sockaddr_hci {
u_char hci_len; /* total length */
u_char hci_family; /* address family */
char hci_node[32]; /* address (size == NG_NODESIZ ) */
};
/* Raw HCI socket options */
#define SOL_HCI_RAW 0x0802 /* socket options level */
#define SO_HCI_RAW_FILTER 1 /* get/set filter on socket */
#define SO_HCI_RAW_DIRECTION 2 /* turn on/off direction info */
#define SCM_HCI_RAW_DIRECTION SO_HCI_RAW_DIRECTION /* cmsg_type */
/*
* Raw HCI socket filter.
*
* For packet mask use (1 << (HCI packet indicator - 1))
* For event mask use (1 << (Event - 1))
*/
struct ng_btsocket_hci_raw_filter {
bitstr_t bit_decl(packet_mask, 32);
bitstr_t bit_decl(event_mask, (NG_HCI_EVENT_MASK_SIZE * 8));
};
/*
* Raw HCI sockets ioctl's
*/
/* Get state */
struct ng_btsocket_hci_raw_node_state {
ng_hci_node_state_ep state;
};
#define SIOC_HCI_RAW_NODE_GET_STATE \
_IOWR('b', NGM_HCI_NODE_GET_STATE, \
struct ng_btsocket_hci_raw_node_state)
/* Initialize */
#define SIOC_HCI_RAW_NODE_INIT \
_IO('b', NGM_HCI_NODE_INIT)
/* Get/Set debug level */
struct ng_btsocket_hci_raw_node_debug {
ng_hci_node_debug_ep debug;
};
#define SIOC_HCI_RAW_NODE_GET_DEBUG \
_IOWR('b', NGM_HCI_NODE_GET_DEBUG, \
struct ng_btsocket_hci_raw_node_debug)
#define SIOC_HCI_RAW_NODE_SET_DEBUG \
_IOWR('b', NGM_HCI_NODE_SET_DEBUG, \
struct ng_btsocket_hci_raw_node_debug)
/* Get buffer info */
struct ng_btsocket_hci_raw_node_buffer {
ng_hci_node_buffer_ep buffer;
};
#define SIOC_HCI_RAW_NODE_GET_BUFFER \
_IOWR('b', NGM_HCI_NODE_GET_BUFFER, \
struct ng_btsocket_hci_raw_node_buffer)
/* Get BD_ADDR */
struct ng_btsocket_hci_raw_node_bdaddr {
bdaddr_t bdaddr;
};
#define SIOC_HCI_RAW_NODE_GET_BDADDR \
_IOWR('b', NGM_HCI_NODE_GET_BDADDR, \
struct ng_btsocket_hci_raw_node_bdaddr)
/* Get features */
struct ng_btsocket_hci_raw_node_features {
u_int8_t features[NG_HCI_FEATURES_SIZE];
};
#define SIOC_HCI_RAW_NODE_GET_FEATURES \
_IOWR('b', NGM_HCI_NODE_GET_FEATURES, \
struct ng_btsocket_hci_raw_node_features)
/* Get stat */
struct ng_btsocket_hci_raw_node_stat {
ng_hci_node_stat_ep stat;
};
#define SIOC_HCI_RAW_NODE_GET_STAT \
_IOWR('b', NGM_HCI_NODE_GET_STAT, \
struct ng_btsocket_hci_raw_node_stat)
/* Reset stat */
#define SIOC_HCI_RAW_NODE_RESET_STAT \
_IO('b', NGM_HCI_NODE_RESET_STAT)
/* Flush neighbor cache */
#define SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE \
_IO('b', NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE)
/* Get neighbor cache */
struct ng_btsocket_hci_raw_node_neighbor_cache {
u_int32_t num_entries;
ng_hci_node_neighbor_cache_entry_ep *entries;
};
#define SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE \
_IOWR('b', NGM_HCI_NODE_GET_NEIGHBOR_CACHE, \
struct ng_btsocket_hci_raw_node_neighbor_cache)
/* Get connection list */
struct ng_btsocket_hci_raw_con_list {
u_int32_t num_connections;
ng_hci_node_con_ep *connections;
};
#define SIOC_HCI_RAW_NODE_GET_CON_LIST \
_IOWR('b', NGM_HCI_NODE_GET_CON_LIST, \
struct ng_btsocket_hci_raw_con_list)
/* Get/Set link policy settings mask */
struct ng_btsocket_hci_raw_node_link_policy_mask {
ng_hci_node_link_policy_mask_ep policy_mask;
};
#define SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK \
_IOWR('b', NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK, \
struct ng_btsocket_hci_raw_node_link_policy_mask)
#define SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK \
_IOWR('b', NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK, \
struct ng_btsocket_hci_raw_node_link_policy_mask)
/* Get/Set packet mask */
struct ng_btsocket_hci_raw_node_packet_mask {
ng_hci_node_packet_mask_ep packet_mask;
};
#define SIOC_HCI_RAW_NODE_GET_PACKET_MASK \
_IOWR('b', NGM_HCI_NODE_GET_PACKET_MASK, \
struct ng_btsocket_hci_raw_node_packet_mask)
#define SIOC_HCI_RAW_NODE_SET_PACKET_MASK \
_IOWR('b', NGM_HCI_NODE_SET_PACKET_MASK, \
struct ng_btsocket_hci_raw_node_packet_mask)
/* Get/Set role switch */
struct ng_btsocket_hci_raw_node_role_switch {
ng_hci_node_role_switch_ep role_switch;
};
#define SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH \
_IOWR('b', NGM_HCI_NODE_GET_ROLE_SWITCH, \
struct ng_btsocket_hci_raw_node_role_switch)
#define SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH \
_IOWR('b', NGM_HCI_NODE_SET_ROLE_SWITCH, \
struct ng_btsocket_hci_raw_node_role_switch)
/* Get list of HCI node names */
struct ng_btsocket_hci_raw_node_list_names {
u_int32_t num_names;
struct nodeinfo *names;
};
#define SIOC_HCI_RAW_NODE_LIST_NAMES \
_IOWR('b', NGM_HCI_NODE_LIST_NAMES, \
struct ng_btsocket_hci_raw_node_list_names)
/*
* XXX FIXME: probably does not belong here
* Bluetooth version of struct sockaddr for SCO sockets (SEQPACKET)
*/
struct sockaddr_sco {
u_char sco_len; /* total length */
u_char sco_family; /* address family */
bdaddr_t sco_bdaddr; /* address */
};
/* SCO socket options */
#define SOL_SCO 0x0209 /* socket options level */
#define SO_SCO_MTU 1 /* get sockets mtu */
#define SO_SCO_CONNINFO 2 /* get HCI connection handle */
/*
* XXX FIXME: probably does not belong here
* Bluetooth version of struct sockaddr for L2CAP sockets (RAW and SEQPACKET)
*/
struct sockaddr_l2cap_compat {
u_char l2cap_len; /* total length */
u_char l2cap_family; /* address family */
u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
bdaddr_t l2cap_bdaddr; /* address */
};
#define BDADDR_BREDR 0
#define BDADDR_LE_PUBLIC 1
#define BDADDR_LE_RANDOM 2
struct sockaddr_l2cap {
u_char l2cap_len; /* total length */
u_char l2cap_family; /* address family */
u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
bdaddr_t l2cap_bdaddr; /* address */
u_int16_t l2cap_cid; /*cid*/
u_int8_t l2cap_bdaddr_type; /*address type*/
};
#if !defined(L2CAP_SOCKET_CHECKED) && !defined(_KERNEL)
#warning "Make sure new member of socket address initialized"
#endif
/* L2CAP socket options */
#define SOL_L2CAP 0x1609 /* socket option level */
#define SO_L2CAP_IMTU 1 /* get/set incoming MTU */
#define SO_L2CAP_OMTU 2 /* get outgoing (peer incoming) MTU */
#define SO_L2CAP_IFLOW 3 /* get incoming flow spec. */
#define SO_L2CAP_OFLOW 4 /* get/set outgoing flow spec. */
#define SO_L2CAP_FLUSH 5 /* get/set flush timeout */
#define SO_L2CAP_ENCRYPTED 6 /* get/set whether wait for encryptin on connect */
/*
* Raw L2CAP sockets ioctl's
*/
/* Ping */
struct ng_btsocket_l2cap_raw_ping {
u_int32_t result;
u_int32_t echo_size;
u_int8_t *echo_data;
};
#define SIOC_L2CAP_L2CA_PING \
_IOWR('b', NGM_L2CAP_L2CA_PING, \
struct ng_btsocket_l2cap_raw_ping)
/* Get info */
struct ng_btsocket_l2cap_raw_get_info {
u_int32_t result;
u_int32_t info_type;
u_int32_t info_size;
u_int8_t *info_data;
};
#define SIOC_L2CAP_L2CA_GET_INFO \
_IOWR('b', NGM_L2CAP_L2CA_GET_INFO, \
struct ng_btsocket_l2cap_raw_get_info)
/* Get flags */
struct ng_btsocket_l2cap_raw_node_flags {
ng_l2cap_node_flags_ep flags;
};
#define SIOC_L2CAP_NODE_GET_FLAGS \
_IOWR('b', NGM_L2CAP_NODE_GET_FLAGS, \
struct ng_btsocket_l2cap_raw_node_flags)
/* Get/Set debug level */
struct ng_btsocket_l2cap_raw_node_debug {
ng_l2cap_node_debug_ep debug;
};
#define SIOC_L2CAP_NODE_GET_DEBUG \
_IOWR('b', NGM_L2CAP_NODE_GET_DEBUG, \
struct ng_btsocket_l2cap_raw_node_debug)
#define SIOC_L2CAP_NODE_SET_DEBUG \
_IOWR('b', NGM_L2CAP_NODE_SET_DEBUG, \
struct ng_btsocket_l2cap_raw_node_debug)
/* Get connection list */
struct ng_btsocket_l2cap_raw_con_list {
u_int32_t num_connections;
ng_l2cap_node_con_ep *connections;
};
#define SIOC_L2CAP_NODE_GET_CON_LIST \
_IOWR('b', NGM_L2CAP_NODE_GET_CON_LIST, \
struct ng_btsocket_l2cap_raw_con_list)
/* Get channel list */
struct ng_btsocket_l2cap_raw_chan_list {
u_int32_t num_channels;
ng_l2cap_node_chan_ep *channels;
};
#define SIOC_L2CAP_NODE_GET_CHAN_LIST \
_IOWR('b', NGM_L2CAP_NODE_GET_CHAN_LIST, \
struct ng_btsocket_l2cap_raw_chan_list)
/* Get/Set auto disconnect timeout */
struct ng_btsocket_l2cap_raw_auto_discon_timo
{
ng_l2cap_node_auto_discon_ep timeout;
};
#define SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO \
_IOWR('b', NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, \
struct ng_btsocket_l2cap_raw_auto_discon_timo)
#define SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO \
_IOWR('b', NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, \
struct ng_btsocket_l2cap_raw_auto_discon_timo)
/*
* XXX FIXME: probably does not belong here
* Bluetooth version of struct sockaddr for RFCOMM sockets (STREAM)
*/
struct sockaddr_rfcomm {
u_char rfcomm_len; /* total length */
u_char rfcomm_family; /* address family */
bdaddr_t rfcomm_bdaddr; /* address */
u_int8_t rfcomm_channel; /* channel */
};
/* Flow control information */
struct ng_btsocket_rfcomm_fc_info {
u_int8_t lmodem; /* modem signals (local) */
u_int8_t rmodem; /* modem signals (remote) */
u_int8_t tx_cred; /* TX credits */
u_int8_t rx_cred; /* RX credits */
u_int8_t cfc; /* credit flow control */
u_int8_t reserved;
};
/* STREAM RFCOMM socket options */
#define SOL_RFCOMM 0x0816 /* socket options level */
#define SO_RFCOMM_MTU 1 /* get channel MTU */
#define SO_RFCOMM_FC_INFO 2 /* get flow control information */
/*
* Netgraph node type name and cookie
*/
#define NG_BTSOCKET_HCI_RAW_NODE_TYPE "btsock_hci_raw"
#define NG_BTSOCKET_L2CAP_RAW_NODE_TYPE "btsock_l2c_raw"
#define NG_BTSOCKET_L2CAP_NODE_TYPE "btsock_l2c"
#define NG_BTSOCKET_SCO_NODE_TYPE "btsock_sco"
/*
* Debug levels
*/
#define NG_BTSOCKET_ALERT_LEVEL 1
#define NG_BTSOCKET_ERR_LEVEL 2
#define NG_BTSOCKET_WARN_LEVEL 3
#define NG_BTSOCKET_INFO_LEVEL 4
#endif /* _NETGRAPH_BTSOCKET_H_ */

View File

@ -0,0 +1,90 @@
/*
* ng_btsocket_hci_raw.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket_hci_raw.h,v 1.3 2003/03/25 23:53:32 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_HCI_RAW_H_
#define _NETGRAPH_BTSOCKET_HCI_RAW_H_
#define NG_BTSOCKET_HCI_RAW_SENDSPACE (4 * 1024)
#define NG_BTSOCKET_HCI_RAW_RECVSPACE (4 * 1024)
/*
* Bluetooth raw HCI socket PCB
*/
struct ng_btsocket_hci_raw_pcb {
struct socket *so; /* socket */
u_int32_t flags; /* flags */
#define NG_BTSOCKET_HCI_RAW_DIRECTION (1 << 0)
#define NG_BTSOCKET_HCI_RAW_PRIVILEGED (1 << 1)
struct sockaddr_hci addr; /* local address */
struct ng_btsocket_hci_raw_filter filter; /* filter */
u_int32_t token; /* message token */
struct ng_mesg *msg; /* message */
LIST_ENTRY(ng_btsocket_hci_raw_pcb) next; /* link to next */
struct mtx pcb_mtx; /* pcb mutex */
};
typedef struct ng_btsocket_hci_raw_pcb ng_btsocket_hci_raw_pcb_t;
typedef struct ng_btsocket_hci_raw_pcb * ng_btsocket_hci_raw_pcb_p;
#define so2hci_raw_pcb(so) \
((struct ng_btsocket_hci_raw_pcb *)((so)->so_pcb))
/*
* Bluetooth raw HCI socket methods
*/
#ifdef _KERNEL
void ng_btsocket_hci_raw_init (void);
void ng_btsocket_hci_raw_abort (struct socket *);
void ng_btsocket_hci_raw_close (struct socket *);
int ng_btsocket_hci_raw_attach (struct socket *, int, struct thread *);
int ng_btsocket_hci_raw_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_hci_raw_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_hci_raw_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_hci_raw_ctloutput (struct socket *, struct sockopt *);
void ng_btsocket_hci_raw_detach (struct socket *);
int ng_btsocket_hci_raw_disconnect (struct socket *);
int ng_btsocket_hci_raw_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_hci_raw_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_hci_raw_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* ndef _NETGRAPH_BTSOCKET_HCI_RAW_H_ */

View File

@ -0,0 +1,216 @@
/*
* ng_btsocket_l2cap.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket_l2cap.h,v 1.4 2003/03/25 23:53:33 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_L2CAP_H_
#define _NETGRAPH_BTSOCKET_L2CAP_H_
/*
* L2CAP routing entry
*/
struct ng_hook;
struct ng_message;
struct ng_btsocket_l2cap_rtentry {
bdaddr_t src; /* source BD_ADDR */
struct ng_hook *hook; /* downstream hook */
LIST_ENTRY(ng_btsocket_l2cap_rtentry) next; /* link to next */
};
typedef struct ng_btsocket_l2cap_rtentry ng_btsocket_l2cap_rtentry_t;
typedef struct ng_btsocket_l2cap_rtentry * ng_btsocket_l2cap_rtentry_p;
/*****************************************************************************
*****************************************************************************
** SOCK_RAW L2CAP sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_L2CAP_RAW_SENDSPACE NG_L2CAP_MTU_DEFAULT
#define NG_BTSOCKET_L2CAP_RAW_RECVSPACE NG_L2CAP_MTU_DEFAULT
/*
* Bluetooth raw L2CAP socket PCB
*/
struct ng_btsocket_l2cap_raw_pcb {
struct socket *so; /* socket */
u_int32_t flags; /* flags */
#define NG_BTSOCKET_L2CAP_RAW_PRIVILEGED (1 << 0)
bdaddr_t src; /* source address */
bdaddr_t dst; /* dest address */
uint8_t srctype;/*source addr type*/
uint8_t dsttype;/*source addr type*/
ng_btsocket_l2cap_rtentry_p rt; /* routing info */
u_int32_t token; /* message token */
struct ng_mesg *msg; /* message */
struct mtx pcb_mtx; /* pcb mutex */
LIST_ENTRY(ng_btsocket_l2cap_raw_pcb) next; /* link to next PCB */
};
typedef struct ng_btsocket_l2cap_raw_pcb ng_btsocket_l2cap_raw_pcb_t;
typedef struct ng_btsocket_l2cap_raw_pcb * ng_btsocket_l2cap_raw_pcb_p;
#define so2l2cap_raw_pcb(so) \
((struct ng_btsocket_l2cap_raw_pcb *)((so)->so_pcb))
/*
* Bluetooth raw L2CAP socket methods
*/
#ifdef _KERNEL
void ng_btsocket_l2cap_raw_init (void);
void ng_btsocket_l2cap_raw_abort (struct socket *);
void ng_btsocket_l2cap_raw_close (struct socket *);
int ng_btsocket_l2cap_raw_attach (struct socket *, int, struct thread *);
int ng_btsocket_l2cap_raw_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_raw_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_raw_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
void ng_btsocket_l2cap_raw_detach (struct socket *);
int ng_btsocket_l2cap_raw_disconnect (struct socket *);
int ng_btsocket_l2cap_raw_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_raw_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_l2cap_raw_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
/*****************************************************************************
*****************************************************************************
** SOCK_SEQPACKET L2CAP sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_L2CAP_SENDSPACE NG_L2CAP_MTU_DEFAULT /* (64 * 1024) */
#define NG_BTSOCKET_L2CAP_RECVSPACE (64 * 1024)
/*
* Bluetooth L2CAP socket PCB
*/
struct ng_btsocket_l2cap_pcb {
struct socket *so; /* Pointer to socket */
bdaddr_t src; /* Source address */
bdaddr_t dst; /* Destination address */
uint8_t srctype; /*source addr type*/
uint8_t dsttype; /*source addr type*/
u_int16_t psm; /* PSM */
u_int16_t cid; /* Local channel ID */
uint8_t idtype;
u_int16_t flags; /* socket flags */
#define NG_BTSOCKET_L2CAP_CLIENT (1 << 0) /* socket is client */
#define NG_BTSOCKET_L2CAP_TIMO (1 << 1) /* timeout pending */
u_int8_t state; /* socket state */
#define NG_BTSOCKET_L2CAP_CLOSED 0 /* socket closed */
#define NG_BTSOCKET_L2CAP_CONNECTING 1 /* wait for connect */
#define NG_BTSOCKET_L2CAP_CONFIGURING 2 /* wait for config */
#define NG_BTSOCKET_L2CAP_OPEN 3 /* socket open */
#define NG_BTSOCKET_L2CAP_DISCONNECTING 4 /* wait for disconnect */
#define NG_BTSOCKET_L2CAP_W4_ENC_CHANGE 5
u_int8_t cfg_state; /* config state */
#define NG_BTSOCKET_L2CAP_CFG_IN (1 << 0) /* incoming path done */
#define NG_BTSOCKET_L2CAP_CFG_OUT (1 << 1) /* outgoing path done */
#define NG_BTSOCKET_L2CAP_CFG_BOTH \
(NG_BTSOCKET_L2CAP_CFG_IN | NG_BTSOCKET_L2CAP_CFG_OUT)
#define NG_BTSOCKET_L2CAP_CFG_IN_SENT (1 << 2) /* L2CAP ConfigReq sent */
#define NG_BTSOCKET_L2CAP_CFG_OUT_SENT (1 << 3) /* ---/--- */
uint8_t encryption;
u_int16_t imtu; /* Incoming MTU */
ng_l2cap_flow_t iflow; /* Input flow spec */
u_int16_t omtu; /* Outgoing MTU */
ng_l2cap_flow_t oflow; /* Outgoing flow spec */
u_int16_t flush_timo; /* flush timeout */
u_int16_t link_timo; /* link timeout */
struct callout timo; /* timeout */
u_int32_t token; /* message token */
ng_btsocket_l2cap_rtentry_p rt; /* routing info */
struct mtx pcb_mtx; /* pcb mutex */
uint16_t need_encrypt; /*encryption needed*/
LIST_ENTRY(ng_btsocket_l2cap_pcb) next; /* link to next PCB */
};
typedef struct ng_btsocket_l2cap_pcb ng_btsocket_l2cap_pcb_t;
typedef struct ng_btsocket_l2cap_pcb * ng_btsocket_l2cap_pcb_p;
#define so2l2cap_pcb(so) \
((struct ng_btsocket_l2cap_pcb *)((so)->so_pcb))
/*
* Bluetooth L2CAP socket methods
*/
#ifdef _KERNEL
void ng_btsocket_l2cap_init (void);
void ng_btsocket_l2cap_abort (struct socket *);
void ng_btsocket_l2cap_close (struct socket *);
int ng_btsocket_l2cap_accept (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_attach (struct socket *, int, struct thread *);
int ng_btsocket_l2cap_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_l2cap_ctloutput (struct socket *, struct sockopt *);
void ng_btsocket_l2cap_detach (struct socket *);
int ng_btsocket_l2cap_disconnect (struct socket *);
int ng_btsocket_l2cap_listen (struct socket *, int, struct thread *);
int ng_btsocket_l2cap_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_l2cap_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* _NETGRAPH_BTSOCKET_L2CAP_H_ */

View File

@ -0,0 +1,340 @@
/*
* ng_btsocket_rfcomm.h
*/
/*-
* Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket_rfcomm.h,v 1.10 2003/03/29 22:27:42 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_RFCOMM_H_
#define _NETGRAPH_BTSOCKET_RFCOMM_H_
/*****************************************************************************
*****************************************************************************
** RFCOMM **
*****************************************************************************
*****************************************************************************/
/* XXX FIXME this does not belong here */
#define RFCOMM_DEFAULT_MTU 667
#define RFCOMM_MAX_MTU 1024
#define RFCOMM_DEFAULT_CREDITS 7
#define RFCOMM_MAX_CREDITS 40
/* RFCOMM frame types */
#define RFCOMM_FRAME_SABM 0x2f
#define RFCOMM_FRAME_DISC 0x43
#define RFCOMM_FRAME_UA 0x63
#define RFCOMM_FRAME_DM 0x0f
#define RFCOMM_FRAME_UIH 0xef
/* RFCOMM MCC commands */
#define RFCOMM_MCC_TEST 0x08 /* Test */
#define RFCOMM_MCC_FCON 0x28 /* Flow Control on */
#define RFCOMM_MCC_FCOFF 0x18 /* Flow Control off */
#define RFCOMM_MCC_MSC 0x38 /* Modem Status Command */
#define RFCOMM_MCC_RPN 0x24 /* Remote Port Negotiation */
#define RFCOMM_MCC_RLS 0x14 /* Remote Line Status */
#define RFCOMM_MCC_PN 0x20 /* Port Negotiation */
#define RFCOMM_MCC_NSC 0x04 /* Non Supported Command */
/* RFCOMM modem signals */
#define RFCOMM_MODEM_FC 0x02 /* Flow Control asserted */
#define RFCOMM_MODEM_RTC 0x04 /* Ready To Communicate */
#define RFCOMM_MODEM_RTR 0x08 /* Ready To Receive */
#define RFCOMM_MODEM_IC 0x40 /* Incoming Call */
#define RFCOMM_MODEM_DV 0x80 /* Data Valid */
/* RPN parameters - baud rate */
#define RFCOMM_RPN_BR_2400 0x0
#define RFCOMM_RPN_BR_4800 0x1
#define RFCOMM_RPN_BR_7200 0x2
#define RFCOMM_RPN_BR_9600 0x3
#define RFCOMM_RPN_BR_19200 0x4
#define RFCOMM_RPN_BR_38400 0x5
#define RFCOMM_RPN_BR_57600 0x6
#define RFCOMM_RPN_BR_115200 0x7
#define RFCOMM_RPN_BR_230400 0x8
/* RPN parameters - data bits */
#define RFCOMM_RPN_DATA_5 0x0
#define RFCOMM_RPN_DATA_6 0x2
#define RFCOMM_RPN_DATA_7 0x1
#define RFCOMM_RPN_DATA_8 0x3
/* RPN parameters - stop bit */
#define RFCOMM_RPN_STOP_1 0
#define RFCOMM_RPN_STOP_15 1
/* RPN parameters - parity */
#define RFCOMM_RPN_PARITY_NONE 0x0
#define RFCOMM_RPN_PARITY_ODD 0x4
#define RFCOMM_RPN_PARITY_EVEN 0x5
#define RFCOMM_RPN_PARITY_MARK 0x6
#define RFCOMM_RPN_PARITY_SPACE 0x7
/* RPN parameters - flow control */
#define RFCOMM_RPN_FLOW_NONE 0x00
#define RFCOMM_RPN_XON_CHAR 0x11
#define RFCOMM_RPN_XOFF_CHAR 0x13
/* RPN parameters - mask */
#define RFCOMM_RPN_PM_BITRATE 0x0001
#define RFCOMM_RPN_PM_DATA 0x0002
#define RFCOMM_RPN_PM_STOP 0x0004
#define RFCOMM_RPN_PM_PARITY 0x0008
#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
#define RFCOMM_RPN_PM_XON 0x0020
#define RFCOMM_RPN_PM_XOFF 0x0040
#define RFCOMM_RPN_PM_FLOW 0x3F00
#define RFCOMM_RPN_PM_ALL 0x3F7F
/* RFCOMM frame header */
struct rfcomm_frame_hdr
{
u_int8_t address;
u_int8_t control;
u_int8_t length; /* Actual size could be 2 bytes */
} __attribute__ ((packed));
/* RFCOMM command frame header */
struct rfcomm_cmd_hdr
{
u_int8_t address;
u_int8_t control;
u_int8_t length;
u_int8_t fcs;
} __attribute__ ((packed));
/* RFCOMM MCC command header */
struct rfcomm_mcc_hdr
{
u_int8_t type;
u_int8_t length; /* XXX FIXME Can actual size be 2 bytes?? */
} __attribute__ ((packed));
/* RFCOMM MSC command */
struct rfcomm_mcc_msc
{
u_int8_t address;
u_int8_t modem;
} __attribute__ ((packed));
/* RFCOMM RPN command */
struct rfcomm_mcc_rpn
{
u_int8_t dlci;
u_int8_t bit_rate;
u_int8_t line_settings;
u_int8_t flow_control;
u_int8_t xon_char;
u_int8_t xoff_char;
u_int16_t param_mask;
} __attribute__ ((packed));
/* RFCOMM RLS command */
struct rfcomm_mcc_rls
{
u_int8_t address;
u_int8_t status;
} __attribute__ ((packed));
/* RFCOMM PN command */
struct rfcomm_mcc_pn
{
u_int8_t dlci;
u_int8_t flow_control;
u_int8_t priority;
u_int8_t ack_timer;
u_int16_t mtu;
u_int8_t max_retrans;
u_int8_t credits;
} __attribute__ ((packed));
/* RFCOMM frame parsing macros */
#define RFCOMM_DLCI(b) (((b) & 0xfc) >> 2)
#define RFCOMM_CHANNEL(b) (((b) & 0xf8) >> 3)
#define RFCOMM_DIRECTION(b) (((b) & 0x04) >> 2)
#define RFCOMM_TYPE(b) (((b) & 0xef))
#define RFCOMM_EA(b) (((b) & 0x01))
#define RFCOMM_CR(b) (((b) & 0x02) >> 1)
#define RFCOMM_PF(b) (((b) & 0x10) >> 4)
#define RFCOMM_SRVCHANNEL(dlci) ((dlci) >> 1)
#define RFCOMM_MKADDRESS(cr, dlci) \
((((dlci) & 0x3f) << 2) | ((cr) << 1) | 0x01)
#define RFCOMM_MKCONTROL(type, pf) ((((type) & 0xef) | ((pf) << 4)))
#define RFCOMM_MKDLCI(dir, channel) ((((channel) & 0x1f) << 1) | (dir))
#define RFCOMM_MKLEN8(len) (((len) << 1) | 1)
#define RFCOMM_MKLEN16(len) ((len) << 1)
/* RFCOMM MCC macros */
#define RFCOMM_MCC_TYPE(b) (((b) & 0xfc) >> 2)
#define RFCOMM_MCC_LENGTH(b) (((b) & 0xfe) >> 1)
#define RFCOMM_MKMCC_TYPE(cr, type) ((((type) << 2) | ((cr) << 1) | 0x01))
/* RPN macros */
#define RFCOMM_RPN_DATA_BITS(line) ((line) & 0x3)
#define RFCOMM_RPN_STOP_BITS(line) (((line) >> 2) & 0x1)
#define RFCOMM_RPN_PARITY(line) (((line) >> 3) & 0x3)
#define RFCOMM_MKRPN_LINE_SETTINGS(data, stop, parity) \
(((data) & 0x3) | (((stop) & 0x1) << 2) | (((parity) & 0x3) << 3))
/*****************************************************************************
*****************************************************************************
** SOCK_STREAM RFCOMM sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_RFCOMM_SENDSPACE \
(RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 2)
#define NG_BTSOCKET_RFCOMM_RECVSPACE \
(RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 2)
/*
* Bluetooth RFCOMM session. One L2CAP connection == one RFCOMM session
*/
struct ng_btsocket_rfcomm_pcb;
struct ng_btsocket_rfcomm_session;
struct ng_btsocket_rfcomm_session {
struct socket *l2so; /* L2CAP socket */
u_int16_t state; /* session state */
#define NG_BTSOCKET_RFCOMM_SESSION_CLOSED 0
#define NG_BTSOCKET_RFCOMM_SESSION_LISTENING 1
#define NG_BTSOCKET_RFCOMM_SESSION_CONNECTING 2
#define NG_BTSOCKET_RFCOMM_SESSION_CONNECTED 3
#define NG_BTSOCKET_RFCOMM_SESSION_OPEN 4
#define NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING 5
u_int16_t flags; /* session flags */
#define NG_BTSOCKET_RFCOMM_SESSION_INITIATOR (1 << 0) /* initiator */
#define NG_BTSOCKET_RFCOMM_SESSION_LFC (1 << 1) /* local flow */
#define NG_BTSOCKET_RFCOMM_SESSION_RFC (1 << 2) /* remote flow */
#define INITIATOR(s) \
(((s)->flags & NG_BTSOCKET_RFCOMM_SESSION_INITIATOR)? 1 : 0)
u_int16_t mtu; /* default MTU */
struct ng_bt_mbufq outq; /* outgoing queue */
struct mtx session_mtx; /* session lock */
LIST_HEAD(, ng_btsocket_rfcomm_pcb) dlcs; /* active DLC */
LIST_ENTRY(ng_btsocket_rfcomm_session) next; /* link to next */
};
typedef struct ng_btsocket_rfcomm_session ng_btsocket_rfcomm_session_t;
typedef struct ng_btsocket_rfcomm_session * ng_btsocket_rfcomm_session_p;
/*
* Bluetooth RFCOMM socket PCB (DLC)
*/
struct ng_btsocket_rfcomm_pcb {
struct socket *so; /* RFCOMM socket */
struct ng_btsocket_rfcomm_session *session; /* RFCOMM session */
u_int16_t flags; /* DLC flags */
#define NG_BTSOCKET_RFCOMM_DLC_TIMO (1 << 0) /* timeout pending */
#define NG_BTSOCKET_RFCOMM_DLC_CFC (1 << 1) /* credit flow ctrl */
#define NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT (1 << 2) /* timeout happened */
#define NG_BTSOCKET_RFCOMM_DLC_DETACHED (1 << 3) /* DLC detached */
#define NG_BTSOCKET_RFCOMM_DLC_SENDING (1 << 4) /* send pending */
u_int16_t state; /* DLC state */
#define NG_BTSOCKET_RFCOMM_DLC_CLOSED 0
#define NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT 1
#define NG_BTSOCKET_RFCOMM_DLC_CONFIGURING 2
#define NG_BTSOCKET_RFCOMM_DLC_CONNECTING 3
#define NG_BTSOCKET_RFCOMM_DLC_CONNECTED 4
#define NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING 5
bdaddr_t src; /* source address */
bdaddr_t dst; /* dest. address */
u_int8_t channel; /* RFCOMM channel */
u_int8_t dlci; /* RFCOMM DLCI */
u_int8_t lmodem; /* local mdm signls */
u_int8_t rmodem; /* remote -/- */
u_int16_t mtu; /* MTU */
int16_t rx_cred; /* RX credits */
int16_t tx_cred; /* TX credits */
struct mtx pcb_mtx; /* PCB lock */
struct callout timo; /* timeout */
LIST_ENTRY(ng_btsocket_rfcomm_pcb) session_next;/* link to next */
LIST_ENTRY(ng_btsocket_rfcomm_pcb) next; /* link to next */
};
typedef struct ng_btsocket_rfcomm_pcb ng_btsocket_rfcomm_pcb_t;
typedef struct ng_btsocket_rfcomm_pcb * ng_btsocket_rfcomm_pcb_p;
#define so2rfcomm_pcb(so) \
((struct ng_btsocket_rfcomm_pcb *)((so)->so_pcb))
/*
* Bluetooth RFCOMM socket methods
*/
#ifdef _KERNEL
void ng_btsocket_rfcomm_init (void);
void ng_btsocket_rfcomm_abort (struct socket *);
void ng_btsocket_rfcomm_close (struct socket *);
int ng_btsocket_rfcomm_accept (struct socket *, struct sockaddr **);
int ng_btsocket_rfcomm_attach (struct socket *, int, struct thread *);
int ng_btsocket_rfcomm_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_rfcomm_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_rfcomm_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_rfcomm_ctloutput (struct socket *, struct sockopt *);
void ng_btsocket_rfcomm_detach (struct socket *);
int ng_btsocket_rfcomm_disconnect (struct socket *);
int ng_btsocket_rfcomm_listen (struct socket *, int, struct thread *);
int ng_btsocket_rfcomm_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_rfcomm_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_rfcomm_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* _NETGRAPH_BTSOCKET_RFCOMM_H_ */

View File

@ -0,0 +1,130 @@
/*
* ng_btsocket_sco.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket_sco.h,v 1.3 2005/10/31 18:08:52 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_SCO_H_
#define _NETGRAPH_BTSOCKET_SCO_H_
/*
* SCO routing entry
*/
struct ng_hook;
struct ng_message;
struct ng_btsocket_sco_rtentry {
bdaddr_t src; /* source BD_ADDR */
u_int16_t pkt_size; /* mtu */
u_int16_t num_pkts; /* buffer size */
int32_t pending; /* pending packets */
struct ng_hook *hook; /* downstream hook */
LIST_ENTRY(ng_btsocket_sco_rtentry) next; /* link to next */
};
typedef struct ng_btsocket_sco_rtentry ng_btsocket_sco_rtentry_t;
typedef struct ng_btsocket_sco_rtentry * ng_btsocket_sco_rtentry_p;
/*****************************************************************************
*****************************************************************************
** SOCK_SEQPACKET SCO sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_SCO_SENDSPACE 1024
#define NG_BTSOCKET_SCO_RECVSPACE (64 * 1024)
/*
* Bluetooth SCO socket PCB
*/
struct ng_btsocket_sco_pcb {
struct socket *so; /* Pointer to socket */
bdaddr_t src; /* Source address */
bdaddr_t dst; /* Destination address */
u_int16_t con_handle; /* connection handle */
u_int16_t flags; /* socket flags */
#define NG_BTSOCKET_SCO_CLIENT (1 << 0) /* socket is client */
#define NG_BTSOCKET_SCO_TIMO (1 << 1) /* timeout pending */
u_int8_t state; /* socket state */
#define NG_BTSOCKET_SCO_CLOSED 0 /* socket closed */
#define NG_BTSOCKET_SCO_CONNECTING 1 /* wait for connect */
#define NG_BTSOCKET_SCO_OPEN 2 /* socket open */
#define NG_BTSOCKET_SCO_DISCONNECTING 3 /* wait for disconnect */
struct callout timo; /* timeout */
ng_btsocket_sco_rtentry_p rt; /* routing info */
struct mtx pcb_mtx; /* pcb mutex */
LIST_ENTRY(ng_btsocket_sco_pcb) next; /* link to next PCB */
};
typedef struct ng_btsocket_sco_pcb ng_btsocket_sco_pcb_t;
typedef struct ng_btsocket_sco_pcb * ng_btsocket_sco_pcb_p;
#define so2sco_pcb(so) \
((struct ng_btsocket_sco_pcb *)((so)->so_pcb))
/*
* Bluetooth SCO socket methods
*/
#ifdef _KERNEL
void ng_btsocket_sco_init (void);
void ng_btsocket_sco_abort (struct socket *);
void ng_btsocket_sco_close (struct socket *);
int ng_btsocket_sco_accept (struct socket *, struct sockaddr **);
int ng_btsocket_sco_attach (struct socket *, int, struct thread *);
int ng_btsocket_sco_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_sco_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_sco_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_sco_ctloutput (struct socket *, struct sockopt *);
void ng_btsocket_sco_detach (struct socket *);
int ng_btsocket_sco_disconnect (struct socket *);
int ng_btsocket_sco_listen (struct socket *, int, struct thread *);
int ng_btsocket_sco_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_sco_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_sco_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* _NETGRAPH_BTSOCKET_SCO_H_ */

View File

@ -0,0 +1,113 @@
/*
* ng_h4.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_h4.h,v 1.1 2002/11/24 19:47:05 max Exp $
* $FreeBSD$
*
* Based on:
* ---------
*
* FreeBSD: src/sys/netgraph/ng_tty.h
* Author: Archie Cobbs <archie@freebsd.org>
*/
/*
* This file contains everything that application needs to know about
* Bluetooth HCI UART transport layer as per chapter H4 of the Bluetooth
* Specification Book v1.1.
*
* This file can be included by both kernel and userland applications.
*/
#ifndef _NETGRAPH_H4_H_
#define _NETGRAPH_H4_H_
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
/* Hook name */
#define NG_H4_HOOK "hook"
/* Node type name and magic cookie */
#define NG_H4_NODE_TYPE "h4"
#define NGM_H4_COOKIE 1013899512
/* Node states */
#define NG_H4_W4_PKT_IND 1 /* Waiting for packet indicator */
#define NG_H4_W4_PKT_HDR 2 /* Waiting for packet header */
#define NG_H4_W4_PKT_DATA 3 /* Waiting for packet data */
/* Debug levels */
#define NG_H4_ALERT_LEVEL 1
#define NG_H4_ERR_LEVEL 2
#define NG_H4_WARN_LEVEL 3
#define NG_H4_INFO_LEVEL 4
/**************************************************************************
**************************************************************************
** H4 node command/event parameters
**************************************************************************
**************************************************************************/
/* Reset node */
#define NGM_H4_NODE_RESET 1
/* Get node state (see states above) */
#define NGM_H4_NODE_GET_STATE 2
typedef u_int16_t ng_h4_node_state_ep;
/* Get/Set node debug level (see levels above) */
#define NGM_H4_NODE_GET_DEBUG 3
#define NGM_H4_NODE_SET_DEBUG 4
typedef u_int16_t ng_h4_node_debug_ep;
/* Get/Set max queue length for the node */
#define NGM_H4_NODE_GET_QLEN 5
#define NGM_H4_NODE_SET_QLEN 6
typedef int32_t ng_h4_node_qlen_ep;
/* Get node statistic */
#define NGM_H4_NODE_GET_STAT 7
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_h4_node_stat_ep;
/* Reset node statistic */
#define NGM_H4_NODE_RESET_STAT 8
#endif /* _NETGRAPH_H4_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,706 @@
/*
* ng_l2cap.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap.h,v 1.2 2003/04/27 00:52:26 max Exp $
* $FreeBSD$
*/
/*
* This file contains everything that application needs to know about
* Link Layer Control and Adaptation Protocol (L2CAP). All information
* was obtained from Bluetooth Specification Book v1.1.
*
* This file can be included by both kernel and userland applications.
*/
#ifndef _NETGRAPH_L2CAP_H_
#define _NETGRAPH_L2CAP_H_
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
/* Netgraph node hook names */
#define NG_L2CAP_HOOK_HCI "hci" /* HCI <-> L2CAP */
#define NG_L2CAP_HOOK_L2C "l2c" /* L2CAP <-> Upper */
#define NG_L2CAP_HOOK_CTL "ctl" /* L2CAP <-> User */
/* Node type name and type cookie */
#define NG_L2CAP_NODE_TYPE "l2cap"
#define NGM_L2CAP_COOKIE 1000774185
/**************************************************************************
**************************************************************************
** Common defines and types (L2CAP)
**************************************************************************
**************************************************************************/
/*
* Channel IDs are assigned relative to the instance of L2CAP node, i.e.
* relative to the unit. So the total number of channels that unit can have
* open at the same time is 0xffff - 0x0040 = 0xffbf (65471). This number
* does not depend on number of connections.
*/
#define NG_L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */
#define NG_L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */
#define NG_L2CAP_CLT_CID 0x0002 /* connectionless channel ID */
#define NG_L2CAP_A2MP_CID 0x0003
#define NG_L2CAP_ATT_CID 0x0004
#define NG_L2CAP_LESIGNAL_CID 0x0005
#define NG_L2CAP_SMP_CID 0x0006
/* 0x0007 - 0x003f Reserved */
#define NG_L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */
#define NG_L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */
#define NG_L2CAP_LELAST_CID 0x007f
/* L2CAP MTU */
#define NG_L2CAP_MTU_LE_MINIMAM 23
#define NG_L2CAP_MTU_MINIMUM 48
#define NG_L2CAP_MTU_DEFAULT 672
#define NG_L2CAP_MTU_MAXIMUM 0xffff
/* L2CAP flush and link timeouts */
#define NG_L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */
#define NG_L2CAP_LINK_TIMO_DEFAULT 0xffff
/* L2CAP Command Reject reasons */
#define NG_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define NG_L2CAP_REJ_MTU_EXCEEDED 0x0001
#define NG_L2CAP_REJ_INVALID_CID 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* Protocol/Service Multioplexor (PSM) values */
#define NG_L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */
#define NG_L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */
#define NG_L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */
#define NG_L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */
/* 0x0006 - 0x1000 - reserved for future use */
/* L2CAP Connection response command result codes */
#define NG_L2CAP_SUCCESS 0x0000
#define NG_L2CAP_PENDING 0x0001
#define NG_L2CAP_PSM_NOT_SUPPORTED 0x0002
#define NG_L2CAP_SEQUIRY_BLOCK 0x0003
#define NG_L2CAP_NO_RESOURCES 0x0004
#define NG_L2CAP_TIMEOUT 0xeeee
#define NG_L2CAP_UNKNOWN 0xffff
/* 0x0005 - 0xffff - reserved for future use */
/* L2CAP Connection response status codes */
#define NG_L2CAP_NO_INFO 0x0000
#define NG_L2CAP_AUTH_PENDING 0x0001
#define NG_L2CAP_AUTZ_PENDING 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration response result codes */
#define NG_L2CAP_UNACCEPTABLE_PARAMS 0x0001
#define NG_L2CAP_REJECT 0x0002
#define NG_L2CAP_UNKNOWN_OPTION 0x0003
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration options */
#define NG_L2CAP_OPT_CFLAG_BIT 0x0001
#define NG_L2CAP_OPT_CFLAG(flags) ((flags) & NG_L2CAP_OPT_CFLAG_BIT)
#define NG_L2CAP_OPT_HINT_BIT 0x80
#define NG_L2CAP_OPT_HINT(type) ((type) & NG_L2CAP_OPT_HINT_BIT)
#define NG_L2CAP_OPT_HINT_MASK 0x7f
#define NG_L2CAP_OPT_MTU 0x01
#define NG_L2CAP_OPT_MTU_SIZE sizeof(u_int16_t)
#define NG_L2CAP_OPT_FLUSH_TIMO 0x02
#define NG_L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(u_int16_t)
#define NG_L2CAP_OPT_QOS 0x03
#define NG_L2CAP_OPT_QOS_SIZE sizeof(ng_l2cap_flow_t)
/* 0x4 - 0xff - reserved for future use */
/* L2CAP Information request type codes */
#define NG_L2CAP_CONNLESS_MTU 0x0001
/* 0x0002 - 0xffff - reserved for future use */
/* L2CAP Information response codes */
#define NG_L2CAP_NOT_SUPPORTED 0x0001
/* 0x0002 - 0xffff - reserved for future use */
/* L2CAP flow control */
typedef struct {
u_int8_t flags; /* reserved for future use */
u_int8_t service_type; /* service type */
u_int32_t token_rate; /* bytes per second */
u_int32_t token_bucket_size; /* bytes */
u_int32_t peak_bandwidth; /* bytes per second */
u_int32_t latency; /* microseconds */
u_int32_t delay_variation; /* microseconds */
} __attribute__ ((packed)) ng_l2cap_flow_t;
typedef ng_l2cap_flow_t * ng_l2cap_flow_p;
/**************************************************************************
**************************************************************************
** Link level defines, headers and types
**************************************************************************
**************************************************************************/
/* L2CAP header */
typedef struct {
u_int16_t length; /* payload size */
u_int16_t dcid; /* destination channel ID */
} __attribute__ ((packed)) ng_l2cap_hdr_t;
/* L2CAP ConnectionLess Traffic (CLT) (if destination cid == 0x2) */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
} __attribute__ ((packed)) ng_l2cap_clt_hdr_t;
#define NG_L2CAP_CLT_MTU_MAXIMUM \
(NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_clt_hdr_t))
/* L2CAP command header */
typedef struct {
u_int8_t code; /* command OpCode */
u_int8_t ident; /* identifier to match request and response */
u_int16_t length; /* command parameters length */
} __attribute__ ((packed)) ng_l2cap_cmd_hdr_t;
/* L2CAP Command Reject */
#define NG_L2CAP_CMD_REJ 0x01
typedef struct {
u_int16_t reason; /* reason to reject command */
/* u_int8_t data[]; -- optional data (depends on reason) */
} __attribute__ ((packed)) ng_l2cap_cmd_rej_cp;
/* CommandReject data */
typedef union {
/* NG_L2CAP_REJ_MTU_EXCEEDED */
struct {
u_int16_t mtu; /* actual signaling MTU */
} __attribute__ ((packed)) mtu;
/* NG_L2CAP_REJ_INVALID_CID */
struct {
u_int16_t scid; /* local CID */
u_int16_t dcid; /* remote CID */
} __attribute__ ((packed)) cid;
} ng_l2cap_cmd_rej_data_t;
typedef ng_l2cap_cmd_rej_data_t * ng_l2cap_cmd_rej_data_p;
/* L2CAP Connection Request */
#define NG_L2CAP_CON_REQ 0x02
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor (PSM) */
u_int16_t scid; /* source channel ID */
} __attribute__ ((packed)) ng_l2cap_con_req_cp;
/* L2CAP Connection Response */
#define NG_L2CAP_CON_RSP 0x03
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t scid; /* source channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* more info if result != 0x00 */
} __attribute__ ((packed)) ng_l2cap_con_rsp_cp;
/* L2CAP Configuration Request */
#define NG_L2CAP_CFG_REQ 0x04
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t flags; /* flags */
/* u_int8_t options[] -- options */
} __attribute__ ((packed)) ng_l2cap_cfg_req_cp;
/* L2CAP Configuration Response */
#define NG_L2CAP_CFG_RSP 0x05
typedef struct {
u_int16_t scid; /* source channel ID */
u_int16_t flags; /* flags */
u_int16_t result; /* 0x00 - success */
/* u_int8_t options[] -- options */
} __attribute__ ((packed)) ng_l2cap_cfg_rsp_cp;
/* L2CAP configuration option */
typedef struct {
u_int8_t type;
u_int8_t length;
/* u_int8_t value[] -- option value (depends on type) */
} __attribute__ ((packed)) ng_l2cap_cfg_opt_t;
typedef ng_l2cap_cfg_opt_t * ng_l2cap_cfg_opt_p;
/* L2CAP configuration option value */
typedef union {
u_int16_t mtu; /* NG_L2CAP_OPT_MTU */
u_int16_t flush_timo; /* NG_L2CAP_OPT_FLUSH_TIMO */
ng_l2cap_flow_t flow; /* NG_L2CAP_OPT_QOS */
uint16_t encryption;
} ng_l2cap_cfg_opt_val_t;
typedef ng_l2cap_cfg_opt_val_t * ng_l2cap_cfg_opt_val_p;
/* L2CAP Disconnect Request */
#define NG_L2CAP_DISCON_REQ 0x06
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t scid; /* source channel ID */
} __attribute__ ((packed)) ng_l2cap_discon_req_cp;
/* L2CAP Disconnect Response */
#define NG_L2CAP_DISCON_RSP 0x07
typedef ng_l2cap_discon_req_cp ng_l2cap_discon_rsp_cp;
/* L2CAP Echo Request */
#define NG_L2CAP_ECHO_REQ 0x08
/* No command parameters, only optional data */
/* L2CAP Echo Response */
#define NG_L2CAP_ECHO_RSP 0x09
#define NG_L2CAP_MAX_ECHO_SIZE \
(NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_cmd_hdr_t))
/* No command parameters, only optional data */
/* L2CAP Information Request */
#define NG_L2CAP_INFO_REQ 0x0a
typedef struct {
u_int16_t type; /* requested information type */
} __attribute__ ((packed)) ng_l2cap_info_req_cp;
/* L2CAP Information Response */
#define NG_L2CAP_INFO_RSP 0x0b
typedef struct {
u_int16_t type; /* requested information type */
u_int16_t result; /* 0x00 - success */
/* u_int8_t info[] -- info data (depends on type)
*
* NG_L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU
*/
} __attribute__ ((packed)) ng_l2cap_info_rsp_cp;
typedef union {
/* NG_L2CAP_CONNLESS_MTU */
struct {
u_int16_t mtu;
} __attribute__ ((packed)) mtu;
} ng_l2cap_info_rsp_data_t;
typedef ng_l2cap_info_rsp_data_t * ng_l2cap_info_rsp_data_p;
#define NG_L2CAP_CMD_PARAM_UPDATE_REQUEST 0x12
typedef struct {
uint16_t interval_min;
uint16_t interval_max;
uint16_t slave_latency;
uint16_t timeout_mpl;
} __attribute__ ((packed)) ng_l2cap_param_update_req_cp;
#define NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE 0x13
#define NG_L2CAP_UPDATE_PARAM_ACCEPT 0
#define NG_L2CAP_UPDATE_PARAM_REJECT 1
//typedef uint16_t update_response;
/**************************************************************************
**************************************************************************
** Upper layer protocol interface. L2CA_xxx messages
**************************************************************************
**************************************************************************/
/*
* NOTE! NOTE! NOTE!
*
* Bluetooth specification says that L2CA_xxx request must block until
* response is ready. We are not allowed to block in Netgraph, so we
* need to queue request and save some information that can be used
* later and help match request and response.
*
* The idea is to use "token" field from Netgraph message header. The
* upper layer protocol _MUST_ populate "token". L2CAP will queue request
* (using L2CAP command descriptor) and start processing. Later, when
* response is ready or timeout has occur L2CAP layer will create new
* Netgraph message, set "token" and RESP flag and send the message to
* the upper layer protocol.
*
* L2CA_xxx_Ind messages _WILL_NOT_ populate "token" and _WILL_NOT_
* set RESP flag. There is no reason for this, because they are just
* notifications and do not require acknowlegment.
*
* NOTE: This is _NOT_ what NG_MKRESPONSE and NG_RESPOND_MSG do, however
* it is somewhat similar.
*/
/* L2CA data packet header */
typedef struct {
u_int32_t token; /* token to use in L2CAP_L2CA_WRITE */
u_int16_t length; /* length of the data */
u_int16_t lcid; /* local channel ID */
uint16_t idtype;
} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t;
#define NG_L2CAP_L2CA_IDTYPE_BREDR 0
#define NG_L2CAP_L2CA_IDTYPE_ATT 1
#define NG_L2CAP_L2CA_IDTYPE_LE 2
#define NG_L2CAP_L2CA_IDTYPE_SMP 3
/* L2CA_Connect */
#define NGM_L2CAP_L2CA_CON 0x80
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
bdaddr_t bdaddr; /* remote unit address */
uint8_t linktype;
uint8_t idtype;
} ng_l2cap_l2ca_con_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local channel ID */
uint16_t idtype; /*ID type*/
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if result != 0x00 */
uint8_t encryption;
} ng_l2cap_l2ca_con_op;
/* L2CA_ConnectInd */
#define NGM_L2CAP_L2CA_CON_IND 0x81
/* L2CAP -> Upper */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t lcid; /* local channel ID */
u_int16_t psm; /* Procotol/Service Multiplexor */
u_int8_t ident; /* identifier */
u_int8_t linktype; /* link type*/
} ng_l2cap_l2ca_con_ind_ip;
/* No output parameters */
/* L2CA_ConnectRsp */
#define NGM_L2CAP_L2CA_CON_RSP 0x82
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int8_t ident; /* "ident" from L2CAP_ConnectInd event */
u_int8_t linktype; /*link type */
u_int16_t lcid; /* local channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if response != 0x00 */
} ng_l2cap_l2ca_con_rsp_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
} ng_l2cap_l2ca_con_rsp_op;
/* L2CA_Config */
#define NGM_L2CAP_L2CA_CFG 0x83
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t imtu; /* receiving MTU for the local channel */
ng_l2cap_flow_t oflow; /* out flow */
u_int16_t flush_timo; /* flush timeout (msec) */
u_int16_t link_timo; /* link timeout (msec) */
} ng_l2cap_l2ca_cfg_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t imtu; /* sending MTU for the remote channel */
ng_l2cap_flow_t oflow; /* out flow */
u_int16_t flush_timo; /* flush timeout (msec) */
} ng_l2cap_l2ca_cfg_op;
/* L2CA_ConfigRsp */
#define NGM_L2CAP_L2CA_CFG_RSP 0x84
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t omtu; /* sending MTU for the local channel */
ng_l2cap_flow_t iflow; /* in FLOW */
} ng_l2cap_l2ca_cfg_rsp_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - sucsess */
} ng_l2cap_l2ca_cfg_rsp_op;
/* L2CA_ConfigInd */
#define NGM_L2CAP_L2CA_CFG_IND 0x85
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t omtu; /* outgoing MTU for the local channel */
ng_l2cap_flow_t iflow; /* in flow */
u_int16_t flush_timo; /* flush timeout (msec) */
} ng_l2cap_l2ca_cfg_ind_ip;
/* No output parameters */
/* L2CA_QoSViolationInd */
#define NGM_L2CAP_L2CA_QOS_IND 0x86
/* L2CAP -> Upper */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
} ng_l2cap_l2ca_qos_ind_ip;
/* No output parameters */
/* L2CA_Disconnect */
#define NGM_L2CAP_L2CA_DISCON 0x87
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t idtype;
} ng_l2cap_l2ca_discon_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - sucsess */
} ng_l2cap_l2ca_discon_op;
/* L2CA_DisconnectInd */
#define NGM_L2CAP_L2CA_DISCON_IND 0x88
/* L2CAP -> Upper */
typedef ng_l2cap_l2ca_discon_ip ng_l2cap_l2ca_discon_ind_ip;
/* No output parameters */
/* L2CA_Write response */
#define NGM_L2CAP_L2CA_WRITE 0x89
/* No input parameters */
/* L2CAP -> Upper */
typedef struct {
int result; /* result (0x00 - success) */
u_int16_t length; /* amount of data written */
u_int16_t lcid; /* local channel ID */
uint16_t idtype;
} ng_l2cap_l2ca_write_op;
/* L2CA_GroupCreate */
#define NGM_L2CAP_L2CA_GRP_CREATE 0x8a
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
} ng_l2cap_l2ca_grp_create_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_create_op;
/* L2CA_GroupClose */
#define NGM_L2CAP_L2CA_GRP_CLOSE 0x8b
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_close_ip;
#if 0
/* L2CAP -> Upper */
* typedef struct {
* u_int16_t result; /* 0x00 - success */
* } ng_l2cap_l2ca_grp_close_op;
#endif
/* L2CA_GroupAddMember */
#define NGM_L2CAP_L2CA_GRP_ADD_MEMBER 0x8c
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
bdaddr_t bdaddr; /* remote unit address */
} ng_l2cap_l2ca_grp_add_member_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
} ng_l2cap_l2ca_grp_add_member_op;
/* L2CA_GroupRemoveMember */
#define NGM_L2CAP_L2CA_GRP_REM_MEMBER 0x8d
/* Upper -> L2CAP */
typedef ng_l2cap_l2ca_grp_add_member_ip ng_l2cap_l2ca_grp_rem_member_ip;
/* L2CAP -> Upper */
#if 0
* typedef ng_l2cap_l2ca_grp_add_member_op ng_l2cap_l2ca_grp_rem_member_op;
#endif
/* L2CA_GroupMembeship */
#define NGM_L2CAP_L2CA_GRP_MEMBERSHIP 0x8e
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_get_members_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t nmembers; /* number of group members */
/* bdaddr_t members[] -- group memebers */
} ng_l2cap_l2ca_grp_get_members_op;
/* L2CA_Ping */
#define NGM_L2CAP_L2CA_PING 0x8f
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t echo_size; /* size of echo data in bytes */
/* u_int8_t echo_data[] -- echo data */
} ng_l2cap_l2ca_ping_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
bdaddr_t bdaddr; /* remote unit address */
u_int16_t echo_size; /* size of echo data in bytes */
/* u_int8_t echo_data[] -- echo data */
} ng_l2cap_l2ca_ping_op;
/* L2CA_GetInfo */
#define NGM_L2CAP_L2CA_GET_INFO 0x90
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t info_type; /* info type */
uint8_t linktype;
uint8_t unused;
} ng_l2cap_l2ca_get_info_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t info_size; /* size of info data in bytes */
/* u_int8_t info_data[] -- info data */
} ng_l2cap_l2ca_get_info_op;
/* L2CA_EnableCLT/L2CA_DisableCLT */
#define NGM_L2CAP_L2CA_ENABLE_CLT 0x91
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
u_int16_t enable; /* 0x00 - disable */
} ng_l2cap_l2ca_enable_clt_ip;
#if 0
/* L2CAP -> Upper */
* typedef struct {
* u_int16_t result; /* 0x00 - success */
* } ng_l2cap_l2ca_enable_clt_op;
#endif
#define NGM_L2CAP_L2CA_ENC_CHANGE 0x92
typedef struct {
uint16_t lcid;
uint16_t result;
uint8_t idtype;
} ng_l2cap_l2ca_enc_chg_op;
/**************************************************************************
**************************************************************************
** L2CAP node messages
**************************************************************************
**************************************************************************/
/* L2CAP connection states */
#define NG_L2CAP_CON_CLOSED 0 /* connection closed */
#define NG_L2CAP_W4_LP_CON_CFM 1 /* waiting... */
#define NG_L2CAP_CON_OPEN 2 /* connection open */
/* L2CAP channel states */
#define NG_L2CAP_CLOSED 0 /* channel closed */
#define NG_L2CAP_W4_L2CAP_CON_RSP 1 /* wait for L2CAP resp. */
#define NG_L2CAP_W4_L2CA_CON_RSP 2 /* wait for upper resp. */
#define NG_L2CAP_CONFIG 3 /* L2CAP configuration */
#define NG_L2CAP_OPEN 4 /* channel open */
#define NG_L2CAP_W4_L2CAP_DISCON_RSP 5 /* wait for L2CAP discon. */
#define NG_L2CAP_W4_L2CA_DISCON_RSP 6 /* wait for upper discon. */
/* Node flags */
#define NG_L2CAP_CLT_SDP_DISABLED (1 << 0) /* disable SDP CLT */
#define NG_L2CAP_CLT_RFCOMM_DISABLED (1 << 1) /* disable RFCOMM CLT */
#define NG_L2CAP_CLT_TCP_DISABLED (1 << 2) /* disable TCP CLT */
/* Debug levels */
#define NG_L2CAP_ALERT_LEVEL 1
#define NG_L2CAP_ERR_LEVEL 2
#define NG_L2CAP_WARN_LEVEL 3
#define NG_L2CAP_INFO_LEVEL 4
/* Get node flags (see flags above) */
#define NGM_L2CAP_NODE_GET_FLAGS 0x400 /* L2CAP -> User */
typedef u_int16_t ng_l2cap_node_flags_ep;
/* Get/Set debug level (see levels above) */
#define NGM_L2CAP_NODE_GET_DEBUG 0x401 /* L2CAP -> User */
#define NGM_L2CAP_NODE_SET_DEBUG 0x402 /* User -> L2CAP */
typedef u_int16_t ng_l2cap_node_debug_ep;
#define NGM_L2CAP_NODE_HOOK_INFO 0x409 /* L2CAP -> Upper */
typedef struct {
bdaddr_t addr;
}ng_l2cap_node_hook_info_ep;
#define NGM_L2CAP_NODE_GET_CON_LIST 0x40a /* L2CAP -> User */
typedef struct {
u_int32_t num_connections; /* number of connections */
} ng_l2cap_node_con_list_ep;
/* Connection flags */
#define NG_L2CAP_CON_TX (1 << 0) /* sending data */
#define NG_L2CAP_CON_RX (1 << 1) /* receiving data */
#define NG_L2CAP_CON_OUTGOING (1 << 2) /* outgoing connection */
#define NG_L2CAP_CON_LP_TIMO (1 << 3) /* LP timeout */
#define NG_L2CAP_CON_AUTO_DISCON_TIMO (1 << 4) /* auto discon. timeout */
#define NG_L2CAP_CON_DYING (1 << 5) /* connection is dying */
typedef struct {
u_int8_t state; /* connection state */
u_int8_t flags; /* flags */
int16_t pending; /* num. pending packets */
u_int16_t con_handle; /* connection handle */
bdaddr_t remote; /* remote bdaddr */
} ng_l2cap_node_con_ep;
#define NG_L2CAP_MAX_CON_NUM \
((0xffff - sizeof(ng_l2cap_node_con_list_ep))/sizeof(ng_l2cap_node_con_ep))
#define NGM_L2CAP_NODE_GET_CHAN_LIST 0x40b /* L2CAP -> User */
typedef struct {
u_int32_t num_channels; /* number of channels */
} ng_l2cap_node_chan_list_ep;
typedef struct {
u_int32_t state; /* channel state */
u_int16_t scid; /* source (local) channel ID */
u_int16_t dcid; /* destination (remote) channel ID */
u_int16_t imtu; /* incoming MTU */
u_int16_t omtu; /* outgoing MTU */
u_int16_t psm; /* PSM */
bdaddr_t remote; /* remote bdaddr */
} ng_l2cap_node_chan_ep;
#define NG_L2CAP_MAX_CHAN_NUM \
((0xffff - sizeof(ng_l2cap_node_chan_list_ep))/sizeof(ng_l2cap_node_chan_ep))
#define NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO 0x40c /* L2CAP -> User */
#define NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO 0x40d /* User -> L2CAP */
typedef u_int16_t ng_l2cap_node_auto_discon_ep;
#endif /* ndef _NETGRAPH_L2CAP_H_ */

View File

@ -0,0 +1,91 @@
/*
* ng_ubt.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_ubt.h,v 1.6 2003/04/13 21:34:42 max Exp $
* $FreeBSD$
*/
#ifndef _NG_UBT_H_
#define _NG_UBT_H_
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
#define NG_UBT_NODE_TYPE "ubt"
#define NG_UBT_HOOK "hook"
#define NGM_UBT_COOKIE 1021837971
/* Debug levels */
#define NG_UBT_ALERT_LEVEL 1
#define NG_UBT_ERR_LEVEL 2
#define NG_UBT_WARN_LEVEL 3
#define NG_UBT_INFO_LEVEL 4
/**************************************************************************
**************************************************************************
** UBT node command/event parameters
**************************************************************************
**************************************************************************/
#define NGM_UBT_NODE_SET_DEBUG 1 /* set debug level */
#define NGM_UBT_NODE_GET_DEBUG 2 /* get debug level */
typedef u_int16_t ng_ubt_node_debug_ep;
#define NGM_UBT_NODE_SET_QLEN 3 /* set queue length */
#define NGM_UBT_NODE_GET_QLEN 4 /* get queue length */
typedef struct {
int32_t queue; /* queue index */
#define NGM_UBT_NODE_QUEUE_CMD 1 /* commands */
#define NGM_UBT_NODE_QUEUE_ACL 2 /* ACL data */
#define NGM_UBT_NODE_QUEUE_SCO 3 /* SCO data */
int32_t qlen; /* queue length */
} ng_ubt_node_qlen_ep;
#define NGM_UBT_NODE_GET_STAT 5 /* get statistic */
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_ubt_node_stat_ep;
#define NGM_UBT_NODE_RESET_STAT 6 /* reset statistic */
#define NGM_UBT_NODE_DEV_NODES 7 /* on/off device interface */
typedef u_int16_t ng_ubt_node_dev_nodes_ep;
#endif /* ndef _NG_UBT_H_ */

View File

@ -0,0 +1,43 @@
$Id: TODO,v 1.1 2002/11/24 19:47:06 max Exp $
$FreeBSD$
FIXME/TODO list
0) Ping itself. Should L2CAP layer loopback data?
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, so
it should be fine as long as Netgraph is SMP safe. Just need to
verify it.
2) Understand and implement L2CAP QoS
Will fix later. I only have CSR based hardware and it does not
support QoS.
3) Better functions to manage CIDs and command ident's.
Resource manager is not good because it uses MTX_DEF mutexes,
(i.e. could block/sleep)
4) Implement group channels (multicast)
Will fix later
5) Add bytes/packets counters and commands to get/reset them
Will fix later. What to count?
6) Better way to get information about channels
L2CAP can support about 65000 channels. Need define some good way
to get data from kernel to user space. For example if we need to pass
1K of information for every channel, then worst case is that we need
to pass 65Mbytes of data from kernel to user space. Not good.
7) Deal properly with "shutdown"s and hook "disconnect"s
For now we destroy all channels when upstream hook is disconnected.
Is there a better way to handle this?

View File

@ -0,0 +1,411 @@
/*
* ng_l2cap_cmds.c
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_cmds.c,v 1.2 2003/09/08 19:11:45 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
/******************************************************************************
******************************************************************************
** L2CAP commands processing module
******************************************************************************
******************************************************************************/
/*
* Process L2CAP command queue on connection
*/
void
ng_l2cap_con_wakeup(ng_l2cap_con_p con)
{
ng_l2cap_cmd_p cmd = NULL;
struct mbuf *m = NULL;
int error = 0;
/* Find first non-pending command in the queue */
TAILQ_FOREACH(cmd, &con->cmd_list, next) {
KASSERT((cmd->con == con),
("%s: %s - invalid connection pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
break;
}
if (cmd == NULL)
return;
/* Detach command packet */
m = cmd->aux;
cmd->aux = NULL;
/* Process command */
switch (cmd->code) {
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
/*
* Do not check return ng_l2cap_lp_send() value, because
* in these cases we do not really have a graceful way out.
* ECHO and INFO responses are internal to the stack and not
* visible to user. REJect is just being nice to remote end
* (otherwise remote end will timeout anyway). DISCON is
* probably most interesting here, however, if it fails
* there is nothing we can do anyway.
*/
(void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CMD_REJ:
(void) ng_l2cap_lp_send(con,
(con->linktype == NG_HCI_LINK_ACL)?
NG_L2CAP_SIGNAL_CID:
NG_L2CAP_LESIGNAL_CID
, m);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CON_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
NG_L2CAP_NO_RESOURCES, 0);
ng_l2cap_free_chan(cmd->ch); /* will free commands */
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_CON_RSP:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
if (cmd->ch != NULL) {
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS :
NG_L2CAP_NO_RESOURCES);
if (error != 0)
ng_l2cap_free_chan(cmd->ch);
}
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CFG_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
NG_L2CAP_NO_RESOURCES);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_CFG_RSP:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
if (cmd->ch != NULL)
ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS :
NG_L2CAP_NO_RESOURCES);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_DISCON_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
if (error != 0)
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_ECHO_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_ping_rsp(con, cmd->token,
NG_L2CAP_NO_RESOURCES, NULL);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_INFO_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
NG_L2CAP_NO_RESOURCES, NULL);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NGM_L2CAP_L2CA_WRITE: {
int length = m->m_pkthdr.len;
if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
if (m == NULL)
error = ENOBUFS;
else
mtod(m, ng_l2cap_clt_hdr_t *)->psm =
htole16(cmd->ch->psm);
}
if (error == 0)
error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
length);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} break;
case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
/*TBD.*/
/* XXX FIXME add other commands */
default:
panic(
"%s: %s - unknown command code=%d\n",
__func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
break;
}
} /* ng_l2cap_con_wakeup */
/*
* We have failed to open ACL connection to the remote unit. Could be negative
* confirmation or timeout. So fail any "delayed" commands, notify upper layer,
* remove all channels and remove connection descriptor.
*/
void
ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
{
ng_l2cap_p l2cap = con->l2cap;
ng_l2cap_cmd_p cmd = NULL;
ng_l2cap_chan_p ch = NULL;
NG_L2CAP_INFO(
"%s: %s - ACL connection failed, result=%d\n",
__func__, NG_NODE_NAME(l2cap->node), result);
/* Connection is dying */
con->flags |= NG_L2CAP_CON_DYING;
/* Clean command queue */
while (!TAILQ_EMPTY(&con->cmd_list)) {
cmd = TAILQ_FIRST(&con->cmd_list);
ng_l2cap_unlink_cmd(cmd);
if(cmd->flags & NG_L2CAP_CMD_PENDING)
ng_l2cap_command_untimeout(cmd);
KASSERT((cmd->con == con),
("%s: %s - invalid connection pointer!\n",
__func__, NG_NODE_NAME(l2cap->node)));
switch (cmd->code) {
case NG_L2CAP_CMD_REJ:
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
break;
case NG_L2CAP_CON_REQ:
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
break;
case NG_L2CAP_CON_RSP:
if (cmd->ch != NULL)
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
result);
break;
case NG_L2CAP_CFG_REQ:
case NG_L2CAP_CFG_RSP:
case NGM_L2CAP_L2CA_WRITE:
ng_l2cap_l2ca_discon_ind(cmd->ch);
break;
case NG_L2CAP_DISCON_REQ:
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
NG_L2CAP_SUCCESS);
break;
case NG_L2CAP_ECHO_REQ:
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
result, NULL);
break;
case NG_L2CAP_INFO_REQ:
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
result, NULL);
break;
/* XXX FIXME add other commands */
default:
panic(
"%s: %s - unexpected command code=%d\n",
__func__, NG_NODE_NAME(l2cap->node), cmd->code);
break;
}
if (cmd->ch != NULL)
ng_l2cap_free_chan(cmd->ch);
ng_l2cap_free_cmd(cmd);
}
/*
* There still might be channels (in OPEN state?) that
* did not submit any commands, so disconnect them
*/
LIST_FOREACH(ch, &l2cap->chan_list, next)
if (ch->con == con)
ng_l2cap_l2ca_discon_ind(ch);
/* Free connection descriptor */
ng_l2cap_free_con(con);
} /* ng_l2cap_con_fail */
/*
* Process L2CAP command timeout. In general - notify upper layer and destroy
* channel. Do not pay much attention to return code, just do our best.
*/
void
ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_l2cap_p l2cap = NULL;
ng_l2cap_con_p con = NULL;
ng_l2cap_cmd_p cmd = NULL;
u_int16_t con_handle = (arg2 & 0x0ffff);
u_int8_t ident = ((arg2 >> 16) & 0xff);
if (NG_NODE_NOT_VALID(node)) {
printf("%s: Netgraph node is not valid\n", __func__);
return;
}
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ALERT(
"%s: %s - could not find connection, con_handle=%d\n",
__func__, NG_NODE_NAME(node), con_handle);
return;
}
cmd = ng_l2cap_cmd_by_ident(con, ident);
if (cmd == NULL) {
NG_L2CAP_ALERT(
"%s: %s - could not find command, con_handle=%d, ident=%d\n",
__func__, NG_NODE_NAME(node), con_handle, ident);
return;
}
cmd->flags &= ~NG_L2CAP_CMD_PENDING;
ng_l2cap_unlink_cmd(cmd);
switch (cmd->code) {
case NG_L2CAP_CON_REQ:
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
ng_l2cap_free_chan(cmd->ch);
break;
case NG_L2CAP_CFG_REQ:
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
break;
case NG_L2CAP_DISCON_REQ:
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
break;
case NG_L2CAP_ECHO_REQ:
/* Echo request timed out. Let the upper layer know */
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
NG_L2CAP_TIMEOUT, NULL);
break;
case NG_L2CAP_INFO_REQ:
/* Info request timed out. Let the upper layer know */
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
NG_L2CAP_TIMEOUT, NULL);
break;
/* XXX FIXME add other commands */
default:
panic(
"%s: %s - unexpected command code=%d\n",
__func__, NG_NODE_NAME(l2cap->node), cmd->code);
break;
}
ng_l2cap_free_cmd(cmd);
} /* ng_l2cap_process_command_timeout */

View File

@ -0,0 +1,428 @@
/*
* ng_l2cap_cmds.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_cmds.h,v 1.4 2003/04/01 18:15:26 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_CMDS_H_
#define _NETGRAPH_L2CAP_CMDS_H_
/******************************************************************************
******************************************************************************
** L2CAP to L2CAP signaling command macros
******************************************************************************
******************************************************************************/
/*
* Note: All L2CAP implementations are required to support minimal signaling
* MTU of 48 bytes. In order to simplify things we will send one command
* per one L2CAP packet. Given evrything above we can assume that one
* signaling packet will fit into single mbuf.
*/
/* L2CAP_CommandRej */
#define _ng_l2cap_cmd_rej(_m, _ident, _reason, _mtu, _scid, _dcid) \
do { \
struct _cmd_rej { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cmd_rej_cp param; \
ng_l2cap_cmd_rej_data_t data; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
c = mtod((_m), struct _cmd_rej *); \
c->hdr.code = NG_L2CAP_CMD_REJ; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.reason = htole16((_reason)); \
\
if ((_reason) == NG_L2CAP_REJ_MTU_EXCEEDED) { \
c->data.mtu.mtu = htole16((_mtu)); \
c->hdr.length += sizeof(c->data.mtu); \
} else if ((_reason) == NG_L2CAP_REJ_INVALID_CID) { \
c->data.cid.scid = htole16((_scid)); \
c->data.cid.dcid = htole16((_dcid)); \
c->hdr.length += sizeof(c->data.cid); \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + \
c->hdr.length; \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
/* L2CAP_ConnectReq */
#define _ng_l2cap_con_req(_m, _ident, _psm, _scid) \
do { \
struct _con_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_con_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _con_req *); \
c->hdr.code = NG_L2CAP_CON_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.psm = htole16((_psm)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CAP_ConnectRsp */
#define _ng_l2cap_con_rsp(_m, _ident, _dcid, _scid, _result, _status) \
do { \
struct _con_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_con_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _con_rsp *); \
c->hdr.code = NG_L2CAP_CON_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
c->param.result = htole16((_result)); \
c->param.status = htole16((_status)); \
} while (0)
/* L2CAP_ConfigReq */
#define _ng_l2cap_cfg_req(_m, _ident, _dcid, _flags, _data) \
do { \
struct _cfg_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cfg_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) { \
NG_FREE_M((_data)); \
break; \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _cfg_req *); \
c->hdr.code = NG_L2CAP_CFG_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.dcid = htole16((_dcid)); \
c->param.flags = htole16((_flags)); \
if ((_data) != NULL) { \
int l = (_data)->m_pkthdr.len; \
\
m_cat((_m), (_data)); \
c->hdr.length += l; \
(_m)->m_pkthdr.len += l; \
} \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
/* L2CAP_ConfigRsp */
#define _ng_l2cap_cfg_rsp(_m, _ident, _scid, _flags, _result, _data) \
do { \
struct _cfg_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cfg_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) { \
NG_FREE_M((_data)); \
break; \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _cfg_rsp *); \
c->hdr.code = NG_L2CAP_CFG_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.scid = htole16((_scid)); \
c->param.flags = htole16((_flags)); \
c->param.result = htole16((_result)); \
if ((_data) != NULL) { \
int l = (_data)->m_pkthdr.len; \
\
m_cat((_m), (_data)); \
c->hdr.length += l; \
(_m)->m_pkthdr.len += l; \
} \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
#define _ng_l2cap_cmd_urs(_m, _ident, _result) \
do { \
struct _cmd_urs{ \
ng_l2cap_cmd_hdr_t hdr; \
uint16_t result; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _cmd_urs *); \
c->hdr.code = NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->result); \
\
c->result = htole16((_result)); \
} while (0)
/* Build configuration options */
#define _ng_l2cap_build_cfg_options(_m, _mtu, _flush_timo, _flow) \
do { \
u_int8_t *p = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = 0; \
p = mtod((_m), u_int8_t *); \
\
if ((_mtu) != NULL) { \
struct _cfg_opt_mtu { \
ng_l2cap_cfg_opt_t hdr; \
u_int16_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_mtu *) p; \
o->hdr.type = NG_L2CAP_OPT_MTU; \
o->hdr.length = sizeof(o->val); \
o->val = htole16(*(u_int16_t *)(_mtu)); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
p += sizeof(*o); \
} \
\
if ((_flush_timo) != NULL) { \
struct _cfg_opt_flush { \
ng_l2cap_cfg_opt_t hdr; \
u_int16_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_flush *) p; \
o->hdr.type = NG_L2CAP_OPT_FLUSH_TIMO; \
o->hdr.length = sizeof(o->val); \
o->val = htole16(*(u_int16_t *)(_flush_timo)); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
p += sizeof(*o); \
} \
\
if ((_flow) != NULL) { \
struct _cfg_opt_flow { \
ng_l2cap_cfg_opt_t hdr; \
ng_l2cap_flow_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_flow *) p; \
o->hdr.type = NG_L2CAP_OPT_QOS; \
o->hdr.length = sizeof(o->val); \
o->val.flags = ((ng_l2cap_flow_p)(_flow))->flags; \
o->val.service_type = ((ng_l2cap_flow_p) \
(_flow))->service_type; \
o->val.token_rate = \
htole32(((ng_l2cap_flow_p)(_flow))->token_rate);\
o->val.token_bucket_size = \
htole32(((ng_l2cap_flow_p) \
(_flow))->token_bucket_size); \
o->val.peak_bandwidth = \
htole32(((ng_l2cap_flow_p) \
(_flow))->peak_bandwidth); \
o->val.latency = htole32(((ng_l2cap_flow_p) \
(_flow))->latency); \
o->val.delay_variation = \
htole32(((ng_l2cap_flow_p) \
(_flow))->delay_variation); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
} \
\
(_m)->m_len = (_m)->m_pkthdr.len; \
} while (0)
/* L2CAP_DisconnectReq */
#define _ng_l2cap_discon_req(_m, _ident, _dcid, _scid) \
do { \
struct _discon_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_discon_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _discon_req *); \
c->hdr.code = NG_L2CAP_DISCON_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CA_DisconnectRsp */
#define _ng_l2cap_discon_rsp(_m, _ident, _dcid, _scid) \
do { \
struct _discon_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_discon_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _discon_rsp *); \
c->hdr.code = NG_L2CAP_DISCON_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CAP_EchoReq */
#define _ng_l2cap_echo_req(_m, _ident, _data, _size) \
do { \
ng_l2cap_cmd_hdr_t *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), ng_l2cap_cmd_hdr_t *); \
c->code = NG_L2CAP_ECHO_REQ; \
c->ident = (_ident); \
c->length = 0; \
\
if ((_data) != NULL) { \
m_copyback((_m), sizeof(*c), (_size), (_data)); \
c->length += (_size); \
} \
\
c->length = htole16(c->length); \
} while (0)
/* L2CAP_InfoReq */
#define _ng_l2cap_info_req(_m, _ident, _type) \
do { \
struct _info_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_info_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _info_req *); \
c->hdr.code = NG_L2CAP_INFO_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.type = htole16((_type)); \
} while (0)
/* L2CAP_InfoRsp */
#define _ng_l2cap_info_rsp(_m, _ident, _type, _result, _mtu) \
do { \
struct _info_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_info_rsp_cp param; \
ng_l2cap_info_rsp_data_t data; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_NOWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
c = mtod((_m), struct _info_rsp *); \
c->hdr.code = NG_L2CAP_INFO_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.type = htole16((_type)); \
c->param.result = htole16((_result)); \
\
if ((_result) == NG_L2CAP_SUCCESS) { \
switch ((_type)) { \
case NG_L2CAP_CONNLESS_MTU: \
c->data.mtu.mtu = htole16((_mtu)); \
c->hdr.length += sizeof((c->data.mtu.mtu)); \
break; \
} \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + \
c->hdr.length; \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
void ng_l2cap_con_wakeup (ng_l2cap_con_p);
void ng_l2cap_con_fail (ng_l2cap_con_p, u_int16_t);
void ng_l2cap_process_command_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_L2CAP_CMDS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
/*
* ng_l2cap_evnt.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_evnt.h,v 1.1 2002/11/24 19:47:06 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_EVNT_H_
#define _NETGRAPH_L2CAP_EVNT_H_
int ng_l2cap_receive (ng_l2cap_con_p);
#endif /* ndef _NETGRAPH_L2CAP_EVNT_H_ */

View File

@ -0,0 +1,967 @@
/*
* ng_l2cap_llpi.c
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_llpi.c,v 1.5 2003/09/08 19:11:45 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
/******************************************************************************
******************************************************************************
** Lower Layer Protocol (HCI) Interface module
******************************************************************************
******************************************************************************/
/*
* Send LP_ConnectReq event to the lower layer protocol. Create new connection
* descriptor and initialize it. Create LP_ConnectReq event and send it to the
* lower layer, then adjust connection state and start timer. The function WILL
* FAIL if connection to the remote unit already exists.
*/
int
ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type)
{
struct ng_mesg *msg = NULL;
ng_hci_lp_con_req_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Verify that we DO NOT have connection to the remote unit */
con = ng_l2cap_con_by_addr(l2cap, bdaddr, type);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectReq event. " \
"Connection already exists, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
return (EEXIST);
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid\n",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return (ENOTCONN);
}
/* Create and intialize new connection descriptor */
con = ng_l2cap_new_con(l2cap, bdaddr, type);
if (con == NULL)
return (ENOMEM);
/* Create and send LP_ConnectReq event */
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
sizeof(*ep), M_NOWAIT);
if (msg == NULL) {
ng_l2cap_free_con(con);
return (ENOMEM);
}
ep = (ng_hci_lp_con_req_ep *) (msg->data);
bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
ep->link_type = type;
con->flags |= NG_L2CAP_CON_OUTGOING;
con->state = NG_L2CAP_W4_LP_CON_CFM;
ng_l2cap_lp_timeout(con);
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
if (error != 0) {
if (ng_l2cap_lp_untimeout(con) == 0)
ng_l2cap_free_con(con);
/*
* Do not free connection if ng_l2cap_lp_untimeout() failed
* let timeout handler deal with it. Always return error to
* the caller.
*/
}
return (error);
} /* ng_l2cap_lp_con_req */
/*
* Process LP_ConnectCfm event from the lower layer protocol. It could be
* positive or negative. Verify remote unit address then stop the timer and
* process event.
*/
int
ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_con_cfm_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_ConnectCfm[Neg] message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
/* Check if we have requested/accepted this connection */
con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
__func__, NG_NODE_NAME(l2cap->node));
error = ENOENT;
goto out;
}
/* Check connection state */
if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectCfm event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/*
* Looks like it is our confirmation. It is safe now to cancel
* connection timer and notify upper layer. If timeout already
* happened then ignore connection confirmation and let timeout
* handle that.
*/
if ((error = ng_l2cap_lp_untimeout(con)) != 0)
goto out;
if (ep->status == 0) {
con->state = NG_L2CAP_CON_OPEN;
con->con_handle = ep->con_handle;
ng_l2cap_lp_deliver(con);
} else /* Negative confirmation - remove connection descriptor */
ng_l2cap_con_fail(con, ep->status);
out:
return (error);
} /* ng_l2cap_lp_con_cfm */
/*
* Process LP_ConnectInd event from the lower layer protocol. This is a good
* place to put some extra check on remote unit address and/or class. We could
* even forward this information to control hook (or check against internal
* black list) and thus implement some kind of firewall. But for now be simple
* and create new connection descriptor, start timer and send LP_ConnectRsp
* event (i.e. accept connection).
*/
int
ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_con_ind_ep *ep = NULL;
ng_hci_lp_con_rsp_ep *rp = NULL;
struct ng_mesg *rsp = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_ConnectInd message size\n",
__func__, NG_NODE_NAME(l2cap->node));
return (EMSGSIZE);
}
ep = (ng_hci_lp_con_ind_ep *) (msg->data);
/* Make sure we have only one connection to the remote unit */
con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectInd event. " \
"Connection already exists, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
return (EEXIST);
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return (ENOTCONN);
}
/* Create and intialize new connection descriptor */
con = ng_l2cap_new_con(l2cap, &ep->bdaddr, ep->link_type);
if (con == NULL)
return (ENOMEM);
/* Create and send LP_ConnectRsp event */
NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
sizeof(*rp), M_NOWAIT);
if (rsp == NULL) {
ng_l2cap_free_con(con);
return (ENOMEM);
}
rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
rp->status = 0x00; /* accept connection */
rp->link_type = NG_HCI_LINK_ACL;
bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));
con->state = NG_L2CAP_W4_LP_CON_CFM;
ng_l2cap_lp_timeout(con);
NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0);
if (error != 0) {
if (ng_l2cap_lp_untimeout(con) == 0)
ng_l2cap_free_con(con);
/*
* Do not free connection if ng_l2cap_lp_untimeout() failed
* let timeout handler deal with it. Always return error to
* the caller.
*/
}
return (error);
} /* ng_l2cap_lp_con_ind */
/*
* Process LP_DisconnectInd event from the lower layer protocol. We have been
* disconnected from the remote unit. So notify the upper layer protocol.
*/
int
ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_discon_ind_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_DisconnectInd message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_discon_ind_ep *) (msg->data);
/* Check if we have this connection */
con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
error = ENOENT;
goto out;
}
/* XXX Verify connection state -- do we need to check this? */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/*
* Notify upper layer and remove connection
* Note: The connection could have auto disconnect timeout set. Try
* to remove it. If auto disconnect timeout happened then ignore
* disconnect indication and let timeout handle that.
*/
if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
if ((error = ng_l2cap_discon_untimeout(con)) != 0)
return (error);
ng_l2cap_con_fail(con, ep->reason);
out:
return (error);
} /* ng_l2cap_lp_discon_ind */
/*
* Send LP_QoSSetupReq event to the lower layer protocol
*/
int
ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
ng_l2cap_flow_p flow)
{
struct ng_mesg *msg = NULL;
ng_hci_lp_qos_req_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Verify that we have this connection */
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle);
return (ENOENT);
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
return (EINVAL);
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return (ENOTCONN);
}
/* Create and send LP_QoSSetupReq event */
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
sizeof(*ep), M_NOWAIT);
if (msg == NULL)
return (ENOMEM);
ep = (ng_hci_lp_qos_req_ep *) (msg->data);
ep->con_handle = con_handle;
ep->flags = flow->flags;
ep->service_type = flow->service_type;
ep->token_rate = flow->token_rate;
ep->peak_bandwidth = flow->peak_bandwidth;
ep->latency = flow->latency;
ep->delay_variation = flow->delay_variation;
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
return (error);
} /* ng_l2cap_lp_con_req */
/*
* Process LP_QoSSetupCfm from the lower layer protocol
*/
int
ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_qos_cfm_ep *ep = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
/* XXX FIXME do something */
out:
return (error);
} /* ng_l2cap_lp_qos_cfm */
/*
* Process LP_QoSViolationInd event from the lower layer protocol. Lower
* layer protocol has detected QoS Violation, so we MUST notify the
* upper layer.
*/
int
ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_qos_ind_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_QoSViolation message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_qos_ind_ep *) (msg->data);
/* Check if we have this connection */
con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSViolationInd event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
error = ENOENT;
goto out;
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSViolationInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/* XXX FIXME Notify upper layer and terminate channels if required */
out:
return (error);
} /* ng_l2cap_qos_ind */
int
ng_l2cap_lp_enc_change(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_enc_change_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
ng_l2cap_chan_p ch = NULL;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_ENCChange message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_enc_change_ep *) (msg->data);
/* Check if we have this connection */
con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_Enc Change Event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
error = ENOENT;
goto out;
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected ENC_CHANGE event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
con->encryption = ep->status;
LIST_FOREACH(ch, &l2cap->chan_list, next){
if((ch->con->con_handle == ep->con_handle) &&
(ch->con->linktype == ep->link_type))
ng_l2cap_l2ca_encryption_change(ch, ep->status);
}
out:
return (error);
} /* ng_l2cap_enc_change */
/*
* Prepare L2CAP packet. Prepend packet with L2CAP packet header and then
* segment it according to HCI MTU.
*/
int
ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0)
{
ng_l2cap_p l2cap = con->l2cap;
ng_l2cap_hdr_t *l2cap_hdr = NULL;
ng_hci_acldata_pkt_t *acl_hdr = NULL;
struct mbuf *m_last = NULL, *m = NULL;
int len, flag = NG_HCI_PACKET_START;
KASSERT((con->tx_pkt == NULL),
("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node)));
KASSERT((l2cap->pkt_size > 0),
("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node)));
/* Prepend mbuf with L2CAP header */
m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr));
if (m0 == NULL) {
NG_L2CAP_ALERT(
"%s: %s - ng_l2cap_prepend(%zd) failed\n",
__func__, NG_NODE_NAME(l2cap->node),
sizeof(*l2cap_hdr));
goto fail;
}
l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *);
l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr));
l2cap_hdr->dcid = htole16(dcid);
/*
* Segment single L2CAP packet according to the HCI layer MTU. Convert
* each segment into ACL data packet and prepend it with ACL data packet
* header. Link all segments together via m_nextpkt link.
*
* XXX BC (Broadcast flag) will always be 0 (zero).
*/
while (m0 != NULL) {
/* Check length of the packet against HCI MTU */
len = m0->m_pkthdr.len;
if (len > l2cap->pkt_size) {
m = m_split(m0, l2cap->pkt_size, M_NOWAIT);
if (m == NULL) {
NG_L2CAP_ALERT(
"%s: %s - m_split(%d) failed\n", __func__, NG_NODE_NAME(l2cap->node),
l2cap->pkt_size);
goto fail;
}
len = l2cap->pkt_size;
}
/* Convert packet fragment into ACL data packet */
m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr));
if (m0 == NULL) {
NG_L2CAP_ALERT(
"%s: %s - ng_l2cap_prepend(%zd) failed\n",
__func__, NG_NODE_NAME(l2cap->node),
sizeof(*acl_hdr));
goto fail;
}
acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *);
acl_hdr->type = NG_HCI_ACL_DATA_PKT;
acl_hdr->length = htole16(len);
acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(
con->con_handle, flag, 0));
/* Add fragment to the chain */
m0->m_nextpkt = NULL;
if (con->tx_pkt == NULL)
con->tx_pkt = m_last = m0;
else {
m_last->m_nextpkt = m0;
m_last = m0;
}
NG_L2CAP_INFO(
"%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->con_handle,
flag, len);
m0 = m;
m = NULL;
flag = NG_HCI_PACKET_FRAGMENT;
}
return (0);
fail:
NG_FREE_M(m0);
NG_FREE_M(m);
while (con->tx_pkt != NULL) {
m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
return (ENOBUFS);
} /* ng_l2cap_lp_send */
/*
* Receive ACL data packet from the HCI layer. First strip ACL packet header
* and get connection handle, PB (Packet Boundary) flag and payload length.
* Then find connection descriptor and verify its state. Then process ACL
* packet as follows.
*
* 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP
* header and get total length of the L2CAP packet. Then start new L2CAP
* packet.
*
* 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT)
* then add segment to the packet.
*/
int
ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
{
ng_hci_acldata_pkt_t *acl_hdr = NULL;
ng_l2cap_hdr_t *l2cap_hdr = NULL;
ng_l2cap_con_p con = NULL;
u_int16_t con_handle, length, pb;
int error = 0;
/* Check ACL data packet */
if (m->m_pkthdr.len < sizeof(*acl_hdr)) {
NG_L2CAP_ERR(
"%s: %s - invalid ACL data packet. Packet too small, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len);
error = EMSGSIZE;
goto drop;
}
/* Strip ACL data packet header */
NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
if (m == NULL)
return (ENOBUFS);
acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
m_adj(m, sizeof(*acl_hdr));
/* Get ACL connection handle, PB flag and payload length */
acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
length = le16toh(acl_hdr->length);
NG_L2CAP_INFO(
"%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);
/* Get connection descriptor */
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle);
error = ENOENT;
goto drop;
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state);
error = EHOSTDOWN;
goto drop;
}
/* Process packet */
if (pb == NG_HCI_PACKET_START) {
if (con->rx_pkt != NULL) {
NG_L2CAP_ERR(
"%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
__func__, NG_NODE_NAME(l2cap->node),
con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
NG_FREE_M(con->rx_pkt);
con->rx_pkt_len = 0;
}
/* Get L2CAP header */
if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
NG_L2CAP_ERR(
"%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
m->m_pkthdr.len);
error = EMSGSIZE;
goto drop;
}
NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
if (m == NULL)
return (ENOBUFS);
l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);
NG_L2CAP_INFO(
"%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle,
le16toh(l2cap_hdr->length));
/* Start new L2CAP packet */
con->rx_pkt = m;
con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
} else if (pb == NG_HCI_PACKET_FRAGMENT) {
if (con->rx_pkt == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet fragment, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
con->con_handle);
goto drop;
}
/* Add fragment to the L2CAP packet */
m_cat(con->rx_pkt, m);
con->rx_pkt->m_pkthdr.len += length;
} else {
NG_L2CAP_ERR(
"%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n",
__func__, NG_NODE_NAME(l2cap->node), pb);
error = EINVAL;
goto drop;
}
con->rx_pkt_len -= length;
if (con->rx_pkt_len < 0) {
NG_L2CAP_ALERT(
"%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n",
__func__, NG_NODE_NAME(l2cap->node),
con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
NG_FREE_M(con->rx_pkt);
con->rx_pkt_len = 0;
} else if (con->rx_pkt_len == 0) {
/* OK, we have got complete L2CAP packet, so process it */
error = ng_l2cap_receive(con);
con->rx_pkt = NULL;
con->rx_pkt_len = 0;
}
return (error);
drop:
NG_FREE_M(m);
return (error);
} /* ng_l2cap_lp_receive */
/*
* Send queued ACL packets to the HCI layer
*/
void
ng_l2cap_lp_deliver(ng_l2cap_con_p con)
{
ng_l2cap_p l2cap = con->l2cap;
struct mbuf *m = NULL;
int error;
/* Check connection */
if (con->state != NG_L2CAP_CON_OPEN)
return;
if (con->tx_pkt == NULL)
ng_l2cap_con_wakeup(con);
if (con->tx_pkt == NULL)
return;
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
goto drop; /* XXX what to do with "pending"? */
}
/* Send ACL data packets */
while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) {
m = con->tx_pkt;
con->tx_pkt = con->tx_pkt->m_nextpkt;
m->m_nextpkt = NULL;
if(m->m_flags &M_PROTO2){
ng_l2cap_lp_receive(con->l2cap, m);
continue;
}
NG_L2CAP_INFO(
"%s: %s - sending ACL packet, con_handle=%d, len=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->con_handle,
m->m_pkthdr.len);
NG_SEND_DATA_ONLY(error, l2cap->hci, m);
if (error != 0) {
NG_L2CAP_ERR(
"%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
con->con_handle, error);
goto drop; /* XXX what to do with "pending"? */
}
con->pending ++;
}
NG_L2CAP_INFO(
"%s: %s - %d ACL packets have been sent, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->pending,
con->con_handle);
return;
drop:
while (con->tx_pkt != NULL) {
m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
} /* ng_l2cap_lp_deliver */
/*
* Process connection timeout. Remove connection from the list. If there
* are any channels that wait for the connection then notify them. Free
* connection descriptor.
*/
void
ng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
{
ng_l2cap_p l2cap = NULL;
ng_l2cap_con_p con = NULL;
if (NG_NODE_NOT_VALID(node)) {
printf("%s: Netgraph node is not valid\n", __func__);
return;
}
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ALERT(
"%s: %s - could not find connection, con_handle=%d\n",
__func__, NG_NODE_NAME(node), con_handle);
return;
}
if (!(con->flags & NG_L2CAP_CON_LP_TIMO)) {
NG_L2CAP_ALERT(
"%s: %s - no pending LP timeout, con_handle=%d, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(node), con_handle, con->state,
con->flags);
return;
}
/*
* Notify channels that connection has timed out. This will remove
* connection, channels and pending commands.
*/
con->flags &= ~NG_L2CAP_CON_LP_TIMO;
ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT);
} /* ng_l2cap_process_lp_timeout */
/*
* Process auto disconnect timeout and send LP_DisconReq event to the
* lower layer protocol
*/
void
ng_l2cap_process_discon_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
{
ng_l2cap_p l2cap = NULL;
ng_l2cap_con_p con = NULL;
struct ng_mesg *msg = NULL;
ng_hci_lp_discon_req_ep *ep = NULL;
int error;
if (NG_NODE_NOT_VALID(node)) {
printf("%s: Netgraph node is not valid\n", __func__);
return;
}
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ALERT(
"%s: %s - could not find connection, con_handle=%d\n",
__func__, NG_NODE_NAME(node), con_handle);
return;
}
if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)) {
NG_L2CAP_ALERT(
"%s: %s - no pending disconnect timeout, con_handle=%d, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(node), con_handle, con->state,
con->flags);
return;
}
con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid\n",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return;
}
/* Create and send LP_DisconReq event */
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
sizeof(*ep), M_NOWAIT);
if (msg == NULL)
return;
ep = (ng_hci_lp_discon_req_ep *) (msg->data);
ep->con_handle = con->con_handle;
ep->reason = 0x13; /* User Ended Connection */
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
} /* ng_l2cap_process_discon_timeout */

View File

@ -0,0 +1,52 @@
/*
* ng_l2cap_llpi.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_llpi.h,v 1.2 2003/04/28 21:44:59 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_LLPI_H_
#define _NETGRAPH_L2CAP_LLPI_H_
int ng_l2cap_lp_con_req (ng_l2cap_p, bdaddr_p, int);
int ng_l2cap_lp_con_cfm (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_con_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_discon_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_qos_req (ng_l2cap_p, u_int16_t, ng_l2cap_flow_p);
int ng_l2cap_lp_qos_cfm (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_qos_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_enc_change (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_send (ng_l2cap_con_p, u_int16_t,struct mbuf *);
int ng_l2cap_lp_receive (ng_l2cap_p, struct mbuf *);
void ng_l2cap_lp_deliver (ng_l2cap_con_p);
void ng_l2cap_process_lp_timeout (node_p, hook_p, void *, int);
void ng_l2cap_process_discon_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_L2CAP_LLPI_H_ */

View File

@ -0,0 +1,758 @@
/*
* ng_l2cap_main.c
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_main.c,v 1.2 2003/04/28 21:44:59 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_prse.h>
/******************************************************************************
******************************************************************************
** This node implements Link Layer Control and Adaptation Protocol (L2CAP)
******************************************************************************
******************************************************************************/
/* MALLOC define */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DEFINE(M_NETGRAPH_L2CAP, "netgraph_l2cap",
"Netgraph Bluetooth L2CAP node");
#else
#define M_NETGRAPH_L2CAP M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Netgraph node methods */
static ng_constructor_t ng_l2cap_constructor;
static ng_shutdown_t ng_l2cap_shutdown;
static ng_newhook_t ng_l2cap_newhook;
static ng_connect_t ng_l2cap_connect;
static ng_disconnect_t ng_l2cap_disconnect;
static ng_rcvmsg_t ng_l2cap_lower_rcvmsg;
static ng_rcvmsg_t ng_l2cap_upper_rcvmsg;
static ng_rcvmsg_t ng_l2cap_default_rcvmsg;
static ng_rcvdata_t ng_l2cap_rcvdata;
/* Netgraph node type descriptor */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_L2CAP_NODE_TYPE,
.constructor = ng_l2cap_constructor,
.rcvmsg = ng_l2cap_default_rcvmsg,
.shutdown = ng_l2cap_shutdown,
.newhook = ng_l2cap_newhook,
.connect = ng_l2cap_connect,
.rcvdata = ng_l2cap_rcvdata,
.disconnect = ng_l2cap_disconnect,
.cmdlist = ng_l2cap_cmdlist,
};
NETGRAPH_INIT(l2cap, &typestruct);
MODULE_VERSION(ng_l2cap, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_l2cap, ng_bluetooth, NG_BLUETOOTH_VERSION,
NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
/*****************************************************************************
*****************************************************************************
** Netgraph methods implementation
*****************************************************************************
*****************************************************************************/
static void ng_l2cap_cleanup (ng_l2cap_p);
static void ng_l2cap_destroy_channels (ng_l2cap_p);
/*
* Create new instance of L2CAP node
*/
static int
ng_l2cap_constructor(node_p node)
{
ng_l2cap_p l2cap = NULL;
/* Create new L2CAP node */
l2cap = malloc(sizeof(*l2cap), M_NETGRAPH_L2CAP, M_WAITOK | M_ZERO);
l2cap->node = node;
l2cap->debug = NG_L2CAP_WARN_LEVEL;
l2cap->discon_timo = 5; /* sec */
LIST_INIT(&l2cap->con_list);
LIST_INIT(&l2cap->chan_list);
NG_NODE_SET_PRIVATE(node, l2cap);
NG_NODE_FORCE_WRITER(node);
return (0);
} /* ng_l2cap_constructor */
/*
* Shutdown L2CAP node
*/
static int
ng_l2cap_shutdown(node_p node)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
/* Clean up L2CAP node. Delete all connection, channels and commands */
l2cap->node = NULL;
ng_l2cap_cleanup(l2cap);
bzero(l2cap, sizeof(*l2cap));
free(l2cap, M_NETGRAPH_L2CAP);
return (0);
} /* ng_l2cap_shutdown */
/*
* Give our OK for a hook to be added. HCI layer is connected to the HCI
* (NG_L2CAP_HOOK_HCI) hook. As per specification L2CAP layer MUST provide
* Procol/Service Multiplexing, so the L2CAP node provides separate hooks
* for SDP (NG_L2CAP_HOOK_SDP), RFCOMM (NG_L2CAP_HOOK_RFCOMM) and TCP
* (NG_L2CAP_HOOK_TCP) protcols. Unknown PSM will be forwarded to
* NG_L2CAP_HOOK_ORPHAN hook. Control node/application is connected to
* control (NG_L2CAP_HOOK_CTL) hook.
*/
static int
ng_l2cap_newhook(node_p node, hook_p hook, char const *name)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
hook_p *h = NULL;
if (strcmp(name, NG_L2CAP_HOOK_HCI) == 0)
h = &l2cap->hci;
else if (strcmp(name, NG_L2CAP_HOOK_L2C) == 0)
h = &l2cap->l2c;
else if (strcmp(name, NG_L2CAP_HOOK_CTL) == 0)
h = &l2cap->ctl;
else
return (EINVAL);
if (*h != NULL)
return (EISCONN);
*h = hook;
return (0);
} /* ng_l2cap_newhook */
/*
* Give our final OK to connect hook. Nothing to do here.
*/
static int
ng_l2cap_connect(hook_p hook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
int error = 0;
if (hook == l2cap->hci)
NG_HOOK_SET_RCVMSG(hook, ng_l2cap_lower_rcvmsg);
else
if (hook == l2cap->l2c || hook == l2cap->ctl) {
NG_HOOK_SET_RCVMSG(hook, ng_l2cap_upper_rcvmsg);
/* Send delayed notification to the upper layer */
error = ng_send_fn(l2cap->node, hook, ng_l2cap_send_hook_info,
NULL, 0);
} else
error = EINVAL;
return (error);
} /* ng_l2cap_connect */
/*
* Disconnect the hook. For downstream hook we must notify upper layers.
*
* XXX For upstream hooks this is really ugly :( Hook was disconnected and it
* XXX is now too late to do anything. For now we just clean up our own mess
* XXX and remove all channels that use disconnected upstream hook. If we don't
* XXX do that then L2CAP node can get out of sync with upper layers.
* XXX No notification will be sent to remote peer.
*/
static int
ng_l2cap_disconnect(hook_p hook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
hook_p *h = NULL;
if (hook == l2cap->hci) {
ng_l2cap_cleanup(l2cap);
h = &l2cap->hci;
} else
if (hook == l2cap->l2c) {
ng_l2cap_destroy_channels(l2cap);
h = &l2cap->l2c;
} else
if (hook == l2cap->ctl)
h = &l2cap->ctl;
else
return (EINVAL);
*h = NULL;
/* Shutdown when all hooks are disconnected */
if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
} /* ng_l2cap_disconnect */
/*
* Process control message from lower layer
*/
static int
ng_l2cap_lower_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
int error = 0;
switch (msg->header.typecookie) {
case NGM_HCI_COOKIE:
switch (msg->header.cmd) {
/* HCI node is ready */
case NGM_HCI_NODE_UP: {
ng_hci_node_up_ep *ep = NULL;
if (msg->header.arglen != sizeof(*ep))
error = EMSGSIZE;
else {
ep = (ng_hci_node_up_ep *)(msg->data);
NG_L2CAP_INFO(
"%s: %s - HCI node is up, bdaddr: %x:%x:%x:%x:%x:%x, " \
"pkt_size=%d bytes, num_pkts=%d\n", __func__, NG_NODE_NAME(l2cap->node),
ep->bdaddr.b[5], ep->bdaddr.b[4],
ep->bdaddr.b[3], ep->bdaddr.b[2],
ep->bdaddr.b[1], ep->bdaddr.b[0],
ep->pkt_size, ep->num_pkts);
bcopy(&ep->bdaddr, &l2cap->bdaddr,
sizeof(l2cap->bdaddr));
l2cap->pkt_size = ep->pkt_size;
l2cap->num_pkts = ep->num_pkts;
/* Notify upper layers */
ng_l2cap_send_hook_info(l2cap->node,
l2cap->l2c, NULL, 0);
ng_l2cap_send_hook_info(l2cap->node,
l2cap->ctl, NULL, 0);
}
} break;
case NGM_HCI_SYNC_CON_QUEUE: {
ng_hci_sync_con_queue_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
if (msg->header.arglen != sizeof(*ep))
error = EMSGSIZE;
else {
ep = (ng_hci_sync_con_queue_ep *)(msg->data);
con = ng_l2cap_con_by_handle(l2cap,
ep->con_handle);
if (con == NULL)
break;
NG_L2CAP_INFO(
"%s: %s - sync HCI connection queue, con_handle=%d, pending=%d, completed=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
ep->con_handle, con->pending,
ep->completed);
con->pending -= ep->completed;
if (con->pending < 0) {
NG_L2CAP_WARN(
"%s: %s - pending packet counter is out of sync! " \
"con_handle=%d, pending=%d, completed=%d\n", __func__,
NG_NODE_NAME(l2cap->node),
con->con_handle, con->pending,
ep->completed);
con->pending = 0;
}
ng_l2cap_lp_deliver(con);
}
} break;
/* LP_ConnectCfm[Neg] */
case NGM_HCI_LP_CON_CFM:
error = ng_l2cap_lp_con_cfm(l2cap, msg);
break;
/* LP_ConnectInd */
case NGM_HCI_LP_CON_IND:
error = ng_l2cap_lp_con_ind(l2cap, msg);
break;
/* LP_DisconnectInd */
case NGM_HCI_LP_DISCON_IND:
error = ng_l2cap_lp_discon_ind(l2cap, msg);
break;
/* LP_QoSSetupCfm[Neg] */
case NGM_HCI_LP_QOS_CFM:
error = ng_l2cap_lp_qos_cfm(l2cap, msg);
break;
/* LP_OoSViolationInd */
case NGM_HCI_LP_QOS_IND:
error = ng_l2cap_lp_qos_ind(l2cap, msg);
break;
case NGM_HCI_LP_ENC_CHG:
error = ng_l2cap_lp_enc_change(l2cap, msg);
break;
default:
error = EINVAL;
break;
}
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
NG_FREE_ITEM(item);
return (error);
} /* ng_l2cap_lower_rcvmsg */
/*
* Process control message from upper layer
*/
static int
ng_l2cap_upper_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
int error = 0;
switch (msg->header.typecookie) {
case NGM_L2CAP_COOKIE:
switch (msg->header.cmd) {
/* L2CA_Connect */
case NGM_L2CAP_L2CA_CON:
error = ng_l2cap_l2ca_con_req(l2cap, msg);
break;
/* L2CA_ConnectRsp */
case NGM_L2CAP_L2CA_CON_RSP:
error = ng_l2cap_l2ca_con_rsp_req(l2cap, msg);
break;
/* L2CA_Config */
case NGM_L2CAP_L2CA_CFG:
error = ng_l2cap_l2ca_cfg_req(l2cap, msg);
break;
/* L2CA_ConfigRsp */
case NGM_L2CAP_L2CA_CFG_RSP:
error = ng_l2cap_l2ca_cfg_rsp_req(l2cap, msg);
break;
/* L2CA_Disconnect */
case NGM_L2CAP_L2CA_DISCON:
error = ng_l2cap_l2ca_discon_req(l2cap, msg);
break;
/* L2CA_GroupCreate */
case NGM_L2CAP_L2CA_GRP_CREATE:
error = ng_l2cap_l2ca_grp_create(l2cap, msg);
break;
/* L2CA_GroupClose */
case NGM_L2CAP_L2CA_GRP_CLOSE:
error = ng_l2cap_l2ca_grp_close(l2cap, msg);
break;
/* L2CA_GroupAddMember */
case NGM_L2CAP_L2CA_GRP_ADD_MEMBER:
error = ng_l2cap_l2ca_grp_add_member_req(l2cap, msg);
break;
/* L2CA_GroupDeleteMember */
case NGM_L2CAP_L2CA_GRP_REM_MEMBER:
error = ng_l2cap_l2ca_grp_rem_member(l2cap, msg);
break;
/* L2CA_GroupMembership */
case NGM_L2CAP_L2CA_GRP_MEMBERSHIP:
error = ng_l2cap_l2ca_grp_get_members(l2cap, msg);
break;
/* L2CA_Ping */
case NGM_L2CAP_L2CA_PING:
error = ng_l2cap_l2ca_ping_req(l2cap, msg);
break;
/* L2CA_GetInfo */
case NGM_L2CAP_L2CA_GET_INFO:
error = ng_l2cap_l2ca_get_info_req(l2cap, msg);
break;
/* L2CA_EnableCLT */
case NGM_L2CAP_L2CA_ENABLE_CLT:
error = ng_l2cap_l2ca_enable_clt(l2cap, msg);
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
NG_FREE_ITEM(item);
return (error);
} /* ng_l2cap_upper_rcvmsg */
/*
* Default control message processing routine
*/
static int
ng_l2cap_default_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NULL, *rsp = NULL;
int error = 0;
/* Detach and process message */
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_GENERIC_COOKIE:
switch (msg->header.cmd) {
case NGM_TEXT_STATUS:
NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
snprintf(rsp->data, NG_TEXTRESPONSE,
"bdaddr %x:%x:%x:%x:%x:%x, " \
"pkt_size %d\n" \
"Hooks %s %s %s\n" \
"Flags %#x\n",
l2cap->bdaddr.b[5], l2cap->bdaddr.b[4],
l2cap->bdaddr.b[3], l2cap->bdaddr.b[2],
l2cap->bdaddr.b[1], l2cap->bdaddr.b[0],
l2cap->pkt_size,
(l2cap->hci != NULL)?
NG_L2CAP_HOOK_HCI : "",
(l2cap->l2c != NULL)?
NG_L2CAP_HOOK_L2C : "",
(l2cap->ctl != NULL)?
NG_L2CAP_HOOK_CTL : "",
l2cap->flags);
break;
default:
error = EINVAL;
break;
}
break;
/* Messages from the upper layer or directed to the local node */
case NGM_L2CAP_COOKIE:
switch (msg->header.cmd) {
/* Get node flags */
case NGM_L2CAP_NODE_GET_FLAGS:
NG_MKRESPONSE(rsp, msg, sizeof(ng_l2cap_node_flags_ep),
M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
*((ng_l2cap_node_flags_ep *)(rsp->data)) =
l2cap->flags;
break;
/* Get node debug */
case NGM_L2CAP_NODE_GET_DEBUG:
NG_MKRESPONSE(rsp, msg, sizeof(ng_l2cap_node_debug_ep),
M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
*((ng_l2cap_node_debug_ep *)(rsp->data)) =
l2cap->debug;
break;
/* Set node debug */
case NGM_L2CAP_NODE_SET_DEBUG:
if (msg->header.arglen !=
sizeof(ng_l2cap_node_debug_ep))
error = EMSGSIZE;
else
l2cap->debug =
*((ng_l2cap_node_debug_ep *)(msg->data));
break;
/* Get connection list */
case NGM_L2CAP_NODE_GET_CON_LIST: {
ng_l2cap_con_p con = NULL;
ng_l2cap_node_con_list_ep *e1 = NULL;
ng_l2cap_node_con_ep *e2 = NULL;
int n = 0;
/* Count number of connections */
LIST_FOREACH(con, &l2cap->con_list, next)
n++;
if (n > NG_L2CAP_MAX_CON_NUM)
n = NG_L2CAP_MAX_CON_NUM;
/* Prepare response */
NG_MKRESPONSE(rsp, msg,
sizeof(*e1) + n * sizeof(*e2), M_NOWAIT);
if (rsp == NULL) {
error = ENOMEM;
break;
}
e1 = (ng_l2cap_node_con_list_ep *)(rsp->data);
e2 = (ng_l2cap_node_con_ep *)(e1 + 1);
e1->num_connections = n;
LIST_FOREACH(con, &l2cap->con_list, next) {
e2->state = con->state;
e2->flags = con->flags;
if (con->tx_pkt != NULL)
e2->flags |= NG_L2CAP_CON_TX;
if (con->rx_pkt != NULL)
e2->flags |= NG_L2CAP_CON_RX;
e2->pending = con->pending;
e2->con_handle = con->con_handle;
bcopy(&con->remote, &e2->remote,
sizeof(e2->remote));
e2 ++;
if (--n <= 0)
break;
}
} break;
/* Get channel list */
case NGM_L2CAP_NODE_GET_CHAN_LIST: {
ng_l2cap_chan_p ch = NULL;
ng_l2cap_node_chan_list_ep *e1 = NULL;
ng_l2cap_node_chan_ep *e2 = NULL;
int n = 0;
/* Count number of channels */
LIST_FOREACH(ch, &l2cap->chan_list, next)
n ++;
if (n > NG_L2CAP_MAX_CHAN_NUM)
n = NG_L2CAP_MAX_CHAN_NUM;
/* Prepare response */
NG_MKRESPONSE(rsp, msg,
sizeof(ng_l2cap_node_chan_list_ep) +
n * sizeof(ng_l2cap_node_chan_ep), M_NOWAIT);
if (rsp == NULL) {
error = ENOMEM;
break;
}
e1 = (ng_l2cap_node_chan_list_ep *)(rsp->data);
e2 = (ng_l2cap_node_chan_ep *)(e1 + 1);
e1->num_channels = n;
LIST_FOREACH(ch, &l2cap->chan_list, next) {
e2->state = ch->state;
e2->scid = ch->scid;
e2->dcid = ch->dcid;
e2->imtu = ch->imtu;
e2->omtu = ch->omtu;
e2->psm = ch->psm;
bcopy(&ch->con->remote, &e2->remote,
sizeof(e2->remote));
e2 ++;
if (--n <= 0)
break;
}
} break;
case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
NG_MKRESPONSE(rsp, msg,
sizeof(ng_l2cap_node_auto_discon_ep), M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
*((ng_l2cap_node_auto_discon_ep *)(rsp->data)) =
l2cap->discon_timo;
break;
case NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO:
if (msg->header.arglen !=
sizeof(ng_l2cap_node_auto_discon_ep))
error = EMSGSIZE;
else
l2cap->discon_timo =
*((ng_l2cap_node_auto_discon_ep *)
(msg->data));
break;
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, rsp);
NG_FREE_MSG(msg);
return (error);
} /* ng_l2cap_rcvmsg */
/*
* Process data packet from one of our hooks.
*
* From the HCI hook we expect to receive ACL data packets. ACL data packets
* gets re-assembled into one L2CAP packet (according to length) and then gets
* processed.
*
* NOTE: We expect to receive L2CAP packet header in the first fragment.
* Otherwise we WILL NOT be able to get length of the L2CAP packet.
*
* Signaling L2CAP packets (destination channel ID == 0x1) are processed within
* the node. Connectionless data packets (destination channel ID == 0x2) will
* be forwarded to appropriate upstream hook unless it is not connected or
* connectionless traffic for the specified PSM was disabled.
*
* From the upstream hooks we expect to receive data packets. These data
* packets will be converted into L2CAP data packets. The length of each
* L2CAP packet must not exceed channel's omtu (our peer's imtu). Then
* these L2CAP packets will be converted to ACL data packets (according to
* HCI layer MTU) and sent to lower layer.
*
* No data is expected from the control hook.
*/
static int
ng_l2cap_rcvdata(hook_p hook, item_p item)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct mbuf *m = NULL;
int error = 0;
/* Detach mbuf, discard item and process data */
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if (hook == l2cap->hci)
error = ng_l2cap_lp_receive(l2cap, m);
else if (hook == l2cap->l2c)
error = ng_l2cap_l2ca_write_req(l2cap, m);
else {
NG_FREE_M(m);
error = EINVAL;
}
return (error);
} /* ng_l2cap_rcvdata */
/*
* Clean all connections, channels and commands for the L2CAP node
*/
static void
ng_l2cap_cleanup(ng_l2cap_p l2cap)
{
ng_l2cap_con_p con = NULL;
/* Clean up connection and channels */
while (!LIST_EMPTY(&l2cap->con_list)) {
con = LIST_FIRST(&l2cap->con_list);
if (con->flags & NG_L2CAP_CON_LP_TIMO)
ng_l2cap_lp_untimeout(con);
else if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
ng_l2cap_discon_untimeout(con);
/* Connection terminated by local host */
ng_l2cap_con_fail(con, 0x16);
}
} /* ng_l2cap_cleanup */
/*
* Destroy all channels that use specified upstream hook
*/
static void
ng_l2cap_destroy_channels(ng_l2cap_p l2cap)
{
while (!LIST_EMPTY(&l2cap->chan_list))
ng_l2cap_free_chan(LIST_FIRST(&l2cap->chan_list));
} /* ng_l2cap_destroy_channels_by_hook */

View File

@ -0,0 +1,698 @@
/*
* ng_l2cap_misc.c
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_misc.c,v 1.5 2003/09/08 19:11:45 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
static u_int16_t ng_l2cap_get_cid (ng_l2cap_p, int);
/******************************************************************************
******************************************************************************
** Utility routines
******************************************************************************
******************************************************************************/
/*
* Send hook information to the upper layer
*/
void
ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_l2cap_p l2cap = NULL;
struct ng_mesg *msg = NULL;
int error = 0;
ng_l2cap_node_hook_info_ep *ep ;
if (node == NULL || NG_NODE_NOT_VALID(node) ||
hook == NULL || NG_HOOK_NOT_VALID(hook))
return;
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) ||
bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0)
return;
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
sizeof(*ep), M_NOWAIT);
if (msg != NULL) {
ep = (ng_l2cap_node_hook_info_ep *) &msg->data;
bcopy(&l2cap->bdaddr, &ep->addr, sizeof(bdaddr_t));
NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
} else
error = ENOMEM;
if (error != 0)
NG_L2CAP_INFO(
"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n",
__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook),
error);
} /* ng_l2cap_send_hook_info */
/*
* Create new connection descriptor for the "remote" unit.
* Will link connection descriptor to the l2cap node.
*/
ng_l2cap_con_p
ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type)
{
static int fake_con_handle = 0x0f00;
ng_l2cap_con_p con = NULL;
/* Create new connection descriptor */
con = malloc(sizeof(*con), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (con == NULL)
return (NULL);
con->l2cap = l2cap;
con->state = NG_L2CAP_CON_CLOSED;
con->encryption = 0;
/*
* XXX
*
* Assign fake connection handle to the connection descriptor.
* Bluetooth specification marks 0x0f00 - 0x0fff connection
* handles as reserved. We need this fake connection handles
* for timeouts. Connection handle will be passed as argument
* to timeout so when timeout happens we can find the right
* connection descriptor. We can not pass pointers, because
* timeouts are external (to Netgraph) events and there might
* be a race when node/hook goes down and timeout event already
* went into node's queue
*/
con->con_handle = fake_con_handle ++;
if (fake_con_handle > 0x0fff)
fake_con_handle = 0x0f00;
bcopy(bdaddr, &con->remote, sizeof(con->remote));
con->linktype = type;
ng_callout_init(&con->con_timo);
con->ident = NG_L2CAP_FIRST_IDENT - 1;
TAILQ_INIT(&con->cmd_list);
/* Link connection */
LIST_INSERT_HEAD(&l2cap->con_list, con, next);
return (con);
} /* ng_l2cap_new_con */
/*
* Add reference to the connection descriptor
*/
void
ng_l2cap_con_ref(ng_l2cap_con_p con)
{
con->refcnt ++;
if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO) {
if ((con->state != NG_L2CAP_CON_OPEN) ||
(con->flags & NG_L2CAP_CON_OUTGOING) == 0)
panic(
"%s: %s - bad auto disconnect timeout, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
ng_l2cap_discon_untimeout(con);
}
} /* ng_l2cap_con_ref */
/*
* Remove reference from the connection descriptor
*/
void
ng_l2cap_con_unref(ng_l2cap_con_p con)
{
con->refcnt --;
if (con->refcnt < 0)
panic(
"%s: %s - con->refcnt < 0\n", __func__, NG_NODE_NAME(con->l2cap->node));
/*
* Set auto disconnect timer only if the following conditions are met:
* 1) we have no reference on the connection
* 2) connection is in OPEN state
* 3) it is an outgoing connection
* 4) disconnect timeout > 0
* 5) connection is not dying
*/
if ((con->refcnt == 0) &&
(con->state == NG_L2CAP_CON_OPEN) &&
(con->flags & NG_L2CAP_CON_OUTGOING) &&
(con->l2cap->discon_timo > 0) &&
((con->flags & NG_L2CAP_CON_DYING) == 0))
ng_l2cap_discon_timeout(con);
} /* ng_l2cap_con_unref */
/*
* Set auto disconnect timeout
* XXX FIXME: check return code from ng_callout
*/
int
ng_l2cap_discon_timeout(ng_l2cap_con_p con)
{
if (con->flags & (NG_L2CAP_CON_LP_TIMO|NG_L2CAP_CON_AUTO_DISCON_TIMO))
panic(
"%s: %s - invalid timeout, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
con->flags |= NG_L2CAP_CON_AUTO_DISCON_TIMO;
ng_callout(&con->con_timo, con->l2cap->node, NULL,
con->l2cap->discon_timo * hz,
ng_l2cap_process_discon_timeout, NULL,
con->con_handle);
return (0);
} /* ng_l2cap_discon_timeout */
/*
* Unset auto disconnect timeout
*/
int
ng_l2cap_discon_untimeout(ng_l2cap_con_p con)
{
if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO))
panic(
"%s: %s - no disconnect timeout, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
if (ng_uncallout(&con->con_timo, con->l2cap->node) == 0)
return (ETIMEDOUT);
con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
return (0);
} /* ng_l2cap_discon_untimeout */
/*
* Free connection descriptor. Will unlink connection and free everything.
*/
void
ng_l2cap_free_con(ng_l2cap_con_p con)
{
ng_l2cap_chan_p f = NULL, n = NULL;
con->state = NG_L2CAP_CON_CLOSED;
while (con->tx_pkt != NULL) {
struct mbuf *m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
NG_FREE_M(con->rx_pkt);
for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) {
n = LIST_NEXT(f, next);
if (f->con == con)
ng_l2cap_free_chan(f);
f = n;
}
while (!TAILQ_EMPTY(&con->cmd_list)) {
ng_l2cap_cmd_p cmd = TAILQ_FIRST(&con->cmd_list);
ng_l2cap_unlink_cmd(cmd);
if (cmd->flags & NG_L2CAP_CMD_PENDING)
ng_l2cap_command_untimeout(cmd);
ng_l2cap_free_cmd(cmd);
}
if (con->flags & (NG_L2CAP_CON_AUTO_DISCON_TIMO|NG_L2CAP_CON_LP_TIMO))
panic(
"%s: %s - timeout pending! state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
LIST_REMOVE(con, next);
bzero(con, sizeof(*con));
free(con, M_NETGRAPH_L2CAP);
} /* ng_l2cap_free_con */
/*
* Get connection by "remote" address
*/
ng_l2cap_con_p
ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr, unsigned int type)
{
ng_l2cap_con_p con = NULL;
LIST_FOREACH(con, &l2cap->con_list, next)
if ((bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)&&
(con->linktype == type))
break;
return (con);
} /* ng_l2cap_con_by_addr */
/*
* Get connection by "handle"
*/
ng_l2cap_con_p
ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
{
ng_l2cap_con_p con = NULL;
LIST_FOREACH(con, &l2cap->con_list, next)
if (con->con_handle == con_handle)
break;
return (con);
} /* ng_l2cap_con_by_handle */
/*
* Allocate new L2CAP channel descriptor on "con" connection with "psm".
* Will link the channel to the l2cap node
*/
ng_l2cap_chan_p
ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm, int idtype)
{
ng_l2cap_chan_p ch = NULL;
ch = malloc(sizeof(*ch), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (ch == NULL)
return (NULL);
if(idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
ch->scid = ch->dcid = NG_L2CAP_ATT_CID;
}else if(idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
ch->scid = ch->dcid = NG_L2CAP_SMP_CID;
}else{
ch->scid = ng_l2cap_get_cid(l2cap,
(con->linktype!= NG_HCI_LINK_ACL));
}
ch->idtype = idtype;
if (ch->scid != NG_L2CAP_NULL_CID) {
/* Initialize channel */
ch->psm = psm;
ch->con = con;
ch->state = NG_L2CAP_CLOSED;
/* Set MTU and flow control settings to defaults */
ch->imtu = NG_L2CAP_MTU_DEFAULT;
bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow));
ch->omtu = NG_L2CAP_MTU_DEFAULT;
bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow));
ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
LIST_INSERT_HEAD(&l2cap->chan_list, ch, next);
ng_l2cap_con_ref(con);
} else {
bzero(ch, sizeof(*ch));
free(ch, M_NETGRAPH_L2CAP);
ch = NULL;
}
return (ch);
} /* ng_l2cap_new_chan */
ng_l2cap_chan_p
ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid, int idtype)
{
ng_l2cap_chan_p ch = NULL;
if((idtype == NG_L2CAP_L2CA_IDTYPE_ATT)||
(idtype == NG_L2CAP_L2CA_IDTYPE_SMP)){
return NULL;
}
LIST_FOREACH(ch, &l2cap->chan_list, next){
if((idtype != NG_L2CAP_L2CA_IDTYPE_BREDR)&&
(ch->con->linktype == NG_HCI_LINK_ACL ))
continue;
if((idtype != NG_L2CAP_L2CA_IDTYPE_LE)&&
(ch->con->linktype != NG_HCI_LINK_ACL ))
continue;
if (ch->scid == scid)
break;
}
return (ch);
} /* ng_l2cap_chan_by_scid */
ng_l2cap_chan_p
ng_l2cap_chan_by_conhandle(ng_l2cap_p l2cap, uint16_t scid,
u_int16_t con_handle)
{
ng_l2cap_chan_p ch = NULL;
LIST_FOREACH(ch, &l2cap->chan_list, next){
if ((ch->scid == scid) &&
(ch->con->con_handle == con_handle))
break;
}
return (ch);
} /* ng_l2cap_chan_by_scid */
/*
* Free channel descriptor.
*/
void
ng_l2cap_free_chan(ng_l2cap_chan_p ch)
{
ng_l2cap_cmd_p f = NULL, n = NULL;
f = TAILQ_FIRST(&ch->con->cmd_list);
while (f != NULL) {
n = TAILQ_NEXT(f, next);
if (f->ch == ch) {
ng_l2cap_unlink_cmd(f);
if (f->flags & NG_L2CAP_CMD_PENDING)
ng_l2cap_command_untimeout(f);
ng_l2cap_free_cmd(f);
}
f = n;
}
LIST_REMOVE(ch, next);
ng_l2cap_con_unref(ch->con);
bzero(ch, sizeof(*ch));
free(ch, M_NETGRAPH_L2CAP);
} /* ng_l2cap_free_chan */
/*
* Create new L2CAP command descriptor. WILL NOT add command to the queue.
*/
ng_l2cap_cmd_p
ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident,
u_int8_t code, u_int32_t token)
{
ng_l2cap_cmd_p cmd = NULL;
KASSERT((ch == NULL || ch->con == con),
("%s: %s - invalid channel pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
cmd = malloc(sizeof(*cmd), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (cmd == NULL)
return (NULL);
cmd->con = con;
cmd->ch = ch;
cmd->ident = ident;
cmd->code = code;
cmd->token = token;
ng_callout_init(&cmd->timo);
return (cmd);
} /* ng_l2cap_new_cmd */
/*
* Get pending (i.e. initiated by local side) L2CAP command descriptor by ident
*/
ng_l2cap_cmd_p
ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
{
ng_l2cap_cmd_p cmd = NULL;
TAILQ_FOREACH(cmd, &con->cmd_list, next) {
if ((cmd->flags & NG_L2CAP_CMD_PENDING) && cmd->ident == ident) {
KASSERT((cmd->con == con),
("%s: %s - invalid connection pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
break;
}
}
return (cmd);
} /* ng_l2cap_cmd_by_ident */
/*
* Set LP timeout
* XXX FIXME: check return code from ng_callout
*/
int
ng_l2cap_lp_timeout(ng_l2cap_con_p con)
{
if (con->flags & (NG_L2CAP_CON_LP_TIMO|NG_L2CAP_CON_AUTO_DISCON_TIMO))
panic(
"%s: %s - invalid timeout, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
con->flags |= NG_L2CAP_CON_LP_TIMO;
ng_callout(&con->con_timo, con->l2cap->node, NULL,
bluetooth_hci_connect_timeout(),
ng_l2cap_process_lp_timeout, NULL,
con->con_handle);
return (0);
} /* ng_l2cap_lp_timeout */
/*
* Unset LP timeout
*/
int
ng_l2cap_lp_untimeout(ng_l2cap_con_p con)
{
if (!(con->flags & NG_L2CAP_CON_LP_TIMO))
panic(
"%s: %s - no LP connection timeout, state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
if (ng_uncallout(&con->con_timo, con->l2cap->node) == 0)
return (ETIMEDOUT);
con->flags &= ~NG_L2CAP_CON_LP_TIMO;
return (0);
} /* ng_l2cap_lp_untimeout */
/*
* Set L2CAP command timeout
* XXX FIXME: check return code from ng_callout
*/
int
ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
{
int arg;
if (cmd->flags & NG_L2CAP_CMD_PENDING)
panic(
"%s: %s - duplicated command timeout, code=%#x, flags=%#x\n",
__func__, NG_NODE_NAME(cmd->con->l2cap->node),
cmd->code, cmd->flags);
arg = ((cmd->ident << 16) | cmd->con->con_handle);
cmd->flags |= NG_L2CAP_CMD_PENDING;
ng_callout(&cmd->timo, cmd->con->l2cap->node, NULL, timo,
ng_l2cap_process_command_timeout, NULL, arg);
return (0);
} /* ng_l2cap_command_timeout */
/*
* Unset L2CAP command timeout
*/
int
ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
{
if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
panic(
"%s: %s - no command timeout, code=%#x, flags=%#x\n",
__func__, NG_NODE_NAME(cmd->con->l2cap->node),
cmd->code, cmd->flags);
if (ng_uncallout(&cmd->timo, cmd->con->l2cap->node) == 0)
return (ETIMEDOUT);
cmd->flags &= ~NG_L2CAP_CMD_PENDING;
return (0);
} /* ng_l2cap_command_untimeout */
/*
* Prepend "m"buf with "size" bytes
*/
struct mbuf *
ng_l2cap_prepend(struct mbuf *m, int size)
{
M_PREPEND(m, size, M_NOWAIT);
if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
return (NULL);
return (m);
} /* ng_l2cap_prepend */
/*
* Default flow settings
*/
ng_l2cap_flow_p
ng_l2cap_default_flow(void)
{
static ng_l2cap_flow_t default_flow = {
/* flags */ 0x0,
/* service_type */ NG_HCI_SERVICE_TYPE_BEST_EFFORT,
/* token_rate */ 0xffffffff, /* maximum */
/* token_bucket_size */ 0xffffffff, /* maximum */
/* peak_bandwidth */ 0x00000000, /* maximum */
/* latency */ 0xffffffff, /* don't care */
/* delay_variation */ 0xffffffff /* don't care */
};
return (&default_flow);
} /* ng_l2cap_default_flow */
/*
* Get next available channel ID
* XXX FIXME this is *UGLY* but will do for now
*/
static u_int16_t
ng_l2cap_get_cid(ng_l2cap_p l2cap,int isle)
{
u_int16_t cid ;
u_int16_t endcid;
uint16_t mask;
int idtype;
if(isle){
endcid = l2cap->lecid;
/*Assume Last CID is 2^n-1 */
mask = NG_L2CAP_LELAST_CID;
idtype = NG_L2CAP_L2CA_IDTYPE_LE;
}else{
endcid = l2cap->cid;
/*Assume Last CID is 2^n-1 */
mask = NG_L2CAP_LAST_CID;
idtype = NG_L2CAP_L2CA_IDTYPE_BREDR;
}
cid = (endcid+1) & mask;
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
while (cid != endcid) {
if (ng_l2cap_chan_by_scid(l2cap, cid, idtype) == NULL) {
if(!isle){
l2cap->cid = cid;
}else{
l2cap->lecid = cid;
}
return (cid);
}
cid ++;
cid &= mask;
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
}
return (NG_L2CAP_NULL_CID);
} /* ng_l2cap_get_cid */
/*
* Get next available command ident
* XXX FIXME this is *UGLY* but will do for now
*/
u_int8_t
ng_l2cap_get_ident(ng_l2cap_con_p con)
{
u_int8_t ident = con->ident + 1;
if (ident < NG_L2CAP_FIRST_IDENT)
ident = NG_L2CAP_FIRST_IDENT;
while (ident != con->ident) {
if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
con->ident = ident;
return (ident);
}
ident ++;
if (ident < NG_L2CAP_FIRST_IDENT)
ident = NG_L2CAP_FIRST_IDENT;
}
return (NG_L2CAP_NULL_IDENT);
} /* ng_l2cap_get_ident */

View File

@ -0,0 +1,108 @@
/*
* ng_l2cap_misc.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_misc.h,v 1.3 2003/09/08 19:11:45 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_MISC_H_
#define _NETGRAPH_L2CAP_MISC_H_
void ng_l2cap_send_hook_info (node_p, hook_p, void *, int);
/*
* ACL Connections
*/
ng_l2cap_con_p ng_l2cap_new_con (ng_l2cap_p, bdaddr_p, int);
void ng_l2cap_con_ref (ng_l2cap_con_p);
void ng_l2cap_con_unref (ng_l2cap_con_p);
ng_l2cap_con_p ng_l2cap_con_by_addr (ng_l2cap_p, bdaddr_p, unsigned int);
ng_l2cap_con_p ng_l2cap_con_by_handle (ng_l2cap_p, u_int16_t);
void ng_l2cap_free_con (ng_l2cap_con_p);
/*
* L2CAP channels
*/
ng_l2cap_chan_p ng_l2cap_new_chan (ng_l2cap_p, ng_l2cap_con_p, u_int16_t, int);
ng_l2cap_chan_p ng_l2cap_chan_by_scid (ng_l2cap_p, u_int16_t, int);
ng_l2cap_chan_p ng_l2cap_chan_by_conhandle(ng_l2cap_p , uint16_t , u_int16_t);
void ng_l2cap_free_chan (ng_l2cap_chan_p);
/*
* L2CAP command descriptors
*/
#define ng_l2cap_link_cmd(con, cmd) \
do { \
TAILQ_INSERT_TAIL(&(con)->cmd_list, (cmd), next); \
ng_l2cap_con_ref((con)); \
} while (0)
#define ng_l2cap_unlink_cmd(cmd) \
do { \
TAILQ_REMOVE(&((cmd)->con->cmd_list), (cmd), next); \
ng_l2cap_con_unref((cmd)->con); \
} while (0)
#define ng_l2cap_free_cmd(cmd) \
do { \
KASSERT(!callout_pending(&(cmd)->timo), ("Pending callout!")); \
NG_FREE_M((cmd)->aux); \
bzero((cmd), sizeof(*(cmd))); \
free((cmd), M_NETGRAPH_L2CAP); \
} while (0)
ng_l2cap_cmd_p ng_l2cap_new_cmd (ng_l2cap_con_p, ng_l2cap_chan_p,
u_int8_t, u_int8_t, u_int32_t);
ng_l2cap_cmd_p ng_l2cap_cmd_by_ident (ng_l2cap_con_p, u_int8_t);
u_int8_t ng_l2cap_get_ident (ng_l2cap_con_p);
/*
* Timeout
*/
int ng_l2cap_discon_timeout (ng_l2cap_con_p);
int ng_l2cap_discon_untimeout (ng_l2cap_con_p);
int ng_l2cap_lp_timeout (ng_l2cap_con_p);
int ng_l2cap_lp_untimeout (ng_l2cap_con_p);
int ng_l2cap_command_timeout (ng_l2cap_cmd_p, int);
int ng_l2cap_command_untimeout (ng_l2cap_cmd_p);
/*
* Other stuff
*/
struct mbuf * ng_l2cap_prepend (struct mbuf *, int);
ng_l2cap_flow_p ng_l2cap_default_flow (void);
#endif /* ndef _NETGRAPH_L2CAP_MISC_H_ */

View File

@ -0,0 +1,87 @@
/*
* ng_l2cap_prse.h
*/
/*-
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_prse.h,v 1.2 2003/04/28 21:44:59 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the L2CAP node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_L2CAP_PRSE_H_
#define _NETGRAPH_L2CAP_PRSE_H_
/*
* L2CAP node command list
*/
static const struct ng_cmdlist ng_l2cap_cmdlist[] = {
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_GET_FLAGS,
"get_flags",
NULL,
&ng_parse_uint16_type
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
"get_disc_timo",
NULL,
&ng_parse_uint16_type
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
"set_disc_timo",
&ng_parse_uint16_type,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_L2CAP_PRSE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/*
* ng_l2cap_ulpi.h
*/
/*-
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_ulpi.h,v 1.1 2002/11/24 19:47:06 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_ULPI_H_
#define _NETGRAPH_L2CAP_ULPI_H_
int ng_l2cap_l2ca_con_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_con_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t, u_int16_t);
int ng_l2cap_l2ca_con_rsp_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_con_rsp_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_con_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_cfg_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_cfg_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_cfg_rsp_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_cfg_rsp_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_cfg_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_write_req (ng_l2cap_p, struct mbuf *);
int ng_l2cap_l2ca_write_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t, u_int16_t);
int ng_l2cap_l2ca_receive (ng_l2cap_con_p);
int ng_l2cap_l2ca_clt_receive (ng_l2cap_con_p);
int ng_l2cap_l2ca_qos_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_discon_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_discon_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_discon_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_grp_create (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_close (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_add_member_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_add_member_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_grp_rem_member (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_get_members (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_ping_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_ping_rsp (ng_l2cap_con_p, u_int32_t, u_int16_t,
struct mbuf *);
int ng_l2cap_l2ca_get_info_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_get_info_rsp (ng_l2cap_con_p, u_int32_t, u_int16_t,
struct mbuf *);
int ng_l2cap_l2ca_enable_clt (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p , uint16_t );
#endif /* ndef _NETGRAPH_L2CAP_ULPI_H_ */

View File

@ -0,0 +1,194 @@
/*
* ng_l2cap_var.h
*/
/*-
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_l2cap_var.h,v 1.2 2003/04/28 21:44:59 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_VAR_H_
#define _NETGRAPH_L2CAP_VAR_H_
/* MALLOC decalation */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_L2CAP);
#else
#define M_NETGRAPH_L2CAP M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Debug */
#define NG_L2CAP_ALERT if (l2cap->debug >= NG_L2CAP_ALERT_LEVEL) printf
#define NG_L2CAP_ERR if (l2cap->debug >= NG_L2CAP_ERR_LEVEL) printf
#define NG_L2CAP_WARN if (l2cap->debug >= NG_L2CAP_WARN_LEVEL) printf
#define NG_L2CAP_INFO if (l2cap->debug >= NG_L2CAP_INFO_LEVEL) printf
/* Wrapper around m_pullup */
#define NG_L2CAP_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) \
NG_L2CAP_ALERT("%s: %s - m_pullup(%zd) failed\n", \
__func__, NG_NODE_NAME(l2cap->node), (s)); \
} while (0)
/*
* L2CAP signaling command ident's are assigned relative to the connection,
* because there is only one signaling channel (cid == 0x01) for every
* connection. So up to 254 (0xff - 0x01) L2CAP commands can be pending at the
* same time for the same connection.
*/
#define NG_L2CAP_NULL_IDENT 0x00 /* DO NOT USE THIS IDENT */
#define NG_L2CAP_FIRST_IDENT 0x01 /* dynamically alloc. (start) */
#define NG_L2CAP_LAST_IDENT 0xff /* dynamically alloc. (end) */
/*
* L2CAP (Node private)
*/
struct ng_l2cap_con;
struct ng_l2cap_chan;
typedef struct ng_l2cap {
node_p node; /* node ptr */
ng_l2cap_node_debug_ep debug; /* debug level */
ng_l2cap_node_flags_ep flags; /* L2CAP node flags */
ng_l2cap_node_auto_discon_ep discon_timo; /* auto discon. timeout */
u_int16_t pkt_size; /* max. ACL packet size */
u_int16_t num_pkts; /* out queue size */
bdaddr_t bdaddr; /* unit BDADDR */
hook_p hci; /* HCI downstream hook */
hook_p l2c; /* L2CAP upstream hook */
hook_p ctl; /* control hook */
LIST_HEAD(, ng_l2cap_con) con_list; /* ACL connections */
u_int16_t cid; /* last allocated CID */
u_int16_t lecid; /* last allocated CID for LE */
LIST_HEAD(, ng_l2cap_chan) chan_list; /* L2CAP channels */
} ng_l2cap_t;
typedef ng_l2cap_t * ng_l2cap_p;
/*
* L2CAP connection descriptor
*/
struct ng_l2cap_cmd;
typedef struct ng_l2cap_con {
ng_l2cap_p l2cap; /* pointer to L2CAP */
u_int16_t state; /* ACL connection state */
u_int16_t flags; /* ACL connection flags */
int32_t refcnt; /* reference count */
bdaddr_t remote; /* remote unit address */
u_int16_t con_handle; /* ACL connection handle */
struct callout con_timo; /* connection timeout */
u_int8_t ident; /* last allocated ident */
uint8_t linktype;
uint8_t encryption;
TAILQ_HEAD(, ng_l2cap_cmd) cmd_list; /* pending L2CAP cmds */
struct mbuf *tx_pkt; /* xmitted L2CAP packet */
int pending; /* num. of pending pkts */
struct mbuf *rx_pkt; /* received L2CAP packet */
int rx_pkt_len; /* packet len. so far */
LIST_ENTRY(ng_l2cap_con) next; /* link */
} ng_l2cap_con_t;
typedef ng_l2cap_con_t * ng_l2cap_con_p;
/*
* L2CAP channel descriptor
*/
typedef struct ng_l2cap_chan {
ng_l2cap_con_p con; /* pointer to connection */
u_int16_t state; /* channel state */
u_int8_t cfg_state; /* configuration state */
#define NG_L2CAP_CFG_IN (1 << 0) /* incoming cfg path done */
#define NG_L2CAP_CFG_OUT (1 << 1) /* outgoing cfg path done */
#define NG_L2CAP_CFG_BOTH (NG_L2CAP_CFG_IN|NG_L2CAP_CFG_OUT)
u_int8_t ident; /* last L2CAP req. ident */
u_int16_t psm; /* channel PSM */
u_int16_t scid; /* source channel ID */
u_int16_t dcid; /* destination channel ID */
uint16_t idtype;
u_int16_t imtu; /* incoming channel MTU */
ng_l2cap_flow_t iflow; /* incoming flow control */
u_int16_t omtu; /* outgoing channel MTU */
ng_l2cap_flow_t oflow; /* outgoing flow control */
u_int16_t flush_timo; /* flush timeout */
u_int16_t link_timo; /* link timeout */
LIST_ENTRY(ng_l2cap_chan) next; /* link */
} ng_l2cap_chan_t;
typedef ng_l2cap_chan_t * ng_l2cap_chan_p;
/*
* L2CAP command descriptor
*/
typedef struct ng_l2cap_cmd {
ng_l2cap_con_p con; /* L2CAP connection */
ng_l2cap_chan_p ch; /* L2CAP channel */
u_int16_t flags; /* command flags */
#define NG_L2CAP_CMD_PENDING (1 << 0) /* command is pending */
u_int8_t code; /* L2CAP command opcode */
u_int8_t ident; /* L2CAP command ident */
u_int32_t token; /* L2CA message token */
struct callout timo; /* RTX/ERTX timeout */
struct mbuf *aux; /* optional data */
TAILQ_ENTRY(ng_l2cap_cmd) next; /* link */
} ng_l2cap_cmd_t;
typedef ng_l2cap_cmd_t * ng_l2cap_cmd_p;
#endif /* ndef _NETGRAPH_L2CAP_VAR_H_ */

View File

@ -0,0 +1,15 @@
$Id: TODO,v 1.1 2002/11/24 19:47:07 max Exp $
$FreeBSD$
FIXME/TODO list
1) Deal properly with "shutdown"s and hook "disconnect"s
How to let L2CAP node that user called "shutdown" on node or
have "disconnect"ed downstream hook. Should L2CAP node deal
with it?
2) Locking
It is OK to use mutexes, but is there a better way?

View File

@ -0,0 +1,289 @@
/*
* ng_btsocket.c
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_btsocket.c,v 1.4 2003/09/14 23:29:06 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bitstring.h>
#include <sys/errno.h>
#include <sys/domain.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <net/vnet.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/bluetooth/include/ng_bluetooth.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/include/ng_btsocket.h>
#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
#include <netgraph/bluetooth/include/ng_btsocket_sco.h>
static int ng_btsocket_modevent (module_t, int, void *);
static struct domain ng_btsocket_domain;
/*
* Bluetooth raw HCI sockets
*/
static struct pr_usrreqs ng_btsocket_hci_raw_usrreqs = {
.pru_abort = ng_btsocket_hci_raw_abort,
.pru_attach = ng_btsocket_hci_raw_attach,
.pru_bind = ng_btsocket_hci_raw_bind,
.pru_connect = ng_btsocket_hci_raw_connect,
.pru_control = ng_btsocket_hci_raw_control,
.pru_detach = ng_btsocket_hci_raw_detach,
.pru_disconnect = ng_btsocket_hci_raw_disconnect,
.pru_peeraddr = ng_btsocket_hci_raw_peeraddr,
.pru_send = ng_btsocket_hci_raw_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_hci_raw_sockaddr,
.pru_close = ng_btsocket_hci_raw_close,
};
/*
* Bluetooth raw L2CAP sockets
*/
static struct pr_usrreqs ng_btsocket_l2cap_raw_usrreqs = {
.pru_abort = ng_btsocket_l2cap_raw_abort,
.pru_attach = ng_btsocket_l2cap_raw_attach,
.pru_bind = ng_btsocket_l2cap_raw_bind,
.pru_connect = ng_btsocket_l2cap_raw_connect,
.pru_control = ng_btsocket_l2cap_raw_control,
.pru_detach = ng_btsocket_l2cap_raw_detach,
.pru_disconnect = ng_btsocket_l2cap_raw_disconnect,
.pru_peeraddr = ng_btsocket_l2cap_raw_peeraddr,
.pru_send = ng_btsocket_l2cap_raw_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_l2cap_raw_sockaddr,
.pru_close = ng_btsocket_l2cap_raw_close,
};
/*
* Bluetooth SEQPACKET L2CAP sockets
*/
static struct pr_usrreqs ng_btsocket_l2cap_usrreqs = {
.pru_abort = ng_btsocket_l2cap_abort,
.pru_accept = ng_btsocket_l2cap_accept,
.pru_attach = ng_btsocket_l2cap_attach,
.pru_bind = ng_btsocket_l2cap_bind,
.pru_connect = ng_btsocket_l2cap_connect,
.pru_control = ng_btsocket_l2cap_control,
.pru_detach = ng_btsocket_l2cap_detach,
.pru_disconnect = ng_btsocket_l2cap_disconnect,
.pru_listen = ng_btsocket_l2cap_listen,
.pru_peeraddr = ng_btsocket_l2cap_peeraddr,
.pru_send = ng_btsocket_l2cap_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_l2cap_sockaddr,
.pru_close = ng_btsocket_l2cap_close,
};
/*
* Bluetooth STREAM RFCOMM sockets
*/
static struct pr_usrreqs ng_btsocket_rfcomm_usrreqs = {
.pru_abort = ng_btsocket_rfcomm_abort,
.pru_accept = ng_btsocket_rfcomm_accept,
.pru_attach = ng_btsocket_rfcomm_attach,
.pru_bind = ng_btsocket_rfcomm_bind,
.pru_connect = ng_btsocket_rfcomm_connect,
.pru_control = ng_btsocket_rfcomm_control,
.pru_detach = ng_btsocket_rfcomm_detach,
.pru_disconnect = ng_btsocket_rfcomm_disconnect,
.pru_listen = ng_btsocket_rfcomm_listen,
.pru_peeraddr = ng_btsocket_rfcomm_peeraddr,
.pru_send = ng_btsocket_rfcomm_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_rfcomm_sockaddr,
.pru_close = ng_btsocket_rfcomm_close,
};
/*
* Bluetooth SEQPACKET SCO sockets
*/
static struct pr_usrreqs ng_btsocket_sco_usrreqs = {
.pru_abort = ng_btsocket_sco_abort,
.pru_accept = ng_btsocket_sco_accept,
.pru_attach = ng_btsocket_sco_attach,
.pru_bind = ng_btsocket_sco_bind,
.pru_connect = ng_btsocket_sco_connect,
.pru_control = ng_btsocket_sco_control,
.pru_detach = ng_btsocket_sco_detach,
.pru_disconnect = ng_btsocket_sco_disconnect,
.pru_listen = ng_btsocket_sco_listen,
.pru_peeraddr = ng_btsocket_sco_peeraddr,
.pru_send = ng_btsocket_sco_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_sco_sockaddr,
.pru_close = ng_btsocket_sco_close,
};
/*
* Definitions of protocols supported in the BLUETOOTH domain
*/
static struct protosw ng_btsocket_protosw[] = {
{
.pr_type = SOCK_RAW,
.pr_domain = &ng_btsocket_domain,
.pr_protocol = BLUETOOTH_PROTO_HCI,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_ctloutput = ng_btsocket_hci_raw_ctloutput,
.pr_init = ng_btsocket_hci_raw_init,
.pr_usrreqs = &ng_btsocket_hci_raw_usrreqs,
},
{
.pr_type = SOCK_RAW,
.pr_domain = &ng_btsocket_domain,
.pr_protocol = BLUETOOTH_PROTO_L2CAP,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_init = ng_btsocket_l2cap_raw_init,
.pr_usrreqs = &ng_btsocket_l2cap_raw_usrreqs,
},
{
.pr_type = SOCK_SEQPACKET,
.pr_domain = &ng_btsocket_domain,
.pr_protocol = BLUETOOTH_PROTO_L2CAP,
.pr_flags = PR_ATOMIC|PR_CONNREQUIRED,
.pr_ctloutput = ng_btsocket_l2cap_ctloutput,
.pr_init = ng_btsocket_l2cap_init,
.pr_usrreqs = &ng_btsocket_l2cap_usrreqs,
},
{
.pr_type = SOCK_STREAM,
.pr_domain = &ng_btsocket_domain,
.pr_protocol = BLUETOOTH_PROTO_RFCOMM,
.pr_flags = PR_CONNREQUIRED,
.pr_ctloutput = ng_btsocket_rfcomm_ctloutput,
.pr_init = ng_btsocket_rfcomm_init,
.pr_usrreqs = &ng_btsocket_rfcomm_usrreqs,
},
{
.pr_type = SOCK_SEQPACKET,
.pr_domain = &ng_btsocket_domain,
.pr_protocol = BLUETOOTH_PROTO_SCO,
.pr_flags = PR_ATOMIC|PR_CONNREQUIRED,
.pr_ctloutput = ng_btsocket_sco_ctloutput,
.pr_init = ng_btsocket_sco_init,
.pr_usrreqs = &ng_btsocket_sco_usrreqs,
},
};
#define ng_btsocket_protosw_end \
&ng_btsocket_protosw[nitems(ng_btsocket_protosw)]
/*
* BLUETOOTH domain
*/
static struct domain ng_btsocket_domain = {
.dom_family = AF_BLUETOOTH,
.dom_name = "bluetooth",
.dom_protosw = ng_btsocket_protosw,
.dom_protoswNPROTOSW = ng_btsocket_protosw_end
};
/*
* Socket sysctl tree
*/
SYSCTL_NODE(_net_bluetooth_hci, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth HCI sockets family");
SYSCTL_NODE(_net_bluetooth_l2cap, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth L2CAP sockets family");
SYSCTL_NODE(_net_bluetooth_rfcomm, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth RFCOMM sockets family");
SYSCTL_NODE(_net_bluetooth_sco, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth SCO sockets family");
/*
* Module
*/
static moduledata_t ng_btsocket_mod = {
"ng_btsocket",
ng_btsocket_modevent,
NULL
};
DECLARE_MODULE(ng_btsocket, ng_btsocket_mod, SI_SUB_PROTO_DOMAIN,
SI_ORDER_ANY);
MODULE_VERSION(ng_btsocket, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_btsocket, ng_bluetooth, NG_BLUETOOTH_VERSION,
NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_btsocket, netgraph, NG_ABI_VERSION,
NG_ABI_VERSION, NG_ABI_VERSION);
/*
* Handle loading and unloading for this node type.
* This is to handle auxiliary linkages (e.g protocol domain addition).
*/
static int
ng_btsocket_modevent(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
break;
case MOD_UNLOAD:
/* XXX can't unload protocol domain yet */
error = EBUSY;
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
} /* ng_btsocket_modevent */
VNET_DOMAIN_SET(ng_btsocket_);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
/*-
* Copyright (c) 2010-2011 Alexander V. Chernikov <melifaro@ipfw.ru>
* Copyright (c) 2004 Gleb Smirnoff <glebius@FreeBSD.org>
* 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.
*
* $SourceForge: netflow.h,v 1.8 2004/09/16 17:05:11 glebius Exp $
* $FreeBSD$
*/
/* netflow timeouts in seconds */
#define ACTIVE_TIMEOUT (30*60) /* maximum flow lifetime is 30 min */
#define INACTIVE_TIMEOUT 15
/*
* More info can be found in these Cisco documents:
*
* Cisco IOS NetFlow, White Papers.
* http://www.cisco.com/en/US/products/ps6601/prod_white_papers_list.html
*
* Cisco CNS NetFlow Collection Engine User Guide, 5.0.2, NetFlow Export
* Datagram Formats.
* http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_user_guide_chapter09186a00803f3147.html#wp26453
*
* Cisco Systems NetFlow Services Export Version 9
* http://www.ietf.org/rfc/rfc3954.txt
*
*/
#define NETFLOW_V1 1
#define NETFLOW_V5 5
#define NETFLOW_V9 9
struct netflow_v1_header
{
uint16_t version; /* NetFlow version */
uint16_t count; /* Number of records in flow */
uint32_t sys_uptime; /* System uptime */
uint32_t unix_secs; /* Current seconds since 0000 UTC 1970 */
uint32_t unix_nsecs; /* Remaining nanoseconds since 0000 UTC 1970 */
} __attribute__((__packed__));
struct netflow_v5_header
{
uint16_t version; /* NetFlow version */
uint16_t count; /* Number of records in flow */
uint32_t sys_uptime; /* System uptime */
uint32_t unix_secs; /* Current seconds since 0000 UTC 1970 */
uint32_t unix_nsecs; /* Remaining nanoseconds since 0000 UTC 1970 */
uint32_t flow_seq; /* Sequence number of the first record */
uint8_t engine_type; /* Type of flow switching engine (RP,VIP,etc.) */
uint8_t engine_id; /* Slot number of the flow switching engine */
uint16_t pad; /* Pad to word boundary */
} __attribute__((__packed__));
struct netflow_v9_header
{
uint16_t version; /* NetFlow version */
uint16_t count; /* Total number of records in packet */
uint32_t sys_uptime; /* System uptime */
uint32_t unix_secs; /* Current seconds since 0000 UTC 1970 */
uint32_t seq_num; /* Sequence number */
uint32_t source_id; /* Observation Domain id */
} __attribute__((__packed__));
struct netflow_v1_record
{
uint32_t src_addr; /* Source IP address */
uint32_t dst_addr; /* Destination IP address */
uint32_t next_hop; /* Next hop IP address */
uint16_t in_ifx; /* Source interface index */
uint16_t out_ifx; /* Destination interface index */
uint32_t packets; /* Number of packets in a flow */
uint32_t octets; /* Number of octets in a flow */
uint32_t first; /* System uptime at start of a flow */
uint32_t last; /* System uptime at end of a flow */
uint16_t s_port; /* Source port */
uint16_t d_port; /* Destination port */
uint16_t pad1; /* Pad to word boundary */
uint8_t prot; /* IP protocol */
uint8_t tos; /* IP type of service */
uint8_t flags; /* Cumulative OR of tcp flags */
uint8_t pad2; /* Pad to word boundary */
uint16_t pad3; /* Pad to word boundary */
uint8_t reserved[5]; /* Reserved for future use */
} __attribute__((__packed__));
struct netflow_v5_record
{
uint32_t src_addr; /* Source IP address */
uint32_t dst_addr; /* Destination IP address */
uint32_t next_hop; /* Next hop IP address */
uint16_t i_ifx; /* Source interface index */
uint16_t o_ifx; /* Destination interface index */
uint32_t packets; /* Number of packets in a flow */
uint32_t octets; /* Number of octets in a flow */
uint32_t first; /* System uptime at start of a flow */
uint32_t last; /* System uptime at end of a flow */
uint16_t s_port; /* Source port */
uint16_t d_port; /* Destination port */
uint8_t pad1; /* Pad to word boundary */
uint8_t flags; /* Cumulative OR of tcp flags */
uint8_t prot; /* IP protocol */
uint8_t tos; /* IP type of service */
uint16_t src_as; /* Src peer/origin Autonomous System */
uint16_t dst_as; /* Dst peer/origin Autonomous System */
uint8_t src_mask; /* Source route's mask bits */
uint8_t dst_mask; /* Destination route's mask bits */
uint16_t pad2; /* Pad to word boundary */
} __attribute__((__packed__));
#define NETFLOW_V1_MAX_RECORDS 24
#define NETFLOW_V5_MAX_RECORDS 30
#define NETFLOW_V1_MAX_SIZE (sizeof(netflow_v1_header)+ \
sizeof(netflow_v1_record)*NETFLOW_V1_MAX_RECORDS)
#define NETFLOW_V5_MAX_SIZE (sizeof(netflow_v5_header)+ \
sizeof(netflow_v5_record)*NETFLOW_V5_MAX_RECORDS)
struct netflow_v5_export_dgram {
struct netflow_v5_header header;
struct netflow_v5_record r[NETFLOW_V5_MAX_RECORDS];
} __attribute__((__packed__));
/* RFC3954 field definitions */
#define NETFLOW_V9_FIELD_IN_BYTES 1 /* Input bytes count for a flow. Default 4, can be 8 */
#define NETFLOW_V9_FIELD_IN_PKTS 2 /* Incoming counter with number of packets associated with an IP Flow. Default 4 */
#define NETFLOW_V9_FIELD_FLOWS 3 /* Number of Flows that were aggregated. Default 4 */
#define NETFLOW_V9_FIELD_PROTOCOL 4 /* IP protocol byte. 1 */
#define NETFLOW_V9_FIELD_TOS 5 /* Type of service byte setting when entering the incoming interface. 1 */
#define NETFLOW_V9_FIELD_TCP_FLAGS 6 /* TCP flags; cumulative of all the TCP flags seen in this Flow. 1 */
#define NETFLOW_V9_FIELD_L4_SRC_PORT 7 /* TCP/UDP source port number. 2 */
#define NETFLOW_V9_FIELD_IPV4_SRC_ADDR 8 /* IPv4 source address. 4 */
#define NETFLOW_V9_FIELD_SRC_MASK 9 /* The number of contiguous bits in the source subnet mask (i.e., the mask in slash notation). 1 */
#define NETFLOW_V9_FIELD_INPUT_SNMP 10 /* Input interface index. Default 2 */
#define NETFLOW_V9_FIELD_L4_DST_PORT 11 /* TCP/UDP destination port number. 2 */
#define NETFLOW_V9_FIELD_IPV4_DST_ADDR 12 /* IPv4 destination address. 4 */
#define NETFLOW_V9_FIELD_DST_MASK 13 /* The number of contiguous bits in the destination subnet mask (i.e., the mask in slash notation). 1 */
#define NETFLOW_V9_FIELD_OUTPUT_SNMP 14 /* Output interface index. Default 2 */
#define NETFLOW_V9_FIELD_IPV4_NEXT_HOP 15 /* IPv4 address of the next-hop router. 4 */
#define NETFLOW_V9_FIELD_SRC_AS 16 /* Source BGP autonomous system number. Default 2, can be 4 */
#define NETFLOW_V9_FIELD_DST_AS 17 /* Destination BGP autonomous system number. Default 2, can be 4 */
#define NETFLOW_V9_FIELD_BGP_IPV4_NEXT_HOP 18 /* Next-hop router's IP address in the BGP domain. 4 */
#define NETFLOW_V9_FIELD_MUL_DST_PKTS 19 /* IP multicast outgoing packet counter for packets associated with IP flow. Default 4 */
#define NETFLOW_V9_FIELD_MUL_DST_BYTES 20 /* IP multicast outgoing Octet (byte) counter for the number of bytes associated with IP flow. Default 4 */
#define NETFLOW_V9_FIELD_LAST_SWITCHED 21 /* sysUptime in msec at which the last packet of this Flow was switched. 4 */
#define NETFLOW_V9_FIELD_FIRST_SWITCHED 22 /* sysUptime in msec at which the first packet of this Flow was switched. 4 */
#define NETFLOW_V9_FIELD_OUT_BYTES 23 /* Outgoing counter for the number of bytes associated with an IP Flow. Default 4 */
#define NETFLOW_V9_FIELD_OUT_PKTS 24 /* Outgoing counter for the number of packets associated with an IP Flow. Default 4 */
#define NETFLOW_V9_FIELD_IPV6_SRC_ADDR 27 /* IPv6 source address. 16 */
#define NETFLOW_V9_FIELD_IPV6_DST_ADDR 28 /* IPv6 destination address. 16 */
#define NETFLOW_V9_FIELD_IPV6_SRC_MASK 29 /* Length of the IPv6 source mask in contiguous bits. 1 */
#define NETFLOW_V9_FIELD_IPV6_DST_MASK 30 /* Length of the IPv6 destination mask in contiguous bits. 1 */
#define NETFLOW_V9_FIELD_IPV6_FLOW_LABEL 31 /* IPv6 flow label as per RFC 2460 definition. 3 */
#define NETFLOW_V9_FIELD_ICMP_TYPE 32 /* Internet Control Message Protocol (ICMP) packet type; reported as ICMP Type * 256 + ICMP code. 2 */
#define NETFLOW_V9_FIELD_MUL_IGMP_TYPE 33 /* Internet Group Management Protocol (IGMP) packet type. 1 */
#define NETFLOW_V9_FIELD_SAMPLING_INTERVAL 34 /* When using sampled NetFlow, the rate at which packets are sampled; for example, a value of 100 indicates that one of every hundred packets is sampled. 4 */
#define NETFLOW_V9_FIELD_SAMPLING_ALGORITHM 35 /* For sampled NetFlow platform-wide: 0x01 deterministic sampling 0x02 random sampling. 1 */
#define NETFLOW_V9_FIELD_FLOW_ACTIVE_TIMEOUT 36 /* Timeout value (in seconds) for active flow entries in the NetFlow cache. 2 */
#define NETFLOW_V9_FIELD_FLOW_INACTIVE_TIMEOUT 37 /* Timeout value (in seconds) for inactive Flow entries in the NetFlow cache. 2 */
#define NETFLOW_V9_FIELD_ENGINE_TYPE 38 /* Type of Flow switching engine (route processor, linecard, etc...). 1 */
#define NETFLOW_V9_FIELD_ENGINE_ID 39 /* ID number of the Flow switching engine. 1 */
#define NETFLOW_V9_FIELD_TOTAL_BYTES_EXP 40 /* Counter with for the number of bytes exported by the Observation Domain. Default 4 */
#define NETFLOW_V9_FIELD_TOTAL_PKTS_EXP 41 /* Counter with for the number of packets exported by the Observation Domain. Default 4 */
#define NETFLOW_V9_FIELD_TOTAL_FLOWS_EXP 42 /* Counter with for the number of flows exported by the Observation Domain. Default 4 */
#define NETFLOW_V9_FIELD_MPLS_TOP_LABEL_TYPE 46 /* MPLS Top Label Type. 1 */
#define NETFLOW_V9_FIELD_MPLS_TOP_LABEL_IP_ADDR 47 /* Forwarding Equivalent Class corresponding to the MPLS Top Label. 4 */
#define NETFLOW_V9_FIELD_FLOW_SAMPLER_ID 48 /* Identifier shown in "show flow-sampler". 1 */
#define NETFLOW_V9_FIELD_FLOW_SAMPLER_MODE 49 /* The type of algorithm used for sampling data. 2 */
#define NETFLOW_V9_FIELD_FLOW_SAMPLER_RANDOM_INTERVAL 50 /* Packet interval at which to sample. 4. */
#define NETFLOW_V9_FIELD_DST_TOS 55 /* Type of Service byte setting when exiting outgoing interface. 1. */
#define NETFLOW_V9_FIELD_SRC_MAC 56 /* Source MAC Address. 6 */
#define NETFLOW_V9_FIELD_DST_MAC 57 /* Destination MAC Address. 6 */
#define NETFLOW_V9_FIELD_SRC_VLAN 58 /* Virtual LAN identifier associated with ingress interface. 2 */
#define NETFLOW_V9_FIELD_DST_VLAN 59 /* Virtual LAN identifier associated with egress interface. 2 */
#define NETFLOW_V9_FIELD_IP_PROTOCOL_VERSION 60 /* Internet Protocol Version. Set to 4 for IPv4, set to 6 for IPv6. If not present in the template, then version 4 is assumed. 1. */
#define NETFLOW_V9_FIELD_DIRECTION 61 /* Flow direction: 0 - ingress flow 1 - egress flow. 1 */
#define NETFLOW_V9_FIELD_IPV6_NEXT_HOP 62 /* IPv6 address of the next-hop router. 16 */
#define NETFLOW_V9_FIELD_BGP_IPV6_NEXT_HOP 63 /* Next-hop router in the BGP domain. 16 */
#define NETFLOW_V9_FIELD_IPV6_OPTION_HEADERS 64 /* Bit-encoded field identifying IPv6 option headers found in the flow */
#define NETFLOW_V9_FIELD_MPLS_LABEL_1 70 /* MPLS label at position 1 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_2 71 /* MPLS label at position 2 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_3 72 /* MPLS label at position 3 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_4 73 /* MPLS label at position 4 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_5 74 /* MPLS label at position 5 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_6 75 /* MPLS label at position 6 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_7 76 /* MPLS label at position 7 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_8 77 /* MPLS label at position 8 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_9 78 /* MPLS label at position 9 in the stack. 3 */
#define NETFLOW_V9_FIELD_MPLS_LABEL_10 79 /* MPLS label at position 10 in the stack. 3 */
#define NETFLOW_V9_MAX_RESERVED_FLOWSET 0xFF /* Clause 5.2 */

View File

@ -0,0 +1,493 @@
/*-
* Copyright (c) 2010 Alexander V. Chernikov <melifaro@ipfw.ru>
* 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.
*
* $FreeBSD$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include "opt_route.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/counter.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <vm/uma.h>
#include <net/if.h>
#include <net/route.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/netflow/netflow.h>
#include <netgraph/netflow/ng_netflow.h>
#include <netgraph/netflow/netflow_v9.h>
MALLOC_DECLARE(M_NETFLOW_GENERAL);
MALLOC_DEFINE(M_NETFLOW_GENERAL, "netflow_general", "plog, V9 templates data");
/*
* Base V9 templates for L4+ IPv4/IPv6 protocols
*/
struct netflow_v9_template _netflow_v9_record_ipv4_tcp[] =
{
{ NETFLOW_V9_FIELD_IPV4_SRC_ADDR, 4},
{ NETFLOW_V9_FIELD_IPV4_DST_ADDR, 4},
{ NETFLOW_V9_FIELD_IPV4_NEXT_HOP, 4},
{ NETFLOW_V9_FIELD_INPUT_SNMP, 2},
{ NETFLOW_V9_FIELD_OUTPUT_SNMP, 2},
{ NETFLOW_V9_FIELD_IN_PKTS, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_IN_BYTES, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_OUT_PKTS, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_OUT_BYTES, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_FIRST_SWITCHED, 4},
{ NETFLOW_V9_FIELD_LAST_SWITCHED, 4},
{ NETFLOW_V9_FIELD_L4_SRC_PORT, 2},
{ NETFLOW_V9_FIELD_L4_DST_PORT, 2},
{ NETFLOW_V9_FIELD_TCP_FLAGS, 1},
{ NETFLOW_V9_FIELD_PROTOCOL, 1},
{ NETFLOW_V9_FIELD_TOS, 1},
{ NETFLOW_V9_FIELD_SRC_AS, 4},
{ NETFLOW_V9_FIELD_DST_AS, 4},
{ NETFLOW_V9_FIELD_SRC_MASK, 1},
{ NETFLOW_V9_FIELD_DST_MASK, 1},
{0, 0}
};
struct netflow_v9_template _netflow_v9_record_ipv6_tcp[] =
{
{ NETFLOW_V9_FIELD_IPV6_SRC_ADDR, 16},
{ NETFLOW_V9_FIELD_IPV6_DST_ADDR, 16},
{ NETFLOW_V9_FIELD_IPV6_NEXT_HOP, 16},
{ NETFLOW_V9_FIELD_INPUT_SNMP, 2},
{ NETFLOW_V9_FIELD_OUTPUT_SNMP, 2},
{ NETFLOW_V9_FIELD_IN_PKTS, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_IN_BYTES, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_OUT_PKTS, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_OUT_BYTES, sizeof(CNTR)},
{ NETFLOW_V9_FIELD_FIRST_SWITCHED, 4},
{ NETFLOW_V9_FIELD_LAST_SWITCHED, 4},
{ NETFLOW_V9_FIELD_L4_SRC_PORT, 2},
{ NETFLOW_V9_FIELD_L4_DST_PORT, 2},
{ NETFLOW_V9_FIELD_TCP_FLAGS, 1},
{ NETFLOW_V9_FIELD_PROTOCOL, 1},
{ NETFLOW_V9_FIELD_TOS, 1},
{ NETFLOW_V9_FIELD_SRC_AS, 4},
{ NETFLOW_V9_FIELD_DST_AS, 4},
{ NETFLOW_V9_FIELD_SRC_MASK, 1},
{ NETFLOW_V9_FIELD_DST_MASK, 1},
{0, 0}
};
/*
* Pre-compiles flow exporter for all possible FlowSets
* so we can add flowset to packet via simple memcpy()
*/
static void
generate_v9_templates(priv_p priv)
{
uint16_t *p, *template_fields_cnt;
int cnt;
int flowset_size = sizeof(struct netflow_v9_flowset_header) +
_NETFLOW_V9_TEMPLATE_SIZE(_netflow_v9_record_ipv4_tcp) + /* netflow_v9_record_ipv4_tcp */
_NETFLOW_V9_TEMPLATE_SIZE(_netflow_v9_record_ipv6_tcp); /* netflow_v9_record_ipv6_tcp */
priv->v9_flowsets[0] = malloc(flowset_size, M_NETFLOW_GENERAL, M_WAITOK | M_ZERO);
if (flowset_size % 4)
flowset_size += 4 - (flowset_size % 4); /* Padding to 4-byte boundary */
priv->flowsets_count = 1;
p = (uint16_t *)priv->v9_flowsets[0];
*p++ = 0; /* Flowset ID, 0 is reserved for Template FlowSets */
*p++ = htons(flowset_size); /* Total FlowSet length */
/*
* Most common TCP/UDP IPv4 template, ID = 256
*/
*p++ = htons(NETFLOW_V9_MAX_RESERVED_FLOWSET + NETFLOW_V9_FLOW_V4_L4);
template_fields_cnt = p++;
for (cnt = 0; _netflow_v9_record_ipv4_tcp[cnt].field_id != 0; cnt++) {
*p++ = htons(_netflow_v9_record_ipv4_tcp[cnt].field_id);
*p++ = htons(_netflow_v9_record_ipv4_tcp[cnt].field_length);
}
*template_fields_cnt = htons(cnt);
/*
* TCP/UDP IPv6 template, ID = 257
*/
*p++ = htons(NETFLOW_V9_MAX_RESERVED_FLOWSET + NETFLOW_V9_FLOW_V6_L4);
template_fields_cnt = p++;
for (cnt = 0; _netflow_v9_record_ipv6_tcp[cnt].field_id != 0; cnt++) {
*p++ = htons(_netflow_v9_record_ipv6_tcp[cnt].field_id);
*p++ = htons(_netflow_v9_record_ipv6_tcp[cnt].field_length);
}
*template_fields_cnt = htons(cnt);
priv->flowset_records[0] = 2;
}
/* Closes current data flowset */
static void inline
close_flowset(struct mbuf *m, struct netflow_v9_packet_opt *t)
{
struct mbuf *m_old;
uint32_t zero = 0;
int offset = 0;
uint16_t *flowset_length, len;
/* Hack to ensure we are not crossing mbuf boundary, length is uint16_t */
m_old = m_getptr(m, t->flow_header + offsetof(struct netflow_v9_flowset_header, length), &offset);
flowset_length = (uint16_t *)(mtod(m_old, char *) + offset);
len = (uint16_t)(m_pktlen(m) - t->flow_header);
/* Align on 4-byte boundary (RFC 3954, Clause 5.3) */
if (len % 4) {
if (m_append(m, 4 - (len % 4), (void *)&zero) != 1)
panic("ng_netflow: m_append() failed!");
len += 4 - (len % 4);
}
*flowset_length = htons(len);
}
/*
* Non-static functions called from ng_netflow.c
*/
/* We have full datagram in fib data. Send it to export hook. */
int
export9_send(priv_p priv, fib_export_p fe, item_p item, struct netflow_v9_packet_opt *t, int flags)
{
struct mbuf *m = NGI_M(item);
struct netflow_v9_export_dgram *dgram = mtod(m,
struct netflow_v9_export_dgram *);
struct netflow_v9_header *header = &dgram->header;
struct timespec ts;
int error = 0;
if (t == NULL) {
CTR0(KTR_NET, "export9_send(): V9 export packet without tag");
NG_FREE_ITEM(item);
return (0);
}
/* Close flowset if not closed already */
if (m_pktlen(m) != t->flow_header)
close_flowset(m, t);
/* Fill export header. */
header->count = t->count;
header->sys_uptime = htonl(MILLIUPTIME(time_uptime));
getnanotime(&ts);
header->unix_secs = htonl(ts.tv_sec);
header->seq_num = htonl(atomic_fetchadd_32(&fe->flow9_seq, 1));
header->count = htons(t->count);
header->source_id = htonl(fe->domain_id);
if (priv->export9 != NULL)
NG_FWD_ITEM_HOOK_FLAGS(error, item, priv->export9, flags);
else
NG_FREE_ITEM(item);
free(t, M_NETFLOW_GENERAL);
return (error);
}
/* Add V9 record to dgram. */
int
export9_add(item_p item, struct netflow_v9_packet_opt *t, struct flow_entry *fle)
{
size_t len = 0;
struct netflow_v9_flowset_header fsh;
struct netflow_v9_record_general rg;
struct mbuf *m = NGI_M(item);
uint16_t flow_type;
struct flow_entry_data *fed;
#ifdef INET6
struct flow6_entry_data *fed6;
#endif
if (t == NULL) {
CTR0(KTR_NET, "ng_netflow: V9 export packet without tag!");
return (0);
}
/* Prepare flow record */
fed = (struct flow_entry_data *)&fle->f;
#ifdef INET6
fed6 = (struct flow6_entry_data *)&fle->f;
#endif
/* We can use flow_type field since fle6 offset is equal to fle */
flow_type = fed->r.flow_type;
switch (flow_type) {
case NETFLOW_V9_FLOW_V4_L4:
{
/* IPv4 TCP/UDP/[SCTP] */
struct netflow_v9_record_ipv4_tcp *rec = &rg.rec.v4_tcp;
rec->src_addr = fed->r.r_src.s_addr;
rec->dst_addr = fed->r.r_dst.s_addr;
rec->next_hop = fed->next_hop.s_addr;
rec->i_ifx = htons(fed->fle_i_ifx);
rec->o_ifx = htons(fed->fle_o_ifx);
rec->i_packets = htonl(fed->packets);
rec->i_octets = htonl(fed->bytes);
rec->o_packets = htonl(0);
rec->o_octets = htonl(0);
rec->first = htonl(MILLIUPTIME(fed->first));
rec->last = htonl(MILLIUPTIME(fed->last));
rec->s_port = fed->r.r_sport;
rec->d_port = fed->r.r_dport;
rec->flags = fed->tcp_flags;
rec->prot = fed->r.r_ip_p;
rec->tos = fed->r.r_tos;
rec->dst_mask = fed->dst_mask;
rec->src_mask = fed->src_mask;
/* Not supported fields. */
rec->src_as = rec->dst_as = 0;
len = sizeof(struct netflow_v9_record_ipv4_tcp);
break;
}
#ifdef INET6
case NETFLOW_V9_FLOW_V6_L4:
{
/* IPv6 TCP/UDP/[SCTP] */
struct netflow_v9_record_ipv6_tcp *rec = &rg.rec.v6_tcp;
rec->src_addr = fed6->r.src.r_src6;
rec->dst_addr = fed6->r.dst.r_dst6;
rec->next_hop = fed6->n.next_hop6;
rec->i_ifx = htons(fed6->fle_i_ifx);
rec->o_ifx = htons(fed6->fle_o_ifx);
rec->i_packets = htonl(fed6->packets);
rec->i_octets = htonl(fed6->bytes);
rec->o_packets = htonl(0);
rec->o_octets = htonl(0);
rec->first = htonl(MILLIUPTIME(fed6->first));
rec->last = htonl(MILLIUPTIME(fed6->last));
rec->s_port = fed6->r.r_sport;
rec->d_port = fed6->r.r_dport;
rec->flags = fed6->tcp_flags;
rec->prot = fed6->r.r_ip_p;
rec->tos = fed6->r.r_tos;
rec->dst_mask = fed6->dst_mask;
rec->src_mask = fed6->src_mask;
/* Not supported fields. */
rec->src_as = rec->dst_as = 0;
len = sizeof(struct netflow_v9_record_ipv6_tcp);
break;
}
#endif
default:
{
CTR1(KTR_NET, "export9_add(): Don't know what to do with %d flow type!", flow_type);
return (0);
}
}
/* Check if new records has the same template */
if (flow_type != t->flow_type) {
/* close old flowset */
if (t->flow_type != 0)
close_flowset(m, t);
t->flow_type = flow_type;
t->flow_header = m_pktlen(m);
/* Generate data flowset ID */
fsh.id = htons(NETFLOW_V9_MAX_RESERVED_FLOWSET + flow_type);
fsh.length = 0;
/* m_append should not fail since all data is already allocated */
if (m_append(m, sizeof(fsh), (void *)&fsh) != 1)
panic("ng_netflow: m_append() failed");
}
if (m_append(m, len, (void *)&rg.rec) != 1)
panic("ng_netflow: m_append() failed");
t->count++;
if (m_pktlen(m) + sizeof(struct netflow_v9_record_general) + sizeof(struct netflow_v9_flowset_header) >= _NETFLOW_V9_MAX_SIZE(t->mtu))
return (1); /* end of datagram */
return (0);
}
/*
* Detach export datagram from fib instance, if there is any.
* If there is no, allocate a new one.
*/
item_p
get_export9_dgram(priv_p priv, fib_export_p fe, struct netflow_v9_packet_opt **tt)
{
item_p item = NULL;
struct netflow_v9_packet_opt *t = NULL;
mtx_lock(&fe->export9_mtx);
if (fe->exp.item9 != NULL) {
item = fe->exp.item9;
fe->exp.item9 = NULL;
t = fe->exp.item9_opt;
fe->exp.item9_opt = NULL;
}
mtx_unlock(&fe->export9_mtx);
if (item == NULL) {
struct netflow_v9_export_dgram *dgram;
struct mbuf *m;
uint16_t mtu = priv->mtu;
/* Allocate entire packet at once, allowing easy m_append() calls */
m = m_getm(NULL, mtu, M_NOWAIT, MT_DATA);
if (m == NULL)
return (NULL);
t = malloc(sizeof(struct netflow_v9_packet_opt), M_NETFLOW_GENERAL, M_NOWAIT | M_ZERO);
if (t == NULL) {
m_free(m);
return (NULL);
}
item = ng_package_data(m, NG_NOFLAGS);
if (item == NULL) {
free(t, M_NETFLOW_GENERAL);
return (NULL);
}
dgram = mtod(m, struct netflow_v9_export_dgram *);
dgram->header.count = 0;
dgram->header.version = htons(NETFLOW_V9);
/* Set mbuf current data length */
m->m_len = m->m_pkthdr.len = sizeof(struct netflow_v9_header);
t->count = 0;
t->mtu = mtu;
t->flow_header = m->m_len;
/*
* Check if we need to insert templates into packet
*/
struct netflow_v9_flowset_header *fl;
if ((time_uptime >= priv->templ_time + fe->templ_last_ts) ||
(fe->sent_packets >= priv->templ_packets + fe->templ_last_pkt)) {
fe->templ_last_ts = time_uptime;
fe->templ_last_pkt = fe->sent_packets;
fl = priv->v9_flowsets[0];
m_append(m, ntohs(fl->length), (void *)fl);
t->flow_header = m->m_len;
t->count += priv->flowset_records[0];
}
}
*tt = t;
return (item);
}
/*
* Re-attach incomplete datagram back to fib instance.
* If there is already another one, then send incomplete.
*/
void
return_export9_dgram(priv_p priv, fib_export_p fe, item_p item, struct netflow_v9_packet_opt *t, int flags)
{
/*
* It may happen on SMP, that some thread has already
* put its item there, in this case we bail out and
* send what we have to collector.
*/
mtx_lock(&fe->export9_mtx);
if (fe->exp.item9 == NULL) {
fe->exp.item9 = item;
fe->exp.item9_opt = t;
mtx_unlock(&fe->export9_mtx);
} else {
mtx_unlock(&fe->export9_mtx);
export9_send(priv, fe, item, t, flags);
}
}
/* Allocate memory and set up flow cache */
void
ng_netflow_v9_cache_init(priv_p priv)
{
generate_v9_templates(priv);
priv->templ_time = NETFLOW_V9_MAX_TIME_TEMPL;
priv->templ_packets = NETFLOW_V9_MAX_PACKETS_TEMPL;
priv->mtu = BASE_MTU;
}
/* Free all flow cache memory. Called from ng_netflow_cache_flush() */
void
ng_netflow_v9_cache_flush(priv_p priv)
{
int i;
/* Free flowsets*/
for (i = 0; i < priv->flowsets_count; i++)
free(priv->v9_flowsets[i], M_NETFLOW_GENERAL);
}
/* Get a snapshot of NetFlow v9 settings */
void
ng_netflow_copyv9info(priv_p priv, struct ng_netflow_v9info *i)
{
i->templ_time = priv->templ_time;
i->templ_packets = priv->templ_packets;
i->mtu = priv->mtu;
}

View File

@ -0,0 +1,148 @@
/*-
* Copyright (c) 2010 Alexander V. Chernikov <melifaro@ipfw.ru>
* 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.
*
* $FreeBSD$
*/
#ifndef _NETFLOW_V9_H_
#define _NETFLOW_V9_H_
#ifdef COUNTERS_64
#define CNTR uint64_t
#define CNTR_MAX UINT64_MAX
#else
#define CNTR uint32_t
#define CNTR_MAX UINT_MAX
#endif
struct netflow_v9_template
{
int field_id;
int field_length;
};
/* Template ID for tcp/udp v4 streams ID:257 (0x100 + NETFLOW_V9_FLOW_V4_L4) */
struct netflow_v9_record_ipv4_tcp
{
uint32_t src_addr; /* Source IPv4 address (IPV4_SRC_ADDR) */
uint32_t dst_addr; /* Destination IPv4 address (IPV4_DST_ADDR) */
uint32_t next_hop; /* Next hop IPv4 address (IPV4_NEXT_HOP) */
uint16_t i_ifx; /* Source interface index (INPUT_SNMP) */
uint16_t o_ifx; /* Destination interface index (OUTPUT_SNMP) */
CNTR i_packets; /* Number of incoming packets in a flow (IN_PKTS) */
CNTR i_octets; /* Number of incoming octets in a flow (IN_BYTES) */
CNTR o_packets; /* Number of outgoing packets in a flow (OUT_PKTS) */
CNTR o_octets; /* Number of outgoing octets in a flow (OUT_BYTES) */
uint32_t first; /* System uptime at start of a flow (FIRST_SWITCHED) */
uint32_t last; /* System uptime at end of a flow (LAST_SWITCHED) */
uint16_t s_port; /* Source port (L4_SRC_PORT) */
uint16_t d_port; /* Destination port (L4_DST_PORT) */
uint8_t flags; /* Cumulative OR of tcp flags (TCP_FLAGS) */
uint8_t prot; /* IP protocol */
uint8_t tos; /* IP type of service IN (or OUT) (TOS) */
uint32_t src_as; /* Src peer/origin Autonomous System (SRC_AS) */
uint32_t dst_as; /* Dst peer/origin Autonomous System (DST_AS) */
uint8_t src_mask; /* Source route's mask bits (SRC_MASK) */
uint8_t dst_mask; /* Destination route's mask bits (DST_MASK) */
} __attribute__((__packed__));
/* Template ID for tcp/udp v6 streams ID: 260 (0x100 + NETFLOW_V9_FLOW_V6_L4) */
struct netflow_v9_record_ipv6_tcp
{
struct in6_addr src_addr; /* Source IPv6 address (IPV6_SRC_ADDR) */
struct in6_addr dst_addr; /* Destination IPv6 address (IPV6_DST_ADDR) */
struct in6_addr next_hop; /* Next hop IPv6 address (IPV6_NEXT_HOP) */
uint16_t i_ifx; /* Source interface index (INPUT_SNMP) */
uint16_t o_ifx; /* Destination interface index (OUTPUT_SNMP) */
CNTR i_packets; /* Number of incoming packets in a flow (IN_PKTS) */
CNTR i_octets; /* Number of incoming octets in a flow (IN_BYTES) */
CNTR o_packets; /* Number of outgoing packets in a flow (OUT_PKTS) */
CNTR o_octets; /* Number of outgoing octets in a flow (OUT_BYTES) */
uint32_t first; /* System uptime at start of a flow (FIRST_SWITCHED) */
uint32_t last; /* System uptime at end of a flow (LAST_SWITCHED) */
uint16_t s_port; /* Source port (L4_SRC_PORT) */
uint16_t d_port; /* Destination port (L4_DST_PORT) */
uint8_t flags; /* Cumulative OR of tcp flags (TCP_FLAGS) */
uint8_t prot; /* IP protocol */
uint8_t tos; /* IP type of service IN (or OUT) (TOS) */
uint32_t src_as; /* Src peer/origin Autonomous System (SRC_AS) */
uint32_t dst_as; /* Dst peer/origin Autonomous System (DST_AS) */
uint8_t src_mask; /* Source route's mask bits (SRC_MASK) */
uint8_t dst_mask; /* Destination route's mask bits (DST_MASK) */
} __attribute__((__packed__));
/* Used in export9_add to determine max record size */
struct netflow_v9_record_general
{
union {
struct netflow_v9_record_ipv4_tcp v4_tcp;
struct netflow_v9_record_ipv6_tcp v6_tcp;
} rec;
};
#define BASE_MTU 1500
#define MIN_MTU sizeof(struct netflow_v5_header)
#define MAX_MTU 16384
#define NETFLOW_V9_MAX_SIZE _NETFLOW_V9_MAX_SIZE(BASE_MTU)
/* Decrease MSS by 16 since there can be some IPv[46] header options */
#define _NETFLOW_V9_MAX_SIZE(x) (x) - sizeof(struct ip6_hdr) - sizeof(struct udphdr) - 16
/* #define NETFLOW_V9_MAX_FLOWSETS 2 */
#define NETFLOW_V9_MAX_RECORD_SIZE sizeof(struct netflow_v9_record_ipv6_tcp)
#define NETFLOW_V9_MAX_PACKETS_TEMPL 500 /* Send data templates every ... packets */
#define NETFLOW_V9_MAX_TIME_TEMPL 600 /* Send data templates every ... seconds */
#define NETFLOW_V9_MAX_TEMPLATES 16 /* Not a real value */
#define _NETFLOW_V9_TEMPLATE_SIZE(x) (sizeof(x) / sizeof(struct netflow_v9_template)) * 4
//#define _NETFLOW_V9_TEMPLATE_SIZE(x) ((x) + 1) * 4
/* Flow Templates */
#define NETFLOW_V9_FLOW_V4_L4 1 /* IPv4 TCP/UDP packet */
#define NETFLOW_V9_FLOW_V4_ICMP 2 /* IPv4 ICMP packet, currently unused */
#define NETFLOW_V9_FLOW_V4_L3 3 /* IPv4 IP packet */
#define NETFLOW_V9_FLOW_V6_L4 4 /* IPv6 TCP/UDP packet */
#define NETFLOW_V9_FLOW_V6_ICMP 5 /* IPv6 ICMP packet, currently unused */
#define NETFLOW_V9_FLOW_V6_L3 6 /* IPv6 IP packet */
#define NETFLOW_V9_FLOW_FAKE 65535 /* Not uset used in real flowsets! */
struct netflow_v9_export_dgram {
struct netflow_v9_header header;
char *data; /* MTU can change, record length is dynamic */
};
struct netflow_v9_flowset_header {
uint16_t id; /* FlowSet id */
uint16_t length; /* FlowSet length */
} __attribute__((__packed__));
struct netflow_v9_packet_opt {
uint16_t length; /* current packet length */
uint16_t count; /* current records count */
uint16_t mtu; /* max MTU shapshot */
uint16_t flow_type; /* current flowset */
uint16_t flow_header; /* offset pointing to current flow header */
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,542 @@
/*-
* Copyright (c) 2010-2011 Alexander V. Chernikov <melifaro@ipfw.ru>
* Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
* Copyright (c) 2001-2003 Roman V. Palagin <romanp@unshadow.net>
* 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.
*
* $SourceForge: ng_netflow.h,v 1.26 2004/09/04 15:44:55 glebius Exp $
* $FreeBSD$
*/
#ifndef _NG_NETFLOW_H_
#define _NG_NETFLOW_H_
#define NG_NETFLOW_NODE_TYPE "netflow"
#define NGM_NETFLOW_COOKIE 1365756954
#define NGM_NETFLOW_V9_COOKIE 1349865386
#define NG_NETFLOW_MAXIFACES USHRT_MAX
/* Hook names */
#define NG_NETFLOW_HOOK_DATA "iface"
#define NG_NETFLOW_HOOK_OUT "out"
#define NG_NETFLOW_HOOK_EXPORT "export"
#define NG_NETFLOW_HOOK_EXPORT9 "export9"
/* This define effectively disable (v5) netflow export hook! */
/* #define COUNTERS_64 */
/* Netgraph commands understood by netflow node */
enum {
NGM_NETFLOW_INFO = 1|NGM_READONLY|NGM_HASREPLY, /* get node info */
NGM_NETFLOW_IFINFO = 2|NGM_READONLY|NGM_HASREPLY, /* get iface info */
NGM_NETFLOW_SHOW = 3|NGM_READONLY|NGM_HASREPLY, /* show ip cache flow */
NGM_NETFLOW_SETDLT = 4, /* set data-link type */
NGM_NETFLOW_SETIFINDEX = 5, /* set interface index */
NGM_NETFLOW_SETTIMEOUTS = 6, /* set active/inactive flow timeouts */
NGM_NETFLOW_SETCONFIG = 7, /* set flow generation options */
NGM_NETFLOW_SETTEMPLATE = 8, /* set v9 flow template periodic */
NGM_NETFLOW_SETMTU = 9, /* set outgoing interface MTU */
NGM_NETFLOW_V9INFO = 10|NGM_READONLY|NGM_HASREPLY, /* get v9 info */
};
/* This structure is returned by the NGM_NETFLOW_INFO message */
struct ng_netflow_info {
uint64_t nfinfo_bytes; /* accounted IPv4 bytes */
uint64_t nfinfo_packets; /* accounted IPv4 packets */
uint64_t nfinfo_bytes6; /* accounted IPv6 bytes */
uint64_t nfinfo_packets6; /* accounted IPv6 packets */
uint64_t nfinfo_sbytes; /* skipped IPv4 bytes */
uint64_t nfinfo_spackets; /* skipped IPv4 packets */
uint64_t nfinfo_sbytes6; /* skipped IPv6 bytes */
uint64_t nfinfo_spackets6; /* skipped IPv6 packets */
uint64_t nfinfo_act_exp; /* active expiries */
uint64_t nfinfo_inact_exp; /* inactive expiries */
uint32_t nfinfo_used; /* used cache records */
uint32_t nfinfo_used6; /* used IPv6 cache records */
uint32_t nfinfo_alloc_failed; /* failed allocations */
uint32_t nfinfo_export_failed; /* failed exports */
uint32_t nfinfo_export9_failed; /* failed exports */
uint32_t nfinfo_realloc_mbuf; /* reallocated mbufs */
uint32_t nfinfo_alloc_fibs; /* fibs allocated */
uint32_t nfinfo_inact_t; /* flow inactive timeout */
uint32_t nfinfo_act_t; /* flow active timeout */
};
/* Parse the info structure */
#define NG_NETFLOW_INFO_TYPE { \
{ "IPv4 bytes", &ng_parse_uint64_type },\
{ "IPv4 packets", &ng_parse_uint64_type },\
{ "IPv6 bytes", &ng_parse_uint64_type },\
{ "IPv6 packets", &ng_parse_uint64_type },\
{ "IPv4 skipped bytes", &ng_parse_uint64_type },\
{ "IPv4 skipped packets", &ng_parse_uint64_type },\
{ "IPv6 skipped bytes", &ng_parse_uint64_type },\
{ "IPv6 skipped packets", &ng_parse_uint64_type },\
{ "Active expiries", &ng_parse_uint64_type },\
{ "Inactive expiries", &ng_parse_uint64_type },\
{ "IPv4 records used", &ng_parse_uint32_type },\
{ "IPv6 records used", &ng_parse_uint32_type },\
{ "Failed allocations", &ng_parse_uint32_type },\
{ "V5 failed exports", &ng_parse_uint32_type },\
{ "V9 failed exports", &ng_parse_uint32_type },\
{ "mbuf reallocations", &ng_parse_uint32_type },\
{ "fibs allocated", &ng_parse_uint32_type },\
{ "Inactive timeout", &ng_parse_uint32_type },\
{ "Active timeout", &ng_parse_uint32_type },\
{ NULL } \
}
/* This structure is returned by the NGM_NETFLOW_IFINFO message */
struct ng_netflow_ifinfo {
uint32_t ifinfo_packets; /* number of packets for this iface */
uint8_t ifinfo_dlt; /* Data Link Type, DLT_XXX */
#define MAXDLTNAMELEN 20
uint16_t ifinfo_index; /* connected iface index */
uint32_t conf;
};
/* This structure is passed to NGM_NETFLOW_SETDLT message */
struct ng_netflow_setdlt {
uint16_t iface; /* which iface dlt change */
uint8_t dlt; /* DLT_XXX from bpf.h */
};
/* This structure is passed to NGM_NETFLOW_SETIFINDEX */
struct ng_netflow_setifindex {
uint16_t iface; /* which iface index change */
uint16_t index; /* new index */
};
/* This structure is passed to NGM_NETFLOW_SETTIMEOUTS */
struct ng_netflow_settimeouts {
uint32_t inactive_timeout; /* flow inactive timeout */
uint32_t active_timeout; /* flow active timeout */
};
#define NG_NETFLOW_CONF_INGRESS 0x01 /* Account on ingress */
#define NG_NETFLOW_CONF_EGRESS 0x02 /* Account on egress */
#define NG_NETFLOW_CONF_ONCE 0x04 /* Add tag to account only once */
#define NG_NETFLOW_CONF_THISONCE 0x08 /* Account once in current node */
#define NG_NETFLOW_CONF_NOSRCLOOKUP 0x10 /* No radix lookup on src */
#define NG_NETFLOW_CONF_NODSTLOOKUP 0x20 /* No radix lookup on dst */
#define NG_NETFLOW_IS_FRAG 0x01
#define NG_NETFLOW_FLOW_FLAGS (NG_NETFLOW_CONF_NOSRCLOOKUP|\
NG_NETFLOW_CONF_NODSTLOOKUP)
/* This structure is passed to NGM_NETFLOW_SETCONFIG */
struct ng_netflow_setconfig {
uint16_t iface; /* which iface config change */
uint32_t conf; /* new config */
};
/* This structure is passed to NGM_NETFLOW_SETTEMPLATE */
struct ng_netflow_settemplate {
uint16_t time; /* max time between announce */
uint16_t packets; /* max packets between announce */
};
/* This structure is passed to NGM_NETFLOW_SETMTU */
struct ng_netflow_setmtu {
uint16_t mtu; /* MTU for packet */
};
/* This structure is used in NGM_NETFLOW_SHOW request/response */
struct ngnf_show_header {
u_char version; /* IPv4 or IPv6 */
uint32_t hash_id; /* current hash index */
uint32_t list_id; /* current record number in hash */
uint32_t nentries; /* number of records in response */
};
/* This structure is used in NGM_NETFLOW_V9INFO message */
struct ng_netflow_v9info {
uint16_t templ_packets; /* v9 template packets */
uint16_t templ_time; /* v9 template time */
uint16_t mtu; /* v9 MTU */
};
/* XXXGL
* Somewhere flow_rec6 is casted to flow_rec, and flow6_entry_data is
* casted to flow_entry_data. After casting, fle->r.fib is accessed.
* So beginning of these structs up to fib should be kept common.
*/
/* This is unique data, which identifies flow */
struct flow_rec {
uint16_t flow_type;
uint16_t fib;
struct in_addr r_src;
struct in_addr r_dst;
union {
struct {
uint16_t s_port; /* source TCP/UDP port */
uint16_t d_port; /* destination TCP/UDP port */
} dir;
uint32_t both;
} ports;
union {
struct {
u_char prot; /* IP protocol */
u_char tos; /* IP TOS */
uint16_t i_ifx; /* input interface index */
} i;
uint32_t all;
} misc;
};
/* This is unique data, which identifies flow */
struct flow6_rec {
uint16_t flow_type;
uint16_t fib;
union {
struct in_addr r_src;
struct in6_addr r_src6;
} src;
union {
struct in_addr r_dst;
struct in6_addr r_dst6;
} dst;
union {
struct {
uint16_t s_port; /* source TCP/UDP port */
uint16_t d_port; /* destination TCP/UDP port */
} dir;
uint32_t both;
} ports;
union {
struct {
u_char prot; /* IP protocol */
u_char tos; /* IP TOS */
uint16_t i_ifx; /* input interface index */
} i;
uint32_t all;
} misc;
};
#define r_ip_p misc.i.prot
#define r_tos misc.i.tos
#define r_i_ifx misc.i.i_ifx
#define r_misc misc.all
#define r_ports ports.both
#define r_sport ports.dir.s_port
#define r_dport ports.dir.d_port
/* A flow entry which accumulates statistics */
struct flow_entry_data {
uint16_t version; /* Protocol version */
struct flow_rec r;
struct in_addr next_hop;
uint16_t fle_o_ifx; /* output interface index */
#define fle_i_ifx r.misc.i.i_ifx
uint8_t dst_mask; /* destination route mask bits */
uint8_t src_mask; /* source route mask bits */
u_long packets;
u_long bytes;
long first; /* uptime on first packet */
long last; /* uptime on last packet */
u_char tcp_flags; /* cumulative OR */
};
struct flow6_entry_data {
uint16_t version; /* Protocol version */
struct flow6_rec r;
union {
struct in_addr next_hop;
struct in6_addr next_hop6;
} n;
uint16_t fle_o_ifx; /* output interface index */
#define fle_i_ifx r.misc.i.i_ifx
uint8_t dst_mask; /* destination route mask bits */
uint8_t src_mask; /* source route mask bits */
u_long packets;
u_long bytes;
long first; /* uptime on first packet */
long last; /* uptime on last packet */
u_char tcp_flags; /* cumulative OR */
};
/*
* How many flow records we will transfer at once
* without overflowing socket receive buffer
*/
#define NREC_AT_ONCE 1000
#define NREC6_AT_ONCE (NREC_AT_ONCE * sizeof(struct flow_entry_data) / \
sizeof(struct flow6_entry_data))
#define NGRESP_SIZE (sizeof(struct ngnf_show_header) + (NREC_AT_ONCE * \
sizeof(struct flow_entry_data)))
#define SORCVBUF_SIZE (NGRESP_SIZE + 2 * sizeof(struct ng_mesg))
/* Everything below is for kernel */
#ifdef _KERNEL
struct flow_entry {
TAILQ_ENTRY(flow_entry) fle_hash; /* entries in hash slot */
struct flow_entry_data f;
};
struct flow6_entry {
TAILQ_ENTRY(flow_entry) fle_hash; /* entries in hash slot */
struct flow6_entry_data f;
};
/* Parsing declarations */
/* Parse the ifinfo structure */
#define NG_NETFLOW_IFINFO_TYPE { \
{ "packets", &ng_parse_uint32_type },\
{ "data link type", &ng_parse_uint8_type }, \
{ "index", &ng_parse_uint16_type },\
{ "conf", &ng_parse_uint32_type },\
{ NULL } \
}
/* Parse the setdlt structure */
#define NG_NETFLOW_SETDLT_TYPE { \
{ "iface", &ng_parse_uint16_type }, \
{ "dlt", &ng_parse_uint8_type }, \
{ NULL } \
}
/* Parse the setifindex structure */
#define NG_NETFLOW_SETIFINDEX_TYPE { \
{ "iface", &ng_parse_uint16_type }, \
{ "index", &ng_parse_uint16_type }, \
{ NULL } \
}
/* Parse the settimeouts structure */
#define NG_NETFLOW_SETTIMEOUTS_TYPE { \
{ "inactive", &ng_parse_uint32_type }, \
{ "active", &ng_parse_uint32_type }, \
{ NULL } \
}
/* Parse the setifindex structure */
#define NG_NETFLOW_SETCONFIG_TYPE { \
{ "iface", &ng_parse_uint16_type }, \
{ "conf", &ng_parse_uint32_type }, \
{ NULL } \
}
/* Parse the settemplate structure */
#define NG_NETFLOW_SETTEMPLATE_TYPE { \
{ "time", &ng_parse_uint16_type }, \
{ "packets", &ng_parse_uint16_type }, \
{ NULL } \
}
/* Parse the setmtu structure */
#define NG_NETFLOW_SETMTU_TYPE { \
{ "mtu", &ng_parse_uint16_type }, \
{ NULL } \
}
/* Parse the v9info structure */
#define NG_NETFLOW_V9INFO_TYPE { \
{ "v9 template packets", &ng_parse_uint16_type },\
{ "v9 template time", &ng_parse_uint16_type },\
{ "v9 MTU", &ng_parse_uint16_type },\
{ NULL } \
}
/* Private hook data */
struct ng_netflow_iface {
hook_p hook; /* NULL when disconnected */
hook_p out; /* NULL when no bypass hook */
struct ng_netflow_ifinfo info;
};
typedef struct ng_netflow_iface *iface_p;
typedef struct ng_netflow_ifinfo *ifinfo_p;
struct netflow_export_item {
item_p item;
item_p item9;
struct netflow_v9_packet_opt *item9_opt;
};
/* Structure contatining fib-specific data */
struct fib_export {
uint32_t fib; /* kernel fib id */
/* Various data used for export */
struct netflow_export_item exp;
struct mtx export_mtx; /* exp.item mutex */
struct mtx export9_mtx; /* exp.item9 mutex */
uint32_t flow_seq; /* current V5 flow sequence */
uint32_t flow9_seq; /* current V9 flow sequence */
uint32_t domain_id; /* Observartion domain id */
/* Netflow V9 counters */
uint32_t templ_last_ts; /* unixtime of last template announce */
uint32_t templ_last_pkt; /* packet count on last announce */
uint32_t sent_packets; /* packets sent by exporter; */
/* Current packet specific options */
struct netflow_v9_packet_opt *export9_opt;
};
typedef struct fib_export *fib_export_p;
/* Structure describing our flow engine */
struct netflow {
node_p node; /* link to the node itself */
hook_p export; /* export data goes there */
hook_p export9; /* Netflow V9 export data goes there */
struct callout exp_callout; /* expiry periodic job */
/*
* Flow entries are allocated in uma(9) zone zone. They are
* indexed by hash hash. Each hash element consist of tailqueue
* head and mutex to protect this element.
*/
#define CACHESIZE (65536*16)
#define CACHELOWAT (CACHESIZE * 3/4)
#define CACHEHIGHWAT (CACHESIZE * 9/10)
uma_zone_t zone;
struct flow_hash_entry *hash;
/*
* NetFlow data export
*
* export_item is a data item, it has an mbuf with cluster
* attached to it. A thread detaches export_item from priv
* and works with it. If the export is full it is sent, and
* a new one is allocated. Before exiting thread re-attaches
* its current item back to priv. If there is item already,
* current incomplete datagram is sent.
* export_mtx is used for attaching/detaching.
*/
/* IPv6 support */
#ifdef INET6
uma_zone_t zone6;
struct flow_hash_entry *hash6;
#endif
/* Statistics. */
counter_u64_t nfinfo_bytes; /* accounted IPv4 bytes */
counter_u64_t nfinfo_packets; /* accounted IPv4 packets */
counter_u64_t nfinfo_bytes6; /* accounted IPv6 bytes */
counter_u64_t nfinfo_packets6; /* accounted IPv6 packets */
counter_u64_t nfinfo_sbytes; /* skipped IPv4 bytes */
counter_u64_t nfinfo_spackets; /* skipped IPv4 packets */
counter_u64_t nfinfo_sbytes6; /* skipped IPv6 bytes */
counter_u64_t nfinfo_spackets6; /* skipped IPv6 packets */
counter_u64_t nfinfo_act_exp; /* active expiries */
counter_u64_t nfinfo_inact_exp; /* inactive expiries */
uint32_t nfinfo_alloc_failed; /* failed allocations */
uint32_t nfinfo_export_failed; /* failed exports */
uint32_t nfinfo_export9_failed; /* failed exports */
uint32_t nfinfo_realloc_mbuf; /* reallocated mbufs */
uint32_t nfinfo_alloc_fibs; /* fibs allocated */
uint32_t nfinfo_inact_t; /* flow inactive timeout */
uint32_t nfinfo_act_t; /* flow active timeout */
/* Multiple FIB support */
fib_export_p *fib_data; /* vector to per-fib data */
uint16_t maxfibs; /* number of allocated fibs */
/* Netflow v9 configuration options */
/*
* RFC 3954 clause 7.3
* "Both options MUST be configurable by the user on the Exporter."
*/
uint16_t templ_time; /* time between sending templates */
uint16_t templ_packets; /* packets between sending templates */
#define NETFLOW_V9_MAX_FLOWSETS 2
u_char flowsets_count; /* current flowsets used */
/* Count of records in each flowset */
u_char flowset_records[NETFLOW_V9_MAX_FLOWSETS - 1];
uint16_t mtu; /* export interface MTU */
/* Pointers to pre-compiled flowsets */
struct netflow_v9_flowset_header
*v9_flowsets[NETFLOW_V9_MAX_FLOWSETS - 1];
struct ng_netflow_iface ifaces[NG_NETFLOW_MAXIFACES];
};
typedef struct netflow *priv_p;
/* Header of a small list in hash cell */
struct flow_hash_entry {
struct mtx mtx;
TAILQ_HEAD(fhead, flow_entry) head;
};
#define ERROUT(x) { error = (x); goto done; }
#define MTAG_NETFLOW 1221656444
#define MTAG_NETFLOW_CALLED 0
#define m_pktlen(m) ((m)->m_pkthdr.len)
#define IP6VERSION 6
#define priv_to_fib(priv, fib) (priv)->fib_data[(fib)]
/*
* Cisco uses milliseconds for uptime. Bad idea, since it overflows
* every 48+ days. But we will do same to keep compatibility. This macro
* does overflowable multiplication to 1000.
*/
#define MILLIUPTIME(t) (((t) << 9) + /* 512 */ \
((t) << 8) + /* 256 */ \
((t) << 7) + /* 128 */ \
((t) << 6) + /* 64 */ \
((t) << 5) + /* 32 */ \
((t) << 3)) /* 8 */
/* Prototypes for netflow.c */
void ng_netflow_cache_init(priv_p);
void ng_netflow_cache_flush(priv_p);
int ng_netflow_fib_init(priv_p priv, int fib);
void ng_netflow_copyinfo(priv_p, struct ng_netflow_info *);
void ng_netflow_copyv9info(priv_p, struct ng_netflow_v9info *);
timeout_t ng_netflow_expire;
int ng_netflow_flow_add(priv_p, fib_export_p, struct ip *, caddr_t,
uint8_t, uint8_t, unsigned int);
int ng_netflow_flow6_add(priv_p, fib_export_p, struct ip6_hdr *, caddr_t,
uint8_t, uint8_t, unsigned int);
int ng_netflow_flow_show(priv_p, struct ngnf_show_header *req,
struct ngnf_show_header *resp);
void ng_netflow_v9_cache_init(priv_p);
void ng_netflow_v9_cache_flush(priv_p);
item_p get_export9_dgram(priv_p, fib_export_p,
struct netflow_v9_packet_opt **);
void return_export9_dgram(priv_p, fib_export_p, item_p,
struct netflow_v9_packet_opt *, int);
int export9_add(item_p, struct netflow_v9_packet_opt *,
struct flow_entry *);
int export9_send(priv_p, fib_export_p, item_p,
struct netflow_v9_packet_opt *, int);
#endif /* _KERNEL */
#endif /* _NG_NETFLOW_H_ */

1219
freebsd/netgraph/netgraph.h Normal file

File diff suppressed because it is too large Load Diff

245
freebsd/netgraph/ng_UI.c Normal file
View File

@ -0,0 +1,245 @@
/*
* ng_UI.c
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Julian Elischer <julian@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_UI.c,v 1.14 1999/11/01 09:24:51 julian Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_UI.h>
/*
* DEFINITIONS
*/
/* Everything, starting with sdlc on has defined UI as 0x03 */
#define HDLC_UI 0x03
/* Node private data */
struct ng_UI_private {
hook_p downlink;
hook_p uplink;
};
typedef struct ng_UI_private *priv_p;
/* Netgraph node methods */
static ng_constructor_t ng_UI_constructor;
static ng_rcvmsg_t ng_UI_rcvmsg;
static ng_shutdown_t ng_UI_shutdown;
static ng_newhook_t ng_UI_newhook;
static ng_rcvdata_t ng_UI_rcvdata;
static ng_disconnect_t ng_UI_disconnect;
/* Node type descriptor */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_UI_NODE_TYPE,
.constructor = ng_UI_constructor,
.rcvmsg = ng_UI_rcvmsg,
.shutdown = ng_UI_shutdown,
.newhook = ng_UI_newhook,
.rcvdata = ng_UI_rcvdata,
.disconnect = ng_UI_disconnect,
};
NETGRAPH_INIT(UI, &typestruct);
/************************************************************************
NETGRAPH NODE STUFF
************************************************************************/
/*
* Create a newborn node. We start with an implicit reference.
*/
static int
ng_UI_constructor(node_p node)
{
priv_p priv;
/* Allocate private structure */
priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
NG_NODE_SET_PRIVATE(node, priv);
return (0);
}
/*
* Give our ok for a hook to be added
*/
static int
ng_UI_newhook(node_p node, hook_p hook, const char *name)
{
const priv_p priv = NG_NODE_PRIVATE(node);
if (!strcmp(name, NG_UI_HOOK_DOWNSTREAM)) {
if (priv->downlink)
return (EISCONN);
priv->downlink = hook;
} else if (!strcmp(name, NG_UI_HOOK_UPSTREAM)) {
if (priv->uplink)
return (EISCONN);
priv->uplink = hook;
} else
return (EINVAL);
return (0);
}
/*
* Receive a control message
*/
static int
ng_UI_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
int error;
const priv_p priv = NG_NODE_PRIVATE(node);
struct ng_mesg *msg;
msg = NGI_MSG(item); /* only peeking */
if ((msg->header.typecookie == NGM_FLOW_COOKIE) && lasthook) {
if (lasthook == priv->downlink) {
if (priv->uplink) {
NG_FWD_ITEM_HOOK(error, item, priv->uplink);
return (error);
}
} else {
if (priv->downlink) {
NG_FWD_ITEM_HOOK(error, item, priv->downlink);
return (error);
}
}
}
NG_FREE_ITEM(item);
return (EINVAL);
}
#define MAX_ENCAPS_HDR 1
#define ERROUT(x) do { error = (x); goto done; } while (0)
/*
* Receive a data frame
*/
static int
ng_UI_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
int error = 0;
NGI_GET_M(item, m);
if (hook == priv->downlink) {
u_char *start, *ptr;
if (m->m_len < MAX_ENCAPS_HDR
&& !(m = m_pullup(m, MAX_ENCAPS_HDR)))
ERROUT(ENOBUFS);
ptr = start = mtod(m, u_char *);
/* Must be UI frame */
if (*ptr++ != HDLC_UI)
ERROUT(0);
m_adj(m, ptr - start);
NG_FWD_NEW_DATA(error, item, priv->uplink, m); /* m -> NULL */
} else if (hook == priv->uplink) {
M_PREPEND(m, 1, M_NOWAIT); /* Prepend IP NLPID */
if (!m)
ERROUT(ENOBUFS);
mtod(m, u_char *)[0] = HDLC_UI;
NG_FWD_NEW_DATA(error, item, priv->downlink, m); /* m -> NULL */
} else
panic("%s", __func__);
done:
NG_FREE_M(m); /* does nothing if m == NULL */
if (item)
NG_FREE_ITEM(item);
return (error);
}
/*
* Shutdown node
*/
static int
ng_UI_shutdown(node_p node)
{
const priv_p priv = NG_NODE_PRIVATE(node);
/* Take down netgraph node */
free(priv, M_NETGRAPH);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
return (0);
}
/*
* Hook disconnection
*/
static int
ng_UI_disconnect(hook_p hook)
{
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
if (hook == priv->downlink)
priv->downlink = NULL;
else if (hook == priv->uplink)
priv->uplink = NULL;
else
panic("%s", __func__);
/*
* If we are not already shutting down,
* and we have no more hooks, then DO shut down.
*/
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
ng_rmnode_self(NG_HOOK_NODE(hook));
}
return (0);
}

56
freebsd/netgraph/ng_UI.h Normal file
View File

@ -0,0 +1,56 @@
/*
* ng_UI.h
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Julian Elischer <julian@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_UI.h,v 1.6 1999/01/20 00:54:15 archie Exp $
*/
#ifndef _NETGRAPH_NG_UI_H_
#define _NETGRAPH_NG_UI_H_
/* Node type name and cookie */
#define NG_UI_NODE_TYPE "UI"
#define NGM_UI_COOKIE 884639499
/* Hook names */
#define NG_UI_HOOK_DOWNSTREAM "downstream"
#define NG_UI_HOOK_UPSTREAM "upstream"
#endif /* _NETGRAPH_NG_UI_H_ */

630
freebsd/netgraph/ng_async.c Normal file
View File

@ -0,0 +1,630 @@
/*
* ng_async.c
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
*/
/*
* This node type implements a PPP style sync <-> async converter.
* See RFC 1661 for details of how asynchronous encoding works.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_async.h>
#include <netgraph/ng_parse.h>
#include <net/ppp_defs.h>
#ifdef NG_SEPARATE_MALLOC
static MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node");
#else
#define M_NETGRAPH_ASYNC M_NETGRAPH
#endif
/* Async decode state */
#define MODE_HUNT 0
#define MODE_NORMAL 1
#define MODE_ESC 2
/* Private data structure */
struct ng_async_private {
node_p node; /* Our node */
hook_p async; /* Asynchronous side */
hook_p sync; /* Synchronous side */
u_char amode; /* Async hunt/esape mode */
u_int16_t fcs; /* Decoded async FCS (so far) */
u_char *abuf; /* Buffer to encode sync into */
u_char *sbuf; /* Buffer to decode async into */
u_int slen; /* Length of data in sbuf */
long lasttime; /* Time of last async packet sent */
struct ng_async_cfg cfg; /* Configuration */
struct ng_async_stat stats; /* Statistics */
};
typedef struct ng_async_private *sc_p;
/* Useful macros */
#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10)
#define SYNC_BUF_SIZE(amru) ((amru) + 10)
#define ERROUT(x) do { error = (x); goto done; } while (0)
/* Netgraph methods */
static ng_constructor_t nga_constructor;
static ng_rcvdata_t nga_rcvdata;
static ng_rcvmsg_t nga_rcvmsg;
static ng_shutdown_t nga_shutdown;
static ng_newhook_t nga_newhook;
static ng_disconnect_t nga_disconnect;
/* Helper stuff */
static int nga_rcv_sync(const sc_p sc, item_p item);
static int nga_rcv_async(const sc_p sc, item_p item);
/* Parse type for struct ng_async_cfg */
static const struct ng_parse_struct_field nga_config_type_fields[]
= NG_ASYNC_CONFIG_TYPE_INFO;
static const struct ng_parse_type nga_config_type = {
&ng_parse_struct_type,
&nga_config_type_fields
};
/* Parse type for struct ng_async_stat */
static const struct ng_parse_struct_field nga_stats_type_fields[]
= NG_ASYNC_STATS_TYPE_INFO;
static const struct ng_parse_type nga_stats_type = {
&ng_parse_struct_type,
&nga_stats_type_fields
};
/* List of commands and how to convert arguments to/from ASCII */
static const struct ng_cmdlist nga_cmdlist[] = {
{
NGM_ASYNC_COOKIE,
NGM_ASYNC_CMD_SET_CONFIG,
"setconfig",
&nga_config_type,
NULL
},
{
NGM_ASYNC_COOKIE,
NGM_ASYNC_CMD_GET_CONFIG,
"getconfig",
NULL,
&nga_config_type
},
{
NGM_ASYNC_COOKIE,
NGM_ASYNC_CMD_GET_STATS,
"getstats",
NULL,
&nga_stats_type
},
{
NGM_ASYNC_COOKIE,
NGM_ASYNC_CMD_CLR_STATS,
"clrstats",
&nga_stats_type,
NULL
},
{ 0 }
};
/* Define the netgraph node type */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_ASYNC_NODE_TYPE,
.constructor = nga_constructor,
.rcvmsg = nga_rcvmsg,
.shutdown = nga_shutdown,
.newhook = nga_newhook,
.rcvdata = nga_rcvdata,
.disconnect = nga_disconnect,
.cmdlist = nga_cmdlist
};
NETGRAPH_INIT(async, &typestruct);
/* CRC table */
static const u_int16_t fcstab[];
/******************************************************************
NETGRAPH NODE METHODS
******************************************************************/
/*
* Initialize a new node
*/
static int
nga_constructor(node_p node)
{
sc_p sc;
sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO);
sc->amode = MODE_HUNT;
sc->cfg.accm = ~0;
sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
M_NETGRAPH_ASYNC, M_WAITOK);
sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
M_NETGRAPH_ASYNC, M_WAITOK);
NG_NODE_SET_PRIVATE(node, sc);
sc->node = node;
return (0);
}
/*
* Reserve a hook for a pending connection
*/
static int
nga_newhook(node_p node, hook_p hook, const char *name)
{
const sc_p sc = NG_NODE_PRIVATE(node);
hook_p *hookp;
if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
/*
* We use a static buffer here so only one packet
* at a time can be allowed to travel in this direction.
* Force Writer semantics.
*/
NG_HOOK_FORCE_WRITER(hook);
hookp = &sc->async;
} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
/*
* We use a static state here so only one packet
* at a time can be allowed to travel in this direction.
* Force Writer semantics.
* Since we set this for both directions
* we might as well set it for the whole node
* bit I haven;t done that (yet).
*/
NG_HOOK_FORCE_WRITER(hook);
hookp = &sc->sync;
} else {
return (EINVAL);
}
if (*hookp) /* actually can't happen I think [JRE] */
return (EISCONN);
*hookp = hook;
return (0);
}
/*
* Receive incoming data
*/
static int
nga_rcvdata(hook_p hook, item_p item)
{
const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
if (hook == sc->sync)
return (nga_rcv_sync(sc, item));
if (hook == sc->async)
return (nga_rcv_async(sc, item));
panic("%s", __func__);
}
/*
* Receive incoming control message
*/
static int
nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
const sc_p sc = NG_NODE_PRIVATE(node);
struct ng_mesg *resp = NULL;
int error = 0;
struct ng_mesg *msg;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_ASYNC_COOKIE:
switch (msg->header.cmd) {
case NGM_ASYNC_CMD_GET_STATS:
NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
if (resp == NULL)
ERROUT(ENOMEM);
*((struct ng_async_stat *) resp->data) = sc->stats;
break;
case NGM_ASYNC_CMD_CLR_STATS:
bzero(&sc->stats, sizeof(sc->stats));
break;
case NGM_ASYNC_CMD_SET_CONFIG:
{
struct ng_async_cfg *const cfg =
(struct ng_async_cfg *) msg->data;
u_char *buf;
if (msg->header.arglen != sizeof(*cfg))
ERROUT(EINVAL);
if (cfg->amru < NG_ASYNC_MIN_MRU
|| cfg->amru > NG_ASYNC_MAX_MRU
|| cfg->smru < NG_ASYNC_MIN_MRU
|| cfg->smru > NG_ASYNC_MAX_MRU)
ERROUT(EINVAL);
cfg->enabled = !!cfg->enabled; /* normalize */
if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */
buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
M_NETGRAPH_ASYNC, M_NOWAIT);
if (!buf)
ERROUT(ENOMEM);
free(sc->abuf, M_NETGRAPH_ASYNC);
sc->abuf = buf;
}
if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */
buf = malloc(SYNC_BUF_SIZE(cfg->amru),
M_NETGRAPH_ASYNC, M_NOWAIT);
if (!buf)
ERROUT(ENOMEM);
free(sc->sbuf, M_NETGRAPH_ASYNC);
sc->sbuf = buf;
sc->amode = MODE_HUNT;
sc->slen = 0;
}
if (!cfg->enabled) {
sc->amode = MODE_HUNT;
sc->slen = 0;
}
sc->cfg = *cfg;
break;
}
case NGM_ASYNC_CMD_GET_CONFIG:
NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
if (!resp)
ERROUT(ENOMEM);
*((struct ng_async_cfg *) resp->data) = sc->cfg;
break;
default:
ERROUT(EINVAL);
}
break;
default:
ERROUT(EINVAL);
}
done:
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Shutdown this node
*/
static int
nga_shutdown(node_p node)
{
const sc_p sc = NG_NODE_PRIVATE(node);
free(sc->abuf, M_NETGRAPH_ASYNC);
free(sc->sbuf, M_NETGRAPH_ASYNC);
bzero(sc, sizeof(*sc));
free(sc, M_NETGRAPH_ASYNC);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
return (0);
}
/*
* Lose a hook. When both hooks go away, we disappear.
*/
static int
nga_disconnect(hook_p hook)
{
const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
hook_p *hookp;
if (hook == sc->async)
hookp = &sc->async;
else if (hook == sc->sync)
hookp = &sc->sync;
else
panic("%s", __func__);
if (!*hookp)
panic("%s 2", __func__);
*hookp = NULL;
bzero(&sc->stats, sizeof(sc->stats));
sc->lasttime = 0;
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
}
/******************************************************************
INTERNAL HELPER STUFF
******************************************************************/
/*
* Encode a byte into the async buffer
*/
static __inline void
nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
{
*fcs = PPP_FCS(*fcs, x);
if ((x < 32 && ((1 << x) & accm))
|| (x == PPP_ESCAPE)
|| (x == PPP_FLAG)) {
sc->abuf[(*len)++] = PPP_ESCAPE;
x ^= PPP_TRANS;
}
sc->abuf[(*len)++] = x;
}
/*
* Receive incoming synchronous data.
*/
static int
nga_rcv_sync(const sc_p sc, item_p item)
{
struct ifnet *rcvif;
int alen, error = 0;
struct timeval time;
u_int16_t fcs, fcs0;
u_int32_t accm;
struct mbuf *m;
#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x))
/* Check for bypass mode */
if (!sc->cfg.enabled) {
NG_FWD_ITEM_HOOK(error, item, sc->async );
return (error);
}
NGI_GET_M(item, m);
rcvif = m->m_pkthdr.rcvif;
/* Get ACCM; special case LCP frames, which use full ACCM */
accm = sc->cfg.accm;
if (m->m_pkthdr.len >= 4) {
static const u_char lcphdr[4] = {
PPP_ALLSTATIONS,
PPP_UI,
(u_char)(PPP_LCP >> 8),
(u_char)(PPP_LCP & 0xff)
};
u_char buf[4];
m_copydata(m, 0, 4, (caddr_t)buf);
if (bcmp(buf, &lcphdr, 4) == 0)
accm = ~0;
}
/* Check for overflow */
if (m->m_pkthdr.len > sc->cfg.smru) {
sc->stats.syncOverflows++;
NG_FREE_M(m);
NG_FREE_ITEM(item);
return (EMSGSIZE);
}
/* Update stats */
sc->stats.syncFrames++;
sc->stats.syncOctets += m->m_pkthdr.len;
/* Initialize async encoded version of input mbuf */
alen = 0;
fcs = PPP_INITFCS;
/* Add beginning sync flag if it's been long enough to need one */
getmicrotime(&time);
if (time.tv_sec >= sc->lasttime + 1) {
sc->abuf[alen++] = PPP_FLAG;
sc->lasttime = time.tv_sec;
}
/* Add packet payload */
while (m != NULL) {
while (m->m_len > 0) {
ADD_BYTE(*mtod(m, u_char *));
m->m_data++;
m->m_len--;
}
m = m_free(m);
}
/* Add checksum and final sync flag */
fcs0 = fcs;
ADD_BYTE(~fcs0 & 0xff);
ADD_BYTE(~fcs0 >> 8);
sc->abuf[alen++] = PPP_FLAG;
/* Put frame in an mbuf and ship it off */
if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
NG_FREE_ITEM(item);
error = ENOBUFS;
} else {
NG_FWD_NEW_DATA(error, item, sc->async, m);
}
return (error);
}
/*
* Receive incoming asynchronous data
* XXX Technically, we should strip out incoming characters
* that are in our ACCM. Not sure if this is good or not.
*/
static int
nga_rcv_async(const sc_p sc, item_p item)
{
struct ifnet *rcvif;
int error;
struct mbuf *m;
if (!sc->cfg.enabled) {
NG_FWD_ITEM_HOOK(error, item, sc->sync);
return (error);
}
NGI_GET_M(item, m);
rcvif = m->m_pkthdr.rcvif;
while (m) {
struct mbuf *n;
for (; m->m_len > 0; m->m_data++, m->m_len--) {
u_char ch = *mtod(m, u_char *);
sc->stats.asyncOctets++;
if (ch == PPP_FLAG) { /* Flag overrides everything */
int skip = 0;
/* Check for runts */
if (sc->slen < 2) {
if (sc->slen > 0)
sc->stats.asyncRunts++;
goto reset;
}
/* Verify CRC */
if (sc->fcs != PPP_GOODFCS) {
sc->stats.asyncBadCheckSums++;
goto reset;
}
sc->slen -= 2;
/* Strip address and control fields */
if (sc->slen >= 2
&& sc->sbuf[0] == PPP_ALLSTATIONS
&& sc->sbuf[1] == PPP_UI)
skip = 2;
/* Check for frame too big */
if (sc->slen - skip > sc->cfg.amru) {
sc->stats.asyncOverflows++;
goto reset;
}
/* OK, ship it out */
if ((n = m_devget(sc->sbuf + skip,
sc->slen - skip, 0, rcvif, NULL))) {
if (item) { /* sets NULL -> item */
NG_FWD_NEW_DATA(error, item,
sc->sync, n);
} else {
NG_SEND_DATA_ONLY(error,
sc->sync ,n);
}
}
sc->stats.asyncFrames++;
reset:
sc->amode = MODE_NORMAL;
sc->fcs = PPP_INITFCS;
sc->slen = 0;
continue;
}
switch (sc->amode) {
case MODE_NORMAL:
if (ch == PPP_ESCAPE) {
sc->amode = MODE_ESC;
continue;
}
break;
case MODE_ESC:
ch ^= PPP_TRANS;
sc->amode = MODE_NORMAL;
break;
case MODE_HUNT:
default:
continue;
}
/* Add byte to frame */
if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
sc->stats.asyncOverflows++;
sc->amode = MODE_HUNT;
sc->slen = 0;
} else {
sc->sbuf[sc->slen++] = ch;
sc->fcs = PPP_FCS(sc->fcs, ch);
}
}
m = m_free(m);
}
if (item)
NG_FREE_ITEM(item);
return (0);
}
/*
* CRC table
*
* Taken from RFC 1171 Appendix B
*/
static const u_int16_t fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};

110
freebsd/netgraph/ng_async.h Normal file
View File

@ -0,0 +1,110 @@
/*
* ng_async.h
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_async.h,v 1.5 1999/01/25 01:17:14 archie Exp $
*/
#ifndef _NETGRAPH_NG_ASYNC_H_
#define _NETGRAPH_NG_ASYNC_H_
/* Type name and cookie */
#define NG_ASYNC_NODE_TYPE "async"
#define NGM_ASYNC_COOKIE 886473717
/* Hook names */
#define NG_ASYNC_HOOK_SYNC "sync" /* Sync frames */
#define NG_ASYNC_HOOK_ASYNC "async" /* Async-encoded frames */
/* Maximum receive size bounds (for both sync and async sides) */
#define NG_ASYNC_MIN_MRU 1
#define NG_ASYNC_MAX_MRU 8192
#define NG_ASYNC_DEFAULT_MRU 1600
/* Frame statistics */
struct ng_async_stat {
u_int32_t syncOctets;
u_int32_t syncFrames;
u_int32_t syncOverflows;
u_int32_t asyncOctets;
u_int32_t asyncFrames;
u_int32_t asyncRunts;
u_int32_t asyncOverflows;
u_int32_t asyncBadCheckSums;
};
/* Keep this in sync with the above structure definition */
#define NG_ASYNC_STATS_TYPE_INFO { \
{ "syncOctets", &ng_parse_uint32_type }, \
{ "syncFrames", &ng_parse_uint32_type }, \
{ "syncOverflows", &ng_parse_uint32_type }, \
{ "asyncOctets", &ng_parse_uint32_type }, \
{ "asyncFrames", &ng_parse_uint32_type }, \
{ "asyncRunts", &ng_parse_uint32_type }, \
{ "asyncOverflows", &ng_parse_uint32_type }, \
{ "asyncBadCheckSums",&ng_parse_uint32_type }, \
{ NULL } \
}
/* Configuration for this node */
struct ng_async_cfg {
u_char enabled; /* Turn encoding on/off */
u_int16_t amru; /* Max receive async frame length */
u_int16_t smru; /* Max receive sync frame length */
u_int32_t accm; /* ACCM encoding */
};
/* Keep this in sync with the above structure definition */
#define NG_ASYNC_CONFIG_TYPE_INFO { \
{ "enabled", &ng_parse_int8_type }, \
{ "amru", &ng_parse_uint16_type }, \
{ "smru", &ng_parse_uint16_type }, \
{ "accm", &ng_parse_hint32_type }, \
{ NULL } \
}
/* Commands */
enum {
NGM_ASYNC_CMD_GET_STATS = 1, /* returns struct ng_async_stat */
NGM_ASYNC_CMD_CLR_STATS,
NGM_ASYNC_CMD_SET_CONFIG, /* takes struct ng_async_cfg */
NGM_ASYNC_CMD_GET_CONFIG, /* returns struct ng_async_cfg */
};
#endif /* _NETGRAPH_NG_ASYNC_H_ */

View File

@ -0,0 +1,271 @@
/*-
* Copyright (c) 2003-2004 Benno Rice <benno@eloquent.com.au>
* 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 ``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 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$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_atmllc.h>
#include <net/if.h>
#include <net/ethernet.h> /* for M_HASFCS and ETHER_HDR_LEN */
#include <net/if_atm.h> /* for struct atmllc */
#define NG_ATMLLC_HEADER "\252\252\3\0\200\302"
#define NG_ATMLLC_HEADER_LEN (sizeof(struct atmllc))
#define NG_ATMLLC_TYPE_ETHERNET_FCS 0x0001
#define NG_ATMLLC_TYPE_FDDI_FCS 0x0004
#define NG_ATMLLC_TYPE_ETHERNET_NOFCS 0x0007
#define NG_ATMLLC_TYPE_FDDI_NOFCS 0x000A
struct ng_atmllc_priv {
hook_p atm;
hook_p ether;
hook_p fddi;
};
/* Netgraph methods. */
static ng_constructor_t ng_atmllc_constructor;
static ng_shutdown_t ng_atmllc_shutdown;
static ng_rcvmsg_t ng_atmllc_rcvmsg;
static ng_newhook_t ng_atmllc_newhook;
static ng_rcvdata_t ng_atmllc_rcvdata;
static ng_disconnect_t ng_atmllc_disconnect;
static struct ng_type ng_atmllc_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_ATMLLC_NODE_TYPE,
.constructor = ng_atmllc_constructor,
.rcvmsg = ng_atmllc_rcvmsg,
.shutdown = ng_atmllc_shutdown,
.newhook = ng_atmllc_newhook,
.rcvdata = ng_atmllc_rcvdata,
.disconnect = ng_atmllc_disconnect,
};
NETGRAPH_INIT(atmllc, &ng_atmllc_typestruct);
static int
ng_atmllc_constructor(node_p node)
{
struct ng_atmllc_priv *priv;
priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
NG_NODE_SET_PRIVATE(node, priv);
return (0);
}
static int
ng_atmllc_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct ng_mesg *msg;
int error;
error = 0;
NGI_GET_MSG(item, msg);
msg->header.flags |= NGF_RESP;
NG_RESPOND_MSG(error, node, item, msg);
return (error);
}
static int
ng_atmllc_shutdown(node_p node)
{
struct ng_atmllc_priv *priv;
priv = NG_NODE_PRIVATE(node);
free(priv, M_NETGRAPH);
NG_NODE_UNREF(node);
return (0);
}
static int
ng_atmllc_newhook(node_p node, hook_p hook, const char *name)
{
struct ng_atmllc_priv *priv;
priv = NG_NODE_PRIVATE(node);
if (strcmp(name, NG_ATMLLC_HOOK_ATM) == 0) {
if (priv->atm != NULL) {
return (EISCONN);
}
priv->atm = hook;
} else if (strcmp(name, NG_ATMLLC_HOOK_ETHER) == 0) {
if (priv->ether != NULL) {
return (EISCONN);
}
priv->ether = hook;
} else if (strcmp(name, NG_ATMLLC_HOOK_FDDI) == 0) {
if (priv->fddi != NULL) {
return (EISCONN);
}
priv->fddi = hook;
} else {
return (EINVAL);
}
return (0);
}
static int
ng_atmllc_rcvdata(hook_p hook, item_p item)
{
struct ng_atmllc_priv *priv;
struct mbuf *m;
struct atmllc *hdr;
hook_p outhook;
u_int padding;
int error;
priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
NGI_GET_M(item, m);
outhook = NULL;
padding = 0;
if (hook == priv->atm) {
/* Ditch the psuedoheader. */
hdr = mtod(m, struct atmllc *);
/* m_adj(m, sizeof(struct atm_pseudohdr)); */
/*
* Make sure we have the LLC and ethernet headers.
* The ethernet header size is slightly larger than the FDDI
* header, which is convenient.
*/
if (m->m_len < sizeof(struct atmllc) + ETHER_HDR_LEN) {
m = m_pullup(m, sizeof(struct atmllc) + ETHER_HDR_LEN);
if (m == NULL) {
NG_FREE_ITEM(item);
return (ENOMEM);
}
}
/* Decode the LLC header. */
hdr = mtod(m, struct atmllc *);
if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_NOFCS) {
m->m_flags &= ~M_HASFCS;
outhook = priv->ether;
padding = 2;
} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_FCS) {
m->m_flags |= M_HASFCS;
outhook = priv->ether;
padding = 2;
} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_NOFCS) {
m->m_flags &= ~M_HASFCS;
outhook = priv->fddi;
padding = 3;
} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_FCS) {
m->m_flags |= M_HASFCS;
outhook = priv->fddi;
padding = 3;
} else {
printf("ng_atmllc: unknown type: %x\n",
ATM_LLC_TYPE(hdr));
}
/* Remove the LLC header and any padding*/
m_adj(m, sizeof(struct atmllc) + padding);
} else if (hook == priv->ether) {
/* Add the LLC header */
M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 2, M_NOWAIT);
if (m == NULL) {
printf("ng_atmllc: M_PREPEND failed\n");
NG_FREE_ITEM(item);
return (ENOMEM);
}
hdr = mtod(m, struct atmllc *);
bzero((void *)hdr, sizeof(struct atmllc) + 2);
bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
if ((m->m_flags & M_HASFCS) != 0) {
ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_FCS);
} else {
ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_NOFCS);
}
outhook = priv->atm;
} else if (hook == priv->fddi) {
/* Add the LLC header */
M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 3, M_NOWAIT);
if (m == NULL) {
printf("ng_atmllc: M_PREPEND failed\n");
NG_FREE_ITEM(item);
return (ENOMEM);
}
hdr = mtod(m, struct atmllc *);
bzero((void *)hdr, sizeof(struct atmllc) + 3);
bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
if ((m->m_flags & M_HASFCS) != 0) {
ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_FCS);
} else {
ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_NOFCS);
}
outhook = priv->atm;
}
if (outhook == NULL) {
NG_FREE_M(m);
NG_FREE_ITEM(item);
return (0);
}
NG_FWD_NEW_DATA(error, item, outhook, m);
return (error);
}
static int
ng_atmllc_disconnect(hook_p hook)
{
node_p node;
struct ng_atmllc_priv *priv;
node = NG_HOOK_NODE(hook);
priv = NG_NODE_PRIVATE(node);
if (hook == priv->atm) {
priv->atm = NULL;
} else if (hook == priv->ether) {
priv->ether = NULL;
} else if (hook == priv->fddi) {
priv->fddi = NULL;
}
if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) {
ng_rmnode_self(node);
}
return (0);
}

View File

@ -0,0 +1,45 @@
/*-
* Copyright (c) 2003-2004 Benno Rice <benno@FreeBSD.org>
* 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 ``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 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$
*/
#ifndef _NETGRAPH_ATMLLC_H_
#define _NETGRAPH_ATMLLC_H_
/* Node type name and magic cookie. */
#define NG_ATMLLC_NODE_TYPE "atmllc"
#define NGM_ATMLLC_COOKIE 1065246274
/* Hook names. */
#define NG_ATMLLC_HOOK_ATM "atm"
#define NG_ATMLLC_HOOK_ETHER "ether"
#define NG_ATMLLC_HOOK_802_4 "ieee8024"
#define NG_ATMLLC_HOOK_802_5 "ieee8025"
#define NG_ATMLLC_HOOK_802_6 "ieee8026"
#define NG_ATMLLC_HOOK_FDDI "fddi"
#define NG_ATMLLC_HOOK_BPDU "bpdu"
#endif /* _NETGRAPH_ATMLLC_H_ */

3846
freebsd/netgraph/ng_base.c Normal file

File diff suppressed because it is too large Load Diff

594
freebsd/netgraph/ng_bpf.c Normal file
View File

@ -0,0 +1,594 @@
/*
* ng_bpf.c
*/
/*-
* Copyright (c) 1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
*/
/*
* BPF NETGRAPH NODE TYPE
*
* This node type accepts any number of hook connections. With each hook
* is associated a bpf(4) filter program, and two hook names (each possibly
* the empty string). Incoming packets are compared against the filter;
* matching packets are delivered out the first named hook (or dropped if
* the empty string), and non-matching packets are delivered out the second
* named hook (or dropped if the empty string).
*
* Each hook also keeps statistics about how many packets have matched, etc.
*/
#include "opt_bpf.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <net/bpf.h>
#ifdef BPF_JITTER
#include <net/bpf_jitter.h>
#endif
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/ng_bpf.h>
#ifdef NG_SEPARATE_MALLOC
static MALLOC_DEFINE(M_NETGRAPH_BPF, "netgraph_bpf", "netgraph bpf node");
#else
#define M_NETGRAPH_BPF M_NETGRAPH
#endif
#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
#define ERROUT(x) do { error = (x); goto done; } while (0)
/* Per hook private info */
struct ng_bpf_hookinfo {
hook_p hook;
hook_p match;
hook_p nomatch;
struct ng_bpf_hookprog *prog;
#ifdef BPF_JITTER
bpf_jit_filter *jit_prog;
#endif
struct ng_bpf_hookstat stats;
};
typedef struct ng_bpf_hookinfo *hinfo_p;
/* Netgraph methods */
static ng_constructor_t ng_bpf_constructor;
static ng_rcvmsg_t ng_bpf_rcvmsg;
static ng_shutdown_t ng_bpf_shutdown;
static ng_newhook_t ng_bpf_newhook;
static ng_rcvdata_t ng_bpf_rcvdata;
static ng_disconnect_t ng_bpf_disconnect;
/* Maximum bpf program instructions */
extern int bpf_maxinsns;
/* Internal helper functions */
static int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
/* Parse type for one struct bfp_insn */
static const struct ng_parse_struct_field ng_bpf_insn_type_fields[] = {
{ "code", &ng_parse_hint16_type },
{ "jt", &ng_parse_uint8_type },
{ "jf", &ng_parse_uint8_type },
{ "k", &ng_parse_uint32_type },
{ NULL }
};
static const struct ng_parse_type ng_bpf_insn_type = {
&ng_parse_struct_type,
&ng_bpf_insn_type_fields
};
/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
static int
ng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
const u_char *start, const u_char *buf)
{
const struct ng_bpf_hookprog *hp;
hp = (const struct ng_bpf_hookprog *)
(buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog));
return hp->bpf_prog_len;
}
static const struct ng_parse_array_info ng_bpf_hookprogary_info = {
&ng_bpf_insn_type,
&ng_bpf_hookprogary_getLength,
NULL
};
static const struct ng_parse_type ng_bpf_hookprogary_type = {
&ng_parse_array_type,
&ng_bpf_hookprogary_info
};
/* Parse type for struct ng_bpf_hookprog */
static const struct ng_parse_struct_field ng_bpf_hookprog_type_fields[]
= NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
static const struct ng_parse_type ng_bpf_hookprog_type = {
&ng_parse_struct_type,
&ng_bpf_hookprog_type_fields
};
/* Parse type for struct ng_bpf_hookstat */
static const struct ng_parse_struct_field ng_bpf_hookstat_type_fields[]
= NG_BPF_HOOKSTAT_TYPE_INFO;
static const struct ng_parse_type ng_bpf_hookstat_type = {
&ng_parse_struct_type,
&ng_bpf_hookstat_type_fields
};
/* List of commands and how to convert arguments to/from ASCII */
static const struct ng_cmdlist ng_bpf_cmdlist[] = {
{
NGM_BPF_COOKIE,
NGM_BPF_SET_PROGRAM,
"setprogram",
&ng_bpf_hookprog_type,
NULL
},
{
NGM_BPF_COOKIE,
NGM_BPF_GET_PROGRAM,
"getprogram",
&ng_parse_hookbuf_type,
&ng_bpf_hookprog_type
},
{
NGM_BPF_COOKIE,
NGM_BPF_GET_STATS,
"getstats",
&ng_parse_hookbuf_type,
&ng_bpf_hookstat_type
},
{
NGM_BPF_COOKIE,
NGM_BPF_CLR_STATS,
"clrstats",
&ng_parse_hookbuf_type,
NULL
},
{
NGM_BPF_COOKIE,
NGM_BPF_GETCLR_STATS,
"getclrstats",
&ng_parse_hookbuf_type,
&ng_bpf_hookstat_type
},
{ 0 }
};
/* Netgraph type descriptor */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_BPF_NODE_TYPE,
.constructor = ng_bpf_constructor,
.rcvmsg = ng_bpf_rcvmsg,
.shutdown = ng_bpf_shutdown,
.newhook = ng_bpf_newhook,
.rcvdata = ng_bpf_rcvdata,
.disconnect = ng_bpf_disconnect,
.cmdlist = ng_bpf_cmdlist,
};
NETGRAPH_INIT(bpf, &typestruct);
/* Default BPF program for a hook that matches nothing */
static const struct ng_bpf_hookprog ng_bpf_default_prog = {
{ '\0' }, /* to be filled in at hook creation time */
{ '\0' },
{ '\0' },
1,
{ BPF_STMT(BPF_RET+BPF_K, 0) }
};
/*
* Node constructor
*
* We don't keep any per-node private data
* We go via the hooks.
*/
static int
ng_bpf_constructor(node_p node)
{
NG_NODE_SET_PRIVATE(node, NULL);
return (0);
}
/*
* Callback functions to be used by NG_NODE_FOREACH_HOOK() macro.
*/
static int
ng_bpf_addrefs(hook_p hook, void* arg)
{
hinfo_p hip = NG_HOOK_PRIVATE(hook);
hook_p h = (hook_p)arg;
if (strcmp(hip->prog->ifMatch, NG_HOOK_NAME(h)) == 0)
hip->match = h;
if (strcmp(hip->prog->ifNotMatch, NG_HOOK_NAME(h)) == 0)
hip->nomatch = h;
return (1);
}
static int
ng_bpf_remrefs(hook_p hook, void* arg)
{
hinfo_p hip = NG_HOOK_PRIVATE(hook);
hook_p h = (hook_p)arg;
if (hip->match == h)
hip->match = NULL;
if (hip->nomatch == h)
hip->nomatch = NULL;
return (1);
}
/*
* Add a hook
*/
static int
ng_bpf_newhook(node_p node, hook_p hook, const char *name)
{
hinfo_p hip;
hook_p tmp;
int error;
/* Create hook private structure */
hip = malloc(sizeof(*hip), M_NETGRAPH_BPF, M_NOWAIT | M_ZERO);
if (hip == NULL)
return (ENOMEM);
hip->hook = hook;
NG_HOOK_SET_PRIVATE(hook, hip);
/* Add our reference into other hooks data. */
NG_NODE_FOREACH_HOOK(node, ng_bpf_addrefs, hook, tmp);
/* Attach the default BPF program */
if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
free(hip, M_NETGRAPH_BPF);
NG_HOOK_SET_PRIVATE(hook, NULL);
return (error);
}
/* Set hook name */
strlcpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook));
return (0);
}
/*
* Receive a control message
*/
static int
ng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct ng_mesg *msg;
struct ng_mesg *resp = NULL;
int error = 0;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_BPF_COOKIE:
switch (msg->header.cmd) {
case NGM_BPF_SET_PROGRAM:
{
struct ng_bpf_hookprog *const
hp = (struct ng_bpf_hookprog *)msg->data;
hook_p hook;
/* Sanity check */
if (msg->header.arglen < sizeof(*hp)
|| msg->header.arglen
!= NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
ERROUT(EINVAL);
/* Find hook */
if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
ERROUT(ENOENT);
/* Set new program */
if ((error = ng_bpf_setprog(hook, hp)) != 0)
ERROUT(error);
break;
}
case NGM_BPF_GET_PROGRAM:
{
struct ng_bpf_hookprog *hp;
hook_p hook;
/* Sanity check */
if (msg->header.arglen == 0)
ERROUT(EINVAL);
msg->data[msg->header.arglen - 1] = '\0';
/* Find hook */
if ((hook = ng_findhook(node, msg->data)) == NULL)
ERROUT(ENOENT);
/* Build response */
hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->prog;
NG_MKRESPONSE(resp, msg,
NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT);
if (resp == NULL)
ERROUT(ENOMEM);
bcopy(hp, resp->data,
NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
break;
}
case NGM_BPF_GET_STATS:
case NGM_BPF_CLR_STATS:
case NGM_BPF_GETCLR_STATS:
{
struct ng_bpf_hookstat *stats;
hook_p hook;
/* Sanity check */
if (msg->header.arglen == 0)
ERROUT(EINVAL);
msg->data[msg->header.arglen - 1] = '\0';
/* Find hook */
if ((hook = ng_findhook(node, msg->data)) == NULL)
ERROUT(ENOENT);
stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
/* Build response (if desired) */
if (msg->header.cmd != NGM_BPF_CLR_STATS) {
NG_MKRESPONSE(resp,
msg, sizeof(*stats), M_NOWAIT);
if (resp == NULL)
ERROUT(ENOMEM);
bcopy(stats, resp->data, sizeof(*stats));
}
/* Clear stats (if desired) */
if (msg->header.cmd != NGM_BPF_GET_STATS)
bzero(stats, sizeof(*stats));
break;
}
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
done:
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Receive data on a hook
*
* Apply the filter, and then drop or forward packet as appropriate.
*/
static int
ng_bpf_rcvdata(hook_p hook, item_p item)
{
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
int totlen;
int needfree = 0, error = 0, usejit = 0;
u_char *data = NULL;
hinfo_p dhip;
hook_p dest;
u_int len;
struct mbuf *m;
m = NGI_M(item); /* 'item' still owns it.. we are peeking */
totlen = m->m_pkthdr.len;
/* Update stats on incoming hook. XXX Can we do 64 bits atomically? */
/* atomic_add_int64(&hip->stats.recvFrames, 1); */
/* atomic_add_int64(&hip->stats.recvOctets, totlen); */
hip->stats.recvFrames++;
hip->stats.recvOctets += totlen;
/* Don't call bpf_filter() with totlen == 0! */
if (totlen == 0) {
len = 0;
goto ready;
}
#ifdef BPF_JITTER
if (bpf_jitter_enable != 0 && hip->jit_prog != NULL)
usejit = 1;
#endif
/* Need to put packet in contiguous memory for bpf */
if (m->m_next != NULL && totlen > MHLEN) {
if (usejit) {
data = malloc(totlen, M_NETGRAPH_BPF, M_NOWAIT);
if (data == NULL) {
NG_FREE_ITEM(item);
return (ENOMEM);
}
needfree = 1;
m_copydata(m, 0, totlen, (caddr_t)data);
}
} else {
if (m->m_next != NULL) {
NGI_M(item) = m = m_pullup(m, totlen);
if (m == NULL) {
NG_FREE_ITEM(item);
return (ENOBUFS);
}
}
data = mtod(m, u_char *);
}
/* Run packet through filter */
#ifdef BPF_JITTER
if (usejit)
len = (*(hip->jit_prog->func))(data, totlen, totlen);
else
#endif
if (data)
len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
else
len = bpf_filter(hip->prog->bpf_prog, (u_char *)m, totlen, 0);
if (needfree)
free(data, M_NETGRAPH_BPF);
ready:
/* See if we got a match and find destination hook */
if (len > 0) {
/* Update stats */
/* XXX atomically? */
hip->stats.recvMatchFrames++;
hip->stats.recvMatchOctets += totlen;
/* Truncate packet length if required by the filter */
/* Assume this never changes m */
if (len < totlen) {
m_adj(m, -(totlen - len));
totlen = len;
}
dest = hip->match;
} else
dest = hip->nomatch;
if (dest == NULL) {
NG_FREE_ITEM(item);
return (0);
}
/* Deliver frame out destination hook */
dhip = NG_HOOK_PRIVATE(dest);
dhip->stats.xmitOctets += totlen;
dhip->stats.xmitFrames++;
NG_FWD_ITEM_HOOK(error, item, dest);
return (error);
}
/*
* Shutdown processing
*/
static int
ng_bpf_shutdown(node_p node)
{
NG_NODE_UNREF(node);
return (0);
}
/*
* Hook disconnection
*/
static int
ng_bpf_disconnect(hook_p hook)
{
const node_p node = NG_HOOK_NODE(hook);
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
hook_p tmp;
KASSERT(hip != NULL, ("%s: null info", __func__));
/* Remove our reference from other hooks data. */
NG_NODE_FOREACH_HOOK(node, ng_bpf_remrefs, hook, tmp);
free(hip->prog, M_NETGRAPH_BPF);
#ifdef BPF_JITTER
if (hip->jit_prog != NULL)
bpf_destroy_jit_filter(hip->jit_prog);
#endif
free(hip, M_NETGRAPH_BPF);
if ((NG_NODE_NUMHOOKS(node) == 0) &&
(NG_NODE_IS_VALID(node))) {
ng_rmnode_self(node);
}
return (0);
}
/************************************************************************
HELPER STUFF
************************************************************************/
/*
* Set the BPF program associated with a hook
*/
static int
ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
{
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
struct ng_bpf_hookprog *hp;
#ifdef BPF_JITTER
bpf_jit_filter *jit_prog;
#endif
int size;
/* Check program for validity */
if (hp0->bpf_prog_len > bpf_maxinsns ||
!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
return (EINVAL);
/* Make a copy of the program */
size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
hp = malloc(size, M_NETGRAPH_BPF, M_NOWAIT);
if (hp == NULL)
return (ENOMEM);
bcopy(hp0, hp, size);
#ifdef BPF_JITTER
jit_prog = bpf_jitter(hp->bpf_prog, hp->bpf_prog_len);
#endif
/* Free previous program, if any, and assign new one */
if (hip->prog != NULL)
free(hip->prog, M_NETGRAPH_BPF);
hip->prog = hp;
#ifdef BPF_JITTER
if (hip->jit_prog != NULL)
bpf_destroy_jit_filter(hip->jit_prog);
hip->jit_prog = jit_prog;
#endif
/* Prepare direct references on target hooks. */
hip->match = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifMatch);
hip->nomatch = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifNotMatch);
return (0);
}

103
freebsd/netgraph/ng_bpf.h Normal file
View File

@ -0,0 +1,103 @@
/*
* ng_bpf.h
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_bpf.h,v 1.3 1999/12/03 20:30:23 archie Exp $
*/
#ifndef _NETGRAPH_NG_BPF_H_
#define _NETGRAPH_NG_BPF_H_
/* Node type name and magic cookie */
#define NG_BPF_NODE_TYPE "bpf"
#define NGM_BPF_COOKIE 944100792
/* Program structure for one hook */
struct ng_bpf_hookprog {
char thisHook[NG_HOOKSIZ]; /* name of hook */
char ifMatch[NG_HOOKSIZ]; /* match dest hook */
char ifNotMatch[NG_HOOKSIZ]; /* !match dest hook */
int32_t bpf_prog_len; /* #insns in program */
struct bpf_insn bpf_prog[]; /* bpf program */
};
#define NG_BPF_HOOKPROG_SIZE(numInsn) \
(sizeof(struct ng_bpf_hookprog) + (numInsn) * sizeof(struct bpf_insn))
/* Keep this in sync with the above structure definition */
#define NG_BPF_HOOKPROG_TYPE_INFO(bptype) { \
{ "thisHook", &ng_parse_hookbuf_type }, \
{ "ifMatch", &ng_parse_hookbuf_type }, \
{ "ifNotMatch", &ng_parse_hookbuf_type }, \
{ "bpf_prog_len", &ng_parse_int32_type }, \
{ "bpf_prog", (bptype) }, \
{ NULL } \
}
/* Statistics structure for one hook */
struct ng_bpf_hookstat {
u_int64_t recvFrames;
u_int64_t recvOctets;
u_int64_t recvMatchFrames;
u_int64_t recvMatchOctets;
u_int64_t xmitFrames;
u_int64_t xmitOctets;
};
/* Keep this in sync with the above structure definition */
#define NG_BPF_HOOKSTAT_TYPE_INFO { \
{ "recvFrames", &ng_parse_uint64_type }, \
{ "recvOctets", &ng_parse_uint64_type }, \
{ "recvMatchFrames", &ng_parse_uint64_type }, \
{ "recvMatchOctets", &ng_parse_uint64_type }, \
{ "xmitFrames", &ng_parse_uint64_type }, \
{ "xmitOctets", &ng_parse_uint64_type }, \
{ NULL } \
}
/* Netgraph commands */
enum {
NGM_BPF_SET_PROGRAM = 1, /* supply a struct ng_bpf_hookprog */
NGM_BPF_GET_PROGRAM, /* returns a struct ng_bpf_hookprog */
NGM_BPF_GET_STATS, /* supply name as char[NG_HOOKSIZ] */
NGM_BPF_CLR_STATS, /* supply name as char[NG_HOOKSIZ] */
NGM_BPF_GETCLR_STATS, /* supply name as char[NG_HOOKSIZ] */
};
#endif /* _NETGRAPH_NG_BPF_H_ */

1055
freebsd/netgraph/ng_bridge.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,156 @@
/*
* ng_bridge.h
*/
/*-
* Copyright (c) 2000 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
*/
#ifndef _NETGRAPH_NG_BRIDGE_H_
#define _NETGRAPH_NG_BRIDGE_H_
/* Node type name and magic cookie */
#define NG_BRIDGE_NODE_TYPE "bridge"
#define NGM_BRIDGE_COOKIE 967239368
/* Hook names */
#define NG_BRIDGE_HOOK_LINK_PREFIX "link" /* append decimal integer */
#define NG_BRIDGE_HOOK_LINK_FMT "link%d" /* for use with printf(3) */
/* Maximum number of supported links */
#define NG_BRIDGE_MAX_LINKS 32
/* Node configuration structure */
struct ng_bridge_config {
u_char ipfw[NG_BRIDGE_MAX_LINKS]; /* enable ipfw */
u_char debugLevel; /* debug level */
u_int32_t loopTimeout; /* link loopback mute time */
u_int32_t maxStaleness; /* max host age before nuking */
u_int32_t minStableAge; /* min time for a stable host */
};
/* Keep this in sync with the above structure definition */
#define NG_BRIDGE_CONFIG_TYPE_INFO(ainfo) { \
{ "ipfw", (ainfo) }, \
{ "debugLevel", &ng_parse_uint8_type }, \
{ "loopTimeout", &ng_parse_uint32_type }, \
{ "maxStaleness", &ng_parse_uint32_type }, \
{ "minStableAge", &ng_parse_uint32_type }, \
{ NULL } \
}
/* Statistics structure (one for each link) */
struct ng_bridge_link_stats {
u_int64_t recvOctets; /* total octets rec'd on link */
u_int64_t recvPackets; /* total pkts rec'd on link */
u_int64_t recvMulticasts; /* multicast pkts rec'd on link */
u_int64_t recvBroadcasts; /* broadcast pkts rec'd on link */
u_int64_t recvUnknown; /* pkts rec'd with unknown dest addr */
u_int64_t recvRunts; /* pkts rec'd less than 14 bytes */
u_int64_t recvInvalid; /* pkts rec'd with bogus source addr */
u_int64_t xmitOctets; /* total octets xmit'd on link */
u_int64_t xmitPackets; /* total pkts xmit'd on link */
u_int64_t xmitMulticasts; /* multicast pkts xmit'd on link */
u_int64_t xmitBroadcasts; /* broadcast pkts xmit'd on link */
u_int64_t loopDrops; /* pkts dropped due to loopback */
u_int64_t loopDetects; /* number of loop detections */
u_int64_t memoryFailures; /* times couldn't get mem or mbuf */
};
/* Keep this in sync with the above structure definition */
#define NG_BRIDGE_STATS_TYPE_INFO { \
{ "recvOctets", &ng_parse_uint64_type }, \
{ "recvPackets", &ng_parse_uint64_type }, \
{ "recvMulticast", &ng_parse_uint64_type }, \
{ "recvBroadcast", &ng_parse_uint64_type }, \
{ "recvUnknown", &ng_parse_uint64_type }, \
{ "recvRunts", &ng_parse_uint64_type }, \
{ "recvInvalid", &ng_parse_uint64_type }, \
{ "xmitOctets", &ng_parse_uint64_type }, \
{ "xmitPackets", &ng_parse_uint64_type }, \
{ "xmitMulticasts", &ng_parse_uint64_type }, \
{ "xmitBroadcasts", &ng_parse_uint64_type }, \
{ "loopDrops", &ng_parse_uint64_type }, \
{ "loopDetects", &ng_parse_uint64_type }, \
{ "memoryFailures", &ng_parse_uint64_type }, \
{ NULL } \
}
/* Structure describing a single host */
struct ng_bridge_host {
u_char addr[6]; /* ethernet address */
u_int16_t linkNum; /* link where addr can be found */
u_int16_t age; /* seconds ago entry was created */
u_int16_t staleness; /* seconds ago host last heard from */
};
/* Keep this in sync with the above structure definition */
#define NG_BRIDGE_HOST_TYPE_INFO(entype) { \
{ "addr", (entype) }, \
{ "linkNum", &ng_parse_uint16_type }, \
{ "age", &ng_parse_uint16_type }, \
{ "staleness", &ng_parse_uint16_type }, \
{ NULL } \
}
/* Structure returned by NGM_BRIDGE_GET_TABLE */
struct ng_bridge_host_ary {
u_int32_t numHosts;
struct ng_bridge_host hosts[];
};
/* Keep this in sync with the above structure definition */
#define NG_BRIDGE_HOST_ARY_TYPE_INFO(harytype) { \
{ "numHosts", &ng_parse_uint32_type }, \
{ "hosts", (harytype) }, \
{ NULL } \
}
/* Netgraph control messages */
enum {
NGM_BRIDGE_SET_CONFIG = 1, /* set node configuration */
NGM_BRIDGE_GET_CONFIG, /* get node configuration */
NGM_BRIDGE_RESET, /* reset (forget) all information */
NGM_BRIDGE_GET_STATS, /* get link stats */
NGM_BRIDGE_CLR_STATS, /* clear link stats */
NGM_BRIDGE_GETCLR_STATS, /* atomically get & clear link stats */
NGM_BRIDGE_GET_TABLE, /* get link table */
NGM_BRIDGE_SET_PERSISTENT, /* set persistent mode */
};
#endif /* _NETGRAPH_NG_BRIDGE_H_ */

764
freebsd/netgraph/ng_car.c Normal file
View File

@ -0,0 +1,764 @@
/*-
* Copyright (c) 2005 Nuno Antunes <nuno.antunes@gmail.com>
* Copyright (c) 2007 Alexander Motin <mav@freebsd.org>
* 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 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 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$
*/
/*
* ng_car - An implementation of committed access rate for netgraph
*
* TODO:
* - Sanitize input config values (impose some limits)
* - Implement internal packet painting (possibly using mbuf tags)
* - Implement color-aware mode
* - Implement DSCP marking for IPv4
*/
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <netgraph/ng_message.h>
#include <netgraph/ng_parse.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_car.h>
#define NG_CAR_QUEUE_SIZE 100 /* Maximum queue size for SHAPE mode */
#define NG_CAR_QUEUE_MIN_TH 8 /* Minimum RED threshold for SHAPE mode */
/* Hook private info */
struct hookinfo {
hook_p hook; /* this (source) hook */
hook_p dest; /* destination hook */
int64_t tc; /* committed token bucket counter */
int64_t te; /* exceeded/peak token bucket counter */
struct bintime lastRefill; /* last token refill time */
struct ng_car_hookconf conf; /* hook configuration */
struct ng_car_hookstats stats; /* hook stats */
struct mbuf *q[NG_CAR_QUEUE_SIZE]; /* circular packet queue */
u_int q_first; /* first queue element */
u_int q_last; /* last queue element */
struct callout q_callout; /* periodic queue processing routine */
struct mtx q_mtx; /* queue mutex */
};
/* Private information for each node instance */
struct privdata {
node_p node; /* the node itself */
struct hookinfo upper; /* hook to upper layers */
struct hookinfo lower; /* hook to lower layers */
};
typedef struct privdata *priv_p;
static ng_constructor_t ng_car_constructor;
static ng_rcvmsg_t ng_car_rcvmsg;
static ng_shutdown_t ng_car_shutdown;
static ng_newhook_t ng_car_newhook;
static ng_rcvdata_t ng_car_rcvdata;
static ng_disconnect_t ng_car_disconnect;
static void ng_car_refillhook(struct hookinfo *h);
static void ng_car_schedule(struct hookinfo *h);
void ng_car_q_event(node_p node, hook_p hook, void *arg, int arg2);
static void ng_car_enqueue(struct hookinfo *h, item_p item);
/* Parse type for struct ng_car_hookstats */
static const struct ng_parse_struct_field ng_car_hookstats_type_fields[]
= NG_CAR_HOOKSTATS;
static const struct ng_parse_type ng_car_hookstats_type = {
&ng_parse_struct_type,
&ng_car_hookstats_type_fields
};
/* Parse type for struct ng_car_bulkstats */
static const struct ng_parse_struct_field ng_car_bulkstats_type_fields[]
= NG_CAR_BULKSTATS(&ng_car_hookstats_type);
static const struct ng_parse_type ng_car_bulkstats_type = {
&ng_parse_struct_type,
&ng_car_bulkstats_type_fields
};
/* Parse type for struct ng_car_hookconf */
static const struct ng_parse_struct_field ng_car_hookconf_type_fields[]
= NG_CAR_HOOKCONF;
static const struct ng_parse_type ng_car_hookconf_type = {
&ng_parse_struct_type,
&ng_car_hookconf_type_fields
};
/* Parse type for struct ng_car_bulkconf */
static const struct ng_parse_struct_field ng_car_bulkconf_type_fields[]
= NG_CAR_BULKCONF(&ng_car_hookconf_type);
static const struct ng_parse_type ng_car_bulkconf_type = {
&ng_parse_struct_type,
&ng_car_bulkconf_type_fields
};
/* Command list */
static struct ng_cmdlist ng_car_cmdlist[] = {
{
NGM_CAR_COOKIE,
NGM_CAR_GET_STATS,
"getstats",
NULL,
&ng_car_bulkstats_type,
},
{
NGM_CAR_COOKIE,
NGM_CAR_CLR_STATS,
"clrstats",
NULL,
NULL,
},
{
NGM_CAR_COOKIE,
NGM_CAR_GETCLR_STATS,
"getclrstats",
NULL,
&ng_car_bulkstats_type,
},
{
NGM_CAR_COOKIE,
NGM_CAR_GET_CONF,
"getconf",
NULL,
&ng_car_bulkconf_type,
},
{
NGM_CAR_COOKIE,
NGM_CAR_SET_CONF,
"setconf",
&ng_car_bulkconf_type,
NULL,
},
{ 0 }
};
/* Netgraph node type descriptor */
static struct ng_type ng_car_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_CAR_NODE_TYPE,
.constructor = ng_car_constructor,
.rcvmsg = ng_car_rcvmsg,
.shutdown = ng_car_shutdown,
.newhook = ng_car_newhook,
.rcvdata = ng_car_rcvdata,
.disconnect = ng_car_disconnect,
.cmdlist = ng_car_cmdlist,
};
NETGRAPH_INIT(car, &ng_car_typestruct);
/*
* Node constructor
*/
static int
ng_car_constructor(node_p node)
{
priv_p priv;
/* Initialize private descriptor. */
priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
NG_NODE_SET_PRIVATE(node, priv);
priv->node = node;
/*
* Arbitrary default values
*/
priv->upper.hook = NULL;
priv->upper.dest = NULL;
priv->upper.tc = priv->upper.conf.cbs = NG_CAR_CBS_MIN;
priv->upper.te = priv->upper.conf.ebs = NG_CAR_EBS_MIN;
priv->upper.conf.cir = NG_CAR_CIR_DFLT;
priv->upper.conf.green_action = NG_CAR_ACTION_FORWARD;
priv->upper.conf.yellow_action = NG_CAR_ACTION_FORWARD;
priv->upper.conf.red_action = NG_CAR_ACTION_DROP;
priv->upper.conf.mode = 0;
getbinuptime(&priv->upper.lastRefill);
priv->upper.q_first = 0;
priv->upper.q_last = 0;
ng_callout_init(&priv->upper.q_callout);
mtx_init(&priv->upper.q_mtx, "ng_car_u", NULL, MTX_DEF);
priv->lower.hook = NULL;
priv->lower.dest = NULL;
priv->lower.tc = priv->lower.conf.cbs = NG_CAR_CBS_MIN;
priv->lower.te = priv->lower.conf.ebs = NG_CAR_EBS_MIN;
priv->lower.conf.cir = NG_CAR_CIR_DFLT;
priv->lower.conf.green_action = NG_CAR_ACTION_FORWARD;
priv->lower.conf.yellow_action = NG_CAR_ACTION_FORWARD;
priv->lower.conf.red_action = NG_CAR_ACTION_DROP;
priv->lower.conf.mode = 0;
priv->lower.lastRefill = priv->upper.lastRefill;
priv->lower.q_first = 0;
priv->lower.q_last = 0;
ng_callout_init(&priv->lower.q_callout);
mtx_init(&priv->lower.q_mtx, "ng_car_l", NULL, MTX_DEF);
return (0);
}
/*
* Add a hook.
*/
static int
ng_car_newhook(node_p node, hook_p hook, const char *name)
{
const priv_p priv = NG_NODE_PRIVATE(node);
if (strcmp(name, NG_CAR_HOOK_LOWER) == 0) {
priv->lower.hook = hook;
priv->upper.dest = hook;
bzero(&priv->lower.stats, sizeof(priv->lower.stats));
NG_HOOK_SET_PRIVATE(hook, &priv->lower);
} else if (strcmp(name, NG_CAR_HOOK_UPPER) == 0) {
priv->upper.hook = hook;
priv->lower.dest = hook;
bzero(&priv->upper.stats, sizeof(priv->upper.stats));
NG_HOOK_SET_PRIVATE(hook, &priv->upper);
} else
return (EINVAL);
return(0);
}
/*
* Data has arrived.
*/
static int
ng_car_rcvdata(hook_p hook, item_p item )
{
struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook);
struct mbuf *m;
int error = 0;
u_int len;
/* If queue is not empty now then enqueue packet. */
if (hinfo->q_first != hinfo->q_last) {
ng_car_enqueue(hinfo, item);
return (0);
}
m = NGI_M(item);
#define NG_CAR_PERFORM_MATCH_ACTION(a) \
do { \
switch (a) { \
case NG_CAR_ACTION_FORWARD: \
/* Do nothing. */ \
break; \
case NG_CAR_ACTION_MARK: \
/* XXX find a way to mark packets (mbuf tag?) */ \
++hinfo->stats.errors; \
break; \
case NG_CAR_ACTION_DROP: \
default: \
/* Drop packet and return. */ \
NG_FREE_ITEM(item); \
++hinfo->stats.droped_pkts; \
return (0); \
} \
} while (0)
/* Packet is counted as 128 tokens for better resolution */
if (hinfo->conf.opt & NG_CAR_COUNT_PACKETS) {
len = 128;
} else {
len = m->m_pkthdr.len;
}
/* Check committed token bucket. */
if (hinfo->tc - len >= 0) {
/* This packet is green. */
++hinfo->stats.green_pkts;
hinfo->tc -= len;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action);
} else {
/* Refill only if not green without it. */
ng_car_refillhook(hinfo);
/* Check committed token bucket again after refill. */
if (hinfo->tc - len >= 0) {
/* This packet is green */
++hinfo->stats.green_pkts;
hinfo->tc -= len;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action);
/* If not green and mode is SHAPE, enqueue packet. */
} else if (hinfo->conf.mode == NG_CAR_SHAPE) {
ng_car_enqueue(hinfo, item);
return (0);
/* If not green and mode is RED, calculate probability. */
} else if (hinfo->conf.mode == NG_CAR_RED) {
/* Is packet is bigger then extended burst? */
if (len - (hinfo->tc - len) > hinfo->conf.ebs) {
/* This packet is definitely red. */
++hinfo->stats.red_pkts;
hinfo->te = 0;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
/* Use token bucket to simulate RED-like drop
probability. */
} else if (hinfo->te + (len - hinfo->tc) <
hinfo->conf.ebs) {
/* This packet is yellow */
++hinfo->stats.yellow_pkts;
hinfo->te += len - hinfo->tc;
/* Go to negative tokens. */
hinfo->tc -= len;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action);
} else {
/* This packet is probably red. */
++hinfo->stats.red_pkts;
hinfo->te = 0;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
}
/* If not green and mode is SINGLE/DOUBLE RATE. */
} else {
/* Check extended token bucket. */
if (hinfo->te - len >= 0) {
/* This packet is yellow */
++hinfo->stats.yellow_pkts;
hinfo->te -= len;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action);
} else {
/* This packet is red */
++hinfo->stats.red_pkts;
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
}
}
}
#undef NG_CAR_PERFORM_MATCH_ACTION
NG_FWD_ITEM_HOOK(error, item, hinfo->dest);
if (error != 0)
++hinfo->stats.errors;
++hinfo->stats.passed_pkts;
return (error);
}
/*
* Receive a control message.
*/
static int
ng_car_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
const priv_p priv = NG_NODE_PRIVATE(node);
struct ng_mesg *resp = NULL;
int error = 0;
struct ng_mesg *msg;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_CAR_COOKIE:
switch (msg->header.cmd) {
case NGM_CAR_GET_STATS:
case NGM_CAR_GETCLR_STATS:
{
struct ng_car_bulkstats *bstats;
NG_MKRESPONSE(resp, msg,
sizeof(*bstats), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
bstats = (struct ng_car_bulkstats *)resp->data;
bcopy(&priv->upper.stats, &bstats->downstream,
sizeof(bstats->downstream));
bcopy(&priv->lower.stats, &bstats->upstream,
sizeof(bstats->upstream));
}
if (msg->header.cmd == NGM_CAR_GET_STATS)
break;
case NGM_CAR_CLR_STATS:
bzero(&priv->upper.stats,
sizeof(priv->upper.stats));
bzero(&priv->lower.stats,
sizeof(priv->lower.stats));
break;
case NGM_CAR_GET_CONF:
{
struct ng_car_bulkconf *bconf;
NG_MKRESPONSE(resp, msg,
sizeof(*bconf), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
bconf = (struct ng_car_bulkconf *)resp->data;
bcopy(&priv->upper.conf, &bconf->downstream,
sizeof(bconf->downstream));
bcopy(&priv->lower.conf, &bconf->upstream,
sizeof(bconf->upstream));
/* Convert internal 1/(8*128) of pps into pps */
if (bconf->downstream.opt & NG_CAR_COUNT_PACKETS) {
bconf->downstream.cir /= 1024;
bconf->downstream.pir /= 1024;
bconf->downstream.cbs /= 128;
bconf->downstream.ebs /= 128;
}
if (bconf->upstream.opt & NG_CAR_COUNT_PACKETS) {
bconf->upstream.cir /= 1024;
bconf->upstream.pir /= 1024;
bconf->upstream.cbs /= 128;
bconf->upstream.ebs /= 128;
}
}
break;
case NGM_CAR_SET_CONF:
{
struct ng_car_bulkconf *const bconf =
(struct ng_car_bulkconf *)msg->data;
/* Check for invalid or illegal config. */
if (msg->header.arglen != sizeof(*bconf)) {
error = EINVAL;
break;
}
/* Convert pps into internal 1/(8*128) of pps */
if (bconf->downstream.opt & NG_CAR_COUNT_PACKETS) {
bconf->downstream.cir *= 1024;
bconf->downstream.pir *= 1024;
bconf->downstream.cbs *= 125;
bconf->downstream.ebs *= 125;
}
if (bconf->upstream.opt & NG_CAR_COUNT_PACKETS) {
bconf->upstream.cir *= 1024;
bconf->upstream.pir *= 1024;
bconf->upstream.cbs *= 125;
bconf->upstream.ebs *= 125;
}
if ((bconf->downstream.cir > 1000000000) ||
(bconf->downstream.pir > 1000000000) ||
(bconf->upstream.cir > 1000000000) ||
(bconf->upstream.pir > 1000000000) ||
(bconf->downstream.cbs == 0 &&
bconf->downstream.ebs == 0) ||
(bconf->upstream.cbs == 0 &&
bconf->upstream.ebs == 0))
{
error = EINVAL;
break;
}
if ((bconf->upstream.mode == NG_CAR_SHAPE) &&
(bconf->upstream.cir == 0)) {
error = EINVAL;
break;
}
if ((bconf->downstream.mode == NG_CAR_SHAPE) &&
(bconf->downstream.cir == 0)) {
error = EINVAL;
break;
}
/* Copy downstream config. */
bcopy(&bconf->downstream, &priv->upper.conf,
sizeof(priv->upper.conf));
priv->upper.tc = priv->upper.conf.cbs;
if (priv->upper.conf.mode == NG_CAR_RED ||
priv->upper.conf.mode == NG_CAR_SHAPE) {
priv->upper.te = 0;
} else {
priv->upper.te = priv->upper.conf.ebs;
}
/* Copy upstream config. */
bcopy(&bconf->upstream, &priv->lower.conf,
sizeof(priv->lower.conf));
priv->lower.tc = priv->lower.conf.cbs;
if (priv->lower.conf.mode == NG_CAR_RED ||
priv->lower.conf.mode == NG_CAR_SHAPE) {
priv->lower.te = 0;
} else {
priv->lower.te = priv->lower.conf.ebs;
}
}
break;
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Do local shutdown processing.
*/
static int
ng_car_shutdown(node_p node)
{
const priv_p priv = NG_NODE_PRIVATE(node);
ng_uncallout(&priv->upper.q_callout, node);
ng_uncallout(&priv->lower.q_callout, node);
mtx_destroy(&priv->upper.q_mtx);
mtx_destroy(&priv->lower.q_mtx);
NG_NODE_UNREF(priv->node);
free(priv, M_NETGRAPH);
return (0);
}
/*
* Hook disconnection.
*
* For this type, removal of the last link destroys the node.
*/
static int
ng_car_disconnect(hook_p hook)
{
struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook);
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
if (hinfo) {
/* Purge queue if not empty. */
while (hinfo->q_first != hinfo->q_last) {
NG_FREE_M(hinfo->q[hinfo->q_first]);
hinfo->q_first++;
if (hinfo->q_first >= NG_CAR_QUEUE_SIZE)
hinfo->q_first = 0;
}
/* Remove hook refs. */
if (hinfo->hook == priv->upper.hook)
priv->lower.dest = NULL;
else
priv->upper.dest = NULL;
hinfo->hook = NULL;
}
/* Already shutting down? */
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
}
/*
* Hook's token buckets refillment.
*/
static void
ng_car_refillhook(struct hookinfo *h)
{
struct bintime newt, deltat;
unsigned int deltat_us;
/* Get current time. */
getbinuptime(&newt);
/* Get time delta since last refill. */
deltat = newt;
bintime_sub(&deltat, &h->lastRefill);
/* Time must go forward. */
if (deltat.sec < 0) {
h->lastRefill = newt;
return;
}
/* But not too far forward. */
if (deltat.sec >= 1000) {
deltat_us = (1000 << 20);
} else {
/* convert bintime to the 1/(2^20) of sec */
deltat_us = (deltat.sec << 20) + (deltat.frac >> 44);
}
if (h->conf.mode == NG_CAR_SINGLE_RATE) {
int64_t delta;
/* Refill committed token bucket. */
h->tc += (h->conf.cir * deltat_us) >> 23;
delta = h->tc - h->conf.cbs;
if (delta > 0) {
h->tc = h->conf.cbs;
/* Refill exceeded token bucket. */
h->te += delta;
if (h->te > ((int64_t)h->conf.ebs))
h->te = h->conf.ebs;
}
} else if (h->conf.mode == NG_CAR_DOUBLE_RATE) {
/* Refill committed token bucket. */
h->tc += (h->conf.cir * deltat_us) >> 23;
if (h->tc > ((int64_t)h->conf.cbs))
h->tc = h->conf.cbs;
/* Refill peak token bucket. */
h->te += (h->conf.pir * deltat_us) >> 23;
if (h->te > ((int64_t)h->conf.ebs))
h->te = h->conf.ebs;
} else { /* RED or SHAPE mode. */
/* Refill committed token bucket. */
h->tc += (h->conf.cir * deltat_us) >> 23;
if (h->tc > ((int64_t)h->conf.cbs))
h->tc = h->conf.cbs;
}
/* Remember this moment. */
h->lastRefill = newt;
}
/*
* Schedule callout when we will have required tokens.
*/
static void
ng_car_schedule(struct hookinfo *hinfo)
{
int delay;
delay = (-(hinfo->tc)) * hz * 8 / hinfo->conf.cir + 1;
ng_callout(&hinfo->q_callout, NG_HOOK_NODE(hinfo->hook), hinfo->hook,
delay, &ng_car_q_event, NULL, 0);
}
/*
* Queue processing callout handler.
*/
void
ng_car_q_event(node_p node, hook_p hook, void *arg, int arg2)
{
struct hookinfo *hinfo = NG_HOOK_PRIVATE(hook);
struct mbuf *m;
int error;
/* Refill tokens for time we have slept. */
ng_car_refillhook(hinfo);
/* If we have some tokens */
while (hinfo->tc >= 0) {
/* Send packet. */
m = hinfo->q[hinfo->q_first];
NG_SEND_DATA_ONLY(error, hinfo->dest, m);
if (error != 0)
++hinfo->stats.errors;
++hinfo->stats.passed_pkts;
/* Get next one. */
hinfo->q_first++;
if (hinfo->q_first >= NG_CAR_QUEUE_SIZE)
hinfo->q_first = 0;
/* Stop if none left. */
if (hinfo->q_first == hinfo->q_last)
break;
/* If we have more packet, try it. */
m = hinfo->q[hinfo->q_first];
if (hinfo->conf.opt & NG_CAR_COUNT_PACKETS) {
hinfo->tc -= 128;
} else {
hinfo->tc -= m->m_pkthdr.len;
}
}
/* If something left */
if (hinfo->q_first != hinfo->q_last)
/* Schedule queue processing. */
ng_car_schedule(hinfo);
}
/*
* Enqueue packet.
*/
static void
ng_car_enqueue(struct hookinfo *hinfo, item_p item)
{
struct mbuf *m;
int len;
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
/* Lock queue mutex. */
mtx_lock(&hinfo->q_mtx);
/* Calculate used queue length. */
len = hinfo->q_last - hinfo->q_first;
if (len < 0)
len += NG_CAR_QUEUE_SIZE;
/* If queue is overflowed or we have no RED tokens. */
if ((len >= (NG_CAR_QUEUE_SIZE - 1)) ||
(hinfo->te + len >= NG_CAR_QUEUE_SIZE)) {
/* Drop packet. */
++hinfo->stats.red_pkts;
++hinfo->stats.droped_pkts;
NG_FREE_M(m);
hinfo->te = 0;
} else {
/* This packet is yellow. */
++hinfo->stats.yellow_pkts;
/* Enqueue packet. */
hinfo->q[hinfo->q_last] = m;
hinfo->q_last++;
if (hinfo->q_last >= NG_CAR_QUEUE_SIZE)
hinfo->q_last = 0;
/* Use RED tokens. */
if (len > NG_CAR_QUEUE_MIN_TH)
hinfo->te += len - NG_CAR_QUEUE_MIN_TH;
/* If this is a first packet in the queue. */
if (len == 0) {
if (hinfo->conf.opt & NG_CAR_COUNT_PACKETS) {
hinfo->tc -= 128;
} else {
hinfo->tc -= m->m_pkthdr.len;
}
/* Schedule queue processing. */
ng_car_schedule(hinfo);
}
}
/* Unlock queue mutex. */
mtx_unlock(&hinfo->q_mtx);
}

140
freebsd/netgraph/ng_car.h Normal file
View File

@ -0,0 +1,140 @@
/*-
* Copyright (c) 2005 Nuno Antunes <nuno.antunes@gmail.com>
* Copyright (c) 2007 Alexander Motin <mav@freebsd.org>
* 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 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 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$
*/
#ifndef _NETGRAPH_NG_CAR_H_
#define _NETGRAPH_NG_CAR_H_
#define NG_CAR_NODE_TYPE "car"
#define NGM_CAR_COOKIE 1173648034
/* Hook names */
#define NG_CAR_HOOK_UPPER "upper"
#define NG_CAR_HOOK_LOWER "lower"
/* Per hook statistics counters */
struct ng_car_hookstats {
u_int64_t passed_pkts; /* Counter for passed packets */
u_int64_t droped_pkts; /* Counter for droped packets */
u_int64_t green_pkts; /* Counter for green packets */
u_int64_t yellow_pkts; /* Counter for yellow packets */
u_int64_t red_pkts; /* Counter for red packets */
u_int64_t errors; /* Counter for operation errors */
};
#define NG_CAR_HOOKSTATS { \
{ "passed", &ng_parse_uint64_type }, \
{ "droped", &ng_parse_uint64_type }, \
{ "green", &ng_parse_uint64_type }, \
{ "yellow", &ng_parse_uint64_type }, \
{ "red", &ng_parse_uint64_type }, \
{ "errors", &ng_parse_uint64_type }, \
{ NULL } \
}
/* Bulk statistics */
struct ng_car_bulkstats {
struct ng_car_hookstats upstream;
struct ng_car_hookstats downstream;
};
#define NG_CAR_BULKSTATS(hstatstype) { \
{ "upstream", (hstatstype) }, \
{ "downstream", (hstatstype) }, \
{ NULL } \
}
/* Per hook configuration */
struct ng_car_hookconf {
u_int64_t cbs; /* Committed burst size (bytes) */
u_int64_t ebs; /* Exceeded/Peak burst size (bytes) */
u_int64_t cir; /* Committed information rate (bits/s) */
u_int64_t pir; /* Peak information rate (bits/s) */
u_int8_t green_action; /* Action for green packets */
u_int8_t yellow_action; /* Action for yellow packets */
u_int8_t red_action; /* Action for red packets */
u_int8_t mode; /* single/double rate, ... */
u_int8_t opt; /* color-aware or color-blind */
};
/* Keep this definition in sync with the above structure */
#define NG_CAR_HOOKCONF { \
{ "cbs", &ng_parse_uint64_type }, \
{ "ebs", &ng_parse_uint64_type }, \
{ "cir", &ng_parse_uint64_type }, \
{ "pir", &ng_parse_uint64_type }, \
{ "greenAction", &ng_parse_uint8_type }, \
{ "yellowAction", &ng_parse_uint8_type }, \
{ "redAction", &ng_parse_uint8_type }, \
{ "mode", &ng_parse_uint8_type }, \
{ "opt", &ng_parse_uint8_type }, \
{ NULL } \
}
#define NG_CAR_CBS_MIN 8192
#define NG_CAR_EBS_MIN 8192
#define NG_CAR_CIR_DFLT 10240
/* possible actions (...Action) */
enum {
NG_CAR_ACTION_FORWARD = 1,
NG_CAR_ACTION_DROP,
NG_CAR_ACTION_MARK,
NG_CAR_ACTION_SET_TOS
};
/* operation modes (mode) */
enum {
NG_CAR_SINGLE_RATE = 0,
NG_CAR_DOUBLE_RATE,
NG_CAR_RED,
NG_CAR_SHAPE
};
/* mode options (opt) */
#define NG_CAR_COLOR_AWARE 1
#define NG_CAR_COUNT_PACKETS 2
/* Bulk config */
struct ng_car_bulkconf {
struct ng_car_hookconf upstream;
struct ng_car_hookconf downstream;
};
#define NG_CAR_BULKCONF(hconftype) { \
{ "upstream", (hconftype) }, \
{ "downstream", (hconftype) }, \
{ NULL } \
}
/* Commands */
enum {
NGM_CAR_GET_STATS = 1, /* Get statistics */
NGM_CAR_CLR_STATS, /* Clear statistics */
NGM_CAR_GETCLR_STATS, /* Get and clear statistics */
NGM_CAR_GET_CONF, /* Get bulk configuration */
NGM_CAR_SET_CONF, /* Set bulk configuration */
};
#endif /* _NETGRAPH_NG_CAR_H_ */

646
freebsd/netgraph/ng_cisco.c Normal file
View File

@ -0,0 +1,646 @@
/*
* ng_cisco.c
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Julian Elischer <julian@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_cisco.c,v 1.25 1999/11/01 09:24:51 julian Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/ng_cisco.h>
#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
#define CISCO_UNICAST 0x0f /* Cisco unicast address */
#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
#define CISCO_ADDR_REQ 0 /* Cisco address request */
#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
#define KEEPALIVE_SECS 10
struct cisco_header {
uint8_t address;
uint8_t control;
uint16_t protocol;
} __packed;
#define CISCO_HEADER_LEN sizeof (struct cisco_header)
struct cisco_packet {
uint32_t type;
uint32_t par1;
uint32_t par2;
uint16_t rel;
uint16_t time0;
uint16_t time1;
} __packed;
#define CISCO_PACKET_LEN (sizeof(struct cisco_packet))
struct protoent {
hook_p hook; /* the hook for this proto */
uint16_t af; /* address family, -1 = downstream */
};
struct cisco_priv {
uint32_t local_seq;
uint32_t remote_seq;
uint32_t seqRetries; /* how many times we've been here throwing out
* the same sequence number without ack */
node_p node;
struct callout handle;
struct protoent downstream;
struct protoent inet; /* IP information */
struct in_addr localip;
struct in_addr localmask;
struct protoent inet6; /* IPv6 information */
struct protoent atalk; /* AppleTalk information */
struct protoent ipx; /* IPX information */
};
typedef struct cisco_priv *sc_p;
/* Netgraph methods */
static ng_constructor_t cisco_constructor;
static ng_rcvmsg_t cisco_rcvmsg;
static ng_shutdown_t cisco_shutdown;
static ng_newhook_t cisco_newhook;
static ng_rcvdata_t cisco_rcvdata;
static ng_disconnect_t cisco_disconnect;
/* Other functions */
static int cisco_input(sc_p sc, item_p item);
static void cisco_keepalive(node_p node, hook_p hook, void *arg1, int arg2);
static int cisco_send(sc_p sc, int type, long par1, long par2);
static void cisco_notify(sc_p sc, uint32_t cmd);
/* Parse type for struct ng_cisco_ipaddr */
static const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
= NG_CISCO_IPADDR_TYPE_INFO;
static const struct ng_parse_type ng_cisco_ipaddr_type = {
&ng_parse_struct_type,
&ng_cisco_ipaddr_type_fields
};
/* Parse type for struct ng_async_stat */
static const struct ng_parse_struct_field ng_cisco_stats_type_fields[]
= NG_CISCO_STATS_TYPE_INFO;
static const struct ng_parse_type ng_cisco_stats_type = {
&ng_parse_struct_type,
&ng_cisco_stats_type_fields
};
/* List of commands and how to convert arguments to/from ASCII */
static const struct ng_cmdlist ng_cisco_cmdlist[] = {
{
NGM_CISCO_COOKIE,
NGM_CISCO_SET_IPADDR,
"setipaddr",
&ng_cisco_ipaddr_type,
NULL
},
{
NGM_CISCO_COOKIE,
NGM_CISCO_GET_IPADDR,
"getipaddr",
NULL,
&ng_cisco_ipaddr_type
},
{
NGM_CISCO_COOKIE,
NGM_CISCO_GET_STATUS,
"getstats",
NULL,
&ng_cisco_stats_type
},
{ 0 }
};
/* Node type */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_CISCO_NODE_TYPE,
.constructor = cisco_constructor,
.rcvmsg = cisco_rcvmsg,
.shutdown = cisco_shutdown,
.newhook = cisco_newhook,
.rcvdata = cisco_rcvdata,
.disconnect = cisco_disconnect,
.cmdlist = ng_cisco_cmdlist,
};
NETGRAPH_INIT(cisco, &typestruct);
/*
* Node constructor
*/
static int
cisco_constructor(node_p node)
{
sc_p sc;
sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO);
ng_callout_init(&sc->handle);
NG_NODE_SET_PRIVATE(node, sc);
sc->node = node;
/* Initialise the varous protocol hook holders */
sc->downstream.af = 0xffff;
sc->inet.af = AF_INET;
sc->inet6.af = AF_INET6;
sc->atalk.af = AF_APPLETALK;
sc->ipx.af = AF_IPX;
return (0);
}
/*
* Check new hook
*/
static int
cisco_newhook(node_p node, hook_p hook, const char *name)
{
const sc_p sc = NG_NODE_PRIVATE(node);
if (strcmp(name, NG_CISCO_HOOK_DOWNSTREAM) == 0) {
sc->downstream.hook = hook;
NG_HOOK_SET_PRIVATE(hook, &sc->downstream);
/* Start keepalives */
ng_callout(&sc->handle, node, NULL, (hz * KEEPALIVE_SECS),
&cisco_keepalive, (void *)sc, 0);
} else if (strcmp(name, NG_CISCO_HOOK_INET) == 0) {
sc->inet.hook = hook;
NG_HOOK_SET_PRIVATE(hook, &sc->inet);
} else if (strcmp(name, NG_CISCO_HOOK_INET6) == 0) {
sc->inet6.hook = hook;
NG_HOOK_SET_PRIVATE(hook, &sc->inet6);
} else if (strcmp(name, NG_CISCO_HOOK_APPLETALK) == 0) {
sc->atalk.hook = hook;
NG_HOOK_SET_PRIVATE(hook, &sc->atalk);
} else if (strcmp(name, NG_CISCO_HOOK_IPX) == 0) {
sc->ipx.hook = hook;
NG_HOOK_SET_PRIVATE(hook, &sc->ipx);
} else if (strcmp(name, NG_CISCO_HOOK_DEBUG) == 0) {
NG_HOOK_SET_PRIVATE(hook, NULL); /* unimplemented */
} else
return (EINVAL);
return 0;
}
/*
* Receive control message.
*/
static int
cisco_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct ng_mesg *msg;
const sc_p sc = NG_NODE_PRIVATE(node);
struct ng_mesg *resp = NULL;
int error = 0;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_GENERIC_COOKIE:
switch (msg->header.cmd) {
case NGM_TEXT_STATUS:
{
char *arg;
int pos;
NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
arg = (char *) resp->data;
pos = sprintf(arg,
"keepalive period: %d sec; ", KEEPALIVE_SECS);
pos += sprintf(arg + pos,
"unacknowledged keepalives: %d", sc->seqRetries);
resp->header.arglen = pos + 1;
break;
}
default:
error = EINVAL;
break;
}
break;
case NGM_CISCO_COOKIE:
switch (msg->header.cmd) {
case NGM_CISCO_GET_IPADDR: /* could be a late reply! */
if ((msg->header.flags & NGF_RESP) == 0) {
struct in_addr *ips;
NG_MKRESPONSE(resp, msg,
2 * sizeof(*ips), M_NOWAIT);
if (!resp) {
error = ENOMEM;
break;
}
ips = (struct in_addr *) resp->data;
ips[0] = sc->localip;
ips[1] = sc->localmask;
break;
}
/* FALLTHROUGH */ /* ...if it's a reply */
case NGM_CISCO_SET_IPADDR:
{
struct in_addr *const ips = (struct in_addr *)msg->data;
if (msg->header.arglen < 2 * sizeof(*ips)) {
error = EINVAL;
break;
}
sc->localip = ips[0];
sc->localmask = ips[1];
break;
}
case NGM_CISCO_GET_STATUS:
{
struct ng_cisco_stats *stat;
NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT);
if (!resp) {
error = ENOMEM;
break;
}
stat = (struct ng_cisco_stats *)resp->data;
stat->seqRetries = sc->seqRetries;
stat->keepAlivePeriod = KEEPALIVE_SECS;
break;
}
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Receive data
*/
static int
cisco_rcvdata(hook_p hook, item_p item)
{
const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct protoent *pep;
struct cisco_header *h;
struct mbuf *m;
int error = 0;
if ((pep = NG_HOOK_PRIVATE(hook)) == NULL)
goto out;
/* If it came from our downlink, deal with it separately */
if (pep->af == 0xffff)
return (cisco_input(sc, item));
/* OK so it came from a protocol, heading out. Prepend general data
packet header. For now, IP,IPX only */
NGI_GET_M(item, m);
M_PREPEND(m, CISCO_HEADER_LEN, M_NOWAIT);
if (!m) {
error = ENOBUFS;
goto out;
}
NGI_M(item) = m;
h = mtod(m, struct cisco_header *);
h->address = CISCO_UNICAST;
h->control = 0;
switch (pep->af) {
case AF_INET: /* Internet Protocol */
h->protocol = htons(ETHERTYPE_IP);
break;
case AF_INET6:
h->protocol = htons(ETHERTYPE_IPV6);
break;
case AF_APPLETALK: /* AppleTalk Protocol */
h->protocol = htons(ETHERTYPE_AT);
break;
case AF_IPX: /* Novell IPX Protocol */
h->protocol = htons(ETHERTYPE_IPX);
break;
default:
error = EAFNOSUPPORT;
goto out;
}
/* Send it */
NG_FWD_NEW_DATA(error, item, sc->downstream.hook, m);
return (error);
out:
NG_FREE_ITEM(item);
return (error);
}
/*
* Shutdown node
*/
static int
cisco_shutdown(node_p node)
{
const sc_p sc = NG_NODE_PRIVATE(node);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(sc->node);
free(sc, M_NETGRAPH);
return (0);
}
/*
* Disconnection of a hook
*
* For this type, removal of the last link destroys the node
*/
static int
cisco_disconnect(hook_p hook)
{
const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct protoent *pep;
/* Check it's not the debug hook */
if ((pep = NG_HOOK_PRIVATE(hook))) {
pep->hook = NULL;
if (pep->af == 0xffff)
/* If it is the downstream hook, stop the timers */
ng_uncallout(&sc->handle, NG_HOOK_NODE(hook));
}
/* If no more hooks, remove the node */
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
}
/*
* Receive data
*/
static int
cisco_input(sc_p sc, item_p item)
{
const struct cisco_header *h;
struct cisco_header hdrbuf;
struct protoent *pep;
struct mbuf *m;
int error = 0;
/* Get data */
m = NGI_M(item);
/* Sanity check header length */
if (m->m_pkthdr.len < sizeof(*h)) {
error = EINVAL;
goto drop;
}
/* Get cisco header */
if (m->m_len >= sizeof(*h)) /* the common case */
h = mtod(m, const struct cisco_header *);
else {
m_copydata(m, 0, sizeof(*h), (caddr_t)&hdrbuf);
h = &hdrbuf;
}
m_adj(m, sizeof(*h));
/* Check header address */
switch (h->address) {
default: /* Invalid Cisco packet. */
goto drop;
case CISCO_UNICAST:
case CISCO_MULTICAST:
/* Don't check the control field here (RFC 1547). */
switch (ntohs(h->protocol)) {
default:
goto drop;
case CISCO_KEEPALIVE:
{
const struct cisco_packet *p;
struct cisco_packet pktbuf;
/* Sanity check packet length */
if (m->m_pkthdr.len < sizeof(*p)) {
error = EINVAL;
goto drop;
}
/* Get cisco packet */
if (m->m_len >= sizeof(*p)) /* the common case */
p = mtod(m, const struct cisco_packet *);
else {
m_copydata(m, 0, sizeof(*p), (caddr_t)&pktbuf);
p = &pktbuf;
}
/* Check packet type */
switch (ntohl(p->type)) {
default:
log(LOG_WARNING,
"cisco: unknown cisco packet type: 0x%lx\n",
(long)ntohl(p->type));
break;
case CISCO_ADDR_REPLY:
/* Reply on address request, ignore */
break;
case CISCO_KEEPALIVE_REQ:
sc->remote_seq = ntohl(p->par1);
if (sc->local_seq == ntohl(p->par2)) {
sc->local_seq++;
if (sc->seqRetries > 1)
cisco_notify(sc, NGM_LINK_IS_UP);
sc->seqRetries = 0;
}
break;
case CISCO_ADDR_REQ:
{
struct ng_mesg *msg;
int dummy_error = 0;
/* Ask inet peer for IP address information */
if (sc->inet.hook == NULL)
goto nomsg;
NG_MKMESSAGE(msg, NGM_CISCO_COOKIE,
NGM_CISCO_GET_IPADDR, 0, M_NOWAIT);
if (msg == NULL)
goto nomsg;
NG_SEND_MSG_HOOK(dummy_error,
sc->node, msg, sc->inet.hook, 0);
/*
* XXX Now maybe we should set a flag telling
* our receiver to send this message when the response comes in
* instead of now when the data may be bad.
*/
nomsg:
/* Send reply to peer device */
error = cisco_send(sc, CISCO_ADDR_REPLY,
ntohl(sc->localip.s_addr),
ntohl(sc->localmask.s_addr));
break;
}
}
goto drop;
}
case ETHERTYPE_IP:
pep = &sc->inet;
break;
case ETHERTYPE_IPV6:
pep = &sc->inet6;
break;
case ETHERTYPE_AT:
pep = &sc->atalk;
break;
case ETHERTYPE_IPX:
pep = &sc->ipx;
break;
}
break;
}
/* Drop if payload is empty */
if (m->m_pkthdr.len == 0) {
error = EINVAL;
goto drop;
}
/* Send it on */
if (pep->hook == NULL)
goto drop;
NG_FWD_NEW_DATA(error, item, pep->hook, m);
return (error);
drop:
NG_FREE_ITEM(item);
return (error);
}
/*
* Send keepalive packets, every 10 seconds.
*/
static void
cisco_keepalive(node_p node, hook_p hook, void *arg1, int arg2)
{
const sc_p sc = arg1;
cisco_send(sc, CISCO_KEEPALIVE_REQ, sc->local_seq, sc->remote_seq);
if (sc->seqRetries++ > 1)
cisco_notify(sc, NGM_LINK_IS_DOWN);
ng_callout(&sc->handle, node, NULL, (hz * KEEPALIVE_SECS),
&cisco_keepalive, (void *)sc, 0);
}
/*
* Send Cisco keepalive packet.
*/
static int
cisco_send(sc_p sc, int type, long par1, long par2)
{
struct cisco_header *h;
struct cisco_packet *ch;
struct mbuf *m;
struct timeval time;
uint32_t t;
int error = 0;
getmicrouptime(&time);
MGETHDR(m, M_NOWAIT, MT_DATA);
if (!m)
return (ENOBUFS);
t = time.tv_sec * 1000 + time.tv_usec / 1000;
m->m_pkthdr.len = m->m_len = CISCO_HEADER_LEN + CISCO_PACKET_LEN;
m->m_pkthdr.rcvif = 0;
h = mtod(m, struct cisco_header *);
h->address = CISCO_MULTICAST;
h->control = 0;
h->protocol = htons(CISCO_KEEPALIVE);
ch = (struct cisco_packet *) (h + 1);
ch->type = htonl(type);
ch->par1 = htonl(par1);
ch->par2 = htonl(par2);
ch->rel = -1;
ch->time0 = htons((uint16_t) (t >> 16));
ch->time1 = htons((uint16_t) t);
NG_SEND_DATA_ONLY(error, sc->downstream.hook, m);
return (error);
}
/*
* Send linkstate to upstream node.
*/
static void
cisco_notify(sc_p sc, uint32_t cmd)
{
struct ng_mesg *msg;
int dummy_error = 0;
if (sc->inet.hook == NULL) /* nothing to notify */
return;
NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT);
if (msg != NULL)
NG_SEND_MSG_HOOK(dummy_error, sc->node, msg, sc->inet.hook, 0);
}

View File

@ -0,0 +1,91 @@
/*
* ng_cisco.h
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_cisco.h,v 1.6 1999/01/25 01:21:48 archie Exp $
*/
#ifndef _NETGRAPH_NG_CISCO_H_
#define _NETGRAPH_NG_CISCO_H_
/* Node type name and magic cookie */
#define NG_CISCO_NODE_TYPE "cisco"
#define NGM_CISCO_COOKIE 860707227
/* Hook names */
#define NG_CISCO_HOOK_DOWNSTREAM "downstream"
#define NG_CISCO_HOOK_INET "inet"
#define NG_CISCO_HOOK_INET6 "inet6"
#define NG_CISCO_HOOK_APPLETALK "atalk"
#define NG_CISCO_HOOK_IPX "ipx"
#define NG_CISCO_HOOK_DEBUG "debug"
/* Netgraph commands */
enum {
NGM_CISCO_SET_IPADDR = 1, /* requires a struct ng_cisco_ipaddr */
NGM_CISCO_GET_IPADDR, /* returns a struct ng_cisco_ipaddr */
NGM_CISCO_GET_STATUS, /* returns a struct ng_cisco_stat */
};
struct ng_cisco_ipaddr {
struct in_addr ipaddr; /* IP address */
struct in_addr netmask; /* Netmask */
};
/* Keep this in sync with the above structure definition */
#define NG_CISCO_IPADDR_TYPE_INFO { \
{ "ipaddr", &ng_parse_ipaddr_type }, \
{ "netmask", &ng_parse_ipaddr_type }, \
{ NULL } \
}
struct ng_cisco_stats {
uint32_t seqRetries; /* # unack'd retries */
uint32_t keepAlivePeriod; /* in seconds */
};
/* Keep this in sync with the above structure definition */
#define NG_CISCO_STATS_TYPE_INFO { \
{ "seqRetries", &ng_parse_uint32_type }, \
{ "keepAlivePeriod", &ng_parse_uint32_type }, \
{ NULL } \
}
#endif /* _NETGRAPH_NG_CISCO_H_ */

View File

@ -0,0 +1,698 @@
/*-
* Copyright (c) 2006 Alexander Motin <mav@alkar.net>
* 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 unmodified, 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$
*/
/*
* Deflate PPP compression netgraph node type.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/zlib.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/ng_deflate.h>
#include "opt_netgraph.h"
static MALLOC_DEFINE(M_NETGRAPH_DEFLATE, "netgraph_deflate",
"netgraph deflate node");
/* DEFLATE header length */
#define DEFLATE_HDRLEN 2
#define PROT_COMPD 0x00fd
#define DEFLATE_BUF_SIZE 4096
/* Node private data */
struct ng_deflate_private {
struct ng_deflate_config cfg; /* configuration */
u_char inbuf[DEFLATE_BUF_SIZE]; /* input buffer */
u_char outbuf[DEFLATE_BUF_SIZE]; /* output buffer */
z_stream cx; /* compression context */
struct ng_deflate_stats stats; /* statistics */
ng_ID_t ctrlnode; /* path to controlling node */
uint16_t seqnum; /* sequence number */
u_char compress; /* compress/decompress flag */
};
typedef struct ng_deflate_private *priv_p;
/* Netgraph node methods */
static ng_constructor_t ng_deflate_constructor;
static ng_rcvmsg_t ng_deflate_rcvmsg;
static ng_shutdown_t ng_deflate_shutdown;
static ng_newhook_t ng_deflate_newhook;
static ng_rcvdata_t ng_deflate_rcvdata;
static ng_disconnect_t ng_deflate_disconnect;
/* Helper functions */
static void *z_alloc(void *, u_int items, u_int size);
static void z_free(void *, void *ptr);
static int ng_deflate_compress(node_p node,
struct mbuf *m, struct mbuf **resultp);
static int ng_deflate_decompress(node_p node,
struct mbuf *m, struct mbuf **resultp);
static void ng_deflate_reset_req(node_p node);
/* Parse type for struct ng_deflate_config. */
static const struct ng_parse_struct_field ng_deflate_config_type_fields[]
= NG_DEFLATE_CONFIG_INFO;
static const struct ng_parse_type ng_deflate_config_type = {
&ng_parse_struct_type,
ng_deflate_config_type_fields
};
/* Parse type for struct ng_deflate_stat. */
static const struct ng_parse_struct_field ng_deflate_stats_type_fields[]
= NG_DEFLATE_STATS_INFO;
static const struct ng_parse_type ng_deflate_stat_type = {
&ng_parse_struct_type,
ng_deflate_stats_type_fields
};
/* List of commands and how to convert arguments to/from ASCII. */
static const struct ng_cmdlist ng_deflate_cmds[] = {
{
NGM_DEFLATE_COOKIE,
NGM_DEFLATE_CONFIG,
"config",
&ng_deflate_config_type,
NULL
},
{
NGM_DEFLATE_COOKIE,
NGM_DEFLATE_RESETREQ,
"resetreq",
NULL,
NULL
},
{
NGM_DEFLATE_COOKIE,
NGM_DEFLATE_GET_STATS,
"getstats",
NULL,
&ng_deflate_stat_type
},
{
NGM_DEFLATE_COOKIE,
NGM_DEFLATE_CLR_STATS,
"clrstats",
NULL,
NULL
},
{
NGM_DEFLATE_COOKIE,
NGM_DEFLATE_GETCLR_STATS,
"getclrstats",
NULL,
&ng_deflate_stat_type
},
{ 0 }
};
/* Node type descriptor */
static struct ng_type ng_deflate_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_DEFLATE_NODE_TYPE,
.constructor = ng_deflate_constructor,
.rcvmsg = ng_deflate_rcvmsg,
.shutdown = ng_deflate_shutdown,
.newhook = ng_deflate_newhook,
.rcvdata = ng_deflate_rcvdata,
.disconnect = ng_deflate_disconnect,
.cmdlist = ng_deflate_cmds,
};
NETGRAPH_INIT(deflate, &ng_deflate_typestruct);
/* Depend on separate zlib module. */
MODULE_DEPEND(ng_deflate, zlib, 1, 1, 1);
#define ERROUT(x) do { error = (x); goto done; } while (0)
/************************************************************************
NETGRAPH NODE STUFF
************************************************************************/
/*
* Node type constructor
*/
static int
ng_deflate_constructor(node_p node)
{
priv_p priv;
/* Allocate private structure. */
priv = malloc(sizeof(*priv), M_NETGRAPH_DEFLATE, M_WAITOK | M_ZERO);
NG_NODE_SET_PRIVATE(node, priv);
/* This node is not thread safe. */
NG_NODE_FORCE_WRITER(node);
/* Done */
return (0);
}
/*
* Give our OK for a hook to be added.
*/
static int
ng_deflate_newhook(node_p node, hook_p hook, const char *name)
{
const priv_p priv = NG_NODE_PRIVATE(node);
if (NG_NODE_NUMHOOKS(node) > 0)
return (EINVAL);
if (strcmp(name, NG_DEFLATE_HOOK_COMP) == 0)
priv->compress = 1;
else if (strcmp(name, NG_DEFLATE_HOOK_DECOMP) == 0)
priv->compress = 0;
else
return (EINVAL);
return (0);
}
/*
* Receive a control message
*/
static int
ng_deflate_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
const priv_p priv = NG_NODE_PRIVATE(node);
struct ng_mesg *resp = NULL;
int error = 0;
struct ng_mesg *msg;
NGI_GET_MSG(item, msg);
if (msg->header.typecookie != NGM_DEFLATE_COOKIE)
ERROUT(EINVAL);
switch (msg->header.cmd) {
case NGM_DEFLATE_CONFIG:
{
struct ng_deflate_config *const cfg
= (struct ng_deflate_config *)msg->data;
/* Check configuration. */
if (msg->header.arglen != sizeof(*cfg))
ERROUT(EINVAL);
if (cfg->enable) {
if (cfg->windowBits < 8 || cfg->windowBits > 15)
ERROUT(EINVAL);
} else
cfg->windowBits = 0;
/* Clear previous state. */
if (priv->cfg.enable) {
if (priv->compress)
deflateEnd(&priv->cx);
else
inflateEnd(&priv->cx);
priv->cfg.enable = 0;
}
/* Configuration is OK, reset to it. */
priv->cfg = *cfg;
if (priv->cfg.enable) {
priv->cx.next_in = NULL;
priv->cx.zalloc = z_alloc;
priv->cx.zfree = z_free;
int res;
if (priv->compress) {
if ((res = deflateInit2(&priv->cx,
Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-cfg->windowBits, 8,
Z_DEFAULT_STRATEGY)) != Z_OK) {
log(LOG_NOTICE,
"deflateInit2: error %d, %s\n",
res, priv->cx.msg);
priv->cfg.enable = 0;
ERROUT(ENOMEM);
}
} else {
if ((res = inflateInit2(&priv->cx,
-cfg->windowBits)) != Z_OK) {
log(LOG_NOTICE,
"inflateInit2: error %d, %s\n",
res, priv->cx.msg);
priv->cfg.enable = 0;
ERROUT(ENOMEM);
}
}
}
/* Initialize other state. */
priv->seqnum = 0;
/* Save return address so we can send reset-req's */
priv->ctrlnode = NGI_RETADDR(item);
break;
}
case NGM_DEFLATE_RESETREQ:
ng_deflate_reset_req(node);
break;
case NGM_DEFLATE_GET_STATS:
case NGM_DEFLATE_CLR_STATS:
case NGM_DEFLATE_GETCLR_STATS:
/* Create response if requested. */
if (msg->header.cmd != NGM_DEFLATE_CLR_STATS) {
NG_MKRESPONSE(resp, msg,
sizeof(struct ng_deflate_stats), M_NOWAIT);
if (resp == NULL)
ERROUT(ENOMEM);
bcopy(&priv->stats, resp->data,
sizeof(struct ng_deflate_stats));
}
/* Clear stats if requested. */
if (msg->header.cmd != NGM_DEFLATE_GET_STATS)
bzero(&priv->stats,
sizeof(struct ng_deflate_stats));
break;
default:
error = EINVAL;
break;
}
done:
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Receive incoming data on our hook.
*/
static int
ng_deflate_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
struct mbuf *m, *out;
int error;
if (!priv->cfg.enable) {
NG_FREE_ITEM(item);
return (ENXIO);
}
NGI_GET_M(item, m);
/* Compress */
if (priv->compress) {
if ((error = ng_deflate_compress(node, m, &out)) != 0) {
NG_FREE_ITEM(item);
log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
return (error);
}
} else { /* Decompress */
if ((error = ng_deflate_decompress(node, m, &out)) != 0) {
NG_FREE_ITEM(item);
log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
if (priv->ctrlnode != 0) {
struct ng_mesg *msg;
/* Need to send a reset-request. */
NG_MKMESSAGE(msg, NGM_DEFLATE_COOKIE,
NGM_DEFLATE_RESETREQ, 0, M_NOWAIT);
if (msg == NULL)
return (error);
NG_SEND_MSG_ID(error, node, msg,
priv->ctrlnode, 0);
}
return (error);
}
}
NG_FWD_NEW_DATA(error, item, hook, out);
return (error);
}
/*
* Destroy node.
*/
static int
ng_deflate_shutdown(node_p node)
{
const priv_p priv = NG_NODE_PRIVATE(node);
/* Take down netgraph node. */
if (priv->cfg.enable) {
if (priv->compress)
deflateEnd(&priv->cx);
else
inflateEnd(&priv->cx);
}
free(priv, M_NETGRAPH_DEFLATE);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node); /* let the node escape */
return (0);
}
/*
* Hook disconnection
*/
static int
ng_deflate_disconnect(hook_p hook)
{
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
if (priv->cfg.enable) {
if (priv->compress)
deflateEnd(&priv->cx);
else
inflateEnd(&priv->cx);
priv->cfg.enable = 0;
}
/* Go away if no longer connected. */
if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node))
ng_rmnode_self(node);
return (0);
}
/************************************************************************
HELPER STUFF
************************************************************************/
/*
* Space allocation and freeing routines for use by zlib routines.
*/
static void *
z_alloc(void *notused, u_int items, u_int size)
{
return (malloc(items * size, M_NETGRAPH_DEFLATE, M_NOWAIT));
}
static void
z_free(void *notused, void *ptr)
{
free(ptr, M_NETGRAPH_DEFLATE);
}
/*
* Compress/encrypt a packet and put the result in a new mbuf at *resultp.
* The original mbuf is not free'd.
*/
static int
ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp)
{
const priv_p priv = NG_NODE_PRIVATE(node);
int outlen, inlen;
int rtn;
/* Initialize. */
*resultp = NULL;
inlen = m->m_pkthdr.len;
priv->stats.FramesPlain++;
priv->stats.InOctets+=inlen;
if (inlen > DEFLATE_BUF_SIZE) {
priv->stats.Errors++;
NG_FREE_M(m);
return (ENOMEM);
}
/* We must own the mbuf chain exclusively to modify it. */
m = m_unshare(m, M_NOWAIT);
if (m == NULL) {
priv->stats.Errors++;
return (ENOMEM);
}
/* Work with contiguous regions of memory. */
m_copydata(m, 0, inlen, (caddr_t)priv->inbuf);
outlen = DEFLATE_BUF_SIZE;
/* Compress "inbuf" into "outbuf". */
/* Prepare to compress. */
if (priv->inbuf[0] != 0) {
priv->cx.next_in = priv->inbuf;
priv->cx.avail_in = inlen;
} else {
priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
priv->cx.avail_in = inlen - 1;
}
priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN;
priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN;
/* Compress. */
rtn = deflate(&priv->cx, Z_PACKET_FLUSH);
/* Check return value. */
if (rtn != Z_OK) {
priv->stats.Errors++;
log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n",
rtn, priv->cx.msg);
NG_FREE_M(m);
return (EINVAL);
}
/* Calculate resulting size. */
outlen -= priv->cx.avail_out;
/* If we can't compress this packet, send it as-is. */
if (outlen > inlen) {
/* Return original packet uncompressed. */
*resultp = m;
priv->stats.FramesUncomp++;
priv->stats.OutOctets+=inlen;
} else {
/* Install header. */
be16enc(priv->outbuf, PROT_COMPD);
be16enc(priv->outbuf + 2, priv->seqnum);
/* Return packet in an mbuf. */
m_copyback(m, 0, outlen, (caddr_t)priv->outbuf);
if (m->m_pkthdr.len < outlen) {
m_freem(m);
priv->stats.Errors++;
return (ENOMEM);
} else if (outlen < m->m_pkthdr.len)
m_adj(m, outlen - m->m_pkthdr.len);
*resultp = m;
priv->stats.FramesComp++;
priv->stats.OutOctets+=outlen;
}
/* Update sequence number. */
priv->seqnum++;
return (0);
}
/*
* Decompress/decrypt packet and put the result in a new mbuf at *resultp.
* The original mbuf is not free'd.
*/
static int
ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
{
const priv_p priv = NG_NODE_PRIVATE(node);
int outlen, inlen;
int rtn;
uint16_t proto;
int offset;
uint16_t rseqnum;
/* Initialize. */
*resultp = NULL;
inlen = m->m_pkthdr.len;
if (inlen > DEFLATE_BUF_SIZE) {
priv->stats.Errors++;
NG_FREE_M(m);
priv->seqnum = 0;
return (ENOMEM);
}
/* We must own the mbuf chain exclusively to modify it. */
m = m_unshare(m, M_NOWAIT);
if (m == NULL) {
priv->stats.Errors++;
return (ENOMEM);
}
/* Work with contiguous regions of memory. */
m_copydata(m, 0, inlen, (caddr_t)priv->inbuf);
/* Separate proto. */
if ((priv->inbuf[0] & 0x01) != 0) {
proto = priv->inbuf[0];
offset = 1;
} else {
proto = be16dec(priv->inbuf);
offset = 2;
}
priv->stats.InOctets += inlen;
/* Packet is compressed, so decompress. */
if (proto == PROT_COMPD) {
priv->stats.FramesComp++;
/* Check sequence number. */
rseqnum = be16dec(priv->inbuf + offset);
offset += 2;
if (rseqnum != priv->seqnum) {
priv->stats.Errors++;
log(LOG_NOTICE, "ng_deflate: wrong sequence: %u "
"instead of %u\n", rseqnum, priv->seqnum);
NG_FREE_M(m);
priv->seqnum = 0;
return (EPIPE);
}
outlen = DEFLATE_BUF_SIZE;
/* Decompress "inbuf" into "outbuf". */
/* Prepare to decompress. */
priv->cx.next_in = priv->inbuf + offset;
priv->cx.avail_in = inlen - offset;
/* Reserve space for protocol decompression. */
priv->cx.next_out = priv->outbuf + 1;
priv->cx.avail_out = outlen - 1;
/* Decompress. */
rtn = inflate(&priv->cx, Z_PACKET_FLUSH);
/* Check return value. */
if (rtn != Z_OK && rtn != Z_STREAM_END) {
priv->stats.Errors++;
NG_FREE_M(m);
priv->seqnum = 0;
log(LOG_NOTICE, "%s: decompression error: %d (%s)\n",
__func__, rtn, priv->cx.msg);
switch (rtn) {
case Z_MEM_ERROR:
return (ENOMEM);
case Z_DATA_ERROR:
return (EIO);
default:
return (EINVAL);
}
}
/* Calculate resulting size. */
outlen -= priv->cx.avail_out;
/* Decompress protocol. */
if ((priv->outbuf[1] & 0x01) != 0) {
priv->outbuf[0] = 0;
/* Return packet in an mbuf. */
m_copyback(m, 0, outlen, (caddr_t)priv->outbuf);
} else {
outlen--;
/* Return packet in an mbuf. */
m_copyback(m, 0, outlen, (caddr_t)(priv->outbuf + 1));
}
if (m->m_pkthdr.len < outlen) {
m_freem(m);
priv->stats.Errors++;
priv->seqnum = 0;
return (ENOMEM);
} else if (outlen < m->m_pkthdr.len)
m_adj(m, outlen - m->m_pkthdr.len);
*resultp = m;
priv->stats.FramesPlain++;
priv->stats.OutOctets+=outlen;
} else { /* Packet is not compressed, just update dictionary. */
priv->stats.FramesUncomp++;
if (priv->inbuf[0] == 0) {
priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
priv->cx.avail_in = inlen - 1;
} else {
priv->cx.next_in = priv->inbuf;
priv->cx.avail_in = inlen;
}
rtn = inflateIncomp(&priv->cx);
/* Check return value */
if (rtn != Z_OK) {
priv->stats.Errors++;
log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n",
__func__, rtn, priv->cx.msg);
NG_FREE_M(m);
priv->seqnum = 0;
return (EINVAL);
}
*resultp = m;
priv->stats.FramesPlain++;
priv->stats.OutOctets += inlen;
}
/* Update sequence number. */
priv->seqnum++;
return (0);
}
/*
* The peer has sent us a CCP ResetRequest, so reset our transmit state.
*/
static void
ng_deflate_reset_req(node_p node)
{
const priv_p priv = NG_NODE_PRIVATE(node);
priv->seqnum = 0;
if (priv->cfg.enable) {
if (priv->compress)
deflateReset(&priv->cx);
else
inflateReset(&priv->cx);
}
}

View File

@ -0,0 +1,85 @@
/*-
* Copyright (c) 2006 Alexander Motin <mav@alkar.net>
* 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 unmodified, 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$
*/
#ifndef _NETGRAPH_NG_DEFLATE_H_
#define _NETGRAPH_NG_DEFLATE_H_
/* Node type name and magic cookie */
#define NG_DEFLATE_NODE_TYPE "deflate"
#define NGM_DEFLATE_COOKIE 1166642656
/* Hook names */
#define NG_DEFLATE_HOOK_COMP "comp" /* compression hook */
#define NG_DEFLATE_HOOK_DECOMP "decomp" /* decompression hook */
/* Config struct */
struct ng_deflate_config {
u_char enable; /* node enabled */
u_char windowBits; /* log2(Window size) */
};
/* Keep this in sync with the above structure definition. */
#define NG_DEFLATE_CONFIG_INFO { \
{ "enable", &ng_parse_uint8_type }, \
{ "windowBits", &ng_parse_uint8_type }, \
{ NULL } \
}
/* Statistics structure for one direction. */
struct ng_deflate_stats {
uint64_t FramesPlain;
uint64_t FramesComp;
uint64_t FramesUncomp;
uint64_t InOctets;
uint64_t OutOctets;
uint64_t Errors;
};
/* Keep this in sync with the above structure definition. */
#define NG_DEFLATE_STATS_INFO { \
{ "FramesPlain",&ng_parse_uint64_type }, \
{ "FramesComp", &ng_parse_uint64_type }, \
{ "FramesUncomp", &ng_parse_uint64_type }, \
{ "InOctets", &ng_parse_uint64_type }, \
{ "OutOctets", &ng_parse_uint64_type }, \
{ "Errors", &ng_parse_uint64_type }, \
{ NULL } \
}
/* Netgraph commands */
enum {
NGM_DEFLATE_CONFIG = 1,
NGM_DEFLATE_RESETREQ, /* sent either way! */
NGM_DEFLATE_GET_STATS,
NGM_DEFLATE_CLR_STATS,
NGM_DEFLATE_GETCLR_STATS,
};
#endif /* _NETGRAPH_NG_DEFLATE_H_ */

View File

@ -0,0 +1,490 @@
/*-
* Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
* Copyright (c) 2004-2005 Gleb Smirnoff <glebius@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 ``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 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 "device" node
*
* This node presents a /dev/ngd%d device that interfaces to an other
* netgraph node.
*
* $FreeBSD$
*
*/
#if 0
#define DBG do { printf("ng_device: %s\n", __func__ ); } while (0)
#else
#define DBG do {} while (0)
#endif
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/poll.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/vnode.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_device.h>
#define ERROUT(x) do { error = (x); goto done; } while (0)
/* Netgraph methods */
static int ng_device_mod_event(module_t, int, void *);
static ng_constructor_t ng_device_constructor;
static ng_rcvmsg_t ng_device_rcvmsg;
static ng_shutdown_t ng_device_shutdown;
static ng_newhook_t ng_device_newhook;
static ng_rcvdata_t ng_device_rcvdata;
static ng_disconnect_t ng_device_disconnect;
/* Netgraph type */
static struct ng_type ngd_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_DEVICE_NODE_TYPE,
.mod_event = ng_device_mod_event,
.constructor = ng_device_constructor,
.rcvmsg = ng_device_rcvmsg,
.shutdown = ng_device_shutdown,
.newhook = ng_device_newhook,
.rcvdata = ng_device_rcvdata,
.disconnect = ng_device_disconnect,
};
NETGRAPH_INIT(device, &ngd_typestruct);
/* per node data */
struct ngd_private {
struct ifqueue readq;
struct ng_node *node;
struct ng_hook *hook;
struct cdev *ngddev;
struct mtx ngd_mtx;
int unit;
uint16_t flags;
#define NGDF_OPEN 0x0001
#define NGDF_RWAIT 0x0002
};
typedef struct ngd_private *priv_p;
/* unit number allocator entity */
static struct unrhdr *ngd_unit;
/* Maximum number of NGD devices */
#define MAX_NGD 999
static d_close_t ngdclose;
static d_open_t ngdopen;
static d_read_t ngdread;
static d_write_t ngdwrite;
#if 0
static d_ioctl_t ngdioctl;
#endif
static d_poll_t ngdpoll;
static struct cdevsw ngd_cdevsw = {
.d_version = D_VERSION,
.d_open = ngdopen,
.d_close = ngdclose,
.d_read = ngdread,
.d_write = ngdwrite,
#if 0
.d_ioctl = ngdioctl,
#endif
.d_poll = ngdpoll,
.d_name = NG_DEVICE_DEVNAME,
};
/******************************************************************************
* Netgraph methods
******************************************************************************/
/*
* Handle loading and unloading for this node type.
*/
static int
ng_device_mod_event(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
break;
case MOD_UNLOAD:
delete_unrhdr(ngd_unit);
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
/*
* create new node
*/
static int
ng_device_constructor(node_p node)
{
priv_p priv;
DBG;
priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
/* Allocate unit number */
priv->unit = alloc_unr(ngd_unit);
/* Initialize mutexes and queue */
mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
/* Link everything together */
NG_NODE_SET_PRIVATE(node, priv);
priv->node = node;
priv->ngddev = make_dev(&ngd_cdevsw, priv->unit, UID_ROOT,
GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
if(priv->ngddev == NULL) {
printf("%s(): make_dev() failed\n",__func__);
mtx_destroy(&priv->ngd_mtx);
mtx_destroy(&priv->readq.ifq_mtx);
free_unr(ngd_unit, priv->unit);
free(priv, M_NETGRAPH);
return(EINVAL);
}
/* XXX: race here? */
priv->ngddev->si_drv1 = priv;
return(0);
}
/*
* Process control message.
*/
static int
ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
const priv_p priv = NG_NODE_PRIVATE(node);
struct ng_mesg *msg;
struct ng_mesg *resp = NULL;
const char *dn;
int error = 0;
NGI_GET_MSG(item, msg);
if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
switch (msg->header.cmd) {
case NGM_DEVICE_GET_DEVNAME:
/* XXX: Fix when MAX_NGD us bigger */
NG_MKRESPONSE(resp, msg,
strlen(NG_DEVICE_DEVNAME) + 4, M_NOWAIT);
if (resp == NULL)
ERROUT(ENOMEM);
dn = devtoname(priv->ngddev);
strlcpy((char *)resp->data, dn, strlen(dn) + 1);
break;
default:
error = EINVAL;
break;
}
} else
error = EINVAL;
done:
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Accept incoming hook. We support only one hook per node.
*/
static int
ng_device_newhook(node_p node, hook_p hook, const char *name)
{
priv_p priv = NG_NODE_PRIVATE(node);
DBG;
/* We have only one hook per node */
if (priv->hook != NULL)
return (EISCONN);
priv->hook = hook;
return(0);
}
/*
* Receive data from hook, write it to device.
*/
static int
ng_device_rcvdata(hook_p hook, item_p item)
{
priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct mbuf *m;
DBG;
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
IF_LOCK(&priv->readq);
if (_IF_QFULL(&priv->readq)) {
IF_UNLOCK(&priv->readq);
NG_FREE_M(m);
return (ENOBUFS);
}
_IF_ENQUEUE(&priv->readq, m);
IF_UNLOCK(&priv->readq);
mtx_lock(&priv->ngd_mtx);
if (priv->flags & NGDF_RWAIT) {
priv->flags &= ~NGDF_RWAIT;
wakeup(priv);
}
mtx_unlock(&priv->ngd_mtx);
return(0);
}
/*
* Removal of the hook destroys the node.
*/
static int
ng_device_disconnect(hook_p hook)
{
priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
DBG;
destroy_dev(priv->ngddev);
mtx_destroy(&priv->ngd_mtx);
IF_DRAIN(&priv->readq);
mtx_destroy(&(priv)->readq.ifq_mtx);
free_unr(ngd_unit, priv->unit);
free(priv, M_NETGRAPH);
ng_rmnode_self(NG_HOOK_NODE(hook));
return(0);
}
/*
* Node shutdown. Everything is already done in disconnect method.
*/
static int
ng_device_shutdown(node_p node)
{
NG_NODE_UNREF(node);
return (0);
}
/******************************************************************************
* Device methods
******************************************************************************/
/*
* the device is opened
*/
static int
ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
{
priv_p priv = (priv_p )dev->si_drv1;
DBG;
mtx_lock(&priv->ngd_mtx);
priv->flags |= NGDF_OPEN;
mtx_unlock(&priv->ngd_mtx);
return(0);
}
/*
* the device is closed
*/
static int
ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
{
priv_p priv = (priv_p )dev->si_drv1;
DBG;
mtx_lock(&priv->ngd_mtx);
priv->flags &= ~NGDF_OPEN;
mtx_unlock(&priv->ngd_mtx);
return(0);
}
#if 0 /*
* The ioctl is transformed into netgraph control message.
* We do not process them, yet.
*/
/*
* process ioctl
*
* they are translated into netgraph messages and passed on
*
*/
static int
ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
struct ngd_softc *sc = &ngd_softc;
struct ngd_connection * connection = NULL;
struct ngd_connection * tmp;
int error = 0;
struct ng_mesg *msg;
struct ngd_param_s * datap;
DBG;
NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
M_NOWAIT);
if (msg == NULL) {
printf("%s(): msg == NULL\n",__func__);
goto nomsg;
}
/* pass the ioctl data into the ->data area */
datap = (struct ngd_param_s *)msg->data;
datap->p = addr;
NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
if(error)
printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
nomsg:
return(0);
}
#endif /* if 0 */
/*
* This function is called when a read(2) is done to our device.
* We process one mbuf from queue.
*/
static int
ngdread(struct cdev *dev, struct uio *uio, int flag)
{
priv_p priv = (priv_p )dev->si_drv1;
struct mbuf *m;
int len, error = 0;
DBG;
/* get an mbuf */
do {
IF_DEQUEUE(&priv->readq, m);
if (m == NULL) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
mtx_lock(&priv->ngd_mtx);
priv->flags |= NGDF_RWAIT;
if ((error = msleep(priv, &priv->ngd_mtx,
PDROP | PCATCH | (PZERO + 1),
"ngdread", 0)) != 0)
return (error);
}
} while (m == NULL);
while (m && uio->uio_resid > 0 && error == 0) {
len = MIN(uio->uio_resid, m->m_len);
if (len != 0)
error = uiomove(mtod(m, void *), len, uio);
m = m_free(m);
}
if (m)
m_freem(m);
return (error);
}
/*
* This function is called when our device is written to.
* We read the data from userland into mbuf chain and pass it to the remote hook.
*
*/
static int
ngdwrite(struct cdev *dev, struct uio *uio, int flag)
{
priv_p priv = (priv_p )dev->si_drv1;
struct mbuf *m;
int error = 0;
DBG;
if (uio->uio_resid == 0)
return (0);
if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
return (EIO);
if ((m = m_uiotombuf(uio, M_NOWAIT, 0, 0, M_PKTHDR)) == NULL)
return (ENOBUFS);
NG_SEND_DATA_ONLY(error, priv->hook, m);
return (error);
}
/*
* we are being polled/selected
* check if there is data available for read
*/
static int
ngdpoll(struct cdev *dev, int events, struct thread *td)
{
priv_p priv = (priv_p )dev->si_drv1;
int revents = 0;
if (events & (POLLIN | POLLRDNORM) &&
!IFQ_IS_EMPTY(&priv->readq))
revents |= events & (POLLIN | POLLRDNORM);
return (revents);
}

View File

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
*
* 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 ``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 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$
*
*/
#ifndef _NETGRAPH_NG_DEVICE_H_
#define _NETGRAPH_NG_DEVICE_H_
/* Node type name and magic cookie */
#define NG_DEVICE_NODE_TYPE "device"
#define NGM_DEVICE_COOKIE 1091129178
#define NG_DEVICE_DEVNAME "ngd"
/* Netgraph control messages */
enum {
NGM_DEVICE_GET_DEVNAME,
};
#if 0
/* passing ioctl params */
struct ngd_param_s {
void * p;
};
#endif
#endif /* _NETGRAPH_NG_DEVICE_H_ */

121
freebsd/netgraph/ng_echo.c Normal file
View File

@ -0,0 +1,121 @@
/*
* ng_echo.c
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Julian Elisher <julian@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_echo.c,v 1.13 1999/11/01 09:24:51 julian Exp $
*/
/*
* Netgraph "echo" node
*
* This node simply bounces data and messages back to whence they came.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_echo.h>
/* Netgraph methods */
static ng_constructor_t nge_cons;
static ng_rcvmsg_t nge_rcvmsg;
static ng_rcvdata_t nge_rcvdata;
static ng_disconnect_t nge_disconnect;
/* Netgraph type */
static struct ng_type typestruct = {
.version = NG_ABI_VERSION,
.name = NG_ECHO_NODE_TYPE,
.constructor = nge_cons,
.rcvmsg = nge_rcvmsg,
.rcvdata = nge_rcvdata,
.disconnect = nge_disconnect,
};
NETGRAPH_INIT(echo, &typestruct);
static int
nge_cons(node_p node)
{
return (0);
}
/*
* Receive control message. We just bounce it back as a reply.
*/
static int
nge_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct ng_mesg *msg;
int error = 0;
NGI_GET_MSG(item, msg);
msg->header.flags |= NGF_RESP;
NG_RESPOND_MSG(error, node, item, msg);
return (error);
}
/*
* Receive data
*/
static int
nge_rcvdata(hook_p hook, item_p item)
{
int error;
NG_FWD_ITEM_HOOK(error, item, hook);
return (error);
}
/*
* Removal of the last link destroys the nodeo
*/
static int
nge_disconnect(hook_p hook)
{
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
ng_rmnode_self(NG_HOOK_NODE(hook));
}
return (0);
}

View File

@ -0,0 +1,51 @@
/*
* ng_echo.h
*/
/*-
* Copyright (c) 1996-1999 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*
* $FreeBSD$
* $Whistle: ng_echo.h,v 1.3 1999/01/20 00:22:12 archie Exp $
*/
#ifndef _NETGRAPH_NG_ECHO_H_
#define _NETGRAPH_NG_ECHO_H_
/* Node type name and magic cookie */
#define NG_ECHO_NODE_TYPE "echo"
#define NGM_ECHO_COOKIE 884298942
#endif /* _NETGRAPH_NG_ECHO_H_ */

Some files were not shown because too many files have changed in this diff Show More