MT7601u/src/sta/rtmp_data.c
Murat Demirtas 612db32659 FIXED
2016-10-30 14:40:00 +00:00

5391 lines
150 KiB
C

/*
***************************************************************************
* Ralink Tech Inc.
* 4F, No. 2 Technology 5th Rd.
* Science-based Industrial Park
* Hsin-chu, Taiwan, R.O.C.
*
* (c) Copyright 2002-2004, Ralink Technology, Inc.
*
* All rights reserved. Ralink's source code is an unpublished work and the
* use of a copyright notice does not imply otherwise. This source code
* contains confidential trade secret material of Ralink Tech. Any attemp
* or participation in deciphering, decoding, reverse engineering or in any
* way altering the source code is stricitly prohibited, unless the prior
* written consent of Ralink Technology, Inc. is obtained.
***************************************************************************
Module Name:
rtmp_data.c
Abstract:
Data path subroutines
Revision History:
Who When What
-------- ---------- ----------------------------------------------
*/
#include "rt_config.h"
VOID STARxEAPOLFrameIndicate(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RX_BLK *pRxBlk,
IN UCHAR FromWhichBSSID)
{
RXWI_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) &&
(pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) &&
(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) {
/* Set key material and cipherAlg to Asic */
RTMP_ASIC_SHARED_KEY_TABLE(pAd,
BSS0,
idx,
&pAd->StaCfg.DesireSharedKey[idx]);
/* STA doesn't need to set WCID attribute for group key */
/* Assign pairwise key info */
RTMP_SET_WCID_SEC_INFO(pAd,
BSS0,
idx,
CipherAlg,
BSSID_WCID,
SHAREDKEYTABLE);
RTMP_IndicateMediaState(pAd,
NdisMediaStateConnected);
pAd->ExtraInfo = GENERAL_LINK_UP;
/* 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);
}
}
}
#ifdef WSC_STA_SUPPORT
else {
/* report EAP packets to MLME to check this packet is WPS packet or not */
if (pAd->StaCfg.WscControl.WscState >= WSC_STATE_LINK_UP) {
pTmpBuf = pRxBlk->pData - LENGTH_802_11;
NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11);
#ifdef MT7601
if ( IS_MT7601(pAd) )
{
REPORT_MGMT_FRAME_TO_MLME(pAd,
pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +LENGTH_802_11,
pRxWI->RxWISNR2,
0,
0,
0,
pRxWI->RxWISNR1,
OPMODE_STA);
}
else
#endif /* MT7601 */
REPORT_MGMT_FRAME_TO_MLME(pAd,
pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +LENGTH_802_11,
pRxWI->RxWIRSSI0,
pRxWI->RxWIRSSI1,
pRxWI->RxWIRSSI2,
0,
0,
OPMODE_STA);
DBGPRINT_RAW(RT_DEBUG_TRACE,
("!!! report EAPOL DATA to MLME (len=%d) !!!\n",
pRxBlk->DataSize));
}
}
#endif /* WSC_STA_SUPPORT */
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);
#ifdef MT7601
if ( IS_MT7601(pAd) )
{
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWISNR2,
0, 0,
0,
pRxWI->RxWISNR1,
OPMODE_STA);
}
else
#endif /* MT7601 */
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWIRSSI0,
pRxWI->RxWIRSSI1, pRxWI->RxWIRSSI2,
0,
0,
OPMODE_STA);
DBGPRINT_RAW(RT_DEBUG_TRACE,
("!!! report EAPOL 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)) {
/* before LINK UP, all DATA frames are rejected */
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
#ifdef DOT11Z_TDLS_SUPPORT
if (TDLS_CheckTDLSframe(pAd, pRxBlk->pData, pRxBlk->DataSize)) {
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
UCHAR *pTmpBuf;
pTmpBuf = pRxBlk->pData - LENGTH_802_11;
NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11);
#ifdef MT7601
if ( IS_MT7601(pAd) )
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWISNR2,
0, 0,
0,
pRxWI->RxWISNR1,
OPMODE_STA);
else
#endif /* MT7601 */
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWIRSSI0,
pRxWI->RxWIRSSI1, pRxWI->RxWIRSSI2,
0,
0,
OPMODE_STA);
DBGPRINT_RAW(RT_DEBUG_TRACE,
("!!! report TDLS Action DATA to MLME (len=%d) !!!\n",
pRxBlk->DataSize));
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
#endif /* DOT11Z_TDLS_SUPPORT */
#ifdef WAPI_SUPPORT
/* report to upper layer if the received frame is WAI frame */
if (RTMPCheckWAIframe(pRxBlk->pData, pRxBlk->DataSize)) {
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
#endif /* WAPI_SUPPORT */
{
/* 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);
}
}
}
#ifdef HDR_TRANS_SUPPORT
VOID STARxDataFrameAnnounce_Hdr_Trns(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RX_BLK *pRxBlk,
IN UCHAR FromWhichBSSID)
{
/* non-EAP frame */
if (!RTMPCheckWPAframe_Hdr_Trns
(pAd, pEntry, pRxBlk->pTransData, pRxBlk->TransDataSize, FromWhichBSSID)) {
/* before LINK UP, all DATA frames are rejected */
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
#ifdef DOT11Z_TDLS_SUPPORT
// TODO: check!!!
if (TDLS_CheckTDLSframe(pAd, pRxBlk->pData, pRxBlk->DataSize)) {
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
UCHAR *pTmpBuf;
pTmpBuf = pRxBlk->pData - LENGTH_802_11;
NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11);
#ifdef MT7601
if ( IS_MT7601(pAd) )
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWISNR2,
0, 0,
0,
pRxWI->RxWISNR1,
OPMODE_STA);
#endif
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID,
pTmpBuf,
pRxBlk->DataSize +
LENGTH_802_11, pRxWI->RxWIRSSI0,
pRxWI->RxWIRSSI1, pRxWI->RxWIRSSI2,
0,
0,
OPMODE_STA);
DBGPRINT_RAW(RT_DEBUG_TRACE,
("!!! report TDLS Action DATA to MLME (len=%d) !!!\n",
pRxBlk->DataSize));
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
#endif /* DOT11Z_TDLS_SUPPORT */
#ifdef WAPI_SUPPORT
// TODO: Check!
/* report to upper layer if the received frame is WAI frame */
if (RTMPCheckWAIframe(pRxBlk->pData, pRxBlk->DataSize)) {
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
#endif /* WAPI_SUPPORT */
{
/* 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_Hdr_Trns(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);
}
}
}
#endif /* HDR_TRANS_SUPPORT */
/* 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->RxWIKeyIndex];
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->net_dev,
(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)
{
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
RXINFO_STRUC *pRxInfo = pRxBlk->pRxInfo;
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;
//+++Add by shiang for debug
if (0 /*!(pRxInfo->Mcast || pRxInfo->Bcast)*/){
DBGPRINT(RT_DEBUG_OFF, ("-->%s(%d): Dump Related Info!\n", __FUNCTION__, __LINE__));
dump_rxinfo(pAd, pRxInfo);
hex_dump("DataFrameHeader", (UCHAR *)pHeader, sizeof(HEADER_802_11));
hex_dump("DataFramePayload", pRxBlk->pData , pRxBlk->DataSize);
}
//---Add by shiangf for debug
if ((pHeader->FC.FrDs == 1) && (pHeader->FC.ToDs == 1)) {
#ifdef CLIENT_WDS
if ((pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)
&& IS_ENTRY_CLIENT(&pAd->MacTab.Content[pRxWI->RxWIWirelessCliID])) {
RX_BLK_SET_FLAG(pRxBlk, fRX_WDS);
} else
#endif /* CLIENT_WDS */
{ /* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
}
else
{
#ifdef QOS_DLS_SUPPORT
if (RTMPRcvFrameDLSCheck
(pAd, pHeader, pRxWI->RxWIMPDUByteCnt, pRxD)) {
return;
}
#endif /* QOS_DLS_SUPPORT */
/* Drop not my BSS frames */
if (pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)
pEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
if (pRxInfo->MyBss == 0) {
#ifdef P2P_SUPPORT
/* When the p2p-IF up, the STA own address would be set as my_bssid address.
If receiving an "encrypted" broadcast packet(its WEP bit as 1) and doesn't match my BSSID,
Asic pass to driver with "Decrypted" marked as 0 in pRxInfo.
The condition is below,
1. p2p IF is ON,
2. the addr2 of the received packet is STA's BSSID,
3. broadcast packet,
4. from DS packet,
5. Asic pass this packet to driver with "pRxInfo->Decrypted=0"
*/
if ((P2P_INF_ON(pAd)) &&
(MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pHeader->Addr2)) &&
(pRxInfo->Bcast || pRxInfo->Mcast) &&
(pHeader->FC.FrDs == 1) &&
(pHeader->FC.ToDs == 0) &&
(pRxInfo->Decrypted == 0))
{
/* set this m-cast frame is my-bss. */
pRxInfo->MyBss = 1;
}
else
#endif /* P2P_SUPPORT */
{
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
}
#ifdef RT3290
// TODO: shiang, find out what's this??
if (pRxInfo->MyBss)
{
// TODO: shiang, I makr this line due to I still didn't know what's this yet
//pAd->Rssi[pAd->WlanFunCtrl.field.INV_TR_SW0] = pAd->StaCfg.RssiSample.AvgRssi0;
}
#endif /* RT3290 */
pAd->RalinkCounters.RxCountSinceLastNULL++;
#ifdef UAPSD_SUPPORT
if (pAd->StaCfg.UapsdInfo.bAPSDCapable
&& pAd->CommonCfg.APEdcaParm.bAPSDCapable
&& (pHeader->FC.SubType & 0x08))
{
UCHAR *pData;
DBGPRINT(RT_DEBUG_INFO, ("bAPSDCapable\n"));
/* Qos bit 4 */
pData = (PUCHAR) pHeader + LENGTH_802_11;
if ((*pData >> 4) & 0x01)
{
#ifdef DOT11Z_TDLS_SUPPORT
/* ccv EOSP frame so the peer can sleep */
if (pEntry != NULL)
{
RTMP_PS_VIRTUAL_SLEEP(pEntry);
}
if (pAd->StaCfg.FlgPsmCanNotSleep == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> Rcv EOSP frame but we can not sleep!\n"));
}
else
#endif /* DOT11Z_TDLS_SUPPORT */
{
DBGPRINT(RT_DEBUG_INFO,
("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))
{
#ifdef RTMP_MAC_USB
RTEnqueueInternalCmd(pAd,
CMDTHREAD_FORCE_SLEEP_AUTO_WAKEUP,
NULL, 0);
#endif /* RTMP_MAC_USB */
}
}
}
if ((pHeader->FC.MoreData)
&& (pAd->CommonCfg.bInServicePeriod)) {
DBGPRINT(RT_DEBUG_TRACE,
("Sending another trigger frame when More Data bit is set to 1\n"));
}
}
#endif /* UAPSD_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
/* 1: PWR_SAVE, 0: PWR_ACTIVE */
if (pEntry != NULL)
{
UCHAR OldPwrMgmt;
FRAME_CONTROL *pFmeCtrl = &pHeader->FC;
OldPwrMgmt = RtmpPsIndicate(pAd, pHeader->Addr2,
pRxWI->RxWIWirelessCliID, pFmeCtrl->PwrMgmt);
#ifdef UAPSD_SUPPORT
RTMP_PS_VIRTUAL_TIMEOUT_RESET(pEntry);
if (pFmeCtrl->PwrMgmt)
{
if ((CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_APSD_CAPABLE)) &&
(pFmeCtrl->SubType & 0x08))
{
/*
In IEEE802.11e, 11.2.1.4 Power management with APSD,
If there is no unscheduled SP in progress, the unscheduled SP begins
when the QAP receives a trigger frame from a non-AP QSTA, which is a
QoS data or QoS Null frame associated with an AC the STA has
configured to be trigger-enabled.
*/
/*
In WMM v1.1, A QoS Data or QoS Null frame that indicates transition
to/from Power Save Mode is not considered to be a Trigger Frame and
the AP shall not respond with a QoS Null frame.
*/
/* Trigger frame must be QoS data or QoS Null frame */
UCHAR OldUP;
if ((*(pRxBlk->pData+LENGTH_802_11) & 0x10) == 0)
{
/* this is not a EOSP frame */
OldUP = (*(pRxBlk->pData+LENGTH_802_11) & 0x07);
if (OldPwrMgmt == PWR_SAVE)
{
//hex_dump("trigger frame", pRxBlk->pData, 26);
UAPSD_TriggerFrameHandle(pAd, pEntry, OldUP);
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE,
("This is a EOSP frame, not a trigger frame!\n"));
}
}
}
#endif /* UAPSD_SUPPORT */
}
#endif /* DOT11Z_TDLS_SUPPORT */
/* 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;
}
if (pAd->StaCfg.BssType == BSS_INFRA) {
/* Infrastructure mode, check address 2 for BSSID */
if (1
#ifdef QOS_DLS_SUPPORT
&& (!pAd->CommonCfg.bDLSCapable)
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
&& (!IS_TDLS_SUPPORT(pAd))
#endif /* DOT11Z_TDLS_SUPPORT */
) {
if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->MlmeAux.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->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE) {
pEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
} else {
/* IOT issue with Marvell test bed AP
Marvell AP ResetToOOB and do wps.
Because of AP send EAP Request too fast and without retransmit.
STA not yet add BSSID to WCID search table.
So, the EAP Request is dropped.
The patch lookup pEntry from MacTable.
*/
pEntry = MacTableLookup(pAd, &pHeader->Addr2);
if ( pEntry == NULL )
{
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
}
/* infra or ad-hoc */
if (pAd->StaCfg.BssType == BSS_INFRA) {
RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA);
#if defined(DOT11Z_TDLS_SUPPORT) || defined(QOS_DLS_SUPPORT)
if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0))
RX_BLK_SET_FLAG(pRxBlk, fRX_DLS);
else
#endif
ASSERT(pRxWI->RxWIWirelessCliID == BSSID_WCID);
}
/* check Atheros Client */
if ((pEntry->bIAmBadAtheros == FALSE) && (pRxInfo->AMPDU == 1)
&& (pHeader->FC.Retry)) {
pEntry->bIAmBadAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE;
if (!STA_AES_ON(pAd))
RTMP_UPDATE_PROTECT(pAd, 8 , ALLN_SETPROTECT, TRUE, FALSE);
}
}
#ifdef RTMP_MAC_USB
#if defined(CONFIG_CSO_SUPPORT) || defined(CONFIG_RX_CSO_SUPPORT)
if (RTMP_TEST_MORE_FLAG(pAd, fASIC_CAP_CSO))
{
#ifdef RLT_MAC
RXFCE_INFO *pRxFceInfo = pRxBlk->pRxFceInfo;
//if ( pRxFceInfo->l3l4_done )
{
if ( (pRxFceInfo->tcp_err) || (pRxFceInfo->udp_err) ) {
RTMP_SET_TCP_CHKSUM_FAIL(pRxPacket, TRUE);
}
}
#endif /* RLT_MAC */
#ifdef RTMP_MAC
if (pRxInfo->tcp_sum_err)
RTMP_SET_TCP_CHKSUM_FAIL(pRxPacket, TRUE);
#endif /* RTMP_MAC */
}
#endif /* defined(CONFIG_CSO_SUPPORT) || defined(CONFIG_RX_CSO_SUPPORT) */
#endif /* RTMP_MAC_USB */
pRxBlk->pData = (UCHAR *) pHeader;
/*
update RxBlk->pData, DataSize
802.11 Header, QOS, HTC, Hw Padding
*/
/* 1. skip 802.11 HEADER */
#ifdef CLIENT_WDS
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_WDS)) {
pRxBlk->pData += LENGTH_802_11_WITH_ADDR4;
pRxBlk->DataSize -= LENGTH_802_11_WITH_ADDR4;
} else
#endif /* CLIENT_WDS */
{
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;
/* check if need to resend PS Poll when received packet with MoreData = 1 */
#ifdef DOT11Z_TDLS_SUPPORT
if (pRxD->U2M)
{
/* only for unicast packet */
/* for TDLS power save, More Data bit is not used */
if (((pEntry != NULL) && (!IS_ENTRY_TDLS(pEntry))) ||
(pEntry == NULL))
#endif /* DOT11Z_TDLS_SUPPORT */
{
if ((RtmpPktPmBitCheck(pAd) == TRUE) && (pHeader->FC.MoreData == 1)) {
if ((((UserPriority == 0) || (UserPriority == 3)) && pAd->CommonCfg.bAPSDAC_BE == 0) ||
(((UserPriority == 1) || (UserPriority == 2)) && pAd->CommonCfg.bAPSDAC_BK == 0) ||
(((UserPriority == 4) || (UserPriority == 5)) && pAd->CommonCfg.bAPSDAC_VI == 0) ||
(((UserPriority == 6) || (UserPriority == 7)) && pAd->CommonCfg.bAPSDAC_VO == 0)) {
/* non-UAPSD delivery-enabled AC */
RTMP_PS_POLL_ENQUEUE(pAd);
}
}
}
#ifdef DOT11Z_TDLS_SUPPORT
}
#endif /* DOT11Z_TDLS_SUPPORT */
/* 3. Order bit: A-Ralink or HTC+ */
if (pHeader->FC.Order) {
#ifdef AGGREGATION_SUPPORT
if ((pRxWI->RxWIPhyMode <= MODE_OFDM)
&& (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)))
{
RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK);
} else
#endif /* AGGREGATION_SUPPORT */
{
#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 (pRxInfo->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 (pRxInfo->BA) {
RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU);
}
#endif /* DOT11_N_SUPPORT */
#if defined(SOFT_ENCRYPT) || defined(ADHOC_WPA2PSK_SUPPORT)
/* Use software to decrypt the encrypted frame if necessary.
If a received "encrypted" unicast packet(its WEP bit as 1)
and it's passed to driver with "Decrypted" marked as 0 in pRxInfo. */
if ((pHeader->FC.Wep == 1) && (pRxInfo->Decrypted == 0)) {
PCIPHER_KEY pSwKey = NULL;
/* Cipher key table selection */
if ((pSwKey = RTMPSwCipherKeySelection(pAd,
pRxBlk->pData, pRxBlk,
pEntry)) == NULL) {
DBGPRINT(RT_DEBUG_TRACE, ("No vaild cipher key for SW decryption!!!\n"));
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
/* Decryption by Software */
if (RTMPSoftDecryptionAction(pAd,
(PUCHAR) pHeader,
UserPriority,
pSwKey,
pRxBlk->pData,
&(pRxBlk->DataSize)) !=
NDIS_STATUS_SUCCESS) {
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
/* Record the Decrypted bit as 1 */
pRxInfo->Decrypted = 1;
}
#endif /* SOFT_ENCRYPT || ADHOC_WPA2PSK_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef TDLS_AUTOLINK_SUPPORT
if (pAd->StaCfg.TdlsInfo.TdlsAutoLink)
{
if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS))
{
TDLS_AutoSetupByRcvFrame(pAd, pHeader);
}
}
#endif /* TDLS_AUTOLINK_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
/* Case I Process Broadcast & Multicast data frame */
if (pRxInfo->Bcast || pRxInfo->Mcast) {
#ifdef STATS_COUNT_SUPPORT
INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount);
#endif /* STATS_COUNT_SUPPORT */
/* 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;
}
if (ADHOC_ON(pAd)) {
MAC_TABLE_ENTRY *pAdhocEntry = NULL;
pAdhocEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pAdhocEntry)
Update_Rssi_Sample(pAd, &pAdhocEntry->RssiSample, pRxWI);
}
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef WFD_SUPPORT
if ((pAd->StaCfg.WfdCfg.bWfdEnable) &&
pRxD->Bcast &&
TDLS_CheckTDLSframe(pAd, pRxBlk->pData, pRxBlk->DataSize)) {
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
UCHAR *pTmpBuf;
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,
0,
OPMODE_STA);
DBGPRINT_RAW(RT_DEBUG_TRACE,
("!!! report TDLS Action DATA to MLME (len=%d) !!!\n",
pRxBlk->DataSize));
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
#endif /* WFD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
{
ULONG Now;
NdisGetSystemUpTime(&Now);
pAd->StaCfg.LastBeaconRxTime = Now;
}
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
else if (pRxInfo->U2M)
{
pAd->LastRxRate = (UINT32)((pRxWI->RxWIMCS) +
(pRxWI->RxWIBW << 7) +
(pRxWI->RxWISGI << 8) +
(pRxWI->RxWISTBC << 9) +
(pRxWI->RxWIPhyMode << 14));
#if defined(DOT11Z_TDLS_SUPPORT) || defined(QOS_DLS_SUPPORT)
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) {
MAC_TABLE_ENTRY *pDlsEntry = NULL;
pDlsEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
if (pDlsEntry && (pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)) {
Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI);
NdisAcquireSpinLock(&pAd->MacTabLock);
pDlsEntry->NoDataIdleCount = 0;
NdisReleaseSpinLock(&pAd->MacTabLock);
}
} else
#endif
if (INFRA_ON(pAd)) {
MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[BSSID_WCID];
if (pEntry)
Update_Rssi_Sample(pAd,
&pEntry->RssiSample,
pRxWI);
}else
if (ADHOC_ON(pAd)) {
MAC_TABLE_ENTRY *pAdhocEntry = NULL;
pAdhocEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pAdhocEntry)
Update_Rssi_Sample(pAd,
&pAdhocEntry->RssiSample,
pRxWI);
}
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI);
pAd->StaCfg.LastSNR0 = (UCHAR) (pRxWI->RxWISNR0);
pAd->StaCfg.LastSNR1 = (UCHAR) (pRxWI->RxWISNR1);
#ifdef DOT11N_SS3_SUPPORT
if (pAd->CommonCfg.RxStream == 3)
pAd->StaCfg.LastSNR2 = (UCHAR) (pRxWI->RxWISNR2);
#endif /* DOT11N_SS3_SUPPORT */
pAd->RalinkCounters.OneSecRxOkDataCnt++;
{
ULONG Now;
NdisGetSystemUpTime(&Now);
pAd->StaCfg.LastBeaconRxTime = Now;
}
if (pEntry != NULL)
{
pEntry->LastRxRate = pAd->LastRxRate;
#ifdef TXBF_SUPPORT
if (pRxWI->ShortGI)
pEntry->OneSecRxSGICount++;
else
pEntry->OneSecRxLGICount++;
#endif /* TXBF_SUPPORT */
pEntry->freqOffset = (CHAR)(pRxWI->RxWIFOFFSET);
pEntry->freqOffsetValid = TRUE;
}
#ifdef PRE_ANT_SWITCH
#endif /* PRE_ANT_SWITCH */
#ifdef RTMP_MAC_USB
/* there's packet sent to me, keep awake for 1200ms */
if (pAd->CountDowntoPsm < 12)
pAd->CountDowntoPsm = 12;
#endif /* RTMP_MAC_USB */
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->RxWIWirelessCliID];
/* process complete frame */
if (bFragment && (pRxInfo->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;
}
}
#ifdef XLINK_SUPPORT
else if (pAd->StaCfg.PSPXlink) {
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
#endif /* XLINK_SUPPORT */
ASSERT(0);
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
}
#ifdef HDR_TRANS_SUPPORT
VOID STAHandleRxDataFrame_Hdr_Trns(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
#ifdef RLT_MAC
RXFCE_INFO *pRxFceInfo = pRxBlk->pRxFceInfo;
#endif /* RLT_MAC */
RXINFO_STRUC *pRxInfo = pRxBlk->pRxInfo;
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;
UCHAR *pData;
//+++Add by shiang for debug
if (0 /*!(pRxInfo->Mcast || pRxInfo->Bcast)*/){
DBGPRINT(RT_DEBUG_OFF, ("-->%s(%d): Dump Related Info!\n", __FUNCTION__, __LINE__));
//dumpRxInfo(pAd, pRxInfo);
hex_dump("DataFrameHeader", pHeader, 36);
hex_dump("DataFramePayload", pRxBlk->pTransData , pRxBlk->TransDataSize);
}
//---Add by shiangf for debug
if ((pHeader->FC.FrDs == 1) && (pHeader->FC.ToDs == 1)) {
#ifdef CLIENT_WDS
if ((pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)
&& IS_ENTRY_CLIENT(&pAd->MacTab.Content[pRxWI->RxWIWirelessCliID])) {
RX_BLK_SET_FLAG(pRxBlk, fRX_WDS);
} else
#endif /* CLIENT_WDS */
{ /* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
}
else
{
#ifdef QOS_DLS_SUPPORT
if (RTMPRcvFrameDLSCheck
(pAd, pHeader, pRxWI->RxWIMPDUByteCnt, pRxD)) {
return;
}
#endif /* QOS_DLS_SUPPORT */
/* Drop not my BSS frames */
if (pRxInfo->MyBss == 0) {
#ifdef P2P_SUPPORT
/* When the p2p-IF up, the STA own address would be set as my_bssid address.
If receiving an "encrypted" broadcast packet(its WEP bit as 1) and doesn't match my BSSID,
Asic pass to driver with "Decrypted" marked as 0 in pRxInfo.
The condition is below,
1. p2p IF is ON,
2. the addr2 of the received packet is STA's BSSID,
3. broadcast packet,
4. from DS packet,
5. Asic pass this packet to driver with "pRxInfo->Decrypted=0"
*/
if ((P2P_INF_ON(pAd)) &&
(MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pHeader->Addr2)) &&
(pRxInfo->Bcast || pRxInfo->Mcast) &&
(pHeader->FC.FrDs == 1) &&
(pHeader->FC.ToDs == 0) &&
(pRxInfo->Decrypted == 0))
{
/* set this m-cast frame is my-bss. */
pRxInfo->MyBss = 1;
}
else
#endif /* P2P_SUPPORT */
{
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
}
#ifdef RT3290
// TODO: shiang, find out what's this??
if (pRxInfo->MyBss)
{
// TODO: shiang, I makr this line due to I still didn't know what's this yet
//pAd->Rssi[pAd->WlanFunCtrl.field.INV_TR_SW0] = pAd->StaCfg.RssiSample.AvgRssi0;
}
#endif /* RT3290 */
pAd->RalinkCounters.RxCountSinceLastNULL++;
if (pAd->StaCfg.UapsdInfo.bAPSDCapable
&& pAd->CommonCfg.APEdcaParm.bAPSDCapable
&& (pHeader->FC.SubType & 0x08)) {
DBGPRINT(RT_DEBUG_INFO, ("bAPSDCapable\n"));
/* Qos bit 4 */
pData = (PUCHAR) pHeader + LENGTH_802_11;
if ((*pData >> 4) & 0x01) {
DBGPRINT(RT_DEBUG_INFO,
("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)) {
#ifdef RTMP_MAC_USB
RTEnqueueInternalCmd(pAd,
CMDTHREAD_FORCE_SLEEP_AUTO_WAKEUP,
NULL, 0);
#endif /* RTMP_MAC_USB */
}
}
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;
}
if (pAd->StaCfg.BssType == BSS_INFRA) {
/* Infrastructure mode, check address 2 for BSSID */
if (1
#ifdef QOS_DLS_SUPPORT
&& (!pAd->CommonCfg.bDLSCapable)
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
&& (!pAd->StaCfg.bTDLSCapable)
#endif /* DOT11Z_TDLS_SUPPORT */
) {
if (!RTMPEqualMemory
(&pHeader->Addr2, &pAd->MlmeAux.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->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE) {
pEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
} else {
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
/* infra or ad-hoc */
if (pAd->StaCfg.BssType == BSS_INFRA) {
RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA);
#if defined(DOT11Z_TDLS_SUPPORT) || defined(QOS_DLS_SUPPORT)
if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0))
RX_BLK_SET_FLAG(pRxBlk, fRX_DLS);
else
#endif
ASSERT(pRxWI->RxWIWirelessCliID == BSSID_WCID);
}
/* check Atheros Client */
if ((pEntry->bIAmBadAtheros == FALSE) && (pRxInfo->AMPDU == 1)
&& (pHeader->FC.Retry)) {
pEntry->bIAmBadAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE;
if (!STA_AES_ON(pAd))
RTMP_UPDATE_PROTECT(pAd, 8 , ALLN_SETPROTECT, TRUE, FALSE);
}
}
#ifdef RTMP_MAC_USB
#endif /* RTMP_MAC_USB */
#ifdef CONFIG_RX_CSO_SUPPORT
if (RTMP_TEST_MORE_FLAG(pAd, fASIC_CAP_CSO))
{
if ( pRxFceInfo->l3l4_done )
{
/*
if ( (pRxFceInfo->ip_err) || (pRxFceInfo->tcp_err)
|| (pRxFceInfo->udp_err) ) {
RTMP_SET_TCP_CHKSUM_FAIL(pRxPacket, TRUE);
}
*/
// Linux always do IP header chksum
if ( (pRxFceInfo->tcp_err) || (pRxFceInfo->udp_err) ) {
RTMP_SET_TCP_CHKSUM_FAIL(pRxPacket, TRUE);
}
}
}
#endif /* CONFIG_RX_CSO_SUPPORT */
pData = (UCHAR *) pHeader;
/*
update RxBlk->pData, DataSize
802.11 Header, QOS, HTC, Hw Padding
*/
/* 1. skip 802.11 HEADER */
#ifdef CLIENT_WDS
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_WDS)) {
pData += LENGTH_802_11_WITH_ADDR4;
} else
#endif /* CLIENT_WDS */
{
pData += LENGTH_802_11;
}
/* 2. QOS */
if (pHeader->FC.SubType & 0x08) {
RX_BLK_SET_FLAG(pRxBlk, fRX_QOS);
UserPriority = *(pData) & 0x0f;
/* bit 7 in QoS Control field signals the HT A-MSDU format */
if ((*pData) & 0x80) {
RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU);
}
/* skip QOS contorl field */
pData += 2;
}
pRxBlk->UserPriority = UserPriority;
/* check if need to resend PS Poll when received packet with MoreData = 1 */
if ((pAd->StaCfg.Psm == PWR_SAVE) && (pHeader->FC.MoreData == 1)) {
if ((((UserPriority == 0) || (UserPriority == 3)) &&
pAd->CommonCfg.bAPSDAC_BE == 0) ||
(((UserPriority == 1) || (UserPriority == 2)) &&
pAd->CommonCfg.bAPSDAC_BK == 0) ||
(((UserPriority == 4) || (UserPriority == 5)) &&
pAd->CommonCfg.bAPSDAC_VI == 0) ||
(((UserPriority == 6) || (UserPriority == 7)) &&
pAd->CommonCfg.bAPSDAC_VO == 0)) {
/* non-UAPSD delivery-enabled AC */
RTMP_PS_POLL_ENQUEUE(pAd);
}
}
/* 3. Order bit: A-Ralink or HTC+ */
if (pHeader->FC.Order) {
#ifdef AGGREGATION_SUPPORT
if ((pRxWI->RxWIPhyMode <= MODE_OFDM)
&& (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)))
{
RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK);
} else
#endif /* AGGREGATION_SUPPORT */
{
#ifdef DOT11_N_SUPPORT
RX_BLK_SET_FLAG(pRxBlk, fRX_HTC);
/* skip HTC contorl field */
pData += 4;
#endif /* DOT11_N_SUPPORT */
}
}
/* 4. skip HW padding */
if (pRxInfo->L2PAD) {
/* just move pData pointer */
/* because DataSize excluding HW padding */
RX_BLK_SET_FLAG(pRxBlk, fRX_PAD);
pData += 2;
}
#ifdef DOT11_N_SUPPORT
if (pRxInfo->BA) {
RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU);
}
#endif /* DOT11_N_SUPPORT */
#if defined(SOFT_ENCRYPT) || defined(ADHOC_WPA2PSK_SUPPORT)
/* Use software to decrypt the encrypted frame if necessary.
If a received "encrypted" unicast packet(its WEP bit as 1)
and it's passed to driver with "Decrypted" marked as 0 in pRxInfo. */
if ((pHeader->FC.Wep == 1) && (pRxInfo->Decrypted == 0)) {
PCIPHER_KEY pSwKey = NULL;
/* Cipher key table selection */
if ((pSwKey = RTMPSwCipherKeySelection(pAd,
pRxBlk->pData, pRxBlk,
pEntry)) == NULL) {
DBGPRINT(RT_DEBUG_TRACE, ("No vaild cipher key for SW decryption!!!\n"));
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
/* Decryption by Software */
if (RTMPSoftDecryptionAction(pAd,
(PUCHAR) pHeader,
UserPriority,
pSwKey,
pRxBlk->pTransData + 14,
&(pRxBlk->TransDataSize)) !=
NDIS_STATUS_SUCCESS) {
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket,
NDIS_STATUS_FAILURE);
return;
}
/* Record the Decrypted bit as 1 */
pRxInfo->Decrypted = 1;
}
#endif /* SOFT_ENCRYPT || ADHOC_WPA2PSK_SUPPORT */
/* Case I Process Broadcast & Multicast data frame */
if (pRxInfo->Bcast || pRxInfo->Mcast) {
#ifdef STATS_COUNT_SUPPORT
INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount);
#endif /* STATS_COUNT_SUPPORT */
/* 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;
}
if (ADHOC_ON(pAd)) {
MAC_TABLE_ENTRY *pAdhocEntry = NULL;
pAdhocEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pAdhocEntry)
Update_Rssi_Sample(pAd, &pAdhocEntry->RssiSample, pRxWI);
}
Indicate_Legacy_Packet_Hdr_Trns(pAd, pRxBlk, FromWhichBSSID);
return;
}
else if (pRxInfo->U2M)
{
pAd->LastRxRate = (USHORT)((pRxWI->RxWIMCS) +
(pRxWI->RxWIBW << 7) +
(pRxWI->RxWISGI << 8) +
(pRxWI->RxWISTBC << 9) +
(pRxWI->RxWIPhyMode << 14));
#if defined(DOT11Z_TDLS_SUPPORT) || defined(QOS_DLS_SUPPORT)
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) {
MAC_TABLE_ENTRY *pDlsEntry = NULL;
pDlsEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
if (pDlsEntry && (pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)) {
Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI);
NdisAcquireSpinLock(&pAd->MacTabLock);
pDlsEntry->NoDataIdleCount = 0;
NdisReleaseSpinLock(&pAd->MacTabLock);
}
} else
#endif
if (ADHOC_ON(pAd)) {
MAC_TABLE_ENTRY *pAdhocEntry = NULL;
pAdhocEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pAdhocEntry)
Update_Rssi_Sample(pAd,
&pAdhocEntry->RssiSample,
pRxWI);
}
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI);
pAd->StaCfg.LastSNR0 = (UCHAR) (pRxWI->RxWISNR0);
pAd->StaCfg.LastSNR1 = (UCHAR) (pRxWI->RxWISNR1);
#ifdef DOT11N_SS3_SUPPORT
if (pAd->CommonCfg.RxStream == 3)
pAd->StaCfg.LastSNR2 = (UCHAR) (pRxWI->RxWISNR2);
#endif /* DOT11N_SS3_SUPPORT */
pAd->RalinkCounters.OneSecRxOkDataCnt++;
if (pEntry != NULL)
{
pEntry->LastRxRate = pAd->LastRxRate;
#ifdef TXBF_SUPPORT
if (pRxWI->ShortGI)
pEntry->OneSecRxSGICount++;
else
pEntry->OneSecRxLGICount++;
#endif /* TXBF_SUPPORT */
pEntry->freqOffset = (CHAR)(pRxWI->RxWIFOFFSET);
pEntry->freqOffsetValid = TRUE;
}
#ifdef PRE_ANT_SWITCH
#endif /* PRE_ANT_SWITCH */
#ifdef RTMP_MAC_USB
/* there's packet sent to me, keep awake for 1200ms */
if (pAd->CountDowntoPsm < 12)
pAd->CountDowntoPsm = 12;
#endif /* RTMP_MAC_USB */
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->RxWIWirelessCliID];
/* process complete frame */
if (bFragment && (pRxInfo->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_Hdr_Trns(pAd, pEntry, pRxBlk, FromWhichBSSID);
return;
} else {
/*
just return because RTMPDeFragmentDataFrame() will release rx packet,
if packet is fragmented
*/
return;
}
}
#ifdef XLINK_SUPPORT
else if (pAd->StaCfg.PSPXlink) {
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
#endif /* XLINK_SUPPORT */
ASSERT(0);
/* release packet */
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
}
#endif /* HDR_TRANS_SUPPORT */
VOID STAHandleRxMgmtFrame(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
UCHAR MinSNR = 0;
do {
/* check if need to resend PS Poll when received packet with MoreData = 1 */
if ((RtmpPktPmBitCheck(pAd) == TRUE)
&& (pHeader->FC.MoreData == 1)) {
/* for UAPSD, all management frames will be VO priority */
if (pAd->CommonCfg.bAPSDAC_VO == 0) {
/* non-UAPSD delivery-enabled AC */
RTMP_PS_POLL_ENQUEUE(pAd);
}
}
/* TODO: if MoreData == 0, station can go to sleep */
/* 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))
&& (pAd->RxAnt.EvaluatePeriod == 0)) {
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI);
pAd->StaCfg.LastSNR0 = (UCHAR) (pRxWI->RxWISNR0);
pAd->StaCfg.LastSNR1 = (UCHAR) (pRxWI->RxWISNR1);
#ifdef DOT11N_SS3_SUPPORT
pAd->StaCfg.LastSNR2 = (UCHAR) (pRxWI->RxWISNR2);
#endif /* DOT11N_SS3_SUPPORT */
#ifdef PRE_ANT_SWITCH
#endif /* PRE_ANT_SWITCH */
}
if ((pHeader->FC.SubType == SUBTYPE_BEACON) &&
(ADHOC_ON(pAd)) &&
(pRxWI->RxWIWirelessCliID < MAX_LEN_OF_MAC_TABLE)) {
MAC_TABLE_ENTRY *pEntry = NULL;
pEntry = &pAd->MacTab.Content[pRxWI->RxWIWirelessCliID];
if (pEntry)
Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI);
}
#if defined(RT30xx) || defined(MT7601)
#endif /* defined(RT30xx) || defined(MT7601) */
/* First check the size, it MUST not exceed the mlme queue size */
if (pRxWI->RxWIMPDUByteCnt > MGMT_DMA_BUFFER_SIZE) {
DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->RxWIMPDUByteCnt));
break;
}
#ifdef DOT11Z_TDLS_SUPPORT
if (pHeader->FC.SubType == SUBTYPE_ACTION)
{
/* only PM bit of ACTION frame can be set */
if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE)
{
RtmpPsIndicate(pAd, pHeader->Addr2, pRxWI->WirelessCliID, pHeader->FC.PwrMgmt);
}
/*
In IEEE802.11, 11.2.1.1 STA Power Management modes,
The Power Managment bit shall not be set in any management
frame, except an Action frame.
*/
/*
In IEEE802.11e, 11.2.1.4 Power management with APSD,
If there is no unscheduled SP in progress, the unscheduled SP
begins when the QAP receives a trigger frame from a non-AP QSTA,
which is a QoS data or QoS Null frame associated with an AC the
STA has configured to be trigger-enabled.
So a management action frame is not trigger frame.
*/
}
#endif /* DOT11Z_TDLS_SUPPORT */
#ifdef MT7601
if ( IS_MT7601(pAd) )
{
MinSNR = (CHAR) pRxWI->RxWISNR0;
/* Signal in MLME_QUEUE isn't used, therefore take this item to save min SNR. */
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID, pHeader,
pRxWI->RxWIMPDUByteCnt,
pRxWI->RxWISNR2, 0,
0, MinSNR, pRxWI->RxWISNR1,
OPMODE_STA);
}
else
#endif /* MT7601 */
{
MinSNR = min((CHAR) pRxWI->RxWISNR0, (CHAR) pRxWI->RxWISNR1);
/* Signal in MLME_QUEUE isn't used, therefore take this item to save min SNR. */
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->RxWIWirelessCliID, pHeader,
pRxWI->RxWIMPDUByteCnt,
pRxWI->RxWIRSSI0, pRxWI->RxWIRSSI1,
pRxWI->RxWIRSSI2, MinSNR, 0,
OPMODE_STA);
}
#ifdef TXBF_SUPPORT
if (pAd->chipCap.FlgHwTxBfCap)
{
pRxBlk->pData += LENGTH_802_11;
pRxBlk->DataSize -= LENGTH_802_11;
if (pHeader->FC.Order) {
//handleHtcField(pAd, pRxBlk); // Ignore MCS FB
pRxBlk->pData += 4;
pRxBlk->DataSize -= 4;
}
// Check for compressed or non-compressed Sounding Response
if ( (pHeader->FC.SubType==SUBTYPE_ACTION || pHeader->FC.SubType==SUBTYPE_ACTION_NO_ACK) &&
pRxBlk->pData[0]==CATEGORY_HT &&
(pRxBlk->pData[1]==MIMO_N_BEACONFORM || pRxBlk->pData[1]==MIMO_BEACONFORM) )
{
handleBfFb(pAd, pRxBlk);
}
}
#endif /* TXBF_SUPPORT */
} while (FALSE);
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS);
}
VOID STAHandleRxControlFrame(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
#ifdef DOT11_N_SUPPORT
RXWI_STRUC *pRxWI = pRxBlk->pRxWI;
#endif /* DOT11_N_SUPPORT */
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
BOOLEAN retStatus;
NDIS_STATUS status = NDIS_STATUS_FAILURE;
switch (pHeader->FC.SubType) {
case SUBTYPE_BLOCK_ACK_REQ:
#ifdef DOT11_N_SUPPORT
{
retStatus = CntlEnqueueForRecv(pAd, pRxWI->RxWIWirelessCliID, (pRxWI->RxWIMPDUByteCnt), (PFRAME_BA_REQ) pHeader);
status = (retStatus == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
}
break;
#endif /* DOT11_N_SUPPORT */
case SUBTYPE_BLOCK_ACK:
case SUBTYPE_ACK:
default:
break;
}
RELEASE_NDIS_PACKET(pAd, pRxPacket, status);
}
/*
========================================================================
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(RTMP_ADAPTER *pAd, BOOLEAN argc)
{
NDIS_STATUS Status;
UINT32 RxProcessed, RxPending;
BOOLEAN bReschedule = FALSE;
RXD_STRUC *pRxD;
RXWI_STRUC *pRxWI;
RXINFO_STRUC *pRxInfo;
PNDIS_PACKET pRxPacket;
HEADER_802_11 *pHeader;
UCHAR *pData;
RX_BLK RxBlk;
UINT8 RXWISize = pAd->chipCap.RXWISize;
#ifdef RLT_MAC
RXFCE_INFO *pFceInfo;
#endif /* RLT_MAC */
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)) &&
!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_POLL_IDLE))
{
break;
}
RxProcessed++;
/*
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, &RxBlk, &bReschedule, &RxPending);
if (pRxPacket == NULL)
break;
/* get rx descriptor and buffer */
pRxD = (RXD_STRUC *)(&RxBlk.hw_rx_info[0]);
#ifdef RLT_MAC
pFceInfo = RxBlk.pRxFceInfo;
#endif /* RLT_MAC */
pRxInfo = RxBlk.pRxInfo;
pData = GET_OS_PKT_DATAPTR(pRxPacket);
pRxWI = (RXWI_STRUC *)pData;
pHeader = (PHEADER_802_11) (pData + RXWISize);
#ifdef RLT_MAC
// TODO: shiang-6590, handle packet from other ports
if (pFceInfo->info_type != 0)
{
DBGPRINT(RT_DEBUG_OFF, ("==>%s(): GetFrameFromOtherPorts!\n", __FUNCTION__));
hex_dump("hw_rx_info", &RxBlk.hw_rx_info[0], sizeof(RxBlk.hw_rx_info));
DBGPRINT(RT_DEBUG_TRACE, ("Dump the RxD, RxFCEInfo and RxInfo:\n"));
hex_dump("RxD", (UCHAR *)pRxD, sizeof(RXD_STRUC));
#ifdef RLT_MAC
dumpRxFCEInfo(pAd, pFceInfo);
#endif /* RLT_MAC */
dump_rxinfo(pAd, pRxInfo);
hex_dump("RxFrame", (UCHAR *)pData, (pFceInfo->pkt_len));
DBGPRINT(RT_DEBUG_OFF, ("<==\n"));
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS);
continue;
}
#endif /* RLT_MAC */
#ifdef RT_BIG_ENDIAN
RTMPFrameEndianChange(pAd, (PUCHAR) pHeader, DIR_READ, TRUE);
RTMPWIEndianChange(pAd, (PUCHAR) pRxWI, TYPE_RXWI);
#endif
if (0){
hex_dump("hw_rx_info", &RxBlk.hw_rx_info[0], sizeof(RxBlk.hw_rx_info));
DBGPRINT(RT_DEBUG_TRACE, ("==>%s():Dump the RxD, RxFCEInfo and RxInfo:\n", __FUNCTION__));
hex_dump("RxD", (UCHAR *)pRxD, sizeof(RXD_STRUC));
#ifdef RLT_MAC
dumpRxFCEInfo(pAd, pFceInfo);
#endif /* RLT_MAC */
dump_rxinfo(pAd, pRxInfo);
DBGPRINT(RT_DEBUG_TRACE, ("Dump the RxWI and RxPacket:\n"));
dump_rxwi(pAd, pRxWI);
hex_dump("RxPacket", (UCHAR *)pHeader, pRxWI->RxWIMPDUByteCnt);
DBGPRINT(RT_DEBUG_TRACE, ("<==%s():Finish dump!\n", __FUNCTION__));
}
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_RXWI)
dbQueueEnqueueRxFrame(pData, (UCHAR *)pHeader, pAd->CommonCfg.DebugFlags);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
/* build RxBlk */
RxBlk.pRxWI = pRxWI;
RxBlk.pHeader = pHeader;
RxBlk.pRxPacket = pRxPacket;
RxBlk.pData = (UCHAR *) pHeader;
RxBlk.DataSize = pRxWI->RxWIMPDUByteCnt;
RxBlk.pRxInfo = pRxInfo;
RxBlk.Flags = 0;
SET_PKT_OPMODE_STA(&RxBlk);
/* Increase Total receive byte counter after real data received no mater any error or not */
pAd->RalinkCounters.ReceivedByteCount += pRxWI->RxWIMPDUByteCnt;
pAd->RalinkCounters.OneSecReceivedByteCount += pRxWI->RxWIMPDUByteCnt;
pAd->RalinkCounters.RxCount++;
#ifdef STATS_COUNT_SUPPORT
INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount);
#endif /* STATS_COUNT_SUPPORT */
if (pRxWI->RxWIMPDUByteCnt < 14)
{
Status = NDIS_STATUS_FAILURE;
continue;
}
if (MONITOR_ON(pAd))
{
STA_MonPktSend(pAd, &RxBlk);
continue;
}
#ifdef RALINK_ATE
if (ATE_ON(pAd)) {
pAd->ate.RxCntPerSec++;
ATESampleRssi(pAd, pRxWI);
#ifdef RALINK_QA
if (pAd->ate.bQARxStart == TRUE) {
/* (*pRxD) has been swapped in GetPacketFromRxRing() */
ATE_QA_Statistics(pAd, pRxWI, pRxInfo, pHeader);
}
#ifdef TXBF_SUPPORT
if (pAd->chipCap.FlgHwTxBfCap)
{
/* Check sounding frame */
if (pHeader->FC.Type == BTYPE_MGMT)
{
RX_BLK *pRxBlk = &RxBlk;
pRxBlk->pData += LENGTH_802_11;
pRxBlk->DataSize -= LENGTH_802_11;
if (pHeader->FC.Order) {
pRxBlk->pData += 4;
pRxBlk->DataSize -= 4;
}
if ((((pHeader->FC.SubType == SUBTYPE_ACTION) || (pHeader->FC.SubType == SUBTYPE_ACTION_NO_ACK))
&& (pRxBlk ->pData)[ 0] == CATEGORY_HT
&& ((pRxBlk ->pData)[ 1] == MIMO_N_BEACONFORM //non-compressed beamforming report
|| (pRxBlk ->pData)[1] == MIMO_BEACONFORM) )) //compressed beamforming report
{
// sounding frame
//printk("Receive sounding response\n");
if (pAd->ate.sounding == 1) {
int i, Nc = ((pRxBlk ->pData)[2] & 0x3) + 1;
pAd->ate.soundingSNR[0] = (CHAR)((pRxBlk ->pData)[8]);
pAd->ate.soundingSNR[1] = (Nc<2)? 0: (CHAR)((pRxBlk ->pData)[9]);
pAd->ate.soundingSNR[2] = (Nc<3)? 0: (CHAR)((pRxBlk ->pData)[10]);
pAd->ate.sounding = 2;
pAd->ate.soundingRespSize = pRxBlk->DataSize;
for (i=0; i<pRxBlk->DataSize && i<sizeof(pAd->ate.soundingResp); i++)
pAd->ate.soundingResp[i] = pRxBlk->pData[i];
}
}
// Roger Debug : Fix Me
else
{
if (pHeader->FC.Order)
DBGPRINT( RT_DEBUG_WARN, ("fcsubtype=%x\ndata[0]=%x\ndata[1]=%x\n", pHeader->FC.SubType, (pRxBlk ->pData)[ 0], (pRxBlk ->pData)[1]));
}
}
}
#endif /* TXBF_SUPPORT */
#endif /* RALINK_QA */
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS);
continue;
}
#endif /* RALINK_ATE */
/* Check for all RxD errors */
Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxInfo);
/* Handle the received frame */
if (Status == NDIS_STATUS_SUCCESS) {
#ifdef RTMP_FREQ_CALIBRATION_SUPPORT
if (pAd->chipCap.FreqCalibrationSupport)
{
if ((pAd->FreqCalibrationCtrl.bEnableFrequencyCalibration == TRUE)
&& (INFRA_ON(pAd)) && (pRxInfo->Crc == 0)
&& (pHeader->FC.Type == BTYPE_MGMT)
&& (pHeader->FC.SubType == SUBTYPE_BEACON)
&& (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))
{
pAd->FreqCalibrationCtrl.LatestFreqOffsetOverBeacon =
GetFrequencyOffset(pAd, pRxWI);
pAd->FreqCalibrationCtrl.BeaconPhyMode = (UCHAR) (pRxWI->RxWIPhyMode);
DBGPRINT(RT_DEBUG_INFO,
("%s: Beacon, CRC error = %d, pHeader->Sequence = %d, SA = %02X:%02X:%02X:%02X:%02X:%02X, frequency offset = %d, MCS = %d, BW = %d PHYMODE = %d\n",
__FUNCTION__, pRxInfo->Crc,
pHeader->Sequence, PRINT_MAC(pHeader->Addr2),
((CHAR) (pRxWI->RxWIFOFFSET)), pRxWI->RxWIMCS,
pRxWI->RxWIBW, pRxWI->RxWIPhyMode));
}
}
#endif /* RTMP_FREQ_CALIBRATION_SUPPORT */
switch (pHeader->FC.Type) {
case BTYPE_DATA:
#ifdef MT7601
#endif /* MT7601 */
#ifdef HDR_TRANS_SUPPORT
RxBlk.bHdrRxTrans = pRxInfo->ip_sum_err; /* RXINFO bit 31 */
if ( RxBlk.bHdrRxTrans )
{
RxBlk.bHdrVlanTaged = pRxInfo->tcp_sum_err; /* RXINFO bit 30 */
RxBlk.pTransData = (UCHAR *) pHeader + 38; /* 36 byte - RX WIFI Size ( 802.11 Header ) */
//RxBlk.TransDataSize = pRxWI->RxWIMPDUByteCnt - 4;
RxBlk.TransDataSize = pRxWI->RxWIMPDUByteCnt;
RxBlk.DataSize += 36;
STAHandleRxDataFrame_Hdr_Trns(pAd, &RxBlk);
}
else
#endif /* HDR_TRANS_SUPPORT */
STAHandleRxDataFrame(pAd, &RxBlk);
break;
case BTYPE_MGMT:
STAHandleRxMgmtFrame(pAd, &RxBlk);
break;
case BTYPE_CNTL:
STAHandleRxControlFrame(pAd, &RxBlk);
break;
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;
}
BOOLEAN STAHandleRxDonePacket(
IN RTMP_ADAPTER *pAd,
IN PNDIS_PACKET pRxPacket,
IN RX_BLK *pRxBlk)
{
RXD_STRUC *pRxD;
RXWI_STRUC *pRxWI;
RXINFO_STRUC *pRxInfo;
PHEADER_802_11 pHeader;
BOOLEAN bReschedule = FALSE;
NDIS_STATUS Status;
pRxWI = pRxBlk->pRxWI;
pRxD = (RXD_STRUC *)&pRxBlk->hw_rx_info[0];
pRxInfo = pRxBlk->pRxInfo;
pHeader = pRxBlk->pHeader;
SET_PKT_OPMODE_STA(pRxBlk);
if (MONITOR_ON(pAd))
{
/*send_monitor_packets(pAd, pRxBlk, RTMPMaxRssi, ConvertToRssi);*/
STA_MonPktSend(pAd, pRxBlk);
return bReschedule;
}
/* STARxDoneInterruptHandle() is called in rtusb_bulk.c */
#ifdef RALINK_ATE
if (ATE_ON(pAd))
{
pAd->ate.RxCntPerSec++;
ATESampleRssi(pAd, pRxWI);
#ifdef RALINK_QA
if (pAd->ate.bQARxStart == TRUE)
{
/* (*pRxD) has been swapped in GetPacketFromRxRing() */
ATE_QA_Statistics(pAd, pRxWI, pRxInfo, pHeader);
}
#ifdef TXBF_SUPPORT
if (pAd->chipCap.FlgHwTxBfCap)
{
/* Check sounding frame */
if (pHeader->FC.Type == BTYPE_MGMT)
{
pRxBlk->pData += LENGTH_802_11;
pRxBlk->DataSize -= LENGTH_802_11;
if (pHeader->FC.Order)
{
pRxBlk->pData += 4;
pRxBlk->DataSize -= 4;
}
if ((((pHeader->FC.SubType == SUBTYPE_ACTION) || (pHeader->FC.SubType == SUBTYPE_ACTION_NO_ACK))
&& (pRxBlk ->pData)[ 0] == CATEGORY_HT
&& ((pRxBlk ->pData)[ 1] == MIMO_N_BEACONFORM /* non-compressed beamforming report */
|| (pRxBlk ->pData)[1] == MIMO_BEACONFORM) )) /* compressed beamforming report */
{
/* sounding frame */
/*printk("Receive sounding response\n"); */
if (pAd->ate.sounding == 1)
{
int i, Nc = ((pRxBlk ->pData)[2] & 0x3) + 1;
pAd->ate.soundingSNR[0] = (CHAR)((pRxBlk ->pData)[8]);
pAd->ate.soundingSNR[1] = (Nc<2)? 0: (CHAR)((pRxBlk ->pData)[9]);
pAd->ate.soundingSNR[2] = (Nc<3)? 0: (CHAR)((pRxBlk ->pData)[10]);
pAd->ate.sounding = 2;
pAd->ate.soundingRespSize = pRxBlk->DataSize;
for (i=0; i<pRxBlk->DataSize && i<sizeof(pAd->ate.soundingResp); i++)
pAd->ate.soundingResp[i] = pRxBlk->pData[i];
}
}
else
{
if (pHeader->FC.Order)
DBGPRINT( RT_DEBUG_WARN, ("fcsubtype=%x\ndata[0]=%x\ndata[1]=%x\n", pHeader->FC.SubType, (pRxBlk ->pData)[ 0], (pRxBlk ->pData)[1]));
}
}
}
#endif /* TXBF_SUPPORT */
#endif /* RALINK_QA */
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS);
return bReschedule;
}
#endif /* RALINK_ATE */
/* Check for all RxD errors */
Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxInfo);
/* Handle the received frame */
if (Status == NDIS_STATUS_SUCCESS)
{
#ifdef RTMP_FREQ_CALIBRATION_SUPPORT
if (pAd->chipCap.FreqCalibrationSupport)
{
if ((pAd->FreqCalibrationCtrl.bEnableFrequencyCalibration == TRUE)
&& (INFRA_ON(pAd)) && (pRxInfo->Crc == 0)
&& (pHeader->FC.Type == BTYPE_MGMT)
&& (pHeader->FC.SubType == SUBTYPE_BEACON)
&& (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))
{
pAd->FreqCalibrationCtrl.LatestFreqOffsetOverBeacon = GetFrequencyOffset(pAd, pRxWI);
pAd->FreqCalibrationCtrl.BeaconPhyMode = (UCHAR) (pRxWI->RxWIPhyMode);
DBGPRINT(RT_DEBUG_INFO,
("%s: Beacon, CRC error = %d, pHeader->Sequence = %d, SA = %02X:%02X:%02X:%02X:%02X:%02X, frequency offset = %d, MCS = %d, BW = %d PHYMODE = %d\n",
__FUNCTION__, pRxInfo->Crc,
pHeader->Sequence, PRINT_MAC(pHeader->Addr2),
((CHAR) (pRxWI->RxWIFOFFSET)), pRxWI->RxWIMCS,
pRxWI->RxWIBW, pRxWI->RxWIPhyMode));
}
}
#endif /* RTMP_FREQ_CALIBRATION_SUPPORT */
switch (pHeader->FC.Type)
{
case BTYPE_DATA:
STAHandleRxDataFrame(pAd, pRxBlk);
break;
case BTYPE_MGMT:
STAHandleRxMgmtFrame(pAd, pRxBlk);
break;
case BTYPE_CNTL:
STAHandleRxControlFrame(pAd, pRxBlk);
break;
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 */
if (INFRA_ON(pAd) && (0
#ifdef QOS_DLS_SUPPORT
|| (pAd->CommonCfg.bDLSCapable)
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
|| IS_TDLS_SUPPORT(pAd)
#endif /* DOT11Z_TDLS_SUPPORT */
)) {
MAC_TABLE_ENTRY *pEntry;
PUCHAR pSrcBufVA =
GET_OS_PKT_DATAPTR(pPacket);
pEntry = MacTableLookup(pAd, pSrcBufVA);
if (pEntry
&& (IS_ENTRY_DLS(pEntry)
#ifdef DOT11Z_TDLS_SUPPORT
|| IS_ENTRY_TDLS(pEntry)
#endif /* DOT11Z_TDLS_SUPPORT */
)) {
RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid);
} else {
RTMP_SET_PACKET_WCID(pPacket, 0);
}
} else {
RTMP_SET_PACKET_WCID(pPacket, 0);
}
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 Rate;
#ifdef CONFIG_MULTI_CHANNEL
if ((pAd->P2pCfg.bStartP2pConnect) && (pAd->Multi_Channel_Enable == TRUE))
{
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
#endif /*CONFIG_MULTI_CHANNEL*/
/* 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 (pAd->StaCfg.BssType == BSS_INFRA) {
#if defined(QOS_DLS_SUPPORT) || defined(DOT11Z_TDLS_SUPPORT)
USHORT tmpWcid;
tmpWcid = RTMP_GET_PACKET_WCID(pPacket);
if (VALID_WCID(tmpWcid) &&
(IS_ENTRY_DLS(&pAd->MacTab.Content[tmpWcid]) ||
IS_ENTRY_TDLS(&pAd->MacTab.Content[tmpWcid]))) {
pEntry = &pAd->MacTab.Content[tmpWcid];
Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate;
} else
#endif
{
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 {
#ifdef XLINK_SUPPORT
if (pAd->StaCfg.PSPXlink) {
pEntry =
&pAd->MacTab.Content[MCAST_WCID];
pEntry->Aid = MCAST_WCID;
} else
#endif /* XLINK_SUPPORT */
pEntry = MacTableLookup(pAd, pSrcBufVA);
if (pEntry)
RTMP_SET_PACKET_WCID(pPacket,
pEntry->Aid);
}
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). */
UserPriority = 0;
QueIdx = QID_AC_BE;
RTMPCheckEtherType(pAd, pPacket, pEntry, OPMODE_STA, &UserPriority, &QueIdx);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
/* the code must behind RTMPCheckEtherType() to get QueIdx */
if ((pEntry != NULL) &&
(pEntry->PsMode == PWR_SAVE) &&
(pEntry->FlgPsModeIsWakeForAWhile == FALSE) &&
(pEntry->bAPSDDeliverEnabledPerAC[QueIdx] == 0))
{
/* the packet will be sent to AP, not the peer directly */
pEntry = &pAd->MacTab.Content[BSSID_WCID];
/* for AP entry, pEntry->bAPSDDeliverEnabledPerAC[QueIdx] always is 0 */
RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID);
Rate = pAd->CommonCfg.TxRate;
}
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
#ifdef WAPI_SUPPORT
/* Check the status of the controlled port and filter the outgoing frame for WAPI */
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAICERT) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAIPSK))
&& (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)
&& (RTMP_GET_PACKET_WAI(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);
}
#endif /* WAPI_SUPPORT */
/* 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 */
)
&& ((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);
}
#ifdef WSC_STA_SUPPORT
if ((pAd->StaCfg.WscControl.WscConfMode != WSC_DISABLE) &&
(pAd->StaCfg.WscControl.bWscTrigger == TRUE) &&
(RTMP_GET_PACKET_EAPOL(pPacket) == FALSE)) {
DBGPRINT(RT_DEBUG_TRACE,
("STASendPacket --> Drop packet before WPS process completed !!!\n"));
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return (NDIS_STATUS_FAILURE);
}
#endif /* WSC_STA_SUPPORT */
/*
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
*/
if (NumberOfFrag > 1)
RTSRequired =
(pAd->CommonCfg.FragmentThreshold >
pAd->CommonCfg.RtsThreshold) ? 1 : 0;
else
RTSRequired =
(PacketInfo.TotalPacketLength >
pAd->CommonCfg.RtsThreshold) ? 1 : 0;
/* Save RTS requirement to Ndis packet reserved field */
RTMP_SET_PACKET_RTS(pPacket, RTSRequired);
RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate);
RTMP_SET_PACKET_UP(pPacket, UserPriority);
#ifdef IP_ASSEMBLY
if (pAd->StaCfg.bFragFlag == TRUE) {
static QUEUE_HEADER queue1[4], queue2[4];
static BOOLEAN is_init = 0;
static INT32 ID1[4] = { -1, -1, -1, -1 }, ID2[4] = {
-1, -1, -1, -1};
static INT32 ID1_FragSize[4] =
{ -1, -1, -1, -1 }, ID2_FragSize[4] = {
-1, -1, -1, -1};
static ULONG jiffies1[4], jiffies2[4];
QUEUE_HEADER *pAC_Queue1, *pAC_Queue2;
INT32 *pAC_ID1, *pAC_ID2, *pAC_ID1_FragSize, *pAC_ID2_FragSize;
ULONG *pAC_Jiffies1, *pAC_Jiffies2;
UINT32 i;
typedef union ip_flags_frag_offset {
struct {
#ifdef RT_BIG_ENDIAN
USHORT flags_reserved:1;
USHORT flags_may_frag:1;
USHORT flags_more_frag:1;
USHORT frag_offset:13;
#else
USHORT frag_offset:13;
USHORT flags_more_frag:1;
USHORT flags_may_frag:1;
USHORT flags_reserved:1;
#endif
} field;
USHORT word;
} IP_FLAGS_FRAG_OFFSET;
typedef struct ip_v4_hdr {
#ifdef RT_BIG_ENDIAN
UCHAR version:4, ihl:4;
#else
UCHAR ihl:4, version:4;
#endif
UCHAR tos;
USHORT tot_len;
USHORT identifier;
} IP_V4_HDR;
IP_V4_HDR *pIpv4Hdr, Ipv4Hdr;
IP_FLAGS_FRAG_OFFSET *pFlags_frag_offset, Flags_frag_offset;
ULONG Now;
if (is_init == 0) {
for (i = 0; i < 4; i++) {
InitializeQueueHeader(&queue1[i]);
InitializeQueueHeader(&queue2[i]);
}
is_init = 1;
}
pAC_Queue1 = &queue1[QueIdx];
pAC_Queue2 = &queue2[QueIdx];
pAC_ID1 = &ID1[QueIdx];
pAC_ID2 = &ID2[QueIdx];
pAC_ID1_FragSize = &ID1_FragSize[QueIdx];
pAC_ID2_FragSize = &ID2_FragSize[QueIdx];
pAC_Jiffies1 = &jiffies1[QueIdx];
pAC_Jiffies2 = &jiffies2[QueIdx];
NdisGetSystemUpTime(&Now);
if ((pAC_Queue1->Number != 0)
&& (RTMP_TIME_AFTER(Now, (*pAC_Jiffies1) + (1000 * OS_HZ))))
{
PQUEUE_ENTRY pBackupPktEntry;
PNDIS_PACKET pBackupPkt;
while (1) {
pBackupPktEntry = RemoveHeadQueue(pAC_Queue1);
if (pBackupPktEntry == NULL)
break;
pBackupPkt =
QUEUE_ENTRY_TO_PACKET(pBackupPktEntry);
RELEASE_NDIS_PACKET(pAd, pBackupPkt,
NDIS_STATUS_FAILURE);
}
*pAC_ID1 = -1;
*pAC_ID1_FragSize = -1;
*pAC_Jiffies1 = 0;
}
NdisGetSystemUpTime(&Now);
if ((pAC_Queue2->Number != 0)
&& (RTMP_TIME_AFTER(Now, (*pAC_Jiffies2) + (1000 * OS_HZ))))
{
PQUEUE_ENTRY pBackupPktEntry;
PNDIS_PACKET pBackupPkt;
while (1) {
pBackupPktEntry = RemoveHeadQueue(pAC_Queue2);
if (pBackupPktEntry == NULL)
break;
pBackupPkt =
QUEUE_ENTRY_TO_PACKET(pBackupPktEntry);
RELEASE_NDIS_PACKET(pAd, pBackupPkt,
NDIS_STATUS_FAILURE);
}
*pAC_ID2 = -1;
*pAC_ID2_FragSize = -1;
*pAC_Jiffies2 = 0;
}
if (RTMP_GET_PACKET_IPV4(pPacket) &&
((pAd->TxSwQueue[QueIdx].Number >=
(pAd->TxSwQMaxLen >> 1)) || ((pAC_Queue1->Number)
|| (pAC_Queue2->Number)))
) {
pIpv4Hdr =
(IP_V4_HDR *) (PacketInfo.pFirstBuffer +
LENGTH_802_3);
pFlags_frag_offset =
(IP_FLAGS_FRAG_OFFSET *) (PacketInfo.pFirstBuffer +
LENGTH_802_3 + 6);
Flags_frag_offset.word =
ntohs(pFlags_frag_offset->word);
Ipv4Hdr.identifier = ntohs(pIpv4Hdr->identifier);
Ipv4Hdr.tot_len = ntohs(pIpv4Hdr->tot_len);
Ipv4Hdr.ihl = pIpv4Hdr->ihl;
/* check if 1st fragment */
if ((Flags_frag_offset.field.flags_more_frag == 1) &&
(Flags_frag_offset.field.frag_offset == 0)) {
NdisGetSystemUpTime(&Now);
if ((*pAC_ID1) == -1) {
*pAC_ID1 = Ipv4Hdr.identifier;
*pAC_Jiffies1 = Now;
*pAC_ID1_FragSize =
Ipv4Hdr.tot_len - (Ipv4Hdr.ihl * 4);
InsertTailQueue(pAC_Queue1,
PACKET_TO_QUEUE_ENTRY
(pPacket));
} else if ((*pAC_ID2) == -1) {
*pAC_ID2 = Ipv4Hdr.identifier;
*pAC_Jiffies2 = Now;
*pAC_ID2_FragSize =
Ipv4Hdr.tot_len - (Ipv4Hdr.ihl * 4);
InsertTailQueue(pAC_Queue2,
PACKET_TO_QUEUE_ENTRY
(pPacket));
} else {
QUEUE_HEADER *pTempqueue;
PQUEUE_ENTRY pBackupPktEntry;
PNDIS_PACKET pBackupPkt;
/* free backup fragments */
if ((*pAC_Jiffies1) > (*pAC_Jiffies2)) {
pTempqueue = pAC_Queue2;
*pAC_ID2 = Ipv4Hdr.identifier;
} else {
pTempqueue = pAC_Queue1;
*pAC_ID1 = Ipv4Hdr.identifier;
}
if (pTempqueue->Number != 0) {
while (1) {
pBackupPktEntry =
RemoveHeadQueue
(pTempqueue);
if (pBackupPktEntry ==
NULL)
break;
pBackupPkt =
QUEUE_ENTRY_TO_PACKET
(pBackupPktEntry);
RELEASE_NDIS_PACKET(pAd,
pBackupPkt,
NDIS_STATUS_FAILURE);
}
}
}
} else {
/* check if last fragment */
if ((Ipv4Hdr.identifier == (*pAC_ID1))
|| (Ipv4Hdr.identifier == (*pAC_ID2))) {
QUEUE_HEADER *pTempqueue;
PQUEUE_ENTRY pBackupPktEntry;
PNDIS_PACKET pBackupPkt;
if (Ipv4Hdr.identifier == (*pAC_ID1)) {
InsertTailQueue(pAC_Queue1,
PACKET_TO_QUEUE_ENTRY
(pPacket));
pTempqueue = pAC_Queue1;
} else {
InsertTailQueue(pAC_Queue2,
PACKET_TO_QUEUE_ENTRY
(pPacket));
pTempqueue = pAC_Queue2;
}
/* the last fragment */
if ((Flags_frag_offset.field.
flags_more_frag == 0)
&& (Flags_frag_offset.field.
frag_offset != 0)) {
UINT32 fragment_count = 0;
BOOLEAN bDrop = FALSE;
if (Ipv4Hdr.identifier ==
(*pAC_ID1)) {
fragment_count =
((Flags_frag_offset.
field.
frag_offset * 8) /
(*pAC_ID1_FragSize))
+ 1;
if (pTempqueue->
Number !=
fragment_count)
bDrop = TRUE;
*pAC_ID1 = -1;
}
if (Ipv4Hdr.identifier ==
(*pAC_ID2)) {
fragment_count =
((Flags_frag_offset.
field.
frag_offset * 8) /
(*pAC_ID2_FragSize))
+ 1;
if (pTempqueue->
Number !=
fragment_count)
bDrop = TRUE;
*pAC_ID2 = -1;
}
/* if number does not equal coreect fragment count or no enough space, */
/* free backup fragments to SwTxQueue[] */
if ((bDrop == TRUE) ||
(pAd->TxSwQueue[QueIdx].Number > (pAd->TxSwQMaxLen - pTempqueue->Number))) {
while (1) {
pBackupPktEntry = RemoveHeadQueue(pTempqueue);
if (pBackupPktEntry == NULL)
break;
pBackupPkt = QUEUE_ENTRY_TO_PACKET(pBackupPktEntry);
RELEASE_NDIS_PACKET(pAd, pBackupPkt, NDIS_STATUS_FAILURE);
}
return
NDIS_STATUS_SUCCESS;
}
/* move backup fragments to SwTxQueue[] */
NdisAcquireSpinLock(&pAd->TxSwQueueLock[QueIdx]);
while (1) {
pBackupPktEntry = RemoveHeadQueue(pTempqueue);
if (pBackupPktEntry == NULL)
break;
InsertTailQueueAc(pAd,
pEntry,
&pAd->TxSwQueue[QueIdx],
pBackupPktEntry);
}
NdisReleaseSpinLock(&pAd->TxSwQueueLock[QueIdx]);
}
} else {
/*
bypass none-fist fragmented packets (we should not drop this packet)
when
1. (pAd->TxSwQueue[QueIdx].Number >= (pAd->TxSwQMaxLen[QueIdx] >> 1)
and
2. two fragmented buffer are empty
*/
if (((*pAC_ID1) == -1)
&& ((*pAC_ID2) == -1)) {
goto normal_drop;
}
if ((Flags_frag_offset.field.flags_more_frag != 0)
&& (Flags_frag_offset.field.frag_offset != 0)) {
NdisAcquireSpinLock(&pAd->TxSwQueueLock[QueIdx]);
RELEASE_NDIS_PACKET(pAd,
pPacket,
NDIS_STATUS_FAILURE);
NdisReleaseSpinLock(&pAd->TxSwQueueLock[QueIdx]);
return NDIS_STATUS_SUCCESS;
} else {
goto normal_drop;
}
}
}
} else
goto normal_drop;
} else {
normal_drop:
#endif /* IP_ASSEMBLY */
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
if ((pEntry != NULL) &&
(pEntry->PsMode == PWR_SAVE) &&
(pEntry->FlgPsModeIsWakeForAWhile == FALSE) &&
(pEntry->bAPSDDeliverEnabledPerAC[QueIdx] != 0))
{
/*
only UAPSD of the peer for the queue is set;
for non-UAPSD queue, we will send it to the AP.
*/
if (RtmpInsertPsQueue(pAd, pPacket, pEntry, QueIdx) != NDIS_STATUS_SUCCESS)
return NDIS_STATUS_FAILURE;
}
else
/* non-PS mode or send PS packet to AP */
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
{
/* Make sure SendTxWait queue resource won't be used by other threads */
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
if (pAd->TxSwQueue[QueIdx].Number >= pAd->TxSwQMaxLen) {
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 {
InsertTailQueueAc(pAd, pEntry, &pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket));
}
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
}
#ifdef IP_ASSEMBLY
}
#endif /* IP_ASSEMBLY */
#ifdef DOT11_N_SUPPORT
if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE) &&
(pEntry->NoBADataCountDown == 0) && IS_HT_STA(pEntry)) {
if (((pEntry->TXBAbitmap & (1 << UserPriority)) == 0) &&
((pEntry->BADeclineBitmap & (1 << UserPriority)) == 0) &&
(pEntry->PortSecured == WPA_802_1X_PORT_SECURED)
&&
((IS_ENTRY_CLIENT(pEntry) && pAd->MlmeAux.APRalinkIe != 0x0)
|| (pEntry->WepStatus != Ndis802_11WEPEnabled
&& pEntry->WepStatus != Ndis802_11Encryption2Enabled))
&&
(!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)))
#ifdef RT3290
&& (!(IS_RT3290(pAd) && pAd->WlanBTCoexInfo.ampduOff == TRUE))
#endif /* RT3290 */
)
{
BAOriSessionSetUp(pAd, pEntry, UserPriority, 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 RTMP_MAC_USB
/*
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 /* RTMP_MAC_USB */
VOID RTMPSendNullFrame(
IN PRTMP_ADAPTER pAd,
IN UCHAR TxRate,
IN BOOLEAN bQosNull,
IN USHORT PwrMgmt)
{
UCHAR NullFrame[48];
ULONG Length;
PHEADER_802_11 pHeader_802_11;
#ifdef CONFIG_MULTI_CHANNEL
if ((pAd->P2pCfg.bStartP2pConnect) && (pAd->Multi_Channel_Enable == TRUE))
return;
#endif /*CONFIG_MULTI_CHANNEL*/
#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
#ifdef WAPI_SUPPORT
|| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAICERT)
|| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAIPSK)
#endif /* WAPI_SUPPORT */
) && (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 {
BOOLEAN FlgCanPmBitSet = TRUE;
#ifdef DOT11Z_TDLS_SUPPORT
/* check TDLS condition */
if (pAd->StaCfg.TdlsInfo.TdlsFlgIsKeepingActiveCountDown == TRUE)
FlgCanPmBitSet = FALSE;
#endif /* DOT11Z_TDLS_SUPPORT */
if (FlgCanPmBitSet == TRUE)
pHeader_802_11->FC.PwrMgmt = PwrMgmt;
else
pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE;
}
pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14);
/* sequence is increased in MlmeHardTx */
pHeader_802_11->Sequence = pAd->Sequence;
pAd->Sequence = (pAd->Sequence + 1) & MAXSEQ; /* next 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);
}
#ifdef CONFIG_MULTI_CHANNEL
VOID RTMPP2PSendNullFrame(
IN PRTMP_ADAPTER pAd,
IN UCHAR TxRate,
IN BOOLEAN bQosNull,
IN USHORT PwrMgmt)
{
UCHAR NullFrame[48];
ULONG Length;
PHEADER_802_11 pHeader_802_11;
PAPCLI_STRUCT pApCliEntry = NULL;
PMAC_TABLE_ENTRY pEntry = NULL;
pApCliEntry = &pAd->ApCfg.ApCliTab[0];
#ifdef RALINK_ATE
if (ATE_ON(pAd)) {
return;
}
#endif /* RALINK_ATE */
if (pApCliEntry == NULL || !pApCliEntry->Valid)
return;
pEntry = MacTableLookup(pAd, pApCliEntry->CfgApCliBssid);
if (pEntry == NULL)
return;
/* WPA 802.1x secured port control */
if (((pEntry->AuthMode == Ndis802_11AuthModeWPA) ||
(pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
(pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
) && (pEntry->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, pEntry->Addr);
COPY_MAC_ADDR(pHeader_802_11->Addr2, pApCliEntry->CurrentAddress);
COPY_MAC_ADDR(pHeader_802_11->Addr3, pApCliEntry->CfgApCliBssid);
if (pAd->CommonCfg.bAPSDForcePowerSave)
{
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
}
else
{
BOOLEAN FlgCanPmBitSet = TRUE;
#ifdef DOT11Z_TDLS_SUPPORT
/* check TDLS condition */
if (pAd->StaCfg.TdlsInfo.TdlsFlgIsKeepingActiveCountDown == TRUE)
FlgCanPmBitSet = FALSE;
#endif /* DOT11Z_TDLS_SUPPORT */
if (FlgCanPmBitSet == TRUE)
pHeader_802_11->FC.PwrMgmt = PwrMgmt;
else
pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE;
}
pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14);
/* sequence is increased in MlmeHardTx */
pHeader_802_11->Sequence = pAd->Sequence;
pAd->Sequence = (pAd->Sequence + 1) & MAXSEQ; /* next 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 */
}
DBGPRINT(RT_DEBUG_OFF, (" RTMPP2PSendNullFrame Addr = %02x:%02x:%02x:%02x:%02x:%02x pwr=%d\n", PRINT_MAC(pHeader_802_11->Addr1),PwrMgmt));
//iversonnote
HAL_KickOutNullFrameTx(pAd, HCCA_PIPE, NullFrame, Length);
}
#endif /*CONFIG_MULTI_CHANNEL*/
/*
--------------------------------------------------------
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;
PMAC_TABLE_ENTRY pMacEntry;
pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket);
pMacEntry = pTxBlk->pMacEntry;
#ifdef WAPI_SUPPORT
if (pMacEntry
&& (pMacEntry->WepStatus == Ndis802_11EncryptionSMS4Enabled)) {
if (RTMP_GET_PACKET_WAI(pTxBlk->pPacket)) {
/* WAI negotiation packet is always clear. */
CipherAlg = CIPHER_NONE;
pKey = NULL;
} else {
KeyIdx = pMacEntry->usk_id; /* USK ID */
CipherAlg = pMacEntry->PairwiseKey.CipherAlg;
if (CipherAlg == CIPHER_SMS4) {
pKey = &pMacEntry->PairwiseKey;
#ifdef SOFT_ENCRYPT
if (CLIENT_STATUS_TEST_FLAG
(pMacEntry,
fCLIENT_STATUS_SOFTWARE_ENCRYPT)) {
TX_BLK_SET_FLAG(pTxBlk, fTX_bSwEncrypt);
/* TSC increment pre encryption transmittion */
inc_iv_byte(pKey->TxTsc, LEN_WAPI_TSC,
2);
}
#endif /* SOFT_ENCRYPT */
}
}
} else
#endif /* WAPI_SUPPORT */
{
/* 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;
#ifdef ADHOC_WPA2PSK_SUPPORT
else if ((ADHOC_ON(pAd))
&& (Cipher == Ndis802_11Encryption3Enabled)
&& (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
&& (pAd->StaCfg.PortSecured ==
WPA_802_1X_PORT_SECURED)) {
CipherAlg = CIPHER_AES;
pKey = &pAd->SharedKey[BSS0][KeyIdx];
}
#endif /* ADHOC_WPA2PSK_SUPPORT */
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 {
CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg;
pKey = &pAd->SharedKey[BSS0][KeyIdx];
}
}
pTxBlk->CipherAlg = CipherAlg;
pTxBlk->pKey = pKey;
pTxBlk->KeyIdx = KeyIdx;
}
#ifdef HDR_TRANS_SUPPORT
VOID STABuildWifiInfo(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
PWIFI_INFO_STRUC pWI;
#ifdef QOS_DLS_SUPPORT
BOOLEAN bDLSFrame = FALSE;
INT DlsEntryIndex = 0;
#endif /* QOS_DLS_SUPPORT */
UINT8 TXWISize = pAd->chipCap.TXWISize;
pTxBlk->MpduHeaderLen = WIFI_INFO_SIZE;
pWI =
(WIFI_INFO_STRUC *) & pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
NdisZeroMemory(pWI, WIFI_INFO_SIZE);
pWI->field.QoS = (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? 1 : 0;
#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)) {
pWI->field.Seq_Num =
pTxBlk->pMacEntry->NonQosDataSeq;
pTxBlk->pMacEntry->NonQosDataSeq =
(pTxBlk->pMacEntry->NonQosDataSeq + 1) & MAXSEQ;
} else {
pWI->field.Seq_Num =
pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority];
pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] =
(pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] + 1) & MAXSEQ;
}
} else {
pWI->field.Seq_Num = pAd->Sequence;
pAd->Sequence = (pAd->Sequence + 1) & MAXSEQ; /* next sequence */
}
pWI->field.More_Data = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData);
if (pAd->StaCfg.BssType == BSS_INFRA) {
#ifdef QOS_DLS_SUPPORT
if (bDLSFrame)
pWI->field.Mode = 0; /* IBSS */
else
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bTdlsEntry))
pWI->field.Mode = 0; /* IBSS */
else
#endif /* DOT11Z_TDLS_SUPPORT */
pWI->field.Mode = 2; /* STA*/
} else if (ADHOC_ON(pAd)) {
pWI->field.Mode = 0; /* IBSS */
}
if (pTxBlk->CipherAlg != CIPHER_NONE)
pWI->field.WEP = 1;
if (pAd->CommonCfg.bAPSDForcePowerSave)
pWI->field.PS = PWR_SAVE;
else
pWI->field.PS = (pAd->StaCfg.Psm == PWR_SAVE);
}
VOID STABuildCacheWifiInfo(
IN RTMP_ADAPTER *pAd,
IN TX_BLK *pTxBlk,
IN UCHAR *pWiInfo)
{
PWIFI_INFO_STRUC pWI;
MAC_TABLE_ENTRY *pMacEntry;
pWI = (PWIFI_INFO_STRUC)pWiInfo;
pMacEntry = pTxBlk->pMacEntry;
pTxBlk->MpduHeaderLen = WIFI_INFO_SIZE;
/* More Bit */
pWI->field.More_Data = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData);
/* Sequence */
pWI->field.Seq_Num = 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) {
pWI->field.Mode = 0; /* IBSS */
} else
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bTdlsEntry)) {
pWI->field.Mode = 0; /* IBSS */
} else
#endif /* DOT11Z_TDLS_SUPPORT */
if (ADHOC_ON(pAd))
pWI->field.Mode = 0; /* IBSS */
else {
pWI->field.Mode = 2; /* STA*/
}
}
/*
-----------------------------------------------------------------
STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later.
-----------------------------------------------------------------
*/
if (pAd->CommonCfg.bAPSDForcePowerSave)
pWI->field.PS = PWR_SAVE;
else
pWI->field.PS = (pAd->StaCfg.Psm == PWR_SAVE);
}
#endif /* HDR_TRANS_SUPPORT */
VOID STABuildCommon802_11Header(RTMP_ADAPTER *pAd, TX_BLK *pTxBlk)
{
HEADER_802_11 *wifi_hdr;
#ifdef QOS_DLS_SUPPORT
BOOLEAN bDLSFrame = FALSE;
INT DlsEntryIndex = 0;
#endif /* QOS_DLS_SUPPORT */
UINT8 TXWISize = pAd->chipCap.TXWISize;
/* MAKE A COMMON 802.11 HEADER */
/* normal wlan header size : 24 octets */
pTxBlk->MpduHeaderLen = sizeof (HEADER_802_11);
wifi_hdr = (HEADER_802_11 *)&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize + TSO_SIZE];
NdisZeroMemory(wifi_hdr, sizeof (HEADER_802_11));
wifi_hdr->FC.FrDs = 0;
wifi_hdr->FC.Type = BTYPE_DATA;
wifi_hdr->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)) {
wifi_hdr->Sequence = pTxBlk->pMacEntry->NonQosDataSeq;
pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq + 1) & MAXSEQ;
} else {
wifi_hdr->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority];
pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] + 1) & MAXSEQ;
}
} else {
wifi_hdr->Sequence = pAd->Sequence;
pAd->Sequence = (pAd->Sequence + 1) & MAXSEQ; /* next sequence */
}
wifi_hdr->Frag = 0;
wifi_hdr->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData);
{
if (pAd->StaCfg.BssType == BSS_INFRA) {
#ifdef QOS_DLS_SUPPORT
if (bDLSFrame) {
COPY_MAC_ADDR(wifi_hdr->Addr1, pTxBlk->pSrcBufHeader);
COPY_MAC_ADDR(wifi_hdr->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(wifi_hdr->Addr3, pAd->CommonCfg.Bssid);
wifi_hdr->FC.ToDs = 0;
} else
#endif /* QOS_DLS_SUPPORT */
#ifdef DOT11Z_TDLS_SUPPORT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bTdlsEntry)) {
COPY_MAC_ADDR(wifi_hdr->Addr1, pTxBlk->pSrcBufHeader);
COPY_MAC_ADDR(wifi_hdr->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(wifi_hdr->Addr3, pAd->CommonCfg.Bssid);
wifi_hdr->FC.ToDs = 0;
} else
#endif /* DOT11Z_TDLS_SUPPORT */
{
COPY_MAC_ADDR(wifi_hdr->Addr1, pAd->CommonCfg.Bssid);
COPY_MAC_ADDR(wifi_hdr->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(wifi_hdr->Addr3, pTxBlk->pSrcBufHeader);
wifi_hdr->FC.ToDs = 1;
#ifdef CLIENT_WDS
if (!MAC_ADDR_EQUAL
((pTxBlk->pSrcBufHeader + MAC_ADDR_LEN),
pAd->CurrentAddress)) {
wifi_hdr->FC.FrDs = 1;
COPY_MAC_ADDR(&wifi_hdr->Octet[0], pTxBlk->pSrcBufHeader + MAC_ADDR_LEN); /* ADDR4 = SA */
pTxBlk->MpduHeaderLen += MAC_ADDR_LEN;
}
#endif /* CLIENT_WDS */
}
}
else if (ADHOC_ON(pAd))
{
COPY_MAC_ADDR(wifi_hdr->Addr1, pTxBlk->pSrcBufHeader);
#ifdef XLINK_SUPPORT
if (pAd->StaCfg.PSPXlink)
/* copy the SA of ether frames to address 2 of 802.11 frame */
COPY_MAC_ADDR(wifi_hdr->Addr2, pTxBlk->pSrcBufHeader + MAC_ADDR_LEN);
else
#endif /* XLINK_SUPPORT */
COPY_MAC_ADDR(wifi_hdr->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(wifi_hdr->Addr3, pAd->CommonCfg.Bssid);
wifi_hdr->FC.ToDs = 0;
}
}
if (pTxBlk->CipherAlg != CIPHER_NONE)
wifi_hdr->FC.Wep = 1;
/*
-----------------------------------------------------------------
STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later.
-----------------------------------------------------------------
*/
if (pAd->CommonCfg.bAPSDForcePowerSave)
wifi_hdr->FC.PwrMgmt = PWR_SAVE;
else
wifi_hdr->FC.PwrMgmt = (RtmpPktPmBitCheck(pAd) == TRUE);
}
#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 */
#ifdef DOT11Z_TDLS_SUPPORT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bTdlsEntry)) {
COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader);
COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid);
} else
#endif /* DOT11Z_TDLS_SUPPORT */
if (ADHOC_ON(pAd))
COPY_MAC_ADDR(pHeader80211->Addr3,
pAd->CommonCfg.Bssid);
else {
COPY_MAC_ADDR(pHeader80211->Addr3,
pTxBlk->pSrcBufHeader);
#ifdef CLIENT_WDS
if (!MAC_ADDR_EQUAL
((pTxBlk->pSrcBufHeader + MAC_ADDR_LEN),
pAd->CurrentAddress)) {
pHeader80211->FC.FrDs = 1;
COPY_MAC_ADDR(&pHeader80211->Octet[0], pTxBlk->pSrcBufHeader + MAC_ADDR_LEN); /* ADDR4 = SA */
pTxBlk->MpduHeaderLen += MAC_ADDR_LEN;
}
#endif /* CLIENT_WDS */
}
}
/*
-----------------------------------------------------------------
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 = (RtmpPktPmBitCheck(pAd) == TRUE);
}
#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;
UINT8 TXWISize = pAd->chipCap.TXWISize;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
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);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
*(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 = (PUCHAR) 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_PACKET(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;
HEADER_802_11 *pHeader_802_11;
UINT8 TXWISize = pAd->chipCap.TXWISize;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
/* skip common header */
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
/* build QOS Control bytes */
*pHeaderBufPtr =
(pTxBlk->UserPriority & 0x0F) | (pAd->CommonCfg.
AckPolicy[pTxBlk->QueIdx] << 5);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
/* A-MSDU packet */
*pHeaderBufPtr |= 0x80;
*(pHeaderBufPtr + 1) = 0;
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += 2;
/*
padding at front of LLC header
LLC header should locate at 4-octets aligment
@@@ MpduHeaderLen excluding padding @@@
*/
pTxBlk->HdrPadLen = (ULONG) pHeaderBufPtr;
pHeaderBufPtr = (PUCHAR) 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 = 0;
MAC_TABLE_ENTRY *pMacEntry;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
BOOLEAN bHTCPlus;
UINT8 TXWISize = pAd->chipCap.TXWISize;
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)
#ifdef TXBF_SUPPORT
&& (pMacEntry->TxSndgType == SNDG_TYPE_DISABLE)
#endif // TXBF_SUPPORT //
)
{
/* NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! */
#ifndef VENDOR_FEATURE1_SUPPORT
NdisMoveMemory((PUCHAR)
(&pTxBlk->HeaderBuf[TXINFO_SIZE]),
(PUCHAR) (&pMacEntry->CachedBuf[0]),
TXWISize + sizeof (HEADER_802_11));
#else
pTxBlk->HeaderBuf = (UCHAR *) (pMacEntry->HeaderBuf);
#endif /* VENDOR_FEATURE1_SUPPORT */
pHeaderBufPtr =
(PUCHAR) (&pTxBlk->
HeaderBuf[TXINFO_SIZE + TXWISize]);
STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr);
#ifdef SOFT_ENCRYPT
RTMPUpdateSwCacheCipherInfo(pAd, pTxBlk, pHeaderBufPtr);
#endif /* SOFT_ENCRYPT */
} else {
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr =
&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
}
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
/* Check if the original data has enough buffer
to insert or append WPI related field. */
if (RTMPExpandPacketForSwEncrypt(pAd, pTxBlk) == FALSE) {
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket,
NDIS_STATUS_FAILURE);
continue;
}
}
#endif /* SOFT_ENCRYPT */
#ifdef VENDOR_FEATURE1_SUPPORT
if (pMacEntry->isCached
&& (pMacEntry->Protocol ==
RTMP_GET_PACKET_PROTOCOL(pTxBlk->pPacket))
#ifdef SOFT_ENCRYPT
&& !TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)
#endif /* SOFT_ENCRYPT */
#ifdef TXBF_SUPPORT
&& (pMacEntry->TxSndgType == SNDG_TYPE_DISABLE)
#endif // TXBF_SUPPORT //
)
{
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
/* skip common header */
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
/* build QOS Control bytes */
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
pTxBlk->MpduHeaderLen = pMacEntry->MpduHeaderLen;
pHeaderBufPtr =
((PUCHAR) pHeader_802_11) + pTxBlk->MpduHeaderLen;
pTxBlk->HdrPadLen = pMacEntry->HdrPadLen;
/* skip 802.3 header */
pTxBlk->pSrcBufData =
pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
/* skip vlan tag */
if (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket)) {
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
}
else
#endif /* VENDOR_FEATURE1_SUPPORT */
{
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
/* skip common header */
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
/*
build QOS Control bytes
*/
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
*(pHeaderBufPtr + 1) = 0;
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += 2;
/*
build HTC+
HTC control field following QoS field
*/
bHTCPlus = FALSE;
if ((pAd->CommonCfg.bRdg == TRUE)
&& CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)
#ifdef TXBF_SUPPORT
&& (pMacEntry->TxSndgType != SNDG_TYPE_NDP)
#endif /* TXBF_SUPPORT */
)
{
if (pMacEntry->isCached == FALSE)
{
/* mark HTC bit */
pHeader_802_11->FC.Order = 1;
NdisZeroMemory(pHeaderBufPtr, sizeof(HT_CONTROL));
((PHT_CONTROL)pHeaderBufPtr)->RDG = 1;
}
bHTCPlus = TRUE;
}
#ifdef TXBF_SUPPORT
pTxBlk->TxSndgPkt = SNDG_TYPE_DISABLE;
NdisAcquireSpinLock(&pMacEntry->TxSndgLock);
if (pMacEntry->TxSndgType >= SNDG_TYPE_SOUNDING)
{
DBGPRINT(RT_DEBUG_TRACE, ("--Sounding in AMPDU: TxSndgType=%d, MCS=%d\n",
pMacEntry->TxSndgType,
pMacEntry->TxSndgType==SNDG_TYPE_NDP? pMacEntry->sndgMcs: pTxBlk->pTransmit->field.MCS));
// Set HTC bit
if (bHTCPlus == FALSE)
{
bHTCPlus = TRUE;
NdisZeroMemory(pHeaderBufPtr, sizeof(HT_CONTROL));
}
if (pMacEntry->TxSndgType == SNDG_TYPE_SOUNDING)
{
// Select compress if supported. Otherwise select noncompress
if (pAd->CommonCfg.ETxBfNoncompress==0 &&
(pMacEntry->HTCapability.TxBFCap.ExpComBF>0) )
((PHT_CONTROL)pHeaderBufPtr)->CSISTEERING = 3;
else
((PHT_CONTROL)pHeaderBufPtr)->CSISTEERING = 2;
}
else if (pMacEntry->TxSndgType == SNDG_TYPE_NDP)
{
// Select compress if supported. Otherwise select noncompress
if (pAd->CommonCfg.ETxBfNoncompress==0 &&
(pMacEntry->HTCapability.TxBFCap.ExpComBF>0) &&
(pMacEntry->HTCapability.TxBFCap.ComSteerBFAntSup >= (pMacEntry->sndgMcs/8))
)
((PHT_CONTROL)pHeaderBufPtr)->CSISTEERING = 3;
else
((PHT_CONTROL)pHeaderBufPtr)->CSISTEERING = 2;
// Set NDP Announcement
((PHT_CONTROL)pHeaderBufPtr)->NDPAnnounce = 1;
pTxBlk->TxNDPSndgBW = pMacEntry->sndgBW;
pTxBlk->TxNDPSndgMcs = pMacEntry->sndgMcs;
}
pTxBlk->TxSndgPkt = pMacEntry->TxSndgType;
pMacEntry->TxSndgType = SNDG_TYPE_DISABLE;
}
NdisReleaseSpinLock(&pMacEntry->TxSndgLock);
#ifdef MFB_SUPPORT
#if defined(MRQ_FORCE_TX)//have to replace this by the correct condition!!!
pMacEntry->HTCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_MRQ;
#endif
if ((pMacEntry->HTCapability.ExtHtCapInfo.MCSFeedback >=MCSFBK_MRQ) &&
(pTxBlk->TxSndgPkt == SNDG_TYPE_DISABLE))//because the signal format of sounding frmae may be different from normal data frame, which may result in different MFB
{
if (bHTCPlus == FALSE)
{
bHTCPlus = TRUE;
NdisZeroMemory(pHeaderBufPtr, sizeof(HT_CONTROL));
}
MFB_PerPareMRQ(pAd, pHeaderBufPtr, pMacEntry);
}
if (pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback >=MCSFBK_MRQ && pMacEntry->toTxMfb == 1)
{
if (bHTCPlus == FALSE)
{
bHTCPlus = TRUE;
NdisZeroMemory(pHeaderBufPtr, sizeof(HT_CONTROL));
}
MFB_PerPareMFB(pAd, pHeaderBufPtr, pMacEntry);// not complete yet!!!
pMacEntry->toTxMfb = 0;
}
#endif // MFB_SUPPORT //
#endif // TXBF_SUPPORT //
if (bHTCPlus)
{
pHeader_802_11->FC.Order = 1;
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 = (PUCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG) (pHeaderBufPtr - pTxBlk->HdrPadLen);
#ifdef VENDOR_FEATURE1_SUPPORT
pMacEntry->HdrPadLen = pTxBlk->HdrPadLen;
#endif /* VENDOR_FEATURE1_SUPPORT */
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
UCHAR iv_offset = 0, ext_offset = 0;
/*
if original Ethernet frame contains no LLC/SNAP,
then an extra LLC/SNAP encap is required
*/
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData - 2,
pTxBlk->pExtraLlcSnapEncap);
/* Insert LLC-SNAP encapsulation (8 octets) to MPDU data buffer */
if (pTxBlk->pExtraLlcSnapEncap) {
/* Reserve the front 8 bytes of data for LLC header */
pTxBlk->pSrcBufData -= LENGTH_802_1_H;
pTxBlk->SrcBufLen += LENGTH_802_1_H;
NdisMoveMemory(pTxBlk->pSrcBufData,
pTxBlk->
pExtraLlcSnapEncap, 6);
}
/* Construct and insert specific IV header to MPDU header */
RTMPSoftConstructIVHdr(pTxBlk->CipherAlg,
pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr,
&iv_offset);
pHeaderBufPtr += iv_offset;
pTxBlk->MpduHeaderLen += iv_offset;
/* Encrypt the MPDU data by software */
RTMPSoftEncryptionAction(pAd,
pTxBlk->CipherAlg,
(PUCHAR)
pHeader_802_11,
pTxBlk->pSrcBufData,
pTxBlk->SrcBufLen,
pTxBlk->KeyIdx,
pTxBlk->pKey,
&ext_offset);
pTxBlk->SrcBufLen += ext_offset;
pTxBlk->TotalFrameLen += ext_offset;
} else
#endif /* SOFT_ENCRYPT */
{
/*
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;
}
}
#ifdef VENDOR_FEATURE1_SUPPORT
pMacEntry->Protocol =
RTMP_GET_PACKET_PROTOCOL(pTxBlk->pPacket);
pMacEntry->MpduHeaderLen = pTxBlk->MpduHeaderLen;
#endif /* VENDOR_FEATURE1_SUPPORT */
}
if ((pMacEntry->isCached)
#ifdef TXBF_SUPPORT
&& (pTxBlk->TxSndgPkt == SNDG_TYPE_DISABLE)
#endif // TXBF_SUPPORT //
)
{
RTMPWriteTxWI_Cache(pAd, (TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
} else {
RTMPWriteTxWI_Data(pAd, (TXWI_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])));
#ifdef VENDOR_FEATURE1_SUPPORT
/* use space to get performance enhancement */
NdisZeroMemory((PUCHAR) (&pMacEntry->HeaderBuf[0]), sizeof (pMacEntry->HeaderBuf));
NdisMoveMemory((PUCHAR) (&pMacEntry->HeaderBuf[0]),
(PUCHAR) (&pTxBlk->HeaderBuf[0]),
(pHeaderBufPtr - (PUCHAR) (&pTxBlk->HeaderBuf[0])));
#endif /* VENDOR_FEATURE1_SUPPORT */
pMacEntry->isCached = TRUE;
}
#ifdef TXBF_SUPPORT
if (pTxBlk->TxSndgPkt != SNDG_TYPE_DISABLE)
pMacEntry->isCached = FALSE;
#endif // TXBF_SUPPORT //
#ifdef STATS_COUNT_SUPPORT
/* calculate Transmitted AMPDU count and ByteCount */
{
pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart++;
pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen;
}
#endif /* STATS_COUNT_SUPPORT */
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (UCHAR *)pHeader_802_11);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
/* Kick out Tx */
#ifdef PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
}
}
#ifdef HDR_TRANS_SUPPORT
VOID STA_AMPDU_Frame_Tx_Hdr_Trns(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
HEADER_802_11 *pHeader_802_11;
UCHAR *pWiBufPtr;
USHORT FreeNumber = 0;
MAC_TABLE_ENTRY *pMacEntry;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
BOOLEAN bHTCPlus;
UINT8 TXWISize = pAd->chipCap.TXWISize;
PWIFI_INFO_STRUC pWI;
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;
}
pTxBlk->NeedTrans = TRUE;
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]),
TXWISize + WIFI_INFO_SIZE);
pWiBufPtr = (PUCHAR) (&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize]);
STABuildCacheWifiInfo(pAd, pTxBlk, pWiBufPtr);
} else {
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildWifiInfo(pAd, pTxBlk);
pWiBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
}
pWI = (PWIFI_INFO_STRUC)pWiBufPtr;
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader;
if (bVLANPkt)
pWI->field.VLAN = TRUE;
pWI->field.TID = (pTxBlk->UserPriority & 0x0F);
{
/*
build HTC+
HTC control field following QoS field
*/
bHTCPlus = FALSE;
if ((pAd->CommonCfg.bRdg == TRUE)
&& CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)
)
{
if (pMacEntry->isCached == FALSE)
{
/* mark HTC bit */
pWI->field.RDG = 1;
}
bHTCPlus = TRUE;
}
}
if ((pMacEntry->isCached))
{
RTMPWriteTxWI_Cache(pAd,
(TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]),
pTxBlk);
} else {
RTMPWriteTxWI_Data(pAd,
(TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]),
pTxBlk);
NdisZeroMemory((PUCHAR) (&pMacEntry->CachedBuf[0]),
sizeof (pMacEntry->CachedBuf));
NdisMoveMemory((PUCHAR) (&pMacEntry->CachedBuf[0]),
(PUCHAR) (&pTxBlk->HeaderBuf[TXINFO_SIZE]),
TXWISize + WIFI_INFO_SIZE);
pMacEntry->isCached = TRUE;
}
#ifdef STATS_COUNT_SUPPORT
/* calculate Transmitted AMPDU count and ByteCount */
{
pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart++;
pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen;
}
#endif /* STATS_COUNT_SUPPORT */
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (UCHAR *)pHeader_802_11);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
/* Kick out Tx */
#ifdef PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
}
}
#endif /* HDR_TRANS_SUPPORT */
VOID STA_AMSDU_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;
USHORT FreeNumber = 0;
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->TxWIMPDUByteCnt will be updated after final frame was handled. */
RTMPWriteTxWI_Data(pAd, (TXWI_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);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), NULL);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
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 PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
#endif /* DOT11_N_SUPPORT */
VOID STA_Legacy_Frame_Tx(RTMP_ADAPTER *pAd, TX_BLK *pTxBlk)
{
HEADER_802_11 *wifi_hdr;
UCHAR *pHeaderBufPtr;
USHORT FreeNumber = 0;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
UINT8 TXWISize = pAd->chipCap.TXWISize;
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;
}
#ifdef STATS_COUNT_SUPPORT
if (pTxBlk->TxFrameType == TX_MCAST_FRAME) {
INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount);
}
#endif /* STATS_COUNT_SUPPORT */
if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket))
TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired);
else
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired);
if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate)
pTxBlk->TxRate = pAd->CommonCfg.MinTxRate;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
/* Check if the original data has enough buffer
to insert or append WPI related field. */
if (RTMPExpandPacketForSwEncrypt(pAd, pTxBlk) == FALSE) {
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
return;
}
}
#endif /* SOFT_ENCRYPT */
/* skip 802.3 header */
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
/* skip vlan tag */
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
if (bVLANPkt) {
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize + TSO_SIZE];
wifi_hdr = (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) | (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] << 5));
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
*(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 = (PUCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG) (pHeaderBufPtr - pTxBlk->HdrPadLen);
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
UCHAR iv_offset = 0, ext_offset = 0;
/*
if original Ethernet frame contains no LLC/SNAP,
then an extra LLC/SNAP encap is required
*/
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData - 2,
pTxBlk->pExtraLlcSnapEncap);
/* Insert LLC-SNAP encapsulation (8 octets) to MPDU data buffer */
if (pTxBlk->pExtraLlcSnapEncap) {
/* Reserve the front 8 bytes of data for LLC header */
pTxBlk->pSrcBufData -= LENGTH_802_1_H;
pTxBlk->SrcBufLen += LENGTH_802_1_H;
NdisMoveMemory(pTxBlk->pSrcBufData,
pTxBlk->pExtraLlcSnapEncap, 6);
}
/* Construct and insert specific IV header to MPDU header */
RTMPSoftConstructIVHdr(pTxBlk->CipherAlg,
pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr, &iv_offset);
pHeaderBufPtr += iv_offset;
pTxBlk->MpduHeaderLen += iv_offset;
/* Encrypt the MPDU data by software */
RTMPSoftEncryptionAction(pAd,
pTxBlk->CipherAlg,
(UCHAR *)wifi_hdr,
pTxBlk->pSrcBufData,
pTxBlk->SrcBufLen,
pTxBlk->KeyIdx,
pTxBlk->pKey, &ext_offset);
pTxBlk->SrcBufLen += ext_offset;
pTxBlk->TotalFrameLen += ext_offset;
}
else
#endif /* SOFT_ENCRYPT */
{
/*
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;
}
}
#ifdef ADHOC_WPA2PSK_SUPPORT
if (ADHOC_ON(pAd)
&& (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
&& (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
&& (!pTxBlk->pMacEntry)) {
/* use Wcid as Hardware Key Index */
GET_GroupKey_WCID(pAd, pTxBlk->Wcid, BSS0);
}
#endif /* ADHOC_WPA2PSK_SUPPORT */
/*
prepare for TXWI
use Wcid as Key Index
*/
RTMPWriteTxWI_Data(pAd, (TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (UCHAR *)wifi_hdr);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
/*
Kick out Tx
*/
#ifdef PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
#ifdef HDR_TRANS_SUPPORT
VOID STA_Legacy_Frame_Tx_Hdr_Trns(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;
USHORT FreeNumber = 0;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
UINT8 TXWISize = pAd->chipCap.TXWISize;
PWIFI_INFO_STRUC pWI;
ASSERT(pTxBlk);
//printk("STA_Legacy_Frame_Tx_Hdr_Trns\n");
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;
}
pTxBlk->NeedTrans = TRUE;
#ifdef STATS_COUNT_SUPPORT
if (pTxBlk->TxFrameType == TX_MCAST_FRAME) {
INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount);
}
#endif /* STATS_COUNT_SUPPORT */
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);
STABuildWifiInfo(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWISize];
pWI = (PWIFI_INFO_STRUC)pHeaderBufPtr;
//hex_dump("wifi info:", pWI, sizeof(WIFI_INFO_STRUC));
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader;
//hex_dump("pSrcBufData" , pTxBlk->pSrcBufData, pTxBlk->SrcBufLen);
if(bVLANPkt)
pWI->field.VLAN = TRUE;
pWI->field.TID = (pTxBlk->UserPriority & 0x0F);
#ifdef ADHOC_WPA2PSK_SUPPORT
if (ADHOC_ON(pAd)
&& (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
&& (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
&& (!pTxBlk->pMacEntry)) {
/* use Wcid as Hardware Key Index */
GET_GroupKey_WCID(pAd, pTxBlk->Wcid, BSS0);
}
#endif /* ADHOC_WPA2PSK_SUPPORT */
/*
prepare for TXWI
use Wcid as Key Index
*/
RTMPWriteTxWI_Data(pAd, (TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (UCHAR *)pHeader_802_11);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
/*
Kick out Tx
*/
#ifdef PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
#endif
VOID STA_ARalink_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK * pTxBlk)
{
PUCHAR pHeaderBufPtr;
USHORT freeCnt = 0;
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->TxWIMPDUByteCnt
will be updated after final frame was handled.
*/
RTMPWriteTxWI_Data(pAd, (TXWI_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,
&freeCnt);
else
LastTxIdx =
HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum,
&freeCnt);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), NULL);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
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 PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
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 freeCnt = 0;
UCHAR fragNum = 0;
PACKET_INFO PacketInfo;
USHORT EncryptionOverhead = 0;
UINT32 FreeMpduSize, SrcRemainingBytes;
USHORT AckDuration;
UINT NextMpduSize;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
HTTRANSMIT_SETTING *pTransmit;
#ifdef SOFT_ENCRYPT
PUCHAR tmp_ptr = NULL;
UINT32 buf_offset = 0;
#endif /* SOFT_ENCRYPT */
UINT8 TXWISize = pAd->chipCap.TXWISize;
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);
#ifdef SOFT_ENCRYPT
/*
Check if the original data has enough buffer
to insert or append extended field.
*/
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
if (RTMPExpandPacketForSwEncrypt(pAd, pTxBlk) == FALSE) {
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket,
NDIS_STATUS_FAILURE);
return;
}
}
#endif /* SOFT_ENCRYPT */
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 + TXWISize];
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);
#ifdef DOT11Z_TDLS_SUPPORT
#ifdef UAPSD_SUPPORT
UAPSD_MR_EOSP_SET(pHeaderBufPtr, pTxBlk);
#endif /* UAPSD_SUPPORT */
#endif /* DOT11Z_TDLS_SUPPORT */
*(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 = (PUCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG) (pHeaderBufPtr - pTxBlk->HdrPadLen);
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
UCHAR iv_offset = 0;
/* if original Ethernet frame contains no LLC/SNAP, */
/* then an extra LLC/SNAP encap is required */
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData - 2,
pTxBlk->pExtraLlcSnapEncap);
/* Insert LLC-SNAP encapsulation (8 octets) to MPDU data buffer */
if (pTxBlk->pExtraLlcSnapEncap) {
/* Reserve the front 8 bytes of data for LLC header */
pTxBlk->pSrcBufData -= LENGTH_802_1_H;
pTxBlk->SrcBufLen += LENGTH_802_1_H;
NdisMoveMemory(pTxBlk->pSrcBufData,
pTxBlk->pExtraLlcSnapEncap, 6);
}
/* Construct and insert specific IV header to MPDU header */
RTMPSoftConstructIVHdr(pTxBlk->CipherAlg,
pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr, &iv_offset);
pHeaderBufPtr += iv_offset;
pTxBlk->MpduHeaderLen += iv_offset;
} else
#endif /* SOFT_ENCRYPT */
{
/*
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) {
RTMPCalculateMICValue(pAd, pTxBlk->pPacket,
pTxBlk->pExtraLlcSnapEncap, pTxBlk->pKey,
0);
/*
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);
pTxBlk->SrcBufLen += 8;
pTxBlk->TotalFrameLen += 8;
}
/*
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)
EncryptionOverhead = 12; /* TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength */
else if (pTxBlk->CipherAlg == CIPHER_AES)
EncryptionOverhead = 16; /* AES: IV[4] + EIV[4] + MIC[8] */
#ifdef WAPI_SUPPORT
else if (pTxBlk->CipherAlg == CIPHER_SMS4)
EncryptionOverhead = 16; /* SMS4: MIC[16] */
#endif /* WAPI_SUPPORT */
else
EncryptionOverhead = 0;
pTransmit = pTxBlk->pTransmit;
/* Decide the TX rate */
if (pTransmit->field.MODE == MODE_CCK)
pTxBlk->TxRate = pTransmit->field.MCS;
else if (pTransmit->field.MODE == MODE_OFDM)
pTxBlk->TxRate = pTransmit->field.MCS + RATE_FIRST_OFDM_RATE;
else
pTxBlk->TxRate = RATE_6_5;
/* decide how much time an ACK/CTS frame will consume in the air */
if (pTxBlk->TxRate <= RATE_LAST_OFDM_RATE)
AckDuration =
RTMPCalcDuration(pAd,
pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate],
14);
else
AckDuration = RTMPCalcDuration(pAd, RATE_6_5, 14);
/* Init the total payload length of this frame. */
SrcRemainingBytes = pTxBlk->SrcBufLen;
pTxBlk->TotalFragNum = 0xff;
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
/* store the outgoing frame for calculating MIC per fragmented frame */
os_alloc_mem(pAd, (PUCHAR *) & tmp_ptr, pTxBlk->SrcBufLen);
if (tmp_ptr == NULL) {
DBGPRINT(RT_DEBUG_ERROR,
("!!!%s : no memory for SW MIC calculation !!!\n",
__FUNCTION__));
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket,
NDIS_STATUS_FAILURE);
return;
}
NdisMoveMemory(tmp_ptr, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen);
}
#endif /* SOFT_ENCRYPT */
do {
FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC - 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);
}
SrcRemainingBytes -= pTxBlk->SrcBufLen;
if (fragNum == 0)
pTxBlk->FrameGap = IFS_HTTXOP;
else
pTxBlk->FrameGap = IFS_SIFS;
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
UCHAR ext_offset = 0;
NdisMoveMemory(pTxBlk->pSrcBufData,
tmp_ptr + buf_offset, pTxBlk->SrcBufLen);
buf_offset += pTxBlk->SrcBufLen;
/* Encrypt the MPDU data by software */
RTMPSoftEncryptionAction(pAd,
pTxBlk->CipherAlg,
(PUCHAR) pHeader_802_11,
pTxBlk->pSrcBufData,
pTxBlk->SrcBufLen,
pTxBlk->KeyIdx,
pTxBlk->pKey, &ext_offset);
pTxBlk->SrcBufLen += ext_offset;
pTxBlk->TotalFrameLen += ext_offset;
}
#endif /* SOFT_ENCRYPT */
RTMPWriteTxWI_Data(pAd, (TXWI_STRUC *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &freeCnt);
#ifdef DBG_CTRL_SUPPORT
#ifdef INCLUDE_DEBUG_QUEUE
if (pAd->CommonCfg.DebugFlags & DBF_DBQ_TXFRAME)
dbQueueEnqueueTxFrame((UCHAR *)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (UCHAR *)pHeader_802_11);
#endif /* INCLUDE_DEBUG_QUEUE */
#endif /* DBG_CTRL_SUPPORT */
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
/* Update the frame number, remaining size of the NDIS packet payload. */
#ifdef SOFT_ENCRYPT
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bSwEncrypt)) {
#ifdef WAPI_SUPPORT
if (pTxBlk->CipherAlg == CIPHER_SMS4) {
/* incease WPI IV for next MPDU */
inc_iv_byte(pTxBlk->pKey->TxTsc, LEN_WAPI_TSC,
2);
/* Construct and insert WPI-SMS4 IV header to MPDU header */
RTMPConstructWPIIVHdr(pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr -
(LEN_WPI_IV_HDR));
} else
#endif /* WAPI_SUPPORT */
if ((pTxBlk->CipherAlg == CIPHER_WEP64)
|| (pTxBlk->CipherAlg == CIPHER_WEP128)) {
inc_iv_byte(pTxBlk->pKey->TxTsc, LEN_WEP_TSC,
1);
/* Construct and insert 4-bytes WEP IV header to MPDU header */
RTMPConstructWEPIVHdr(pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr -
(LEN_WEP_IV_HDR));
} else if (pTxBlk->CipherAlg == CIPHER_TKIP) ;
else if (pTxBlk->CipherAlg == CIPHER_AES) {
inc_iv_byte(pTxBlk->pKey->TxTsc, LEN_WPA_TSC,
1);
/* Construct and insert 8-bytes CCMP header to MPDU header */
RTMPConstructCCMPHdr(pTxBlk->KeyIdx,
pTxBlk->pKey->TxTsc,
pHeaderBufPtr -
(LEN_CCMP_HDR));
}
} else
#endif /* SOFT_ENCRYPT */
{
/* 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);
#ifdef SOFT_ENCRYPT
if (tmp_ptr != NULL)
os_free_mem(pAd, tmp_ptr);
#endif /* SOFT_ENCRYPT */
/*
Kick out Tx
*/
#ifdef PCIE_PS_SUPPORT
if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX))
#endif /* PCIE_PS_SUPPORT */
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(RTMP_ADAPTER *pAd, TX_BLK *pTxBlk, UCHAR QueIdx)
{
NDIS_PACKET *pPacket;
PQUEUE_ENTRY pQEntry;
#ifdef HDR_TRANS_SUPPORT
BOOLEAN bDoHdrTrans = TRUE;
#endif /* HDR_TRANS_SUPPORT */
#ifdef CONFIG_MULTI_CHANNEL
if (pAd->Multi_Channel_Enable == TRUE)
{
if (pAd->P2pCfg.bStartP2pConnect)
{
return NDIS_STATUS_FAILURE;
}
if (INFRA_ON(pAd) && (pAd->LatchRfRegs.Channel != pAd->CommonCfg.Channel) &&
(pAd->LatchRfRegs.Channel != pAd->CommonCfg.CentralChannel))
{
return NDIS_STATUS_FAILURE;
}
}
#endif /*CONFIG_MULTI_CHANNEL*/
/*
---------------------------------------------
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);
#ifdef RTMP_MAC_USB
/* there's packet to be sent, keep awake for 1200ms */
if (pAd->CountDowntoPsm < 12)
pAd->CountDowntoPsm = 12;
#endif /* RTMP_MAC_USB */
/* ------------------------------------------------------------------
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_INFO, ("AsicForceWakeup At HardTx\n"));
#ifdef RTMP_MAC_USB
RTEnqueueInternalCmd(pAd, CMDTHREAD_FORCE_WAKE_UP, NULL, 0);
#endif /* RTMP_MAC_USB */
}
/* It should not change PSM bit, when APSD turn on. */
if ((!
(pAd->StaCfg.UapsdInfo.bAPSDCapable
&& pAd->CommonCfg.APEdcaParm.bAPSDCapable)
&& (pAd->CommonCfg.bAPSDForcePowerSave == FALSE))
|| (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket))
|| (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) {
if ((RtmpPktPmBitCheck(pAd) == TRUE) &&
(pAd->StaCfg.WindowsPowerMode ==
Ndis802_11PowerModeFast_PSP))
RTMP_SET_PSM_BIT(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);
}
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, OPMODE_STA);
} else {
/* release packet */
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
}