summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/atm/atmpif/ng_atmpif_harp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netgraph/atm/atmpif/ng_atmpif_harp.c')
-rw-r--r--sys/netgraph/atm/atmpif/ng_atmpif_harp.c933
1 files changed, 933 insertions, 0 deletions
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 <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);
+}
OpenPOWER on IntegriCloud