diff options
Diffstat (limited to 'drivers/staging/rt2870/sta/rtmp_data.c')
-rw-r--r-- | drivers/staging/rt2870/sta/rtmp_data.c | 2619 |
1 files changed, 2619 insertions, 0 deletions
diff --git a/drivers/staging/rt2870/sta/rtmp_data.c b/drivers/staging/rt2870/sta/rtmp_data.c new file mode 100644 index 00000000000..9942ecaf5e2 --- /dev/null +++ b/drivers/staging/rt2870/sta/rtmp_data.c @@ -0,0 +1,2619 @@ +/* + ************************************************************************* + * Ralink Tech Inc. + * 5F., No.36, Taiyuan St., Jhubei City, + * Hsinchu County 302, + * Taiwan, R.O.C. + * + * (c) Copyright 2002-2007, Ralink Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + ************************************************************************* + + Module Name: + rtmp_data.c + + Abstract: + Data path subroutines + + Revision History: + Who When What + -------- ---------- ---------------------------------------------- + John Aug/17/04 major modification for RT2561/2661 + Jan Lee Mar/17/06 major modification for RT2860 New Ring Design +*/ +#include "../rt_config.h" + + +VOID STARxEAPOLFrameIndicate( + IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY *pEntry, + IN RX_BLK *pRxBlk, + IN UCHAR FromWhichBSSID) +{ + PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); + PRXWI_STRUC pRxWI = pRxBlk->pRxWI; + UCHAR *pTmpBuf; + +#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.WpaSupplicantUP) + { + // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) + // TBD : process fragmented EAPol frames + { + // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable + if ( pAd->StaCfg.IEEE8021X == TRUE && + (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) + { + PUCHAR Key; + UCHAR CipherAlg; + int idx = 0; + + DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); + //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; + STA_PORT_SECURED(pAd); + + if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) + { + idx = pAd->StaCfg.DesireSharedKeyId; + CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; + Key = pAd->StaCfg.DesireSharedKey[idx].Key; + + if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) + { +#ifdef RT2870 + union + { + char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; + NDIS_802_11_WEP keyinfo; + } WepKey; + int len; + + + NdisZeroMemory(&WepKey, sizeof(WepKey)); + len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; + + NdisMoveMemory(WepKey.keyinfo.KeyMaterial, + pAd->StaCfg.DesireSharedKey[idx].Key, + pAd->StaCfg.DesireSharedKey[idx].KeyLen); + + WepKey.keyinfo.KeyIndex = 0x80000000 + idx; + WepKey.keyinfo.KeyLength = len; + pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); + + pAd->IndicateMediaState = NdisMediaStateConnected; + pAd->ExtraInfo = GENERAL_LINK_UP; + // need to enqueue cmd to thread + RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); +#endif // RT2870 // + // For Preventing ShardKey Table is cleared by remove key procedure. + pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; + pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; + NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, + pAd->StaCfg.DesireSharedKey[idx].Key, + pAd->StaCfg.DesireSharedKey[idx].KeyLen); + } + } + } + + Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); + return; + } + } + else +#endif // WPA_SUPPLICANT_SUPPORT // + { + // Special DATA frame that has to pass to MLME + // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process + // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process + { + pTmpBuf = pRxBlk->pData - LENGTH_802_11; + NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); + REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); + DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); + } + } + + RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); + return; + +} + +VOID STARxDataFrameAnnounce( + IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY *pEntry, + IN RX_BLK *pRxBlk, + IN UCHAR FromWhichBSSID) +{ + + // non-EAP frame + if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) + { + { + // drop all non-EAP DATA frame before + // this client's Port-Access-Control is secured + if (pRxBlk->pHeader->FC.Wep) + { + // unsupported cipher suite + if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); + return; + } + } + else + { + // encryption in-use but receive a non-EAPOL clear text frame, drop it + if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && + (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); + return; + } + } + } + RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); + if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) + { + // Normal legacy, AMPDU or AMSDU + CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); + + } + else + { + // ARALINK + CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); + } +#ifdef QOS_DLS_SUPPORT + RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); +#endif // QOS_DLS_SUPPORT // + } + else + { + RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); +#ifdef DOT11_N_SUPPORT + if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) + { + Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); + } + else +#endif // DOT11_N_SUPPORT // + { + // Determin the destination of the EAP frame + // to WPA state machine or upper layer + STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); + } + } +} + + +// For TKIP frame, calculate the MIC value +BOOLEAN STACheckTkipMICValue( + IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY *pEntry, + IN RX_BLK *pRxBlk) +{ + PHEADER_802_11 pHeader = pRxBlk->pHeader; + UCHAR *pData = pRxBlk->pData; + USHORT DataSize = pRxBlk->DataSize; + UCHAR UserPriority = pRxBlk->UserPriority; + PCIPHER_KEY pWpaKey; + UCHAR *pDA, *pSA; + + pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; + + pDA = pHeader->Addr1; + if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) + { + pSA = pHeader->Addr3; + } + else + { + pSA = pHeader->Addr2; + } + + if (RTMPTkipCompareMICValue(pAd, + pData, + pDA, + pSA, + pWpaKey->RxMic, + UserPriority, + DataSize) == FALSE) + { + DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); + +#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.WpaSupplicantUP) + { + WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); + } + else +#endif // WPA_SUPPLICANT_SUPPORT // + { + RTMPReportMicError(pAd, pWpaKey); + } + + // release packet + RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); + return FALSE; + } + + return TRUE; +} + + +// +// All Rx routines use RX_BLK structure to hande rx events +// It is very important to build pRxBlk attributes +// 1. pHeader pointer to 802.11 Header +// 2. pData pointer to payload including LLC (just skip Header) +// 3. set payload size including LLC to DataSize +// 4. set some flags with RX_BLK_SET_FLAG() +// +VOID STAHandleRxDataFrame( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk) +{ + PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); + PRXWI_STRUC pRxWI = pRxBlk->pRxWI; + PHEADER_802_11 pHeader = pRxBlk->pHeader; + PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; + BOOLEAN bFragment = FALSE; + MAC_TABLE_ENTRY *pEntry = NULL; + UCHAR FromWhichBSSID = BSS0; + UCHAR UserPriority = 0; + + { + // before LINK UP, all DATA frames are rejected + if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + +#ifdef QOS_DLS_SUPPORT + //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) + if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) + { + return; + } +#endif // QOS_DLS_SUPPORT // + + // Drop not my BSS frames + if (pRxD->MyBss == 0) + { + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + } + + pAd->RalinkCounters.RxCountSinceLastNULL++; + if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) + { + UCHAR *pData; + DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); + + // Qos bit 4 + pData = (PUCHAR)pHeader + LENGTH_802_11; + if ((*pData >> 4) & 0x01) + { + DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); + pAd->CommonCfg.bInServicePeriod = FALSE; + + // Force driver to fall into sleep mode when rcv EOSP frame + if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) + { + USHORT TbttNumToNextWakeUp; + USHORT NextDtim = pAd->StaCfg.DtimPeriod; + ULONG Now; + + NdisGetSystemUpTime(&Now); + NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; + + TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) + TbttNumToNextWakeUp = NextDtim; + + MlmeSetPsmBit(pAd, PWR_SAVE); + // if WMM-APSD is failed, try to disable following line + AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); + } + } + + if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) + { + DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); + } + } + + // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame + if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + + // Drop not my BSS frame (we can not only check the MyBss bit in RxD) +#ifdef QOS_DLS_SUPPORT + if (!pAd->CommonCfg.bDLSCapable) + { +#endif // QOS_DLS_SUPPORT // + if (INFRA_ON(pAd)) + { + // Infrastructure mode, check address 2 for BSSID + if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) + { + // Receive frame not my BSSID + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + } + else // Ad-Hoc mode or Not associated + { + // Ad-Hoc mode, check address 3 for BSSID + if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) + { + // Receive frame not my BSSID + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + } +#ifdef QOS_DLS_SUPPORT + } +#endif // QOS_DLS_SUPPORT // + + // + // find pEntry + // + if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) + { + pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; + } + else + { + // 1. release packet if infra mode + // 2. new a pEntry if ad-hoc mode + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + + // infra or ad-hoc + if (INFRA_ON(pAd)) + { + RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); +#ifdef QOS_DLS_SUPPORT + if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) + RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); + else +#endif // QOS_DLS_SUPPORT // + ASSERT(pRxWI->WirelessCliID == BSSID_WCID); + } + + // check Atheros Client + if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) + { + pEntry->bIAmBadAtheros = TRUE; + pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; + pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; + if (!STA_AES_ON(pAd)) + { + AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); + } + } + } + + pRxBlk->pData = (UCHAR *)pHeader; + + // + // update RxBlk->pData, DataSize + // 802.11 Header, QOS, HTC, Hw Padding + // + + // 1. skip 802.11 HEADER + { + pRxBlk->pData += LENGTH_802_11; + pRxBlk->DataSize -= LENGTH_802_11; + } + + // 2. QOS + if (pHeader->FC.SubType & 0x08) + { + RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); + UserPriority = *(pRxBlk->pData) & 0x0f; + // bit 7 in QoS Control field signals the HT A-MSDU format + if ((*pRxBlk->pData) & 0x80) + { + RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); + } + + // skip QOS contorl field + pRxBlk->pData += 2; + pRxBlk->DataSize -=2; + } + pRxBlk->UserPriority = UserPriority; + + // 3. Order bit: A-Ralink or HTC+ + if (pHeader->FC.Order) + { +#ifdef AGGREGATION_SUPPORT + if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) + { + RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); + } + else +#endif + { +#ifdef DOT11_N_SUPPORT + RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); + // skip HTC contorl field + pRxBlk->pData += 4; + pRxBlk->DataSize -= 4; +#endif // DOT11_N_SUPPORT // + } + } + + // 4. skip HW padding + if (pRxD->L2PAD) + { + // just move pData pointer + // because DataSize excluding HW padding + RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); + pRxBlk->pData += 2; + } + +#ifdef DOT11_N_SUPPORT + if (pRxD->BA) + { + RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); + } +#endif // DOT11_N_SUPPORT // + + + // + // Case I Process Broadcast & Multicast data frame + // + if (pRxD->Bcast || pRxD->Mcast) + { + INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); + + // Drop Mcast/Bcast frame with fragment bit on + if (pHeader->FC.MoreFrag) + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + + // Filter out Bcast frame which AP relayed for us + if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) + { + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + return; + } + + Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); + return; + } + else if (pRxD->U2M) + { + pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; + + +#ifdef QOS_DLS_SUPPORT + if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) + { + MAC_TABLE_ENTRY *pDlsEntry = NULL; + + pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); + if(pDlsEntry) + Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); + } + else +#endif // QOS_DLS_SUPPORT // + if (ADHOC_ON(pAd)) + { + pEntry = MacTableLookup(pAd, pHeader->Addr2); + if (pEntry) + Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); + } + + + Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); + + pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); + pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); + + pAd->RalinkCounters.OneSecRxOkDataCnt++; + + + if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) + { + // re-assemble the fragmented packets + // return complete frame (pRxPacket) or NULL + bFragment = TRUE; + pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); + } + + if (pRxPacket) + { + pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; + + // process complete frame + if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) + { + // Minus MIC length + pRxBlk->DataSize -= 8; + + // For TKIP frame, calculate the MIC value + if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) + { + return; + } + } + + STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); + return; + } + else + { + // just return + // because RTMPDeFragmentDataFrame() will release rx packet, + // if packet is fragmented + return; + } + } + + ASSERT(0); + // release packet + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); +} + +VOID STAHandleRxMgmtFrame( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk) +{ + PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); + PRXWI_STRUC pRxWI = pRxBlk->pRxWI; + PHEADER_802_11 pHeader = pRxBlk->pHeader; + PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; + + do + { + + // We should collect RSSI not only U2M data but also my beacon + if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))) + { + Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); + + pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); + pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); + } + + // First check the size, it MUST not exceed the mlme queue size + if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) + { + DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); + break; + } + + REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, + pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); + } while (FALSE); + + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); +} + +VOID STAHandleRxControlFrame( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk) +{ +#ifdef DOT11_N_SUPPORT + PRXWI_STRUC pRxWI = pRxBlk->pRxWI; +#endif // DOT11_N_SUPPORT // + PHEADER_802_11 pHeader = pRxBlk->pHeader; + PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; + + switch (pHeader->FC.SubType) + { + case SUBTYPE_BLOCK_ACK_REQ: +#ifdef DOT11_N_SUPPORT + { + CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); + } + break; +#endif // DOT11_N_SUPPORT // + case SUBTYPE_BLOCK_ACK: + case SUBTYPE_ACK: + default: + break; + } + + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); +} + + +/* + ======================================================================== + + Routine Description: + Process RxDone interrupt, running in DPC level + + Arguments: + pAd Pointer to our adapter + + Return Value: + None + + IRQL = DISPATCH_LEVEL + + Note: + This routine has to maintain Rx ring read pointer. + Need to consider QOS DATA format when converting to 802.3 + ======================================================================== +*/ +BOOLEAN STARxDoneInterruptHandle( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN argc) +{ + NDIS_STATUS Status; + UINT32 RxProcessed, RxPending; + BOOLEAN bReschedule = FALSE; + RT28XX_RXD_STRUC *pRxD; + UCHAR *pData; + PRXWI_STRUC pRxWI; + PNDIS_PACKET pRxPacket; + PHEADER_802_11 pHeader; + RX_BLK RxCell; + + RxProcessed = RxPending = 0; + + // process whole rx ring + while (1) + { + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | + fRTMP_ADAPTER_RESET_IN_PROGRESS | + fRTMP_ADAPTER_HALT_IN_PROGRESS | + fRTMP_ADAPTER_NIC_NOT_EXIST) || + !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) + { + break; + } + + + RxProcessed ++; // test + + // 1. allocate a new data packet into rx ring to replace received packet + // then processing the received packet + // 2. the callee must take charge of release of packet + // 3. As far as driver is concerned , + // the rx packet must + // a. be indicated to upper layer or + // b. be released if it is discarded + pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); + if (pRxPacket == NULL) + { + // no more packet to process + break; + } + + // get rx ring descriptor + pRxD = &(RxCell.RxD); + // get rx data buffer + pData = GET_OS_PKT_DATAPTR(pRxPacket); + pRxWI = (PRXWI_STRUC) pData; + pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; + +#ifdef RT_BIG_ENDIAN + RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); + RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); +#endif + + // build RxCell + RxCell.pRxWI = pRxWI; + RxCell.pHeader = pHeader; + RxCell.pRxPacket = pRxPacket; + RxCell.pData = (UCHAR *) pHeader; + RxCell.DataSize = pRxWI->MPDUtotalByteCount; + RxCell.Flags = 0; + + // Increase Total receive byte counter after real data received no mater any error or not + pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; + pAd->RalinkCounters.RxCount ++; + + INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); + + if (pRxWI->MPDUtotalByteCount < 14) + Status = NDIS_STATUS_FAILURE; + + if (MONITOR_ON(pAd)) + { + send_monitor_packets(pAd, &RxCell); + break; + } + /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ +#ifdef RALINK_ATE + if (ATE_ON(pAd)) + { + pAd->ate.RxCntPerSec++; + ATESampleRssi(pAd, pRxWI); +#ifdef RALINK_28xx_QA + if (pAd->ate.bQARxStart == TRUE) + { + /* (*pRxD) has been swapped in GetPacketFromRxRing() */ + ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); + } +#endif // RALINK_28xx_QA // + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); + continue; + } +#endif // RALINK_ATE // + + // Check for all RxD errors + Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); + + // Handle the received frame + if (Status == NDIS_STATUS_SUCCESS) + { + switch (pHeader->FC.Type) + { + // CASE I, receive a DATA frame + case BTYPE_DATA: + { + // process DATA frame + STAHandleRxDataFrame(pAd, &RxCell); + } + break; + // CASE II, receive a MGMT frame + case BTYPE_MGMT: + { + STAHandleRxMgmtFrame(pAd, &RxCell); + } + break; + // CASE III. receive a CNTL frame + case BTYPE_CNTL: + { + STAHandleRxControlFrame(pAd, &RxCell); + } + break; + // discard other type + default: + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + break; + } + } + else + { + pAd->Counters8023.RxErrors++; + // discard this frame + RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); + } + } + + return bReschedule; +} + +/* + ======================================================================== + + Routine Description: + Arguments: + pAd Pointer to our adapter + + IRQL = DISPATCH_LEVEL + + ======================================================================== +*/ +VOID RTMPHandleTwakeupInterrupt( + IN PRTMP_ADAPTER pAd) +{ + AsicForceWakeup(pAd, FALSE); +} + +/* +======================================================================== +Routine Description: + Early checking and OS-depened parsing for Tx packet send to our STA driver. + +Arguments: + NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. + PPNDIS_PACKET ppPacketArray The packet array need to do transmission. + UINT NumberOfPackets Number of packet in packet array. + +Return Value: + NONE + +Note: + This function do early checking and classification for send-out packet. + You only can put OS-depened & STA related code in here. +======================================================================== +*/ +VOID STASendPackets( + IN NDIS_HANDLE MiniportAdapterContext, + IN PPNDIS_PACKET ppPacketArray, + IN UINT NumberOfPackets) +{ + UINT Index; + PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; + PNDIS_PACKET pPacket; + BOOLEAN allowToSend = FALSE; + + + for (Index = 0; Index < NumberOfPackets; Index++) + { + pPacket = ppPacketArray[Index]; + + do + { + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || + RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || + RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + { + // Drop send request since hardware is in reset state + break; + } + else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) + { + // Drop send request since there are no physical connection yet + break; + } + else + { + // Record that orignal packet source is from NDIS layer,so that + // later on driver knows how to release this NDIS PACKET +#ifdef QOS_DLS_SUPPORT + MAC_TABLE_ENTRY *pEntry; + PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); + + pEntry = MacTableLookup(pAd, pSrcBufVA); + if (pEntry && (pEntry->ValidAsDls == TRUE)) + { + RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); + } + else +#endif // QOS_DLS_SUPPORT // + RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode + RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); + NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); + pAd->RalinkCounters.PendingNdisPacketCount++; + + allowToSend = TRUE; + } + } while(FALSE); + + if (allowToSend == TRUE) + STASendPacket(pAd, pPacket); + else + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + } + + // Dequeue outgoing frames from TxSwQueue[] and process it + RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); + +} + + +/* +======================================================================== +Routine Description: + This routine is used to do packet parsing and classification for Tx packet + to STA device, and it will en-queue packets to our TxSwQueue depends on AC + class. + +Arguments: + pAd Pointer to our adapter + pPacket Pointer to send packet + +Return Value: + NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. + NDIS_STATUS_FAILURE If failed to do en-queue. + +Note: + You only can put OS-indepened & STA related code in here. +======================================================================== +*/ +NDIS_STATUS STASendPacket( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket) +{ + PACKET_INFO PacketInfo; + PUCHAR pSrcBufVA; + UINT SrcBufLen; + UINT AllowFragSize; + UCHAR NumberOfFrag; +// UCHAR RTSRequired; + UCHAR QueIdx, UserPriority; + MAC_TABLE_ENTRY *pEntry = NULL; + unsigned int IrqFlags; + UCHAR FlgIsIP = 0; + UCHAR Rate; + + // Prepare packet information structure for buffer descriptor + // chained within a single NDIS packet. + RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); + + if (pSrcBufVA == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); + // Resourece is low, system did not allocate virtual address + // return NDIS_STATUS_FAILURE directly to upper layer + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + return NDIS_STATUS_FAILURE; + } + + + if (SrcBufLen < 14) + { + DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + return (NDIS_STATUS_FAILURE); + } + + // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. + // Note multicast packets in adhoc also use BSSID_WCID index. + { + if(INFRA_ON(pAd)) + { +#ifdef QOS_DLS_SUPPORT + USHORT tmpWcid; + + tmpWcid = RTMP_GET_PACKET_WCID(pPacket); + if (VALID_WCID(tmpWcid) && + (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) + { + pEntry = &pAd->MacTab.Content[tmpWcid]; + Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; + } + else +#endif // QOS_DLS_SUPPORT // + { + pEntry = &pAd->MacTab.Content[BSSID_WCID]; + RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); + Rate = pAd->CommonCfg.TxRate; + } + } + else if (ADHOC_ON(pAd)) + { + if (*pSrcBufVA & 0x01) + { + RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); + pEntry = &pAd->MacTab.Content[MCAST_WCID]; + } + else + { + pEntry = MacTableLookup(pAd, pSrcBufVA); + } + Rate = pAd->CommonCfg.TxRate; + } + } + + if (!pEntry) + { + DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); + // Resourece is low, system did not allocate virtual address + // return NDIS_STATUS_FAILURE directly to upper layer + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + return NDIS_STATUS_FAILURE; + } + + if (ADHOC_ON(pAd) + ) + { + RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); + } + + // + // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. + // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). + RTMPCheckEtherType(pAd, pPacket); + + + + // + // WPA 802.1x secured port control - drop all non-802.1x frame before port secured + // + if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) +#ifdef WPA_SUPPLICANT_SUPPORT + || (pAd->StaCfg.IEEE8021X == TRUE) +#endif // WPA_SUPPLICANT_SUPPORT // +#ifdef LEAP_SUPPORT + || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) +#endif // LEAP_SUPPORT // + ) + && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) + && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) + ) + { + DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + + return (NDIS_STATUS_FAILURE); + } + + + // STEP 1. Decide number of fragments required to deliver this MSDU. + // The estimation here is not very accurate because difficult to + // take encryption overhead into consideration here. The result + // "NumberOfFrag" is then just used to pre-check if enough free + // TXD are available to hold this MSDU. + + + if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast + NumberOfFrag = 1; + else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) + NumberOfFrag = 1; // Aggregation overwhelms fragmentation + else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) + NumberOfFrag = 1; // Aggregation overwhelms fragmentation +#ifdef DOT11_N_SUPPORT + else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) + NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation +#endif // DOT11_N_SUPPORT // + else + { + // The calculated "NumberOfFrag" is a rough estimation because of various + // encryption/encapsulation overhead not taken into consideration. This number is just + // used to make sure enough free TXD are available before fragmentation takes place. + // In case the actual required number of fragments of an NDIS packet + // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the + // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of + // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should + // rarely happen and the penalty is just like a TX RETRY fail. Affordable. + + AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; + NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; + // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size + if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) + { + NumberOfFrag--; + } + } + + // Save fragment number to Ndis packet reserved field + RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); + + + // STEP 2. Check the requirement of RTS: + // If multiple fragment required, RTS is required only for the first fragment + // if the fragment size large than RTS threshold + // For RT28xx, Let ASIC send RTS/CTS + RTMP_SET_PACKET_RTS(pPacket, 0); + RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); + + // + // STEP 3. Traffic classification. outcome = <UserPriority, QueIdx> + // + UserPriority = 0; + QueIdx = QID_AC_BE; + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && + CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) + { + USHORT Protocol; + UCHAR LlcSnapLen = 0, Byte0, Byte1; + do + { + // get Ethernet protocol field + Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); + if (Protocol <= 1500) + { + // get Ethernet protocol field from LLC/SNAP + if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) + break; + + Protocol = (USHORT)((Byte0 << 8) + Byte1); + LlcSnapLen = 8; + } + + // always AC_BE for non-IP packet + if (Protocol != 0x0800) + break; + + // get IP header + if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) + break; + + // return AC_BE if packet is not IPv4 + if ((Byte0 & 0xf0) != 0x40) + break; + + FlgIsIP = 1; + UserPriority = (Byte1 & 0xe0) >> 5; + QueIdx = MapUserPriorityToAccessCategory[UserPriority]; + + // TODO: have to check ACM bit. apply TSPEC if ACM is ON + // TODO: downgrade UP & QueIdx before passing ACM + if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) + { + UserPriority = 0; + QueIdx = QID_AC_BE; + } + } while (FALSE); + } + + RTMP_SET_PACKET_UP(pPacket, UserPriority); + + + + // Make sure SendTxWait queue resource won't be used by other threads + RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); + if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) + { + RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); +#ifdef BLOCK_NET_IF + StopNetIfQueue(pAd, QueIdx, pPacket); +#endif // BLOCK_NET_IF // + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + + return NDIS_STATUS_FAILURE; + } + else + { + InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); + } + RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); + +#ifdef DOT11_N_SUPPORT + if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& + IS_HT_STA(pEntry)) + { + //PMAC_TABLE_ENTRY pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; + if (((pEntry->TXBAbitmap & (1<<UserPriority)) == 0) && + ((pEntry->BADeclineBitmap & (1<<UserPriority)) == 0) && + (pEntry->PortSecured == WPA_802_1X_PORT_SECURED) + // For IOT compatibility, if + // 1. It is Ralink chip or + // 2. It is OPEN or AES mode, + // then BA session can be bulit. + && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || + (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) + ) + { + BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); + } + } +#endif // DOT11_N_SUPPORT // + + pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed + return NDIS_STATUS_SUCCESS; +} + + +/* + ======================================================================== + + Routine Description: + This subroutine will scan through releative ring descriptor to find + out avaliable free ring descriptor and compare with request size. + + Arguments: + pAd Pointer to our adapter + QueIdx Selected TX Ring + + Return Value: + NDIS_STATUS_FAILURE Not enough free descriptor + NDIS_STATUS_SUCCESS Enough free descriptor + + IRQL = PASSIVE_LEVEL + IRQL = DISPATCH_LEVEL + + Note: + + ======================================================================== +*/ + +#ifdef RT2870 +/* + Actually, this function used to check if the TxHardware Queue still has frame need to send. + If no frame need to send, go to sleep, else, still wake up. +*/ +NDIS_STATUS RTMPFreeTXDRequest( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN UCHAR NumberRequired, + IN PUCHAR FreeNumberIs) +{ + //ULONG FreeNumber = 0; + NDIS_STATUS Status = NDIS_STATUS_FAILURE; + unsigned long IrqFlags; + HT_TX_CONTEXT *pHTTXContext; + + switch (QueIdx) + { + case QID_AC_BK: + case QID_AC_BE: + case QID_AC_VI: + case QID_AC_VO: + case QID_HCCA: + { + pHTTXContext = &pAd->TxContext[QueIdx]; + RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); + if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || + (pHTTXContext->IRPPending == TRUE)) + { + Status = NDIS_STATUS_FAILURE; + } + else + { + Status = NDIS_STATUS_SUCCESS; + } + RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); + } + break; + + case QID_MGMT: + if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) + Status = NDIS_STATUS_FAILURE; + else + Status = NDIS_STATUS_SUCCESS; + break; + + default: + DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); + break; + } + + return (Status); + +} +#endif // RT2870 // + + +VOID RTMPSendDisassociationFrame( + IN PRTMP_ADAPTER pAd) +{ +} + +VOID RTMPSendNullFrame( + IN PRTMP_ADAPTER pAd, + IN UCHAR TxRate, + IN BOOLEAN bQosNull) +{ + UCHAR NullFrame[48]; + ULONG Length; + PHEADER_802_11 pHeader_802_11; + + +#ifdef RALINK_ATE + if(ATE_ON(pAd)) + { + return; + } +#endif // RALINK_ATE // + + // WPA 802.1x secured port control + if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || + (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) +#ifdef WPA_SUPPLICANT_SUPPORT + || (pAd->StaCfg.IEEE8021X == TRUE) +#endif + ) && + (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) + { + return; + } + + NdisZeroMemory(NullFrame, 48); + Length = sizeof(HEADER_802_11); + + pHeader_802_11 = (PHEADER_802_11) NullFrame; + + pHeader_802_11->FC.Type = BTYPE_DATA; + pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; + pHeader_802_11->FC.ToDs = 1; + COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); + COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); + + if (pAd->CommonCfg.bAPSDForcePowerSave) + { + pHeader_802_11->FC.PwrMgmt = PWR_SAVE; + } + else + { + pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; + } + pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); + + pAd->Sequence++; + pHeader_802_11->Sequence = pAd->Sequence; + + // Prepare QosNull function frame + if (bQosNull) + { + pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; + + // copy QOS control bytes + NullFrame[Length] = 0; + NullFrame[Length+1] = 0; + Length += 2;// if pad with 2 bytes for alignment, APSD will fail + } + + HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); + +} + +// IRQL = DISPATCH_LEVEL +VOID RTMPSendRTSFrame( + IN PRTMP_ADAPTER pAd, + IN PUCHAR pDA, + IN unsigned int NextMpduSize, + IN UCHAR TxRate, + IN UCHAR RTSRate, + IN USHORT AckDuration, + IN UCHAR QueIdx, + IN UCHAR FrameGap) +{ +} + + + +// -------------------------------------------------------- +// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM +// Find the WPA key, either Group or Pairwise Key +// LEAP + TKIP also use WPA key. +// -------------------------------------------------------- +// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst +// In Cisco CCX 2.0 Leap Authentication +// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey +// Instead of the SharedKey, SharedKey Length may be Zero. +VOID STAFindCipherAlgorithm( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet + UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm + UCHAR KeyIdx = 0xff; + PUCHAR pSrcBufVA; + PCIPHER_KEY pKey = NULL; + + pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); + + { + // Select Cipher + if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) + Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast + else + Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast + + if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) + { + ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); + + // 4-way handshaking frame must be clear + if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && + (pAd->SharedKey[BSS0][0].KeyLen)) + { + CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; + KeyIdx = 0; + } + } + else if (Cipher == Ndis802_11Encryption1Enabled) + { +#ifdef LEAP_SUPPORT + if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on + { + if (LEAP_CCKM_ON(pAd)) + { + if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) + KeyIdx = 1; + else + KeyIdx = 0; + } + else + KeyIdx = pAd->StaCfg.DefaultKeyId; + } + else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC + KeyIdx = pAd->StaCfg.DefaultKeyId; + else if (LEAP_CCKM_ON(pAd)) + { + if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) + KeyIdx = 1; + else + KeyIdx = 0; + } + else // standard WEP64 or WEP128 +#endif // LEAP_SUPPORT // + KeyIdx = pAd->StaCfg.DefaultKeyId; + } + else if ((Cipher == Ndis802_11Encryption2Enabled) || + (Cipher == Ndis802_11Encryption3Enabled)) + { + if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast + KeyIdx = pAd->StaCfg.DefaultKeyId; + else if (pAd->SharedKey[BSS0][0].KeyLen) + KeyIdx = 0; + else + KeyIdx = pAd->StaCfg.DefaultKeyId; + } + + if (KeyIdx == 0xff) + CipherAlg = CIPHER_NONE; + else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) + CipherAlg = CIPHER_NONE; +#ifdef WPA_SUPPLICANT_SUPPORT + else if ( pAd->StaCfg.WpaSupplicantUP && + (Cipher == Ndis802_11Encryption1Enabled) && + (pAd->StaCfg.IEEE8021X == TRUE) && + (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) + CipherAlg = CIPHER_NONE; +#endif // WPA_SUPPLICANT_SUPPORT // + else + { + //Header_802_11.FC.Wep = 1; + CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; + pKey = &pAd->SharedKey[BSS0][KeyIdx]; + } + } + + pTxBlk->CipherAlg = CipherAlg; + pTxBlk->pKey = pKey; +} + + +VOID STABuildCommon802_11Header( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + + HEADER_802_11 *pHeader_802_11; +#ifdef QOS_DLS_SUPPORT + BOOLEAN bDLSFrame = FALSE; + INT DlsEntryIndex = 0; +#endif // QOS_DLS_SUPPORT // + + // + // MAKE A COMMON 802.11 HEADER + // + + // normal wlan header size : 24 octets + pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); + + pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + + NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); + + pHeader_802_11->FC.FrDs = 0; + pHeader_802_11->FC.Type = BTYPE_DATA; + pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); + +#ifdef QOS_DLS_SUPPORT + if (INFRA_ON(pAd)) + { + // Check if the frame can be sent through DLS direct link interface + // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) + DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); + if (DlsEntryIndex >= 0) + bDLSFrame = TRUE; + else + bDLSFrame = FALSE; + } +#endif // QOS_DLS_SUPPORT // + + if (pTxBlk->pMacEntry) + { + if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) + { + pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; + pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; + } + else + { + pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; + pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; + } + } + else + { + pHeader_802_11->Sequence = pAd->Sequence; + pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence + } + + pHeader_802_11->Frag = 0; + + pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); + + { + if (INFRA_ON(pAd)) + { +#ifdef QOS_DLS_SUPPORT + if (bDLSFrame) + { + COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); + COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); + pHeader_802_11->FC.ToDs = 0; + } + else +#endif // QOS_DLS_SUPPORT // + { + COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); + COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); + pHeader_802_11->FC.ToDs = 1; + } + } + else if (ADHOC_ON(pAd)) + { + COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); + COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); + pHeader_802_11->FC.ToDs = 0; + } + } + + if (pTxBlk->CipherAlg != CIPHER_NONE) + pHeader_802_11->FC.Wep = 1; + + // ----------------------------------------------------------------- + // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. + // ----------------------------------------------------------------- + if (pAd->CommonCfg.bAPSDForcePowerSave) + pHeader_802_11->FC.PwrMgmt = PWR_SAVE; + else + pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); +} + +#ifdef DOT11_N_SUPPORT +VOID STABuildCache802_11Header( + IN RTMP_ADAPTER *pAd, + IN TX_BLK *pTxBlk, + IN UCHAR *pHeader) +{ + MAC_TABLE_ENTRY *pMacEntry; + PHEADER_802_11 pHeader80211; + + pHeader80211 = (PHEADER_802_11)pHeader; + pMacEntry = pTxBlk->pMacEntry; + + // + // Update the cached 802.11 HEADER + // + + // normal wlan header size : 24 octets + pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); + + // More Bit + pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); + + // Sequence + pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; + pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; + + { + // Check if the frame can be sent through DLS direct link interface + // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) +#ifdef QOS_DLS_SUPPORT + BOOLEAN bDLSFrame = FALSE; + INT DlsEntryIndex = 0; + + DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); + if (DlsEntryIndex >= 0) + bDLSFrame = TRUE; + else + bDLSFrame = FALSE; +#endif // QOS_DLS_SUPPORT // + + // The addr3 of normal packet send from DS is Dest Mac address. +#ifdef QOS_DLS_SUPPORT + if (bDLSFrame) + { + COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); + COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); + pHeader80211->FC.ToDs = 0; + } + else +#endif // QOS_DLS_SUPPORT // + if (ADHOC_ON(pAd)) + COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); + else + COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); + } + + // ----------------------------------------------------------------- + // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. + // ----------------------------------------------------------------- + if (pAd->CommonCfg.bAPSDForcePowerSave) + pHeader80211->FC.PwrMgmt = PWR_SAVE; + else + pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); +} +#endif // DOT11_N_SUPPORT // + +static inline PUCHAR STA_Build_ARalink_Frame_Header( + IN RTMP_ADAPTER *pAd, + IN TX_BLK *pTxBlk) +{ + PUCHAR pHeaderBufPtr; + HEADER_802_11 *pHeader_802_11; + PNDIS_PACKET pNextPacket; + UINT32 nextBufLen; + PQUEUE_ENTRY pQEntry; + + STAFindCipherAlgorithm(pAd, pTxBlk); + STABuildCommon802_11Header(pAd, pTxBlk); + + + pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; + + // steal "order" bit to mark "aggregation" + pHeader_802_11->FC.Order = 1; + + // skip common header + pHeaderBufPtr += pTxBlk->MpduHeaderLen; + + if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) + { + // + // build QOS Control bytes + // + *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); + + *(pHeaderBufPtr+1) = 0; + pHeaderBufPtr +=2; + pTxBlk->MpduHeaderLen += 2; + } + + // padding at front of LLC header. LLC header should at 4-bytes aligment. + pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; + pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); + pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); + + // For RA Aggregation, + // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format + pQEntry = pTxBlk->TxPacketList.Head; + pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); + nextBufLen = GET_OS_PKT_LEN(pNextPacket); + if (RTMP_GET_PACKET_VLAN(pNextPacket)) + nextBufLen -= LENGTH_802_1Q; + + *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; + *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); + + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += 2; + + return pHeaderBufPtr; + +} + +#ifdef DOT11_N_SUPPORT +static inline PUCHAR STA_Build_AMSDU_Frame_Header( + IN RTMP_ADAPTER *pAd, + IN TX_BLK *pTxBlk) +{ + PUCHAR pHeaderBufPtr;//, pSaveBufPtr; + HEADER_802_11 *pHeader_802_11; + + + STAFindCipherAlgorithm(pAd, pTxBlk); + STABuildCommon802_11Header(pAd, pTxBlk); + + pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; + + // skip common header + pHeaderBufPtr += pTxBlk->MpduHeaderLen; + + // + // build QOS Control bytes + // + *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); + + // + // A-MSDU packet + // + *pHeaderBufPtr |= 0x80; + + *(pHeaderBufPtr+1) = 0; + pHeaderBufPtr +=2; + pTxBlk->MpduHeaderLen += 2; + + //pSaveBufPtr = pHeaderBufPtr; + + // + // padding at front of LLC header + // LLC header should locate at 4-octets aligment + // + // @@@ MpduHeaderLen excluding padding @@@ + // + pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; + pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); + pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); + + return pHeaderBufPtr; + +} + + +VOID STA_AMPDU_Frame_Tx( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + HEADER_802_11 *pHeader_802_11; + PUCHAR pHeaderBufPtr; + USHORT FreeNumber; + MAC_TABLE_ENTRY *pMacEntry; + BOOLEAN bVLANPkt; + PQUEUE_ENTRY pQEntry; + + ASSERT(pTxBlk); + + while(pTxBlk->TxPacketList.Head) + { + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) + { + RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); + continue; + } + + bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); + + pMacEntry = pTxBlk->pMacEntry; + if (pMacEntry->isCached) + { + // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! + NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); + pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); + STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); + } + else + { + STAFindCipherAlgorithm(pAd, pTxBlk); + STABuildCommon802_11Header(pAd, pTxBlk); + + pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + } + + + pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; + + // skip common header + pHeaderBufPtr += pTxBlk->MpduHeaderLen; + + // + // build QOS Control bytes + // + *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); + *(pHeaderBufPtr+1) = 0; + pHeaderBufPtr +=2; + pTxBlk->MpduHeaderLen += 2; + + // + // build HTC+ + // HTC control filed following QoS field + // + if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) + { + if (pMacEntry->isCached == FALSE) + { + // mark HTC bit + pHeader_802_11->FC.Order = 1; + + NdisZeroMemory(pHeaderBufPtr, 4); + *(pHeaderBufPtr+3) |= 0x80; + } + pHeaderBufPtr += 4; + pTxBlk->MpduHeaderLen += 4; + } + + //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; + ASSERT(pTxBlk->MpduHeaderLen >= 24); + + // skip 802.3 header + pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; + pTxBlk->SrcBufLen -= LENGTH_802_3; + + // skip vlan tag + if (bVLANPkt) + { + pTxBlk->pSrcBufData += LENGTH_802_1Q; + pTxBlk->SrcBufLen -= LENGTH_802_1Q; + } + + // + // padding at front of LLC header + // LLC header should locate at 4-octets aligment + // + // @@@ MpduHeaderLen excluding padding @@@ + // + pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; + pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); + pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); + + { + + // + // Insert LLC-SNAP encapsulation - 8 octets + // + EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); + if (pTxBlk->pExtraLlcSnapEncap) + { + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); + pHeaderBufPtr += 6; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += LENGTH_802_1_H; + } + + } + + if (pMacEntry->isCached) + { + RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + } + else + { + RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + + NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); + NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); + pMacEntry->isCached = TRUE; + } + + // calculate Transmitted AMPDU count and ByteCount + { + pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; + pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; + } + + //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); + + HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); + + // + // Kick out Tx + // + HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; + } + +} + + +VOID STA_AMSDU_Frame_Tx( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + PUCHAR pHeaderBufPtr; + USHORT FreeNumber; + USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. + USHORT totalMPDUSize=0; + UCHAR *subFrameHeader; + UCHAR padding = 0; + USHORT FirstTx = 0, LastTxIdx = 0; + BOOLEAN bVLANPkt; + int frameNum = 0; + PQUEUE_ENTRY pQEntry; + + + ASSERT(pTxBlk); + + ASSERT((pTxBlk->TxPacketList.Number > 1)); + + while(pTxBlk->TxPacketList.Head) + { + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) + { + RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); + continue; + } + + bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); + + // skip 802.3 header + pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; + pTxBlk->SrcBufLen -= LENGTH_802_3; + + // skip vlan tag + if (bVLANPkt) + { + pTxBlk->pSrcBufData += LENGTH_802_1Q; + pTxBlk->SrcBufLen -= LENGTH_802_1Q; + } + + if (frameNum == 0) + { + pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); + + // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. + RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + } + else + { + pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; + padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); + NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); + pHeaderBufPtr += padding; + pTxBlk->MpduHeaderLen = padding; + } + + // + // A-MSDU subframe + // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap + // + subFrameHeader = pHeaderBufPtr; + subFramePayloadLen = pTxBlk->SrcBufLen; + + NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); + + + pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; + pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; + + + // + // Insert LLC-SNAP encapsulation - 8 octets + // + EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); + + subFramePayloadLen = pTxBlk->SrcBufLen; + + if (pTxBlk->pExtraLlcSnapEncap) + { + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); + pHeaderBufPtr += 6; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += LENGTH_802_1_H; + subFramePayloadLen += LENGTH_802_1_H; + } + + // update subFrame Length field + subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; + subFrameHeader[13] = subFramePayloadLen & 0xFF; + + totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; + + if (frameNum ==0) + FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); + else + LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); + + frameNum++; + + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; + + // calculate Transmitted AMSDU Count and ByteCount + { + pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; + pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; + } + + } + + HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); + HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); + + // + // Kick out Tx + // + HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); +} +#endif // DOT11_N_SUPPORT // + +VOID STA_Legacy_Frame_Tx( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + HEADER_802_11 *pHeader_802_11; + PUCHAR pHeaderBufPtr; + USHORT FreeNumber; + BOOLEAN bVLANPkt; + PQUEUE_ENTRY pQEntry; + + ASSERT(pTxBlk); + + + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) + { + RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); + return; + } + + if (pTxBlk->TxFrameType == TX_MCAST_FRAME) + { + INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); + } + + if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) + TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); + else + TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); + + bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); + + if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) + pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; + + STAFindCipherAlgorithm(pAd, pTxBlk); + STABuildCommon802_11Header(pAd, pTxBlk); + + + // skip 802.3 header + pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; + pTxBlk->SrcBufLen -= LENGTH_802_3; + + // skip vlan tag + if (bVLANPkt) + { + pTxBlk->pSrcBufData += LENGTH_802_1Q; + pTxBlk->SrcBufLen -= LENGTH_802_1Q; + } + + pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; + + // skip common header + pHeaderBufPtr += pTxBlk->MpduHeaderLen; + + if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) + { + // + // build QOS Control bytes + // + *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); + *(pHeaderBufPtr+1) = 0; + pHeaderBufPtr +=2; + pTxBlk->MpduHeaderLen += 2; + } + + // The remaining content of MPDU header should locate at 4-octets aligment + pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; + pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); + pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); + + { + + // + // Insert LLC-SNAP encapsulation - 8 octets + // + // + // if original Ethernet frame contains no LLC/SNAP, + // then an extra LLC/SNAP encap is required + // + EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); + if (pTxBlk->pExtraLlcSnapEncap) + { + UCHAR vlan_size; + + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); + pHeaderBufPtr += 6; + // skip vlan tag + vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += LENGTH_802_1_H; + } + + } + + // + // prepare for TXWI + // use Wcid as Key Index + // + + RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + + //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); + + HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); + + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; + + // + // Kick out Tx + // + HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); +} + + +VOID STA_ARalink_Frame_Tx( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk) +{ + PUCHAR pHeaderBufPtr; + USHORT FreeNumber; + USHORT totalMPDUSize=0; + USHORT FirstTx, LastTxIdx; + int frameNum = 0; + BOOLEAN bVLANPkt; + PQUEUE_ENTRY pQEntry; + + + ASSERT(pTxBlk); + + ASSERT((pTxBlk->TxPacketList.Number== 2)); + + + FirstTx = LastTxIdx = 0; // Is it ok init they as 0? + while(pTxBlk->TxPacketList.Head) + { + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + + if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) + { + RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); + continue; + } + + bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); + + // skip 802.3 header + pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; + pTxBlk->SrcBufLen -= LENGTH_802_3; + + // skip vlan tag + if (bVLANPkt) + { + pTxBlk->pSrcBufData += LENGTH_802_1Q; + pTxBlk->SrcBufLen -= LENGTH_802_1Q; + } + + if (frameNum == 0) + { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header + + pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); + + // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount + // will be updated after final frame was handled. + RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + + + // + // Insert LLC-SNAP encapsulation - 8 octets + // + EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); + + if (pTxBlk->pExtraLlcSnapEncap) + { + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); + pHeaderBufPtr += 6; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += LENGTH_802_1_H; + } + } + else + { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. + + pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; + pTxBlk->MpduHeaderLen = 0; + + // A-Ralink sub-sequent frame header is the same as 802.3 header. + // DA(6)+SA(6)+FrameType(2) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); + pHeaderBufPtr += 12; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; + } + + totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; + + //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); + if (frameNum ==0) + FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); + else + LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); + + frameNum++; + + pAd->RalinkCounters.OneSecTxAggregationCount++; + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; + + } + + HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); + HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); + + // + // Kick out Tx + // + HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + +} + + +VOID STA_Fragment_Frame_Tx( + IN RTMP_ADAPTER *pAd, + IN TX_BLK *pTxBlk) +{ + HEADER_802_11 *pHeader_802_11; + PUCHAR pHeaderBufPtr; + USHORT FreeNumber; + UCHAR fragNum = 0; + PACKET_INFO PacketInfo; + USHORT EncryptionOverhead = 0; + UINT32 FreeMpduSize, SrcRemainingBytes; + USHORT AckDuration; + UINT NextMpduSize; + BOOLEAN bVLANPkt; + PQUEUE_ENTRY pQEntry; + + + ASSERT(pTxBlk); + + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) + { + RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); + return; + } + + ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); + bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); + + STAFindCipherAlgorithm(pAd, pTxBlk); + STABuildCommon802_11Header(pAd, pTxBlk); + + if (pTxBlk->CipherAlg == CIPHER_TKIP) + { + pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); + if (pTxBlk->pPacket == NULL) + return; + RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); + } + + // skip 802.3 header + pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; + pTxBlk->SrcBufLen -= LENGTH_802_3; + + + // skip vlan tag + if (bVLANPkt) + { + pTxBlk->pSrcBufData += LENGTH_802_1Q; + pTxBlk->SrcBufLen -= LENGTH_802_1Q; + } + + pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; + pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; + + + // skip common header + pHeaderBufPtr += pTxBlk->MpduHeaderLen; + + if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) + { + // + // build QOS Control bytes + // + *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); + + *(pHeaderBufPtr+1) = 0; + pHeaderBufPtr +=2; + pTxBlk->MpduHeaderLen += 2; + } + + // + // padding at front of LLC header + // LLC header should locate at 4-octets aligment + // + pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; + pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); + pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); + + + + // + // Insert LLC-SNAP encapsulation - 8 octets + // + // + // if original Ethernet frame contains no LLC/SNAP, + // then an extra LLC/SNAP encap is required + // + EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); + if (pTxBlk->pExtraLlcSnapEncap) + { + UCHAR vlan_size; + + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); + pHeaderBufPtr += 6; + // skip vlan tag + vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; + // get 2 octets (TypeofLen) + NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); + pHeaderBufPtr += 2; + pTxBlk->MpduHeaderLen += LENGTH_802_1_H; + } + + + // If TKIP is used and fragmentation is required. Driver has to + // append TKIP MIC at tail of the scatter buffer + // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC + if (pTxBlk->CipherAlg == CIPHER_TKIP) + { + + // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust + // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. + NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); + //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); + pTxBlk->SrcBufLen += 8; + pTxBlk->TotalFrameLen += 8; + pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; + } + + // + // calcuate the overhead bytes that encryption algorithm may add. This + // affects the calculate of "duration" field + // + if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) + EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; + else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) + EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength + else if (pTxBlk->CipherAlg == CIPHER_TKIP) + EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] + else if (pTxBlk->CipherAlg == CIPHER_AES) + EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] + else + EncryptionOverhead = 0; + + // decide how much time an ACK/CTS frame will consume in the air + AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); + + // Init the total payload length of this frame. + SrcRemainingBytes = pTxBlk->SrcBufLen; + + pTxBlk->TotalFragNum = 0xff; + + do { + + FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; + + FreeMpduSize -= pTxBlk->MpduHeaderLen; + + if (SrcRemainingBytes <= FreeMpduSize) + { // this is the last or only fragment + + pTxBlk->SrcBufLen = SrcRemainingBytes; + + pHeader_802_11->FC.MoreFrag = 0; + pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; + + // Indicate the lower layer that this's the last fragment. + pTxBlk->TotalFragNum = fragNum; + } + else + { // more fragment is required + + pTxBlk->SrcBufLen = FreeMpduSize; + + NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); + pHeader_802_11->FC.MoreFrag = 1; + pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); + } + + if (fragNum == 0) + pTxBlk->FrameGap = IFS_HTTXOP; + else + pTxBlk->FrameGap = IFS_SIFS; + + RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); + + HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); + + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; + + // Update the frame number, remaining size of the NDIS packet payload. + + // space for 802.11 header. + if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) + pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; + + fragNum++; + SrcRemainingBytes -= pTxBlk->SrcBufLen; + pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; + + pHeader_802_11->Frag++; // increase Frag # + + }while(SrcRemainingBytes > 0); + + // + // Kick out Tx + // + HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); +} + + +#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ + while(_pTxBlk->TxPacketList.Head) \ + { \ + _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ + RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ + } + + +/* + ======================================================================== + + Routine Description: + Copy frame from waiting queue into relative ring buffer and set + appropriate ASIC register to kick hardware encryption before really + sent out to air. + + Arguments: + pAd Pointer to our adapter + PNDIS_PACKET Pointer to outgoing Ndis frame + NumberOfFrag Number of fragment required + + Return Value: + None + + IRQL = DISPATCH_LEVEL + + Note: + + ======================================================================== +*/ +NDIS_STATUS STAHardTransmit( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN UCHAR QueIdx) +{ + NDIS_PACKET *pPacket; + PQUEUE_ENTRY pQEntry; + + // --------------------------------------------- + // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. + // --------------------------------------------- + // + ASSERT(pTxBlk->TxPacketList.Number); + if (pTxBlk->TxPacketList.Head == NULL) + { + DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); + return NDIS_STATUS_FAILURE; + } + + pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); + +#if 0 //def CARRIER_DETECTION_SUPPORT // Roger sync Carrier + if ((pAd->CommonCfg.CarrierDetect.Enable == TRUE) && (isCarrierDetectExist(pAd) == TRUE)) + { + DBGPRINT(RT_DEBUG_INFO,("STAHardTransmit --> radar detect not in normal mode !!!\n")); + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + return (NDIS_STATUS_FAILURE); + } +#endif // CARRIER_DETECTION_SUPPORT // + + // ------------------------------------------------------------------ + // STEP 1. WAKE UP PHY + // outgoing frame always wakeup PHY to prevent frame lost and + // turn off PSM bit to improve performance + // ------------------------------------------------------------------ + // not to change PSM bit, just send this frame out? + if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) + { + DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); + AsicForceWakeup(pAd, TRUE); + } + + // It should not change PSM bit, when APSD turn on. + if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) + || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) + || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) + { + if ((pAd->StaCfg.Psm == PWR_SAVE) && + (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) + MlmeSetPsmBit(pAd, PWR_ACTIVE); + } + + switch (pTxBlk->TxFrameType) + { +#ifdef DOT11_N_SUPPORT + case TX_AMPDU_FRAME: + STA_AMPDU_Frame_Tx(pAd, pTxBlk); + break; + case TX_AMSDU_FRAME: + STA_AMSDU_Frame_Tx(pAd, pTxBlk); + break; +#endif // DOT11_N_SUPPORT // + case TX_LEGACY_FRAME: + STA_Legacy_Frame_Tx(pAd, pTxBlk); + break; + case TX_MCAST_FRAME: + STA_Legacy_Frame_Tx(pAd, pTxBlk); + break; + case TX_RALINK_FRAME: + STA_ARalink_Frame_Tx(pAd, pTxBlk); + break; + case TX_FRAG_FRAME: + STA_Fragment_Frame_Tx(pAd, pTxBlk); + break; + default: + { + // It should not happened! + DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); + while(pTxBlk->TxPacketList.Number) + { + pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); + pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); + if (pPacket) + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + } + } + break; + } + + return (NDIS_STATUS_SUCCESS); + +} + +ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) +{ + unsigned char *word = value; + unsigned int ret = 0; + unsigned int i; + + for(i=0; i < len; i++) + { + int mod = i % 32; + ret ^=(unsigned int) (word[i]) << mod; + ret ^=(unsigned int) (word[i]) >> (32 - mod); + } + return ret; +} + +VOID Sta_Announce_or_Forward_802_3_Packet( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket, + IN UCHAR FromWhichBSSID) +{ + if (TRUE + ) + { + announce_802_3_packet(pAd, pPacket); + } + else + { + // release packet + RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); + } +} + |