Add ng_atmpif: a HARP physical interface emulation. This allows one

to run the HARP ATM stack without real hardware.

Submitted by:	Vincent Jardin <vjardin@wanadoo.fr>
This commit is contained in:
Hartmut Brandt 2003-08-11 08:40:02 +00:00
parent a57b72b4b9
commit ee4080d424
11 changed files with 2131 additions and 2 deletions

View file

@ -135,6 +135,7 @@ MAN= aac.4 \
netgraph.4 \
netintro.4 \
ng_atm.4 \
ng_atmpif.4 \
ng_UI.4 \
ng_async.4 \
ng_bluetooth.4 \

150
share/man/man4/ng_atmpif.4 Normal file
View file

@ -0,0 +1,150 @@
.\"
.\" Copyright (c) 2001-2003
.\" Harti Brandt.
.\" Vincent Jardin.
.\" 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>
.\" Author: Vincent Jardin <vjardin@free.fr>
.\"
.\" $FreeBSD$
.\"
.\" ng_atmpif(4) man page
.\"
.Dd August 7, 2003
.Dt ng_atmpif 4
.Os FreeBSD
.Sh NAME
.Nm ng_atmpif
.Nd netgraph HARP/ATM Virtual Physical Interface
.Sh SYNOPSIS
.Fd #include <netgraph/netgraph.h>
.Fd #include <netgraph/atm/ng_atmpif.h>
.Sh DESCIPTION
The
.Nm
netgraph node type allows the emulation of
.Xr atm 8
(netatm/HARP) Physical devices (PIF) to be connected to the
.Xr netgraph 4
networking subsystem.
Moreover it includes protection of the PDU against duplication and
desequencement.
It supports up to 65535 VCs and up to 255 VPs. AAL0, AAL3/4 and AAL5
emulation are provided.
In order to optimize CPU, this node does not emulate the SAR layer.
.Pp
The purpose of this node is to help in debugging and testing the HARP
stack when one does not have an ATM board or when the available boards do not
have enough features.
.Pp
When a node
.Nm
is created, a PIF is created automatically.
It is named hvaX.
It has the same features as any other HARP devices.
The PIF is removed when the node is removed.
.Sh HOOKS
There is only one hook: link. This hook can be connected to any other
Netgraph node. For example, in order
to test the HARP stack over UDP, it can be connected on a
.Xr ksocket 4
node.
.Sh CONTROL MESSAGES
This node type supports the generic messages plus the following:
.Bl -tag -width xxx
.It Dv NGM_ATMPIF_SET_CONFIG Ta setconfig
Configures the debugging features of the node and a virtual
Peak Cell Rate (PCR).
It uses the same structure as NGM_ATMPIF_GET_CONFIG.
.It Dv NGM_ATMPIF_GET_CONFIG Ta getconfig
Returns a structure defining the configuration of the interface:
.Bd -literal
struct ng_vatmpif_config {
uint8_t debug; /* debug bit field (see below) */
uint32_t pcr; /* peak cell rate */
Mac_addr macaddr; /* Mac Address */
};
.Ed
Note that the following debugging flags can be used:
.Bl -column ATM_PH_LLCSNAP -offset indent
.It Dv VATMPIF_DEBUG_NONE Ta disable debugging
.It Dv VATMPIF_DEBUG_PACKET Ta enable debugging
.El
.Pp
.It Dv NGM_ATMPIF_GET_LINK_STATUS Ta getlinkstatus
Returns the last received sequence number, the last sent sequence
number and the current total PCR that is reserved among all the VCCs
of the interface.
.Bd -literal
struct ng_atmpif_link_status {
uint32_t InSeq; /* last received sequence number + 1 */
uint32_t OutSeq; /* last sent sequence number */
uint32_t cur_pcr; /* slot's reserved PCR */
};
.Ed
.Pp
.It Dv NGM_ATMPIF_GET_STATS Ta getstats
.It Dv NGM_ATMPIF_CLR_STATS Ta clrstats
.It Dv NGM_ATMPIF_GETCLR_STATS Ta getclrstats
It returns the node's statistics, it clears them or it returns and reset
their values to 0.
The following stats are provided.
.Bd -literal
struct hva_stats_ng {
uint32_t ng_errseq; /* Duplicate or out of order */
uint32_t ng_lostpdu; /* PDU lost detected */
uint32_t ng_badpdu; /* Unknown PDU type */
uint32_t ng_rx_novcc; /* Draining PDU on closed VCC */
uint32_t ng_rx_iqfull; /* PDU drops no room in atm_intrq */
uint32_t ng_tx_rawcell; /* PDU raw cells transmitted */
uint32_t ng_rx_rawcell; /* PDU raw cells received */
uint64_t ng_tx_pdu; /* PDU transmitted */
uint64_t ng_rx_pdu; /* PDU received */
};
struct hva_stats_atm {
uint64_t atm_xmit; /* Cells transmitted */
uint64_t atm_rcvd; /* Cells received */
};
struct hva_stats_aal5 {
uint64_t aal5_xmit; /* Cells transmitted */
uint64_t aal5_rcvd; /* Cells received */
uint32_t aal5_crc_len; /* Cells with CRC/length errors */
uint32_t aal5_drops; /* Cell drops */
uint64_t aal5_pdu_xmit; /* CS PDUs transmitted */
uint64_t aal5_pdu_rcvd; /* CS PDUs received */
uint32_t aal5_pdu_crc; /* CS PDUs with CRC errors */
uint32_t aal5_pdu_errs; /* CS layer protocol errors */
uint32_t aal5_pdu_drops; /* CS PDUs dropped */
};
.Ed
.El
.Sh SEE ALSO
.Xr netgraph 4 ,
.Xr ng_ksocket 4 ,
.Xr natm 4 ,
.Xr ngctl 8
.Sh AUTHORS
.An Harti Brandt Aq harti@freebsd.org
.An Vincent Jardin Aq vjardin@wanadoo.fr

View file

@ -442,6 +442,7 @@ options NETGRAPH_TEE
options NETGRAPH_TTY
options NETGRAPH_UI
options NETGRAPH_VJC
options NETGRAPH_ATM_ATMPIF
# NgATM - Netgraph ATM
options NGATM_ATM

View file

@ -1338,6 +1338,8 @@ netatm/uni/unisig_sigmgr_state.c optional atm_uni atm_core
netatm/uni/unisig_subr.c optional atm_uni atm_core
netatm/uni/unisig_util.c optional atm_uni atm_core
netatm/uni/unisig_vc_state.c optional atm_uni atm_core
netgraph/atm/atmpif/ng_atmpif.c optional netgraph_atm_atmpif
netgraph/atm/atmpif/ng_atmpif_harp.c optional netgraph_atm_atmpif
netgraph/atm/ng_atm.c optional ngatm_atm
netgraph/ng_UI.c optional netgraph_UI
netgraph/ng_async.c optional netgraph_async

View file

@ -396,6 +396,7 @@ NETGRAPH_TEE opt_netgraph.h
NETGRAPH_TTY opt_netgraph.h
NETGRAPH_UI opt_netgraph.h
NETGRAPH_VJC opt_netgraph.h
NETGRAPH_ATM_ATMPIF opt_netgraph.h
# NgATM options
NGATM_ATM opt_netgraph.h

View file

@ -1,7 +1,8 @@
# $FreeBSD$
SUBDIR= \
atm
SUBDIR= \
atm \
atmpif
.include <bsd.subdir.mk>

View file

@ -0,0 +1,10 @@
# $FreeBSD$
#
# Author: Harti Brandt <harti@freebsd.org>
#
.PATH: ${.CURDIR}/../../../../netgraph/atm/atmpif
KMOD= ng_atmpif
SRCS= ng_atmpif.c ng_atmpif_harp.c
.include <bsd.kmod.mk>

View file

@ -0,0 +1,708 @@
/*
* Copyright 2003 Harti Brandt
* Copyright 2003 Vincent Jardin
* 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.
*/
/*
* ATM Virtal Adapter Support
* --------------------------
*
* Loadable kernel module and netgraph support
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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 <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syslog.h>
#include <vm/uma.h>
#include <net/if.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_cm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_pcb.h>
#include <netatm/atm_stack.h>
#include <netatm/atm_var.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/atm/ng_atmpif.h>
#include <netgraph/atm/atmpif/ng_atmpif_var.h>
#ifdef NG_SEPARATE_MALLOC
MALLOC_DEFINE(M_NETGRAPH_ATMPIF, "netgraph_vatmpif",
"netgraph HARP virtual Physical Interface");
#else
#define M_NETGRAPH_ATMPIF M_NETGRAPH
#endif
/*
* Local definitions
*/
/*
* Protocol header
*/
struct vatmpif_header {
/* The cell header (minus the HEC) is contained in the least-significant
* 32-bits of a word.
*/
uint32_t cellhdr; /* Stored in network order */
/* Let's use cellhdr = htonl(ATM_HDR_SET(vpi, vci, pt, clp))
* and vpi = ATM_HDR_GET_VPI(ntohl(cellhdr))
* vci = ATM_HDR_GET_VCI(ntohl(cellhdr))
* pt = ATM_HDR_GET_PT (ntohl(cellhdr))
* clp = ATM_HDR_GET_CLP(ntohl(cellhdr))
*/
int32_t seq; /* sequence number in network byte order */
uint64_t cookie; /* optional field */
uint8_t aal; /* AAL */
uint8_t __pad[3];
};
/*
* Local functions
*/
/* Parse type for a MAC address */
static ng_parse_t ng_macaddr_parse;
static ng_unparse_t ng_macaddr_unparse;
const struct ng_parse_type ng_mac_addr_type = {
parse: ng_macaddr_parse,
unparse: ng_macaddr_unparse,
};
/* Parse type for struct ng_atmpif_config */
static const struct ng_parse_struct_field
ng_atmpif_config_type_fields[] = NG_ATMPIF_CONFIG_TYPE_INFO;
static const struct ng_parse_type ng_atmpif_config_type = {
&ng_parse_struct_type,
&ng_atmpif_config_type_fields,
};
/* Parse type for struct ng_atmpif_link_status */
static const struct ng_parse_struct_field
ng_atmpif_link_status_type_fields[] = NG_ATMPIF_LINK_STATUS_TYPE_INFO;
static const struct ng_parse_type ng_atmpif_link_status_type = {
&ng_parse_struct_type,
&ng_atmpif_link_status_type_fields,
};
/* Parse type for struct ng_atmpif_stats */
static const struct ng_parse_struct_field
ng_atmpif_stats_type_fields[] = NG_ATMPIF_STATS_TYPE_INFO;
static const struct ng_parse_type ng_atmpif_stats_type = {
&ng_parse_struct_type,
&ng_atmpif_stats_type_fields,
};
static const struct ng_cmdlist ng_atmpif_cmdlist[] = {
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_SET_CONFIG,
"setconfig",
mesgType: &ng_atmpif_config_type,
respType: NULL
},
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_GET_CONFIG,
"getconfig",
mesgType: NULL,
respType: &ng_atmpif_config_type
},
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_GET_LINK_STATUS,
"getlinkstatus",
mesgType: NULL,
respType: &ng_atmpif_link_status_type
},
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_GET_STATS,
"getstats",
mesgType: NULL,
respType: &ng_atmpif_stats_type
},
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_CLR_STATS,
"clrstats",
mesgType: NULL,
respType: NULL
},
{
NGM_ATMPIF_COOKIE,
NGM_ATMPIF_GETCLR_STATS,
"getclrstats",
mesgType: NULL,
respType: &ng_atmpif_stats_type
},
{ 0 }
};
uma_zone_t vatmpif_nif_zone;
uma_zone_t vatmpif_vcc_zone;
/*
* Netgraph node methods
*/
static ng_constructor_t ng_atmpif_constructor;
static ng_rcvmsg_t ng_atmpif_rcvmsg;
static ng_shutdown_t ng_atmpif_rmnode;
static ng_newhook_t ng_atmpif_newhook;
static ng_rcvdata_t ng_atmpif_rcvdata;
static ng_disconnect_t ng_atmpif_disconnect;
static int ng_atmpif_mod_event(module_t, int, void *);
/*
* Node type descriptor
*/
static struct ng_type ng_atmpif_typestruct = {
NG_ABI_VERSION, /* version */
NG_ATMPIF_NODE_TYPE, /* name */
ng_atmpif_mod_event, /* mod_event */
ng_atmpif_constructor, /* constructor */
ng_atmpif_rcvmsg, /* rcvmsg */
ng_atmpif_rmnode, /* shutdown */
ng_atmpif_newhook, /* newhook */
NULL, /* findhook */
NULL, /* connect */
ng_atmpif_rcvdata, /* rcvdata */
ng_atmpif_disconnect, /* disconnect */
ng_atmpif_cmdlist, /* cmdlist */
};
NETGRAPH_INIT(atmpif, &ng_atmpif_typestruct);
/******************************************************************
NETGRAPH NODE METHODS
******************************************************************/
/*
* Node constructor
*
* Called at splnet()
*/
static int
ng_atmpif_constructor(node_p nodep)
{
priv_p priv;
/*
* Allocate and initialize private info
*/
priv = malloc(sizeof(*priv), M_NETGRAPH_ATMPIF, M_NOWAIT | M_ZERO);
if (priv == NULL)
return (ENOMEM);
priv->conf.debug = 0x00;
priv->conf.pcr = ATM_PCR_OC3C;
priv->conf.macaddr.ma_data[0] = 0x02; /* XXX : non unique bit */
priv->conf.macaddr.ma_data[1] = 0x09; /* XXX */
priv->conf.macaddr.ma_data[2] = 0xc0; /* XXX */
priv->conf.macaddr.ma_data[3] = (u_char)((random() & 0xff0000) >> 16);
priv->conf.macaddr.ma_data[4] = (u_char)((random() & 0x00ff00) >> 8);
priv->conf.macaddr.ma_data[5] = (u_char)((random() & 0x0000ff) >> 0);
NG_NODE_SET_PRIVATE(nodep, priv);
priv->node = nodep;
/* Done */
return (0);
}
/*
* Method for attaching a new hook
* A hook is a virtual ATM link.
*/
static int
ng_atmpif_newhook(node_p node, hook_p hook, const char *name)
{
const priv_p priv = NG_NODE_PRIVATE(node);
/*
* Check for a link hook
*/
if (strcmp(name, NG_ATMPIF_HOOK_LINK) == 0) {
int error;
/*
* Do not create twice a link hook
*/
if (priv->link != NULL)
return (EEXIST);
priv->link = malloc(sizeof(*priv->link),
M_NETGRAPH_ATMPIF, M_NOWAIT | M_ZERO);
if (priv->link == NULL)
return (ENOMEM);
/*
* Register as an HARP device
*/
if ((error = vatmpif_harp_attach(node))) {
free(priv->link, M_NETGRAPH_ATMPIF);
priv->link = NULL;
return (error);
}
priv->link->hook = hook;
return (0);
}
/* Unknown hook name */
return (EINVAL);
}
/*
* Receive a control message from ngctl or the netgraph's API
*/
static int
ng_atmpif_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;
int error = 0;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_ATMPIF_COOKIE:
switch (msg->header.cmd) {
case NGM_ATMPIF_GET_CONFIG:
{
struct ng_vatmpif_config *conf;
NG_MKRESPONSE(resp, msg,
sizeof(struct ng_vatmpif_config), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
conf = (struct ng_vatmpif_config *)resp->data;
*conf = priv->conf; /* no sanity checking needed */
break;
}
case NGM_ATMPIF_SET_CONFIG:
{
struct ng_vatmpif_config *conf;
if (msg->header.arglen != sizeof(*conf)) {
error = EINVAL;
break;
}
conf = (struct ng_vatmpif_config *)msg->data;
priv->conf = *conf;
break;
}
case NGM_ATMPIF_GET_LINK_STATUS:
{
struct ng_vatmpif_hook *link;
struct ng_atmpif_link_status *status;
if ((link = priv->link) == NULL) {
error = ENOTCONN;
break;
}
NG_MKRESPONSE(resp, msg, sizeof(*status), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
status = (struct ng_atmpif_link_status *)resp->data;
status->InSeq = link->InSeq;
status->OutSeq = link->OutSeq;
status->cur_pcr = link->cur_pcr;
break;
}
case NGM_ATMPIF_GET_STATS:
case NGM_ATMPIF_CLR_STATS:
case NGM_ATMPIF_GETCLR_STATS:
{
struct ng_vatmpif_hook *link;
if ((link = priv->link) == NULL) {
error = ENOTCONN;
break;
}
/* Get/clear stats */
if (msg->header.cmd != NGM_ATMPIF_CLR_STATS) {
NG_MKRESPONSE(resp, msg,
sizeof(link->stats), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
bcopy(&link->stats,
resp->data, sizeof(link->stats));
}
if (msg->header.cmd != NGM_ATMPIF_GET_STATS)
bzero(&link->stats, sizeof(link->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);
}
/*
* Hook disconnection.
* It shutdown the virtual ATM link however the node is kept.
*/
static int
ng_atmpif_disconnect(hook_p hook)
{
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
/*
* Deregister from the HARP stack
*/
vatmpif_harp_detach(node);
/*
* Free associated link information
*/
KASSERT(priv->link != NULL, ("%s: no link", __func__));
FREE(priv->link, M_NETGRAPH_ATMPIF);
priv->link = NULL;
/* Shutdown the physical interface */
priv->vu_pif.pif_flags &= ~PIF_UP;
/* No more hooks, however I prefer to keep the node
* instead of going away
* However, if we are interested in removing it, let's
* call ng_rmnode(hook->node); here.
*/
return (0);
}
/*
* Shutdown node
*
* Free the private data.
*/
static int
ng_atmpif_rmnode(node_p node)
{
const priv_p priv = NG_NODE_PRIVATE(node);
/* Free private data */
FREE(priv, M_NETGRAPH_ATMPIF);
NG_NODE_SET_PRIVATE(node, NULL);
/* Unref node */
NG_NODE_UNREF(node);
return (0);
}
/*
* Receive data
*
* Then vatmpif_harp_recv_drain will schedule a call into the kernel
* to process the atm_intrq.
* It means that it should be processing at splimp() if
* the node was a regular hw driver.
*/
static int
ng_atmpif_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
const priv_p priv = NG_NODE_PRIVATE(node);
struct vatmpif_header *h;
struct vatmpif_header hdrbuf;
int error = 0;
struct mbuf *m;
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
/* Is the Physical Interface UP ? */
if (!(priv->vu_pif.pif_flags & PIF_UP)) {
log(LOG_ERR, "%s%d: down while %s",
priv->vu_pif.pif_name, priv->vu_pif.pif_unit, __func__);
error = ENETDOWN;
goto drop;
}
/* Sanity check header length */
if (m->m_pkthdr.len < sizeof(*h)) {
priv->link->stats.hva_st_ng.ng_badpdu++;
error = EINVAL;
goto drop;
}
/* Get the Virtual ATM Physical Interface header */
if (m->m_len >= sizeof(*h)) { /* the common case */
h = mtod(m, struct vatmpif_header *);
} else {
m_copydata(m, 0, sizeof(*h), (caddr_t)&hdrbuf);
h = &hdrbuf; /* allocated on the stack */
}
/*
* Consume the vatmpif header
*/
m_adj(m, sizeof(*h));
/*
* Parse the header h
*/
/*
* duplication and out of order test.
*
* . let's SEQ_MAX be the highest sequence number
* . let's assume that h->seq = SEQ_MAX, (1)
*/
if (ntohl(h->seq) < priv->link->InSeq) {
/* . is false due to (1) */
/* duplicate or out of order */
priv->link->stats.hva_st_ng.ng_errseq++;
error = EINVAL;
goto drop;
}
/* . then the mbuf is not dropped */
/* PDUs have been lost ?? */
if (priv->link->InSeq < ntohl(h->seq)) {
/* . it is true only if a PDU has been lost,
* . else due to (1) priv->link->InSeq is
* . already equal to SEQ_MAX.
*/
priv->link->stats.hva_st_ng.ng_lostpdu++;
priv->link->InSeq = ntohl(h->seq);
}
/* Save the sequence number */
priv->link->InSeq = ntohl(h->seq) + 1;
/* . it leads to InSeq = SEQ_MAX + 1 = SEQ_MIN */
/* . it means that InSeq is always the next intended
* . sequence number if none is lost, doesn't it ?
*/
/*
* Send the packet to the stack.
*/
priv->link->stats.hva_st_ng.ng_rx_pdu++;
error = vatmpif_harp_recv_drain(priv, m,
ATM_HDR_GET_VPI(ntohl(h->cellhdr)),
ATM_HDR_GET_VCI(ntohl(h->cellhdr)),
ATM_HDR_GET_PT (ntohl(h->cellhdr)),
ATM_HDR_GET_CLP(ntohl(h->cellhdr)), h->aal);
return (error);
drop:
m_freem(m);
return (error);
}
/*
* Transmit data. Called by the HARP's outpout function. You should
* notice that the return value is not returned upward by the HARP
* stack. It is only used in order to update the stats.
*/
int
ng_atmpif_transmit(const priv_p priv, struct mbuf *m,
uint8_t vpi, uint16_t vci, uint8_t pt, uint8_t clp, Vatmpif_aal aal)
{
struct vatmpif_header *h;
int error = 0;
/* Is the Physical Interface UP ? */
if (!(priv->vu_pif.pif_flags & PIF_UP)) {
log(LOG_ERR, "%s%d: down while %s",
priv->vu_pif.pif_name, priv->vu_pif.pif_unit, __func__);
error = ENETDOWN;
goto drop;
}
/* If the hook is not connected, free the mbuf */
if (priv->link == NULL) {
log(LOG_ERR, "%s%d: no hook while %s",
priv->vu_pif.pif_name, priv->vu_pif.pif_unit, __func__);
error = ENETDOWN;
goto drop;
}
M_PREPEND(m, sizeof(*h), M_DONTWAIT);
if (m == NULL) {
error = ENOBUFS;
goto drop;
}
m = m_pullup(m, sizeof(*h));
if (m == NULL) {
error = ENOBUFS;
goto drop;
}
h = mtod(m, struct vatmpif_header *);
/* htonl is linear */
h->cellhdr = htonl(ATM_HDR_SET_VPI(vpi));
h->cellhdr += htonl(ATM_HDR_SET_VCI(vci));
h->cellhdr += htonl(ATM_HDR_SET_PT (pt));
h->cellhdr += htonl(ATM_HDR_SET_CLP(clp));
h->aal = aal;
priv->link->OutSeq++;
h->seq = htonl(priv->link->OutSeq);
h->cookie = 0;
if (IS_VATMPIF_DEBUG_PACKET(priv))
atm_pdu_print(m, __func__);
/* Send it out to the "link" hook */
priv->link->stats.hva_st_ng.ng_tx_pdu++;
NG_SEND_DATA_ONLY(error, priv->link->hook, m);
return (error);
drop:
if (m != NULL)
m_freem(m);
return (error);
}
/******************************************************************
MAC Address parser
*****************************************************************/
static int
ng_macaddr_parse(const struct ng_parse_type *type, const char *s,
int *const off, const u_char *const start, u_char *const buf,
int *const buflen)
{
char *eptr;
u_long val;
int i;
if (*buflen < 6)
return (ERANGE);
for (i = 0; i < 6; i++) {
val = strtoul(s + *off, &eptr, 16);
if (val > 0xff || eptr == s + *off)
return (EINVAL);
buf[i] = (u_char)val;
*off = (eptr - s);
if (i < 6 - 1) {
if (*eptr != ':')
return (EINVAL);
(*off)++;
}
}
*buflen = 6;
return (0);
}
static int
ng_macaddr_unparse(const struct ng_parse_type *type, const u_char *data,
int *off, char *cbuf, int cbuflen)
{
int len;
len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x",
data[*off], data[*off + 1], data[*off + 2],
data[*off + 3], data[*off + 4], data[*off + 5]);
if (len >= cbuflen)
return (ERANGE);
*off += 6;
return (0);
}
/*
* this holds all the stuff that should be done at load time
*/
static int
ng_atmpif_mod_event(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
vatmpif_nif_zone = uma_zcreate("vatmpif nif",
sizeof(struct atm_nif), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
if (vatmpif_nif_zone == NULL) {
error = ENOMEM;
break;
}
vatmpif_vcc_zone = uma_zcreate("vatmpif vcc",
sizeof(Vatmpif_vcc), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
if (vatmpif_vcc_zone == NULL) {
uma_zdestroy(vatmpif_nif_zone);
error = ENOMEM;
break;
}
break;
case MOD_UNLOAD:
uma_zdestroy(vatmpif_nif_zone);
uma_zdestroy(vatmpif_vcc_zone);
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}

View file

@ -0,0 +1,933 @@
/*
* Copyright 2003 Harti Brandt
* Copyright 2003 Vincent Jardin
* 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.
*/
/*
* ATM Virtal Adapter Support
* --------------------------
*
* API between HARP and Netgraph
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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 <sys/syslog.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <vm/uma.h>
#include <net/if.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_cm.h>
#include <netatm/atm_vc.h>
#include <netatm/atm_if.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_pcb.h>
#include <netatm/atm_stack.h>
#include <netatm/atm_var.h>
#include <netatm/atm_ioctl.h>
#include <net/netisr.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/atm/ng_atmpif.h>
#include <netgraph/atm/atmpif/ng_atmpif_var.h>
/*
* Local definitions
*/
/*
* Local methods
*/
static int vatmpif_nunits = 0;
/*
* ATM Interface services
*
* this virtual device does not use a soft SAR of the AAL5 PDU, neither
* of the AAL3/4 PDU.
*/
static struct stack_defn vatmpif_svaal5 = {
sd_next: NULL,
sd_sap: SAP_CPCS_AAL5,
sd_flag: SDF_TERM, /* no soft SAR */
sd_inst: atm_dev_inst,
sd_lower: atm_dev_lower,
sd_upper: NULL,
sd_toku: 0,
};
static struct stack_defn vatmpif_svaal4 = {
sd_next: &vatmpif_svaal5,
sd_sap: SAP_CPCS_AAL3_4,
sd_flag: SDF_TERM, /* no soft SAR */
sd_inst: atm_dev_inst,
sd_lower: atm_dev_lower,
sd_upper: NULL,
sd_toku: 0,
};
static struct stack_defn vatmpif_svaal0 = {
sd_next: &vatmpif_svaal4,
sd_sap: SAP_ATM,
sd_flag: SDF_TERM, /* no soft SAR */
sd_inst: atm_dev_inst,
sd_lower: atm_dev_lower,
sd_upper: NULL,
sd_toku: 0,
};
static struct stack_defn *vatmpif_services = &vatmpif_svaal0;
/******************************************************************
HARP API METHODS
******************************************************************/
/*
* Local methods
*/
static int vatmpif_harp_ioctl(int code, caddr_t data, caddr_t arg);
static int vatmpif_harp_instvcc(Cmn_unit *cup, Cmn_vcc *cvp);
static int vatmpif_harp_openvcc(Cmn_unit *cup, Cmn_vcc *cvp);
static int vatmpif_harp_closevcc(Cmn_unit *cup, Cmn_vcc *cvp);
static void vatmpif_harp_output(Cmn_unit *cup, Cmn_vcc *cvp, KBuffer *m);
static atm_intr_t vatmpif_harp_recv_stack;
/*
* Attach an virtual ATM physical inteface with the HARP stack
*
* Each virtual ATM device interface must register itself here
* upon completing the netgraph node constructor.
*
* Arguments:
* node pointer on the netgraph node
*
* Returns:
* 0 successful
* errno failed - reason indicated
*/
int
vatmpif_harp_attach(node_p node)
{
Vatmpif_unit *vup;
static int unit = 0;
int err;
/*
* Sanity check
*/
if (node == NULL)
return (EINVAL);
/*
* Get the virtual unit structure
*/
vup = (Vatmpif_unit *)NG_NODE_PRIVATE(node);
if (vup == NULL)
return (EINVAL);
/*
* Start initializing the HARP binding
*/
vup->vu_unit = unit;
/* 9188 bytes: Default ATM network interface MTU + LLC/SNAP header */
vup->vu_mtu = ATM_NIF_MTU + 8;
vup->vu_vcc_zone = vatmpif_vcc_zone;
vup->vu_nif_zone = vatmpif_nif_zone;
vup->vu_ioctl = vatmpif_harp_ioctl;
vup->vu_instvcc = vatmpif_harp_instvcc;
vup->vu_openvcc = vatmpif_harp_openvcc;
vup->vu_closevcc = vatmpif_harp_closevcc;
vup->vu_output = vatmpif_harp_output;
vup->vu_softc = vup;
/*
* Consider this virtual unit assigned
*/
unit++;
/*
* Get our device type and setup the adapter config info
* - at least as much as we can
*/
vup->vu_config.ac_vendor = VENDOR_NETGRAPH;
vup->vu_config.ac_vendapi = VENDAPI_NETGRAPH_1;
vup->vu_config.ac_device = DEV_VATMPIF;
vup->vu_config.ac_media = MEDIA_VIRTUAL;
vup->vu_config.ac_serial = (u_long)node;
vup->vu_config.ac_bustype = BUS_VIRTUAL;
vup->vu_config.ac_busslot = NGM_ATMPIF_COOKIE;
vup->vu_config.ac_ram = (u_long)node;
vup->vu_config.ac_ramsize = sizeof(*node);
vup->vu_config.ac_macaddr = vup->conf.macaddr;
snprintf(vup->vu_config.ac_hard_vers,
sizeof(vup->vu_config.ac_hard_vers),
"%s", "Virt. ATM 1.0");
snprintf(vup->vu_config.ac_firm_vers,
sizeof(vup->vu_config.ac_firm_vers),
"%d", __FreeBSD__);
/*
* Set the interface capabilities
*/
vup->vu_pif.pif_maxvpi = VATMPIF_MAX_VPI;
vup->vu_pif.pif_maxvci = VATMPIF_MAX_VCI;
vup->vu_pif.pif_pcr = vup->conf.pcr;
/*
* Register this interface with ATM core services
*/
if ((err = atm_physif_register((Cmn_unit *)vup,
VATMPIF_DEV_NAME, vatmpif_services)) != 0 ) {
/*
* Registration failed - back everything out
*
* The netgraph node must not be created.
*/
return (err);
}
vatmpif_nunits++;
/*
* Mark device initialization completed
*/
vup->vu_flags |= CUF_INITED;
/* Done */
return (0);
}
/*
* Halt driver processing
*
* This will be called just prior the destruction of the Netgraph's node.
*
* Arguments:
* node pointer on the netgraph node
*
* Returns:
* 0 detach was successful
* errno detach failed - reason indicated
*/
int
vatmpif_harp_detach(node_p node)
{
Vatmpif_unit *vup = (Vatmpif_unit *)NG_NODE_PRIVATE(node);
int err;
/*
* Deregister device from kernel services
*/
if ((err = atm_physif_deregister((Cmn_unit *)vup)))
return (err);
vatmpif_nunits--;
/*
* Clear device initialized
*/
vup->vu_flags &= ~CUF_INITED;
/* Done */
return (0);
}
/*
* Handle netatm core service interface ioctl requests
*
* Arguments:
* code ioctl function (sub)code
* data data to/from ioctl
* arg optional code-specific argument
*
* Returns:
* 0 request processed successfully
* errno request failed - reason code
*/
static int
vatmpif_harp_ioctl(int code, caddr_t data, caddr_t arg)
{
struct atminfreq *aip = (struct atminfreq *)data;
struct atm_pif *pip;
Vatmpif_unit *vup;
caddr_t buf = aip->air_buf_addr;
struct air_vinfo_rsp *avr;
size_t count, len, buf_len = aip->air_buf_len;
int err = 0;
char ifname[2 * IFNAMSIZ];
ATM_DEBUG3("%s: code=%d, opcode=%d\n", __func__, code, aip->air_opcode);
switch (aip->air_opcode) {
case AIOCS_INF_VST:
/*
* Get vendor statistics
*/
pip = (struct atm_pif *)arg;
vup = (Vatmpif_unit *)pip;
if (pip == NULL)
return (ENXIO);
snprintf(ifname, sizeof(ifname), "%s%d",
pip->pif_name, pip->pif_unit);
/*
* Cast response structure onto user's buffer
*/
avr = (struct air_vinfo_rsp *)(void *)buf;
/*
* How lare is the response structure ?
*/
len = sizeof(struct air_vinfo_rsp);
/*
* Sanity check - enough room for response structure
*/
if (buf_len < len)
return ENOSPC;
/*
* Copy interface name into response structure
*/
if ((err = copyout(ifname, avr->avsp_intf, IFNAMSIZ)) != 0)
break;
/*
* Advance the buffer address and decrement the size
*/
buf += len;
buf_len -= len;
/*
* Get the vendor stats
*/
/* vup->vu_stats */
/*
* Stick as much of it as we have room for
* into the response
*/
count = MIN(sizeof(Vatmpif_stats), buf_len);
/*
* Copy stats into user's buffer. Return value is
* amount of data copied.
*/
if ((err = copyout((caddr_t)&vup->vu_stats, buf,
buf_len)) != 0)
break;
buf += count;
buf_len -= count;
if (count < sizeof(Vatmpif_stats))
err = ENOSPC;
/*
* Record amount we are returning as vendor info...
*/
if ((err = copyout(&count, &avr->avsp_len, sizeof(count))) != 0)
break;
/*
* Update the reply pointers and lengths
*/
aip->air_buf_addr = buf;
aip->air_buf_len = buf_len;
break;
default:
err = ENOSYS;
break;
}
return (err);
}
/*
* Get CBR/VBR/ABR/UBR from bearer attribute
*
* Arguments:
* bearer T_ATM_BEARER_CAP option value structure
*
* Returns:
* Driver traffic class
*/
static Vatmpif_traffic_type
vatmpif_bearerclass(struct attr_bearer *bearer)
{
switch (bearer->v.bearer_class) {
case T_ATM_CLASS_A:
return (VATMPIF_TRAF_CBR);
case T_ATM_CLASS_C:
return (VATMPIF_TRAF_VBR);
case T_ATM_CLASS_X:
switch (bearer->v.traffic_type) {
case T_ATM_CBR:
return (VATMPIF_TRAF_CBR);
case T_ATM_VBR:
return (VATMPIF_TRAF_VBR);
case T_ATM_ABR:
return (VATMPIF_TRAF_ABR);
case T_ATM_NULL:
case T_ATM_UBR:
return (VATMPIF_TRAF_UBR);
}
break;
}
/* never reached */
log(LOG_ERR, "%s: could not determine the traffic type.\n", __func__);
return (VATMPIF_TRAF_UBR);
}
/*
* VCC Stack Instantiation
*
* This function is called via the common driver code during a device VCC
* stack instantiation. The common code has already validated some of
* the request so we just need to check a few more VATMPIF-specific details.
*
* Arguments:
* cup pointer to device common unit
* cvp pointer to common VCC entry
*
* Returns:
* 0 instantiation successful
* errno instantiation failed - reason indicated
*/
static int
vatmpif_harp_instvcc(Cmn_unit *cup, Cmn_vcc *cvp)
{
Vatmpif_unit *vup = (Vatmpif_unit *)cup;
Vatmpif_vcc *vvp = (Vatmpif_vcc *)cvp;
Atm_attributes *ap = &vvp->vv_connvc->cvc_attr;
int32_t pcr = 0;
int32_t scr = 0;
Vatmpif_traffic_type traffic = VATMPIF_TRAF_UBR;
ATM_DEBUG3("%s: vup=%p, vvp=%p\n", __func__, vup, vvp);
if (ap->traffic.tag == T_ATM_PRESENT) {
pcr = ap->traffic.v.forward.PCR_all_traffic;
scr = ap->traffic.v.forward.SCR_all_traffic;
}
if (pcr < 0)
pcr = 0;
if (scr < 0)
scr = 0;
KASSERT(ap->bearer.tag == T_ATM_PRESENT, ("Bearer tag is required"));
traffic = vatmpif_bearerclass(&ap->bearer);
/* Guarantee PCR of the PVC with CBR */
if (traffic == VATMPIF_TRAF_CBR &&
vup->vu_cur_pcr + pcr > vup->vu_pif.pif_pcr) {
return (EINVAL);
}
/* Guarantee SCR of the PVC with VBR */
if (traffic == VATMPIF_TRAF_VBR &&
vup->vu_cur_pcr + scr > vup->vu_pif.pif_pcr) {
return (EINVAL);
}
/*
* Validate requested AAL
*/
KASSERT(ap->aal.tag == T_ATM_PRESENT, ("AAL tag is required"));
switch (ap->aal.type) {
case ATM_AAL0:
break;
case ATM_AAL1:
break;
case ATM_AAL2:
return (EINVAL);
case ATM_AAL3_4:
if (ap->aal.v.aal4.forward_max_SDU_size > vup->vu_mtu ||
ap->aal.v.aal4.backward_max_SDU_size > vup->vu_mtu)
return (EINVAL);
break;
case ATM_AAL5:
if (ap->aal.v.aal5.forward_max_SDU_size > vup->vu_mtu ||
ap->aal.v.aal5.backward_max_SDU_size > vup->vu_mtu)
return (EINVAL);
break;
default:
return (EINVAL);
}
/* Done */
return (0);
}
/*
* Open a VCC
*
* This function is called via the common driver code after receiving a
* stack *_INIT command. The common has already validated most of
* the request so we just need to check a few more VATMPIF-specific details.
* Then we just forward to the Netgraph node.
*
* Called at splimp.
*
* Arguments:
* cup pointer to device common unit
* cvp pointer to common VCC entry
*
* Returns:
* 0 open successful
* errno open failed - reason indicated
*/
static int
vatmpif_harp_openvcc(Cmn_unit *cup, Cmn_vcc *cvp)
{
Vatmpif_unit *vup = (Vatmpif_unit *)cup;
Vatmpif_vcc *vvp = (Vatmpif_vcc *)cvp;
struct vccb *vcp = vvp->vv_connvc->cvc_vcc;
Atm_attributes *ap = &vvp->vv_connvc->cvc_attr;
ATM_DEBUG5("%s: vup=%p, vvp=%p, vcc=(%d,%d)\n", __func__,
vup, vvp, vcp->vc_vpi, vcp->vc_vci);
/*
* We only need to open incoming VC's so outbound VC's
* just get set to CVS_ACTIVE state.
*/
if ((vcp->vc_type & VCC_IN) == 0) {
/*
* Set the state and return - nothing else needed
*/
vvp->vv_state = CVS_ACTIVE;
return (0);
}
/*
* Set the AAL and traffic
*/
switch (ap->aal.type) {
case ATM_AAL0:
vvp->vv_aal = VATMPIF_AAL_0;
break;
case ATM_AAL2:
return (EINVAL);
case ATM_AAL3_4:
vvp->vv_aal = VATMPIF_AAL_4;
break;
case ATM_AAL5:
vvp->vv_aal = VATMPIF_AAL_5;
break;
default:
return (EINVAL);
}
vvp->vv_traffic_type = vatmpif_bearerclass(&ap->bearer);
vvp->vv_traffic = ap->traffic.v;
switch (vvp->vv_traffic_type) {
case VATMPIF_TRAF_ABR:
/* TODO */
case VATMPIF_TRAF_UBR:
break;
case VATMPIF_TRAF_VBR:
vup->vu_cur_pcr += vvp->vv_traffic.forward.SCR_all_traffic;
break;
case VATMPIF_TRAF_CBR:
vup->vu_cur_pcr += vvp->vv_traffic.forward.PCR_all_traffic;
break;
}
/*
* Indicate VC active
*/
vvp->vv_state = CVS_ACTIVE;
/* Done */
return (0);
}
/*
* Close a VCC
*
* This function is called via the common driver code after receiving a
* stack *_TERM command. The common code has already validated most of
* the request so we just need to check a few more VATMPIF-specific detail.
* Then we just remove the entry from the list.
*
* Arguments:
* cup pointer to device common unit
* cvp pointer to common VCC entry
*
* Returns:
* 0 close successful
* errno close failed - reason indicated
*/
static int
vatmpif_harp_closevcc(Cmn_unit *cup, Cmn_vcc *cvp)
{
Vatmpif_unit *vup = (Vatmpif_unit *)cup;
Vatmpif_vcc *vvp = (Vatmpif_vcc *)cvp;
struct vccb *vcp = vvp->vv_connvc->cvc_vcc;
/*
* If this is an outbound only VCI, then we can close
* immediately.
*/
if ((vcp->vc_type & VCC_IN) == 0) {
/*
* The state will be set to TERM when we return
* to the *_TERM caller.
*/
return (0);
}
switch (vvp->vv_traffic_type) {
case VATMPIF_TRAF_ABR:
/* TODO */
case VATMPIF_TRAF_UBR:
break;
case VATMPIF_TRAF_VBR:
vup->vu_cur_pcr -= vvp->vv_traffic.forward.SCR_all_traffic;
break;
case VATMPIF_TRAF_CBR:
vup->vu_cur_pcr -= vvp->vv_traffic.forward.PCR_all_traffic;
break;
}
return (0);
}
/*
* Output a PDU
*
* This function is called via the common driver code after receiving a
* stack *_DATA* command. The command code has already validated most of
* the request so we just need to check a few more VATMPIF-specific detail.
* Then we just forward the transmit mbuf to the Netgraph node.
*
* Arguments:
* cup pointer to device common
* cvp pointer to common VCC entry
* m pointer to output PDU buffer chain head
*
* Returns:
* none
*/
static void
vatmpif_harp_output(Cmn_unit *cup, Cmn_vcc *cvp, KBuffer *m)
{
Vatmpif_unit *vup = (Vatmpif_unit *)cup;
Vatmpif_vcc *vvp = (Vatmpif_vcc *)cvp;
struct vccb *vcp = vvp->vv_connvc->cvc_vcc;
Atm_attributes *ap = &vvp->vv_connvc->cvc_attr;
int err = 0;
u_long pdulen = 0;
if (IS_VATMPIF_DEBUG_PACKET(vup))
atm_dev_pdu_print(cup, cvp, m, __func__);
/*
* Get packet PDU length
*/
KB_PLENGET (m, pdulen);
err = ng_atmpif_transmit(vup, m, vcp->vc_vpi, vcp->vc_vci,
0, 0, ap->aal.type);
/*
* Now collect some statistics
*/
if (err) {
vup->vu_pif.pif_oerrors++;
vcp->vc_oerrors++;
if (vcp->vc_nif)
vcp->vc_nif->nif_if.if_oerrors++;
} else {
/*
* Good transmission
*/
switch (ap->aal.type) {
case VATMPIF_AAL_0:
vup->vu_stats.hva_st_ng.ng_tx_rawcell++;
break;
case VATMPIF_AAL_4:
/* TODO */
break;
case VATMPIF_AAL_5:
vup->vu_stats.hva_st_aal5.aal5_xmit +=
(pdulen + 47) / 48;
vup->vu_stats.hva_st_aal5.aal5_pdu_xmit++;
break;
default:
log(LOG_ERR, "%s%d: unknown AAL while %s",
vup->vu_pif.pif_name, vup->vu_pif.pif_unit,
__func__);
}
vup->vu_pif.pif_opdus++;
vup->vu_pif.pif_obytes += pdulen;
if (vvp) {
vcp = vvp->vv_connvc->cvc_vcc;
vcp->vc_opdus++;
vcp->vc_obytes += pdulen;
if (vcp->vc_nif) {
vcp->vc_nif->nif_obytes += pdulen;
vcp->vc_nif->nif_if.if_opackets++;
vcp->vc_nif->nif_if.if_obytes += pdulen;
}
}
}
}
/*
* Pass Incoming PDU up to the HARP stack
*
* This function is called via the core ATM interrupt queue callback
* set in vatmpif_harp_recv_drain(). It will pass the supplied incoming
* PDU up the incoming VCC's stack.
*
* Arguments:
* tok token to identify stack instantiation
* m pointer to incoming PDU buffer chain
*
* Returns:
* none
*/
static void
vatmpif_harp_recv_stack(void *tok, KBuffer *m)
{
Vatmpif_vcc *vvp = (Vatmpif_vcc *)tok;
int err;
/*
* Send the data up the stack
*/
STACK_CALL(CPCS_UNITDATA_SIG, vvp->vv_upper,
vvp->vv_toku, vvp->vv_connvc, (intptr_t)m, 0, err);
if (err)
KB_FREEALL(m);
}
/*
* Drain Receive Queue
*
* The function will process all completed entries at the head of the
* receive queue. The received segments will be linked into a received
* PDU buffer cahin and it will then be passed up the PDU's VCC stack
* function processing by the next higher protocol layer.
*
* May be called in interrupt state.
* Must be called with interrupts locked out.
*
* Arguments:
* vup pointer to the virtual device structure
* m pointer to incoming PDU buffer chain
* vpi Virtual Path Identifier
* vci Virtual Channel Identifier (host order)
* pt Payload Type Identifier (3 bit)
* ATM_PT_USER_SDU0
* ATM_PT_USER_SDU1
* ATM_PT_USER_CONG_SDU0
* ATM_PT_USER_CONG_SDU1
* ATM_PT_NONUSER
* ATM_PT_OAMF5_SEG
* ATM_PT_OAMF5_E2E
* clp Cell Loss Priority (1 bit)
*
* Returns:
* 0 close successful
* errno close failed - reason indicated
*/
int
vatmpif_harp_recv_drain(Vatmpif_unit *vup, KBuffer *m,
uint8_t vpi, uint16_t vci, uint8_t pt, uint8_t clp, Vatmpif_aal aal)
{
Vatmpif_vcc *vvp;
struct vccb *vcp;
u_long pdulen = 0;
caddr_t cp;
int err = 0;
/*
* Locate incoming VCC for this PDU
*/
vvp = (Vatmpif_vcc *)atm_dev_vcc_find((Cmn_unit *)vup,
vpi, vci, VCC_IN);
if (vvp == NULL) {
vup->vu_stats.hva_st_ng.ng_rx_novcc++;
vup->vu_pif.pif_ierrors++;
KB_FREEALL(m);
err = EIO;
goto failed;
}
switch (aal) {
case VATMPIF_AAL_0:
vup->vu_stats.hva_st_ng.ng_rx_rawcell++;
break;
case VATMPIF_AAL_4:
/* TODO */
break;
case VATMPIF_AAL_5:
vup->vu_stats.hva_st_aal5.aal5_rcvd += (pdulen + 47) / 48;
vup->vu_stats.hva_st_aal5.aal5_pdu_rcvd++;
break;
default:
vup->vu_stats.hva_st_ng.ng_badpdu++;
vup->vu_pif.pif_ierrors++;
KB_FREEALL(m);
err = EINVAL;
goto failed;
}
/*
* TODO:
* For now, only user data PDUs are supported
*/
if (pt & ATM_HDR_SET_PT(ATM_PT_NONUSER)) {
vup->vu_stats.hva_st_ng.ng_badpdu++;
vup->vu_pif.pif_ierrors++;
if (aal == VATMPIF_AAL_5) {
vup->vu_stats.hva_st_aal5.aal5_drops +=
(pdulen + 47) / 48;
vup->vu_stats.hva_st_aal5.aal5_pdu_drops++;
}
err = EINVAL;
goto failed;
}
if (IS_VATMPIF_DEBUG_PACKET(vup))
atm_dev_pdu_print((Cmn_unit *)vup, (Cmn_vcc *)vvp, m,
__FUNCTION__);
/*
* Get packet PDU length
*/
KB_PLENGET(m, pdulen);
/*
* Only try queueing this if there is data
* to be handed up to the next layer.
*/
if (pdulen == 0) {
/*
* Free zero-length buffer
*/
vup->vu_stats.hva_st_ng.ng_badpdu++;
vup->vu_pif.pif_ierrors++;
if (aal == VATMPIF_AAL_5)
vup->vu_stats.hva_st_aal5.aal5_pdu_errs++;
err = EIO;
KB_FREEALL(m);
goto failed;
}
/* TODO: process the AAL4 CRC, AAL5 CRC,
* then update aal5_crc_len, aal5_drops, aal5_pdu_crc,
* aal5_pdu_errs, aal5_pdu_drops ...
*/
/*
* Quick count the PDU
*/
vup->vu_pif.pif_ipdus++;
vup->vu_pif.pif_ibytes += pdulen;
vup->vu_stats.hva_st_ng.ng_rx_pdu++;
vup->vu_stats.hva_st_atm.atm_rcvd += (pdulen + 47) / 48;
/*
* Update the VCC statistics:
* XXX: This code should not be into the driver.
*/
vcp = vvp->vv_connvc->cvc_vcc;
if (vcp) {
vcp->vc_ipdus++;
vcp->vc_ibytes += pdulen;
/*
* Update the NIF statistics if any
* XXX: beurk !
*/
if (vcp->vc_nif) {
vcp->vc_nif->nif_ibytes += pdulen;
vcp->vc_nif->nif_if.if_ipackets++;
vcp->vc_nif->nif_if.if_ibytes += pdulen;
}
}
/*
* The STACK_CALL needs to happen at splnet() in order
* for the stack sequence processing to work. Schedule an
* interrupt queue callback at splnet().
*/
/*
* Prepend callback function pointer and token value to buffer.
* We have already guaranteed that the space is available in the
* first buffer because the vatmpif_header structure is greater
* than our callback pointer.
* XXX
*/
KB_HEADADJ(m, sizeof(atm_intr_func_t) + sizeof(void *));
KB_DATASTART(m, cp, caddr_t);
*((atm_intr_func_t *) cp) = vatmpif_harp_recv_stack;
cp += sizeof (atm_intr_func_t);
*((void **)cp) = (void *)vvp;
/*
* Schedule callback
*/
if (!netisr_queue(NETISR_ATM, m)) {
/*
* queue is full. Unable to pass up to the HARP stack
* Update the stats.
*/
vup->vu_stats.hva_st_ng.ng_rx_iqfull++;
vup->vu_pif.pif_ierrors++;
goto failed;
}
/* Done */
return (0);
failed:
return (err);
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2003 Harti Brandt.
* Copyright (c) 2003 Vincent Jardin.
* 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$
*/
/*
* Supported AALs
*/
enum vatmpif_aal {
VATMPIF_AAL_0 = 0, /* Cell Service */
VATMPIF_AAL_4 = 4, /* AAL 3/4 */
VATMPIF_AAL_5 = 5, /* AAL 5 */
};
typedef enum vatmpif_aal Vatmpif_aal;
/*
* Supported traffic type
*/
enum vatmpif_traffic_type {
VATMPIF_TRAF_CBR = 0x01, /* Constant bit rate */
VATMPIF_TRAF_VBR = 0x02, /* Variable bit rate */
VATMPIF_TRAF_ABR = 0x03, /* Available Bit Rate */
VATMPIF_TRAF_UBR = 0x04, /* Unspecified bit rate */
};
typedef enum vatmpif_traffic_type Vatmpif_traffic_type;
typedef struct t_atm_traffic Vatmpif_traffic;
/*
* Host protocol control blocks
*
*/
/*
* Device VCC Entry
*
* Contains the common (vv_cmn) and specific information for each VCC
* which is opened through a ATM PIF node.
* It is a virtual VCC. From the Netgraph poit of view it is a
* per-node's hook private data.
*
* It is a polymorph object with the instances of Cmn_vcc.
*/
struct vatmpif_vcc {
Cmn_vcc vv_cmn; /* Common VCC stuff */
Vatmpif_aal vv_aal; /* AAL */
Vatmpif_traffic vv_traffic; /* forward and backward ATM traffic */
Vatmpif_traffic_type vv_traffic_type;/* CBR, VBR, UBR, ... */
};
typedef struct vatmpif_vcc Vatmpif_vcc;
#define vv_next vv_cmn.cv_next
#define vv_toku vv_cmn.cv_toku
#define vv_upper vv_cmn.cv_upper
#define vv_connvc vv_cmn.cv_connvc
#define vv_state vv_cmn.cv_state
/*
* The hook structure describes a virtual link
*/
struct ng_vatmpif_hook {
hook_p hook; /* netgraph hook */
Vatmpif_stats stats; /* link stats */
uint32_t InSeq; /* last received sequence number + 1 */
uint32_t OutSeq; /* last sent sequence number */
uint32_t cur_pcr; /* slot's reserved PCR */
};
/*
* Device Virtual Unit Structure
*
* Contains all the information for a single device (adapter).
* It is a virtual device. From the Netgraph point of view it is
* a per-node private data.
*
* It is a polymorph object with the instances of Cmn_unit.
*/
struct vatmpif_unit {
Cmn_unit vu_cmn; /* Common unit stuff */
node_p node; /* netgraph node */
struct ng_vatmpif_hook* link; /* virtual link hoook */
struct ng_vatmpif_config conf; /* node configuration */
};
typedef struct vatmpif_unit Vatmpif_unit;
#define ng_vatmpif_private vatmpif_unit
typedef struct ng_vatmpif_private *priv_p;
#define vu_pif vu_cmn.cu_pif
#define vu_unit vu_cmn.cu_unit
#define vu_flags vu_cmn.cu_flags
#define vu_mtu vu_cmn.cu_mtu
#define vu_open_vcc vu_cmn.cu_open_vcc
#define vu_vcc vu_cmn.cu_vcc
#define vu_vcc_zone vu_cmn.cu_vcc_zone
#define vu_nif_zone vu_cmn.cu_nif_zone
#define vu_ioctl vu_cmn.cu_ioctl
#define vu_instvcc vu_cmn.cu_instvcc
#define vu_openvcc vu_cmn.cu_openvcc
#define vu_closevcc vu_cmn.cu_closevcc
#define vu_output vu_cmn.cu_output
#define vu_config vu_cmn.cu_config
#define vu_softc vu_cmn.cu_softc
#define vu_stats link->stats
#define vu_cur_pcr link->cur_pcr
/*
* Netgraph to HARP API
*/
int vatmpif_harp_attach(node_p node);
int vatmpif_harp_detach(node_p node);
int vatmpif_harp_recv_drain(Vatmpif_unit *vup, KBuffer *m,
uint8_t vpi, uint16_t vci, uint8_t pt, uint8_t clp, Vatmpif_aal aal);
/*
* HARP to Netgraph API
*/
int ng_atmpif_transmit(const priv_p priv, struct mbuf *m,
uint8_t vpi, uint16_t vci, uint8_t pt, uint8_t clp, Vatmpif_aal aal);
extern uma_zone_t vatmpif_nif_zone;
extern uma_zone_t vatmpif_vcc_zone;

View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2003 Harti Brandt.
* Copyright (c) 2003 Vincent Jardin.
* 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 _NETGRAPH_ATM_NG_ATMPIF_H_
#define _NETGRAPH_ATM_NG_ATMPIF_H_
/* Node type name and magic cookie */
#define NG_ATMPIF_NODE_TYPE "atmpif"
#define NGM_ATMPIF_COOKIE 967239456
/*
* Physical device name - used to configure HARP devices
*/
#ifndef VATMPIF_DEV_NAME
#define VATMPIF_DEV_NAME "hva" /* HARP Virtual ATM */
#endif
#define VATMPIF_MAX_VCI 65535
#define VATMPIF_MAX_VPI 255
/* Hook name */
#define NG_ATMPIF_HOOK_LINK "link" /* virtual link hook */
/*
* Node configuration structure
*/
struct ng_vatmpif_config {
uint8_t debug; /* debug bit field (see below) */
uint32_t pcr; /* peak cell rate */
Mac_addr macaddr; /* Mac Address */
};
/* Keep this in sync with the above structure definition */
#define NG_ATMPIF_CONFIG_TYPE_INFO { \
{ "debug", &ng_parse_uint8_type }, \
{ "pcr", &ng_parse_uint32_type }, \
{ "macaddr", &ng_mac_addr_type }, \
{ NULL } \
}
/*
* Debug bit-fields
*/
#define VATMPIF_DEBUG_NONE 0x00
#define VATMPIF_DEBUG_PACKET 0x01 /* enable ng_atmpif debugging */
#define IS_VATMPIF_DEBUG_PACKET(a) ( (a) \
&& ((a)->conf.debug & VATMPIF_DEBUG_PACKET) )
/*
* Statistics
*/
struct hva_stats_ng {
uint32_t ng_errseq; /* Duplicate or out of order */
uint32_t ng_lostpdu; /* PDU lost detected */
uint32_t ng_badpdu; /* Unknown PDU type */
uint32_t ng_rx_novcc; /* Draining PDU on closed VCC */
uint32_t ng_rx_iqfull; /* PDU drops, no room in atm_intrq */
uint32_t ng_tx_rawcell; /* PDU raw cells transmitted */
uint32_t ng_rx_rawcell; /* PDU raw cells received */
uint64_t ng_tx_pdu; /* PDU transmitted */
uint64_t ng_rx_pdu; /* PDU received */
};
typedef struct hva_stats_ng Hva_Stats_ng;
/* Keep this in sync with the above structure definition */
#define HVA_STATS_NG_TYPE_INFO \
{ "errSeqOrder", &ng_parse_uint32_type }, \
{ "errLostPDU", &ng_parse_uint32_type }, \
{ "recvBadPDU", &ng_parse_uint32_type }, \
{ "ErrATMVC", &ng_parse_uint32_type }, \
{ "ErrQfull", &ng_parse_uint32_type }, \
{ "xmitRawCell", &ng_parse_uint32_type }, \
{ "recvRawCell", &ng_parse_uint32_type }, \
{ "xmitPDU", &ng_parse_uint64_type }, \
{ "recvPDU", &ng_parse_uint64_type },
struct hva_stats_atm {
uint64_t atm_xmit; /* Cells transmitted */
uint64_t atm_rcvd; /* Cells received */
};
typedef struct hva_stats_atm Hva_Stats_atm;
/* Keep this in sync with the above structure definition */
#define HVA_STATS_ATM_NG_TYPE_INFO \
{ "xmitATMCells", &ng_parse_uint64_type }, \
{ "recvATMCells", &ng_parse_uint64_type },
struct hva_stats_aal5 {
uint64_t aal5_xmit; /* Cells transmitted */
uint64_t aal5_rcvd; /* Cells received */
uint32_t aal5_crc_len; /* Cells with CRC/length errors */
uint32_t aal5_drops; /* Cell drops */
uint64_t aal5_pdu_xmit; /* CS PDUs transmitted */
uint64_t aal5_pdu_rcvd; /* CS PDUs received */
uint32_t aal5_pdu_crc; /* CS PDUs with CRC errors */
uint32_t aal5_pdu_errs; /* CS layer protocol errors */
uint32_t aal5_pdu_drops; /* CS PDUs dropped */
};
typedef struct hva_stats_aal5 Hva_Stats_aal5;
/* Keep this in sync with the above structure definition */
#define HVA_STATS_AAL5_NG_TYPE_INFO \
{ "xmitAAL5Cells", &ng_parse_uint64_type }, \
{ "recvAAL5Cells", &ng_parse_uint64_type }, \
{ "AAL5ErrCRCCells", &ng_parse_uint32_type }, \
{ "AAL5DropsCells", &ng_parse_uint32_type }, \
{ "xmitAAL5PDU", &ng_parse_uint64_type }, \
{ "recvAAL5PDU", &ng_parse_uint64_type }, \
{ "AAL5CRCPDU", &ng_parse_uint32_type }, \
{ "AAL5ErrPDU", &ng_parse_uint32_type }, \
{ "AAL5DropsPDU", &ng_parse_uint32_type },
struct vatmpif_stats {
Hva_Stats_ng hva_st_ng; /* Netgraph layer stats */
Hva_Stats_atm hva_st_atm; /* ATM layer stats */
Hva_Stats_aal5 hva_st_aal5; /* AAL5 layer stats */
};
typedef struct vatmpif_stats Vatmpif_stats;
/* Keep this in sync with the above structure definition */
#define NG_ATMPIF_STATS_TYPE_INFO { \
HVA_STATS_NG_TYPE_INFO \
HVA_STATS_ATM_NG_TYPE_INFO \
HVA_STATS_AAL5_NG_TYPE_INFO \
{ NULL } \
}
/* Structure returned by NGM_ATMPIF_GET_LINK_STATUS */
struct ng_atmpif_link_status {
uint32_t InSeq; /* last received sequence number + 1 */
uint32_t OutSeq; /* last sent sequence number */
uint32_t cur_pcr; /* slot's reserved PCR */
};
/* Keep this in sync with the above structure definition */
#define NG_ATMPIF_LINK_STATUS_TYPE_INFO { \
{ "InSeq", &ng_parse_uint32_type }, \
{ "OutSeq", &ng_parse_uint32_type }, \
{ "cur_pcr", &ng_parse_uint32_type }, \
{ NULL } \
}
/* Netgraph control messages */
enum {
NGM_ATMPIF_SET_CONFIG = 1, /* set node configuration */
NGM_ATMPIF_GET_CONFIG, /* get node configuration */
NGM_ATMPIF_GET_LINK_STATUS, /* get link status */
NGM_ATMPIF_GET_STATS, /* get link stats */
NGM_ATMPIF_CLR_STATS, /* clear link stats */
NGM_ATMPIF_GETCLR_STATS, /* atomically get & clear link stats */
};
#endif /* _NETGRAPH_NG_ATMPIF_H_ */