2586 lines
67 KiB
C
2586 lines
67 KiB
C
/*
|
|
*************************************************************************
|
|
* Ralink Tech Inc.
|
|
* 5F., No.36, Taiyuan St., Jhubei City,
|
|
* Hsinchu County 302,
|
|
* Taiwan, R.O.C.
|
|
*
|
|
* (c) Copyright 2002-2007, Ralink Technology, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
*************************************************************************
|
|
*/
|
|
|
|
#include "../rt_config.h"
|
|
|
|
#define MAX_TX_IN_TBTT (16)
|
|
|
|
|
|
UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
|
|
UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
|
|
// Add Cisco Aironet SNAP heade for CCX2 support
|
|
UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00};
|
|
UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02};
|
|
UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e};
|
|
UCHAR EAPOL[] = {0x88, 0x8e};
|
|
UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */
|
|
|
|
UCHAR IPX[] = {0x81, 0x37};
|
|
UCHAR APPLE_TALK[] = {0x80, 0xf3};
|
|
UCHAR RateIdToPlcpSignal[12] = {
|
|
0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec
|
|
11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14
|
|
9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14
|
|
|
|
UCHAR OfdmSignalToRateId[16] = {
|
|
RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively
|
|
RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively
|
|
RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively
|
|
RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively
|
|
};
|
|
|
|
UCHAR OfdmRateToRxwiMCS[12] = {
|
|
0, 0, 0, 0,
|
|
0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3
|
|
4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7
|
|
};
|
|
UCHAR RxwiMCSToOfdmRate[12] = {
|
|
RATE_6, RATE_9, RATE_12, RATE_18,
|
|
RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3
|
|
4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7
|
|
};
|
|
|
|
char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"};
|
|
|
|
UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2};
|
|
UCHAR default_sta_aifsn[]={3,7,2,2};
|
|
|
|
UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO};
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
API for MLME to transmit management frame to AP (BSS Mode)
|
|
or station (IBSS Mode)
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
pData Pointer to the outgoing 802.11 frame
|
|
Length Size of outgoing management frame
|
|
|
|
Return Value:
|
|
NDIS_STATUS_FAILURE
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_SUCCESS
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
NDIS_STATUS MiniportMMRequest(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PUCHAR pData,
|
|
IN UINT Length)
|
|
{
|
|
PNDIS_PACKET pPacket;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
ULONG FreeNum;
|
|
UCHAR IrqState;
|
|
UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN];
|
|
|
|
ASSERT(Length <= MGMT_DMA_BUFFER_SIZE);
|
|
|
|
QueIdx=3;
|
|
|
|
// 2860C use Tx Ring
|
|
|
|
IrqState = pAd->irq_disabled;
|
|
|
|
do
|
|
{
|
|
// Reset is in progress, stop immediately
|
|
if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
|
|
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)||
|
|
!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Check Free priority queue
|
|
// Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing.
|
|
|
|
// 2860C use Tx Ring
|
|
if (pAd->MACVersion == 0x28600100)
|
|
{
|
|
FreeNum = GET_TXRING_FREENO(pAd, QueIdx);
|
|
}
|
|
else
|
|
{
|
|
FreeNum = GET_MGMTRING_FREENO(pAd);
|
|
}
|
|
|
|
if ((FreeNum > 0))
|
|
{
|
|
// We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870
|
|
NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE));
|
|
Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n"));
|
|
break;
|
|
}
|
|
|
|
//pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
|
|
//pAd->CommonCfg.MlmeRate = RATE_2;
|
|
|
|
|
|
Status = MlmeHardTransmit(pAd, QueIdx, pPacket);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
RTMPFreeNdisPacket(pAd, pPacket);
|
|
}
|
|
else
|
|
{
|
|
pAd->RalinkCounters.MgmtRingFullCount++;
|
|
DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n",
|
|
QueIdx, pAd->RalinkCounters.MgmtRingFullCount));
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
#ifdef RT30xx
|
|
NDIS_STATUS MlmeDataHardTransmit(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PNDIS_PACKET pPacket);
|
|
|
|
#define MAX_DATAMM_RETRY 3
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
API for MLME to transmit management frame to AP (BSS Mode)
|
|
or station (IBSS Mode)
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
pData Pointer to the outgoing 802.11 frame
|
|
Length Size of outgoing management frame
|
|
|
|
Return Value:
|
|
NDIS_STATUS_FAILURE
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_SUCCESS
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
NDIS_STATUS MiniportDataMMRequest(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PUCHAR pData,
|
|
IN UINT Length)
|
|
{
|
|
PNDIS_PACKET pPacket;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
ULONG FreeNum;
|
|
int retry = 0;
|
|
UCHAR IrqState;
|
|
UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN];
|
|
|
|
ASSERT(Length <= MGMT_DMA_BUFFER_SIZE);
|
|
|
|
// 2860C use Tx Ring
|
|
IrqState = pAd->irq_disabled;
|
|
|
|
do
|
|
{
|
|
// Reset is in progress, stop immediately
|
|
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
|
|
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)||
|
|
!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Check Free priority queue
|
|
// Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing.
|
|
|
|
// 2860C use Tx Ring
|
|
|
|
// free Tx(QueIdx) resources
|
|
FreeNum = GET_TXRING_FREENO(pAd, QueIdx);
|
|
|
|
if ((FreeNum > 0))
|
|
{
|
|
// We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870
|
|
NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE));
|
|
Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n"));
|
|
break;
|
|
}
|
|
|
|
//pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
|
|
//pAd->CommonCfg.MlmeRate = RATE_2;
|
|
|
|
|
|
Status = MlmeDataHardTransmit(pAd, QueIdx, pPacket);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
RTMPFreeNdisPacket(pAd, pPacket);
|
|
retry = MAX_DATAMM_RETRY;
|
|
}
|
|
else
|
|
{
|
|
retry ++;
|
|
|
|
printk("retry %d\n", retry);
|
|
pAd->RalinkCounters.MgmtRingFullCount++;
|
|
|
|
if (retry >= MAX_DATAMM_RETRY)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n",
|
|
QueIdx, pAd->RalinkCounters.MgmtRingFullCount));
|
|
}
|
|
}
|
|
|
|
} while (retry < MAX_DATAMM_RETRY);
|
|
|
|
|
|
return Status;
|
|
}
|
|
#endif /* RT30xx */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Copy frame from waiting queue into relative ring buffer and set
|
|
appropriate ASIC register to kick hardware transmit function
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
pBuffer Pointer to memory of outgoing frame
|
|
Length Size of outgoing management frame
|
|
|
|
Return Value:
|
|
NDIS_STATUS_FAILURE
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_SUCCESS
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
NDIS_STATUS MlmeHardTransmit(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
|
|
)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket);
|
|
|
|
}
|
|
|
|
#ifdef RT30xx
|
|
NDIS_STATUS MlmeDataHardTransmit(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
|
|
)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
#ifdef RT2870
|
|
return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket);
|
|
#endif // RT2870 //
|
|
}
|
|
#endif /* RT30xx */
|
|
|
|
NDIS_STATUS MlmeHardTransmitMgmtRing(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR QueIdx,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
PACKET_INFO PacketInfo;
|
|
PUCHAR pSrcBufVA;
|
|
UINT SrcBufLen;
|
|
PHEADER_802_11 pHeader_802_11;
|
|
BOOLEAN bAckRequired, bInsertTimestamp;
|
|
UCHAR MlmeRate;
|
|
PTXWI_STRUC pFirstTxWI;
|
|
MAC_TABLE_ENTRY *pMacEntry = NULL;
|
|
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
|
|
|
|
RTMP_SEM_LOCK(&pAd->MgmtRingLock);
|
|
|
|
|
|
if (pSrcBufVA == NULL)
|
|
{
|
|
RTMP_SEM_UNLOCK(&pAd->MgmtRingLock);
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
// outgoing frame always wakeup PHY to prevent frame lost
|
|
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
|
|
AsicForceWakeup(pAd, TRUE);
|
|
|
|
pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE);
|
|
pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE);
|
|
|
|
if (pHeader_802_11->Addr1[0] & 0x01)
|
|
{
|
|
MlmeRate = pAd->CommonCfg.BasicMlmeRate;
|
|
}
|
|
else
|
|
{
|
|
MlmeRate = pAd->CommonCfg.MlmeRate;
|
|
}
|
|
|
|
// Verify Mlme rate for a / g bands.
|
|
if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band
|
|
MlmeRate = RATE_6;
|
|
|
|
if ((pHeader_802_11->FC.Type == BTYPE_DATA) &&
|
|
(pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL))
|
|
{
|
|
pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1);
|
|
}
|
|
|
|
{
|
|
// Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode.
|
|
if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED
|
|
|| pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED
|
|
)
|
|
{
|
|
if (pAd->LatchRfRegs.Channel > 14)
|
|
pAd->CommonCfg.MlmeTransmit.field.MODE = 1;
|
|
else
|
|
pAd->CommonCfg.MlmeTransmit.field.MODE = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE)
|
|
// Snice it's been set to 0 while on MgtMacHeaderInit
|
|
// By the way this will cause frame to be send on PWR_SAVE failed.
|
|
//
|
|
// pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE);
|
|
//
|
|
// In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame
|
|
|
|
// Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD
|
|
if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL))
|
|
{
|
|
if ((pAd->StaCfg.Psm == PWR_SAVE) &&
|
|
(pHeader_802_11->FC.SubType == SUBTYPE_ACTION))
|
|
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
|
|
else
|
|
pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE;
|
|
}
|
|
|
|
bInsertTimestamp = FALSE;
|
|
if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL
|
|
{
|
|
//Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue.
|
|
if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL))
|
|
{
|
|
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
|
|
}
|
|
bAckRequired = FALSE;
|
|
}
|
|
else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame)
|
|
{
|
|
if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST
|
|
{
|
|
bAckRequired = FALSE;
|
|
pHeader_802_11->Duration = 0;
|
|
}
|
|
else
|
|
{
|
|
bAckRequired = TRUE;
|
|
pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14);
|
|
if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP)
|
|
{
|
|
bInsertTimestamp = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
pHeader_802_11->Sequence = pAd->Sequence++;
|
|
if (pAd->Sequence >0xfff)
|
|
pAd->Sequence = 0;
|
|
|
|
// Before radar detection done, mgmt frame can not be sent but probe req
|
|
// Because we need to use probe req to trigger driver to send probe req in passive scan
|
|
if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ)
|
|
&& (pAd->CommonCfg.bIEEE80211H == 1)
|
|
&& (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n"));
|
|
RTMP_SEM_UNLOCK(&pAd->MgmtRingLock);
|
|
return (NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET
|
|
// should always has only one ohysical buffer, and the whole frame size equals
|
|
// to the first scatter buffer size
|
|
//
|
|
|
|
// Initialize TX Descriptor
|
|
// For inter-frame gap, the number is for this frame and next frame
|
|
// For MLME rate, we will fix as 2Mb to match other vendor's implement
|
|
|
|
// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not.
|
|
if (pMacEntry == NULL)
|
|
{
|
|
RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE,
|
|
0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit);
|
|
}
|
|
else
|
|
{
|
|
RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE,
|
|
bInsertTimestamp, FALSE, bAckRequired, FALSE,
|
|
0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE),
|
|
pMacEntry->MaxHTPhyMode.field.MCS, 0,
|
|
(UCHAR)pMacEntry->MaxHTPhyMode.field.MCS,
|
|
IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode);
|
|
}
|
|
|
|
// Now do hardware-depened kick out.
|
|
HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen);
|
|
|
|
// Make sure to release MGMT ring resource
|
|
RTMP_SEM_UNLOCK(&pAd->MgmtRingLock);
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/********************************************************************************
|
|
|
|
New DeQueue Procedures.
|
|
|
|
********************************************************************************/
|
|
|
|
#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \
|
|
do{ \
|
|
if (bIntContext == FALSE) \
|
|
RTMP_IRQ_LOCK((lock), IrqFlags); \
|
|
}while(0)
|
|
|
|
#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \
|
|
do{ \
|
|
if (bIntContext == FALSE) \
|
|
RTMP_IRQ_UNLOCK((lock), IrqFlags); \
|
|
}while(0)
|
|
|
|
/*
|
|
========================================================================
|
|
Tx Path design algorithm:
|
|
Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal),
|
|
Specific Packet Type. Following show the classification rule and policy for each kinds of packets.
|
|
Classification Rule=>
|
|
Multicast: (*addr1 & 0x01) == 0x01
|
|
Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc.
|
|
11N Rate : If peer support HT
|
|
(1).AMPDU -- If TXBA is negotiated.
|
|
(2).AMSDU -- If AMSDU is capable for both peer and ourself.
|
|
*). AMSDU can embedded in a AMPDU, but now we didn't support it.
|
|
(3).Normal -- Other packets which send as 11n rate.
|
|
|
|
B/G Rate : If peer is b/g only.
|
|
(1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6
|
|
(2).Normal -- Other packets which send as b/g rate.
|
|
Fragment:
|
|
The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment.
|
|
|
|
Classified Packet Handle Rule=>
|
|
Multicast:
|
|
No ACK, //pTxBlk->bAckRequired = FALSE;
|
|
No WMM, //pTxBlk->bWMM = FALSE;
|
|
No piggyback, //pTxBlk->bPiggyBack = FALSE;
|
|
Force LowRate, //pTxBlk->bForceLowRate = TRUE;
|
|
Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use
|
|
the same policy to handle it.
|
|
Force LowRate, //pTxBlk->bForceLowRate = TRUE;
|
|
|
|
11N Rate :
|
|
No piggyback, //pTxBlk->bPiggyBack = FALSE;
|
|
|
|
(1).AMSDU
|
|
pTxBlk->bWMM = TRUE;
|
|
(2).AMPDU
|
|
pTxBlk->bWMM = TRUE;
|
|
(3).Normal
|
|
|
|
B/G Rate :
|
|
(1).ARALINK
|
|
|
|
(2).Normal
|
|
========================================================================
|
|
*/
|
|
static UCHAR TxPktClassification(
|
|
IN RTMP_ADAPTER *pAd,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
UCHAR TxFrameType = TX_UNKOWN_FRAME;
|
|
UCHAR Wcid;
|
|
MAC_TABLE_ENTRY *pMacEntry = NULL;
|
|
BOOLEAN bHTRate = FALSE;
|
|
|
|
Wcid = RTMP_GET_PACKET_WCID(pPacket);
|
|
if (Wcid == MCAST_WCID)
|
|
{ // Handle for RA is Broadcast/Multicast Address.
|
|
return TX_MCAST_FRAME;
|
|
}
|
|
|
|
// Handle for unicast packets
|
|
pMacEntry = &pAd->MacTab.Content[Wcid];
|
|
if (RTMP_GET_PACKET_LOWRATE(pPacket))
|
|
{ // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame
|
|
TxFrameType = TX_LEGACY_FRAME;
|
|
}
|
|
else if (IS_HT_RATE(pMacEntry))
|
|
{ // it's a 11n capable packet
|
|
|
|
// Depends on HTPhyMode to check if the peer support the HTRate transmission.
|
|
// Currently didn't support A-MSDU embedded in A-MPDU
|
|
bHTRate = TRUE;
|
|
if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE))
|
|
TxFrameType = TX_LEGACY_FRAME;
|
|
#ifdef UAPSD_AP_SUPPORT
|
|
else if (RTMP_GET_PACKET_EOSP(pPacket))
|
|
TxFrameType = TX_LEGACY_FRAME;
|
|
#endif // UAPSD_AP_SUPPORT //
|
|
else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0)
|
|
return TX_AMPDU_FRAME;
|
|
else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED))
|
|
return TX_AMSDU_FRAME;
|
|
else
|
|
TxFrameType = TX_LEGACY_FRAME;
|
|
}
|
|
else
|
|
{ // it's a legacy b/g packet.
|
|
if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) &&
|
|
(RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) &&
|
|
(!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE))))
|
|
{ // if peer support Ralink Aggregation, we use it.
|
|
TxFrameType = TX_RALINK_FRAME;
|
|
}
|
|
else
|
|
{
|
|
TxFrameType = TX_LEGACY_FRAME;
|
|
}
|
|
}
|
|
|
|
// Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU.
|
|
if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME))
|
|
TxFrameType = TX_FRAG_FRAME;
|
|
|
|
return TxFrameType;
|
|
}
|
|
|
|
|
|
BOOLEAN RTMP_FillTxBlkInfo(
|
|
IN RTMP_ADAPTER *pAd,
|
|
IN TX_BLK *pTxBlk)
|
|
{
|
|
PACKET_INFO PacketInfo;
|
|
PNDIS_PACKET pPacket;
|
|
PMAC_TABLE_ENTRY pMacEntry = NULL;
|
|
|
|
pPacket = pTxBlk->pPacket;
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen);
|
|
|
|
pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket);
|
|
pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket);
|
|
pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket);
|
|
pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap
|
|
|
|
if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket))
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame);
|
|
else
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame);
|
|
|
|
// Default to clear this flag
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS);
|
|
|
|
|
|
if (pTxBlk->Wcid == MCAST_WCID)
|
|
{
|
|
pTxBlk->pMacEntry = NULL;
|
|
{
|
|
#ifdef MCAST_RATE_SPECIFIC
|
|
PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket);
|
|
if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff))
|
|
pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode;
|
|
else
|
|
#endif // MCAST_RATE_SPECIFIC //
|
|
pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode;
|
|
}
|
|
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode.
|
|
//TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate);
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag);
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM);
|
|
if (RTMP_GET_PACKET_MOREDATA(pPacket))
|
|
{
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid];
|
|
pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode;
|
|
|
|
pMacEntry = pTxBlk->pMacEntry;
|
|
|
|
|
|
// For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK.
|
|
if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK)
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired);
|
|
else
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired);
|
|
|
|
{
|
|
// If support WMM, enable it.
|
|
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) &&
|
|
CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE))
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM);
|
|
}
|
|
|
|
if (pTxBlk->TxFrameType == TX_LEGACY_FRAME)
|
|
{
|
|
if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) ||
|
|
((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1)))
|
|
{ // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate.
|
|
pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode;
|
|
|
|
// Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it???
|
|
if (IS_HT_STA(pTxBlk->pMacEntry) &&
|
|
(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) &&
|
|
((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)))
|
|
{
|
|
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM);
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS);
|
|
}
|
|
}
|
|
|
|
if ( (IS_HT_RATE(pMacEntry) == FALSE) &&
|
|
(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE)))
|
|
{ // Currently piggy-back only support when peer is operate in b/g mode.
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack);
|
|
}
|
|
|
|
if (RTMP_GET_PACKET_MOREDATA(pPacket))
|
|
{
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData);
|
|
}
|
|
#ifdef UAPSD_AP_SUPPORT
|
|
if (RTMP_GET_PACKET_EOSP(pPacket))
|
|
{
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP);
|
|
}
|
|
#endif // UAPSD_AP_SUPPORT //
|
|
}
|
|
else if (pTxBlk->TxFrameType == TX_FRAG_FRAME)
|
|
{
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag);
|
|
}
|
|
|
|
pMacEntry->DebugTxCount++;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
#ifdef RT30xx
|
|
FillTxBlkErr:
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
|
|
BOOLEAN CanDoAggregateTransmit(
|
|
IN RTMP_ADAPTER *pAd,
|
|
IN NDIS_PACKET *pPacket,
|
|
IN TX_BLK *pTxBlk)
|
|
{
|
|
|
|
//printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType);
|
|
|
|
if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID)
|
|
return FALSE;
|
|
|
|
if (RTMP_GET_PACKET_DHCP(pPacket) ||
|
|
RTMP_GET_PACKET_EAPOL(pPacket) ||
|
|
RTMP_GET_PACKET_WAI(pPacket))
|
|
return FALSE;
|
|
|
|
if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) &&
|
|
((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100)))
|
|
{ // For AMSDU, allow the packets with total length < max-amsdu size
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) &&
|
|
(pTxBlk->TxPacketList.Number == 2))
|
|
{ // For RALINK-Aggregation, allow two frames in one batch.
|
|
return FALSE;
|
|
}
|
|
|
|
if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
To do the enqueue operation and extract the first item of waiting
|
|
list. If a number of available shared memory segments could meet
|
|
the request of extracted item, the extracted item will be fragmented
|
|
into shared memory segments.
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
pQueue Pointer to Waiting Queue
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPDeQueuePacket(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN BOOLEAN bIntContext,
|
|
IN UCHAR QIdx, /* BulkOutPipeId */
|
|
IN UCHAR Max_Tx_Packets)
|
|
{
|
|
PQUEUE_ENTRY pEntry = NULL;
|
|
PNDIS_PACKET pPacket;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
UCHAR Count=0;
|
|
PQUEUE_HEADER pQueue;
|
|
ULONG FreeNumber[NUM_OF_TX_RING];
|
|
UCHAR QueIdx, sQIdx, eQIdx;
|
|
unsigned long IrqFlags = 0;
|
|
BOOLEAN hasTxDesc = FALSE;
|
|
TX_BLK TxBlk;
|
|
TX_BLK *pTxBlk;
|
|
|
|
#ifdef DBG_DIAGNOSE
|
|
BOOLEAN firstRound;
|
|
RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct;
|
|
#endif
|
|
|
|
|
|
if (QIdx == NUM_OF_TX_RING)
|
|
{
|
|
sQIdx = 0;
|
|
//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA)
|
|
eQIdx = 3; // 4 ACs, start from 0.
|
|
}
|
|
else
|
|
{
|
|
sQIdx = eQIdx = QIdx;
|
|
}
|
|
|
|
for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++)
|
|
{
|
|
Count=0;
|
|
|
|
RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
|
|
#ifdef DBG_DIAGNOSE
|
|
firstRound = ((QueIdx == 0) ? TRUE : FALSE);
|
|
#endif // DBG_DIAGNOSE //
|
|
|
|
while (1)
|
|
{
|
|
if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS |
|
|
fRTMP_ADAPTER_RADIO_OFF |
|
|
fRTMP_ADAPTER_RESET_IN_PROGRESS |
|
|
fRTMP_ADAPTER_HALT_IN_PROGRESS |
|
|
fRTMP_ADAPTER_NIC_NOT_EXIST))))
|
|
{
|
|
RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
return;
|
|
}
|
|
|
|
if (Count >= Max_Tx_Packets)
|
|
break;
|
|
|
|
DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
if (&pAd->TxSwQueue[QueIdx] == NULL)
|
|
{
|
|
#ifdef DBG_DIAGNOSE
|
|
if (firstRound == TRUE)
|
|
pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++;
|
|
#endif // DBG_DIAGNOSE //
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
break;
|
|
}
|
|
|
|
|
|
// probe the Queue Head
|
|
pQueue = &pAd->TxSwQueue[QueIdx];
|
|
if ((pEntry = pQueue->Head) == NULL)
|
|
{
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
break;
|
|
}
|
|
|
|
pTxBlk = &TxBlk;
|
|
NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK));
|
|
pTxBlk->QueIdx = QueIdx;
|
|
|
|
pPacket = QUEUE_ENTRY_TO_PKT(pEntry);
|
|
|
|
// Early check to make sure we have enoguh Tx Resource.
|
|
hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket);
|
|
if (!hasTxDesc)
|
|
{
|
|
pAd->PrivateInfo.TxRingFullCnt++;
|
|
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
|
|
break;
|
|
}
|
|
|
|
pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket);
|
|
pEntry = RemoveHeadQueue(pQueue);
|
|
pTxBlk->TotalFrameNum++;
|
|
pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary
|
|
pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket);
|
|
pTxBlk->pPacket = pPacket;
|
|
InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket));
|
|
|
|
if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME)
|
|
{
|
|
// Enhance SW Aggregation Mechanism
|
|
if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType))
|
|
{
|
|
InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket));
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
break;
|
|
}
|
|
|
|
do{
|
|
if((pEntry = pQueue->Head) == NULL)
|
|
break;
|
|
|
|
// For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation.
|
|
pPacket = QUEUE_ENTRY_TO_PKT(pEntry);
|
|
FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx);
|
|
hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket);
|
|
if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE))
|
|
break;
|
|
|
|
//Remove the packet from the TxSwQueue and insert into pTxBlk
|
|
pEntry = RemoveHeadQueue(pQueue);
|
|
ASSERT(pEntry);
|
|
pPacket = QUEUE_ENTRY_TO_PKT(pEntry);
|
|
pTxBlk->TotalFrameNum++;
|
|
pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary
|
|
pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket);
|
|
InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket));
|
|
}while(1);
|
|
|
|
if (pTxBlk->TxPacketList.Number == 1)
|
|
pTxBlk->TxFrameType = TX_LEGACY_FRAME;
|
|
}
|
|
|
|
#ifdef RT2870
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
#endif // RT2870 //
|
|
|
|
Count += pTxBlk->TxPacketList.Number;
|
|
|
|
// Do HardTransmit now.
|
|
Status = STAHardTransmit(pAd, pTxBlk, QueIdx);
|
|
}
|
|
|
|
RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
|
|
#ifdef RT2870
|
|
if (!hasTxDesc)
|
|
RTUSBKickBulkOut(pAd);
|
|
#endif // RT2870 //
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Calculates the duration which is required to transmit out frames
|
|
with given size and specified rate.
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
Rate Transmit rate
|
|
Size Frame size in units of byte
|
|
|
|
Return Value:
|
|
Duration number in units of usec
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
USHORT RTMPCalcDuration(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR Rate,
|
|
IN ULONG Size)
|
|
{
|
|
ULONG Duration = 0;
|
|
|
|
if (Rate < RATE_FIRST_OFDM_RATE) // CCK
|
|
{
|
|
if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED))
|
|
Duration = 96; // 72+24 preamble+plcp
|
|
else
|
|
Duration = 192; // 144+48 preamble+plcp
|
|
|
|
Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]);
|
|
if ((Size << 4) % RateIdTo500Kbps[Rate])
|
|
Duration ++;
|
|
}
|
|
else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates
|
|
{
|
|
Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension
|
|
Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]);
|
|
if ((11 + Size * 4) % RateIdTo500Kbps[Rate])
|
|
Duration += 4;
|
|
}
|
|
else //mimo rate
|
|
{
|
|
Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension
|
|
}
|
|
|
|
return (USHORT)Duration;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Calculates the duration which is required to transmit out frames
|
|
with given size and specified rate.
|
|
|
|
Arguments:
|
|
pTxWI Pointer to head of each MPDU to HW.
|
|
Ack Setting for Ack requirement bit
|
|
Fragment Setting for Fragment bit
|
|
RetryMode Setting for retry mode
|
|
Ifs Setting for IFS gap
|
|
Rate Setting for transmit rate
|
|
Service Setting for service
|
|
Length Frame length
|
|
TxPreamble Short or Long preamble when using CCK rates
|
|
QueIdx - 0-3, according to 802.11e/d4.4 June/2003
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
See also : BASmartHardTransmit() !!!
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPWriteTxWI(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PTXWI_STRUC pOutTxWI,
|
|
IN BOOLEAN FRAG,
|
|
IN BOOLEAN CFACK,
|
|
IN BOOLEAN InsTimestamp,
|
|
IN BOOLEAN AMPDU,
|
|
IN BOOLEAN Ack,
|
|
IN BOOLEAN NSeq, // HW new a sequence.
|
|
IN UCHAR BASize,
|
|
IN UCHAR WCID,
|
|
IN ULONG Length,
|
|
IN UCHAR PID,
|
|
IN UCHAR TID,
|
|
IN UCHAR TxRate,
|
|
IN UCHAR Txopmode,
|
|
IN BOOLEAN CfAck,
|
|
IN HTTRANSMIT_SETTING *pTransmit)
|
|
{
|
|
PMAC_TABLE_ENTRY pMac = NULL;
|
|
TXWI_STRUC TxWI;
|
|
PTXWI_STRUC pTxWI;
|
|
|
|
if (WCID < MAX_LEN_OF_MAC_TABLE)
|
|
pMac = &pAd->MacTab.Content[WCID];
|
|
|
|
//
|
|
// Always use Long preamble before verifiation short preamble functionality works well.
|
|
// Todo: remove the following line if short preamble functionality works
|
|
//
|
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
|
|
NdisZeroMemory(&TxWI, TXWI_SIZE);
|
|
pTxWI = &TxWI;
|
|
|
|
pTxWI->FRAG= FRAG;
|
|
|
|
pTxWI->CFACK = CFACK;
|
|
pTxWI->TS= InsTimestamp;
|
|
pTxWI->AMPDU = AMPDU;
|
|
pTxWI->ACK = Ack;
|
|
pTxWI->txop= Txopmode;
|
|
|
|
pTxWI->NSEQ = NSeq;
|
|
// John tune the performace with Intel Client in 20 MHz performance
|
|
BASize = pAd->CommonCfg.TxBASize;
|
|
|
|
if( BASize >7 )
|
|
BASize =7;
|
|
pTxWI->BAWinSize = BASize;
|
|
pTxWI->ShortGI = pTransmit->field.ShortGI;
|
|
pTxWI->STBC = pTransmit->field.STBC;
|
|
|
|
pTxWI->WirelessCliID = WCID;
|
|
pTxWI->MPDUtotalByteCount = Length;
|
|
pTxWI->PacketId = PID;
|
|
|
|
// If CCK or OFDM, BW must be 20
|
|
pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW);
|
|
|
|
pTxWI->MCS = pTransmit->field.MCS;
|
|
pTxWI->PHYMODE = pTransmit->field.MODE;
|
|
pTxWI->CFACK = CfAck;
|
|
|
|
if (pMac)
|
|
{
|
|
if (pAd->CommonCfg.bMIMOPSEnable)
|
|
{
|
|
if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7))
|
|
{
|
|
// Dynamic MIMO Power Save Mode
|
|
pTxWI->MIMOps = 1;
|
|
}
|
|
else if (pMac->MmpsMode == MMPS_STATIC)
|
|
{
|
|
// Static MIMO Power Save Mode
|
|
if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7)
|
|
{
|
|
pTxWI->MCS = 7;
|
|
pTxWI->MIMOps = 0;
|
|
}
|
|
}
|
|
}
|
|
//pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0;
|
|
if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled))
|
|
{
|
|
pTxWI->MpduDensity = 7;
|
|
}
|
|
else
|
|
{
|
|
pTxWI->MpduDensity = pMac->MpduDensity;
|
|
}
|
|
}
|
|
|
|
pTxWI->PacketId = pTxWI->MCS;
|
|
NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC));
|
|
}
|
|
|
|
|
|
VOID RTMPWriteTxWI_Data(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN OUT PTXWI_STRUC pTxWI,
|
|
IN TX_BLK *pTxBlk)
|
|
{
|
|
HTTRANSMIT_SETTING *pTransmit;
|
|
PMAC_TABLE_ENTRY pMacEntry;
|
|
UCHAR BASize;
|
|
|
|
ASSERT(pTxWI);
|
|
|
|
pTransmit = pTxBlk->pTransmit;
|
|
pMacEntry = pTxBlk->pMacEntry;
|
|
|
|
|
|
//
|
|
// Always use Long preamble before verifiation short preamble functionality works well.
|
|
// Todo: remove the following line if short preamble functionality works
|
|
//
|
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
|
|
NdisZeroMemory(pTxWI, TXWI_SIZE);
|
|
|
|
pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag);
|
|
pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired);
|
|
pTxWI->txop = pTxBlk->FrameGap;
|
|
|
|
pTxWI->WirelessCliID = pTxBlk->Wcid;
|
|
|
|
pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen;
|
|
pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack);
|
|
|
|
// If CCK or OFDM, BW must be 20
|
|
pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW);
|
|
pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE);
|
|
|
|
// John tune the performace with Intel Client in 20 MHz performance
|
|
BASize = pAd->CommonCfg.TxBASize;
|
|
if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry))
|
|
{
|
|
UCHAR RABAOriIdx = 0; //The RA's BA Originator table index.
|
|
|
|
RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority];
|
|
BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize;
|
|
}
|
|
|
|
pTxWI->TxBF = pTransmit->field.TxBF;
|
|
pTxWI->BAWinSize = BASize;
|
|
pTxWI->ShortGI = pTransmit->field.ShortGI;
|
|
pTxWI->STBC = pTransmit->field.STBC;
|
|
|
|
pTxWI->MCS = pTransmit->field.MCS;
|
|
pTxWI->PHYMODE = pTransmit->field.MODE;
|
|
|
|
if (pMacEntry)
|
|
{
|
|
if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7))
|
|
{
|
|
// Dynamic MIMO Power Save Mode
|
|
pTxWI->MIMOps = 1;
|
|
}
|
|
else if (pMacEntry->MmpsMode == MMPS_STATIC)
|
|
{
|
|
// Static MIMO Power Save Mode
|
|
if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7)
|
|
{
|
|
pTxWI->MCS = 7;
|
|
pTxWI->MIMOps = 0;
|
|
}
|
|
}
|
|
|
|
if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled))
|
|
{
|
|
pTxWI->MpduDensity = 7;
|
|
}
|
|
else
|
|
{
|
|
pTxWI->MpduDensity = pMacEntry->MpduDensity;
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_DIAGNOSE
|
|
if (pTxBlk->QueIdx== 0)
|
|
{
|
|
pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++;
|
|
pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++;
|
|
}
|
|
#endif // DBG_DIAGNOSE //
|
|
|
|
// for rate adapation
|
|
pTxWI->PacketId = pTxWI->MCS;
|
|
}
|
|
|
|
|
|
VOID RTMPWriteTxWI_Cache(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN OUT PTXWI_STRUC pTxWI,
|
|
IN TX_BLK *pTxBlk)
|
|
{
|
|
PHTTRANSMIT_SETTING pTransmit;
|
|
PMAC_TABLE_ENTRY pMacEntry;
|
|
|
|
//
|
|
// update TXWI
|
|
//
|
|
pMacEntry = pTxBlk->pMacEntry;
|
|
pTransmit = pTxBlk->pTransmit;
|
|
|
|
if (pMacEntry->bAutoTxRateSwitch)
|
|
{
|
|
pTxWI->txop = IFS_HTTXOP;
|
|
|
|
// If CCK or OFDM, BW must be 20
|
|
pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW);
|
|
pTxWI->ShortGI = pTransmit->field.ShortGI;
|
|
pTxWI->STBC = pTransmit->field.STBC;
|
|
|
|
pTxWI->MCS = pTransmit->field.MCS;
|
|
pTxWI->PHYMODE = pTransmit->field.MODE;
|
|
|
|
// set PID for TxRateSwitching
|
|
pTxWI->PacketId = pTransmit->field.MCS;
|
|
}
|
|
|
|
pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE);
|
|
pTxWI->MIMOps = 0;
|
|
|
|
if (pAd->CommonCfg.bMIMOPSEnable)
|
|
{
|
|
// MIMO Power Save Mode
|
|
if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7))
|
|
{
|
|
// Dynamic MIMO Power Save Mode
|
|
pTxWI->MIMOps = 1;
|
|
}
|
|
else if (pMacEntry->MmpsMode == MMPS_STATIC)
|
|
{
|
|
// Static MIMO Power Save Mode
|
|
if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7))
|
|
{
|
|
pTxWI->MCS = 7;
|
|
pTxWI->MIMOps = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_DIAGNOSE
|
|
if (pTxBlk->QueIdx== 0)
|
|
{
|
|
pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++;
|
|
pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++;
|
|
}
|
|
#endif // DBG_DIAGNOSE //
|
|
|
|
pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Calculates the duration which is required to transmit out frames
|
|
with given size and specified rate.
|
|
|
|
Arguments:
|
|
pTxD Pointer to transmit descriptor
|
|
Ack Setting for Ack requirement bit
|
|
Fragment Setting for Fragment bit
|
|
RetryMode Setting for retry mode
|
|
Ifs Setting for IFS gap
|
|
Rate Setting for transmit rate
|
|
Service Setting for service
|
|
Length Frame length
|
|
TxPreamble Short or Long preamble when using CCK rates
|
|
QueIdx - 0-3, according to 802.11e/d4.4 June/2003
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = PASSIVE_LEVEL
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPWriteTxDescriptor(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PTXD_STRUC pTxD,
|
|
IN BOOLEAN bWIV,
|
|
IN UCHAR QueueSEL)
|
|
{
|
|
//
|
|
// Always use Long preamble before verifiation short preamble functionality works well.
|
|
// Todo: remove the following line if short preamble functionality works
|
|
//
|
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
|
|
|
|
pTxD->WIV = (bWIV) ? 1: 0;
|
|
pTxD->QSEL= (QueueSEL);
|
|
if (pAd->bGenOneHCCA == TRUE)
|
|
pTxD->QSEL= FIFO_HCCA;
|
|
pTxD->DMADONE = 0;
|
|
}
|
|
|
|
|
|
// should be called only when -
|
|
// 1. MEADIA_CONNECTED
|
|
// 2. AGGREGATION_IN_USED
|
|
// 3. Fragmentation not in used
|
|
// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible
|
|
BOOLEAN TxFrameIsAggregatible(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pPrevAddr1,
|
|
IN PUCHAR p8023hdr)
|
|
{
|
|
|
|
// can't aggregate EAPOL (802.1x) frame
|
|
if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e))
|
|
return FALSE;
|
|
|
|
// can't aggregate multicast/broadcast frame
|
|
if (p8023hdr[0] & 0x01)
|
|
return FALSE;
|
|
|
|
if (INFRA_ON(pAd)) // must be unicast to AP
|
|
return TRUE;
|
|
else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Check the MSDU Aggregation policy
|
|
1.HT aggregation is A-MSDU
|
|
2.legaacy rate aggregation is software aggregation by Ralink.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
BOOLEAN PeerIsAggreOn(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN ULONG TxRate,
|
|
IN PMAC_TABLE_ENTRY pMacEntry)
|
|
{
|
|
ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE);
|
|
|
|
if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags))
|
|
{
|
|
if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef AGGREGATION_SUPPORT
|
|
if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE))))
|
|
{ // legacy Ralink Aggregation support
|
|
return TRUE;
|
|
}
|
|
#endif // AGGREGATION_SUPPORT //
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Check and fine the packet waiting in SW queue with highest priority
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
pQueue Pointer to Waiting Queue
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
PQUEUE_HEADER RTMPCheckTxSwQueue(
|
|
IN PRTMP_ADAPTER pAd,
|
|
OUT PUCHAR pQueIdx)
|
|
{
|
|
ULONG Number;
|
|
|
|
Number = pAd->TxSwQueue[QID_AC_BK].Number
|
|
+ pAd->TxSwQueue[QID_AC_BE].Number
|
|
+ pAd->TxSwQueue[QID_AC_VI].Number
|
|
+ pAd->TxSwQueue[QID_AC_VO].Number
|
|
+ pAd->TxSwQueue[QID_HCCA].Number;
|
|
|
|
if (pAd->TxSwQueue[QID_AC_VO].Head != NULL)
|
|
{
|
|
*pQueIdx = QID_AC_VO;
|
|
return (&pAd->TxSwQueue[QID_AC_VO]);
|
|
}
|
|
else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL)
|
|
{
|
|
*pQueIdx = QID_AC_VI;
|
|
return (&pAd->TxSwQueue[QID_AC_VI]);
|
|
}
|
|
else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL)
|
|
{
|
|
*pQueIdx = QID_AC_BE;
|
|
return (&pAd->TxSwQueue[QID_AC_BE]);
|
|
}
|
|
else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL)
|
|
{
|
|
*pQueIdx = QID_AC_BK;
|
|
return (&pAd->TxSwQueue[QID_AC_BK]);
|
|
}
|
|
else if (pAd->TxSwQueue[QID_HCCA].Head != NULL)
|
|
{
|
|
*pQueIdx = QID_HCCA;
|
|
return (&pAd->TxSwQueue[QID_HCCA]);
|
|
}
|
|
|
|
// No packet pending in Tx Sw queue
|
|
*pQueIdx = QID_AC_BK;
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Suspend MSDU transmission
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPSuspendMsduTransmission(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n"));
|
|
|
|
|
|
//
|
|
// Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and
|
|
// use Lowbound as R66 value on ScanNextChannel(...)
|
|
//
|
|
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue);
|
|
|
|
// set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning)
|
|
RTMPSetAGCInitValue(pAd, BW_20);
|
|
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Resume MSDU transmission
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPResumeMsduTransmission(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n"));
|
|
|
|
#ifdef RT30xx
|
|
// After finish BSS_SCAN_IN_PROGRESS, we need to restore Current R66 value
|
|
// R66 should not be 0
|
|
if (pAd->BbpTuning.R66CurrentValue == 0)
|
|
{
|
|
pAd->BbpTuning.R66CurrentValue = 0x38;
|
|
DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n"));
|
|
}
|
|
#endif
|
|
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue);
|
|
|
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
|
|
RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS);
|
|
}
|
|
|
|
|
|
UINT deaggregate_AMSDU_announce(
|
|
IN PRTMP_ADAPTER pAd,
|
|
PNDIS_PACKET pPacket,
|
|
IN PUCHAR pData,
|
|
IN ULONG DataSize)
|
|
{
|
|
USHORT PayloadSize;
|
|
USHORT SubFrameSize;
|
|
PHEADER_802_3 pAMSDUsubheader;
|
|
UINT nMSDU;
|
|
UCHAR Header802_3[14];
|
|
|
|
PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP;
|
|
PNDIS_PACKET pClonePacket;
|
|
|
|
|
|
|
|
nMSDU = 0;
|
|
|
|
while (DataSize > LENGTH_802_3)
|
|
{
|
|
|
|
nMSDU++;
|
|
|
|
pAMSDUsubheader = (PHEADER_802_3)pData;
|
|
PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8);
|
|
SubFrameSize = PayloadSize + LENGTH_802_3;
|
|
|
|
|
|
if ((DataSize < SubFrameSize) || (PayloadSize > 1518 ))
|
|
{
|
|
break;
|
|
}
|
|
|
|
pPayload = pData + LENGTH_802_3;
|
|
pDA = pData;
|
|
pSA = pData + MAC_ADDR_LEN;
|
|
|
|
// convert to 802.3 header
|
|
CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP);
|
|
|
|
if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) )
|
|
{
|
|
// avoid local heap overflow, use dyanamic allocation
|
|
MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
|
|
memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize);
|
|
Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize;
|
|
WpaEAPOLKeyAction(pAd, Elem);
|
|
kfree(Elem);
|
|
}
|
|
|
|
{
|
|
if (pRemovedLLCSNAP)
|
|
{
|
|
pPayload -= LENGTH_802_3;
|
|
PayloadSize += LENGTH_802_3;
|
|
NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3);
|
|
}
|
|
}
|
|
|
|
pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize);
|
|
if (pClonePacket)
|
|
{
|
|
ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket));
|
|
}
|
|
|
|
|
|
// A-MSDU has padding to multiple of 4 including subframe header.
|
|
// align SubFrameSize up to multiple of 4
|
|
SubFrameSize = (SubFrameSize+3)&(~0x3);
|
|
|
|
|
|
if (SubFrameSize > 1528 || SubFrameSize < 32)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (DataSize > SubFrameSize)
|
|
{
|
|
pData += SubFrameSize;
|
|
DataSize -= SubFrameSize;
|
|
}
|
|
else
|
|
{
|
|
// end of A-MSDU
|
|
DataSize = 0;
|
|
}
|
|
}
|
|
|
|
// finally release original rx packet
|
|
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
|
|
|
|
return nMSDU;
|
|
}
|
|
|
|
|
|
UINT BA_Reorder_AMSDU_Annnounce(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
PUCHAR pData;
|
|
USHORT DataSize;
|
|
UINT nMSDU = 0;
|
|
|
|
pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket);
|
|
DataSize = (USHORT) GET_OS_PKT_LEN(pPacket);
|
|
|
|
nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize);
|
|
|
|
return nMSDU;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Look up the MAC address in the MAC table. Return NULL if not found.
|
|
Return:
|
|
pEntry - pointer to the MAC entry; NULL is not found
|
|
==========================================================================
|
|
*/
|
|
MAC_TABLE_ENTRY *MacTableLookup(
|
|
IN PRTMP_ADAPTER pAd,
|
|
PUCHAR pAddr)
|
|
{
|
|
ULONG HashIdx;
|
|
MAC_TABLE_ENTRY *pEntry = NULL;
|
|
|
|
HashIdx = MAC_ADDR_HASH_INDEX(pAddr);
|
|
pEntry = pAd->MacTab.Hash[HashIdx];
|
|
|
|
while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh))
|
|
{
|
|
if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
return pEntry;
|
|
}
|
|
|
|
MAC_TABLE_ENTRY *MacTableInsertEntry(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pAddr,
|
|
IN UCHAR apidx,
|
|
IN BOOLEAN CleanAll)
|
|
{
|
|
UCHAR HashIdx;
|
|
int i, FirstWcid;
|
|
MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry;
|
|
|
|
// if FULL, return
|
|
if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE)
|
|
return NULL;
|
|
|
|
FirstWcid = 1;
|
|
|
|
if (pAd->StaCfg.BssType == BSS_INFRA)
|
|
FirstWcid = 2;
|
|
|
|
// allocate one MAC entry
|
|
NdisAcquireSpinLock(&pAd->MacTabLock);
|
|
for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup
|
|
{
|
|
// pick up the first available vacancy
|
|
if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) &&
|
|
(pAd->MacTab.Content[i].ValidAsWDS == FALSE) &&
|
|
(pAd->MacTab.Content[i].ValidAsApCli== FALSE) &&
|
|
(pAd->MacTab.Content[i].ValidAsMesh == FALSE)
|
|
)
|
|
{
|
|
pEntry = &pAd->MacTab.Content[i];
|
|
if (CleanAll == TRUE)
|
|
{
|
|
pEntry->MaxSupportedRate = RATE_11;
|
|
pEntry->CurrTxRate = RATE_11;
|
|
NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY));
|
|
pEntry->PairwiseKey.KeyLen = 0;
|
|
pEntry->PairwiseKey.CipherAlg = CIPHER_NONE;
|
|
}
|
|
{
|
|
{
|
|
pEntry->ValidAsCLI = TRUE;
|
|
pEntry->ValidAsWDS = FALSE;
|
|
pEntry->ValidAsApCli = FALSE;
|
|
pEntry->ValidAsMesh = FALSE;
|
|
pEntry->ValidAsDls = FALSE;
|
|
}
|
|
}
|
|
|
|
pEntry->bIAmBadAtheros = FALSE;
|
|
pEntry->pAd = pAd;
|
|
pEntry->CMTimerRunning = FALSE;
|
|
pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
|
|
pEntry->RSNIE_Len = 0;
|
|
NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter));
|
|
pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR;
|
|
|
|
if (pEntry->ValidAsMesh)
|
|
pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH);
|
|
else if (pEntry->ValidAsApCli)
|
|
pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI);
|
|
else if (pEntry->ValidAsWDS)
|
|
pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS);
|
|
else
|
|
pEntry->apidx = apidx;
|
|
|
|
{
|
|
{
|
|
pEntry->AuthMode = pAd->StaCfg.AuthMode;
|
|
pEntry->WepStatus = pAd->StaCfg.WepStatus;
|
|
pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
|
|
}
|
|
}
|
|
|
|
pEntry->GTKState = REKEY_NEGOTIATING;
|
|
pEntry->PairwiseKey.KeyLen = 0;
|
|
pEntry->PairwiseKey.CipherAlg = CIPHER_NONE;
|
|
pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED;
|
|
pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND;
|
|
COPY_MAC_ADDR(pEntry->Addr, pAddr);
|
|
pEntry->Sst = SST_NOT_AUTH;
|
|
pEntry->AuthState = AS_NOT_AUTH;
|
|
pEntry->Aid = (USHORT)i; //0;
|
|
pEntry->CapabilityInfo = 0;
|
|
pEntry->PsMode = PWR_ACTIVE;
|
|
pEntry->PsQIdleCount = 0;
|
|
pEntry->NoDataIdleCount = 0;
|
|
pEntry->ContinueTxFailCnt = 0;
|
|
InitializeQueueHeader(&pEntry->PsQueue);
|
|
|
|
|
|
pAd->MacTab.Size ++;
|
|
// Add this entry into ASIC RX WCID search table
|
|
RT28XX_STA_ENTRY_ADD(pAd, pEntry);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// add this MAC entry into HASH table
|
|
if (pEntry)
|
|
{
|
|
HashIdx = MAC_ADDR_HASH_INDEX(pAddr);
|
|
if (pAd->MacTab.Hash[HashIdx] == NULL)
|
|
{
|
|
pAd->MacTab.Hash[HashIdx] = pEntry;
|
|
}
|
|
else
|
|
{
|
|
pCurrEntry = pAd->MacTab.Hash[HashIdx];
|
|
while (pCurrEntry->pNext != NULL)
|
|
pCurrEntry = pCurrEntry->pNext;
|
|
pCurrEntry->pNext = pEntry;
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&pAd->MacTabLock);
|
|
return pEntry;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Delete a specified client from MAC table
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN MacTableDeleteEntry(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN USHORT wcid,
|
|
IN PUCHAR pAddr)
|
|
{
|
|
USHORT HashIdx;
|
|
MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry;
|
|
BOOLEAN Cancelled;
|
|
|
|
if (wcid >= MAX_LEN_OF_MAC_TABLE)
|
|
return FALSE;
|
|
|
|
NdisAcquireSpinLock(&pAd->MacTabLock);
|
|
|
|
HashIdx = MAC_ADDR_HASH_INDEX(pAddr);
|
|
pEntry = &pAd->MacTab.Content[wcid];
|
|
|
|
if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh
|
|
))
|
|
{
|
|
if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr))
|
|
{
|
|
|
|
// Delete this entry from ASIC on-chip WCID Table
|
|
RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid);
|
|
|
|
// free resources of BA
|
|
BASessionTearDownALL(pAd, pEntry->Aid);
|
|
|
|
pPrevEntry = NULL;
|
|
pProbeEntry = pAd->MacTab.Hash[HashIdx];
|
|
ASSERT(pProbeEntry);
|
|
|
|
// update Hash list
|
|
do
|
|
{
|
|
if (pProbeEntry == pEntry)
|
|
{
|
|
if (pPrevEntry == NULL)
|
|
{
|
|
pAd->MacTab.Hash[HashIdx] = pEntry->pNext;
|
|
}
|
|
else
|
|
{
|
|
pPrevEntry->pNext = pEntry->pNext;
|
|
}
|
|
break;
|
|
}
|
|
|
|
pPrevEntry = pProbeEntry;
|
|
pProbeEntry = pProbeEntry->pNext;
|
|
} while (pProbeEntry);
|
|
|
|
// not found !!!
|
|
ASSERT(pProbeEntry != NULL);
|
|
|
|
RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid);
|
|
|
|
|
|
if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE)
|
|
{
|
|
RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled);
|
|
pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
|
|
}
|
|
|
|
|
|
NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY));
|
|
pAd->MacTab.Size --;
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size));
|
|
}
|
|
else
|
|
{
|
|
printk("\n%s: Impossible Wcid = %d !!!!!\n", __func__, wcid);
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&pAd->MacTabLock);
|
|
|
|
//Reset operating mode when no Sta.
|
|
if (pAd->MacTab.Size == 0)
|
|
{
|
|
pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0;
|
|
#ifndef RT30xx
|
|
AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/);
|
|
#endif
|
|
#ifdef RT30xx
|
|
RT28XX_UPDATE_PROTECT(pAd); // edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet
|
|
#endif
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
This routine reset the entire MAC table. All packets pending in
|
|
the power-saving queues are freed here.
|
|
==========================================================================
|
|
*/
|
|
VOID MacTableReset(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
int i;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n"));
|
|
//NdisAcquireSpinLock(&pAd->MacTabLock);
|
|
|
|
for (i=1; i<MAX_LEN_OF_MAC_TABLE; i++)
|
|
{
|
|
if (pAd->MacTab.Content[i].ValidAsCLI == TRUE)
|
|
{
|
|
// free resources of BA
|
|
BASessionTearDownALL(pAd, i);
|
|
|
|
pAd->MacTab.Content[i].ValidAsCLI = FALSE;
|
|
|
|
|
|
|
|
#ifdef RT2870
|
|
NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6);
|
|
RT28XX_STA_ENTRY_MAC_RESET(pAd, i);
|
|
#endif // RT2870 //
|
|
|
|
//AsicDelWcidTab(pAd, i);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
==========================================================================
|
|
*/
|
|
VOID AssocParmFill(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq,
|
|
IN PUCHAR pAddr,
|
|
IN USHORT CapabilityInfo,
|
|
IN ULONG Timeout,
|
|
IN USHORT ListenIntv)
|
|
{
|
|
COPY_MAC_ADDR(AssocReq->Addr, pAddr);
|
|
// Add mask to support 802.11b mode only
|
|
AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request
|
|
AssocReq->Timeout = Timeout;
|
|
AssocReq->ListenIntv = ListenIntv;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
==========================================================================
|
|
*/
|
|
VOID DisassocParmFill(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq,
|
|
IN PUCHAR pAddr,
|
|
IN USHORT Reason)
|
|
{
|
|
COPY_MAC_ADDR(DisassocReq->Addr, pAddr);
|
|
DisassocReq->Reason = Reason;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Check the out going frame, if this is an DHCP or ARP datagram
|
|
will be duplicate another frame at low data rate transmit.
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
pPacket Pointer to outgoing Ndis frame
|
|
|
|
Return Value:
|
|
TRUE To be duplicate at Low data rate transmit. (1mb)
|
|
FALSE Do nothing.
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
MAC header + IP Header + UDP Header
|
|
14 Bytes 20 Bytes
|
|
|
|
UDP Header
|
|
00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|
|
|
Source Port
|
|
16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|
|
|
Destination Port
|
|
|
|
port 0x43 means Bootstrap Protocol, server.
|
|
Port 0x44 means Bootstrap Protocol, client.
|
|
|
|
========================================================================
|
|
*/
|
|
|
|
BOOLEAN RTMPCheckDHCPFrame(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
PACKET_INFO PacketInfo;
|
|
ULONG NumberOfBytesRead = 0;
|
|
ULONG CurrentOffset = 0;
|
|
PVOID pVirtualAddress = NULL;
|
|
UINT NdisBufferLength;
|
|
PUCHAR pSrc;
|
|
USHORT Protocol;
|
|
UCHAR ByteOffset36 = 0;
|
|
UCHAR ByteOffset38 = 0;
|
|
BOOLEAN ReadFirstParm = TRUE;
|
|
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength);
|
|
|
|
NumberOfBytesRead += NdisBufferLength;
|
|
pSrc = (PUCHAR) pVirtualAddress;
|
|
Protocol = *(pSrc + 12) * 256 + *(pSrc + 13);
|
|
|
|
//
|
|
// Check DHCP & BOOTP protocol
|
|
//
|
|
while (NumberOfBytesRead <= PacketInfo.TotalPacketLength)
|
|
{
|
|
if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE))
|
|
{
|
|
CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength);
|
|
ByteOffset36 = *(pSrc + CurrentOffset);
|
|
ReadFirstParm = FALSE;
|
|
}
|
|
|
|
if (NumberOfBytesRead >= 37)
|
|
{
|
|
CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength);
|
|
ByteOffset38 = *(pSrc + CurrentOffset);
|
|
//End of Read
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Check for DHCP & BOOTP protocol
|
|
if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43))
|
|
{
|
|
//
|
|
// 2054 (hex 0806) for ARP datagrams
|
|
// if this packet is not ARP datagrams, then do nothing
|
|
// ARP datagrams will also be duplicate at 1mb broadcast frames
|
|
//
|
|
if (Protocol != 0x0806 )
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN RTMPCheckEtherType(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PNDIS_PACKET pPacket)
|
|
{
|
|
USHORT TypeLen;
|
|
UCHAR Byte0, Byte1;
|
|
PUCHAR pSrcBuf;
|
|
UINT32 pktLen;
|
|
UINT16 srcPort, dstPort;
|
|
BOOLEAN status = TRUE;
|
|
|
|
|
|
pSrcBuf = GET_OS_PKT_DATAPTR(pPacket);
|
|
pktLen = GET_OS_PKT_LEN(pPacket);
|
|
|
|
ASSERT(pSrcBuf);
|
|
|
|
RTMP_SET_PACKET_SPECIFIC(pPacket, 0);
|
|
|
|
// get Ethernet protocol field
|
|
TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13];
|
|
|
|
pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header.
|
|
|
|
if (TypeLen <= 1500)
|
|
{ // 802.3, 802.3 LLC
|
|
/*
|
|
DestMAC(6) + SrcMAC(6) + Lenght(2) +
|
|
DSAP(1) + SSAP(1) + Control(1) +
|
|
if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header.
|
|
=> + SNAP (5, OriginationID(3) + etherType(2))
|
|
*/
|
|
if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03)
|
|
{
|
|
Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1);
|
|
RTMP_SET_PACKET_LLCSNAP(pPacket, 1);
|
|
TypeLen = (USHORT)((Byte0 << 8) + Byte1);
|
|
pSrcBuf += 8; // Skip this LLC/SNAP header
|
|
}
|
|
else
|
|
{
|
|
//It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it.
|
|
}
|
|
}
|
|
|
|
// If it's a VLAN packet, get the real Type/Length field.
|
|
if (TypeLen == 0x8100)
|
|
{
|
|
/* 0x8100 means VLAN packets */
|
|
|
|
/* Dest. MAC Address (6-bytes) +
|
|
Source MAC Address (6-bytes) +
|
|
Length/Type = 802.1Q Tag Type (2-byte) +
|
|
Tag Control Information (2-bytes) +
|
|
Length / Type (2-bytes) +
|
|
data payload (0-n bytes) +
|
|
Pad (0-p bytes) +
|
|
Frame Check Sequence (4-bytes) */
|
|
|
|
RTMP_SET_PACKET_VLAN(pPacket, 1);
|
|
Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1);
|
|
TypeLen = (USHORT)((Byte0 << 8) + Byte1);
|
|
|
|
pSrcBuf += 4; // Skip the VLAN Header.
|
|
}
|
|
|
|
switch (TypeLen)
|
|
{
|
|
case 0x0800:
|
|
{
|
|
ASSERT((pktLen > 34));
|
|
if (*(pSrcBuf + 9) == 0x11)
|
|
{ // udp packet
|
|
ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header
|
|
|
|
pSrcBuf += 20; // Skip the IP header
|
|
srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf));
|
|
dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2)));
|
|
|
|
if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44))
|
|
{ //It's a BOOTP/DHCP packet
|
|
RTMP_SET_PACKET_DHCP(pPacket, 1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 0x0806:
|
|
{
|
|
//ARP Packet.
|
|
RTMP_SET_PACKET_DHCP(pPacket, 1);
|
|
}
|
|
break;
|
|
case 0x888e:
|
|
{
|
|
// EAPOL Packet.
|
|
RTMP_SET_PACKET_EAPOL(pPacket, 1);
|
|
}
|
|
break;
|
|
default:
|
|
status = FALSE;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID Update_Rssi_Sample(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RSSI_SAMPLE *pRssi,
|
|
IN PRXWI_STRUC pRxWI)
|
|
{
|
|
CHAR rssi0 = pRxWI->RSSI0;
|
|
CHAR rssi1 = pRxWI->RSSI1;
|
|
CHAR rssi2 = pRxWI->RSSI2;
|
|
|
|
if (rssi0 != 0)
|
|
{
|
|
pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0);
|
|
pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0;
|
|
pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3;
|
|
}
|
|
|
|
if (rssi1 != 0)
|
|
{
|
|
pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1);
|
|
pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1;
|
|
pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3;
|
|
}
|
|
|
|
if (rssi2 != 0)
|
|
{
|
|
pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2);
|
|
pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2;
|
|
pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Normal legacy Rx packet indication
|
|
VOID Indicate_Legacy_Packet(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RX_BLK *pRxBlk,
|
|
IN UCHAR FromWhichBSSID)
|
|
{
|
|
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
|
|
UCHAR Header802_3[LENGTH_802_3];
|
|
|
|
// 1. get 802.3 Header
|
|
// 2. remove LLC
|
|
// a. pointer pRxBlk->pData to payload
|
|
// b. modify pRxBlk->DataSize
|
|
RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3);
|
|
|
|
if (pRxBlk->DataSize > MAX_RX_PKT_LEN)
|
|
{
|
|
|
|
// release packet
|
|
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
|
|
return;
|
|
}
|
|
|
|
|
|
STATS_INC_RX_PACKETS(pAd, FromWhichBSSID);
|
|
|
|
#ifdef RT2870
|
|
if (pAd->CommonCfg.bDisableReordering == 0)
|
|
{
|
|
PBA_REC_ENTRY pBAEntry;
|
|
ULONG Now32;
|
|
UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID;
|
|
UCHAR TID = pRxBlk->pRxWI->TID;
|
|
USHORT Idx;
|
|
|
|
#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms
|
|
|
|
if (Wcid < MAX_LEN_OF_MAC_TABLE)
|
|
{
|
|
Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
|
|
if (Idx != 0)
|
|
{
|
|
pBAEntry = &pAd->BATable.BARecEntry[Idx];
|
|
// update last rx time
|
|
NdisGetSystemUpTime(&Now32);
|
|
if ((pBAEntry->list.qlen > 0) &&
|
|
RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT)))
|
|
)
|
|
{
|
|
printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU);
|
|
hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64);
|
|
ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // RT2870 //
|
|
|
|
wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID);
|
|
|
|
//
|
|
// pass this 802.3 packet to upper layer or forward this packet to WM directly
|
|
//
|
|
ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID);
|
|
}
|
|
|
|
|
|
// Normal, AMPDU or AMSDU
|
|
VOID CmmRxnonRalinkFrameIndicate(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RX_BLK *pRxBlk,
|
|
IN UCHAR FromWhichBSSID)
|
|
{
|
|
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0))
|
|
{
|
|
Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID);
|
|
}
|
|
else
|
|
{
|
|
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU))
|
|
{
|
|
// handle A-MSDU
|
|
Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID);
|
|
}
|
|
else
|
|
{
|
|
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID CmmRxRalinkFrameIndicate(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN MAC_TABLE_ENTRY *pEntry,
|
|
IN RX_BLK *pRxBlk,
|
|
IN UCHAR FromWhichBSSID)
|
|
{
|
|
UCHAR Header802_3[LENGTH_802_3];
|
|
UINT16 Msdu2Size;
|
|
UINT16 Payload1Size, Payload2Size;
|
|
PUCHAR pData2;
|
|
PNDIS_PACKET pPacket2 = NULL;
|
|
|
|
|
|
|
|
Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8);
|
|
|
|
if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize))
|
|
{
|
|
/* skip two byte MSDU2 len */
|
|
pRxBlk->pData += 2;
|
|
pRxBlk->DataSize -= 2;
|
|
}
|
|
else
|
|
{
|
|
// release packet
|
|
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
|
|
return;
|
|
}
|
|
|
|
// get 802.3 Header and remove LLC
|
|
RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3);
|
|
|
|
ASSERT(pRxBlk->pRxPacket);
|
|
|
|
// Ralink Aggregation frame
|
|
pAd->RalinkCounters.OneSecRxAggregationCount ++;
|
|
Payload1Size = pRxBlk->DataSize - Msdu2Size;
|
|
Payload2Size = Msdu2Size - LENGTH_802_3;
|
|
|
|
pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3;
|
|
|
|
pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID);
|
|
|
|
if (!pPacket2)
|
|
{
|
|
// release packet
|
|
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
|
|
return;
|
|
}
|
|
|
|
// update payload size of 1st packet
|
|
pRxBlk->DataSize = Payload1Size;
|
|
wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID);
|
|
|
|
ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID);
|
|
|
|
if (pPacket2)
|
|
{
|
|
ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID);
|
|
}
|
|
}
|
|
|
|
|
|
#define RESET_FRAGFRAME(_fragFrame) \
|
|
{ \
|
|
_fragFrame.RxSize = 0; \
|
|
_fragFrame.Sequence = 0; \
|
|
_fragFrame.LastFrag = 0; \
|
|
_fragFrame.Flags = 0; \
|
|
}
|
|
|
|
|
|
PNDIS_PACKET RTMPDeFragmentDataFrame(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RX_BLK *pRxBlk)
|
|
{
|
|
PHEADER_802_11 pHeader = pRxBlk->pHeader;
|
|
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
|
|
UCHAR *pData = pRxBlk->pData;
|
|
USHORT DataSize = pRxBlk->DataSize;
|
|
PNDIS_PACKET pRetPacket = NULL;
|
|
UCHAR *pFragBuffer = NULL;
|
|
BOOLEAN bReassDone = FALSE;
|
|
UCHAR HeaderRoom = 0;
|
|
|
|
|
|
ASSERT(pHeader);
|
|
|
|
HeaderRoom = pData - (UCHAR *)pHeader;
|
|
|
|
// Re-assemble the fragmented packets
|
|
if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt
|
|
{
|
|
// the first pkt of fragment, record it.
|
|
if (pHeader->FC.MoreFrag)
|
|
{
|
|
ASSERT(pAd->FragFrame.pFragPacket);
|
|
pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket);
|
|
pAd->FragFrame.RxSize = DataSize + HeaderRoom;
|
|
NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize);
|
|
pAd->FragFrame.Sequence = pHeader->Sequence;
|
|
pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0
|
|
ASSERT(pAd->FragFrame.LastFrag == 0);
|
|
goto done; // end of processing this frame
|
|
}
|
|
}
|
|
else //Middle & End of fragment
|
|
{
|
|
if ((pHeader->Sequence != pAd->FragFrame.Sequence) ||
|
|
(pHeader->Frag != (pAd->FragFrame.LastFrag + 1)))
|
|
{
|
|
// Fragment is not the same sequence or out of fragment number order
|
|
// Reset Fragment control blk
|
|
RESET_FRAGFRAME(pAd->FragFrame);
|
|
DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n"));
|
|
goto done; // give up this frame
|
|
}
|
|
else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE)
|
|
{
|
|
// Fragment frame is too large, it exeeds the maximum frame size.
|
|
// Reset Fragment control blk
|
|
RESET_FRAGFRAME(pAd->FragFrame);
|
|
DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n"));
|
|
goto done; // give up this frame
|
|
}
|
|
|
|
//
|
|
// Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment.
|
|
// In this case, we will dropt it.
|
|
//
|
|
if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag));
|
|
goto done; // give up this frame
|
|
}
|
|
|
|
pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket);
|
|
|
|
// concatenate this fragment into the re-assembly buffer
|
|
NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize);
|
|
pAd->FragFrame.RxSize += DataSize;
|
|
pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number
|
|
|
|
// Last fragment
|
|
if (pHeader->FC.MoreFrag == FALSE)
|
|
{
|
|
bReassDone = TRUE;
|
|
}
|
|
}
|
|
|
|
done:
|
|
// always release rx fragmented packet
|
|
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
|
|
|
|
// return defragmented packet if packet is reassembled completely
|
|
// otherwise return NULL
|
|
if (bReassDone)
|
|
{
|
|
PNDIS_PACKET pNewFragPacket;
|
|
|
|
// allocate a new packet buffer for fragment
|
|
pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
|
|
if (pNewFragPacket)
|
|
{
|
|
// update RxBlk
|
|
pRetPacket = pAd->FragFrame.pFragPacket;
|
|
pAd->FragFrame.pFragPacket = pNewFragPacket;
|
|
pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket);
|
|
pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom;
|
|
pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom;
|
|
pRxBlk->pRxPacket = pRetPacket;
|
|
}
|
|
else
|
|
{
|
|
RESET_FRAGFRAME(pAd->FragFrame);
|
|
}
|
|
}
|
|
|
|
return pRetPacket;
|
|
}
|
|
|
|
|
|
VOID Indicate_AMSDU_Packet(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RX_BLK *pRxBlk,
|
|
IN UCHAR FromWhichBSSID)
|
|
{
|
|
UINT nMSDU;
|
|
|
|
update_os_packet_info(pAd, pRxBlk, FromWhichBSSID);
|
|
RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID);
|
|
nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize);
|
|
}
|
|
|
|
VOID Indicate_EAPOL_Packet(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN RX_BLK *pRxBlk,
|
|
IN UCHAR FromWhichBSSID)
|
|
{
|
|
MAC_TABLE_ENTRY *pEntry = NULL;
|
|
|
|
{
|
|
pEntry = &pAd->MacTab.Content[BSSID_WCID];
|
|
STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID);
|
|
return;
|
|
}
|
|
|
|
if (pEntry == NULL)
|
|
{
|
|
DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n"));
|
|
// release packet
|
|
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#define BCN_TBTT_OFFSET 64 //defer 64 us
|
|
VOID ReSyncBeaconTime(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
|
|
UINT32 Offset;
|
|
|
|
|
|
Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET);
|
|
|
|
pAd->TbttTickCount++;
|
|
|
|
//
|
|
// The updated BeaconInterval Value will affect Beacon Interval after two TBTT
|
|
// beacasue the original BeaconInterval had been loaded into next TBTT_TIMER
|
|
//
|
|
if (Offset == (BCN_TBTT_OFFSET-2))
|
|
{
|
|
BCN_TIME_CFG_STRUC csr;
|
|
RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word);
|
|
csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us
|
|
RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word);
|
|
}
|
|
else
|
|
{
|
|
if (Offset == (BCN_TBTT_OFFSET-1))
|
|
{
|
|
BCN_TIME_CFG_STRUC csr;
|
|
|
|
RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word);
|
|
csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU
|
|
RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word);
|
|
}
|
|
}
|
|
}
|
|
|