/* * Copyright (c) 2007-2008 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* */ /* Module Name : htr.c */ /* */ /* Abstract */ /* This module contains Tx and Rx functions. */ /* */ /* NOTES */ /* None */ /* */ /************************************************************************/ #include "cprecomp.h" u16_t zfWlanRxValidate(zdev_t* dev, zbuf_t* buf); u16_t zfWlanRxFilter(zdev_t* dev, zbuf_t* buf); const u8_t zgSnapBridgeTunnel[6] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8 }; const u8_t zgSnap8021h[6] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00 }; /* Table for converting IP DSCP P2-P0 bits to 802.11e Access Category */ const u8_t zcUpToAc[8] = {0, 1, 1, 0, 2, 2, 3, 3}; //WMM default //const u8_t zcUpToAc[8] = {0, 1, 1, 0, 0, 0, 0, 0}; //For 2 TxQ //const u8_t zcUpToAc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; //For single TxQ const u8_t zcMaxspToPktNum[4] = {8, 2, 4, 6}; u8_t zfGetEncryModeFromRxStatus(struct zsAdditionInfo* addInfo) { u8_t securityByte; u8_t encryMode; securityByte = (addInfo->Tail.Data.SAIndex & 0xc0) >> 4; /* byte4 */ securityByte |= (addInfo->Tail.Data.DAIndex & 0xc0) >> 6; /* byte5 */ switch( securityByte ) { case ZM_NO_WEP: case ZM_WEP64: case ZM_WEP128: case ZM_WEP256: #ifdef ZM_ENABLE_CENC case ZM_CENC: #endif //ZM_ENABLE_CENC case ZM_TKIP: case ZM_AES: encryMode = securityByte; break; default: if ( (securityByte & 0xf8) == 0x08 ) { // decrypted by software } encryMode = ZM_NO_WEP; break; } return encryMode; } void zfGetRxIvIcvLength(zdev_t* dev, zbuf_t* buf, u8_t vap, u16_t* pIvLen, u16_t* pIcvLen, struct zsAdditionInfo* addInfo) { u16_t wdsPort; u8_t encryMode; zmw_get_wlan_dev(dev); *pIvLen = 0; *pIcvLen = 0; encryMode = zfGetEncryModeFromRxStatus(addInfo); if ( wd->wlanMode == ZM_MODE_AP ) { if (vap < ZM_MAX_AP_SUPPORT) { if (( wd->ap.encryMode[vap] == ZM_WEP64 ) || ( wd->ap.encryMode[vap] == ZM_WEP128 ) || ( wd->ap.encryMode[vap] == ZM_WEP256 )) { *pIvLen = 4; *pIcvLen = 4; } else { u16_t id; u16_t addr[3]; addr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); addr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); addr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); /* Find STA's information */ if ((id = zfApFindSta(dev, addr)) != 0xffff) { if (wd->ap.staTable[id].encryMode == ZM_TKIP) { *pIvLen = 8; *pIcvLen = 4; } else if (wd->ap.staTable[id].encryMode == ZM_AES) { *pIvLen = 8; *pIcvLen = 8; // AES MIC //*pIcvLen = 0; } #ifdef ZM_ENABLE_CENC else if (wd->ap.staTable[id].encryMode == ZM_CENC) { *pIvLen = 18; *pIcvLen= 16; } #endif //ZM_ENABLE_CENC } } /* WDS port checking */ if ((wdsPort = vap - 0x20) >= ZM_MAX_WDS_SUPPORT) { wdsPort = 0; } switch (wd->ap.wds.encryMode[wdsPort]) { case ZM_WEP64: case ZM_WEP128: case ZM_WEP256: *pIvLen = 4; *pIcvLen = 4; break; case ZM_TKIP: *pIvLen = 8; *pIcvLen = 4; break; case ZM_AES: *pIvLen = 8; *pIcvLen = 0; break; #ifdef ZM_ENABLE_CENC case ZM_CENC: *pIvLen = 18; *pIcvLen = 16; break; #endif //ZM_ENABLE_CENC }/* end of switch */ } } else if ( wd->wlanMode == ZM_MODE_PSEUDO) { /* test: 6518 for QA auto test */ switch (encryMode) { case ZM_WEP64: case ZM_WEP128: case ZM_WEP256: *pIvLen = 4; *pIcvLen = 4; break; case ZM_TKIP: *pIvLen = 8; *pIcvLen = 4; break; case ZM_AES: *pIvLen = 8; *pIcvLen = 0; break; #ifdef ZM_ENABLE_CENC case ZM_CENC: *pIvLen = 18; *pIcvLen = 16; #endif //ZM_ENABLE_CENC }/* end of switch */ } else { if ( (encryMode == ZM_WEP64)|| (encryMode == ZM_WEP128)|| (encryMode == ZM_WEP256) ) { *pIvLen = 4; *pIcvLen = 4; } else if ( encryMode == ZM_TKIP ) { *pIvLen = 8; *pIcvLen = 4; } else if ( encryMode == ZM_AES ) { *pIvLen = 8; *pIcvLen = 8; // AES MIC } #ifdef ZM_ENABLE_CENC else if ( encryMode == ZM_CENC) { *pIvLen = 18; *pIcvLen= 16; } #endif //ZM_ENABLE_CENC } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfAgingDefragList */ /* Force flushing whole defrag list or aging the buffer */ /* in the defrag list. */ /* */ /* INPUTS */ /* dev : device pointer */ /* flushFlag : 1=>flushing, 0=>Aging */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen Chen Atheros Communications, INC. 2007.1 */ /* */ /************************************************************************/ void zfAgingDefragList(zdev_t* dev, u16_t flushFlag) { u16_t i, j; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); for(i=0; idefragTable.defragEntry[i].fragCount != 0 ) { if (((wd->tick - wd->defragTable.defragEntry[i].tick) > (ZM_DEFRAG_AGING_TIME_SEC * ZM_TICK_PER_SECOND)) || (flushFlag != 0)) { zm_msg1_rx(ZM_LV_2, "Aging defrag list :", i); /* Free the buffers in the defrag list */ for (j=0; jdefragTable.defragEntry[i].fragCount; j++) { zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[j], 0); } } } wd->defragTable.defragEntry[i].fragCount = 0; } zmw_leave_critical_section(dev); return; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfAddFirstFragToDefragList */ /* Add first fragment to defragment list, the first empty entry */ /* will be selected. If the list is full, sequentially select */ /* one entry for replacement. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : first fragment buffer */ /* addr : address of first fragment buffer */ /* seqNum : sequence of first fragment buffer */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen Chen Atheros Communications, INC. 2007.1 */ /* */ /************************************************************************/ void zfAddFirstFragToDefragList(zdev_t* dev, zbuf_t* buf, u8_t* addr, u16_t seqNum) { u16_t i, j; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); /* Find an empty one in defrag list */ for(i=0; idefragTable.defragEntry[i].fragCount == 0 ) { break; } } /* If full, sequentially replace existing one */ if (i == ZM_MAX_DEFRAG_ENTRIES) { i = wd->defragTable.replaceNum++ & (ZM_MAX_DEFRAG_ENTRIES-1); /* Free the buffers in the defrag list to be replaced */ for (j=0; jdefragTable.defragEntry[i].fragCount; j++) { zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[j], 0); } } wd->defragTable.defragEntry[i].fragCount = 1; wd->defragTable.defragEntry[i].fragment[0] = buf; wd->defragTable.defragEntry[i].seqNum = seqNum; wd->defragTable.defragEntry[i].tick = wd->tick; for (j=0; j<6; j++) { wd->defragTable.defragEntry[i].addr[j] = addr[j]; } zmw_leave_critical_section(dev); return; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfAddFragToDefragList */ /* Add middle or last fragment to defragment list. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : first fragment buffer */ /* addr : address of fragment buffer */ /* seqNum : sequence fragment buffer */ /* fragNum : fragment number of fragment buffer */ /* moreFrag : more frag bit of fragment buffer */ /* addInfo : addition info of fragment buffer */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen Chen Atheros Communications, INC. 2007.1 */ /* */ /************************************************************************/ zbuf_t* zfAddFragToDefragList(zdev_t* dev, zbuf_t* buf, u8_t* addr, u16_t seqNum, u8_t fragNum, u8_t moreFrag, struct zsAdditionInfo* addInfo) { u16_t i, j, k; zbuf_t* returnBuf = NULL; u16_t defragDone = 0; u16_t lenErr = 0; u16_t startAddr, fragHead, frameLen, ivLen, icvLen; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); /* Find frag in the defrag list */ for(i=0; idefragTable.defragEntry[i].fragCount != 0 ) { /* Compare address */ for (j=0; j<6; j++) { if (addr[j] != wd->defragTable.defragEntry[i].addr[j]) { break; } } if (j == 6) { /* Compare sequence and fragment number */ if (seqNum == wd->defragTable.defragEntry[i].seqNum) { if ((fragNum == wd->defragTable.defragEntry[i].fragCount) && (fragNum < 8)) { /* Add frag frame to defrag list */ wd->defragTable.defragEntry[i].fragment[fragNum] = buf; wd->defragTable.defragEntry[i].fragCount++; defragDone = 1; if (moreFrag == 0) { /* merge all fragment if more data bit is cleared */ returnBuf = wd->defragTable.defragEntry[i].fragment[0]; startAddr = zfwBufGetSize(dev, returnBuf); /* skip WLAN header 24(Data) or 26(QoS Data) */ fragHead = 24 + ((zmw_rx_buf_readh(dev, returnBuf, 0) & 0x80) >> 6); zfGetRxIvIcvLength(dev, returnBuf, 0, &ivLen, &icvLen, addInfo); fragHead += ivLen; /* skip IV */ for(k=1; kdefragTable.defragEntry[i].fragCount; k++) { frameLen = zfwBufGetSize(dev, wd->defragTable.defragEntry[i].fragment[k]); if ((startAddr+frameLen-fragHead) < 1560) { zfRxBufferCopy(dev, returnBuf, wd->defragTable.defragEntry[i].fragment[k], startAddr, fragHead, frameLen-fragHead); startAddr += (frameLen-fragHead); } else { lenErr = 1; } zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[k], 0); } wd->defragTable.defragEntry[i].fragCount = 0; zfwBufSetSize(dev, returnBuf, startAddr); } break; } } } } } zmw_leave_critical_section(dev); if (lenErr == 1) { zfwBufFree(dev, returnBuf, 0); return NULL; } if (defragDone == 0) { zfwBufFree(dev, buf, 0); return NULL; } return returnBuf; } /* return value = NULL => save or free this frame */ zbuf_t* zfDefragment(zdev_t* dev, zbuf_t* buf, u8_t* pbIsDefrag, struct zsAdditionInfo* addInfo) { u8_t fragNum; u16_t seqNum; u8_t moreFragBit; u8_t addr[6]; u16_t i; zmw_get_wlan_dev(dev); ZM_BUFFER_TRACE(dev, buf) *pbIsDefrag = FALSE; seqNum = zmw_buf_readh(dev, buf, 22); fragNum = (u8_t)(seqNum & 0xf); moreFragBit = (zmw_buf_readb(dev, buf, 1) & ZM_BIT_2) >> 2; if ((fragNum == 0) && (moreFragBit == 0)) { /* Not part of a fragmentation */ return buf; } else { wd->commTally.swRxFragmentCount++; seqNum = seqNum >> 4; for (i=0; i<6; i++) { addr[i] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+i); } if (fragNum == 0) { /* more frag = 1 */ /* First part of a fragmentation */ zm_msg1_rx(ZM_LV_2, "First Frag, seq=", seqNum); zfAddFirstFragToDefragList(dev, buf, addr, seqNum); buf = NULL; } else { /* Middle or last part of a fragmentation */ zm_msg1_rx(ZM_LV_2, "Frag seq=", seqNum); zm_msg1_rx(ZM_LV_2, "Frag moreFragBit=", moreFragBit); buf = zfAddFragToDefragList(dev, buf, addr, seqNum, fragNum, moreFragBit, addInfo); if (buf != NULL) { *pbIsDefrag = TRUE; } } } return buf; } #if ZM_PROTOCOL_RESPONSE_SIMULATION u16_t zfSwap(u16_t num) { return ((num >> 8) + ((num & 0xff) << 8)); } void zfProtRspSim(zdev_t* dev, zbuf_t* buf) { u16_t ethType; u16_t arpOp; u16_t prot; u16_t temp; u16_t i; u16_t dip[2]; u16_t dstPort; u16_t srcPort; ethType = zmw_rx_buf_readh(dev, buf, 12); zm_msg2_rx(ZM_LV_2, "ethType=", ethType); /* ARP */ if (ethType == 0x0608) { arpOp = zmw_rx_buf_readh(dev, buf, 20); dip[0] = zmw_rx_buf_readh(dev, buf, 38); dip[1] = zmw_rx_buf_readh(dev, buf, 40); zm_msg2_rx(ZM_LV_2, "arpOp=", arpOp); zm_msg2_rx(ZM_LV_2, "ip0=", dip[0]); zm_msg2_rx(ZM_LV_2, "ip1=", dip[1]); //ARP request to 192.168.1.15 if ((arpOp == 0x0100) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01)); { zm_msg0_rx(ZM_LV_2, "ARP"); /* ARP response */ zmw_rx_buf_writeh(dev, buf, 20, 0x0200); /* dst hardware address */ /* src hardware address */ //zmw_rx_buf_writeh(dev, buf, 6, 0xa000); //zmw_rx_buf_writeh(dev, buf, 8, 0x0000); //zmw_rx_buf_writeh(dev, buf, 10, 0x0000); /* dst ip address */ for (i=0; i<5; i++) { temp = zmw_rx_buf_readh(dev, buf, 22+(i*2)); zmw_rx_buf_writeh(dev, buf, 32+(i*2), temp); } /* src hardware address */ zmw_rx_buf_writeh(dev, buf, 22, 0xa000); zmw_rx_buf_writeh(dev, buf, 24, 0x0000); zmw_rx_buf_writeh(dev, buf, 26, 0x0000); /* src ip address */ zmw_rx_buf_writeh(dev, buf, 28, 0xa8c0); zmw_rx_buf_writeh(dev, buf, 30, 0x0f01); } } /* ICMP */ else if (ethType == 0x0008) { zm_msg0_rx(ZM_LV_2, "IP"); prot = zmw_rx_buf_readb(dev, buf, 23); dip[0] = zmw_rx_buf_readh(dev, buf, 30); dip[1] = zmw_rx_buf_readh(dev, buf, 32); zm_msg2_rx(ZM_LV_2, "prot=", prot); zm_msg2_rx(ZM_LV_2, "ip0=", dip[0]); zm_msg2_rx(ZM_LV_2, "ip1=", dip[1]); /* PING request to 192.168.1.15 */ if ((prot == 0x1) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01)) { zm_msg0_rx(ZM_LV_2, "ICMP"); /* change dst */ for (i=0; i<3; i++) { temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); zmw_rx_buf_writeh(dev, buf, i*2, temp); } /* change src */ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); zmw_rx_buf_writeh(dev, buf, 8, 0x0000); zmw_rx_buf_writeh(dev, buf, 10, 0x0000); /* exchange src ip and dst ip */ for (i=0; i<2; i++) { temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); } zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); /* change icmp type to echo reply */ zmw_rx_buf_writeb(dev, buf, 34, 0x0); /* update icmp checksum */ temp = zmw_rx_buf_readh(dev, buf, 36); temp += 8; zmw_rx_buf_writeh(dev, buf, 36, temp); } else if (prot == 0x6) { zm_msg0_rx(ZM_LV_2, "TCP"); srcPort = zmw_rx_buf_readh(dev, buf, 34); dstPort = zmw_rx_buf_readh(dev, buf, 36); zm_msg2_rx(ZM_LV_2, "Src Port=", srcPort); zm_msg2_rx(ZM_LV_2, "Dst Port=", dstPort); if ((dstPort == 0x1500) || (srcPort == 0x1500)) { zm_msg0_rx(ZM_LV_2, "FTP"); /* change dst */ for (i=0; i<3; i++) { temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); zmw_rx_buf_writeh(dev, buf, i*2, temp); } /* change src */ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); zmw_rx_buf_writeh(dev, buf, 8, 0x0000); zmw_rx_buf_writeh(dev, buf, 10, 0x0000); /* exchange src ip and dst ip */ for (i=0; i<2; i++) { temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); } zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); #if 0 /* Patch src port */ temp = zmw_rx_buf_readh(dev, buf, 34); temp = zfSwap(zfSwap(temp) + 1); zmw_rx_buf_writeh(dev, buf, 34, temp); temp = zmw_rx_buf_readh(dev, buf, 38); temp = zfSwap(zfSwap(temp) + 1); zmw_rx_buf_writeh(dev, buf, 38, temp); /* Patch checksum */ temp = zmw_rx_buf_readh(dev, buf, 50); temp = zfSwap(temp); temp = ~temp; temp += 2; temp = ~temp; temp = zfSwap(temp); zmw_rx_buf_writeh(dev, buf, 50, temp); #endif } } else if (prot == 0x11) { /* change dst */ for (i=0; i<3; i++) { temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); zmw_rx_buf_writeh(dev, buf, i*2, temp); } /* change src */ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); zmw_rx_buf_writeh(dev, buf, 8, 0x0000); zmw_rx_buf_writeh(dev, buf, 10, 0x0000); zm_msg0_rx(ZM_LV_2, "UDP"); srcPort = zmw_rx_buf_readh(dev, buf, 34); dstPort = zmw_rx_buf_readh(dev, buf, 36); zm_msg2_rx(ZM_LV_2, "Src Port=", srcPort); zm_msg2_rx(ZM_LV_2, "Dst Port=", dstPort); /* exchange src ip and dst ip */ for (i=0; i<2; i++) { temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); } zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); /* exchange port */ zmw_rx_buf_writeh(dev, buf, 34, srcPort+1); zmw_rx_buf_writeh(dev, buf, 36, dstPort); /* checksum = 0 */ zmw_rx_buf_writeh(dev, buf, 40, 0); } } else if (ethType == 0x0060) /* =>0x0060 is port */ { /* change src for Evl tool loop back receive */ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); zmw_rx_buf_writeh(dev, buf, 8, 0x0000); zmw_rx_buf_writeh(dev, buf, 10, 0x0000); } } #endif /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfiTxSendEth */ /* Called to native 802.11 management frames */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : buffer pointer */ /* port : WLAN port, 0=>standard, 0x1-0x7=>VAP, 0x20-0x25=>WDS */ /* */ /* OUTPUTS */ /* error code */ /* */ /* AUTHOR */ /* Ray ZyDAS Technology Corporation 2005.5 */ /* */ /************************************************************************/ u16_t zfiTxSend80211Mgmt(zdev_t* dev, zbuf_t* buf, u16_t port) { u16_t err; //u16_t addrTblSize = 0; //struct zsAddrTbl addrTbl; u16_t hlen; u16_t header[(24+25+1)/2]; int i; for(i=0;i<12;i++) { header[i] = zmw_buf_readh(dev, buf, i); } hlen = 24; zfwBufRemoveHead(dev, buf, 24); if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0, 0)) != ZM_SUCCESS) { goto zlError; } return 0; zlError: zfwBufFree(dev, buf, 0); return 0; } u8_t zfiIsTxQueueFull(zdev_t* dev) { zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); if ((((wd->vtxqHead[0] + 1) & ZM_VTXQ_SIZE_MASK) != wd->vtxqTail[0]) ) { zmw_leave_critical_section(dev); return 0; } else { zmw_leave_critical_section(dev); return 1; } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfiTxSendEth */ /* Called to transmit Ethernet frame from upper layer. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : buffer pointer */ /* port : WLAN port, 0=>standard, 0x1-0x7=>VAP, 0x20-0x25=>WDS */ /* */ /* OUTPUTS */ /* error code */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.5 */ /* */ /************************************************************************/ u16_t zfiTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port) { u16_t err, ret; zmw_get_wlan_dev(dev); ZM_PERFORMANCE_TX_MSDU(dev, wd->tick); zm_msg1_tx(ZM_LV_2, "zfiTxSendEth(), port=", port); /* Return error if port is disabled */ if ((err = zfTxPortControl(dev, buf, port)) == ZM_PORT_DISABLED) { err = ZM_ERR_TX_PORT_DISABLED; goto zlError; } #if 1 if ((wd->wlanMode == ZM_MODE_AP) && (port < 0x20)) { /* AP : Buffer frame for power saving STA */ if ((ret = zfApBufferPsFrame(dev, buf, port)) == 1) { return ZM_SUCCESS; } } else #endif if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) { if ( zfPowerSavingMgrIsSleeping(dev) ) { /*check ZM_ENABLE_POWER_SAVE flag*/ zfPowerSavingMgrWakeup(dev); } } #ifdef ZM_ENABLE_IBSS_PS /* IBSS power-saving mode */ else if ( wd->wlanMode == ZM_MODE_IBSS ) { if ( zfStaIbssPSQueueData(dev, buf) ) { return ZM_SUCCESS; } } #endif #if 1 //if ( wd->bQoSEnable ) if (1) { /* Put to VTXQ[ac] */ ret = zfPutVtxq(dev, buf); /* Push VTXQ[ac] */ zfPushVtxq(dev); } else { ret = zfTxSendEth(dev, buf, port, ZM_EXTERNAL_ALLOC_BUF, 0); } return ret; #else return zfTxSendEth(dev, buf, port, ZM_EXTERNAL_ALLOC_BUF, 0); #endif zlError: zm_msg2_tx(ZM_LV_1, "Tx Comp err=", err); zfwBufFree(dev, buf, err); return err; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfTxSendEth */ /* Called to transmit Ethernet frame from upper layer. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : buffer pointer */ /* port : WLAN port, 0=>standard, 0x10-0x17=>VAP, 0x20-0x25=>WDS */ /* */ /* OUTPUTS */ /* error code */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.5 */ /* */ /************************************************************************/ u16_t zfTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u16_t flag) { u16_t err; //u16_t addrTblSize; //struct zsAddrTbl addrTbl; u16_t removeLen; u16_t header[(8+30+2+18)/2]; /* ctr+(4+a1+a2+a3+2+a4)+qos+iv */ u16_t headerLen; u16_t mic[8/2]; u16_t micLen; u16_t snap[8/2]; u16_t snapLen; u16_t fragLen; u16_t frameLen; u16_t fragNum; struct zsFrag frag; u16_t i, j, id; u16_t offset; u16_t da[3]; u16_t sa[3]; u8_t up; u8_t qosType, keyIdx = 0; u16_t fragOff; u16_t newFlag; struct zsMicVar* pMicKey; u8_t tkipFrameOffset = 0; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); newFlag = flag & 0xff00; flag = flag & 0xff; zm_msg1_tx(ZM_LV_2, "zfTxSendEth(), port=", port); /* Get IP TOS for QoS AC and IP frag offset */ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); //EOSP bit if (newFlag & 0x100) { up |= 0x10; } #ifdef ZM_ENABLE_NATIVE_WIFI if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { /* DA */ da[0] = zmw_tx_buf_readh(dev, buf, 16); da[1] = zmw_tx_buf_readh(dev, buf, 18); da[2] = zmw_tx_buf_readh(dev, buf, 20); /* SA */ sa[0] = zmw_tx_buf_readh(dev, buf, 10); sa[1] = zmw_tx_buf_readh(dev, buf, 12); sa[2] = zmw_tx_buf_readh(dev, buf, 14); } else if ( wd->wlanMode == ZM_MODE_IBSS ) { /* DA */ da[0] = zmw_tx_buf_readh(dev, buf, 4); da[1] = zmw_tx_buf_readh(dev, buf, 6); da[2] = zmw_tx_buf_readh(dev, buf, 8); /* SA */ sa[0] = zmw_tx_buf_readh(dev, buf, 10); sa[1] = zmw_tx_buf_readh(dev, buf, 12); sa[2] = zmw_tx_buf_readh(dev, buf, 14); } else if ( wd->wlanMode == ZM_MODE_AP ) { /* DA */ da[0] = zmw_tx_buf_readh(dev, buf, 4); da[1] = zmw_tx_buf_readh(dev, buf, 6); da[2] = zmw_tx_buf_readh(dev, buf, 8); /* SA */ sa[0] = zmw_tx_buf_readh(dev, buf, 16); sa[1] = zmw_tx_buf_readh(dev, buf, 18); sa[2] = zmw_tx_buf_readh(dev, buf, 20); } else { // } #else /* DA */ da[0] = zmw_tx_buf_readh(dev, buf, 0); da[1] = zmw_tx_buf_readh(dev, buf, 2); da[2] = zmw_tx_buf_readh(dev, buf, 4); /* SA */ sa[0] = zmw_tx_buf_readh(dev, buf, 6); sa[1] = zmw_tx_buf_readh(dev, buf, 8); sa[2] = zmw_tx_buf_readh(dev, buf, 10); #endif //Decide Key Index in ATOM, No meaning in OTUS--CWYang(m) if (wd->wlanMode == ZM_MODE_AP) { keyIdx = wd->ap.bcHalKeyIdx[port]; id = zfApFindSta(dev, da); if (id != 0xffff) { switch (wd->ap.staTable[id].encryMode) { case ZM_AES: case ZM_TKIP: #ifdef ZM_ENABLE_CENC case ZM_CENC: #endif //ZM_ENABLE_CENC keyIdx = wd->ap.staTable[id].keyIdx; break; } } } else { switch (wd->sta.encryMode) { case ZM_WEP64: case ZM_WEP128: case ZM_WEP256: keyIdx = wd->sta.keyId; break; case ZM_AES: case ZM_TKIP: if ((da[0] & 0x1)) keyIdx = 5; else keyIdx = 4; break; #ifdef ZM_ENABLE_CENC case ZM_CENC: keyIdx = wd->sta.cencKeyId; break; #endif //ZM_ENABLE_CENC } } /* Create SNAP */ removeLen = zfTxGenWlanSnap(dev, buf, snap, &snapLen); //zm_msg1_tx(ZM_LV_0, "fragOff=", fragOff); /* ********************************************************************************************** */ /* Add 20071025 Mxzeng */ /* ********************************************************************************************** */ /* ---------------------------------------------------------------------------------------------- */ /* Ethernet : frameLen = zfwBufGetSize(dev, buf); */ /* ---+--6--+--6--+--2--+-----20-----+-------------------------+------ Variable -------+--------- */ /* | DA | SA | Type| IP Header | TCP(20) UDP(12) ICMP(8) | Application Payload L | */ /* ---+-----+-----+-----+------------+-------------------------+-----------------------+--------- */ /* MSDU = 6 + 6 + 2 + ( Network Layer header ) + ( Transport Layer header ) + L */ /* */ /* MSDU - DA - SA : frameLen -= removeLen; */ /* ---+--2--+-----20-----+-------------------------+------ Variable -------+--------------------- */ /* | Type| IP Header | TCP(20) UDP(12) ICMP(8) | Application Payload L | */ /* ---+-----+------------+-------------------------+-----------------------+--------------------- */ /* */ /* MPDU : frameLen + mpduLengthOffset ; */ /* -+---2---+----2---+-6-+-6-+--6--+---2----+--1--+--1-+---1---+-------3------+-frameLen-+---4--+- */ /* | frame |duration| DA|SA |BSSID|sequence|SNAP |SNAP|Control| RFC 1042 | | FCS | */ /* |Control| | | | | number |DSAP |SSAP| | encapsulation| | | */ /* -+-------+--------+---+---+-----+--------+-----+----+-------+--------------+----------+------+- */ /* ----------------------------------------------------------------------------------------------- */ if ( wd->sta.encryMode == ZM_TKIP ) tkipFrameOffset = 8; fragLen = wd->fragThreshold + tkipFrameOffset; // Fragmentation threshold for MPDU Lengths frameLen = zfwBufGetSize(dev, buf); // MSDU Lengths frameLen -= removeLen; // MSDU Lengths - DA - SA /* #1st create MIC Length manually */ micLen = 0; /* Access Category */ if (wd->wlanMode == ZM_MODE_AP) { zfApGetStaQosType(dev, da, &qosType); if (qosType == 0) { up = 0; } } else if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) { if (wd->sta.wmeConnected == 0) { up = 0; } } else { /* TODO : STA QoS control field */ up = 0; } /* #2nd Assign sequence number */ zmw_enter_critical_section(dev); frag.seq[0] = ((wd->seq[zcUpToAc[up&0x7]]++) << 4); zmw_leave_critical_section(dev); /* #3rd Pass the total payload to generate MPDU length ! */ frag.buf[0] = buf; frag.bufType[0] = bufType; frag.flag[0] = (u8_t)flag; fragNum = 1; headerLen = zfTxGenWlanHeader(dev, frag.buf[0], header, frag.seq[0], frag.flag[0], snapLen+micLen, removeLen, port, da, sa, up, &micLen, snap, snapLen, NULL); //zm_debug_msg1("#1 headerLen = ", headerLen); /* #4th Check the HeaderLen and determine whether the MPDU Lengths bigger than Fragmentation threshold */ /* If MPDU Lengths large than fragmentation threshold --> headerLen = 0 */ if( headerLen != 0 ) { zf80211FrameSend(dev, frag.buf[0], header, snapLen, da, sa, up, headerLen, snap, mic, micLen, removeLen, frag.bufType[0], zcUpToAc[up&0x7], keyIdx); } else //if( headerLen == 0 ) // Need to be fragmented { u16_t mpduLengthOffset; u16_t pseudSnapLen = 0; mpduLengthOffset = header[0] - frameLen; // For fragmentation threshold ! micLen = zfTxGenWlanTail(dev, buf, snap, snapLen, mic); // Get snap and mic information fragLen = fragLen - mpduLengthOffset; //zm_debug_msg1("#2 frameLen = ", frameLen); //zm_debug_msg1("#3 fragThreshold = ", fragLen); /* fragmentation */ if (frameLen >= fragLen) { //copy fragLen to frag i = 0; while( frameLen > 0 ) { if ((frag.buf[i] = zfwBufAllocate(dev, fragLen+32)) != NULL) { frag.bufType[i] = ZM_INTERNAL_ALLOC_BUF; frag.seq[i] = frag.seq[0] + i; offset = removeLen + i*fragLen; /* Consider the offset if we consider snap length to the other fragmented frame */ if ( i >= 1 ) offset = offset + pseudSnapLen*(i-1); if (frameLen > fragLen + pseudSnapLen) { frag.flag[i] = flag | 0x4; /* More data */ /* First fragment */ if (i == 0) { /* Add SNAP */ for (j=0; j>1)]); } zfTxBufferCopy(dev, frag.buf[i], buf, snapLen, offset, fragLen); zfwBufSetSize(dev, frag.buf[i], snapLen+fragLen); /* Add pseud snap length to the other fragmented frame */ pseudSnapLen = snapLen; frameLen -= fragLen; } /* Intermediate Fragment */ else { //zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, fragLen); //zfwBufSetSize(dev, frag.buf[i], fragLen); zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, fragLen+pseudSnapLen ); zfwBufSetSize(dev, frag.buf[i], fragLen+pseudSnapLen); frameLen -= (fragLen+pseudSnapLen); } //frameLen -= fragLen; } else { /* Last fragment */ zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, frameLen); /* Add MIC if need */ if ( micLen ) { zfCopyToRxBuffer(dev, frag.buf[i], (u8_t*) mic, frameLen, micLen); } zfwBufSetSize(dev, frag.buf[i], frameLen+micLen); frameLen = 0; frag.flag[i] = (u8_t)flag; /* No more data */ } i++; } else { break; } // Please pay attention to the index of the buf !!! // If write to null buf , the OS will crash !!! zfwCopyBufContext(dev, buf, frag.buf[i-1]); } fragNum = i; snapLen = micLen = removeLen = 0; zfwBufFree(dev, buf, 0); } for (i=0; istandard, 10-17=>Virtual AP, 20-25=>WDS */ /* */ /* OUTPUTS */ /* ZM_PORT_ENABLED or ZM_PORT_DISABLE */ /* */ /* AUTHOR */ /* Signature ZyDAS Technology Corporation 2005.4 */ /* */ /************************************************************************/ u16_t zfTxPortControl(zdev_t* dev, zbuf_t* buf, u16_t port) { zmw_get_wlan_dev(dev); if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { if ( wd->sta.adapterState == ZM_STA_STATE_DISCONNECT ) { zm_msg0_tx(ZM_LV_3, "Packets dropped due to disconnect state"); return ZM_PORT_DISABLED; } } return ZM_PORT_ENABLED; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfIdlRecv */ /* Do frame validation and filtering then pass to zfwRecv80211(). */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : received 802.11 frame buffer. */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.10 */ /* */ /************************************************************************/ void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo) { u16_t ret = 0; u16_t bssid[3]; struct agg_tid_rx *tid_rx; zmw_get_wlan_dev(dev); ZM_BUFFER_TRACE(dev, buf) /* tally */ wd->commTally.DriverRxFrmCnt++; bssid[0] = zmw_buf_readh(dev, buf, 16); bssid[1] = zmw_buf_readh(dev, buf, 18); bssid[2] = zmw_buf_readh(dev, buf, 20); /* Validate Rx frame */ if ((ret = zfWlanRxValidate(dev, buf)) != ZM_SUCCESS) { zm_msg1_rx(ZM_LV_1, "Rx invalid:", ret); goto zlError; } #ifdef ZM_ENABLE_AGGREGATION //#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION /* * add by honda */ tid_rx = zfAggRxEnabled(dev, buf); if (tid_rx && wd->reorder) { zfAggRx(dev, buf, addInfo, tid_rx); return; } /* * end of add by honda */ //#endif #endif /* Filter Rx frame */ if ((ret = zfWlanRxFilter(dev, buf)) != ZM_SUCCESS) { zm_msg1_rx(ZM_LV_1, "Rx duplicated:", ret); goto zlError; } /* Discard error frame except mic failure */ if ((addInfo->Tail.Data.ErrorIndication & 0x3f) != 0) { if ( wd->XLinkMode && ((addInfo->Tail.Data.ErrorIndication & 0x3f)==0x10) && zfCompareWithBssid(dev, bssid) ) { // Bypass frames !!! } else { goto zlError; } } /* OTUS command-8212 dump rx packet */ if (wd->rxPacketDump) { zfwDumpBuf(dev, buf); } /* Call zfwRecv80211() wrapper function to deliver Rx packet */ /* to driver framework. */ if (wd->zfcbRecv80211 != NULL) { wd->zfcbRecv80211(dev, buf, addInfo); //CWYang(m) } else { zfiRecv80211(dev, buf, addInfo); } return; zlError: zm_msg1_rx(ZM_LV_1, "Free packet, error code:", ret); wd->commTally.DriverDiscardedFrm++; /* Free Rx buffer */ zfwBufFree(dev, buf, 0); return; } void zfShowRxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset) { u8_t packetType, keyType, code, identifier, type, flags; u16_t packetLen, keyInfo, keyLen, keyDataLen, length, Op_Code; u32_t replayCounterH, replayCounterL, vendorId, VendorType; /* EAPOL packet type */ packetType = zmw_rx_buf_readb(dev, buf, offset+1); // 0: EAP-Packet // 1: EAPOL-Start // 2: EAPOL-Logoff // 3: EAPOL-Key // 4: EAPOL-Encapsulated-ASF-Alert /* EAPOL frame format */ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ /* ----------------------------------------------- */ /* PAE Ethernet Type (0x888e) */ /* ----------------------------------------------- 2 */ /* Protocol Version | Type */ /* ----------------------------------------------- 4 */ /* Length */ /* ----------------------------------------------- 6 */ /* Packet Body */ /* ----------------------------------------------- N */ /* EAPOL body length */ packetLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+2)) << 8) + zmw_rx_buf_readb(dev, buf, offset+3); if( packetType == 0 ) { // EAP-Packet /* EAP-Packet Code */ code = zmw_rx_buf_readb(dev, buf, offset+4); // 1 : Request // 2 : Response // 3 : Success // 4 : Failure // An EAP packet of the type of Success and Failure has no Data field, and has a length of 4. /* EAP Packet format */ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ /* ----------------------------------------------- */ /* Code | Identifier */ /* ----------------------------------------------- 2 */ /* Length */ /* ----------------------------------------------- 4 */ /* Data */ /* ----------------------------------------------- N */ zm_debug_msg0("EAP-Packet"); zm_debug_msg1("Packet Length = ", packetLen); zm_debug_msg1("EAP-Packet Code = ", code); if( code == 1 ) { zm_debug_msg0("EAP-Packet Request"); /* EAP-Packet Identifier */ identifier = zmw_rx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + zmw_rx_buf_readb(dev, buf, offset+7); /* EAP-Packet Type */ type = zmw_rx_buf_readb(dev, buf, offset+8); // 1 : Identity // 2 : Notification // 3 : Nak (Response Only) // 4 : MD5-Challenge // 5 : One Time Password (OTP) // 6 : Generic Token Card (GTC) // 254 : (Expanded Types)Wi-Fi Protected Setup // 255 : Experimental Use /* The data field in an EAP packet of the type of Request or Response is in the format shown bellowing */ /* 0 1 2 3 4 5 6 7 N */ /* ----------------------------------------------- */ /* Type | Type Data */ /* ----------------------------------------------- */ zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); zm_debug_msg1("EAP-Packet Type = ", type); if( type == 1 ) { zm_debug_msg0("EAP-Packet Request Identity"); } else if( type == 2 ) { zm_debug_msg0("EAP-Packet Request Notification"); } else if( type == 4 ) { zm_debug_msg0("EAP-Packet Request MD5-Challenge"); } else if( type == 5 ) { zm_debug_msg0("EAP-Packet Request One Time Password"); } else if( type == 6 ) { zm_debug_msg0("EAP-Packet Request Generic Token Card"); } else if( type == 254 ) { zm_debug_msg0("EAP-Packet Request Wi-Fi Protected Setup"); /* 0 1 2 3 */ /* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Type | Vendor-Id |*/ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Vendor-Type |*/ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Vendor data... */ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* EAP-Packet Vendor ID */ vendorId = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 8) + zmw_rx_buf_readb(dev, buf, offset+11); /* EAP-Packet Vendor Type */ VendorType = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+12)) << 24) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 8) + zmw_rx_buf_readb(dev, buf, offset+15); /* EAP-Packet Op Code */ Op_Code = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+16)) << 8) + zmw_rx_buf_readb(dev, buf, offset+17); /* EAP-Packet Flags */ flags = zmw_rx_buf_readb(dev, buf, offset+18); zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); zm_debug_msg1("EAP-Packet Flags = ", flags); } } else if( code == 2 ) { zm_debug_msg0("EAP-Packet Response"); /* EAP-Packet Identifier */ identifier = zmw_rx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + zmw_rx_buf_readb(dev, buf, offset+7); /* EAP-Packet Type */ type = zmw_rx_buf_readb(dev, buf, offset+8); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); zm_debug_msg1("EAP-Packet Type = ", type); if( type == 1 ) { zm_debug_msg0("EAP-Packet Response Identity"); } else if( type == 2 ) { zm_debug_msg0("EAP-Packet Request Notification"); } else if( type == 3 ) { zm_debug_msg0("EAP-Packet Request Nak"); } else if( type == 4 ) { zm_debug_msg0("EAP-Packet Request MD5-Challenge"); } else if( type == 5 ) { zm_debug_msg0("EAP-Packet Request One Time Password"); } else if( type == 6 ) { zm_debug_msg0("EAP-Packet Request Generic Token Card"); } else if( type == 254 ) { zm_debug_msg0("EAP-Packet Response Wi-Fi Protected Setup"); /* EAP-Packet Vendor ID */ vendorId = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 8) + zmw_rx_buf_readb(dev, buf, offset+11); /* EAP-Packet Vendor Type */ VendorType = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+12)) << 24) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 8) + zmw_rx_buf_readb(dev, buf, offset+15); /* EAP-Packet Op Code */ Op_Code = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+16)) << 8) + zmw_rx_buf_readb(dev, buf, offset+17); /* EAP-Packet Flags */ flags = zmw_rx_buf_readb(dev, buf, offset+18); zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); zm_debug_msg1("EAP-Packet Flags = ", flags); } } else if( code == 3 ) { zm_debug_msg0("EAP-Packet Success"); /* EAP-Packet Identifier */ identifier = zmw_rx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + zmw_rx_buf_readb(dev, buf, offset+7); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); } else if( code == 4 ) { zm_debug_msg0("EAP-Packet Failure"); /* EAP-Packet Identifier */ identifier = zmw_rx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + zmw_rx_buf_readb(dev, buf, offset+7); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); } } else if( packetType == 1 ) { // EAPOL-Start zm_debug_msg0("EAPOL-Start"); } else if( packetType == 2 ) { // EAPOL-Logoff zm_debug_msg0("EAPOL-Logoff"); } else if( packetType == 3 ) { // EAPOL-Key /* EAPOL-Key type */ keyType = zmw_rx_buf_readb(dev, buf, offset+4); /* EAPOL-Key information */ keyInfo = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+5)) << 8) + zmw_rx_buf_readb(dev, buf, offset+6); /* EAPOL-Key length */ keyLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+7)) << 8) + zmw_rx_buf_readb(dev, buf, offset+8); /* EAPOL-Key replay counter (high double word) */ replayCounterH = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 24) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+11)) << 8) + zmw_rx_buf_readb(dev, buf, offset+12); /* EAPOL-Key replay counter (low double word) */ replayCounterL = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 24) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 16) + (((u32_t) zmw_rx_buf_readb(dev, buf, offset+15)) << 8) + zmw_rx_buf_readb(dev, buf, offset+16); /* EAPOL-Key data length */ keyDataLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+97)) << 8) + zmw_rx_buf_readb(dev, buf, offset+98); zm_debug_msg0("EAPOL-Key"); zm_debug_msg1("packet length = ", packetLen); if ( keyType == 254 ) { zm_debug_msg0("key type = 254 (SSN key descriptor)"); } else { zm_debug_msg2("key type = 0x", keyType); } zm_debug_msg2("replay counter(L) = ", replayCounterL); zm_debug_msg2("key information = ", keyInfo); if ( keyInfo & ZM_BIT_3 ) { zm_debug_msg0(" - pairwise key"); } else { zm_debug_msg0(" - group key"); } if ( keyInfo & ZM_BIT_6 ) { zm_debug_msg0(" - Tx key installed"); } else { zm_debug_msg0(" - Tx key not set"); } if ( keyInfo & ZM_BIT_7 ) { zm_debug_msg0(" - Ack needed"); } else { zm_debug_msg0(" - Ack not needed"); } if ( keyInfo & ZM_BIT_8 ) { zm_debug_msg0(" - MIC set"); } else { zm_debug_msg0(" - MIC not set"); } if ( keyInfo & ZM_BIT_9 ) { zm_debug_msg0(" - packet encrypted"); } else { zm_debug_msg0(" - packet not encrypted"); } zm_debug_msg1("keyLen = ", keyLen); zm_debug_msg1("keyDataLen = ", keyDataLen); } else if( packetType == 4 ) { zm_debug_msg0("EAPOL-Encapsulated-ASF-Alert"); } } void zfShowTxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset) { u8_t packetType, keyType, code, identifier, type, flags; u16_t packetLen, keyInfo, keyLen, keyDataLen, length, Op_Code; u32_t replayCounterH, replayCounterL, vendorId, VendorType; zmw_get_wlan_dev(dev); zm_debug_msg1("EAPOL Packet size = ", zfwBufGetSize(dev, buf)); /* EAPOL packet type */ // 0: EAP-Packet // 1: EAPOL-Start // 2: EAPOL-Logoff // 3: EAPOL-Key // 4: EAPOL-Encapsulated-ASF-Alert /* EAPOL frame format */ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ /* ----------------------------------------------- */ /* PAE Ethernet Type (0x888e) */ /* ----------------------------------------------- 2 */ /* Protocol Version | Type */ /* ----------------------------------------------- 4 */ /* Length */ /* ----------------------------------------------- 6 */ /* Packet Body */ /* ----------------------------------------------- N */ packetType = zmw_tx_buf_readb(dev, buf, offset+1); /* EAPOL body length */ packetLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+2)) << 8) + zmw_tx_buf_readb(dev, buf, offset+3); if( packetType == 0 ) { // EAP-Packet /* EAP-Packet Code */ code = zmw_tx_buf_readb(dev, buf, offset+4); // 1 : Request // 2 : Response // 3 : Success // 4 : Failure // An EAP packet of the type of Success and Failure has no Data field, and has a length of 4. /* EAP Packet format */ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ /* ----------------------------------------------- */ /* Code | Identifier */ /* ----------------------------------------------- 2 */ /* Length */ /* ----------------------------------------------- 4 */ /* Data */ /* ----------------------------------------------- N */ zm_debug_msg0("EAP-Packet"); zm_debug_msg1("Packet Length = ", packetLen); zm_debug_msg1("EAP-Packet Code = ", code); if( code == 1 ) { zm_debug_msg0("EAP-Packet Request"); /* EAP-Packet Identifier */ identifier = zmw_tx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + zmw_tx_buf_readb(dev, buf, offset+7); /* EAP-Packet Type */ type = zmw_tx_buf_readb(dev, buf, offset+8); // 1 : Identity // 2 : Notification // 3 : Nak (Response Only) // 4 : MD5-Challenge // 5 : One Time Password (OTP) // 6 : Generic Token Card (GTC) // 254 : (Expanded Types)Wi-Fi Protected Setup // 255 : Experimental Use /* The data field in an EAP packet of the type of Request or Response is in the format shown bellowing */ /* 0 1 2 3 4 5 6 7 N */ /* ----------------------------------------------- */ /* Type | Type Data */ /* ----------------------------------------------- */ zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); zm_debug_msg1("EAP-Packet Type = ", type); if( type == 1 ) { zm_debug_msg0("EAP-Packet Request Identity"); } else if( type == 2 ) { zm_debug_msg0("EAP-Packet Request Notification"); } else if( type == 4 ) { zm_debug_msg0("EAP-Packet Request MD5-Challenge"); } else if( type == 5 ) { zm_debug_msg0("EAP-Packet Request One Time Password"); } else if( type == 6 ) { zm_debug_msg0("EAP-Packet Request Generic Token Card"); } else if( type == 254 ) { zm_debug_msg0("EAP-Packet Request Wi-Fi Protected Setup"); /* 0 1 2 3 */ /* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Type | Vendor-Id |*/ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Vendor-Type |*/ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ /*| Vendor data... */ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* EAP-Packet Vendor ID */ vendorId = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 8) + zmw_tx_buf_readb(dev, buf, offset+11); /* EAP-Packet Vendor Type */ VendorType = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+12)) << 24) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 8) + zmw_tx_buf_readb(dev, buf, offset+15); /* EAP-Packet Op Code */ Op_Code = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+16)) << 8) + zmw_tx_buf_readb(dev, buf, offset+17); /* EAP-Packet Flags */ flags = zmw_tx_buf_readb(dev, buf, offset+18); zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); zm_debug_msg1("EAP-Packet Flags = ", flags); } } else if( code == 2 ) { zm_debug_msg0("EAP-Packet Response"); /* EAP-Packet Identifier */ identifier = zmw_tx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + zmw_tx_buf_readb(dev, buf, offset+7); /* EAP-Packet Type */ type = zmw_tx_buf_readb(dev, buf, offset+8); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); zm_debug_msg1("EAP-Packet Type = ", type); if( type == 1 ) { zm_debug_msg0("EAP-Packet Response Identity"); } else if( type == 2 ) { zm_debug_msg0("EAP-Packet Request Notification"); } else if( type == 3 ) { zm_debug_msg0("EAP-Packet Request Nak"); } else if( type == 4 ) { zm_debug_msg0("EAP-Packet Request MD5-Challenge"); } else if( type == 5 ) { zm_debug_msg0("EAP-Packet Request One Time Password"); } else if( type == 6 ) { zm_debug_msg0("EAP-Packet Request Generic Token Card"); } else if( type == 254 ) { zm_debug_msg0("EAP-Packet Response Wi-Fi Protected Setup"); /* EAP-Packet Vendor ID */ vendorId = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 8) + zmw_tx_buf_readb(dev, buf, offset+11); /* EAP-Packet Vendor Type */ VendorType = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+12)) << 24) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 8) + zmw_tx_buf_readb(dev, buf, offset+15); /* EAP-Packet Op Code */ Op_Code = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+16)) << 8) + zmw_tx_buf_readb(dev, buf, offset+17); /* EAP-Packet Flags */ flags = zmw_tx_buf_readb(dev, buf, offset+18); zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); zm_debug_msg1("EAP-Packet Flags = ", flags); } } else if( code == 3 ) { zm_debug_msg0("EAP-Packet Success"); /* EAP-Packet Identifier */ identifier = zmw_rx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + zmw_rx_buf_readb(dev, buf, offset+7); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); } else if( code == 4 ) { zm_debug_msg0("EAP-Packet Failure"); /* EAP-Packet Identifier */ identifier = zmw_tx_buf_readb(dev, buf, offset+5); /* EAP-Packet Length */ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + zmw_tx_buf_readb(dev, buf, offset+7); zm_debug_msg1("EAP-Packet Identifier = ", identifier); zm_debug_msg1("EAP-Packet Length = ", length); } } else if( packetType == 1 ) { // EAPOL-Start zm_debug_msg0("EAPOL-Start"); } else if( packetType == 2 ) { // EAPOL-Logoff zm_debug_msg0("EAPOL-Logoff"); } else if( packetType == 3 ) { // EAPOL-Key /* EAPOL-Key type */ keyType = zmw_tx_buf_readb(dev, buf, offset+4); /* EAPOL-Key information */ keyInfo = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+5)) << 8) + zmw_tx_buf_readb(dev, buf, offset+6); /* EAPOL-Key length */ keyLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+7)) << 8) + zmw_tx_buf_readb(dev, buf, offset+8); /* EAPOL-Key replay counter (high double word) */ replayCounterH = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 24) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+11)) << 8) + zmw_tx_buf_readb(dev, buf, offset+12); /* EAPOL-Key replay counter (low double word) */ replayCounterL = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 24) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 16) + (((u32_t) zmw_tx_buf_readb(dev, buf, offset+15)) << 8) + zmw_tx_buf_readb(dev, buf, offset+16); /* EAPOL-Key data length */ keyDataLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+97)) << 8) + zmw_tx_buf_readb(dev, buf, offset+98); zm_debug_msg0("EAPOL-Key"); zm_debug_msg1("packet length = ", packetLen); if ( keyType == 254 ) { zm_debug_msg0("key type = 254 (SSN key descriptor)"); } else { zm_debug_msg2("key type = 0x", keyType); } zm_debug_msg2("replay counter(L) = ", replayCounterL); zm_debug_msg2("key information = ", keyInfo); if ( keyInfo & ZM_BIT_3 ) { zm_debug_msg0(" - pairwise key"); } else { zm_debug_msg0(" - group key"); } if ( keyInfo & ZM_BIT_6 ) { zm_debug_msg0(" - Tx key installed"); } else { zm_debug_msg0(" - Tx key not set"); } if ( keyInfo & ZM_BIT_7 ) { zm_debug_msg0(" - Ack needed"); } else { zm_debug_msg0(" - Ack not needed"); } if ( keyInfo & ZM_BIT_8 ) { zm_debug_msg0(" - MIC set"); } else { zm_debug_msg0(" - MIC not set"); } if ( keyInfo & ZM_BIT_9 ) { zm_debug_msg0(" - packet encrypted"); } else { zm_debug_msg0(" - packet not encrypted"); } zm_debug_msg1("keyLen = ", keyLen); zm_debug_msg1("keyDataLen = ", keyDataLen); } else if( packetType == 4 ) { zm_debug_msg0("EAPOL-Encapsulated-ASF-Alert"); } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfiRecv80211 */ /* Called to receive 802.11 frame. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : received 802.11 frame buffer. */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.5 */ /* */ /************************************************************************/ void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo) { u8_t snapCase=0, encryMode; u16_t frameType, typeLengthField; u16_t frameCtrl; u16_t frameSubtype; u16_t ret; u16_t len; u8_t bIsDefrag = 0; u16_t offset, tailLen; u8_t vap = 0; u16_t da[3], sa[3]; u16_t ii; u8_t uapsdTrig = 0; zbuf_t* psBuf; #ifdef ZM_ENABLE_NATIVE_WIFI u8_t i; #endif zmw_get_wlan_dev(dev); ZM_BUFFER_TRACE(dev, buf) //zm_msg2_rx(ZM_LV_2, "zfiRecv80211(), buf=", buf); //zm_msg2_rx(ZM_LV_0, "h[0]=", zmw_rx_buf_readh(dev, buf, 0)); //zm_msg2_rx(ZM_LV_0, "h[2]=", zmw_rx_buf_readh(dev, buf, 2)); //zm_msg2_rx(ZM_LV_0, "h[4]=", zmw_rx_buf_readh(dev, buf, 4)); frameCtrl = zmw_rx_buf_readb(dev, buf, 0); frameType = frameCtrl & 0xf; frameSubtype = frameCtrl & 0xf0; #if 0 // Move to ProcessBeacon to judge if there's a new peer station if ( (wd->wlanMode == ZM_MODE_IBSS)&& (wd->sta.ibssPartnerStatus != ZM_IBSS_PARTNER_ALIVE) ) { zfStaIbssMonitoring(dev, buf); } #endif /* If data frame */ if (frameType == ZM_WLAN_DATA_FRAME) { wd->sta.TotalNumberOfReceivePackets++; wd->sta.TotalNumberOfReceiveBytes += zfwBufGetSize(dev, buf); //zm_debug_msg1("Receive packets = ", wd->sta.TotalNumberOfReceivePackets); //zm_msg0_rx(ZM_LV_0, "Rx data"); if (wd->wlanMode == ZM_MODE_AP) { if ((ret = zfApUpdatePsBit(dev, buf, &vap, &uapsdTrig)) != ZM_SUCCESS) { zfwBufFree(dev, buf, 0); return; } if (((uapsdTrig&0xf) != 0) && ((frameSubtype & 0x80) != 0)) { u8_t ac = zcUpToAc[zmw_buf_readb(dev, buf, 24)&0x7]; u8_t pktNum; u8_t mb; u16_t flag; u8_t src[6]; //printk("QoS ctrl=%d\n", zmw_buf_readb(dev, buf, 24)); //printk("UAPSD trigger, ac=%d\n", ac); if (((0x8>>ac) & uapsdTrig) != 0) { pktNum = zcMaxspToPktNum[(uapsdTrig>>4) & 0x3]; for (ii=0; ii<6; ii++) { src[ii] = zmw_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+ii); } for (ii=0; iiap.uapsdQ)) != NULL) if ((psBuf = zfQueueGetWithMac(dev, wd->ap.uapsdQ, src, &mb)) != NULL) { if ((ii+1) == pktNum) { //EOSP anyway flag = 0x100 | (mb<<5); } else { if (mb != 0) { //more data, not EOSP flag = 0x20; } else { //no more data, EOSP flag = 0x100; } } zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, flag); } if ((psBuf == NULL) || (mb == 0)) { if ((ii == 0) && (psBuf == NULL)) { zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_QOS_NULL, (u16_t*)src, 0, 0, 0); } break; } } } } } else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { u16_t frameCtrlMSB; u8_t bssid[6]; /* Check Is RIFS frame and decide to enable RIFS or not */ if( wd->sta.EnableHT ) zfCheckIsRIFSFrame(dev, buf, frameSubtype); if ( zfPowerSavingMgrIsSleeping(dev) || wd->sta.psMgr.tempWakeUp == 1) { frameCtrlMSB = zmw_rx_buf_readb(dev, buf, 1); /* check more data */ if ( frameCtrlMSB & ZM_BIT_5 ) { //if rx frame's AC is not delivery-enabled if ((wd->sta.qosInfo&0xf) != 0xf) { u8_t rxAc = 0; if ((frameSubtype & 0x80) != 0) { rxAc = zcUpToAc[zmw_buf_readb(dev, buf, 24)&0x7]; } if (((0x8>>rxAc) & wd->sta.qosInfo) == 0) { zfSendPSPoll(dev); wd->sta.psMgr.tempWakeUp = 0; } } } } /*increase beacon count when receive vaild data frame from AP*/ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid); if (zfStaIsConnected(dev)&& zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6)) { wd->sta.rxBeaconCount++; } } zm_msg1_rx(ZM_LV_2, "Rx VAP=", vap); /* handle IV, EXT-IV, ICV, and EXT-ICV */ zfGetRxIvIcvLength(dev, buf, vap, &offset, &tailLen, addInfo); zfStaIbssPSCheckState(dev, buf); //QoS data frame if ((frameSubtype & 0x80) == 0x80) { offset += 2; } len = zfwBufGetSize(dev, buf); /* remove ICV */ if (tailLen > 0) { if (len > tailLen) { len -= tailLen; zfwBufSetSize(dev, buf, len); } } /* Filter NULL data */ if (((frameSubtype&0x40) != 0) || ((len = zfwBufGetSize(dev, buf))<=24)) { zm_msg1_rx(ZM_LV_1, "Free Rx NULL data, len=", len); zfwBufFree(dev, buf, 0); return; } /* check and handle defragmentation */ if ( wd->sta.bSafeMode && (wd->sta.wepStatus == ZM_ENCRYPTION_AES) && wd->sta.SWEncryptEnable ) { zm_msg0_rx(ZM_LV_1, "Bypass defragmentation packets in safe mode"); } else { if ( (buf = zfDefragment(dev, buf, &bIsDefrag, addInfo)) == NULL ) { /* In this case, the buffer has been freed in zfDefragment */ return; } } ret = ZM_MIC_SUCCESS; /* If SW WEP/TKIP are not turned on */ if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_DECRY_EN) == 0 && (wd->sta.SWEncryptEnable & ZM_SW_WEP_DECRY_EN) == 0) { encryMode = zfGetEncryModeFromRxStatus(addInfo); /* check if TKIP */ if ( encryMode == ZM_TKIP ) { if ( bIsDefrag ) { ret = zfMicRxVerify(dev, buf); } else { /* check MIC failure bit */ if ( ZM_RX_STATUS_IS_MIC_FAIL(addInfo) ) { ret = ZM_MIC_FAILURE; } } if ( ret == ZM_MIC_FAILURE ) { u8_t Unicast_Pkt = 0x0; if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) { wd->commTally.swRxUnicastMicFailCount++; Unicast_Pkt = 0x1; }/* else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) { wd->commTally.swRxMulticastMicFailCount++; }*/ else { wd->commTally.swRxMulticastMicFailCount++; } if ( wd->wlanMode == ZM_MODE_AP ) { u16_t idx; u8_t addr[6]; for (idx=0; idx<6; idx++) { addr[idx] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+idx); } if (wd->zfcbApMicFailureNotify != NULL) { wd->zfcbApMicFailureNotify(dev, addr, buf); } } else { if(Unicast_Pkt) { zm_debug_msg0("Countermeasure : Unicast_Pkt "); } else { zm_debug_msg0("Countermeasure : Non-Unicast_Pkt "); } if((wd->TKIP_Group_KeyChanging == 0x0) || (Unicast_Pkt == 0x1)) { zm_debug_msg0("Countermeasure : Do MIC Check "); zfStaMicFailureHandling(dev, buf); } else { zm_debug_msg0("Countermeasure : SKIP MIC Check due to Group Keychanging "); } } /* Discard MIC failed frame */ zfwBufFree(dev, buf, 0); return; } } } else { u8_t IsEncryFrame; /* TODO: Check whether WEP bit is turned on in MAC header */ encryMode = ZM_NO_WEP; IsEncryFrame = (zmw_rx_buf_readb(dev, buf, 1) & 0x40); if (IsEncryFrame) { /* Software decryption for TKIP */ if (wd->sta.SWEncryptEnable & ZM_SW_TKIP_DECRY_EN) { u16_t iv16; u16_t iv32; u8_t RC4Key[16]; u16_t IvOffset; struct zsTkipSeed *rxSeed; IvOffset = offset + ZM_SIZE_OF_WLAN_DATA_HEADER; rxSeed = zfStaGetRxSeed(dev, buf); if (rxSeed == NULL) { zm_debug_msg0("rxSeed is NULL"); /* Discard this frame */ zfwBufFree(dev, buf, 0); return; } iv16 = (zmw_rx_buf_readb(dev, buf, IvOffset) << 8) + zmw_rx_buf_readb(dev, buf, IvOffset+2); iv32 = zmw_rx_buf_readb(dev, buf, IvOffset+4) + (zmw_rx_buf_readb(dev, buf, IvOffset+5) << 8) + (zmw_rx_buf_readb(dev, buf, IvOffset+6) << 16) + (zmw_rx_buf_readb(dev, buf, IvOffset+7) << 24); /* TKIP Key Mixing */ zfTkipPhase1KeyMix(iv32, rxSeed); zfTkipPhase2KeyMix(iv16, rxSeed); zfTkipGetseeds(iv16, RC4Key, rxSeed); /* Decrypt Data */ ret = zfTKIPDecrypt(dev, buf, IvOffset+ZM_SIZE_OF_IV+ZM_SIZE_OF_EXT_IV, 16, RC4Key); if (ret == ZM_ICV_FAILURE) { zm_debug_msg0("TKIP ICV fail"); /* Discard ICV failed frame */ zfwBufFree(dev, buf, 0); return; } /* Remove ICV from buffer */ zfwBufSetSize(dev, buf, len-4); /* Check MIC */ ret = zfMicRxVerify(dev, buf); if (ret == ZM_MIC_FAILURE) { if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) { wd->commTally.swRxUnicastMicFailCount++; } else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) { wd->commTally.swRxMulticastMicFailCount++; } else { wd->commTally.swRxMulticastMicFailCount++; } if ( wd->wlanMode == ZM_MODE_AP ) { u16_t idx; u8_t addr[6]; for (idx=0; idx<6; idx++) { addr[idx] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+idx); } if (wd->zfcbApMicFailureNotify != NULL) { wd->zfcbApMicFailureNotify(dev, addr, buf); } } else { zfStaMicFailureHandling(dev, buf); } zm_debug_msg0("MIC fail"); /* Discard MIC failed frame */ zfwBufFree(dev, buf, 0); return; } encryMode = ZM_TKIP; offset += ZM_SIZE_OF_IV + ZM_SIZE_OF_EXT_IV; } else if(wd->sta.SWEncryptEnable & ZM_SW_WEP_DECRY_EN) { u16_t IvOffset; u8_t keyLen = 5; u8_t iv[3]; u8_t *wepKey; u8_t keyIdx; IvOffset = offset + ZM_SIZE_OF_WLAN_DATA_HEADER; /* Retrieve IV */ iv[0] = zmw_rx_buf_readb(dev, buf, IvOffset); iv[1] = zmw_rx_buf_readb(dev, buf, IvOffset+1); iv[2] = zmw_rx_buf_readb(dev, buf, IvOffset+2); keyIdx = ((zmw_rx_buf_readb(dev, buf, IvOffset+3) >> 6) & 0x03); IvOffset += ZM_SIZE_OF_IV; if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP64) { keyLen = 5; } else if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP128) { keyLen = 13; } else if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP256) { keyLen = 29; } zfWEPDecrypt(dev, buf, IvOffset, keyLen, wd->sta.wepKey[keyIdx], iv); if (ret == ZM_ICV_FAILURE) { zm_debug_msg0("WEP ICV fail"); /* Discard ICV failed frame */ zfwBufFree(dev, buf, 0); return; } encryMode = wd->sta.SWEncryMode[keyIdx]; /* Remove ICV from buffer */ zfwBufSetSize(dev, buf, len-4); offset += ZM_SIZE_OF_IV; } } } #ifdef ZM_ENABLE_CENC //else if ( encryMode == ZM_CENC ) /* check if CENC */ if ( encryMode == ZM_CENC ) { u32_t rxIV[4]; rxIV[0] = (zmw_rx_buf_readh(dev, buf, 28) << 16) + zmw_rx_buf_readh(dev, buf, 26); rxIV[1] = (zmw_rx_buf_readh(dev, buf, 32) << 16) + zmw_rx_buf_readh(dev, buf, 30); rxIV[2] = (zmw_rx_buf_readh(dev, buf, 36) << 16) + zmw_rx_buf_readh(dev, buf, 34); rxIV[3] = (zmw_rx_buf_readh(dev, buf, 40) << 16) + zmw_rx_buf_readh(dev, buf, 38); //zm_debug_msg2("rxIV[0] = 0x", rxIV[0]); //zm_debug_msg2("rxIV[1] = 0x", rxIV[1]); //zm_debug_msg2("rxIV[2] = 0x", rxIV[2]); //zm_debug_msg2("rxIV[3] = 0x", rxIV[3]); /* destination address*/ da[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); da[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+2); da[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+4); if ( wd->wlanMode == ZM_MODE_AP ) { } else { if ((da[0] & 0x1)) { //multicast frame /* Accumlate the PN sequence */ wd->sta.rxivGK[0] ++; if (wd->sta.rxivGK[0] == 0) { wd->sta.rxivGK[1]++; } if (wd->sta.rxivGK[1] == 0) { wd->sta.rxivGK[2]++; } if (wd->sta.rxivGK[2] == 0) { wd->sta.rxivGK[3]++; } if (wd->sta.rxivGK[3] == 0) { wd->sta.rxivGK[0] = 0; wd->sta.rxivGK[1] = 0; wd->sta.rxivGK[2] = 0; } //zm_debug_msg2("wd->sta.rxivGK[0] = 0x", wd->sta.rxivGK[0]); //zm_debug_msg2("wd->sta.rxivGK[1] = 0x", wd->sta.rxivGK[1]); //zm_debug_msg2("wd->sta.rxivGK[2] = 0x", wd->sta.rxivGK[2]); //zm_debug_msg2("wd->sta.rxivGK[3] = 0x", wd->sta.rxivGK[3]); if ( !((wd->sta.rxivGK[0] == rxIV[0]) && (wd->sta.rxivGK[1] == rxIV[1]) && (wd->sta.rxivGK[2] == rxIV[2]) && (wd->sta.rxivGK[3] == rxIV[3]))) { u8_t PacketDiscard = 0; /* Discard PN Code Error frame */ if (rxIV[0] < wd->sta.rxivGK[0]) { PacketDiscard = 1; } if (wd->sta.rxivGK[0] > 0xfffffff0) { //boundary case if ((rxIV[0] < 0xfffffff0) && (((0xffffffff - wd->sta.rxivGK[0]) + rxIV[0]) > 16)) { PacketDiscard = 1; } } else { //normal case if ((rxIV[0] - wd->sta.rxivGK[0]) > 16) { PacketDiscard = 1; } } // sync sta pn code with ap because of losting some packets wd->sta.rxivGK[0] = rxIV[0]; wd->sta.rxivGK[1] = rxIV[1]; wd->sta.rxivGK[2] = rxIV[2]; wd->sta.rxivGK[3] = rxIV[3]; if (PacketDiscard) { zm_debug_msg0("Discard PN Code lost too much multicast frame"); zfwBufFree(dev, buf, 0); return; } } } else { //unicast frame /* Accumlate the PN sequence */ wd->sta.rxiv[0] += 2; if (wd->sta.rxiv[0] == 0 || wd->sta.rxiv[0] == 1) { wd->sta.rxiv[1]++; } if (wd->sta.rxiv[1] == 0) { wd->sta.rxiv[2]++; } if (wd->sta.rxiv[2] == 0) { wd->sta.rxiv[3]++; } if (wd->sta.rxiv[3] == 0) { wd->sta.rxiv[0] = 0; wd->sta.rxiv[1] = 0; wd->sta.rxiv[2] = 0; } //zm_debug_msg2("wd->sta.rxiv[0] = 0x", wd->sta.rxiv[0]); //zm_debug_msg2("wd->sta.rxiv[1] = 0x", wd->sta.rxiv[1]); //zm_debug_msg2("wd->sta.rxiv[2] = 0x", wd->sta.rxiv[2]); //zm_debug_msg2("wd->sta.rxiv[3] = 0x", wd->sta.rxiv[3]); if ( !((wd->sta.rxiv[0] == rxIV[0]) && (wd->sta.rxiv[1] == rxIV[1]) && (wd->sta.rxiv[2] == rxIV[2]) && (wd->sta.rxiv[3] == rxIV[3]))) { zm_debug_msg0("PN Code mismatch, lost unicast frame, sync pn code to recv packet"); // sync sta pn code with ap because of losting some packets wd->sta.rxiv[0] = rxIV[0]; wd->sta.rxiv[1] = rxIV[1]; wd->sta.rxiv[2] = rxIV[2]; wd->sta.rxiv[3] = rxIV[3]; /* Discard PN Code Error frame */ //zm_debug_msg0("Discard PN Code mismatch unicast frame"); //zfwBufFree(dev, buf, 0); //return; } } } } #endif //ZM_ENABLE_CENC /* for tally */ if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) { /* for ACU to display RxRate */ zfWlanUpdateRxRate(dev, addInfo); wd->commTally.rxUnicastFrm++; wd->commTally.rxUnicastOctets += (len-24); } else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) { wd->commTally.rxBroadcastFrm++; wd->commTally.rxBroadcastOctets += (len-24); } else { wd->commTally.rxMulticastFrm++; wd->commTally.rxMulticastOctets += (len-24); } wd->ledStruct.rxTraffic++; if ((frameSubtype & 0x80) == 0x80) { /* if QoS control bit-7 is 1 => A-MSDU frame */ if ((zmw_rx_buf_readh(dev, buf, 24) & 0x80) != 0) { zfDeAmsdu(dev, buf, vap, encryMode); return; } } // Remove MIC of TKIP if ( encryMode == ZM_TKIP ) { zfwBufSetSize(dev, buf, zfwBufGetSize(dev, buf) - 8); } /* Convert 802.11 and SNAP header to ethernet header */ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)|| (wd->wlanMode == ZM_MODE_IBSS) ) { /* destination address*/ da[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); da[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+2); da[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+4); /* check broadcast frame */ if ( (da[0] == 0xffff) && (da[1] == 0xffff) && (da[2] == 0xffff) ) { // Ap send broadcast frame to the DUT ! } /* check multicast frame */ /* TODO : Remove these code, hardware should be able to block */ /* multicast frame on the multicast address list */ /* or bypass all multicast packet by flag bAllMulticast */ else if ((da[0] & 0x01) && (wd->sta.bAllMulticast == 0)) { for(ii=0; iista.multicastList.size; ii++) { if ( zfMemoryIsEqual(wd->sta.multicastList.macAddr[ii].addr, (u8_t*) da, 6)) { break; } } if ( ii == wd->sta.multicastList.size ) { /* not found */ zm_debug_msg0("discard unknown multicast frame"); zfwBufFree(dev, buf, 0); return; } } #ifdef ZM_ENABLE_NATIVE_WIFI //Native Wifi : 1, Ethernet format : 0 //To remove IV if (offset > 0) { for (i=12; i>0; i--) { zmw_rx_buf_writeh(dev, buf, ((i-1)*2)+offset, zmw_rx_buf_readh(dev, buf, (i-1)*2)); } zfwBufRemoveHead(dev, buf, offset); } #else if (zfRxBufferEqualToStr(dev, buf, zgSnapBridgeTunnel, 24+offset, 6)) { snapCase = 1; } else if ( zfRxBufferEqualToStr(dev, buf, zgSnap8021h, 24+offset, 6) ) { typeLengthField = (((u16_t) zmw_rx_buf_readb(dev, buf, 30+offset)) << 8) + zmw_rx_buf_readb(dev, buf, 31+offset); //zm_debug_msg2("tpyeLengthField = ", typeLengthField); //8137 : IPX, 80F3 : Appletalk if ( (typeLengthField != 0x8137)&& (typeLengthField != 0x80F3) ) { snapCase = 2; } if ( typeLengthField == 0x888E ) { zfShowRxEAPOL(dev, buf, 32); } } else { //zfwDumpBuf(dev, buf); } /* source address */ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { /* SA = Address 3 */ sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET); sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2); sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4); } else { /* SA = Address 2 */ sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); } if ( snapCase ) { /* SA */ zmw_rx_buf_writeh(dev, buf, 24+offset, sa[0]); zmw_rx_buf_writeh(dev, buf, 26+offset, sa[1]); zmw_rx_buf_writeh(dev, buf, 28+offset, sa[2]); /* DA = Address 1 */ zmw_rx_buf_writeh(dev, buf, 18+offset, da[0]); zmw_rx_buf_writeh(dev, buf, 20+offset, da[1]); zmw_rx_buf_writeh(dev, buf, 22+offset, da[2]); zfwBufRemoveHead(dev, buf, 18+offset); } else { /* SA */ zmw_rx_buf_writeh(dev, buf, 16+offset, sa[0]); zmw_rx_buf_writeh(dev, buf, 18+offset, sa[1]); zmw_rx_buf_writeh(dev, buf, 20+offset, sa[2]); /* DA = Address 1 */ zmw_rx_buf_writeh(dev, buf, 10+offset, da[0]); zmw_rx_buf_writeh(dev, buf, 12+offset, da[1]); zmw_rx_buf_writeh(dev, buf, 14+offset, da[2]); zfwBufRemoveHead(dev, buf, 10+offset); /* Ethernet payload length */ typeLengthField = zfwBufGetSize(dev, buf) - 14; zmw_rx_buf_writeh(dev, buf, 12, (typeLengthField<<8)+(typeLengthField>>8)); } #endif // ZM_ENABLE_NATIVE_WIFI } else if (wd->wlanMode == ZM_MODE_AP) { //if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3) if (vap < ZM_MAX_AP_SUPPORT) /* AP mode */ { #ifdef ZM_ENABLE_NATIVE_WIFI //Native Wifi : 1, Ethernet format : 0 //To remove IV if (offset > 0) { for (i=12; i>0; i--) { zmw_rx_buf_writeh(dev, buf, ((i-1)*2)+offset, zmw_rx_buf_readh(dev, buf, (i-1)*2)); } zfwBufRemoveHead(dev, buf, offset); } #else /* SA = Address 2 */ zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET)); zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4)); /* DA = Address 3 */ /* Seq : Read 20 write 22, read 18 write 20, read 16 write 18 */ /* sequence must not be inverted */ zmw_rx_buf_writeh(dev, buf, 22+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4)); zmw_rx_buf_writeh(dev, buf, 20+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 18+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET)); zfwBufRemoveHead(dev, buf, 18+offset); #endif // ZM_ENABLE_NATIVE_WIFI #if 1 if ((ret = zfIntrabssForward(dev, buf, vap)) == 1) { /* Free Rx buffer if intra-BSS unicast frame */ zm_msg0_rx(ZM_LV_2, "Free intra-BSS unicast frame"); zfwBufFree(dev, buf, 0); return; } #endif } else /* WDS mode */ { zm_msg0_rx(ZM_LV_2, "Rx WDS data"); /* SA = Address 4 */ zmw_rx_buf_writeh(dev, buf, 30+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A4_OFFSET)); zmw_rx_buf_writeh(dev, buf, 32+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A4_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 34+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A4_OFFSET+4)); /* DA = Address 3 */ /* Seq : Read 20 write 22, read 18 write 20, read 16 write 18 */ /* sequence must not be inverted */ zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4)); zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET)); zfwBufRemoveHead(dev, buf, 24+offset); } } else if (wd->wlanMode == ZM_MODE_PSEUDO) { /* WDS test: remove add4 */ if (wd->enableWDS) { offset += 6; } /* SA = Address 2 */ zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET)); zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4)); /* DA = Address 1 */ zmw_rx_buf_writeh(dev, buf, 18+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET)); zmw_rx_buf_writeh(dev, buf, 20+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+2)); zmw_rx_buf_writeh(dev, buf, 22+offset, zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+4)); zfwBufRemoveHead(dev, buf, 18+offset); } else { zm_assert(0); } /* Call zfwRecvEth() to notify upper layer */ //zm_msg2_rx(ZM_LV_2, "Call zfwRecvEth(), buf=", buf); //zfwDumpBuf(dev, buf); #if ZM_PROTOCOL_RESPONSE_SIMULATION == 1 zfProtRspSim(dev, buf); #endif //zfwDumpBuf(dev, buf); /* tally */ wd->commTally.NotifyNDISRxFrmCnt++; if (wd->zfcbRecvEth != NULL) { wd->zfcbRecvEth(dev, buf, vap); ZM_PERFORMANCE_RX_MSDU(dev, wd->tick) } } /* if management frame */ else if (frameType == ZM_WLAN_MANAGEMENT_FRAME) { zm_msg2_rx(ZM_LV_2, "Rx management,FC=", frameCtrl); /* Call zfProcessManagement() to handle management frame */ zfProcessManagement(dev, buf, addInfo); //CWYang(m) zfwBufFree(dev, buf, 0); } /* PsPoll */ else if ((wd->wlanMode == ZM_MODE_AP) && (frameCtrl == 0xa4)) { zm_msg0_rx(ZM_LV_0, "Rx PsPoll"); zfApProcessPsPoll(dev, buf); zfwBufFree(dev, buf, 0); } else { zm_msg0_rx(ZM_LV_1, "Rx discard!!"); wd->commTally.DriverDiscardedFrm++; zfwBufFree(dev, buf, 0); } return; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfWlanRxValidate */ /* Validate Rx frame. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : received 802.11 frame buffer. */ /* */ /* OUTPUTS */ /* Error code */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.10 */ /* */ /************************************************************************/ u16_t zfWlanRxValidate(zdev_t* dev, zbuf_t* buf) { u16_t frameType; u16_t frameCtrl; u16_t frameLen; u16_t ret; u8_t frameSubType; zmw_get_wlan_dev(dev); frameCtrl = zmw_rx_buf_readh(dev, buf, 0); frameType = frameCtrl & 0xC; frameSubType = (frameCtrl & 0xF0) >> 4; frameLen = zfwBufGetSize(dev, buf); /* Accept Data/Management frame with protocol version = 0 */ if ((frameType == 0x8) || (frameType == 0x0)) { /* TODO : check rx status => erro bit */ /* Check Minimum Length with Wep */ if ((frameCtrl & 0x4000) != 0) { /* Minimum Length = */ /* PLCP(5)+Header(24)+IV(4)+ICV(4)+CRC(4)+RxStatus(8) */ if (frameLen < 32) { return ZM_ERR_MIN_RX_ENCRYPT_FRAME_LENGTH; } } else if ( frameSubType == 0x5 || frameSubType == 0x8 ) { /* Minimum Length = PLCP(5)+MACHeader(24)+Timestamp(8)+BeaconInterval(2)+Cap(2)+CRC(4)+RxStatus(8) */ if (frameLen < 36) { return ZM_ERR_MIN_RX_FRAME_LENGTH; } } else { /* Minimum Length = PLCP(5)+MACHeader(24)+CRC(4)+RxStatus(8) */ if (frameLen < 24) { return ZM_ERR_MIN_RX_FRAME_LENGTH; } } /* Check if frame Length > ZM_WLAN_MAX_RX_SIZE. */ if (frameLen > ZM_WLAN_MAX_RX_SIZE) { return ZM_ERR_MAX_RX_FRAME_LENGTH; } } else if ((frameCtrl&0xff) == 0xa4) { /* PsPoll */ //zm_msg0_rx(ZM_LV_0, "rx pspoll"); } else if ((frameCtrl&0xff) == ZM_WLAN_FRAME_TYPE_BAR) { if (wd->sta.enableDrvBA == 1) { zfAggRecvBAR(dev, buf); } return ZM_ERR_RX_BAR_FRAME; } else { return ZM_ERR_RX_FRAME_TYPE; } if ( wd->wlanMode == ZM_MODE_AP ) { } else if ( wd->wlanMode != ZM_MODE_PSEUDO ) { if ( (ret=zfStaRxValidateFrame(dev, buf))!=ZM_SUCCESS ) { //zm_debug_msg1("discard frame, code = ", ret); return ret; } } return ZM_SUCCESS; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfWlanRxFilter */ /* Filter duplicated frame. */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : received 802.11 frame buffer. */ /* */ /* OUTPUTS */ /* Error code */ /* */ /* AUTHOR */ /* Stephen ZyDAS Technology Corporation 2005.10 */ /* */ /************************************************************************/ u16_t zfWlanRxFilter(zdev_t* dev, zbuf_t* buf) { u16_t src[3]; u16_t dst0; u16_t frameType; u16_t seq; u16_t offset; u16_t index; u16_t col; u16_t i; u8_t up = 0; /* User priority */ zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); ZM_BUFFER_TRACE(dev, buf) /* RX PREFIX */ offset = 0; frameType = zmw_rx_buf_readh(dev, buf, offset); // Don't divide 2^4 because we don't want the fragmentation pkt to be treated as // duplicated frames seq = zmw_rx_buf_readh(dev, buf, offset+22); dst0 = zmw_rx_buf_readh(dev, buf, offset+4); src[0] = zmw_rx_buf_readh(dev, buf, offset+10); src[1] = zmw_rx_buf_readh(dev, buf, offset+12); src[2] = zmw_rx_buf_readh(dev, buf, offset+14); /* QoS data frame */ if ((frameType & 0x88) == 0x88) { up = zmw_rx_buf_readb(dev, buf, offset+24); up &= 0x7; } index = (src[2]+up) & (ZM_FILTER_TABLE_ROW-1); /* TBD : filter frame with source address == own MAC adress */ if ((wd->macAddr[0] == src[0]) && (wd->macAddr[1] == src[1]) && (wd->macAddr[2] == src[2])) { //zm_msg0_rx(ZM_LV_0, "Rx filter=>src is own MAC"); wd->trafTally.rxSrcIsOwnMac++; #if 0 return ZM_ERR_RX_SRC_ADDR_IS_OWN_MAC; #endif } zm_msg2_rx(ZM_LV_2, "Rx seq=", seq); /* Filter unicast frame only */ if ((dst0 & 0x1) == 0) { zmw_enter_critical_section(dev); for(i=0; irxFilterTbl[i][index].addr[0] == src[0]) && (wd->rxFilterTbl[i][index].addr[1] == src[1]) && (wd->rxFilterTbl[i][index].addr[2] == src[2]) && (wd->rxFilterTbl[i][index].up == up)) { if (((frameType&0x800)==0x800) &&(wd->rxFilterTbl[i][index].seq==seq)) { zmw_leave_critical_section(dev); /* hit : duplicated frame */ zm_msg0_rx(ZM_LV_1, "Rx filter hit=>duplicated"); wd->trafTally.rxDuplicate++; return ZM_ERR_RX_DUPLICATE; } else { /* hit : not duplicated frame, update sequence number */ wd->rxFilterTbl[i][index].seq = seq; zmw_leave_critical_section(dev); zm_msg0_rx(ZM_LV_2, "Rx filter hit"); return ZM_SUCCESS; } } } /* for(i=0; itick & (ZM_FILTER_TABLE_COL-1)); wd->rxFilterTbl[col][index].addr[0] = src[0]; wd->rxFilterTbl[col][index].addr[1] = src[1]; wd->rxFilterTbl[col][index].addr[2] = src[2]; wd->rxFilterTbl[col][index].seq = seq; wd->rxFilterTbl[col][index].up = up; zmw_leave_critical_section(dev); } /* if ((dst0 & 0x1) == 0) */ return ZM_SUCCESS; } u16_t zfTxGenWlanTail(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t snaplen, u16_t* mic) { struct zsMicVar* pMicKey; u16_t i, length, payloadOffset; u8_t bValue, qosType = 0; u8_t snapByte[12]; zmw_get_wlan_dev(dev); if ( wd->wlanMode == ZM_MODE_AP ) { pMicKey = zfApGetTxMicKey(dev, buf, &qosType); if ( pMicKey == NULL ) { return 0; } } else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { pMicKey = zfStaGetTxMicKey(dev, buf); if ( pMicKey == NULL ) { return 0; } } else { return 0; } length = zfwBufGetSize(dev, buf); zfMicClear(pMicKey); /* append DA and SA */ #ifdef ZM_ENABLE_NATIVE_WIFI for(i=16; i<22; i++) { // VISTA DA bValue = zmw_tx_buf_readb(dev, buf, i); zfMicAppendByte(bValue, pMicKey); } for(i=10; i<16; i++) { // VISTA SA bValue = zmw_tx_buf_readb(dev, buf, i); zfMicAppendByte(bValue, pMicKey); } #else for(i=0; i<12; i++) { bValue = zmw_tx_buf_readb(dev, buf, i); zfMicAppendByte(bValue, pMicKey); } #endif /* append for alignment */ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) { if (wd->sta.wmeConnected != 0) zfMicAppendByte(zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1) >> 5, pMicKey); else zfMicAppendByte(0, pMicKey); } else if ( wd->wlanMode == ZM_MODE_AP ) { if (qosType == 1) zfMicAppendByte(zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1) >> 5, pMicKey); else zfMicAppendByte(0, pMicKey); } else { /* TODO : Qos Software MIC in IBSS Mode */ zfMicAppendByte(0, pMicKey); } zfMicAppendByte(0, pMicKey); zfMicAppendByte(0, pMicKey); zfMicAppendByte(0, pMicKey); if ( snaplen == 0 ) { payloadOffset = ZM_80211_FRAME_IP_OFFSET; } else { payloadOffset = ZM_80211_FRAME_TYPE_OFFSET; for(i=0; i<(snaplen>>1); i++) { snapByte[i*2] = (u8_t) (snap[i] & 0xff); snapByte[i*2+1] = (u8_t) ((snap[i] >> 8) & 0xff); } for(i=0; i= 34) //Minimum IPv4 packet size, 14(Ether header)+20(IPv4 header) { etherType = (((u16_t)zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_TYPE_OFFSET))<<8) + zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_TYPE_OFFSET + 1); /* protocol type = IP */ if (etherType == 0x0800) { ipv = zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET) >> 4; if (ipv == 0x4) //IPv4 { tos = zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1); *up = (tos >> 5); *fragOff = zmw_tx_buf_readh(dev, buf, ZM_80211_FRAME_IP_OFFSET + 6); } /* TODO : handle VLAN tag and IPv6 packet */ } } return; } #ifdef ZM_ENABLE_NATIVE_WIFI u16_t zfTxGenWlanSnap(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t* snaplen) { snap[0] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 0); snap[1] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 2); snap[2] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 4); *snaplen = 6; return ZM_80211_FRAME_HEADER_LEN + *snaplen; } #else u16_t zfTxGenWlanSnap(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t* snaplen) { u16_t removed; u16_t etherType; u16_t len; len = zfwBufGetSize(dev, buf); if (len < 14) //Minimum Ethernet packet size, 14(Ether header) { /* TODO : Assert? */ *snaplen = 0; return 0; } /* Generate RFC1042 header */ etherType = (((u16_t)zmw_tx_buf_readb(dev, buf, 12))<<8) + zmw_tx_buf_readb(dev, buf, 13); //zm_debug_msg2("ethernet type or length = ", etherType); if (etherType > 1500) { /* ETHERNET format */ removed = 12; snap[0] = 0xaaaa; snap[1] = 0x0003; if ((etherType ==0x8137) || (etherType == 0x80f3)) { /* Bridge Tunnel */ snap[2] = 0xF800; } else { /* RFC 1042 */ snap[2] = 0x0000; } *snaplen = 6; if ( etherType == 0x888E ) { zfShowTxEAPOL(dev, buf, 14); } } else { /* 802.3 format */ removed = 14; *snaplen = 0; } return removed; } #endif u8_t zfIsVtxqEmpty(zdev_t* dev) { u8_t isEmpty = TRUE; u8_t i; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); if (wd->vmmqHead != wd->vmmqTail) { isEmpty = FALSE; goto check_done; } for(i=0; i < 4; i++) { if (wd->vtxqHead[i] != wd->vtxqTail[i]) { isEmpty = FALSE; goto check_done; } } check_done: zmw_leave_critical_section(dev); return isEmpty; } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfPutVtxq */ /* Put Tx buffer to virtual TxQ */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : Tx buffer pointer */ /* */ /* OUTPUTS */ /* ZM_SUCCESS or error code */ /* */ /* AUTHOR */ /* Stephen Chen ZyDAS Technology Corporation 2006.6 */ /* */ /************************************************************************/ u16_t zfPutVtxq(zdev_t* dev, zbuf_t* buf) { u8_t ac; u8_t up; u16_t fragOff; #ifdef ZM_AGG_TALLY struct aggTally *agg_tal; #endif #ifdef ZM_ENABLE_AGGREGATION #ifndef ZM_BYPASS_AGGR_SCHEDULING u16_t ret; u16_t tid; #endif #endif zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); if ( wd->zfcbClassifyTxPacket != NULL ) { ac = wd->zfcbClassifyTxPacket(dev, buf); } else { ac = zcUpToAc[up&0x7] & 0x3; } /* * add by honda * main A-MPDU aggregation function */ #ifdef ZM_AGG_TALLY agg_tal = &wd->agg_tal; agg_tal->got_packets_sum++; #endif #ifdef ZM_ENABLE_AGGREGATION #ifndef ZM_BYPASS_AGGR_SCHEDULING tid = up&0x7; if(wd->enableAggregation==0) { if( (wd->wlanMode == ZM_MODE_AP) || (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || (wd->wlanMode == ZM_MODE_PSEUDO) ) { // (infrastructure_mode && connect_to_11n_ap) || (ap_mode && is_11n_ap) //ret = zfAggPutVtxq(dev, buf); ret = zfAggTx(dev, buf, tid); if (ZM_SUCCESS == ret) { //zfwBufFree(dev, buf, ZM_SUCCESS); return ZM_SUCCESS; } if (ZM_ERR_EXCEED_PRIORITY_THRESHOLD == ret) { wd->commTally.txQosDropCount[ac]++; zfwBufFree(dev, buf, ZM_SUCCESS); zm_msg1_tx(ZM_LV_1, "Packet discarded, VTXQ full, ac=", ac); return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; } if (ZM_ERR_TX_BUFFER_UNAVAILABLE == ret) { /* * do nothing * continue following procession, put into VTXQ * return ZM_SUCCESS; */ } } } #endif #endif /* * end of add by honda */ /* First Ip frag */ if ((fragOff & 0xff3f) == 0x0020) { /* Don't let ip frag in if VTXQ unable to hold */ /* whole ip frag burst(assume 20 frag) */ zmw_enter_critical_section(dev); if (((wd->vtxqHead[ac] - wd->vtxqTail[ac])& ZM_VTXQ_SIZE_MASK) > (ZM_VTXQ_SIZE-20)) { wd->qosDropIpFrag[ac] = 1; } else { wd->qosDropIpFrag[ac] = 0; } zmw_leave_critical_section(dev); if (wd->qosDropIpFrag[ac] == 1) { //zm_debug_msg2("vtQ full, drop buf = ", buf); wd->commTally.txQosDropCount[ac]++; zfwBufFree(dev, buf, ZM_SUCCESS); zm_msg1_tx(ZM_LV_1, "Packet discarded, first ip frag, ac=", ac); //VTXQ[] can not hold whold ip frag burst(assume 20 frags) return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; } } else if ((fragOff & 0xff3f) == 0) { wd->qosDropIpFrag[ac] = 0; } if (((fragOff &= 0xff1f) != 0) && (wd->qosDropIpFrag[ac] == 1)) { wd->commTally.txQosDropCount[ac]++; zfwBufFree(dev, buf, ZM_SUCCESS); zm_msg1_tx(ZM_LV_1, "Packet discarded, ip frag, ac=", ac); //Discard following ip frags return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; } zmw_enter_critical_section(dev); if (((wd->vtxqHead[ac] + 1) & ZM_VTXQ_SIZE_MASK) != wd->vtxqTail[ac]) { wd->vtxq[ac][wd->vtxqHead[ac]] = buf; wd->vtxqHead[ac] = ((wd->vtxqHead[ac] + 1) & ZM_VTXQ_SIZE_MASK); zmw_leave_critical_section(dev); return ZM_SUCCESS; } else { zmw_leave_critical_section(dev); wd->commTally.txQosDropCount[ac]++; zfwBufFree(dev, buf, ZM_SUCCESS); zm_msg1_tx(ZM_LV_1, "Packet discarded, VTXQ full, ac=", ac); return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; //VTXQ[] Full } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfGetVtxq */ /* Get Tx buffer from virtual TxQ */ /* */ /* INPUTS */ /* dev : device pointer */ /* */ /* OUTPUTS */ /* Tx buffer pointer */ /* */ /* AUTHOR */ /* Stephen Chen ZyDAS Technology Corporation 2006.6 */ /* */ /************************************************************************/ zbuf_t* zfGetVtxq(zdev_t* dev, u8_t ac) { zbuf_t* buf; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); ac &= 0x3; zmw_enter_critical_section(dev); if (wd->vtxqHead[ac] != wd->vtxqTail[ac]) { buf = wd->vtxq[ac][wd->vtxqTail[ac]]; wd->vtxqTail[ac] = ((wd->vtxqTail[ac] + 1) & ZM_VTXQ_SIZE_MASK); zmw_leave_critical_section(dev); return buf; } else { zmw_leave_critical_section(dev); return 0; //VTXQ[] empty } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfPutVmmq */ /* Put Tx buffer to virtual MmQ */ /* */ /* INPUTS */ /* dev : device pointer */ /* buf : Tx buffer pointer */ /* */ /* OUTPUTS */ /* ZM_SUCCESS or error code */ /* */ /* AUTHOR */ /* Stephen Chen ZyDAS Technology Corporation 2006.12 */ /* */ /************************************************************************/ u16_t zfPutVmmq(zdev_t* dev, zbuf_t* buf) { zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); if (((wd->vmmqHead + 1) & ZM_VMMQ_SIZE_MASK) != wd->vmmqTail) { wd->vmmq[wd->vmmqHead] = buf; wd->vmmqHead = ((wd->vmmqHead + 1) & ZM_VMMQ_SIZE_MASK); zmw_leave_critical_section(dev); return ZM_SUCCESS; } else { zmw_leave_critical_section(dev); zfwBufFree(dev, buf, ZM_SUCCESS); zm_msg0_mm(ZM_LV_0, "Packet discarded, VMmQ full"); return ZM_ERR_VMMQ_FULL; //VTXQ[] Full } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfGetVmmq */ /* Get Tx buffer from virtual MmQ */ /* */ /* INPUTS */ /* dev : device pointer */ /* */ /* OUTPUTS */ /* Tx buffer pointer */ /* */ /* AUTHOR */ /* Stephen Chen ZyDAS Technology Corporation 2006.12 */ /* */ /************************************************************************/ zbuf_t* zfGetVmmq(zdev_t* dev) { zbuf_t* buf; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); zmw_enter_critical_section(dev); if (wd->vmmqHead != wd->vmmqTail) { buf = wd->vmmq[wd->vmmqTail]; wd->vmmqTail = ((wd->vmmqTail + 1) & ZM_VMMQ_SIZE_MASK); zmw_leave_critical_section(dev); return buf; } else { zmw_leave_critical_section(dev); return 0; //VTXQ[] empty } } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfPushVtxq */ /* Service Virtual TxQ (weighted round robin) */ /* Get Tx buffer form virtual TxQ and put to hardware TxD queue */ /* */ /* INPUTS */ /* dev : device pointer */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen Chen ZyDAS Technology Corporation 2006.6 */ /* */ /************************************************************************/ void zfPushVtxq(zdev_t* dev) { zbuf_t* buf; u16_t i; u16_t txed; u32_t freeTxd; u16_t err; u16_t skipFlag = 0; zmw_get_wlan_dev(dev); zmw_declare_for_critical_section(); //zm_debug_msg1("zfHpGetFreeTxdCount = ", zfHpGetFreeTxdCount(dev)); if (wd->halState == ZM_HAL_STATE_INIT) { if (!wd->modeMDKEnable) { zm_debug_msg0("HAL is not ready for Tx"); } return; } else if (wd->sta.DFSDisableTx) { zm_debug_msg0("return because 802.11h DFS Disable Tx"); return; } else if (wd->sta.flagFreqChanging != 0) { //Hold until RF frequency changed return; } else if (( wd->sta.flagKeyChanging ) && ( wd->wlanMode != ZM_MODE_AP )) { return; } #ifdef ZM_ENABLE_POWER_SAVE else if ( zfPowerSavingMgrIsSleeping(dev) ) { //zm_debug_msg0("Packets queued since the MAC is in power-saving mode\n"); return; } #endif zmw_enter_critical_section(dev); if (wd->vtxqPushing != 0) { skipFlag = 1; } else { wd->vtxqPushing = 1; } zmw_leave_critical_section(dev); if (skipFlag == 1) { return; } while (1) { txed = 0; /* 2006.12.20, Serve Management queue */ while( zfHpGetFreeTxdCount(dev) > 0 ) { if ((buf = zfGetVmmq(dev)) != 0) { txed = 1; //zm_debug_msg2("send buf = ", buf); if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) { zfwBufFree(dev, buf, 0); } } else { break; } } if ((wd->sta.bScheduleScan) || ((wd->sta.bChannelScan == TRUE) && (zfStaIsConnected(dev)))) { //Hold until Scan Stop wd->vtxqPushing = 0; return; } #ifdef ZM_ENABLE_AGGREGATION #ifndef ZM_BYPASS_AGGR_SCHEDULING if( (wd->wlanMode == ZM_MODE_AP) || (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || (wd->wlanMode == ZM_MODE_PSEUDO) ) { zfAggTxScheduler(dev, 0); if (txed == 0) { wd->vtxqPushing = 0; return; } else { continue; } } #endif #endif /* Service VTxQ[3] */ for (i=0; i<4; i++) { if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= 3) { if ((buf = zfGetVtxq(dev, 3)) != 0) { txed = 1; //zm_debug_msg2("send buf = ", buf); zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); } } else { break; } } /* Service VTxQ[2] */ for (i=0; i<3; i++) { if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*1/4)) { if ((buf = zfGetVtxq(dev, 2)) != 0) { txed = 1; zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); } if (wd->sta.ac0PriorityHigherThanAc2 == 1) { if ((buf = zfGetVtxq(dev, 0)) != 0) { txed = 1; zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); } } } else { break; } } /* Service VTxQ[0] */ for (i=0; i<2; i++) { if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*2/4)) { if ((buf = zfGetVtxq(dev, 0)) != 0) { txed = 1; zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); } } else { break; } } /* Service VTxQ[1] */ if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*3/4)) { if ((buf = zfGetVtxq(dev, 1)) != 0) { txed = 1; zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); } } /* All VTxQs are either empty or exceed their threshold */ if (txed == 0) { wd->vtxqPushing = 0; return; } } //while (1) } /************************************************************************/ /* */ /* FUNCTION DESCRIPTION zfFlushVtxq */ /* Flush Virtual TxQ and MmQ */ /* */ /* INPUTS */ /* dev : device pointer */ /* */ /* OUTPUTS */ /* None */ /* */ /* AUTHOR */ /* Stephen Chen Atheros Communications, INC. 2007.1 */ /* */ /************************************************************************/ void zfFlushVtxq(zdev_t* dev) { zbuf_t* buf; u8_t i; zmw_get_wlan_dev(dev); /* Flush MmQ */ while ((buf = zfGetVmmq(dev)) != 0) { zfwBufFree(dev, buf, 0); zm_debug_msg0("zfFlushVtxq: [Vmmq]"); wd->queueFlushed |= 0x10; } /* Flush VTxQ */ for (i=0; i<4; i++) { while ((buf = zfGetVtxq(dev, i)) != 0) { zfwBufFree(dev, buf, 0); zm_debug_msg1("zfFlushVtxq: [zfGetVtxq]- ", i); wd->queueFlushed |= (1<commTally.txUnicastFrm++; wd->commTally.txUnicastOctets += (fragLen+snapLen); } else if (da[0] == 0xffff) { wd->commTally.txBroadcastFrm++; wd->commTally.txBroadcastOctets += (fragLen+snapLen); } else { wd->commTally.txMulticastFrm++; wd->commTally.txMulticastOctets += (fragLen+snapLen); } wd->ledStruct.txTraffic++; if ((err = zfHpSend(dev, header, headerLen, snap, snapLen, tail, tailLen, buf, offset, bufType, ac, keyIdx)) != ZM_SUCCESS) { if (bufType == ZM_EXTERNAL_ALLOC_BUF) { zfwBufFree(dev, buf, err); } else if (bufType == ZM_INTERNAL_ALLOC_BUF) { zfwBufFree(dev, buf, 0); } else { zm_assert(0); } } } void zfCheckIsRIFSFrame(zdev_t* dev, zbuf_t* buf, u16_t frameSubtype) { zmw_get_wlan_dev(dev); /* #2 Record the sequence number to determine whether the unicast frame is separated by RIFS or not */ if (frameSubtype & 0x80) { //QoS data frame u16_t sequenceNum; u16_t qosControlField; sequenceNum = ( zmw_buf_readh(dev, buf, 22) >> 4 ); // Discard fragment number ! qosControlField = zmw_buf_readh(dev, buf, 24); // Don't consider WDS (Wireless Distribution System) //DbgPrint("The QoS Control Field : %d", qosControlField); //DbgPrint("The RIFS Count : %d", wd->sta.rifsCount); if( qosControlField & ZM_BIT_5 ) {// ACK policy is "No ACK" /* RIFS-Like frame */ wd->sta.rifsLikeFrameSequence[wd->sta.rifsLikeFrameCnt] = sequenceNum; if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTING ) { if( wd->sta.rifsLikeFrameSequence[2] != 0 ) {// RIFS-like Pattern collected if( ( wd->sta.rifsLikeFrameSequence[2] - wd->sta.rifsLikeFrameSequence[1] == 2 ) && ( wd->sta.rifsLikeFrameSequence[1] - wd->sta.rifsLikeFrameSequence[0] == 2 ) ) { /* RIFS pattern matched */ /* #3 Enable RIFS function if the RIFS pattern matched */ zfHpEnableRifs(dev, ((wd->sta.currentFrequency<3000)?1:0), wd->sta.EnableHT, wd->sta.HT2040); // Set RIFS timer wd->sta.rifsTimer = wd->tick; wd->sta.rifsCount++; // Set state to be Detected wd->sta.rifsState = ZM_RIFS_STATE_DETECTED; } } } else {// state = Detected // Reset RIFS timer if( (wd->tick - wd->sta.rifsTimer) < ZM_RIFS_TIMER_TIMEOUT ) wd->sta.rifsTimer = wd->tick; } //DbgPrint("SN1 = %d, SN2 = %d, SN3 = %d\n", wd->sta.rifsLikeFrameSequence[0], // wd->sta.rifsLikeFrameSequence[1], // wd->sta.rifsLikeFrameSequence[2]); // Update RIFS-like sequence number if( wd->sta.rifsLikeFrameSequence[2] != 0 ) { wd->sta.rifsLikeFrameSequence[0] = wd->sta.rifsLikeFrameSequence[1]; wd->sta.rifsLikeFrameSequence[1] = wd->sta.rifsLikeFrameSequence[2]; wd->sta.rifsLikeFrameSequence[2] = 0; } // Only record three adjacent frame if( wd->sta.rifsLikeFrameCnt < 2 ) wd->sta.rifsLikeFrameCnt++; } } /* #4 Disable RIFS function if the timer TIMEOUT */ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) { if( ( wd->tick - wd->sta.rifsTimer ) > ZM_RIFS_TIMER_TIMEOUT ) {// TIMEOUT // Disable RIFS zfHpDisableRifs(dev); // Reset RIFS-like sequence number FIFO wd->sta.rifsLikeFrameSequence[0] = 0; wd->sta.rifsLikeFrameSequence[1] = 0; wd->sta.rifsLikeFrameSequence[2] = 0; wd->sta.rifsLikeFrameCnt = 0; // Set state to be Detecting wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; } } }