mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
324148788b
Drop cast on the result of kmalloc and similar functions. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ type T; @@ - (T *) (\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)) // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2361 lines
68 KiB
C
2361 lines
68 KiB
C
/*
|
|
*************************************************************************
|
|
* Ralink Tech Inc.
|
|
* 5F., No.36, Taiyuan St., Jhubei City,
|
|
* Hsinchu County 302,
|
|
* Taiwan, R.O.C.
|
|
*
|
|
* (c) Copyright 2002-2007, Ralink Technology, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
*************************************************************************
|
|
*/
|
|
|
|
#include "../rt_config.h"
|
|
|
|
u8 SNAP_802_1H[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
|
u8 SNAP_BRIDGE_TUNNEL[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
|
|
|
/* Add Cisco Aironet SNAP heade for CCX2 support */
|
|
u8 SNAP_AIRONET[] = { 0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00 };
|
|
u8 CKIP_LLC_SNAP[] = { 0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02 };
|
|
u8 EAPOL_LLC_SNAP[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
|
|
u8 EAPOL[] = { 0x88, 0x8e };
|
|
u8 TPID[] = { 0x81, 0x00 }; /* VLAN related */
|
|
|
|
u8 IPX[] = { 0x81, 0x37 };
|
|
u8 APPLE_TALK[] = { 0x80, 0xf3 };
|
|
|
|
u8 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 */
|
|
|
|
u8 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 */
|
|
};
|
|
|
|
u8 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 */
|
|
};
|
|
|
|
u8 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" };
|
|
|
|
u8 default_cwmin[] =
|
|
{ CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS - 1, CW_MIN_IN_BITS - 2 };
|
|
/*u8 default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; */
|
|
u8 default_sta_aifsn[] = { 3, 7, 2, 2 };
|
|
|
|
u8 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:
|
|
|
|
========================================================================
|
|
*/
|
|
int MiniportMMRequest(struct rt_rtmp_adapter *pAd,
|
|
u8 QueIdx, u8 *pData, u32 Length)
|
|
{
|
|
void *pPacket;
|
|
int Status = NDIS_STATUS_SUCCESS;
|
|
unsigned long FreeNum;
|
|
u8 rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; /*RTMP_HW_HDR_LEN]; */
|
|
#ifdef RTMP_MAC_PCI
|
|
unsigned long IrqFlags = 0;
|
|
u8 IrqState;
|
|
#endif /* RTMP_MAC_PCI // */
|
|
BOOLEAN bUseDataQ = FALSE;
|
|
int retryCnt = 0;
|
|
|
|
ASSERT(Length <= MGMT_DMA_BUFFER_SIZE);
|
|
|
|
if ((QueIdx & MGMT_USE_QUEUE_FLAG) == MGMT_USE_QUEUE_FLAG) {
|
|
bUseDataQ = TRUE;
|
|
QueIdx &= (~MGMT_USE_QUEUE_FLAG);
|
|
}
|
|
#ifdef RTMP_MAC_PCI
|
|
/* 2860C use Tx Ring */
|
|
IrqState = pAd->irq_disabled;
|
|
if (pAd->MACVersion == 0x28600100) {
|
|
QueIdx = (bUseDataQ == TRUE ? QueIdx : 3);
|
|
bUseDataQ = TRUE;
|
|
}
|
|
if (bUseDataQ && (!IrqState))
|
|
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
|
|
#endif /* RTMP_MAC_PCI // */
|
|
|
|
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. */
|
|
#ifdef RTMP_MAC_PCI
|
|
if (bUseDataQ) {
|
|
retryCnt = MAX_DATAMM_RETRY;
|
|
/* free Tx(QueIdx) resources */
|
|
RTMPFreeTXDUponTxDmaDone(pAd, QueIdx);
|
|
FreeNum = GET_TXRING_FREENO(pAd, QueIdx);
|
|
} else
|
|
#endif /* RTMP_MAC_PCI // */
|
|
{
|
|
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,
|
|
(u8 *)& 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; */
|
|
|
|
#ifdef RTMP_MAC_PCI
|
|
if (bUseDataQ) {
|
|
Status =
|
|
MlmeDataHardTransmit(pAd, QueIdx, pPacket);
|
|
retryCnt--;
|
|
} else
|
|
#endif /* RTMP_MAC_PCI // */
|
|
Status = MlmeHardTransmit(pAd, QueIdx, pPacket);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
retryCnt = 0;
|
|
else
|
|
RTMPFreeNdisPacket(pAd, pPacket);
|
|
} else {
|
|
pAd->RalinkCounters.MgmtRingFullCount++;
|
|
#ifdef RTMP_MAC_PCI
|
|
if (bUseDataQ) {
|
|
retryCnt--;
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("retryCnt %d\n", retryCnt));
|
|
if (retryCnt == 0) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n",
|
|
QueIdx,
|
|
pAd->RalinkCounters.
|
|
MgmtRingFullCount));
|
|
}
|
|
}
|
|
#endif /* RTMP_MAC_PCI // */
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n",
|
|
QueIdx,
|
|
pAd->RalinkCounters.MgmtRingFullCount));
|
|
}
|
|
} while (retryCnt > 0);
|
|
|
|
#ifdef RTMP_MAC_PCI
|
|
if (bUseDataQ && (!IrqState))
|
|
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
|
|
#endif /* RTMP_MAC_PCI // */
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
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:
|
|
|
|
========================================================================
|
|
*/
|
|
int MlmeHardTransmit(struct rt_rtmp_adapter *pAd,
|
|
u8 QueIdx, void *pPacket)
|
|
{
|
|
struct rt_packet_info PacketInfo;
|
|
u8 *pSrcBufVA;
|
|
u32 SrcBufLen;
|
|
struct rt_header_802_11 * pHeader_802_11;
|
|
|
|
if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
|
|
) {
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
|
|
if (pSrcBufVA == NULL)
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
pHeader_802_11 = (struct rt_header_802_11 *) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE);
|
|
|
|
#ifdef RTMP_MAC_PCI
|
|
if (pAd->MACVersion == 0x28600100)
|
|
return MlmeHardTransmitTxRing(pAd, QueIdx, pPacket);
|
|
else
|
|
#endif /* RTMP_MAC_PCI // */
|
|
return MlmeHardTransmitMgmtRing(pAd, QueIdx, pPacket);
|
|
|
|
}
|
|
|
|
int MlmeHardTransmitMgmtRing(struct rt_rtmp_adapter *pAd,
|
|
u8 QueIdx, void *pPacket)
|
|
{
|
|
struct rt_packet_info PacketInfo;
|
|
u8 *pSrcBufVA;
|
|
u32 SrcBufLen;
|
|
struct rt_header_802_11 * pHeader_802_11;
|
|
BOOLEAN bAckRequired, bInsertTimestamp;
|
|
u8 MlmeRate;
|
|
struct rt_txwi * pFirstTxWI;
|
|
struct rt_mac_table_entry *pMacEntry = NULL;
|
|
u8 PID;
|
|
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
|
|
|
|
/* Make sure MGMT ring resource won't be used by other threads */
|
|
RTMP_SEM_LOCK(&pAd->MgmtRingLock);
|
|
if (pSrcBufVA == NULL) {
|
|
/* The buffer shouldn't be 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 = (struct rt_txwi *) (pSrcBufVA + TXINFO_SIZE);
|
|
pHeader_802_11 = (struct rt_header_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 = PWR_ACTIVE; /* (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 ((pHeader_802_11->FC.SubType == SUBTYPE_ACTION) ||
|
|
((pHeader_802_11->FC.Type == BTYPE_DATA) &&
|
|
((pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL) ||
|
|
(pHeader_802_11->FC.SubType == SUBTYPE_NULL_FUNC)))) {
|
|
if (pAd->StaCfg.Psm == PWR_SAVE)
|
|
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
|
|
else
|
|
pHeader_802_11->FC.PwrMgmt =
|
|
pAd->CommonCfg.bAPSDForcePowerSave;
|
|
}
|
|
}
|
|
|
|
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) */
|
|
{
|
|
/*pAd->Sequence++; */
|
|
/*pHeader_802_11->Sequence = pAd->Sequence; */
|
|
|
|
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)
|
|
&& (pHeader_802_11->FC.Type == BTYPE_MGMT)) {
|
|
bInsertTimestamp = TRUE;
|
|
bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Response */
|
|
} else
|
|
if ((pHeader_802_11->FC.SubType ==
|
|
SUBTYPE_PROBE_REQ)
|
|
&& (pHeader_802_11->FC.Type == BTYPE_MGMT)) {
|
|
bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Request */
|
|
}
|
|
}
|
|
}
|
|
|
|
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"));
|
|
/* if (!IrqState) */
|
|
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 physical 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 */
|
|
/* pAd->CommonCfg.MlmeTransmit.field.MODE = 1; */
|
|
|
|
/* management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. */
|
|
PID = PID_MGMT;
|
|
|
|
if (pMacEntry == NULL) {
|
|
RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp,
|
|
FALSE, bAckRequired, FALSE, 0, RESERVED_WCID,
|
|
(SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID, 0,
|
|
(u8)pAd->CommonCfg.MlmeTransmit.field.MCS,
|
|
IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit);
|
|
} else {
|
|
/* dont use low rate to send QoS Null data frame */
|
|
RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE,
|
|
bInsertTimestamp, FALSE, bAckRequired, FALSE,
|
|
0, pMacEntry->Aid,
|
|
(SrcBufLen - TXINFO_SIZE - TXWI_SIZE),
|
|
pMacEntry->MaxHTPhyMode.field.MCS, 0,
|
|
(u8)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 */
|
|
/* if (!IrqState) */
|
|
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 u8 TxPktClassification(struct rt_rtmp_adapter *pAd, void *pPacket)
|
|
{
|
|
u8 TxFrameType = TX_UNKOWN_FRAME;
|
|
u8 Wcid;
|
|
struct rt_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;
|
|
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(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk)
|
|
{
|
|
struct rt_packet_info PacketInfo;
|
|
void *pPacket;
|
|
struct rt_mac_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;
|
|
{
|
|
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 ((pAd->OpMode == OPMODE_STA) &&
|
|
(ADHOC_ON(pAd)) &&
|
|
(RX_FILTER_TEST_FLAG(pAd, fRX_FILTER_ACCEPT_PROMISCUOUS))) {
|
|
if (pAd->CommonCfg.PSPXlink)
|
|
TX_BLK_CLEAR_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 (pAd->StaCfg.bAutoTxRateSwitch) */
|
|
/* TX_BLK_SET_FLAG(pTxBlk, fTX_AutoRateSwitch); */
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
} else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) {
|
|
TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag);
|
|
}
|
|
|
|
pMacEntry->DebugTxCount++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN CanDoAggregateTransmit(struct rt_rtmp_adapter *pAd,
|
|
char * pPacket, struct rt_tx_blk *pTxBlk)
|
|
{
|
|
|
|
/*DBGPRINT(RT_DEBUG_TRACE, ("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(struct rt_rtmp_adapter *pAd, IN BOOLEAN bIntContext, u8 QIdx, /* BulkOutPipeId */
|
|
u8 Max_Tx_Packets)
|
|
{
|
|
struct rt_queue_entry *pEntry = NULL;
|
|
void *pPacket;
|
|
int Status = NDIS_STATUS_SUCCESS;
|
|
u8 Count = 0;
|
|
struct rt_queue_header *pQueue;
|
|
unsigned long FreeNumber[NUM_OF_TX_RING];
|
|
u8 QueIdx, sQIdx, eQIdx;
|
|
unsigned long IrqFlags = 0;
|
|
BOOLEAN hasTxDesc = FALSE;
|
|
struct rt_tx_blk TxBlk;
|
|
struct rt_tx_blk *pTxBlk;
|
|
|
|
if (QIdx == NUM_OF_TX_RING) {
|
|
sQIdx = 0;
|
|
eQIdx = 3; /* 4 ACs, start from 0. */
|
|
} else {
|
|
sQIdx = eQIdx = QIdx;
|
|
}
|
|
|
|
for (QueIdx = sQIdx; QueIdx <= eQIdx; QueIdx++) {
|
|
Count = 0;
|
|
|
|
RTMP_START_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
|
|
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)))) {
|
|
RTMP_STOP_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
return;
|
|
}
|
|
|
|
if (Count >= Max_Tx_Packets)
|
|
break;
|
|
|
|
DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
if (&pAd->TxSwQueue[QueIdx] == NULL) {
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext,
|
|
IrqFlags);
|
|
break;
|
|
}
|
|
#ifdef RTMP_MAC_PCI
|
|
FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx);
|
|
|
|
if (FreeNumber[QueIdx] <= 5) {
|
|
/* free Tx(QueIdx) resources */
|
|
RTMPFreeTXDUponTxDmaDone(pAd, QueIdx);
|
|
FreeNumber[QueIdx] =
|
|
GET_TXRING_FREENO(pAd, QueIdx);
|
|
}
|
|
#endif /* RTMP_MAC_PCI // */
|
|
|
|
/* probe the Queue Head */
|
|
pQueue = &pAd->TxSwQueue[QueIdx];
|
|
pEntry = pQueue->Head;
|
|
if (pEntry == NULL) {
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext,
|
|
IrqFlags);
|
|
break;
|
|
}
|
|
|
|
pTxBlk = &TxBlk;
|
|
NdisZeroMemory((u8 *)pTxBlk, sizeof(struct rt_tx_blk));
|
|
/*InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. */
|
|
pTxBlk->QueIdx = QueIdx;
|
|
|
|
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
|
|
|
|
/* Early check to make sure we have enoguh Tx Resource. */
|
|
hasTxDesc =
|
|
RTMP_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 {
|
|
pEntry = pQueue->Head;
|
|
if (pEntry == NULL)
|
|
break;
|
|
|
|
/* For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. */
|
|
pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
|
|
FreeNumber[QueIdx] =
|
|
GET_TXRING_FREENO(pAd, QueIdx);
|
|
hasTxDesc =
|
|
RTMP_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_PACKET(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 RTMP_MAC_USB
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
#endif /* RTMP_MAC_USB // */
|
|
Count += pTxBlk->TxPacketList.Number;
|
|
|
|
/* Do HardTransmit now. */
|
|
Status = STAHardTransmit(pAd, pTxBlk, QueIdx);
|
|
|
|
#ifdef RTMP_MAC_PCI
|
|
DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags);
|
|
/* static rate also need NICUpdateFifoStaCounters() function. */
|
|
/*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */
|
|
NICUpdateFifoStaCounters(pAd);
|
|
#endif /* RTMP_MAC_PCI // */
|
|
|
|
}
|
|
|
|
RTMP_STOP_DEQUEUE(pAd, QueIdx, IrqFlags);
|
|
|
|
#ifdef RTMP_MAC_USB
|
|
if (!hasTxDesc)
|
|
RTUSBKickBulkOut(pAd);
|
|
#endif /* RTMP_MAC_USB // */
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
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:
|
|
|
|
========================================================================
|
|
*/
|
|
u16 RTMPCalcDuration(struct rt_rtmp_adapter *pAd, u8 Rate, unsigned long Size)
|
|
{
|
|
unsigned long 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 += (u16)((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 * (u16)((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 (u16)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(struct rt_rtmp_adapter *pAd, struct rt_txwi * pOutTxWI, IN BOOLEAN FRAG, IN BOOLEAN CFACK, IN BOOLEAN InsTimestamp, IN BOOLEAN AMPDU, IN BOOLEAN Ack, IN BOOLEAN NSeq, /* HW new a sequence. */
|
|
u8 BASize,
|
|
u8 WCID,
|
|
unsigned long Length,
|
|
u8 PID,
|
|
u8 TID,
|
|
u8 TxRate,
|
|
u8 Txopmode,
|
|
IN BOOLEAN CfAck, IN HTTRANSMIT_SETTING * pTransmit)
|
|
{
|
|
struct rt_mac_table_entry *pMac = NULL;
|
|
struct rt_txwi TxWI;
|
|
struct rt_txwi * 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 (pAd->MACVersion == 0x28720200) {
|
|
if (BASize > 13)
|
|
BASize = 13;
|
|
} else {
|
|
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(struct rt_txwi));
|
|
}
|
|
|
|
void RTMPWriteTxWI_Data(struct rt_rtmp_adapter *pAd,
|
|
struct rt_txwi * pTxWI, struct rt_tx_blk *pTxBlk)
|
|
{
|
|
HTTRANSMIT_SETTING *pTransmit;
|
|
struct rt_mac_table_entry *pMacEntry;
|
|
u8 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)) {
|
|
u8 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;
|
|
}
|
|
}
|
|
|
|
/* for rate adapation */
|
|
pTxWI->PacketId = pTxWI->MCS;
|
|
}
|
|
|
|
void RTMPWriteTxWI_Cache(struct rt_rtmp_adapter *pAd,
|
|
struct rt_txwi * pTxWI, struct rt_tx_blk *pTxBlk)
|
|
{
|
|
PHTTRANSMIT_SETTING /*pTxHTPhyMode, */ pTransmit;
|
|
struct rt_mac_table_entry *pMacEntry;
|
|
|
|
/* */
|
|
/* update TXWI */
|
|
/* */
|
|
pMacEntry = pTxBlk->pMacEntry;
|
|
pTransmit = pTxBlk->pTransmit;
|
|
|
|
/*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */
|
|
/*if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pMacEntry)) */
|
|
/*if (TX_BLK_TEST_FLAG(pTxBlk, fTX_AutoRateSwitch)) */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen;
|
|
|
|
}
|
|
|
|
/* 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(struct rt_rtmp_adapter *pAd,
|
|
u8 *pPrevAddr1, u8 *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(struct rt_rtmp_adapter *pAd,
|
|
unsigned long TxRate, struct rt_mac_table_entry *pMacEntry)
|
|
{
|
|
unsigned long 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:
|
|
|
|
========================================================================
|
|
*/
|
|
struct rt_queue_header *RTMPCheckTxSwQueue(struct rt_rtmp_adapter *pAd, u8 *pQueIdx)
|
|
{
|
|
|
|
unsigned long Number;
|
|
/* 2004-11-15 to be removed. test aggregation only */
|
|
/* if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) */
|
|
/* return NULL; */
|
|
|
|
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;
|
|
|
|
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]);
|
|
}
|
|
/* 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(struct rt_rtmp_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) */
|
|
/*RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); */
|
|
RTMPSetAGCInitValue(pAd, BW_20);
|
|
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
|
|
/*RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings */
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Resume MSDU transmission
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void RTMPResumeMsduTransmission(struct rt_rtmp_adapter *pAd)
|
|
{
|
|
/* u8 IrqState; */
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("SCAN done, resume MSDU transmission ...\n"));
|
|
|
|
/* 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"));
|
|
}
|
|
|
|
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66,
|
|
pAd->BbpTuning.R66CurrentValue);
|
|
|
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
|
|
/* sample, for IRQ LOCK to SEM LOCK */
|
|
/* IrqState = pAd->irq_disabled; */
|
|
/* if (IrqState) */
|
|
/* RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); */
|
|
/* else */
|
|
RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS);
|
|
}
|
|
|
|
u32 deaggregate_AMSDU_announce(struct rt_rtmp_adapter *pAd,
|
|
void *pPacket,
|
|
u8 *pData, unsigned long DataSize)
|
|
{
|
|
u16 PayloadSize;
|
|
u16 SubFrameSize;
|
|
struct rt_header_802_3 * pAMSDUsubheader;
|
|
u32 nMSDU;
|
|
u8 Header802_3[14];
|
|
|
|
u8 *pPayload, *pDA, *pSA, *pRemovedLLCSNAP;
|
|
void *pClonePacket;
|
|
|
|
nMSDU = 0;
|
|
|
|
while (DataSize > LENGTH_802_3) {
|
|
|
|
nMSDU++;
|
|
|
|
/*hex_dump("subheader", pData, 64); */
|
|
pAMSDUsubheader = (struct rt_header_802_3 *) pData;
|
|
/*pData += LENGTH_802_3; */
|
|
PayloadSize =
|
|
pAMSDUsubheader->Octet[1] +
|
|
(pAMSDUsubheader->Octet[0] << 8);
|
|
SubFrameSize = PayloadSize + LENGTH_802_3;
|
|
|
|
if ((DataSize < SubFrameSize) || (PayloadSize > 1518)) {
|
|
break;
|
|
}
|
|
/*DBGPRINT(RT_DEBUG_TRACE,("%d subframe: Size = %d\n", nMSDU, PayloadSize)); */
|
|
|
|
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 */
|
|
struct rt_mlme_queue_elem *Elem =
|
|
kmalloc(sizeof(struct rt_mlme_queue_elem),
|
|
MEM_ALLOC_FLAG);
|
|
if (Elem != NULL) {
|
|
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); */
|
|
REPORT_MGMT_FRAME_TO_MLME(pAd, BSSID_WCID,
|
|
Elem->Msg,
|
|
Elem->MsgLen, 0, 0, 0,
|
|
0);
|
|
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;
|
|
}
|
|
|
|
u32 BA_Reorder_AMSDU_Annnounce(struct rt_rtmp_adapter *pAd, void *pPacket)
|
|
{
|
|
u8 *pData;
|
|
u16 DataSize;
|
|
u32 nMSDU = 0;
|
|
|
|
pData = (u8 *)GET_OS_PKT_DATAPTR(pPacket);
|
|
DataSize = (u16)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
|
|
==========================================================================
|
|
*/
|
|
struct rt_mac_table_entry *MacTableLookup(struct rt_rtmp_adapter *pAd, u8 *pAddr)
|
|
{
|
|
unsigned long HashIdx;
|
|
struct rt_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;
|
|
}
|
|
|
|
struct rt_mac_table_entry *MacTableInsertEntry(struct rt_rtmp_adapter *pAd,
|
|
u8 *pAddr,
|
|
u8 apidx, IN BOOLEAN CleanAll)
|
|
{
|
|
u8 HashIdx;
|
|
int i, FirstWcid;
|
|
struct rt_mac_table_entry *pEntry = NULL, *pCurrEntry;
|
|
/* u16 offset; */
|
|
/* unsigned long addr; */
|
|
|
|
/* 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(struct rt_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;
|
|
#ifdef RTMP_MAC_PCI
|
|
AsicRemovePairwiseKeyEntry(pAd,
|
|
pEntry->
|
|
apidx,
|
|
(u8)i);
|
|
#endif /* RTMP_MAC_PCI // */
|
|
}
|
|
}
|
|
|
|
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 = (u16)i; /*0; */
|
|
pEntry->CapabilityInfo = 0;
|
|
pEntry->PsMode = PWR_ACTIVE;
|
|
pEntry->PsQIdleCount = 0;
|
|
pEntry->NoDataIdleCount = 0;
|
|
pEntry->AssocDeadLine = MAC_TABLE_ASSOC_TIMEOUT;
|
|
pEntry->ContinueTxFailCnt = 0;
|
|
InitializeQueueHeader(&pEntry->PsQueue);
|
|
|
|
pAd->MacTab.Size++;
|
|
/* Add this entry into ASIC RX WCID search table */
|
|
RTMP_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(struct rt_rtmp_adapter *pAd,
|
|
u16 wcid, u8 *pAddr)
|
|
{
|
|
u16 HashIdx;
|
|
struct rt_mac_table_entry *pEntry, *pPrevEntry, *pProbeEntry;
|
|
BOOLEAN Cancelled;
|
|
/*u16 offset; // unused variable */
|
|
/*u8 j; // unused variable */
|
|
|
|
if (wcid >= MAX_LEN_OF_MAC_TABLE)
|
|
return FALSE;
|
|
|
|
NdisAcquireSpinLock(&pAd->MacTabLock);
|
|
|
|
HashIdx = MAC_ADDR_HASH_INDEX(pAddr);
|
|
/*pEntry = pAd->MacTab.Hash[HashIdx]; */
|
|
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 */
|
|
RTMP_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);
|
|
|
|
RTMP_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(struct rt_mac_table_entry));
|
|
pAd->MacTab.Size--;
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("MacTableDeleteEntry1 - Total= %d\n",
|
|
pAd->MacTab.Size));
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_OFF,
|
|
("\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;
|
|
RTMP_UPDATE_PROTECT(pAd); /* edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet */
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
This routine reset the entire MAC table. All packets pending in
|
|
the power-saving queues are freed here.
|
|
==========================================================================
|
|
*/
|
|
void MacTableReset(struct rt_rtmp_adapter *pAd)
|
|
{
|
|
int i;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n"));
|
|
/*NdisAcquireSpinLock(&pAd->MacTabLock); */
|
|
|
|
for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
|
|
#ifdef RTMP_MAC_PCI
|
|
RTMP_STA_ENTRY_MAC_RESET(pAd, i);
|
|
#endif /* RTMP_MAC_PCI // */
|
|
if (pAd->MacTab.Content[i].ValidAsCLI == TRUE) {
|
|
|
|
/* free resources of BA */
|
|
BASessionTearDownALL(pAd, i);
|
|
|
|
pAd->MacTab.Content[i].ValidAsCLI = FALSE;
|
|
|
|
#ifdef RTMP_MAC_USB
|
|
NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6);
|
|
RTMP_STA_ENTRY_MAC_RESET(pAd, i);
|
|
#endif /* RTMP_MAC_USB // */
|
|
|
|
/*AsicDelWcidTab(pAd, i); */
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
|
|
IRQL = DISPATCH_LEVEL
|
|
|
|
==========================================================================
|
|
*/
|
|
void AssocParmFill(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mlme_assoc_req *AssocReq,
|
|
u8 *pAddr,
|
|
u16 CapabilityInfo,
|
|
unsigned long Timeout, u16 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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mlme_disassoc_req *DisassocReq,
|
|
u8 *pAddr, u16 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(struct rt_rtmp_adapter *pAd, void *pPacket)
|
|
{
|
|
struct rt_packet_info PacketInfo;
|
|
unsigned long NumberOfBytesRead = 0;
|
|
unsigned long CurrentOffset = 0;
|
|
void *pVirtualAddress = NULL;
|
|
u32 NdisBufferLength;
|
|
u8 *pSrc;
|
|
u16 Protocol;
|
|
u8 ByteOffset36 = 0;
|
|
u8 ByteOffset38 = 0;
|
|
BOOLEAN ReadFirstParm = TRUE;
|
|
|
|
RTMP_QueryPacketInfo(pPacket, &PacketInfo, (u8 **) & pVirtualAddress,
|
|
&NdisBufferLength);
|
|
|
|
NumberOfBytesRead += NdisBufferLength;
|
|
pSrc = (u8 *)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(struct rt_rtmp_adapter *pAd, void *pPacket)
|
|
{
|
|
u16 TypeLen;
|
|
u8 Byte0, Byte1;
|
|
u8 *pSrcBuf;
|
|
u32 pktLen;
|
|
u16 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((char *)pSrcBuf, 6,
|
|
&Byte0, &Byte1);
|
|
RTMP_SET_PACKET_LLCSNAP(pPacket, 1);
|
|
TypeLen = (u16)((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((char *)pSrcBuf, 2, &Byte0,
|
|
&Byte1);
|
|
TypeLen = (u16)((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(get_unaligned
|
|
((u16 *)(pSrcBuf)));
|
|
dstPort =
|
|
OS_NTOHS(get_unaligned
|
|
((u16 *)(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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rssi_sample *pRssi, struct rt_rxwi * 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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
|
|
{
|
|
void *pRxPacket = pRxBlk->pRxPacket;
|
|
u8 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 RTMP_MAC_USB
|
|
if (pAd->CommonCfg.bDisableReordering == 0) {
|
|
struct rt_ba_rec_entry *pBAEntry;
|
|
unsigned long Now32;
|
|
u8 Wcid = pRxBlk->pRxWI->WirelessCliID;
|
|
u8 TID = pRxBlk->pRxWI->TID;
|
|
u16 Idx;
|
|
|
|
#define REORDERING_PACKET_TIMEOUT ((100 * OS_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)))
|
|
) {
|
|
DBGPRINT(RT_DEBUG_OFF,
|
|
("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 /* RTMP_MAC_USB // */
|
|
|
|
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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rx_blk *pRxBlk, u8 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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry,
|
|
struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
|
|
{
|
|
u8 Header802_3[LENGTH_802_3];
|
|
u16 Msdu2Size;
|
|
u16 Payload1Size, Payload2Size;
|
|
u8 *pData2;
|
|
void *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; \
|
|
}
|
|
|
|
void *RTMPDeFragmentDataFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk)
|
|
{
|
|
struct rt_header_802_11 * pHeader = pRxBlk->pHeader;
|
|
void *pRxPacket = pRxBlk->pRxPacket;
|
|
u8 *pData = pRxBlk->pData;
|
|
u16 DataSize = pRxBlk->DataSize;
|
|
void *pRetPacket = NULL;
|
|
u8 *pFragBuffer = NULL;
|
|
BOOLEAN bReassDone = FALSE;
|
|
u8 HeaderRoom = 0;
|
|
|
|
ASSERT(pHeader);
|
|
|
|
HeaderRoom = pData - (u8 *) 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) {
|
|
void *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 =
|
|
(struct rt_header_802_11 *) GET_OS_PKT_DATAPTR(pRetPacket);
|
|
pRxBlk->pData = (u8 *) pRxBlk->pHeader + HeaderRoom;
|
|
pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom;
|
|
pRxBlk->pRxPacket = pRetPacket;
|
|
} else {
|
|
RESET_FRAGFRAME(pAd->FragFrame);
|
|
}
|
|
}
|
|
|
|
return pRetPacket;
|
|
}
|
|
|
|
void Indicate_AMSDU_Packet(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
|
|
{
|
|
u32 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(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
|
|
{
|
|
struct rt_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(struct rt_rtmp_adapter *pAd)
|
|
{
|
|
|
|
u32 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);
|
|
}
|
|
}
|
|
}
|