blob: 9fc34a8f218022dc651a984d1c323bc1836e484c [file] [log] [blame]
/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************
Module Name:
mlme.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John Chang 2004-08-25 Modify from RT2500 code base
John Chang 2004-09-06 modified for RT2600
*/
#include "../rt_config.h"
#include <stdarg.h>
u8 CISCO_OUI[] = { 0x00, 0x40, 0x96 };
u8 WPA_OUI[] = { 0x00, 0x50, 0xf2, 0x01 };
u8 RSN_OUI[] = { 0x00, 0x0f, 0xac };
u8 WME_INFO_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01 };
u8 WME_PARM_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01 };
u8 Ccx2QosInfo[] = { 0x00, 0x40, 0x96, 0x04 };
u8 RALINK_OUI[] = { 0x00, 0x0c, 0x43 };
u8 BROADCOM_OUI[] = { 0x00, 0x90, 0x4c };
u8 WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
u8 PRE_N_HT_OUI[] = { 0x00, 0x90, 0x4c };
u8 RateSwitchTable[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x11, 0x00, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 35, 45,
0x03, 0x00, 3, 20, 45,
0x04, 0x21, 0, 30, 50,
0x05, 0x21, 1, 20, 50,
0x06, 0x21, 2, 20, 50,
0x07, 0x21, 3, 15, 50,
0x08, 0x21, 4, 15, 30,
0x09, 0x21, 5, 10, 25,
0x0a, 0x21, 6, 8, 25,
0x0b, 0x21, 7, 8, 25,
0x0c, 0x20, 12, 15, 30,
0x0d, 0x20, 13, 8, 20,
0x0e, 0x20, 14, 8, 20,
0x0f, 0x20, 15, 8, 25,
0x10, 0x22, 15, 8, 25,
0x11, 0x00, 0, 0, 0,
0x12, 0x00, 0, 0, 0,
0x13, 0x00, 0, 0, 0,
0x14, 0x00, 0, 0, 0,
0x15, 0x00, 0, 0, 0,
0x16, 0x00, 0, 0, 0,
0x17, 0x00, 0, 0, 0,
0x18, 0x00, 0, 0, 0,
0x19, 0x00, 0, 0, 0,
0x1a, 0x00, 0, 0, 0,
0x1b, 0x00, 0, 0, 0,
0x1c, 0x00, 0, 0, 0,
0x1d, 0x00, 0, 0, 0,
0x1e, 0x00, 0, 0, 0,
0x1f, 0x00, 0, 0, 0,
};
u8 RateSwitchTable11B[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x04, 0x03, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 35, 45,
0x03, 0x00, 3, 20, 45,
};
u8 RateSwitchTable11BG[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0a, 0x00, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 35, 45,
0x03, 0x00, 3, 20, 45,
0x04, 0x10, 2, 20, 35,
0x05, 0x10, 3, 16, 35,
0x06, 0x10, 4, 10, 25,
0x07, 0x10, 5, 16, 25,
0x08, 0x10, 6, 10, 25,
0x09, 0x10, 7, 10, 13,
};
u8 RateSwitchTable11G[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x08, 0x00, 0, 0, 0, /* Initial used item after association */
0x00, 0x10, 0, 20, 101,
0x01, 0x10, 1, 20, 35,
0x02, 0x10, 2, 20, 35,
0x03, 0x10, 3, 16, 35,
0x04, 0x10, 4, 10, 25,
0x05, 0x10, 5, 16, 25,
0x06, 0x10, 6, 10, 25,
0x07, 0x10, 7, 10, 13,
};
u8 RateSwitchTable11N1S[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0c, 0x0a, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 25, 45,
0x03, 0x21, 0, 20, 35,
0x04, 0x21, 1, 20, 35,
0x05, 0x21, 2, 20, 35,
0x06, 0x21, 3, 15, 35,
0x07, 0x21, 4, 15, 30,
0x08, 0x21, 5, 10, 25,
0x09, 0x21, 6, 8, 14,
0x0a, 0x21, 7, 8, 14,
0x0b, 0x23, 7, 8, 14,
};
u8 RateSwitchTable11N2S[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0e, 0x0c, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 25, 45,
0x03, 0x21, 0, 20, 35,
0x04, 0x21, 1, 20, 35,
0x05, 0x21, 2, 20, 35,
0x06, 0x21, 3, 15, 35,
0x07, 0x21, 4, 15, 30,
0x08, 0x20, 11, 15, 30,
0x09, 0x20, 12, 15, 30,
0x0a, 0x20, 13, 8, 20,
0x0b, 0x20, 14, 8, 20,
0x0c, 0x20, 15, 8, 25,
0x0d, 0x22, 15, 8, 15,
};
u8 RateSwitchTable11N3S[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0b, 0x00, 0, 0, 0, /* 0x0a, 0x00, 0, 0, 0, // Initial used item after association */
0x00, 0x21, 0, 30, 101,
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 15, 50,
0x04, 0x21, 4, 15, 30,
0x05, 0x20, 11, 15, 30, /* Required by System-Alan @ 20080812 */
0x06, 0x20, 12, 15, 30, /* 0x05, 0x20, 12, 15, 30, */
0x07, 0x20, 13, 8, 20, /* 0x06, 0x20, 13, 8, 20, */
0x08, 0x20, 14, 8, 20, /* 0x07, 0x20, 14, 8, 20, */
0x09, 0x20, 15, 8, 25, /* 0x08, 0x20, 15, 8, 25, */
0x0a, 0x22, 15, 8, 25, /* 0x09, 0x22, 15, 8, 25, */
};
u8 RateSwitchTable11N2SForABand[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
0x00, 0x21, 0, 30, 101,
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 15, 50,
0x04, 0x21, 4, 15, 30,
0x05, 0x21, 5, 15, 30,
0x06, 0x20, 12, 15, 30,
0x07, 0x20, 13, 8, 20,
0x08, 0x20, 14, 8, 20,
0x09, 0x20, 15, 8, 25,
0x0a, 0x22, 15, 8, 25,
};
u8 RateSwitchTable11N3SForABand[] = { /* 3*3 */
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
0x00, 0x21, 0, 30, 101,
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 15, 50,
0x04, 0x21, 4, 15, 30,
0x05, 0x21, 5, 15, 30,
0x06, 0x20, 12, 15, 30,
0x07, 0x20, 13, 8, 20,
0x08, 0x20, 14, 8, 20,
0x09, 0x20, 15, 8, 25,
0x0a, 0x22, 15, 8, 25,
};
u8 RateSwitchTable11BGN1S[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0c, 0x0a, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 25, 45,
0x03, 0x21, 0, 20, 35,
0x04, 0x21, 1, 20, 35,
0x05, 0x21, 2, 20, 35,
0x06, 0x21, 3, 15, 35,
0x07, 0x21, 4, 15, 30,
0x08, 0x21, 5, 10, 25,
0x09, 0x21, 6, 8, 14,
0x0a, 0x21, 7, 8, 14,
0x0b, 0x23, 7, 8, 14,
};
u8 RateSwitchTable11BGN2S[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0e, 0x0c, 0, 0, 0, /* Initial used item after association */
0x00, 0x00, 0, 40, 101,
0x01, 0x00, 1, 40, 50,
0x02, 0x00, 2, 25, 45,
0x03, 0x21, 0, 20, 35,
0x04, 0x21, 1, 20, 35,
0x05, 0x21, 2, 20, 35,
0x06, 0x21, 3, 15, 35,
0x07, 0x21, 4, 15, 30,
0x08, 0x20, 11, 15, 30,
0x09, 0x20, 12, 15, 30,
0x0a, 0x20, 13, 8, 20,
0x0b, 0x20, 14, 8, 20,
0x0c, 0x20, 15, 8, 25,
0x0d, 0x22, 15, 8, 15,
};
u8 RateSwitchTable11BGN3S[] = { /* 3*3 */
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0a, 0x00, 0, 0, 0, /* Initial used item after association */
0x00, 0x21, 0, 30, 101, /*50 */
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 20, 50,
0x04, 0x21, 4, 15, 50,
0x05, 0x20, 20, 15, 30,
0x06, 0x20, 21, 8, 20,
0x07, 0x20, 22, 8, 20,
0x08, 0x20, 23, 8, 25,
0x09, 0x22, 23, 8, 25,
};
u8 RateSwitchTable11BGN2SForABand[] = {
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
0x00, 0x21, 0, 30, 101, /*50 */
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 15, 50,
0x04, 0x21, 4, 15, 30,
0x05, 0x21, 5, 15, 30,
0x06, 0x20, 12, 15, 30,
0x07, 0x20, 13, 8, 20,
0x08, 0x20, 14, 8, 20,
0x09, 0x20, 15, 8, 25,
0x0a, 0x22, 15, 8, 25,
};
u8 RateSwitchTable11BGN3SForABand[] = { /* 3*3 */
/* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
0x0c, 0x09, 0, 0, 0, /* Initial used item after association */
0x00, 0x21, 0, 30, 101, /*50 */
0x01, 0x21, 1, 20, 50,
0x02, 0x21, 2, 20, 50,
0x03, 0x21, 3, 15, 50,
0x04, 0x21, 4, 15, 30,
0x05, 0x21, 5, 15, 30,
0x06, 0x21, 12, 15, 30,
0x07, 0x20, 20, 15, 30,
0x08, 0x20, 21, 8, 20,
0x09, 0x20, 22, 8, 20,
0x0a, 0x20, 23, 8, 25,
0x0b, 0x22, 23, 8, 25,
};
extern u8 OfdmRateToRxwiMCS[];
/* since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. */
/* otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate */
unsigned long BasicRateMask[12] =
{ 0xfffff001 /* 1-Mbps */ , 0xfffff003 /* 2 Mbps */ , 0xfffff007 /* 5.5 */ ,
0xfffff00f /* 11 */ ,
0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ ,
0xfffff0ff /* 18 */ ,
0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ ,
0xffffffff /* 54 */
};
u8 BROADCAST_ADDR[MAC_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
u8 ZERO_MAC_ADDR[MAC_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than */
/* this value, then it's quaranteed capable of operating in 36 mbps TX rate in */
/* clean environment. */
/* TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 */
char RssiSafeLevelForTxRate[] =
{ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
u8 RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100 };
u16 RateIdTo500Kbps[] =
{ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200 };
u8 SsidIe = IE_SSID;
u8 SupRateIe = IE_SUPP_RATES;
u8 ExtRateIe = IE_EXT_SUPP_RATES;
u8 HtCapIe = IE_HT_CAP;
u8 AddHtInfoIe = IE_ADD_HT;
u8 NewExtChanIe = IE_SECONDARY_CH_OFFSET;
u8 ErpIe = IE_ERP;
u8 DsIe = IE_DS_PARM;
u8 TimIe = IE_TIM;
u8 WpaIe = IE_WPA;
u8 Wpa2Ie = IE_WPA2;
u8 IbssIe = IE_IBSS_PARM;
extern u8 WPA_OUI[];
u8 SES_OUI[] = { 0x00, 0x90, 0x4c };
u8 ZeroSsid[32] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
/*
==========================================================================
Description:
initialize the MLME task and its data structure (queue, spinlock,
timer, state machines).
IRQL = PASSIVE_LEVEL
Return:
always return NDIS_STATUS_SUCCESS
==========================================================================
*/
int MlmeInit(struct rt_rtmp_adapter *pAd)
{
int Status = NDIS_STATUS_SUCCESS;
DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n"));
do {
Status = MlmeQueueInit(&pAd->Mlme.Queue);
if (Status != NDIS_STATUS_SUCCESS)
break;
pAd->Mlme.bRunning = FALSE;
NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
{
BssTableInit(&pAd->ScanTab);
/* init STA state machines */
AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine,
pAd->Mlme.AssocFunc);
AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine,
pAd->Mlme.AuthFunc);
AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine,
pAd->Mlme.AuthRspFunc);
SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine,
pAd->Mlme.SyncFunc);
/* Since we are using switch/case to implement it, the init is different from the above */
/* state machine init */
MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
}
WpaStateMachineInit(pAd, &pAd->Mlme.WpaMachine,
pAd->Mlme.WpaFunc);
ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine,
pAd->Mlme.ActFunc);
/* Init mlme periodic timer */
RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer,
GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE);
/* Set mlme periodic timer */
RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
/* software-based RX Antenna diversity */
RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer,
GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd,
FALSE);
{
#ifdef RTMP_PCI_SUPPORT
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
/* only PCIe cards need these two timers */
RTMPInitTimer(pAd, &pAd->Mlme.PsPollTimer,
GET_TIMER_FUNCTION
(PsPollWakeExec), pAd, FALSE);
RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer,
GET_TIMER_FUNCTION(RadioOnExec),
pAd, FALSE);
}
#endif /* RTMP_PCI_SUPPORT // */
RTMPInitTimer(pAd, &pAd->Mlme.LinkDownTimer,
GET_TIMER_FUNCTION(LinkDownExec), pAd,
FALSE);
#ifdef RTMP_MAC_USB
RTMPInitTimer(pAd, &pAd->Mlme.AutoWakeupTimer,
GET_TIMER_FUNCTION
(RtmpUsbStaAsicForceWakeupTimeout), pAd,
FALSE);
pAd->Mlme.AutoWakeupTimerRunning = FALSE;
#endif /* RTMP_MAC_USB // */
}
} while (FALSE);
DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n"));
return Status;
}
/*
==========================================================================
Description:
main loop of the MLME
Pre:
Mlme has to be initialized, and there are something inside the queue
Note:
This function is invoked from MPSetInformation and MPReceive;
This task guarantee only one MlmeHandler will run.
IRQL = DISPATCH_LEVEL
==========================================================================
*/
void MlmeHandler(struct rt_rtmp_adapter *pAd)
{
struct rt_mlme_queue_elem *Elem = NULL;
/* Only accept MLME and Frame from peer side, no other (control/data) frame should */
/* get into this state machine */
NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
if (pAd->Mlme.bRunning) {
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
return;
} else {
pAd->Mlme.bRunning = TRUE;
}
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) {
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
DBGPRINT(RT_DEBUG_TRACE,
("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n",
pAd->Mlme.Queue.Num));
break;
}
/*From message type, determine which state machine I should drive */
if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
#ifdef RTMP_MAC_USB
if (Elem->MsgType == MT2_RESET_CONF) {
DBGPRINT_RAW(RT_DEBUG_TRACE,
("reset MLME state machine!\n"));
MlmeRestartStateMachine(pAd);
Elem->Occupied = FALSE;
Elem->MsgLen = 0;
continue;
}
#endif /* RTMP_MAC_USB // */
/* if dequeue success */
switch (Elem->Machine) {
/* STA state machines */
case ASSOC_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.
AssocMachine, Elem);
break;
case AUTH_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.
AuthMachine, Elem);
break;
case AUTH_RSP_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.
AuthRspMachine, Elem);
break;
case SYNC_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.
SyncMachine, Elem);
break;
case MLME_CNTL_STATE_MACHINE:
MlmeCntlMachinePerformAction(pAd,
&pAd->Mlme.
CntlMachine, Elem);
break;
case WPA_PSK_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.
WpaPskMachine, Elem);
break;
case ACTION_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.ActMachine,
Elem);
break;
case WPA_STATE_MACHINE:
StateMachinePerformAction(pAd,
&pAd->Mlme.WpaMachine,
Elem);
break;
default:
DBGPRINT(RT_DEBUG_TRACE,
("ERROR: Illegal machine %ld in MlmeHandler()\n",
Elem->Machine));
break;
} /* end of switch */
/* free MLME element */
Elem->Occupied = FALSE;
Elem->MsgLen = 0;
} else {
DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
}
}
NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
pAd->Mlme.bRunning = FALSE;
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
}
/*
==========================================================================
Description:
Destructor of MLME (Destroy queue, state machine, spin lock and timer)
Parameters:
Adapter - NIC Adapter pointer
Post:
The MLME task will no longer work properly
IRQL = PASSIVE_LEVEL
==========================================================================
*/
void MlmeHalt(struct rt_rtmp_adapter *pAd)
{
BOOLEAN Cancelled;
DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n"));
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
/* disable BEACON generation and other BEACON related hardware timers */
AsicDisableSync(pAd);
}
{
/* Cancel pending timers */
RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled);
RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled);
RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled);
RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled);
RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
#ifdef RTMP_MAC_PCI
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
&& (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
}
#endif /* RTMP_MAC_PCI // */
RTMPCancelTimer(&pAd->Mlme.LinkDownTimer, &Cancelled);
#ifdef RTMP_MAC_USB
RTMPCancelTimer(&pAd->Mlme.AutoWakeupTimer, &Cancelled);
#endif /* RTMP_MAC_USB // */
}
RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled);
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
/* Set LED */
RTMPSetLED(pAd, LED_HALT);
RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware is not done it. */
#ifdef RTMP_MAC_USB
{
LED_CFG_STRUC LedCfg;
RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word);
LedCfg.field.LedPolar = 0;
LedCfg.field.RLedMode = 0;
LedCfg.field.GLedMode = 0;
LedCfg.field.YLedMode = 0;
RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word);
}
#endif /* RTMP_MAC_USB // */
if (pChipOps->AsicHaltAction)
pChipOps->AsicHaltAction(pAd);
}
RTMPusecDelay(5000); /* 5 msec to gurantee Ant Diversity timer canceled */
MlmeQueueDestroy(&pAd->Mlme.Queue);
NdisFreeSpinLock(&pAd->Mlme.TaskLock);
DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n"));
}
void MlmeResetRalinkCounters(struct rt_rtmp_adapter *pAd)
{
pAd->RalinkCounters.LastOneSecRxOkDataCnt =
pAd->RalinkCounters.OneSecRxOkDataCnt;
/* clear all OneSecxxx counters. */
pAd->RalinkCounters.OneSecBeaconSentCnt = 0;
pAd->RalinkCounters.OneSecFalseCCACnt = 0;
pAd->RalinkCounters.OneSecRxFcsErrCnt = 0;
pAd->RalinkCounters.OneSecRxOkCnt = 0;
pAd->RalinkCounters.OneSecTxFailCount = 0;
pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0;
pAd->RalinkCounters.OneSecTxRetryOkCount = 0;
pAd->RalinkCounters.OneSecRxOkDataCnt = 0;
pAd->RalinkCounters.OneSecReceivedByteCount = 0;
pAd->RalinkCounters.OneSecTransmittedByteCount = 0;
/* TODO: for debug only. to be removed */
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0;
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0;
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0;
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0;
pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0;
pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0;
pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0;
pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0;
pAd->RalinkCounters.OneSecTxDoneCount = 0;
pAd->RalinkCounters.OneSecRxCount = 0;
pAd->RalinkCounters.OneSecTxAggregationCount = 0;
pAd->RalinkCounters.OneSecRxAggregationCount = 0;
return;
}
/*
==========================================================================
Description:
This routine is executed periodically to -
1. Decide if it's a right time to turn on PwrMgmt bit of all
outgoiing frames
2. Calculate ChannelQuality based on statistics of the last
period, so that TX rate won't toggling very frequently between a
successful TX and a failed TX.
3. If the calculated ChannelQuality indicated current connection not
healthy, then a ROAMing attempt is tried here.
IRQL = DISPATCH_LEVEL
==========================================================================
*/
#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) /* 8 sec */
void MlmePeriodicExec(void *SystemSpecific1,
void *FunctionContext,
void *SystemSpecific2, void *SystemSpecific3)
{
unsigned long TxTotalCnt;
struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
#ifdef RTMP_MAC_PCI
{
/* If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. */
/* Move code to here, because following code will return when radio is off */
if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) ==
0) && (pAd->StaCfg.bHardwareRadio == TRUE)
&& (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
&& (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
/*&&(pAd->bPCIclkOff == FALSE) */
) {
u32 data = 0;
/* Read GPIO pin2 as Hardware controlled radio state */
#ifndef RT3090
RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data);
#endif /* RT3090 // */
/*KH(PCIE PS):Added based on Jane<-- */
#ifdef RT3090
/* Read GPIO pin2 as Hardware controlled radio state */
/* We need to Read GPIO if HW said so no mater what advance power saving */
if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd))
&&
(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))
&& (pAd->StaCfg.PSControl.field.EnablePSinIdle ==
TRUE)) {
/* Want to make sure device goes to L0 state before reading register. */
RTMPPCIeLinkCtrlValueRestore(pAd, 0);
RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
RTMPPCIeLinkCtrlSetting(pAd, 3);
} else
RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
#endif /* RT3090 // */
/*KH(PCIE PS):Added based on Jane--> */
if (data & 0x04) {
pAd->StaCfg.bHwRadio = TRUE;
} else {
pAd->StaCfg.bHwRadio = FALSE;
}
if (pAd->StaCfg.bRadio !=
(pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) {
pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio
&& pAd->StaCfg.bSwRadio);
if (pAd->StaCfg.bRadio == TRUE) {
MlmeRadioOn(pAd);
/* Update extra information */
pAd->ExtraInfo = EXTRA_INFO_CLEAR;
} else {
MlmeRadioOff(pAd);
/* Update extra information */
pAd->ExtraInfo = HW_RADIO_OFF;
}
}
}
}
#endif /* RTMP_MAC_PCI // */
/* Do nothing if the driver is starting halt state. */
/* This might happen when timer already been fired before cancel timer with mlmehalt */
if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS |
fRTMP_ADAPTER_RADIO_OFF |
fRTMP_ADAPTER_RADIO_MEASUREMENT |
fRTMP_ADAPTER_RESET_IN_PROGRESS))))
return;
RTMP_MLME_PRE_SANITY_CHECK(pAd);
{
/* Do nothing if monitor mode is on */
if (MONITOR_ON(pAd))
return;
if (pAd->Mlme.PeriodicRound & 0x1) {
/* This is the fix for wifi 11n extension channel overlapping test case. for 2860D */
if (((pAd->MACVersion & 0xffff) == 0x0101) &&
(STA_TGN_WIFI_ON(pAd)) &&
(pAd->CommonCfg.IOTestParm.bToggle == FALSE))
{
RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf);
pAd->CommonCfg.IOTestParm.bToggle = TRUE;
} else if ((STA_TGN_WIFI_ON(pAd)) &&
((pAd->MACVersion & 0xffff) == 0x0101)) {
RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f);
pAd->CommonCfg.IOTestParm.bToggle = FALSE;
}
}
}
pAd->bUpdateBcnCntDone = FALSE;
/* RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); */
pAd->Mlme.PeriodicRound++;
#ifdef RTMP_MAC_USB
/* execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. */
NICUpdateFifoStaCounters(pAd);
#endif /* RTMP_MAC_USB // */
/* execute every 500ms */
if ((pAd->Mlme.PeriodicRound % 5 == 0)
&& RTMPAutoRateSwitchCheck(pAd)
/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ )
{
/* perform dynamic tx rate switching based on past TX history */
{
if ((OPSTATUS_TEST_FLAG
(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
)
&& (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)))
MlmeDynamicTxRateSwitching(pAd);
}
}
/* Normal 1 second Mlme PeriodicExec. */
if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE == 0) {
pAd->Mlme.OneSecPeriodicRound++;
/*ORIBATimerTimeout(pAd); */
/* Media status changed, report to NDIS */
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) {
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE);
if (OPSTATUS_TEST_FLAG
(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
pAd->IndicateMediaState =
NdisMediaStateConnected;
RTMP_IndicateMediaState(pAd);
} else {
pAd->IndicateMediaState =
NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
}
}
NdisGetSystemUpTime(&pAd->Mlme.Now32);
/* add the most up-to-date h/w raw counters into software variable, so that */
/* the dynamic tuning mechanism below are based on most up-to-date information */
NICUpdateRawCounters(pAd);
#ifdef RTMP_MAC_USB
RTUSBWatchDog(pAd);
#endif /* RTMP_MAC_USB // */
/* Need statistics after read counter. So put after NICUpdateRawCounters */
ORIBATimerTimeout(pAd);
/* if MGMT RING is full more than twice within 1 second, we consider there's */
/* a hardware problem stucking the TX path. In this case, try a hardware reset */
/* to recover the system */
/* if (pAd->RalinkCounters.MgmtRingFullCount >= 2) */
/* RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); */
/* else */
/* pAd->RalinkCounters.MgmtRingFullCount = 0; */
/* The time period for checking antenna is according to traffic */
{
if (pAd->Mlme.bEnableAutoAntennaCheck) {
TxTotalCnt =
pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
/* dynamic adjust antenna evaluation period according to the traffic */
if (TxTotalCnt > 50) {
if (pAd->Mlme.OneSecPeriodicRound %
10 == 0) {
AsicEvaluateRxAnt(pAd);
}
} else {
if (pAd->Mlme.OneSecPeriodicRound % 3 ==
0) {
AsicEvaluateRxAnt(pAd);
}
}
}
}
STAMlmePeriodicExec(pAd);
MlmeResetRalinkCounters(pAd);
{
#ifdef RTMP_MAC_PCI
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)
&& (pAd->bPCIclkOff == FALSE))
#endif /* RTMP_MAC_PCI // */
{
/* When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock */
/* and sending CTS-to-self over and over. */
/* Software Patch Solution: */
/* 1. Polling debug state register 0x10F4 every one second. */
/* 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. */
/* 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. */
u32 MacReg = 0;
RTMP_IO_READ32(pAd, 0x10F4, &MacReg);
if (((MacReg & 0x20000000) && (MacReg & 0x80))
|| ((MacReg & 0x20000000)
&& (MacReg & 0x20))) {
RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1);
RTMPusecDelay(1);
RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC);
DBGPRINT(RT_DEBUG_WARN,
("Warning, MAC specific condition occurs \n"));
}
}
}
RTMP_MLME_HANDLER(pAd);
}
pAd->bUpdateBcnCntDone = FALSE;
}
/*
==========================================================================
Validate SSID for connection try and rescan purpose
Valid SSID will have visible chars only.
The valid length is from 0 to 32.
IRQL = DISPATCH_LEVEL
==========================================================================
*/
BOOLEAN MlmeValidateSSID(u8 *pSsid, u8 SsidLen)
{
int index;
if (SsidLen > MAX_LEN_OF_SSID)
return (FALSE);
/* Check each character value */
for (index = 0; index < SsidLen; index++) {
if (pSsid[index] < 0x20)
return (FALSE);
}
/* All checked */
return (TRUE);
}
void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd,
struct rt_mac_table_entry *pEntry,
u8 ** ppTable,
u8 *pTableSize, u8 *pInitTxRateIdx)
{
do {
/* decide the rate table for tuning */
if (pAd->CommonCfg.TxRateTableSize > 0) {
*ppTable = RateSwitchTable;
*pTableSize = RateSwitchTable[0];
*pInitTxRateIdx = RateSwitchTable[1];
break;
}
if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) {
if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) { /* 11N 1S Adhoc */
*ppTable = RateSwitchTable11N1S;
*pTableSize = RateSwitchTable11N1S[0];
*pInitTxRateIdx = RateSwitchTable11N1S[1];
} else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) { /* 11N 2S Adhoc */
if (pAd->LatchRfRegs.Channel <= 14) {
*ppTable = RateSwitchTable11N2S;
*pTableSize = RateSwitchTable11N2S[0];
*pInitTxRateIdx =
RateSwitchTable11N2S[1];
} else {
*ppTable = RateSwitchTable11N2SForABand;
*pTableSize =
RateSwitchTable11N2SForABand[0];
*pInitTxRateIdx =
RateSwitchTable11N2SForABand[1];
}
} else if ((pEntry->RateLen == 4)
&& (pEntry->HTCapability.MCSSet[0] == 0)
&& (pEntry->HTCapability.MCSSet[1] == 0)
) {
*ppTable = RateSwitchTable11B;
*pTableSize = RateSwitchTable11B[0];
*pInitTxRateIdx = RateSwitchTable11B[1];
} else if (pAd->LatchRfRegs.Channel <= 14) {
*ppTable = RateSwitchTable11BG;
*pTableSize = RateSwitchTable11BG[0];
*pInitTxRateIdx = RateSwitchTable11BG[1];
} else {
*ppTable = RateSwitchTable11G;
*pTableSize = RateSwitchTable11G[0];
*pInitTxRateIdx = RateSwitchTable11G[1];
}
break;
}
/*if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && */
/* ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) */
if (((pEntry->RateLen == 12) || (pAd->OpMode == OPMODE_STA)) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) { /* 11BGN 1S AP */
*ppTable = RateSwitchTable11BGN1S;
*pTableSize = RateSwitchTable11BGN1S[0];
*pInitTxRateIdx = RateSwitchTable11BGN1S[1];
break;
}
/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && */
/* (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) */
if (((pEntry->RateLen == 12) || (pAd->OpMode == OPMODE_STA)) && (pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) { /* 11BGN 2S AP */
if (pAd->LatchRfRegs.Channel <= 14) {
*ppTable = RateSwitchTable11BGN2S;
*pTableSize = RateSwitchTable11BGN2S[0];
*pInitTxRateIdx = RateSwitchTable11BGN2S[1];
} else {
*ppTable = RateSwitchTable11BGN2SForABand;
*pTableSize = RateSwitchTable11BGN2SForABand[0];
*pInitTxRateIdx =
RateSwitchTable11BGN2SForABand[1];
}
break;
}
/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) */
if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) { /* 11N 1S AP */
*ppTable = RateSwitchTable11N1S;
*pTableSize = RateSwitchTable11N1S[0];
*pInitTxRateIdx = RateSwitchTable11N1S[1];
break;
}
/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) */
if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) { /* 11N 2S AP */
if (pAd->LatchRfRegs.Channel <= 14) {
*ppTable = RateSwitchTable11N2S;
*pTableSize = RateSwitchTable11N2S[0];
*pInitTxRateIdx = RateSwitchTable11N2S[1];
} else {
*ppTable = RateSwitchTable11N2SForABand;
*pTableSize = RateSwitchTable11N2SForABand[0];
*pInitTxRateIdx =
RateSwitchTable11N2SForABand[1];
}
break;
}
/*else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
if ((pEntry->RateLen == 4 || pAd->CommonCfg.PhyMode == PHY_11B)
/*Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode */
/* && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) */
) { /* B only AP */
*ppTable = RateSwitchTable11B;
*pTableSize = RateSwitchTable11B[0];
*pInitTxRateIdx = RateSwitchTable11B[1];
break;
}
/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
if ((pEntry->RateLen > 8)
&& (pEntry->HTCapability.MCSSet[0] == 0)
&& (pEntry->HTCapability.MCSSet[1] == 0)
) { /* B/G mixed AP */
*ppTable = RateSwitchTable11BG;
*pTableSize = RateSwitchTable11BG[0];
*pInitTxRateIdx = RateSwitchTable11BG[1];
break;
}
/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
if ((pEntry->RateLen == 8)
&& (pEntry->HTCapability.MCSSet[0] == 0)
&& (pEntry->HTCapability.MCSSet[1] == 0)
) { /* G only AP */
*ppTable = RateSwitchTable11G;
*pTableSize = RateSwitchTable11G[0];
*pInitTxRateIdx = RateSwitchTable11G[1];
break;
}
{
/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) { /* Legacy mode */
if (pAd->CommonCfg.MaxTxRate <= RATE_11) {
*ppTable = RateSwitchTable11B;
*pTableSize = RateSwitchTable11B[0];
*pInitTxRateIdx = RateSwitchTable11B[1];
} else if ((pAd->CommonCfg.MaxTxRate > RATE_11)
&& (pAd->CommonCfg.MinTxRate >
RATE_11)) {
*ppTable = RateSwitchTable11G;
*pTableSize = RateSwitchTable11G[0];
*pInitTxRateIdx = RateSwitchTable11G[1];
} else {
*ppTable = RateSwitchTable11BG;
*pTableSize = RateSwitchTable11BG[0];
*pInitTxRateIdx =
RateSwitchTable11BG[1];
}
break;
}
if (pAd->LatchRfRegs.Channel <= 14) {
if (pAd->CommonCfg.TxStream == 1) {
*ppTable = RateSwitchTable11N1S;
*pTableSize = RateSwitchTable11N1S[0];
*pInitTxRateIdx =
RateSwitchTable11N1S[1];
DBGPRINT_RAW(RT_DEBUG_ERROR,
("DRS: unkown mode,default use 11N 1S AP \n"));
} else {
*ppTable = RateSwitchTable11N2S;
*pTableSize = RateSwitchTable11N2S[0];
*pInitTxRateIdx =
RateSwitchTable11N2S[1];
DBGPRINT_RAW(RT_DEBUG_ERROR,
("DRS: unkown mode,default use 11N 2S AP \n"));
}
} else {
if (pAd->CommonCfg.TxStream == 1) {
*ppTable = RateSwitchTable11N1S;
*pTableSize = RateSwitchTable11N1S[0];
*pInitTxRateIdx =
RateSwitchTable11N1S[1];
DBGPRINT_RAW(RT_DEBUG_ERROR,
("DRS: unkown mode,default use 11N 1S AP \n"));
} else {
*ppTable = RateSwitchTable11N2SForABand;
*pTableSize =
RateSwitchTable11N2SForABand[0];
*pInitTxRateIdx =
RateSwitchTable11N2SForABand[1];
DBGPRINT_RAW(RT_DEBUG_ERROR,
("DRS: unkown mode,default use 11N 2S AP \n"));
}
}
DBGPRINT_RAW(RT_DEBUG_ERROR,
("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n",
pAd->StaActive.SupRateLen,
pAd->StaActive.ExtRateLen,
pAd->StaActive.SupportedPhyInfo.MCSSet[0],
pAd->StaActive.SupportedPhyInfo.
MCSSet[1]));
}
} while (FALSE);
}
void STAMlmePeriodicExec(struct rt_rtmp_adapter *pAd)
{
unsigned long TxTotalCnt;
int i;
/*
We return here in ATE mode, because the statistics
that ATE need are not collected via this routine.
*/
#if defined(RT305x)||defined(RT3070)
/* request by Gary, if Rssi0 > -42, BBP 82 need to be changed from 0x62 to 0x42, , bbp 67 need to be changed from 0x20 to 0x18 */
if (!pAd->CommonCfg.HighPowerPatchDisabled) {
#ifdef RT3070
if ((IS_RT3070(pAd) && ((pAd->MACVersion & 0xffff) < 0x0201)))
#endif /* RT3070 // */
{
if ((pAd->StaCfg.RssiSample.AvgRssi0 != 0)
&& (pAd->StaCfg.RssiSample.AvgRssi0 >
(pAd->BbpRssiToDbmDelta - 35))) {
RT30xxWriteRFRegister(pAd, RF_R27, 0x20);
} else {
RT30xxWriteRFRegister(pAd, RF_R27, 0x23);
}
}
}
#endif
#ifdef PCIE_PS_SUPPORT
/* don't perform idle-power-save mechanism within 3 min after driver initialization. */
/* This can make rebooter test more robust */
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd))
&& (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE)
&& (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
&& (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) {
if (IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) {
if (pAd->StaCfg.PSControl.field.EnableNewPS ==
TRUE) {
DBGPRINT(RT_DEBUG_TRACE,
("%s\n", __func__));
RT28xxPciAsicRadioOff(pAd,
GUI_IDLE_POWER_SAVE,
0);
} else {
AsicSendCommandToMcu(pAd, 0x30,
PowerSafeCID, 0xff,
0x2);
/* Wait command success */
AsicCheckCommanOk(pAd, PowerSafeCID);
RTMP_SET_FLAG(pAd,
fRTMP_ADAPTER_IDLE_RADIO_OFF);
DBGPRINT(RT_DEBUG_TRACE,
("PSM - rt30xx Issue Sleep command)\n"));
}
} else if (pAd->Mlme.OneSecPeriodicRound > 180) {
if (pAd->StaCfg.PSControl.field.EnableNewPS ==
TRUE) {
DBGPRINT(RT_DEBUG_TRACE,
("%s\n", __func__));
RT28xxPciAsicRadioOff(pAd,
GUI_IDLE_POWER_SAVE,
0);
} else {
AsicSendCommandToMcu(pAd, 0x30,
PowerSafeCID, 0xff,
0x02);
/* Wait command success */
AsicCheckCommanOk(pAd, PowerSafeCID);
RTMP_SET_FLAG(pAd,
fRTMP_ADAPTER_IDLE_RADIO_OFF);
DBGPRINT(RT_DEBUG_TRACE,
("PSM - rt28xx Issue Sleep command)\n"));
}
}
} else {
DBGPRINT(RT_DEBUG_TRACE,
("STAMlmePeriodicExec MMCHK - CommonCfg.Ssid[%d]=%c%c%c%c... MlmeAux.Ssid[%d]=%c%c%c%c...\n",
pAd->CommonCfg.SsidLen,
pAd->CommonCfg.Ssid[0],
pAd->CommonCfg.Ssid[1],
pAd->CommonCfg.Ssid[2],
pAd->CommonCfg.Ssid[3], pAd->MlmeAux.SsidLen,
pAd->MlmeAux.Ssid[0], pAd->MlmeAux.Ssid[1],
pAd->MlmeAux.Ssid[2], pAd->MlmeAux.Ssid[3]));
}
}
#endif /* PCIE_PS_SUPPORT // */
if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) {
/* WPA MIC error should block association attempt for 60 seconds */
if (pAd->StaCfg.bBlockAssoc &&
RTMP_TIME_AFTER(pAd->Mlme.Now32,
pAd->StaCfg.LastMicErrorTime +
(60 * OS_HZ)))
pAd->StaCfg.bBlockAssoc = FALSE;
}
if ((pAd->PreMediaState != pAd->IndicateMediaState)
&& (pAd->CommonCfg.bWirelessEvent)) {
if (pAd->IndicateMediaState == NdisMediaStateConnected) {
RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG,
pAd->MacTab.Content[BSSID_WCID].
Addr, BSS0, 0);
}
pAd->PreMediaState = pAd->IndicateMediaState;
}
if (pAd->CommonCfg.PSPXlink && ADHOC_ON(pAd)) {
} else {
AsicStaBbpTuning(pAd);
}
TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
/* update channel quality for Roaming and UI LinkQuality display */
MlmeCalculateChannelQuality(pAd, NULL, pAd->Mlme.Now32);
}
/* must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if */
/* Radio is currently in noisy environment */
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
AsicAdjustTxPower(pAd);
if (INFRA_ON(pAd)) {
/* Is PSM bit consistent with user power management policy? */
/* This is the only place that will set PSM bit ON. */
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
MlmeCheckPsmChange(pAd, pAd->Mlme.Now32);
pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt;
if ((RTMP_TIME_AFTER
(pAd->Mlme.Now32,
pAd->StaCfg.LastBeaconRxTime + (1 * OS_HZ)))
&&
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
&&
(((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt) <
600))) {
RTMPSetAGCInitValue(pAd, BW_20);
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - No BEACON. restore R66 to the low bound(%d) \n",
(0x2E + GET_LNA_GAIN(pAd))));
}
/*if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && */
/* (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) */
{
if (pAd->CommonCfg.bAPSDCapable
&& pAd->CommonCfg.APEdcaParm.bAPSDCapable) {
/* When APSD is enabled, the period changes as 20 sec */
if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8)
RTMPSendNullFrame(pAd,
pAd->CommonCfg.TxRate,
TRUE);
} else {
/* Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) */
if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) {
if (pAd->CommonCfg.bWmmCapable)
RTMPSendNullFrame(pAd,
pAd->
CommonCfg.
TxRate, TRUE);
else
RTMPSendNullFrame(pAd,
pAd->
CommonCfg.
TxRate,
FALSE);
}
}
}
if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) {
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n",
pAd->RalinkCounters.BadCQIAutoRecoveryCount));
/* Lost AP, send disconnect & link down event */
LinkDown(pAd, FALSE);
RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL,
0);
/* RTMPPatchMacBbpBug(pAd); */
MlmeAutoReconnectLastSSID(pAd);
} else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) {
pAd->RalinkCounters.BadCQIAutoRecoveryCount++;
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n",
pAd->RalinkCounters.BadCQIAutoRecoveryCount));
MlmeAutoReconnectLastSSID(pAd);
}
if (pAd->StaCfg.bAutoRoaming) {
BOOLEAN rv = FALSE;
char dBmToRoam = pAd->StaCfg.dBmToRoam;
char MaxRssi = RTMPMaxRssi(pAd,
pAd->StaCfg.RssiSample.
LastRssi0,
pAd->StaCfg.RssiSample.
LastRssi1,
pAd->StaCfg.RssiSample.
LastRssi2);
/* Scanning, ignore Roaming */
if (!RTMP_TEST_FLAG
(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)
&& (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE)
&& (MaxRssi <= dBmToRoam)) {
DBGPRINT(RT_DEBUG_TRACE,
("Rssi=%d, dBmToRoam=%d\n", MaxRssi,
(char)dBmToRoam));
/* Add auto seamless roaming */
if (rv == FALSE)
rv = MlmeCheckForFastRoaming(pAd);
if (rv == FALSE) {
if ((pAd->StaCfg.LastScanTime +
10 * OS_HZ) < pAd->Mlme.Now32) {
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - Roaming, No eligable entry, try new scan!\n"));
pAd->StaCfg.ScanCnt = 2;
pAd->StaCfg.LastScanTime =
pAd->Mlme.Now32;
MlmeAutoScan(pAd);
}
}
}
}
} else if (ADHOC_ON(pAd)) {
/* If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState */
/* to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can */
/* join later. */
if (RTMP_TIME_AFTER
(pAd->Mlme.Now32,
pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME)
&& OPSTATUS_TEST_FLAG(pAd,
fOP_STATUS_MEDIA_STATE_CONNECTED)) {
struct rt_mlme_start_req StartReq;
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"));
LinkDown(pAd, FALSE);
StartParmFill(pAd, &StartReq,
(char *) pAd->MlmeAux.Ssid,
pAd->MlmeAux.SsidLen);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ,
sizeof(struct rt_mlme_start_req), &StartReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
}
for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
struct rt_mac_table_entry *pEntry = &pAd->MacTab.Content[i];
if (pEntry->ValidAsCLI == FALSE)
continue;
if (RTMP_TIME_AFTER
(pAd->Mlme.Now32,
pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME))
MacTableDeleteEntry(pAd, pEntry->Aid,
pEntry->Addr);
}
} else /* no INFRA nor ADHOC connection */
{
if (pAd->StaCfg.bScanReqIsFromWebUI &&
RTMP_TIME_BEFORE(pAd->Mlme.Now32,
pAd->StaCfg.LastScanTime + (30 * OS_HZ)))
goto SKIP_AUTO_SCAN_CONN;
else
pAd->StaCfg.bScanReqIsFromWebUI = FALSE;
if ((pAd->StaCfg.bAutoReconnect == TRUE)
&& RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)
&&
(MlmeValidateSSID
(pAd->MlmeAux.AutoReconnectSsid,
pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
if ((pAd->ScanTab.BssNr == 0)
&& (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) {
struct rt_mlme_scan_req ScanReq;
if (RTMP_TIME_AFTER
(pAd->Mlme.Now32,
pAd->StaCfg.LastScanTime + (10 * OS_HZ))) {
DBGPRINT(RT_DEBUG_TRACE,
("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n",
pAd->MlmeAux.
AutoReconnectSsid));
ScanParmFill(pAd, &ScanReq,
(char *)pAd->MlmeAux.
AutoReconnectSsid,
pAd->MlmeAux.
AutoReconnectSsidLen,
BSS_ANY, SCAN_ACTIVE);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE,
MT2_MLME_SCAN_REQ,
sizeof
(struct rt_mlme_scan_req),
&ScanReq);
pAd->Mlme.CntlMachine.CurrState =
CNTL_WAIT_OID_LIST_SCAN;
/* Reset Missed scan number */
pAd->StaCfg.LastScanTime =
pAd->Mlme.Now32;
} else if (pAd->StaCfg.BssType == BSS_ADHOC) /* Quit the forever scan when in a very clean room */
MlmeAutoReconnectLastSSID(pAd);
} else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) {
MlmeAutoScan(pAd);
pAd->StaCfg.LastScanTime =
pAd->Mlme.Now32;
} else {
MlmeAutoReconnectLastSSID(pAd);
}
}
}
}
SKIP_AUTO_SCAN_CONN:
if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap != 0)
&& (pAd->MacTab.fAnyBASession == FALSE)) {
pAd->MacTab.fAnyBASession = TRUE;
AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE,
FALSE);
} else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap == 0)
&& (pAd->MacTab.fAnyBASession == TRUE)) {
pAd->MacTab.fAnyBASession = FALSE;
AsicUpdateProtect(pAd,
pAd->MlmeAux.AddHtInfo.AddHtInfo2.
OperaionMode, ALLN_SETPROTECT, FALSE, FALSE);
}
return;
}
/* Link down report */
void LinkDownExec(void *SystemSpecific1,
void *FunctionContext,
void *SystemSpecific2, void *SystemSpecific3)
{
struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
if (pAd != NULL) {
struct rt_mlme_disassoc_req DisassocReq;
if ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) &&
(INFRA_ON(pAd))) {
DBGPRINT(RT_DEBUG_TRACE,
("LinkDownExec(): disassociate with current AP...\n"));
DisassocParmFill(pAd, &DisassocReq,
pAd->CommonCfg.Bssid,
REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE,
MT2_MLME_DISASSOC_REQ,
sizeof(struct rt_mlme_disassoc_req),
&DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
}
}
}
/* IRQL = DISPATCH_LEVEL */
void MlmeAutoScan(struct rt_rtmp_adapter *pAd)
{
/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n"));
MlmeEnqueue(pAd,
MLME_CNTL_STATE_MACHINE,
OID_802_11_BSSID_LIST_SCAN,
pAd->MlmeAux.AutoReconnectSsidLen,
pAd->MlmeAux.AutoReconnectSsid);
RTMP_MLME_HANDLER(pAd);
}
}
/* IRQL = DISPATCH_LEVEL */
void MlmeAutoReconnectLastSSID(struct rt_rtmp_adapter *pAd)
{
if (pAd->StaCfg.bAutoConnectByBssid) {
DBGPRINT(RT_DEBUG_TRACE,
("Driver auto reconnect to last OID_802_11_BSSID setting - %02X:%02X:%02X:%02X:%02X:%02X\n",
pAd->MlmeAux.Bssid[0], pAd->MlmeAux.Bssid[1],
pAd->MlmeAux.Bssid[2], pAd->MlmeAux.Bssid[3],
pAd->MlmeAux.Bssid[4], pAd->MlmeAux.Bssid[5]));
pAd->MlmeAux.Channel = pAd->CommonCfg.Channel;
MlmeEnqueue(pAd,
MLME_CNTL_STATE_MACHINE,
OID_802_11_BSSID, MAC_ADDR_LEN, pAd->MlmeAux.Bssid);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
RTMP_MLME_HANDLER(pAd);
}
/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
else if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
(MlmeValidateSSID
(pAd->MlmeAux.AutoReconnectSsid,
pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
struct rt_ndis_802_11_ssid OidSsid;
OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen;
NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid,
pAd->MlmeAux.AutoReconnectSsidLen);
DBGPRINT(RT_DEBUG_TRACE,
("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n",
pAd->MlmeAux.AutoReconnectSsid,
pAd->MlmeAux.AutoReconnectSsidLen));
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, OID_802_11_SSID,
sizeof(struct rt_ndis_802_11_ssid), &OidSsid);
RTMP_MLME_HANDLER(pAd);
}
}
/*
==========================================================================
Description:
This routine checks if there're other APs out there capable for
roaming. Caller should call this routine only when Link up in INFRA mode
and channel quality is below CQI_GOOD_THRESHOLD.
IRQL = DISPATCH_LEVEL
Output:
==========================================================================
*/
void MlmeCheckForRoaming(struct rt_rtmp_adapter *pAd, unsigned long Now32)
{
u16 i;
struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
struct rt_bss_entry *pBss;
DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n"));
/* put all roaming candidates into RoamTab, and sort in RSSI order */
BssTableInit(pRoamTab);
for (i = 0; i < pAd->ScanTab.BssNr; i++) {
pBss = &pAd->ScanTab.BssEntry[i];
if ((pBss->LastBeaconRxTime + pAd->StaCfg.BeaconLostTime) <
Now32)
continue; /* AP disappear */
if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
continue; /* RSSI too weak. forget it. */
if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
continue; /* skip current AP */
if (pBss->Rssi <
(pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA))
continue; /* only AP with stronger RSSI is eligible for roaming */
/* AP passing all above rules is put into roaming candidate table */
NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss,
sizeof(struct rt_bss_entry));
pRoamTab->BssNr += 1;
}
if (pRoamTab->BssNr > 0) {
/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
pAd->RalinkCounters.PoorCQIRoamingCount++;
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - Roaming attempt #%ld\n",
pAd->RalinkCounters.PoorCQIRoamingCount));
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
MT2_MLME_ROAMING_REQ, 0, NULL);
RTMP_MLME_HANDLER(pAd);
}
}
DBGPRINT(RT_DEBUG_TRACE,
("<== MlmeCheckForRoaming(# of candidate= %d)\n",
pRoamTab->BssNr));
}
/*
==========================================================================
Description:
This routine checks if there're other APs out there capable for
roaming. Caller should call this routine only when link up in INFRA mode
and channel quality is below CQI_GOOD_THRESHOLD.
IRQL = DISPATCH_LEVEL
Output:
==========================================================================
*/
BOOLEAN MlmeCheckForFastRoaming(struct rt_rtmp_adapter *pAd)
{
u16 i;
struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
struct rt_bss_entry *pBss;
DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n"));
/* put all roaming candidates into RoamTab, and sort in RSSI order */
BssTableInit(pRoamTab);
for (i = 0; i < pAd->ScanTab.BssNr; i++) {
pBss = &pAd->ScanTab.BssEntry[i];
if ((pBss->Rssi <= -50)
&& (pBss->Channel == pAd->CommonCfg.Channel))
continue; /* RSSI too weak. forget it. */
if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
continue; /* skip current AP */
if (!SSID_EQUAL
(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid,
pAd->CommonCfg.SsidLen))
continue; /* skip different SSID */
if (pBss->Rssi <
(RTMPMaxRssi
(pAd, pAd->StaCfg.RssiSample.LastRssi0,
pAd->StaCfg.RssiSample.LastRssi1,
pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA))
continue; /* skip AP without better RSSI */
DBGPRINT(RT_DEBUG_TRACE,
("LastRssi0 = %d, pBss->Rssi = %d\n",
RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0,
pAd->StaCfg.RssiSample.LastRssi1,
pAd->StaCfg.RssiSample.LastRssi2),
pBss->Rssi));
/* AP passing all above rules is put into roaming candidate table */
NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss,
sizeof(struct rt_bss_entry));
pRoamTab->BssNr += 1;
}
DBGPRINT(RT_DEBUG_TRACE,
("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr));
if (pRoamTab->BssNr > 0) {
/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
pAd->RalinkCounters.PoorCQIRoamingCount++;
DBGPRINT(RT_DEBUG_TRACE,
("MMCHK - Roaming attempt #%ld\n",
pAd->RalinkCounters.PoorCQIRoamingCount));
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
MT2_MLME_ROAMING_REQ, 0, NULL);
RTMP_MLME_HANDLER(pAd);
return TRUE;
}
}
return FALSE;
}
void MlmeSetTxRate(struct rt_rtmp_adapter *pAd,
struct rt_mac_table_entry *pEntry, struct rt_rtmp_tx_rate_switch * pTxRate)
{
u8 MaxMode = MODE_OFDM;
MaxMode = MODE_HTGREENFIELD;
if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC)
&& (pAd->Antenna.field.TxPath == 2))
pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE;
else
pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;
if (pTxRate->CurrMCS < MCS_AUTO)
pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS;
if (pAd->StaCfg.HTPhyMode.field.MCS > 7)
pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;
if (ADHOC_ON(pAd)) {
/* If peer adhoc is b-only mode, we can't send 11g rate. */
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
pEntry->HTPhyMode.field.STBC = STBC_NONE;
/* */
/* For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary */
/* */
pEntry->HTPhyMode.field.MODE = pTxRate->Mode;
pEntry->HTPhyMode.field.ShortGI =
pAd->StaCfg.HTPhyMode.field.ShortGI;
pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
/* Patch speed error in status page */
pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE;
} else {
if (pTxRate->Mode <= MaxMode)
pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode;
if (pTxRate->ShortGI
&& (pAd->StaCfg.MaxHTPhyMode.field.ShortGI))
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400;
else
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
/* Reexam each bandwidth's SGI support. */
if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) {
if ((pEntry->HTPhyMode.field.BW == BW_20)
&&
(!CLIENT_STATUS_TEST_FLAG
(pEntry, fCLIENT_STATUS_SGI20_CAPABLE)))
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
if ((pEntry->HTPhyMode.field.BW == BW_40)
&&
(!CLIENT_STATUS_TEST_FLAG
(pEntry, fCLIENT_STATUS_SGI40_CAPABLE)))
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
}
/* Turn RTS/CTS rate to 6Mbps. */
if ((pEntry->HTPhyMode.field.MCS == 0)
&& (pAd->StaCfg.HTPhyMode.field.MCS != 0)) {
pEntry->HTPhyMode.field.MCS =
pAd->StaCfg.HTPhyMode.field.MCS;
if (pAd->MacTab.fAnyBASession) {
AsicUpdateProtect(pAd, HT_FORCERTSCTS,
ALLN_SETPROTECT, TRUE,
(BOOLEAN) pAd->MlmeAux.
AddHtInfo.AddHtInfo2.
NonGfPresent);
} else {
AsicUpdateProtect(pAd,
pAd->MlmeAux.AddHtInfo.
AddHtInfo2.OperaionMode,
ALLN_SETPROTECT, TRUE,
(BOOLEAN) pAd->MlmeAux.
AddHtInfo.AddHtInfo2.
NonGfPresent);
}
} else if ((pEntry->HTPhyMode.field.MCS == 8)
&& (pAd->StaCfg.HTPhyMode.field.MCS != 8)) {
pEntry->HTPhyMode.field.MCS =
pAd->StaCfg.HTPhyMode.field.MCS;
if (pAd->MacTab.fAnyBASession) {
AsicUpdateProtect(pAd, HT_FORCERTSCTS,
ALLN_SETPROTECT, TRUE,
(BOOLEAN) pAd->MlmeAux.
AddHtInfo.AddHtInfo2.
NonGfPresent);
} else {
AsicUpdateProtect(pAd,
pAd->MlmeAux.AddHtInfo.
AddHtInfo2.OperaionMode,
ALLN_SETPROTECT, TRUE,
(BOOLEAN) pAd->MlmeAux.
AddHtInfo.AddHtInfo2.
NonGfPresent);
}
} else if ((pEntry->HTPhyMode.field.MCS != 0)
&& (pAd->StaCfg.HTPhyMode.field.MCS == 0)) {
AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT,
TRUE,
(BOOLEAN) pAd->MlmeAux.AddHtInfo.
AddHtInfo2.NonGfPresent);
} else if ((pEntry->HTPhyMode.field.MCS != 8)
&& (pAd->StaCfg.HTPhyMode.field.MCS == 8)) {
AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT,
TRUE,
(BOOLEAN) pAd->MlmeAux.AddHtInfo.
AddHtInfo2.NonGfPresent);
}
pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC;
pEntry->HTPhyMode.field.ShortGI =
pAd->StaCfg.HTPhyMode.field.ShortGI;
pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE;
if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD)
&& pAd->WIFItestbed.bGreenField)
pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD;
}
pAd->LastTxRate = (u16)(pEntry->HTPhyMode.word);
}
/*
==========================================================================
Description:
This routine calculates the acumulated TxPER of eaxh TxRate. And
according to the calculation result, change CommonCfg.TxRate which
is the stable TX Rate we expect the Radio situation could sustained.
CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
Output:
CommonCfg.TxRate -
IRQL = DISPATCH_LEVEL
NOTE:
call this routine every second
==========================================================================
*/
void MlmeDynamicTxRateSwitching(struct rt_rtmp_adapter *pAd)
{
u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
unsigned long i, AccuTxTotalCnt = 0, TxTotalCnt;
unsigned long TxErrorRatio = 0;
BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
u8 *pTable;
u8 TableSize = 0;
u8 InitTxRateIdx = 0, TrainUp, TrainDown;
char Rssi, RssiOffset = 0;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
struct rt_mac_table_entry *pEntry;
struct rt_rssi_sample *pRssi = &pAd->StaCfg.RssiSample;
/* */
/* walk through MAC table, see if need to change AP's TX rate toward each entry */
/* */
for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
pEntry = &pAd->MacTab.Content[i];
/* check if this entry need to switch rate automatically */
if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
continue;
if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) {
Rssi = RTMPMaxRssi(pAd,
pRssi->AvgRssi0,
pRssi->AvgRssi1, pRssi->AvgRssi2);
/* Update statistic counter */
RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
pAd->bUpdateBcnCntDone = TRUE;
TxRetransmit = StaTx1.field.TxRetransmit;
TxSuccess = StaTx1.field.TxSuccess;
TxFailCount = TxStaCnt0.field.TxFailCount;
TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
pAd->RalinkCounters.OneSecTxRetryOkCount +=
StaTx1.field.TxRetransmit;
pAd->RalinkCounters.OneSecTxNoRetryOkCount +=
StaTx1.field.TxSuccess;
pAd->RalinkCounters.OneSecTxFailCount +=
TxStaCnt0.field.TxFailCount;
pAd->WlanCounters.TransmittedFragmentCount.u.LowPart +=
StaTx1.field.TxSuccess;
pAd->WlanCounters.RetryCount.u.LowPart +=
StaTx1.field.TxRetransmit;
pAd->WlanCounters.FailedCount.u.LowPart +=
TxStaCnt0.field.TxFailCount;
/* if no traffic in the past 1-sec period, don't change TX rate, */
/* but clear all bad history. because the bad history may affect the next */
/* Chariot throughput test */
AccuTxTotalCnt =
pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio =
((TxRetransmit +
TxFailCount) * 100) / TxTotalCnt;
} else {
if (INFRA_ON(pAd) && (i == 1))
Rssi = RTMPMaxRssi(pAd,
pRssi->AvgRssi0,
pRssi->AvgRssi1,
pRssi->AvgRssi2);
else
Rssi = RTMPMaxRssi(pAd,
pEntry->RssiSample.AvgRssi0,
pEntry->RssiSample.AvgRssi1,
pEntry->RssiSample.AvgRssi2);
TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
pEntry->OneSecTxRetryOkCount +
pEntry->OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio =
((pEntry->OneSecTxRetryOkCount +
pEntry->OneSecTxFailCount) * 100) /
TxTotalCnt;
}
if (TxTotalCnt) {
/*
Three AdHoc connections can not work normally if one AdHoc connection is disappeared from a heavy traffic environment generated by ping tool
We force to set LongRtyLimit and ShortRtyLimit to 0 to stop retransmitting packet, after a while, resoring original settings
*/
if (TxErrorRatio == 100) {
TX_RTY_CFG_STRUC TxRtyCfg, TxRtyCfgtmp;
unsigned long Index;
unsigned long MACValue;
RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
TxRtyCfgtmp.word = TxRtyCfg.word;
TxRtyCfg.field.LongRtyLimit = 0x0;
TxRtyCfg.field.ShortRtyLimit = 0x0;
RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
RTMPusecDelay(1);
Index = 0;
MACValue = 0;
do {
RTMP_IO_READ32(pAd, TXRXQ_PCNT,
&MACValue);
if ((MACValue & 0xffffff) == 0)
break;
Index++;
RTMPusecDelay(1000);
} while ((Index < 330)
&&
(!RTMP_TEST_FLAG
(pAd,
fRTMP_ADAPTER_HALT_IN_PROGRESS)));
RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
TxRtyCfg.field.LongRtyLimit =
TxRtyCfgtmp.field.LongRtyLimit;
TxRtyCfg.field.ShortRtyLimit =
TxRtyCfgtmp.field.ShortRtyLimit;
RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
}
}
CurrRateIdx = pEntry->CurrTxRateIndex;
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
&InitTxRateIdx);
if (CurrRateIdx >= TableSize) {
CurrRateIdx = TableSize - 1;
}
/* When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. */
/* So need to sync here. */
pCurrTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS)
/*&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) */
) {
/* Need to sync Real Tx rate and our record. */
/* Then return for next DRS. */
pCurrTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(InitTxRateIdx + 1)
* 5];
pEntry->CurrTxRateIndex = InitTxRateIdx;
MlmeSetTxRate(pAd, pEntry, pCurrTxRate);
/* reset all OneSecTx counters */
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
/* decide the next upgrade rate and downgrade rate, if any */
if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx - 1;
} else if (CurrRateIdx == 0) {
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx;
} else if (CurrRateIdx == (TableSize - 1)) {
UpRateIdx = CurrRateIdx;
DownRateIdx = CurrRateIdx - 1;
}
pCurrTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
TrainUp =
(pCurrTxRate->TrainUp +
(pCurrTxRate->TrainUp >> 1));
TrainDown =
(pCurrTxRate->TrainDown +
(pCurrTxRate->TrainDown >> 1));
} else {
TrainUp = pCurrTxRate->TrainUp;
TrainDown = pCurrTxRate->TrainDown;
}
/*pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; */
/* */
/* Keep the last time TxRateChangeAction status. */
/* */
pEntry->LastTimeTxRateChangeAction =
pEntry->LastSecTxRateChangeAction;
/* */
/* CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI */
/* (criteria copied from RT2500 for Netopia case) */
/* */
if (TxTotalCnt <= 15) {
char idx = 0;
u8 TxRateIdx;
u8 MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 =
0, MCS5 = 0, MCS6 = 0, MCS7 = 0;
u8 MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
u8 MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; /* 3*3 */
/* check the existence and index of each needed MCS */
while (idx < pTable[0]) {
pCurrTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(idx + 1) *
5];
if (pCurrTxRate->CurrMCS == MCS_0) {
MCS0 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_1) {
MCS1 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_2) {
MCS2 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_3) {
MCS3 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_4) {
MCS4 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_5) {
MCS5 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_6) {
MCS6 = idx;
}
/*else if (pCurrTxRate->CurrMCS == MCS_7) */
else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) /* prevent the highest MCS using short GI when 1T and low throughput */
{
MCS7 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_12) {
MCS12 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_13) {
MCS13 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_14) {
MCS14 = idx;
}
else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) /*we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI */
{
MCS15 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_20) /* 3*3 */
{
MCS20 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_21) {
MCS21 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_22) {
MCS22 = idx;
} else if (pCurrTxRate->CurrMCS == MCS_23) {
MCS23 = idx;
}
idx++;
}
if (pAd->LatchRfRegs.Channel <= 14) {
if (pAd->NicConfig2.field.ExternalLNAForG) {
RssiOffset = 2;
} else {
RssiOffset = 5;
}
} else {
if (pAd->NicConfig2.field.ExternalLNAForA) {
RssiOffset = 5;
} else {
RssiOffset = 8;
}
}
/*if (MCS15) */
if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable)) { /* N mode with 3 stream // 3*3 */
if (MCS23 && (Rssi >= -70))
TxRateIdx = MCS23;
else if (MCS22 && (Rssi >= -72))
TxRateIdx = MCS22;
else if (MCS21 && (Rssi >= -76))
TxRateIdx = MCS21;
else if (MCS20 && (Rssi >= -78))
TxRateIdx = MCS20;
else if (MCS4 && (Rssi >= -82))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi >= -84))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi >= -86))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi >= -88))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
/* else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) */
else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) || (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand)) /* 3*3 */
{ /* N mode with 2 stream */
if (MCS15 && (Rssi >= (-70 + RssiOffset)))
TxRateIdx = MCS15;
else if (MCS14 && (Rssi >= (-72 + RssiOffset)))
TxRateIdx = MCS14;
else if (MCS13 && (Rssi >= (-76 + RssiOffset)))
TxRateIdx = MCS13;
else if (MCS12 && (Rssi >= (-78 + RssiOffset)))
TxRateIdx = MCS12;
else if (MCS4 && (Rssi >= (-82 + RssiOffset)))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi >= (-84 + RssiOffset)))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi >= (-86 + RssiOffset)))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi >= (-88 + RssiOffset)))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
} else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) { /* N mode with 1 stream */
if (MCS7 && (Rssi > (-72 + RssiOffset)))
TxRateIdx = MCS7;
else if (MCS6 && (Rssi > (-74 + RssiOffset)))
TxRateIdx = MCS6;
else if (MCS5 && (Rssi > (-77 + RssiOffset)))
TxRateIdx = MCS5;
else if (MCS4 && (Rssi > (-79 + RssiOffset)))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi > (-81 + RssiOffset)))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi > (-83 + RssiOffset)))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi > (-86 + RssiOffset)))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
} else { /* Legacy mode */
if (MCS7 && (Rssi > -70))
TxRateIdx = MCS7;
else if (MCS6 && (Rssi > -74))
TxRateIdx = MCS6;
else if (MCS5 && (Rssi > -78))
TxRateIdx = MCS5;
else if (MCS4 && (Rssi > -82))
TxRateIdx = MCS4;
else if (MCS4 == 0) /* for B-only mode */
TxRateIdx = MCS3;
else if (MCS3 && (Rssi > -85))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi > -87))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi > -90))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
/* if (TxRateIdx != pAd->CommonCfg.TxRateIndex) */
{
pEntry->CurrTxRateIndex = TxRateIdx;
pNextTxRate =
(struct rt_rtmp_tx_rate_switch *) &
pTable[(pEntry->CurrTxRateIndex + 1) * 5];
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
NdisZeroMemory(pEntry->TxQuality,
sizeof(u16)*
MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER,
sizeof(u8)*
MAX_STEP_OF_TX_RATE_SWITCH);
pEntry->fLastSecAccordingRSSI = TRUE;
/* reset all OneSecTx counters */
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
if (pEntry->fLastSecAccordingRSSI == TRUE) {
pEntry->fLastSecAccordingRSSI = FALSE;
pEntry->LastSecTxRateChangeAction = 0;
/* reset all OneSecTx counters */
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
do {
BOOLEAN bTrainUpDown = FALSE;
pEntry->CurrTxRateStableTime++;
/* downgrade TX quality if PER >= Rate-Down threshold */
if (TxErrorRatio >= TrainDown) {
bTrainUpDown = TRUE;
pEntry->TxQuality[CurrRateIdx] =
DRS_TX_QUALITY_WORST_BOUND;
}
/* upgrade TX quality if PER <= Rate-Up threshold */
else if (TxErrorRatio <= TrainUp) {
bTrainUpDown = TRUE;
bUpgradeQuality = TRUE;
if (pEntry->TxQuality[CurrRateIdx])
pEntry->TxQuality[CurrRateIdx]--; /* quality very good in CurrRate */
if (pEntry->TxRateUpPenalty)
pEntry->TxRateUpPenalty--;
else if (pEntry->TxQuality[UpRateIdx])
pEntry->TxQuality[UpRateIdx]--; /* may improve next UP rate's quality */
}
pEntry->PER[CurrRateIdx] = (u8)TxErrorRatio;
if (bTrainUpDown) {
/* perform DRS - consider TxRate Down first, then rate up. */
if ((CurrRateIdx != DownRateIdx)
&& (pEntry->TxQuality[CurrRateIdx] >=
DRS_TX_QUALITY_WORST_BOUND)) {
pEntry->CurrTxRateIndex = DownRateIdx;
} else if ((CurrRateIdx != UpRateIdx)
&& (pEntry->TxQuality[UpRateIdx] <=
0)) {
pEntry->CurrTxRateIndex = UpRateIdx;
}
}
} while (FALSE);
/* if rate-up happen, clear all bad history of all TX rates */
if (pEntry->CurrTxRateIndex > CurrRateIdx) {
pEntry->CurrTxRateStableTime = 0;
pEntry->TxRateUpPenalty = 0;
pEntry->LastSecTxRateChangeAction = 1; /* rate UP */
NdisZeroMemory(pEntry->TxQuality,
sizeof(u16)*
MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER,
sizeof(u8)*
MAX_STEP_OF_TX_RATE_SWITCH);
/* */
/* For TxRate fast train up */
/* */
if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
RTMPSetTimer(&pAd->StaCfg.
StaQuickResponeForRateUpTimer,
100);
pAd->StaCfg.
StaQuickResponeForRateUpTimerRunning = TRUE;
}
bTxRateChanged = TRUE;
}
/* if rate-down happen, only clear DownRate's bad history */
else if (pEntry->CurrTxRateIndex < CurrRateIdx) {
pEntry->CurrTxRateStableTime = 0;
pEntry->TxRateUpPenalty = 0; /* no penalty */
pEntry->LastSecTxRateChangeAction = 2; /* rate DOWN */
pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
pEntry->PER[pEntry->CurrTxRateIndex] = 0;
/* */
/* For TxRate fast train down */
/* */
if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
RTMPSetTimer(&pAd->StaCfg.
StaQuickResponeForRateUpTimer,
100);
pAd->StaCfg.
StaQuickResponeForRateUpTimerRunning = TRUE;
}
bTxRateChanged = TRUE;
} else {
pEntry->LastSecTxRateChangeAction = 0; /* rate no change */
bTxRateChanged = FALSE;
}
pEntry->LastTxOkCount = TxSuccess;
{
u8 tmpTxRate;
/* to fix tcp ack issue */
if (!bTxRateChanged
&& (pAd->RalinkCounters.OneSecReceivedByteCount >
(pAd->RalinkCounters.
OneSecTransmittedByteCount * 5))) {
tmpTxRate = DownRateIdx;
DBGPRINT_RAW(RT_DEBUG_TRACE,
("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n",
pAd->RalinkCounters.
OneSecReceivedByteCount,
pAd->RalinkCounters.
OneSecTransmittedByteCount,
pEntry->CurrTxRateIndex,
tmpTxRate));
} else {
tmpTxRate = pEntry->CurrTxRateIndex;
}
pNextTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(tmpTxRate + 1) *
5];
}
if (bTxRateChanged && pNextTxRate) {
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
/* reset all OneSecTx counters */
RESET_ONE_SEC_TX_CNT(pEntry);
}
}
/*
========================================================================
Routine Description:
Station side, Auto TxRate faster train up timer call back function.
Arguments:
SystemSpecific1 - Not used.
FunctionContext - Pointer to our Adapter context.
SystemSpecific2 - Not used.
SystemSpecific3 - Not used.
Return Value:
None
========================================================================
*/
void StaQuickResponeForRateUpExec(void *SystemSpecific1,
void *FunctionContext,
void *SystemSpecific2,
void *SystemSpecific3)
{
struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
unsigned long TxTotalCnt;
unsigned long TxErrorRatio = 0;
BOOLEAN bTxRateChanged; /*, bUpgradeQuality = FALSE; */
struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
u8 *pTable;
u8 TableSize = 0;
u8 InitTxRateIdx = 0, TrainUp, TrainDown;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
char Rssi, ratio;
unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
struct rt_mac_table_entry *pEntry;
unsigned long i;
pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
/* */
/* walk through MAC table, see if need to change AP's TX rate toward each entry */
/* */
for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
pEntry = &pAd->MacTab.Content[i];
/* check if this entry need to switch rate automatically */
if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
continue;
if (INFRA_ON(pAd) && (i == 1))
Rssi = RTMPMaxRssi(pAd,
pAd->StaCfg.RssiSample.AvgRssi0,
pAd->StaCfg.RssiSample.AvgRssi1,
pAd->StaCfg.RssiSample.AvgRssi2);
else
Rssi = RTMPMaxRssi(pAd,
pEntry->RssiSample.AvgRssi0,
pEntry->RssiSample.AvgRssi1,
pEntry->RssiSample.AvgRssi2);
CurrRateIdx = pAd->CommonCfg.TxRateIndex;
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
&InitTxRateIdx);
/* decide the next upgrade rate and downgrade rate, if any */
if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx - 1;
} else if (CurrRateIdx == 0) {
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx;
} else if (CurrRateIdx == (TableSize - 1)) {
UpRateIdx = CurrRateIdx;
DownRateIdx = CurrRateIdx - 1;
}
pCurrTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
TrainUp =
(pCurrTxRate->TrainUp +
(pCurrTxRate->TrainUp >> 1));
TrainDown =
(pCurrTxRate->TrainDown +