From e6ffc57441a25e3a8cab5d8757dd6c94416ae90f Mon Sep 17 00:00:00 2001 From: harti Date: Mon, 11 Aug 2003 08:40:02 +0000 Subject: Add ng_atmpif: a HARP physical interface emulation. This allows one to run the HARP ATM stack without real hardware. Submitted by: Vincent Jardin --- sys/netgraph/atm/atmpif/ng_atmpif.c | 708 +++++++++++++++++++++++ sys/netgraph/atm/atmpif/ng_atmpif_harp.c | 933 +++++++++++++++++++++++++++++++ sys/netgraph/atm/atmpif/ng_atmpif_var.h | 147 +++++ sys/netgraph/atm/ng_atmpif.h | 175 ++++++ 4 files changed, 1963 insertions(+) create mode 100644 sys/netgraph/atm/atmpif/ng_atmpif.c create mode 100644 sys/netgraph/atm/atmpif/ng_atmpif_harp.c create mode 100644 sys/netgraph/atm/atmpif/ng_atmpif_var.h create mode 100644 sys/netgraph/atm/ng_atmpif.h (limited to 'sys/netgraph') diff --git a/sys/netgraph/atm/atmpif/ng_atmpif.c b/sys/netgraph/atm/atmpif/ng_atmpif.c new file mode 100644 index 0000000..b79117a --- /dev/null +++ b/sys/netgraph/atm/atmpif/ng_atmpif.c @@ -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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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); +} diff --git a/sys/netgraph/atm/atmpif/ng_atmpif_harp.c b/sys/netgraph/atm/atmpif/ng_atmpif_harp.c new file mode 100644 index 0000000..261107b --- /dev/null +++ b/sys/netgraph/atm/atmpif/ng_atmpif_harp.c @@ -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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* + * 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); +} diff --git a/sys/netgraph/atm/atmpif/ng_atmpif_var.h b/sys/netgraph/atm/atmpif/ng_atmpif_var.h new file mode 100644 index 0000000..f295461 --- /dev/null +++ b/sys/netgraph/atm/atmpif/ng_atmpif_var.h @@ -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; diff --git a/sys/netgraph/atm/ng_atmpif.h b/sys/netgraph/atm/ng_atmpif.h new file mode 100644 index 0000000..b45df75 --- /dev/null +++ b/sys/netgraph/atm/ng_atmpif.h @@ -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_ */ -- cgit v1.1