2521 lines
68 KiB
C
2521 lines
68 KiB
C
/*
|
|
*************************************************************************
|
|
* 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;
|
|
|
|
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"));
|
|
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 RT2860
|
|
MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[BSSID_WCID];
|
|
|
|
// Set key material and cipherAlg to Asic
|
|
AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL);
|
|
|
|
// Assign group key info
|
|
RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL);
|
|
|
|
// Assign pairwise key info
|
|
RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry);
|
|
|
|
pAd->IndicateMediaState = NdisMediaStateConnected;
|
|
pAd->ExtraInfo = GENERAL_LINK_UP;
|
|
#endif
|
|
#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
|
|
{
|
|
// 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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RX_BLK_SET_FLAG(pRxBlk, fRX_EAP);
|
|
|
|
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0))
|
|
{
|
|
Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID);
|
|
}
|
|
else
|
|
{
|
|
// 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"));
|
|
|
|
if (pAd->StaCfg.WpaSupplicantUP)
|
|
{
|
|
WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE);
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
|
|
// 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)
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
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
|
|
{
|
|
RX_BLK_SET_FLAG(pRxBlk, fRX_HTC);
|
|
// skip HTC contorl field
|
|
pRxBlk->pData += 4;
|
|
pRxBlk->DataSize -= 4;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
if (pRxD->BA)
|
|
{
|
|
RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU);
|
|
}
|
|
|
|
//
|
|
// 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)) ;
|
|
|
|
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 (pAd->RxAnt.EvaluatePeriod == 0 &&
|
|
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);
|
|
}
|
|
|
|
#ifdef RT2870
|
|
// collect rssi information for antenna diversity
|
|
if (pAd->NicConfig2.field.AntDiversity)
|
|
{
|
|
if ((pRxD->U2M) || ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))))
|
|
{
|
|
COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAd, ConvertToRssi(pAd, (UCHAR)pRxWI->RSSI0, RSSI_0), 0); //Note: RSSI2 not used on RT73
|
|
pAd->StaCfg.NumOfAvgRssiSample ++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// 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)
|
|
{
|
|
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
|
|
PHEADER_802_11 pHeader = pRxBlk->pHeader;
|
|
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
|
|
|
|
switch (pHeader->FC.SubType)
|
|
{
|
|
case SUBTYPE_BLOCK_ACK_REQ:
|
|
{
|
|
CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader);
|
|
}
|
|
break;
|
|
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;
|
|
}
|
|
|
|
#ifdef RT2860
|
|
if (RxProcessed++ > MAX_RX_PROCESS_CNT)
|
|
{
|
|
// need to reschedule rx handle
|
|
bReschedule = TRUE;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
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) ;
|
|
|
|
// 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 */
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
#ifdef RT2860
|
|
// fRTMP_PS_GO_TO_SLEEP_NOW is set if receiving beacon.
|
|
if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW) && (INFRA_ON(pAd)))
|
|
{
|
|
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
|
|
AsicSleepThenAutoWakeup(pAd, pAd->ThisTbttNumToNextWakeUp);
|
|
bReschedule = FALSE;
|
|
}
|
|
#endif
|
|
return bReschedule;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPHandleTwakeupInterrupt(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
#ifdef RT2860
|
|
AsicForceWakeup(pAd, DOT11POWERSAVE);
|
|
#endif
|
|
#ifdef RT2870
|
|
AsicForceWakeup(pAd, FALSE);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
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
|
|
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 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))
|
|
{
|
|
{
|
|
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)
|
|
|| (pAd->StaCfg.IEEE8021X == TRUE)
|
|
)
|
|
&& ((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
|
|
else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD))
|
|
NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation
|
|
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;
|
|
#ifdef RT2860
|
|
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))
|
|
#endif
|
|
#ifdef RT2870
|
|
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) &&
|
|
CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE))
|
|
#endif
|
|
{
|
|
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);
|
|
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);
|
|
|
|
if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&&
|
|
#ifdef RT2860
|
|
(pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE))
|
|
#endif
|
|
#ifdef RT2870
|
|
IS_HT_STA(pEntry))
|
|
#endif
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
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.
|
|
*/
|
|
#endif
|
|
NDIS_STATUS RTMPFreeTXDRequest(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN UCHAR NumberRequired,
|
|
IN PUCHAR FreeNumberIs)
|
|
{
|
|
#ifdef RT2860
|
|
ULONG FreeNumber = 0;
|
|
#endif
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
#ifdef RT2870
|
|
unsigned long IrqFlags;
|
|
HT_TX_CONTEXT *pHTTXContext;
|
|
#endif
|
|
|
|
switch (QueIdx)
|
|
{
|
|
case QID_AC_BK:
|
|
case QID_AC_BE:
|
|
case QID_AC_VI:
|
|
case QID_AC_VO:
|
|
case QID_HCCA:
|
|
#ifdef RT2860
|
|
if (pAd->TxRing[QueIdx].TxSwFreeIdx > pAd->TxRing[QueIdx].TxCpuIdx)
|
|
FreeNumber = pAd->TxRing[QueIdx].TxSwFreeIdx - pAd->TxRing[QueIdx].TxCpuIdx - 1;
|
|
else
|
|
FreeNumber = pAd->TxRing[QueIdx].TxSwFreeIdx + TX_RING_SIZE - pAd->TxRing[QueIdx].TxCpuIdx - 1;
|
|
|
|
if (FreeNumber >= NumberRequired)
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
#endif
|
|
#ifdef RT2870
|
|
{
|
|
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);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case QID_MGMT:
|
|
#ifdef RT2860
|
|
if (pAd->MgmtRing.TxSwFreeIdx > pAd->MgmtRing.TxCpuIdx)
|
|
FreeNumber = pAd->MgmtRing.TxSwFreeIdx - pAd->MgmtRing.TxCpuIdx - 1;
|
|
else
|
|
FreeNumber = pAd->MgmtRing.TxSwFreeIdx + MGMT_RING_SIZE - pAd->MgmtRing.TxCpuIdx - 1;
|
|
|
|
if (FreeNumber >= NumberRequired)
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
#endif
|
|
#ifdef RT2870
|
|
if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE)
|
|
Status = NDIS_STATUS_FAILURE;
|
|
else
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx));
|
|
break;
|
|
}
|
|
#ifdef RT2860
|
|
*FreeNumberIs = (UCHAR)FreeNumber;
|
|
#endif
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
// 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)
|
|
|| (pAd->StaCfg.IEEE8021X == TRUE)
|
|
) &&
|
|
(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)
|
|
{
|
|
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;
|
|
else if ( pAd->StaCfg.WpaSupplicantUP &&
|
|
(Cipher == Ndis802_11Encryption1Enabled) &&
|
|
(pAd->StaCfg.IEEE8021X == TRUE) &&
|
|
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
|
|
CipherAlg = CIPHER_NONE;
|
|
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;
|
|
|
|
//
|
|
// 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);
|
|
|
|
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))
|
|
{
|
|
{
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
{
|
|
// The addr3 of normal packet send from DS is Dest Mac address.
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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
|
|
//
|
|
#ifdef RT2860
|
|
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
|
|
#endif
|
|
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
|
|
//
|
|
#ifdef RT2860
|
|
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
|
|
#endif
|
|
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
|
|
}
|
|
|
|
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
|
|
//
|
|
#ifdef RT2860
|
|
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
|
|
#endif
|
|
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
|
|
//
|
|
#ifdef RT2860
|
|
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
|
|
#endif
|
|
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);
|
|
|
|
// ------------------------------------------------------------------
|
|
// 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"));
|
|
#ifdef RT2860
|
|
AsicForceWakeup(pAd, FROM_TX);
|
|
#endif
|
|
#ifdef RT2870
|
|
AsicForceWakeup(pAd, TRUE);
|
|
#endif
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
case TX_AMPDU_FRAME:
|
|
STA_AMPDU_Frame_Tx(pAd, pTxBlk);
|
|
break;
|
|
case TX_AMSDU_FRAME:
|
|
STA_AMSDU_Frame_Tx(pAd, pTxBlk);
|
|
break;
|
|
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);
|
|
}
|
|
}
|
|
|