diff options
Diffstat (limited to 'sys/netgraph/atm/atmpif/ng_atmpif_harp.c')
-rw-r--r-- | sys/netgraph/atm/atmpif/ng_atmpif_harp.c | 933 |
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); +} |