blob: 1613c04c59325b63e91af3486de2439f4f5063d8 [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>
UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96};
UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01};
UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac};
UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72};
UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04};
UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43};
UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c};
UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
#ifdef CONFIG_STA_SUPPORT
#ifdef DOT11_N_SUPPORT
UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c};
#endif // DOT11_N_SUPPORT //
#endif // CONFIG_STA_SUPPORT //
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
#ifdef DOT11_N_SUPPORT
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
UCHAR 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,
};
#endif // DOT11_N_SUPPORT //
extern UCHAR 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
ULONG 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 */};
UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
UCHAR 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 };
UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100};
USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200};
UCHAR SsidIe = IE_SSID;
UCHAR SupRateIe = IE_SUPP_RATES;
UCHAR ExtRateIe = IE_EXT_SUPP_RATES;
#ifdef DOT11_N_SUPPORT
UCHAR HtCapIe = IE_HT_CAP;
UCHAR AddHtInfoIe = IE_ADD_HT;
UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET;
#ifdef DOT11N_DRAFT3
UCHAR ExtHtCapIe = IE_EXT_CAPABILITY;
#endif // DOT11N_DRAFT3 //
#endif // DOT11_N_SUPPORT //
UCHAR ErpIe = IE_ERP;
UCHAR DsIe = IE_DS_PARM;
UCHAR TimIe = IE_TIM;
UCHAR WpaIe = IE_WPA;
UCHAR Wpa2Ie = IE_WPA2;
UCHAR IbssIe = IE_IBSS_PARM;
UCHAR Ccx2Ie = IE_CCX_V2;
UCHAR WapiIe = IE_WAPI;
extern UCHAR WPA_OUI[];
UCHAR SES_OUI[] = {0x00, 0x90, 0x4c};
UCHAR 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
==========================================================================
*/
NDIS_STATUS MlmeInit(
IN PRTMP_ADAPTER pAd)
{
NDIS_STATUS 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);
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
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);
#ifdef QOS_DLS_SUPPORT
DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc);
#endif // QOS_DLS_SUPPORT //
// 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);
}
#endif // CONFIG_STA_SUPPORT //
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 CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
#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);
}
#endif // CONFIG_STA_SUPPORT //
} 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(
IN PRTMP_ADAPTER pAd)
{
MLME_QUEUE_ELEM *Elem = NULL;
#ifdef APCLI_SUPPORT
SHORT apcliIfIndex;
#endif // APCLI_SUPPORT //
// 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;
}
#ifdef RALINK_ATE
if(ATE_ON(pAd))
{
DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n"));
break;
}
#endif // RALINK_ATE //
//From message type, determine which state machine I should drive
if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
{
// if dequeue success
switch (Elem->Machine)
{
// STA state machines
#ifdef CONFIG_STA_SUPPORT
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;
#ifdef QOS_DLS_SUPPORT
case DLS_STATE_MACHINE:
StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem);
break;
#endif // QOS_DLS_SUPPORT //
#endif // CONFIG_STA_SUPPORT //
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(
IN PRTMP_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);
}
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
#ifdef QOS_DLS_SUPPORT
UCHAR i;
#endif // QOS_DLS_SUPPORT //
// 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 //
#ifdef QOS_DLS_SUPPORT
for (i=0; i<MAX_NUM_OF_DLS_ENTRY; i++)
{
RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &Cancelled);
}
#endif // QOS_DLS_SUPPORT //
RTMPCancelTimer(&pAd->Mlme.LinkDownTimer, &Cancelled);
}
#endif // CONFIG_STA_SUPPORT //
RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled);
RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled);
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
{
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.
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(
IN PRTMP_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(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
ULONG TxTotalCnt;
PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext;
SHORT realavgrssi;
#ifdef CONFIG_STA_SUPPORT
#ifdef RTMP_MAC_PCI
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
// 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)*/)
{
UINT32 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 //
#endif // CONFIG_STA_SUPPORT //
// 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);
#ifdef RALINK_ATE
/* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */
if (ATE_ON(pAd))
{
if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1))
{
pAd->Mlme.PeriodicRound ++;
return;
}
}
#endif // RALINK_ATE //
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(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;
}
}
}
#endif // CONFIG_STA_SUPPORT //
pAd->bUpdateBcnCntDone = FALSE;
// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3);
pAd->Mlme.PeriodicRound ++;
// execute every 500ms
if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/)
{
#ifdef CONFIG_STA_SUPPORT
// perform dynamic tx rate switching based on past TX history
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
)
&& (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)))
MlmeDynamicTxRateSwitching(pAd);
}
#endif // CONFIG_STA_SUPPORT //
}
// Normal 1 second Mlme PeriodicExec.
if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0)
{
pAd->Mlme.OneSecPeriodicRound ++;
#ifdef RALINK_ATE
if (ATE_ON(pAd))
{
/* request from Baron : move this routine from later to here */
/* for showing Rx error count in ATE RXFRAME */
NICUpdateRawCounters(pAd);
if (pAd->ate.bRxFER == 1)
{
pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec;
ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt);
pAd->ate.RxCntPerSec = 0;
if (pAd->ate.RxAntennaSel == 0)
ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n",
pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2);
else
ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0);
}
MlmeResetRalinkCounters(pAd);
return;
}
#endif // RALINK_ATE //
//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 DOT11_N_SUPPORT
// Need statistics after read counter. So put after NICUpdateRawCounters
ORIBATimerTimeout(pAd);
#endif // DOT11_N_SUPPORT //
// 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
#ifdef ANT_DIVERSITY_SUPPORT
if ((pAd->NicConfig2.field.AntDiversity) &&
(pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE) &&
(!pAd->EepromAccess))
AsicAntennaSelect(pAd, pAd->MlmeAux.Channel);
else if(pAd->CommonCfg.bRxAntDiversity == ANT_FIX_ANT1 || pAd->CommonCfg.bRxAntDiversity == ANT_FIX_ANT2)
{
#ifdef CONFIG_STA_SUPPORT
realavgrssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3);
#endif // CONFIG_STA_SUPPORT //
DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt));
}
else
#endif // ANT_DIVERSITY_SUPPORT //
{
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);
}
}
}
}
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
STAMlmePeriodicExec(pAd);
#endif // CONFIG_STA_SUPPORT //
MlmeResetRalinkCounters(pAd);
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(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.
UINT32 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"));
}
}
}
#endif // CONFIG_STA_SUPPORT //
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(
IN PUCHAR pSsid,
IN UCHAR 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(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pEntry,
IN PUCHAR *ppTable,
IN PUCHAR pTableSize,
IN PUCHAR pInitTxRateIdx)
{
do
{
// decide the rate table for tuning
if (pAd->CommonCfg.TxRateTableSize > 0)
{
*ppTable = RateSwitchTable;
*pTableSize = RateSwitchTable[0];
*pInitTxRateIdx = RateSwitchTable[1];
break;
}
#ifdef CONFIG_STA_SUPPORT
if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd))
{
#ifdef DOT11_N_SUPPORT
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
#endif // DOT11_N_SUPPORT //
if ((pEntry->RateLen == 4)
#ifdef DOT11_N_SUPPORT
&& (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
#endif // DOT11_N_SUPPORT //
)
{
*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;
}
#endif // CONFIG_STA_SUPPORT //
#ifdef DOT11_N_SUPPORT
//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;
}
#endif // DOT11_N_SUPPORT //
//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)
#ifdef DOT11_N_SUPPORT
//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)*/
#endif // DOT11_N_SUPPORT //
)
{// 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)
#ifdef DOT11_N_SUPPORT
&& (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
#endif // DOT11_N_SUPPORT //
)
{// 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)
#ifdef DOT11_N_SUPPORT
&& (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
#endif // DOT11_N_SUPPORT //
)
{// G only AP
*ppTable = RateSwitchTable11G;
*pTableSize = RateSwitchTable11G[0];
*pInitTxRateIdx = RateSwitchTable11G[1];
break;
}
#ifdef DOT11_N_SUPPORT
#endif // DOT11_N_SUPPORT //
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
#ifdef DOT11_N_SUPPORT
//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))
#endif // DOT11_N_SUPPORT //
{ // 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;
}
#ifdef DOT11_N_SUPPORT
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"));
}
}
#endif // DOT11_N_SUPPORT //
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]));
}
#endif // CONFIG_STA_SUPPORT //
} while(FALSE);
}
#ifdef CONFIG_STA_SUPPORT
VOID STAMlmePeriodicExec(
PRTMP_ADAPTER pAd)
{
ULONG TxTotalCnt;
int i;
/*
We return here in ATE mode, because the statistics
that ATE need are not collected via this routine.
*/
#ifdef RALINK_ATE
if (ATE_ON(pAd))
return;
#endif // RALINK_ATE //
#ifdef RALINK_ATE
// It is supposed that we will never reach here in ATE mode.
ASSERT(!(ATE_ON(pAd)));
if (ATE_ON(pAd))
return;
#endif // RALINK_ATE //
#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::%d\n",__FUNCTION__,__LINE__));
RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0);
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__));
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::%d\n",__FUNCTION__,__LINE__));
RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0);
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__));
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 //
#ifdef WPA_SUPPLICANT_SUPPORT
if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)
#endif // WPA_SUPPLICANT_SUPPORT //
{
// 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))
{
#ifdef QOS_DLS_SUPPORT
// Check DLS time out, then tear down those session
RTMPCheckDLSTimeOut(pAd);
#endif // QOS_DLS_SUPPORT //
// 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);
#ifdef WPA_SUPPLICANT_SUPPORT
#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT
//send disassociate event to wpa_supplicant
if (pAd->StaCfg.WpaSupplicantUP) {
RtmpOSWrielessEventSend(pAd, IWEVCUSTOM, RT_DISASSOC_EVENT_FLAG, NULL, NULL, 0);
}
#endif // NATIVE_WPA_SUPPLICANT_SUPPORT //
#endif // WPA_SUPPLICANT_SUPPORT //
#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT
RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL, 0);
#endif // NATIVE_WPA_SUPPLICANT_SUPPORT //
// 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))
{
MLME_START_REQ_STRUCT 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(MLME_START_REQ_STRUCT), &StartReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
}
for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
{
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))
{
MLME_SCAN_REQ_STRUCT 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, (PSTRING) pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &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
{
#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier
if (pAd->CommonCfg.CarrierDetect.Enable == TRUE)
{
if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1)
MlmeAutoReconnectLastSSID(pAd);
}
else
#endif // CARRIER_DETECTION_SUPPORT //
MlmeAutoReconnectLastSSID(pAd);
}
}
}
}
SKIP_AUTO_SCAN_CONN:
#ifdef DOT11_N_SUPPORT
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);
}
#endif // DOT11_N_SUPPORT //
#ifdef DOT11_N_SUPPORT
#ifdef DOT11N_DRAFT3
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))
TriEventCounterMaintenance(pAd);
#endif // DOT11N_DRAFT3 //
#endif // DOT11_N_SUPPORT //
return;
}
// Link down report
VOID LinkDownExec(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
if (pAd != NULL)
{
MLME_DISASSOC_REQ_STRUCT 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(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
}
}
}
// IRQL = DISPATCH_LEVEL
VOID MlmeAutoScan(
IN PRTMP_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(
IN PRTMP_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))
{
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(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(
IN PRTMP_ADAPTER pAd,
IN ULONG Now32)
{
USHORT i;
BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab;
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(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(
IN PRTMP_ADAPTER pAd)
{
USHORT i;
BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab;
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(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(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pEntry,
IN PRTMP_TX_RATE_SWITCH pTxRate)
{
UCHAR MaxMode = MODE_OFDM;
#ifdef DOT11_N_SUPPORT
MaxMode = MODE_HTGREENFIELD;
if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2))
pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE;
else
#endif // DOT11_N_SUPPORT //
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;
#ifdef DOT11_N_SUPPORT
if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI))
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400;
else
#endif // DOT11_N_SUPPORT //
pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
#ifdef DOT11_N_SUPPORT
// 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);
}
#endif // DOT11_N_SUPPORT //
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;
#ifdef DOT11_N_SUPPORT
if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) &&
pAd->WIFItestbed.bGreenField)
pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD;
#endif // DOT11_N_SUPPORT //
}
pAd->LastTxRate = (USHORT)(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(
IN PRTMP_ADAPTER pAd)
{
UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
ULONG i, AccuTxTotalCnt = 0, TxTotalCnt;
ULONG TxErrorRatio = 0;
BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL;
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx = 0, TrainUp, TrainDown;
CHAR Rssi, RssiOffset = 0;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
MAC_TABLE_ENTRY *pEntry;
RSSI_SAMPLE *pRssi = &pAd->StaCfg.RssiSample;
#ifdef RALINK_ATE
if (ATE_ON(pAd))
{
return;
}
#endif // RALINK_ATE //
//
// 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;
ULONG Index;
ULONG 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 = (PRTMP_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 = (PRTMP_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 = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];
#ifdef DOT11_N_SUPPORT
if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
{
TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
}
else
#endif // DOT11_N_SUPPORT //
{
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;
UCHAR TxRateIdx;
UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0;
UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3
// check the existence and index of each needed MCS
while (idx < pTable[0])
{
pCurrTxRate = (PRTMP_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
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;
}
}
#ifdef DOT11_N_SUPPORT
/*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
#endif // DOT11_N_SUPPORT //
{// 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 = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5];
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * 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] = (UCHAR)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(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * 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;
{
UCHAR 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 = (PRTMP_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(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext;
UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
ULONG TxTotalCnt;
ULONG TxErrorRatio = 0;
BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE;
PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL;
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx = 0, TrainUp, TrainDown;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
CHAR Rssi, ratio;
ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
MAC_TABLE_ENTRY *pEntry;
ULONG 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 = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];
#ifdef DOT11_N_SUPPORT
if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
{
TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
}
else
#endif // DOT11_N_SUPPORT //
{
TrainUp = pCurrTxRate->TrainUp;
TrainDown = pCurrTxRate->TrainDown;
}
if (pAd->MacTab.Size == 1)
{
// Update statistic counter
RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
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 (TxTotalCnt)
TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
}
else
{
TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
pEntry->OneSecTxRetryOkCount +
pEntry->OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt;
}
//
// 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 <= 12)
{
NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx))
{
pAd->CommonCfg.TxRateIndex = DownRateIdx;
pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
}
else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx))
{
pAd->CommonCfg.TxRateIndex = UpRateIdx;
}
DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
return;
}
do
{
ULONG OneSecTxNoRetryOKRationCount;
if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
ratio = 5;
else
ratio = 4;
// downgrade TX quality if PER >= Rate-Down threshold
if (TxErrorRatio >= TrainDown)
{
pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
}
pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
// perform DRS - consider TxRate Down first, then rate up.
if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx))
{
if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
{
pAd->CommonCfg.TxRateIndex = DownRateIdx;
pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
}
}
else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx))
{
if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown))
{
}
else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
{
pAd->CommonCfg.TxRateIndex = UpRateIdx;
}
}
}while (FALSE);
// if rate-up happen, clear all bad history of all TX rates
if (pAd->CommonCfg.TxRateIndex > CurrRateIdx)
{
pAd->DrsCounters.TxRateUpPenalty = 0;
NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
bTxRateChanged = TRUE;
}
// if rate-down happen, only clear DownRate's bad history
else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx)
{
DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex));
pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty
pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0;
pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
bTxRateChanged = TRUE;
}
else
{
bTxRateChanged = FALSE;
}
pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5];
if (bTxRateChanged && pNextTxRate)
{
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
}
}
/*
==========================================================================
Description:
This routine is executed periodically inside MlmePeriodicExec() after
association with an AP.
It checks if StaCfg.Psm is consistent with user policy (recorded in
StaCfg.WindowsPowerMode). If not, enforce user policy. However,
there're some conditions to consider:
1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
the time when Mibss==TRUE
2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
if outgoing traffic available in TxRing or MgmtRing.
Output:
1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeCheckPsmChange(
IN PRTMP_ADAPTER pAd,
IN ULONG Now32)
{
ULONG PowerMode;
// condition -
// 1. Psm maybe ON only happen in INFRASTRUCTURE mode
// 2. user wants either MAX_PSP or FAST_PSP
// 3. but current psm is not in PWR_SAVE
// 4. CNTL state machine is not doing SCANning
// 5. no TX SUCCESS event for the past 1-sec period
PowerMode = pAd->StaCfg.WindowsPowerMode;
if (INFRA_ON(pAd) &&
(PowerMode != Ndis802_11PowerModeCAM) &&
(pAd->StaCfg.Psm == PWR_ACTIVE) &&
// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
(pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)&&
RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)
/*&&
(pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) &&
(pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/)
{
NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
pAd->RalinkCounters.RxCountSinceLastNULL = 0;
RTMP_SET_PSM_BIT(pAd, PWR_SAVE);
if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable))
{
RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
}
else
{
RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
}
}
}
// IRQL = PASSIVE_LEVEL
// IRQL = DISPATCH_LEVEL
VOID MlmeSetPsmBit(
IN PRTMP_ADAPTER pAd,
IN USHORT psm)
{
AUTO_RSP_CFG_STRUC csr4;
pAd->StaCfg.Psm = psm;
RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0;
RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
}
#endif // CONFIG_STA_SUPPORT //
/*
==========================================================================
Description:
This routine calculates TxPER, RxPER of the past N-sec period. And
according to the calculation result, ChannelQuality is calculated here
to decide if current AP is still doing the job.
If ChannelQuality is not good, a ROAMing attempt may be tried later.
Output:
StaCfg.ChannelQuality - 0..100
IRQL = DISPATCH_LEVEL
NOTE: This routine decide channle quality based on RX CRC error ratio.
Caller should make sure a function call to NICUpdateRawCounters(pAd)
is performed right before this routine, so that this routine can decide
channel quality based on the most up-to-date information
==========================================================================
*/
VOID MlmeCalculateChannelQuality(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pMacEntry,
IN ULONG Now32)
{
ULONG TxOkCnt, TxCnt, TxPER, TxPRR;
ULONG RxCnt, RxPER;
UCHAR NorRssi;
CHAR MaxRssi;
RSSI_SAMPLE *pRssiSample = NULL;
UINT32 OneSecTxNoRetryOkCount = 0;
UINT32 OneSecTxRetryOkCount = 0;
UINT32 OneSecTxFailCount = 0;
UINT32 OneSecRxOkCnt = 0;
UINT32 OneSecRxFcsErrCnt = 0;
ULONG ChannelQuality = 0; // 0..100, Channel Quality Indication for Roaming
#ifdef CONFIG_STA_SUPPORT
ULONG BeaconLostTime = pAd->StaCfg.BeaconLostTime;
#endif // CONFIG_STA_SUPPORT //
#ifdef CONFIG_STA_SUPPORT
#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier
// longer beacon lost time when carrier detection enabled
if (pAd->CommonCfg.CarrierDetect.Enable == TRUE)
{
BeaconLostTime = pAd->StaCfg.BeaconLostTime + (pAd->StaCfg.BeaconLostTime/2);
}
#endif // CARRIER_DETECTION_SUPPORT //
#endif // CONFIG_STA_SUPPORT //
#ifdef CONFIG_STA_SUPPORT
if (pAd->OpMode == OPMODE_STA)
{
pRssiSample = &pAd->StaCfg.RssiSample;
OneSecTxNoRetryOkCount = pAd->RalinkCounters.OneSecTxNoRetryOkCount;
OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount;
OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount;
OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
}
#endif // CONFIG_STA_SUPPORT //
MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0,
pRssiSample->LastRssi1,
pRssiSample->LastRssi2);
//
// calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics
//
TxOkCnt = OneSecTxNoRetryOkCount + OneSecTxRetryOkCount;
TxCnt = TxOkCnt + OneSecTxFailCount;
if (TxCnt < 5)
{
TxPER = 0;
TxPRR = 0;
}
else
{
TxPER = (OneSecTxFailCount * 100) / TxCnt;
TxPRR = ((TxCnt - OneSecTxNoRetryOkCount) * 100) / TxCnt;
}
//
// calculate RX PER - don't take RxPER into consideration if too few sample
//
RxCnt = OneSecRxOkCnt + OneSecRxFcsErrCnt;
if (RxCnt < 5)
RxPER = 0;
else
RxPER = (OneSecRxFcsErrCnt * 100) / RxCnt;
//
// decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER
//
#ifdef CONFIG_STA_SUPPORT
if ((pAd->OpMode == OPMODE_STA) &&
INFRA_ON(pAd) &&
(OneSecTxNoRetryOkCount < 2) && // no heavy traffic
((pAd->StaCfg.LastBeaconRxTime + BeaconLostTime) < Now32))
{
DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt));
ChannelQuality = 0;
}
else
#endif // CONFIG_STA_SUPPORT //
{
// Normalize Rssi
if (MaxRssi > -40)
NorRssi = 100;
else if (MaxRssi < -90)
NorRssi = 0;
else
NorRssi = (MaxRssi + 90) * 2;
// ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
ChannelQuality = (RSSI_WEIGHTING * NorRssi +
TX_WEIGHTING * (100 - TxPRR) +
RX_WEIGHTING* (100 - RxPER)) / 100;
}
#ifdef CONFIG_STA_SUPPORT
if (pAd->OpMode == OPMODE_STA)
pAd->Mlme.ChannelQuality = (ChannelQuality > 100) ? 100 : ChannelQuality;
#endif // CONFIG_STA_SUPPORT //
}
// IRQL = DISPATCH_LEVEL
VOID MlmeSetTxPreamble(
IN PRTMP_ADAPTER pAd,
IN USHORT TxPreamble)
{
AUTO_RSP_CFG_STRUC csr4;
//
// Always use Long preamble before verifiation short preamble functionality works well.
// Todo: remove the following line if short preamble functionality works
//
//TxPreamble = Rt802_11PreambleLong;
RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
if (TxPreamble == Rt802_11PreambleLong)
{
DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n"));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
csr4.field.AutoResponderPreamble = 0;
}
else
{
// NOTE: 1Mbps should always use long preamble
DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n"));
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
csr4.field.AutoResponderPreamble = 1;
}
RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
}
/*
==========================================================================
Description:
Update basic rate bitmap
==========================================================================
*/
VOID UpdateBasicRateBitmap(
IN PRTMP_ADAPTER pAdapter)
{
INT i, j;
/* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */
UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
UCHAR *sup_p = pAdapter->CommonCfg.SupRate;
UCHAR *ext_p = pAdapter->CommonCfg.ExtRate;
ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap;
/* if A mode, always use fix BasicRateBitMap */
//if (pAdapter->CommonCfg.Channel == PHY_11A)
if (pAdapter->CommonCfg.Channel > 14)
pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */
/* End of if */
if (pAdapter->CommonCfg.BasicRateBitmap > 4095)
{
/* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
return;
} /* End of if */
for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
{
sup_p[i] &= 0x7f;
ext_p[i] &= 0x7f;
} /* End of for */
for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
{
if (bitmap & (1 << i))
{
for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++)
{
if (sup_p[j] == rate[i])
sup_p[j] |= 0x80;
/* End of if */
} /* End of for */
for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++)
{
if (ext_p[j] == rate[i])
ext_p[j] |= 0x80;
/* End of if */
} /* End of for */
} /* End of if */
} /* End of for */
} /* End of UpdateBasicRateBitmap */
// IRQL = PASSIVE_LEVEL
// IRQL = DISPATCH_LEVEL
// bLinkUp is to identify the inital link speed.
// TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps.
VOID MlmeUpdateTxRates(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN bLinkUp,
IN UCHAR apidx)
{
int i, num;
UCHAR Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1;
UCHAR MinSupport = RATE_54;
ULONG BasicRateBitmap = 0;
UCHAR CurrBasicRate = RATE_1;
UCHAR *pSupRate, SupRateLen, *pExtRate, ExtRateLen;
PHTTRANSMIT_SETTING pHtPhy = NULL;
PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
PHTTRANSMIT_SETTING pMinHtPhy = NULL;
BOOLEAN *auto_rate_cur_p;
UCHAR HtMcs = MCS_AUTO;
// find max desired rate
UpdateBasicRateBitmap(pAd);
num = 0;
auto_rate_cur_p = NULL;
for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
{
switch (pAd->CommonCfg.DesireRate[i] & 0x7f)
{
case 2: Rate = RATE_1; num++; break;
case 4: Rate = RATE_2; num++; break;
case 11: Rate = RATE_5_5; num++; break;
case 22: Rate = RATE_11; num++; break;
case 12: Rate = RATE_6; num++; break;
case 18: Rate = RATE_9; num++; break;
case 24: Rate = RATE_12; num++; break;
case 36: Rate = RATE_18; num++; break;
case 48: Rate = RATE_24; num++; break;
case 72: Rate = RATE_36; num++; break;
case 96: Rate = RATE_48; num++; break;
case 108: Rate = RATE_54; num++; break;
//default: Rate = RATE_1; break;
}
if (MaxDesire < Rate) MaxDesire = Rate;
}
//===========================================================================
//===========================================================================
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
pHtPhy = &pAd->StaCfg.HTPhyMode;
pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS;
if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
(pAd->CommonCfg.PhyMode == PHY_11B) &&
(MaxDesire > RATE_11))
{
MaxDesire = RATE_11;
}
}
#endif // CONFIG_STA_SUPPORT //
pAd->CommonCfg.MaxDesiredRate = MaxDesire;
pMinHtPhy->word = 0;
pMaxHtPhy->word = 0;
pHtPhy->word = 0;
// Auto rate switching is enabled only if more than one DESIRED RATES are
// specified; otherwise disabled
if (num <= 1)
{
//OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
//pAd->CommonCfg.bAutoTxRateSwitch = FALSE;
*auto_rate_cur_p = FALSE;
}
else
{
//OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
//pAd->CommonCfg.bAutoTxRateSwitch = TRUE;
*auto_rate_cur_p = TRUE;
}
if (HtMcs != MCS_AUTO)
{
//OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
//pAd->CommonCfg.bAutoTxRateSwitch = FALSE;
*auto_rate_cur_p = FALSE;
}
else
{
//OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
//pAd->CommonCfg.bAutoTxRateSwitch = TRUE;
*auto_rate_cur_p = TRUE;
}
#ifdef CONFIG_STA_SUPPORT
if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA))
{
pSupRate = &pAd->StaActive.SupRate[0];
pExtRate = &pAd->StaActive.ExtRate[0];
SupRateLen = pAd->StaActive.SupRateLen;
ExtRateLen = pAd->StaActive.ExtRateLen;
}
else
#endif // CONFIG_STA_SUPPORT //
{
pSupRate = &pAd->CommonCfg.SupRate[0];
pExtRate = &pAd->CommonCfg.ExtRate[0];
SupRateLen = pAd->CommonCfg.SupRateLen;
ExtRateLen = pAd->CommonCfg.ExtRateLen;
}
// find max supported rate
for (i=0; i<SupRateLen; i++)
{
switch (pSupRate[i] & 0x7f)
{
case 2: Rate = RATE_1; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0001; break;
case 4: Rate = RATE_2; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0002; break;
case 11: Rate = RATE_5_5; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0004; break;
case 22: Rate = RATE_11; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0008; break;
case 12: Rate = RATE_6; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0010; break;
case 18: Rate = RATE_9; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0020; break;
case 24: Rate = RATE_12; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0040; break;
case 36: Rate = RATE_18; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0080; break;
case 48: Rate = RATE_24; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0100; break;
case 72: Rate = RATE_36; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0200; break;
case 96: Rate = RATE_48; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0400; break;
case 108: Rate = RATE_54; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0800; break;
default: Rate = RATE_1; break;
}
if (MaxSupport < Rate) MaxSupport = Rate;
if (MinSupport > Rate) MinSupport = Rate;
}
for (i=0; i<ExtRateLen; i++)
{
switch (pExtRate[i] & 0x7f)
{
case 2: Rate = RATE_1; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0001; break;
case 4: Rate = RATE_2; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0002; break;
case 11: Rate = RATE_5_5; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0004; break;
case 22: Rate = RATE_11; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0008; break;
case 12: Rate = RATE_6; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0010; break;
case 18: Rate = RATE_9; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0020; break;
case 24: Rate = RATE_12; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0040; break;
case 36: Rate = RATE_18; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0080; break;
case 48: Rate = RATE_24; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0100; break;
case 72: Rate = RATE_36; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0200; break;
case 96: Rate = RATE_48; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0400; break;
case 108: Rate = RATE_54; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0800; break;
default: Rate = RATE_1; break;
}
if (MaxSupport < Rate) MaxSupport = Rate;
if (MinSupport > Rate) MinSupport = Rate;
}
RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);
// bug fix
// pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap;
// calculate the exptected ACK rate for each TX rate. This info is used to caculate
// the DURATION field of outgoing uniicast DATA/MGMT frame
for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
{
if (BasicRateBitmap & (0x01 << i))
CurrBasicRate = (UCHAR)i;
pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate;
}
DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire]));
// max tx rate = min {max desire rate, max supported rate}
if (MaxSupport < MaxDesire)
pAd->CommonCfg.MaxTxRate = MaxSupport;
else
pAd->CommonCfg.MaxTxRate = MaxDesire;
pAd->CommonCfg.MinTxRate = MinSupport;
// 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success
// ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending
// on average RSSI
// 1. RSSI >= -70db, start at 54 Mbps (short distance)
// 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance)
// 3. -75 > RSSI, start at 11 Mbps (long distance)
//if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* &&
// OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/)
if (*auto_rate_cur_p)
{
short dbm = 0;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;
#endif // CONFIG_STA_SUPPORT //
if (bLinkUp == TRUE)
pAd->CommonCfg.TxRate = RATE_24;
else
pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
if (dbm < -75)
pAd->CommonCfg.TxRate = RATE_11;
else if (dbm < -70)
pAd->CommonCfg.TxRate = RATE_24;
// should never exceed MaxTxRate (consider 11B-only mode)
if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
pAd->CommonCfg.TxRateIndex = 0;
}
else
{
pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate;
pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK;
pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC;
pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI;
pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS;
pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE;
}
if (pAd->CommonCfg.TxRate <= RATE_11)
{
pMaxHtPhy->field.MODE = MODE_CCK;
pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate;
pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
}
else
{
pMaxHtPhy->field.MODE = MODE_OFDM;
pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate];
if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54))
{pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];}
else
{pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;}
}
pHtPhy->word = (pMaxHtPhy->word);
if (bLinkUp && (pAd->OpMode == OPMODE_STA))
{
pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word;
pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word;
pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word;
}
else
{
switch (pAd->CommonCfg.PhyMode)
{
case PHY_11BG_MIXED:
case PHY_11B:
#ifdef DOT11_N_SUPPORT
case PHY_11BGN_MIXED:
#endif // DOT11_N_SUPPORT //
pAd->CommonCfg.MlmeRate = RATE_1;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
//#ifdef WIFI_TEST
pAd->CommonCfg.RtsRate = RATE_11;
//#else
// pAd->CommonCfg.RtsRate = RATE_1;
//#endif
break;
case PHY_11G:
case PHY_11A:
#ifdef DOT11_N_SUPPORT
case PHY_11AGN_MIXED:
case PHY_11GN_MIXED:
case PHY_11N_2_4G:
case PHY_11AN_MIXED:
case PHY_11N_5G:
#endif // DOT11_N_SUPPORT //
pAd->CommonCfg.MlmeRate = RATE_6;
pAd->CommonCfg.RtsRate = RATE_6;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
break;
case PHY_11ABG_MIXED:
#ifdef DOT11_N_SUPPORT
case PHY_11ABGN_MIXED:
#endif // DOT11_N_SUPPORT //
if (pAd->CommonCfg.Channel <= 14)
{
pAd->CommonCfg.MlmeRate = RATE_1;
pAd->CommonCfg.RtsRate = RATE_1;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
}
else
{
pAd->CommonCfg.MlmeRate = RATE_6;
pAd->CommonCfg.RtsRate = RATE_6;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
}
break;
default: // error
pAd->CommonCfg.MlmeRate = RATE_6;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
pAd->CommonCfg.RtsRate = RATE_1;
break;
}
//
// Keep Basic Mlme Rate.
//
pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word;
if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM)
pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24];
else
pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1;
pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate;
}
DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n",
RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate],
/*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p));
DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n",
RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap));
DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n",
pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word ));
}
#ifdef DOT11_N_SUPPORT
/*
==========================================================================
Description:
This function update HT Rate setting.
Input Wcid value is valid for 2 case :
1. it's used for Station in infra mode that copy AP rate to Mactable.
2. OR Station in adhoc mode to copy peer's HT rate to Mactable.
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeUpdateHtTxRates(
IN PRTMP_ADAPTER pAd,
IN UCHAR apidx)
{
UCHAR StbcMcs; //j, StbcMcs, bitmask;
CHAR i; // 3*3
RT_HT_CAPABILITY *pRtHtCap = NULL;
RT_HT_PHY_INFO *pActiveHtPhy = NULL;
ULONG BasicMCS;
UCHAR j, bitmask;
PRT_HT_PHY_INFO pDesireHtPhy = NULL;
PHTTRANSMIT_SETTING pHtPhy = NULL;
PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
PHTTRANSMIT_SETTING pMinHtPhy = NULL;
BOOLEAN *auto_rate_cur_p;
DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n"));
auto_rate_cur_p = NULL;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
pHtPhy = &pAd->StaCfg.HTPhyMode;
pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
}
#endif // CONFIG_STA_SUPPORT //
#ifdef CONFIG_STA_SUPPORT
if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA))
{
if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
return;
pRtHtCap = &pAd->StaActive.SupportedHtPhy;
pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo;
StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs;
BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16);
if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2))
pMaxHtPhy->field.STBC = STBC_USE;
else
pMaxHtPhy->field.STBC = STBC_NONE;
}
else
#endif // CONFIG_STA_SUPPORT //
{
if (pDesireHtPhy->bHtEnable == FALSE)
return;
pRtHtCap = &pAd->CommonCfg.DesiredHtPhy;
StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs;
BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16);
if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2))
pMaxHtPhy->field.STBC = STBC_USE;
else
pMaxHtPhy->field.STBC = STBC_NONE;
}
// Decide MAX ht rate.
if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
pMaxHtPhy->field.MODE = MODE_HTGREENFIELD;
else
pMaxHtPhy->field.MODE = MODE_HTMIX;
if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth))
pMaxHtPhy->field.BW = BW_40;
else
pMaxHtPhy->field.BW = BW_20;
if (pMaxHtPhy->field.BW == BW_20)
pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20);
else
pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40);
if (pDesireHtPhy->MCSSet[4] != 0)
{
pMaxHtPhy->field.MCS = 32;
}
for (i=23; i>=0; i--) // 3*3
{
j = i/8;
bitmask = (1<<(i-(j*8)));
if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask))
{
pMaxHtPhy->field.MCS = i;
break;
}
if (i==0)
break;
}
// Copy MIN ht rate. rt2860???
pMinHtPhy->field.BW = BW_20;
pMinHtPhy->field.MCS = 0;
pMinHtPhy->field.STBC = 0;
pMinHtPhy->field.ShortGI = 0;
//If STA assigns fixed rate. update to fixed here.
#ifdef CONFIG_STA_SUPPORT
if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff))
{
if (pDesireHtPhy->MCSSet[4] != 0)
{
pMaxHtPhy->field.MCS = 32;
pMinHtPhy->field.MCS = 32;
DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS));
}
for (i=23; (CHAR)i >= 0; i--) // 3*3
{
j = i/8;
bitmask = (1<<(i-(j*8)));
if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask))
{
pMaxHtPhy->field.MCS = i;
pMinHtPhy->field.MCS = i;
break;
}
if (i==0)
break;
}
}
#endif // CONFIG_STA_SUPPORT //
// Decide ht rate
pHtPhy->field.STBC = pMaxHtPhy->field.STBC;
pHtPhy->field.BW = pMaxHtPhy->field.BW;
pHtPhy->field.MODE = pMaxHtPhy->field.MODE;
pHtPhy->field.MCS = pMaxHtPhy->field.MCS;
pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI;
// use default now. rt2860
if (pDesireHtPhy->MCSSet[0] != 0xff)
*auto_rate_cur_p = FALSE;
else
*auto_rate_cur_p = TRUE;
DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize ));
DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS,
pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE));
DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n"));
}
VOID BATableInit(
IN PRTMP_ADAPTER pAd,
IN BA_TABLE *Tab)
{
int i;
Tab->numAsOriginator = 0;
Tab->numAsRecipient = 0;
Tab->numDoneOriginator = 0;
NdisAllocateSpinLock(&pAd->BATabLock);
for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++)
{
Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock));
}
for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++)
{
Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
}
}
#endif // DOT11_N_SUPPORT //
// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOff(
IN PRTMP_ADAPTER pAd)
{
RTMP_MLME_RADIO_OFF(pAd);
}
// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOn(
IN PRTMP_ADAPTER pAd)
{
RTMP_MLME_RADIO_ON(pAd);
}
// ===========================================================================================
// bss_table.c
// ===========================================================================================
/*! \brief initialize BSS table
* \param p_tab pointer to the table
* \return none
* \pre
* \post
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
*/
VOID BssTableInit(
IN BSS_TABLE *Tab)
{
int i;
Tab->BssNr = 0;
Tab->BssOverlapNr = 0;
for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++)
{
NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value
}
}
/*! \brief search the BSS table by SSID
* \param p_tab pointer to the bss table
* \param ssid SSID string
* \return index of the table, BSS_NOT_FOUND if not in the table
* \pre
* \post
* \note search by sequential search
IRQL = DISPATCH_LEVEL
*/
ULONG BssTableSearch(
IN BSS_TABLE *Tab,
IN PUCHAR pBssid,
IN UCHAR Channel)
{
UCHAR i;
for (i = 0; i < Tab->BssNr; i++)
{
//
// Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
// We should distinguish this case.
//
if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))
{
return i;
}
}
return (ULONG)BSS_NOT_FOUND;
}
ULONG BssSsidTableSearch(
IN BSS_TABLE *Tab,
IN PUCHAR pBssid,
IN PUCHAR pSsid,
IN UCHAR SsidLen,
IN UCHAR Channel)
{
UCHAR i;
for (i = 0; i < Tab->BssNr; i++)
{
//
// Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
// We should distinguish this case.
//
if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) &&
SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen))
{
return i;
}
}
return (ULONG)BSS_NOT_FOUND;
}
ULONG BssTableSearchWithSSID(
IN BSS_TABLE *Tab,
IN PUCHAR Bssid,
IN PUCHAR pSsid,
IN UCHAR SsidLen,
IN UCHAR Channel)
{
UCHAR i;
for (i = 0; i < Tab->BssNr; i++)
{
if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) &&
(SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) ||
(NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) ||
(NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen))))
{
return i;
}
}
return (ULONG)BSS_NOT_FOUND;
}
ULONG BssSsidTableSearchBySSID(
IN BSS_TABLE *Tab,
IN PUCHAR pSsid,
IN UCHAR SsidLen)
{
UCHAR i;
for (i = 0; i < Tab->BssNr; i++)
{
if (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen))
{
return i;
}
}
return (ULONG)BSS_NOT_FOUND;
}
// IRQL = DISPATCH_LEVEL
VOID BssTableDeleteEntry(
IN OUT BSS_TABLE *Tab,
IN PUCHAR pBssid,
IN UCHAR Channel)
{
UCHAR i, j;
for (i = 0; i < Tab->BssNr; i++)
{
if ((Tab->BssEntry[i].Channel == Channel) &&
(MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)))
{
for (j = i; j < Tab->BssNr - 1; j++)
{
NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
}
NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY));
Tab->BssNr -= 1;
return;
}
}
}
#ifdef DOT11_N_SUPPORT
/*
========================================================================
Routine Description:
Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.
Arguments:
// IRQL = DISPATCH_LEVEL
========================================================================
*/
VOID BATableDeleteORIEntry(
IN OUT PRTMP_ADAPTER pAd,
IN BA_ORI_ENTRY *pBAORIEntry)
{
if (pBAORIEntry->ORI_BA_Status != Originator_NONE)
{
NdisAcquireSpinLock(&pAd->BATabLock);
if (pBAORIEntry->ORI_BA_Status == Originator_Done)
{
pAd->BATable.numAsOriginator -= 1;
DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient));
// Erase Bitmap flag.
}
pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here
pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here
pBAORIEntry->ORI_BA_Status = Originator_NONE;
pBAORIEntry->Token = 1;
// Not clear Sequence here.
NdisReleaseSpinLock(&pAd->BATabLock);
}
}
#endif // DOT11_N_SUPPORT //
/*! \brief
* \param
* \return
* \pre
* \post
IRQL = DISPATCH_LEVEL
*/
VOID BssEntrySet(
IN PRTMP_ADAPTER pAd,
OUT BSS_ENTRY *pBss,
IN PUCHAR pBssid,
IN CHAR Ssid[],
IN UCHAR SsidLen,
IN UCHAR BssType,
IN USHORT BeaconPeriod,
IN PCF_PARM pCfParm,
IN USHORT AtimWin,
IN USHORT CapabilityInfo,
IN UCHAR SupRate[],
IN UCHAR SupRateLen,
IN UCHAR ExtRate[],
IN UCHAR ExtRateLen,
IN HT_CAPABILITY_IE *pHtCapability,
IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE
IN UCHAR HtCapabilityLen,
IN UCHAR AddHtInfoLen,
IN UCHAR NewExtChanOffset,
IN UCHAR Channel,
IN CHAR Rssi,
IN LARGE_INTEGER TimeStamp,
IN UCHAR CkipFlag,
IN PEDCA_PARM pEdcaParm,
IN PQOS_CAPABILITY_PARM pQosCapability,
IN PQBSS_LOAD_PARM pQbssLoad,
IN USHORT LengthVIE,
IN PNDIS_802_11_VARIABLE_IEs pVIE)
{
COPY_MAC_ADDR(pBss->Bssid, pBssid);
// Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID
pBss->Hidden = 1;
if (SsidLen > 0)
{
// For hidden SSID AP, it might send beacon with SSID len equal to 0
// Or send beacon /probe response with SSID len matching real SSID length,
// but SSID is all zero. such as "00-00-00-00" with length 4.
// We have to prevent this case overwrite correct table
if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0)
{
NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
pBss->SsidLen = SsidLen;
pBss->Hidden = 0;
}
}
else
pBss->SsidLen = 0;
pBss->BssType = BssType;
pBss->BeaconPeriod = BeaconPeriod;
if (BssType == BSS_INFRA)
{
if (pCfParm->bValid)
{
pBss->CfpCount = pCfParm->CfpCount;
pBss->CfpPeriod = pCfParm->CfpPeriod;
pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
}
}
else
{
pBss->AtimWin = AtimWin;
}
pBss->CapabilityInfo = CapabilityInfo;
// The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
// Combine with AuthMode, they will decide the connection methods.
pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen);
else
NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES);
pBss->SupRateLen = SupRateLen;
ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen);
pBss->NewExtChanOffset = NewExtChanOffset;
pBss->ExtRateLen = ExtRateLen;
pBss->Channel = Channel;
pBss->CentralChannel = Channel;
pBss->Rssi = Rssi;
// Update CkipFlag. if not exists, the value is 0x0
pBss->CkipFlag = CkipFlag;
// New for microsoft Fixed IEs
NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
pBss->FixIEs.BeaconInterval = BeaconPeriod;
pBss->FixIEs.Capabilities = CapabilityInfo;
// New for microsoft Variable IEs
if (LengthVIE != 0)
{
pBss->VarIELen = LengthVIE;
NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
}
else
{
pBss->VarIELen = 0;
}
pBss->AddHtInfoLen = 0;
pBss->HtCapabilityLen = 0;
#ifdef DOT11_N_SUPPORT
if (HtCapabilityLen> 0)
{
pBss->HtCapabilityLen = HtCapabilityLen;
NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen);
if (AddHtInfoLen > 0)
{
pBss->AddHtInfoLen = AddHtInfoLen;
NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen);
if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40))
{
pBss->CentralChannel = pAddHtInfo->ControlChan - 2;
}
else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40))
{
pBss->CentralChannel = pAddHtInfo->ControlChan + 2;
}
}
}
#endif // DOT11_N_SUPPORT //
BssCipherParse(pBss);
// new for QOS
if (pEdcaParm)
NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM));
else
pBss->EdcaParm.bValid = FALSE;
if (pQosCapability)
NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM));
else
pBss->QosCapability.bValid = FALSE;
if (pQbssLoad)
NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM));
else
pBss->QbssLoad.bValid = FALSE;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
PEID_STRUCT pEid;
USHORT Length = 0;
NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN);
NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN);
#ifdef EXT_BUILD_CHANNEL_LIST
NdisZeroMemory(&pBss->CountryString[0], 3);
pBss->bHasCountryIE = FALSE;
#endif // EXT_BUILD_CHANNEL_LIST //
pEid = (PEID_STRUCT) pVIE;
while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE)
{
switch(pEid->Eid)
{
case IE_WPA:
if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))
{
if ((pEid->Len + 2) > MAX_CUSTOM_LEN)
{
pBss->WpaIE.IELen = 0;
break;
}
pBss->WpaIE.IELen = pEid->Len + 2;
NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen);
}
break;
case IE_RSN:
if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))
{
if ((pEid->Len + 2) > MAX_CUSTOM_LEN)
{
pBss->RsnIE.IELen = 0;
break;
}
pBss->RsnIE.IELen = pEid->Len + 2;
NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen);
}
break;
#ifdef EXT_BUILD_CHANNEL_LIST
case IE_COUNTRY:
NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3);
pBss->bHasCountryIE = TRUE;
break;
#endif // EXT_BUILD_CHANNEL_LIST //
}
Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len]
pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
}
}
#endif // CONFIG_STA_SUPPORT //
}
/*!
* \brief insert an entry into the bss table
* \param p_tab The BSS table
* \param Bssid BSSID
* \param ssid SSID
* \param ssid_len Length of SSID
* \param bss_type
* \param beacon_period
* \param timestamp
* \param p_cf
* \param atim_win
* \param cap
* \param rates
* \param rates_len
* \param channel_idx
* \return none
* \pre
* \post
* \note If SSID is identical, the old entry will be replaced by the new one
IRQL = DISPATCH_LEVEL
*/
ULONG BssTableSetEntry(
IN PRTMP_ADAPTER pAd,
OUT BSS_TABLE *Tab,
IN PUCHAR pBssid,
IN CHAR Ssid[],
IN UCHAR SsidLen,
IN UCHAR BssType,
IN USHORT BeaconPeriod,
IN CF_PARM *CfParm,
IN USHORT AtimWin,
IN USHORT CapabilityInfo,
IN UCHAR SupRate[],
IN UCHAR SupRateLen,
IN UCHAR ExtRate[],
IN UCHAR ExtRateLen,
IN HT_CAPABILITY_IE *pHtCapability,
IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE
IN UCHAR HtCapabilityLen,
IN UCHAR AddHtInfoLen,
IN UCHAR NewExtChanOffset,
IN UCHAR ChannelNo,
IN CHAR Rssi,
IN LARGE_INTEGER TimeStamp,
IN UCHAR CkipFlag,
IN PEDCA_PARM pEdcaParm,
IN PQOS_CAPABILITY_PARM pQosCapability,
IN PQBSS_LOAD_PARM pQbssLoad,
IN USHORT LengthVIE,
IN PNDIS_802_11_VARIABLE_IEs pVIE)
{
ULONG Idx;
Idx = BssTableSearchWithSSID(Tab, pBssid, (UCHAR *)Ssid, SsidLen, ChannelNo);
if (Idx == BSS_NOT_FOUND)
{
if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE)
{
//
// It may happen when BSS Table was full.
// The desired AP will not be added into BSS Table
// In this case, if we found the desired AP then overwrite BSS Table.
//
if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
{
if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) ||
SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen))
{
Idx = Tab->BssOverlapNr;
BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin,
CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE;
}
return Idx;
}
else
{
return BSS_NOT_FOUND;
}
}
Idx = Tab->BssNr;
BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin,
CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
Tab->BssNr++;
}
else
{
/* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */
if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) ||
(NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen)))
{
BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin,
CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
}
}
return Idx;
}
#ifdef CONFIG_STA_SUPPORT
#ifdef DOT11_N_SUPPORT
#ifdef DOT11N_DRAFT3
VOID TriEventInit(
IN PRTMP_ADAPTER pAd)
{
UCHAR i;
for (i = 0;i < MAX_TRIGGER_EVENT;i++)
pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE;
pAd->CommonCfg.TriggerEventTab.EventANo = 0;
pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0;
}
ULONG TriEventTableSetEntry(
IN PRTMP_ADAPTER pAd,
OUT TRIGGER_EVENT_TAB *Tab,
IN PUCHAR pBssid,
IN HT_CAPABILITY_IE *pHtCapability,
IN UCHAR HtCapabilityLen,
IN UCHAR RegClass,
IN UCHAR ChannelNo)
{
// Event A
if (HtCapabilityLen == 0)
{
if (Tab->EventANo < MAX_TRIGGER_EVENT)
{
RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6);
Tab->EventA[Tab->EventANo].bValid = TRUE;
Tab->EventA[Tab->EventANo].Channel = ChannelNo;
Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay;
if (RegClass != 0)
{
// Beacon has Regulatory class IE. So use beacon's
Tab->EventA[Tab->EventANo].RegClass = RegClass;
}
else
{
// Use Station's Regulatory class instead.
if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE)
{
if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel)
{
Tab->EventA[Tab->EventANo].RegClass = 32;
}
else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel)
Tab->EventA[Tab->EventANo].RegClass = 33;
}
else
Tab->EventA[Tab->EventANo].RegClass = ??;
}
Tab->EventANo ++;
}
}
else if (pHtCapability->HtCapInfo.Intolerant40)
{
Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay;
}
}
/*
========================================================================
Routine Description:
Trigger Event table Maintainence called once every second.
Arguments:
// IRQL = DISPATCH_LEVEL
========================================================================
*/
VOID TriEventCounterMaintenance(
IN PRTMP_ADAPTER pAd)
{
UCHAR i;
BOOLEAN bNotify = FALSE;
for (i = 0;i < MAX_TRIGGER_EVENT;i++)
{
if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0))
{
pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--;
if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0)
{
pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE;
pAd->CommonCfg.TriggerEventTab.EventANo --;
// Need to send 20/40 Coexistence Notify frame if has status change.
bNotify = TRUE;
}
}
}
if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)
{
pAd->CommonCfg.TriggerEventTab.EventBCountDown--;
if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0)
bNotify = TRUE;
}
if (bNotify == TRUE)
Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE);
}
#endif // DOT11N_DRAFT3 //
#endif // DOT11_N_SUPPORT //
// IRQL = DISPATCH_LEVEL
VOID BssTableSsidSort(
IN PRTMP_ADAPTER pAd,
OUT BSS_TABLE *OutTab,
IN CHAR Ssid[],
IN UCHAR SsidLen)
{
INT i;
BssTableInit(OutTab);
for (i = 0; i < pAd->ScanTab.BssNr; i++)
{
BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i];
BOOLEAN bIsHiddenApIncluded = FALSE;
if (((pAd->CommonCfg.bIEEE80211H == 1) &&
(pAd->MlmeAux.Channel > 14) &&
RadarChannelCheck(pAd, pInBss->Channel))
#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier
|| (pAd->CommonCfg.CarrierDetect.Enable == TRUE)
#endif // CARRIER_DETECTION_SUPPORT //
)
{
if (pInBss->Hidden)
bIsHiddenApIncluded = TRUE;
}
if ((pInBss->BssType == pAd->StaCfg.BssType) &&
(SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded))
{
BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
#ifdef EXT_BUILD_CHANNEL_LIST
// If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict.
if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) &&
(pInBss->bHasCountryIE == FALSE))
{
DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n"));
continue;
}
#endif // EXT_BUILD_CHANNEL_LIST //
#ifdef DOT11_N_SUPPORT
// 2.4G/5G N only mode
if ((pInBss->HtCapabilityLen == 0) &&
((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G)))
{
DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
continue;
}
#endif // DOT11_N_SUPPORT //
// New for WPA2
// Check the Authmode first
if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)
{
// Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux))
// None matched
continue;
// Check cipher suite, AP must have more secured cipher than station setting
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
{
// If it's not mixed mode, we should only let BSS pass with the same encryption
if (pInBss->WPA.bMixMode == FALSE)
if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher)
continue;
// check group cipher
if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) &&
(pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) &&
(pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled))
continue;
// check pairwise cipher, skip if none matched
// If profile set to AES, let it pass without question.
// If profile set to TKIP, we must find one mateched
if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
(pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) &&
(pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux))
continue;
}
else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
{
// If it's not mixed mode, we should only let BSS pass with the same encryption
if (pInBss->WPA2.bMixMode == FALSE)
if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher)
continue;
// check group cipher
if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) &&
(pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) &&
(pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled))
continue;
// check pairwise cipher, skip if none matched
// If profile set to AES, let it pass without question.
// If profile set to TKIP, we must find one mateched
if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
(pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) &&
(pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux))
continue;
}
}
// Bss Type matched, SSID matched.
// We will check wepstatus for qualification Bss
else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
{
DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus));
//
// For the SESv2 case, we will not qualify WepStatus.
//
if (!pInBss->bSES)
continue;
}
// Since the AP is using hidden SSID, and we are trying to connect to ANY
// It definitely will fail. So, skip it.
// CCX also require not even try to connect it!!
if (SsidLen == 0)
continue;
#ifdef DOT11_N_SUPPORT
// If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
// If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
if ((pInBss->CentralChannel != pInBss->Channel) &&
(pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40))
{
if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE)
{
pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20;
SetCommonHT(pAd);
pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40;
}
else
{
if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20)
{
SetCommonHT(pAd);
}
}
}
#endif // DOT11_N_SUPPORT //
// copy matching BSS from InTab to OutTab
NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
OutTab->BssNr++;
}
else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0))
{
BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
#ifdef DOT11_N_SUPPORT
// 2.4G/5G N only mode
if ((pInBss->HtCapabilityLen == 0) &&
((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G)))
{
DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
continue;
}
#endif // DOT11_N_SUPPORT //
// New for WPA2
// Check the Authmode first
if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)
{
// Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux))
// None matched
continue;
// Check cipher suite, AP must have more secured cipher than station setting
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
{
// If it's not mixed mode, we should only let BSS pass with the same encryption
if (pInBss->WPA.bMixMode == FALSE)
if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher)
continue;
// check group cipher
if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher)
continue;
// check pairwise cipher, skip if none matched
// If profile set to AES, let it pass without question.
// If profile set to TKIP, we must find one mateched
if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
(pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) &&
(pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux))
continue;
}
else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
{
// If it's not mixed mode, we should only let BSS pass with the same encryption
if (pInBss->WPA2.bMixMode == FALSE)
if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher)
continue;
// check group cipher
if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher)
continue;
// check pairwise cipher, skip if none matched
// If profile set to AES, let it pass without question.
// If profile set to TKIP, we must find one mateched
if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
(pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) &&
(pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux))
continue;
}
}
// Bss Type matched, SSID matched.
// We will check wepstatus for qualification Bss
else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
continue;
#ifdef DOT11_N_SUPPORT
// If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
// If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
if ((pInBss->CentralChannel != pInBss->Channel) &&
(pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40))
{
if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE)
{
pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20;
SetCommonHT(pAd);
pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40;
}
}
#endif // DOT11_N_SUPPORT //
// copy matching BSS from InTab to OutTab
NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
OutTab->BssNr++;
}
if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
break;
}
BssTableSortByRssi(OutTab);
}
// IRQL = DISPATCH_LEVEL
VOID BssTableSortByRssi(
IN OUT BSS_TABLE *OutTab)
{
INT i, j;
BSS_ENTRY TmpBss;
for (i = 0; i < OutTab->BssNr - 1; i++)
{
for (j = i+1; j < OutTab->BssNr; j++)
{
if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi)
{
NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY));
NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY));
NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY));
}
}
}
}
#endif // CONFIG_STA_SUPPORT //
VOID BssCipherParse(
IN OUT PBSS_ENTRY pBss)
{
PEID_STRUCT pEid;
PUCHAR pTmp;
PRSN_IE_HEADER_STRUCT pRsnHeader;
PCIPHER_SUITE_STRUCT pCipher;
PAKM_SUITE_STRUCT pAKM;
USHORT Count;
INT Length;
NDIS_802_11_ENCRYPTION_STATUS TmpCipher;
//
// WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame.
//
if (pBss->Privacy)
{
pBss->WepStatus = Ndis802_11WEPEnabled;
}
else
{
pBss->WepStatus = Ndis802_11WEPDisabled;
}
// Set default to disable & open authentication before parsing variable IE
pBss->AuthMode = Ndis802_11AuthModeOpen;
pBss->AuthModeAux = Ndis802_11AuthModeOpen;
// Init WPA setting
pBss->WPA.PairCipher = Ndis802_11WEPDisabled;
pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
pBss->WPA.GroupCipher = Ndis802_11WEPDisabled;
pBss->WPA.RsnCapability = 0;
pBss->WPA.bMixMode = FALSE;
// Init WPA2 setting
pBss->WPA2.PairCipher = Ndis802_11WEPDisabled;
pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled;
pBss->WPA2.RsnCapability = 0;
pBss->WPA2.bMixMode = FALSE;
Length = (INT) pBss->VarIELen;
while (Length > 0)
{
// Parse cipher suite base on WPA1 & WPA2, they should be parsed differently
pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length;
pEid = (PEID_STRUCT) pTmp;
switch (pEid->Eid)
{
case IE_WPA:
if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7))
{
pBss->bSES = TRUE;
break;
}
else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1)
{
// if unsupported vendor specific IE
break;
}
// Skip OUI, version, and multicast suite
// This part should be improved in the future when AP supported multiple cipher suite.
// For now, it's OK since almost all APs have fixed cipher suite supported.
// pTmp = (PUCHAR) pEid->Octet;
pTmp += 11;
// Cipher Suite Selectors from Spec P802.11i/D3.2 P26.
// Value Meaning
// 0 None
// 1 WEP-40
// 2 Tkip
// 3 WRAP
// 4 AES
// 5 WEP-104
// Parse group cipher
switch (*pTmp)
{
case 1:
pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled;
break;
case 5:
pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled;
break;
case 2:
pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled;
break;
case 4:
pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled;
break;
default:
break;
}
// number of unicast suite
pTmp += 1;
// skip all unicast cipher suites
//Count = *(PUSHORT) pTmp;
Count = (pTmp[1]<<8) + pTmp[0];
pTmp += sizeof(USHORT);
// Parsing all unicast cipher suite
while (Count > 0)
{
// Skip OUI
pTmp += 3;
TmpCipher = Ndis802_11WEPDisabled;
switch (*pTmp)
{
case 1:
case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
TmpCipher = Ndis802_11Encryption1Enabled;
break;
case 2:
TmpCipher = Ndis802_11Encryption2Enabled;
break;
case 4:
TmpCipher = Ndis802_11Encryption3Enabled;
break;
default:
break;
}
if (TmpCipher > pBss->WPA.PairCipher)
{
// Move the lower cipher suite to PairCipherAux
pBss->WPA.PairCipherAux = pBss->WPA.PairCipher;
pBss->WPA.PairCipher = TmpCipher;
}
else
{
pBss->WPA.PairCipherAux = TmpCipher;
}
pTmp++;
Count--;
}
// 4. get AKM suite counts
//Count = *(PUSHORT) pTmp;
Count = (pTmp[1]<<8) + pTmp[0];
pTmp += sizeof(USHORT);
pTmp += 3;
switch (*pTmp)
{
case 1:
// Set AP support WPA-enterprise mode
if (pBss->AuthMode == Ndis802_11AuthModeOpen)
pBss->AuthMode = Ndis802_11AuthModeWPA;
else
pBss->AuthModeAux = Ndis802_11AuthModeWPA;
break;
case 2:
// Set AP support WPA-PSK mode
if (pBss->AuthMode == Ndis802_11AuthModeOpen)
pBss->AuthMode = Ndis802_11AuthModeWPAPSK;
else
pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK;
break;
default:
break;
}
pTmp += 1;
// Fixed for WPA-None
if (pBss->BssType == BSS_ADHOC)
{
pBss->AuthMode = Ndis802_11AuthModeWPANone;
pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
pBss->WepStatus = pBss->WPA.GroupCipher;
// Patched bugs for old driver
if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled)
pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher;
}
else
pBss->WepStatus = pBss->WPA.PairCipher;
// Check the Pair & Group, if different, turn on mixed mode flag
if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher)
pBss->WPA.bMixMode = TRUE;
break;
case IE_RSN:
pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp;
// 0. Version must be 1
if (le2cpu16(pRsnHeader->Version) != 1)
break;
pTmp += sizeof(RSN_IE_HEADER_STRUCT);
// 1. Check group cipher
pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
break;
// Parse group cipher
switch (pCipher->Type)
{
case 1:
pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled;
break;
case 5:
pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled;
break;
case 2:
pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled;
break;
case 4:
pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled;
break;
default:
break;
}
// set to correct offset for next parsing
pTmp += sizeof(CIPHER_SUITE_STRUCT);
// 2. Get pairwise cipher counts
//Count = *(PUSHORT) pTmp;
Count = (pTmp[1]<<8) + pTmp[0];
pTmp += sizeof(USHORT);
// 3. Get pairwise cipher
// Parsing all unicast cipher suite
while (Count > 0)
{
// Skip OUI
pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
TmpCipher = Ndis802_11WEPDisabled;
switch (pCipher->Type)
{
case 1:
case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
TmpCipher = Ndis802_11Encryption1Enabled;
break;
case 2:
TmpCipher = Ndis802_11Encryption2Enabled;
break;
case 4:
TmpCipher = Ndis802_11Encryption3Enabled;
break;
default:
break;
}
if (TmpCipher > pBss->WPA2.PairCipher)
{
// Move the lower cipher suite to PairCipherAux
pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher;
pBss->WPA2.PairCipher = TmpCipher;
}
else
{
pBss->WPA2.PairCipherAux = TmpCipher;
}
pTmp += sizeof(CIPHER_SUITE_STRUCT);
Count--;
}
// 4. get AKM suite counts
//Count = *(PUSHORT) pTmp;
Count = (pTmp[1]<<8) + pTmp[0];
pTmp += sizeof(USHORT);
// 5. Get AKM ciphers
// Parsing all AKM ciphers
while (Count > 0)
{
pAKM = (PAKM_SUITE_STRUCT) pTmp;
if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
break;
switch (pAKM->Type)
{
case 1:
// Set AP support WPA-enterprise mode
if (pBss->AuthMode == Ndis802_11AuthModeOpen)
pBss->AuthMode = Ndis802_11AuthModeWPA2;
else
pBss->AuthModeAux = Ndis802_11AuthModeWPA2;
break;
case 2:
// Set AP support WPA-PSK mode
if (pBss->AuthMode == Ndis802_11AuthModeOpen)
pBss->AuthMode = Ndis802_11AuthModeWPA2PSK;
else
pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK;
break;
default:
if (pBss->AuthMode == Ndis802_11AuthModeOpen)
pBss->AuthMode = Ndis802_11AuthModeMax;
else
pBss->AuthModeAux = Ndis802_11AuthModeMax;
break;
}
pTmp += (Count * sizeof(AKM_SUITE_STRUCT));
Count--;
}
// Fixed for WPA-None
if (pBss->BssType == BSS_ADHOC)
{
pBss->AuthMode = Ndis802_11AuthModeWPANone;
pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux;
pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher;
pBss->WepStatus = pBss->WPA.GroupCipher;
// Patched bugs for old driver
if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled)
pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher;
}
pBss->WepStatus = pBss->WPA2.PairCipher;
// 6. Get RSN capability
//pBss->WPA2.RsnCapability = *(PUSHORT) pTmp;
pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0];
pTmp += sizeof(USHORT);
// Check the Pair & Group, if different, turn on mixed mode flag
if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
pBss->WPA2.bMixMode = TRUE;
break;
default:
break;
}
Length -= (pEid->Len + 2);
}
}
// ===========================================================================================
// mac_table.c
// ===========================================================================================
/*! \brief generates a random mac address value for IBSS BSSID
* \param Addr the bssid location
* \return none
* \pre
* \post
*/
VOID MacAddrRandomBssid(
IN PRTMP_ADAPTER pAd,
OUT PUCHAR pAddr)
{
INT i;
for (i = 0; i < MAC_ADDR_LEN; i++)
{
pAddr[i] = RandomByte(pAd);
}
pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx
}
/*! \brief init the management mac frame header
* \param p_hdr mac header
* \param subtype subtype of the frame
* \param p_ds destination address, don't care if it is a broadcast address
* \return none
* \pre the station has the following information in the pAd->StaCfg
* - bssid
* - station address
* \post
* \note this function initializes the following field
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
*/
VOID MgtMacHeaderInit(
IN PRTMP_ADAPTER pAd,
IN OUT PHEADER_802_11 pHdr80211,
IN UCHAR SubType,
IN UCHAR ToDs,
IN PUCHAR pDA,
IN PUCHAR pBssid)
{
NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
pHdr80211->FC.Type = BTYPE_MGMT;
pHdr80211->FC.SubType = SubType;
// if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type
// pHdr80211->FC.Type = BTYPE_CNTL;
pHdr80211->FC.ToDs = ToDs;
COPY_MAC_ADDR(pHdr80211->Addr1, pDA);
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
#endif // CONFIG_STA_SUPPORT //
COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
}
// ===========================================================================================
// mem_mgmt.c
// ===========================================================================================
/*!***************************************************************************
* This routine build an outgoing frame, and fill all information specified
* in argument list to the frame body. The actual frame size is the summation
* of all arguments.
* input params:
* Buffer - pointer to a pre-allocated memory segment
* args - a list of <int arg_size, arg> pairs.
* NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this
* function will FAIL!!!
* return:
* Size of the buffer
* usage:
* MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
****************************************************************************/
ULONG MakeOutgoingFrame(
OUT UCHAR *Buffer,
OUT ULONG *FrameLen, ...)
{
UCHAR *p;
int leng;
ULONG TotLeng;
va_list Args;
// calculates the total length
TotLeng = 0;
va_start(Args, FrameLen);
do
{
leng = va_arg(Args, int);
if (leng == END_OF_ARGS)
{
break;
}
p = va_arg(Args, PVOID);
NdisMoveMemory(&Buffer[TotLeng], p, leng);
TotLeng = TotLeng + leng;
} while(TRUE);
va_end(Args); /* clean up */
*FrameLen = TotLeng;
return TotLeng;
}
// ===========================================================================================
// mlme_queue.c
// ===========================================================================================
/*! \brief Initialize The MLME Queue, used by MLME Functions
* \param *Queue The MLME Queue
* \return Always Return NDIS_STATE_SUCCESS in this implementation
* \pre
* \post
* \note Because this is done only once (at the init stage), no need to be locked
IRQL = PASSIVE_LEVEL
*/
NDIS_STATUS MlmeQueueInit(
IN MLME_QUEUE *Queue)
{
INT i;
NdisAllocateSpinLock(&Queue->Lock);
Queue->Num = 0;
Queue->Head = 0;
Queue->Tail = 0;
for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++)
{
Queue->Entry[i].Occupied = FALSE;
Queue->Entry[i].MsgLen = 0;
NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE);
}
return NDIS_STATUS_SUCCESS;
}
/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
* \param *Queue The MLME Queue
* \param Machine The State Machine Id
* \param MsgType The Message Type
* \param MsgLen The Message length
* \param *Msg The message pointer
* \return TRUE if enqueue is successful, FALSE if the queue is full
* \pre
* \post
* \note The message has to be initialized
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
*/
BOOLEAN MlmeEnqueue(
IN PRTMP_ADAPTER pAd,
IN ULONG Machine,
IN ULONG MsgType,
IN ULONG MsgLen,
IN VOID *Msg)
{
INT Tail;
MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
// 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_NIC_NOT_EXIST))
return FALSE;
// First check the size, it MUST not exceed the mlme queue size
if (MsgLen > MGMT_DMA_BUFFER_SIZE)
{
DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen));
return FALSE;
}
if (MlmeQueueFull(Queue))
{
return FALSE;
}
NdisAcquireSpinLock(&(Queue->Lock));
Tail = Queue->Tail;
Queue->Tail++;
Queue->Num++;
if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
{
Queue->Tail = 0;
}
Queue->Entry[Tail].Wcid = RESERVED_WCID;
Queue->Entry[Tail].Occupied = TRUE;
Queue->Entry[Tail].Machine = Machine;
Queue->Entry[Tail].MsgType = MsgType;
Queue->Entry[Tail].MsgLen = MsgLen;
if (Msg != NULL)
{
NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
}
NdisReleaseSpinLock(&(Queue->Lock));
return TRUE;
}
/*! \brief This function is used when Recv gets a MLME message
* \param *Queue The MLME Queue
* \param TimeStampHigh The upper 32 bit of timestamp
* \param TimeStampLow The lower 32 bit of timestamp
* \param Rssi The receiving RSSI strength
* \param MsgLen The length of the message
* \param *Msg The message pointer
* \return TRUE if everything ok, FALSE otherwise (like Queue Full)
* \pre
* \post
IRQL = DISPATCH_LEVEL
*/
BOOLEAN MlmeEnqueueForRecv(
IN PRTMP_ADAPTER pAd,
IN ULONG Wcid,
IN ULONG TimeStampHigh,
IN ULONG TimeStampLow,
IN UCHAR Rssi0,
IN UCHAR Rssi1,
IN UCHAR Rssi2,
IN ULONG MsgLen,
IN VOID *Msg,
IN UCHAR Signal)
{
INT Tail, Machine;
PFRAME_802_11 pFrame = (PFRAME_802_11)Msg;
INT MsgType;
MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
#ifdef RALINK_ATE
/* Nothing to do in ATE mode */
if(ATE_ON(pAd))
return FALSE;
#endif // RALINK_ATE //
// 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_NIC_NOT_EXIST))
{
DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
return FALSE;
}
// First check the size, it MUST not exceed the mlme queue size
if (MsgLen > MGMT_DMA_BUFFER_SIZE)
{
DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
return FALSE;
}
if (MlmeQueueFull(Queue))
{
return FALSE;
}
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType))
{
DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType));
return FALSE;
}
}
#endif // CONFIG_STA_SUPPORT //
// OK, we got all the informations, it is time to put things into queue
NdisAcquireSpinLock(&(Queue->Lock));
Tail = Queue->Tail;
Queue->Tail++;
Queue->Num++;
if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
{
Queue->Tail = 0;
}
Queue->Entry[Tail].Occupied = TRUE;
Queue->Entry[Tail].Machine = Machine;
Queue->Entry[Tail].MsgType = MsgType;
Queue->Entry[Tail].MsgLen = MsgLen;
Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
Queue->Entry[Tail].Rssi0 = Rssi0;
Queue->Entry[Tail].Rssi1 = Rssi1;
Queue->Entry[Tail].Rssi2 = Rssi2;
Queue->Entry[Tail].Signal = Signal;
Queue->Entry[Tail].Wcid = (UCHAR)Wcid;
Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;
if (Msg != NULL)
{
NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
}
NdisReleaseSpinLock(&(Queue->Lock));
RTMP_MLME_HANDLER(pAd);
return TRUE;
}
/*! \brief Dequeue a message from the MLME Queue
* \param *Queue The MLME Queue
* \param *Elem The message dequeued from MLME Queue
* \return TRUE if the Elem contains something, FALSE otherwise
* \pre
* \post
IRQL = DISPATCH_LEVEL
*/
BOOLEAN MlmeDequeue(
IN MLME_QUEUE *Queue,
OUT MLME_QUEUE_ELEM **Elem)
{
NdisAcquireSpinLock(&(Queue->Lock));
*Elem = &(Queue->Entry[Queue->Head]);
Queue->Num--;
Queue->Head++;
if (Queue->Head == MAX_LEN_OF_MLME_QUEUE)
{
Queue->Head = 0;
}
NdisReleaseSpinLock(&(Queue->Lock));
return TRUE;
}
// IRQL = DISPATCH_LEVEL
VOID MlmeRestartStateMachine(
IN PRTMP_ADAPTER pAd)
{
#ifdef RTMP_MAC_PCI
MLME_QUEUE_ELEM *Elem = NULL;
#endif // RTMP_MAC_PCI //
#ifdef CONFIG_STA_SUPPORT
BOOLEAN Cancelled;
#endif // CONFIG_STA_SUPPORT //
DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
#ifdef RTMP_MAC_PCI
NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
if(pAd->Mlme.bRunning)
{
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
return;
}
else
{
pAd->Mlme.bRunning = TRUE;
}
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
// Remove all Mlme queues elements
while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
{
//From message type, determine which state machine I should drive
if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
{
// free MLME element
Elem->Occupied = FALSE;
Elem->MsgLen = 0;
}
else {
DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
}
}
#endif // RTMP_MAC_PCI //
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
#ifdef QOS_DLS_SUPPORT
UCHAR i;
#endif // QOS_DLS_SUPPORT //
// Cancel all timer events
// Be careful to cancel new added timer
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 QOS_DLS_SUPPORT
for (i=0; i<MAX_NUM_OF_DLS_ENTRY; i++)
{
RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &Cancelled);
}
#endif // QOS_DLS_SUPPORT //
}
#endif // CONFIG_STA_SUPPORT //
// Change back to original channel in case of doing scan
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
// Resume MSDU which is turned off durning scan
RTMPResumeMsduTransmission(pAd);
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
// Set all state machines back IDLE
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
pAd->Mlme.ActMachine.CurrState = ACT_IDLE;
#ifdef QOS_DLS_SUPPORT
pAd->Mlme.DlsMachine.CurrState = DLS_IDLE;
#endif // QOS_DLS_SUPPORT //
}
#endif // CONFIG_STA_SUPPORT //
#ifdef RTMP_MAC_PCI
// Remove running state
NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
pAd->Mlme.bRunning = FALSE;
NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
#endif // RTMP_MAC_PCI //
}
/*! \brief test if the MLME Queue is empty
* \param *Queue The MLME Queue
* \return TRUE if the Queue is empty, FALSE otherwise
* \pre
* \post
IRQL = DISPATCH_LEVEL
*/
BOOLEAN MlmeQueueEmpty(
IN MLME_QUEUE *Queue)
{
BOOLEAN Ans;
NdisAcquireSpinLock(&(Queue->Lock));
Ans = (Queue->Num == 0);
NdisReleaseSpinLock(&(Queue->Lock));
return Ans;
}
/*! \brief test if the MLME Queue is full
* \param *Queue The MLME Queue
* \return TRUE if the Queue is empty, FALSE otherwise
* \pre
* \post
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
*/
BOOLEAN MlmeQueueFull(
IN MLME_QUEUE *Queue)
{
BOOLEAN Ans;
NdisAcquireSpinLock(&(Queue->Lock));
Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied);
NdisReleaseSpinLock(&(Queue->Lock));
return Ans;
}
/*! \brief The destructor of MLME Queue
* \param
* \return
* \pre
* \post
* \note Clear Mlme Queue, Set Queue->Num to Zero.
IRQL = PASSIVE_LEVEL
*/
VOID MlmeQueueDestroy(
IN MLME_QUEUE *pQueue)
{
NdisAcquireSpinLock(&(pQueue->Lock));
pQueue->Num = 0;
pQueue->Head = 0;
pQueue->Tail = 0;
NdisReleaseSpinLock(&(pQueue->Lock));
NdisFreeSpinLock(&(pQueue->Lock));
}
/*! \brief To substitute the message type if the message is coming from external
* \param pFrame The frame received
* \param *Machine The state machine
* \param *MsgType the message type for the state machine
* \return TRUE if the substitution is successful, FALSE otherwise
* \pre
* \post
IRQL = DISPATCH_LEVEL
*/
#ifdef CONFIG_STA_SUPPORT
BOOLEAN MsgTypeSubst(
IN PRTMP_ADAPTER pAd,
IN PFRAME_802_11 pFrame,
OUT INT *Machine,
OUT INT *MsgType)
{
USHORT Seq, Alg;
UCHAR EAPType;
PUCHAR pData;
// Pointer to start of data frames including SNAP header
pData = (PUCHAR) pFrame + LENGTH_802_11;
// The only data type will pass to this function is EAPOL frame
if (pFrame->Hdr.FC.Type == BTYPE_DATA)
{
{
*Machine = WPA_STATE_MACHINE;
EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1);
return (WpaMsgTypeSubst(EAPType, (INT *) MsgType));
}
}
switch (pFrame->Hdr.FC.SubType)
{
case SUBTYPE_ASSOC_REQ:
*Machine = ASSOC_STATE_MACHINE;
*MsgType = MT2_PEER_ASSOC_REQ;
break;
case SUBTYPE_ASSOC_RSP:
*Machine = ASSOC_STATE_MACHINE;
*MsgType = MT2_PEER_ASSOC_RSP;
break;
case SUBTYPE_REASSOC_REQ:
*Machine = ASSOC_STATE_MACHINE;
*MsgType = MT2_PEER_REASSOC_REQ;
break;
case SUBTYPE_REASSOC_RSP:
*Machine = ASSOC_STATE_MACHINE;
*MsgType = MT2_PEER_REASSOC_RSP;
break;
case SUBTYPE_PROBE_REQ:
*Machine = SYNC_STATE_MACHINE;
*MsgType = MT2_PEER_PROBE_REQ;
break;
case SUBTYPE_PROBE_RSP:
*Machine = SYNC_STATE_MACHINE;
*MsgType = MT2_PEER_PROBE_RSP;
break;
case SUBTYPE_BEACON:
*Machine = SYNC_STATE_MACHINE;
*MsgType = MT2_PEER_BEACON;
break;
case SUBTYPE_ATIM:
*Machine = SYNC_STATE_MACHINE;
*MsgType = MT2_PEER_ATIM;
break;
case SUBTYPE_DISASSOC:
*Machine = ASSOC_STATE_MACHINE;
*MsgType = MT2_PEER_DISASSOC_REQ;
break;
case SUBTYPE_AUTH:
// get the sequence number from payload 24 Mac Header + 2 bytes algorithm
NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT));
NdisMoveMemory(&Alg, &pFrame->Octet[0], sizeof(USHORT));
if (Seq == 1 || Seq == 3)
{
*Machine = AUTH_RSP_STATE_MACHINE;
*MsgType = MT2_PEER_AUTH_ODD;
}
else if (Seq == 2 || Seq == 4)
{
if (Alg == AUTH_MODE_OPEN || Alg == AUTH_MODE_KEY)
{
*Machine = AUTH_STATE_MACHINE;
*MsgType = MT2_PEER_AUTH_EVEN;
}
}
else
{
return FALSE;
}
break;
case SUBTYPE_DEAUTH:
*Machine = AUTH_RSP_STATE_MACHINE;
*MsgType = MT2_PEER_DEAUTH;
break;
case SUBTYPE_ACTION:
*Machine = ACTION_STATE_MACHINE;
// Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support
if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG)
{
*MsgType = MT2_ACT_INVALID;
}
else
{
*MsgType = (pFrame->Octet[0]&0x7F);
}
break;
default:
return FALSE;
break;
}
return TRUE;
}
#endif // CONFIG_STA_SUPPORT //
// ===========================================================================================
// state_machine.c
// ===========================================================================================
/*! \brief Initialize the state machine.
* \param *S pointer to the state machine
* \param Trans State machine transition function
* \param StNr number of states
* \param MsgNr number of messages
* \param DefFunc default function, when there is invalid state/message combination
* \param InitState initial state of the state machine
* \param Base StateMachine base, internal use only
* \pre p_sm should be a legal pointer
* \post
IRQL = PASSIVE_LEVEL
*/
VOID StateMachineInit(
IN STATE_MACHINE *S,
IN STATE_MACHINE_FUNC Trans[],
IN ULONG StNr,
IN ULONG MsgNr,
IN STATE_MACHINE_FUNC DefFunc,
IN ULONG InitState,
IN ULONG Base)
{
ULONG i, j;
// set number of states and messages
S->NrState = StNr;
S->NrMsg = MsgNr;
S->Base = Base;
S->TransFunc = Trans;
// init all state transition to default function
for (i = 0; i < StNr; i++)
{
for (j = 0; j < MsgNr; j++)
{
S->TransFunc[i * MsgNr + j] = DefFunc;
}
}
// set the starting state
S->CurrState = InitState;
}
/*! \brief This function fills in the function pointer into the cell in the state machine
* \param *S pointer to the state machine
* \param St state
* \param Msg incoming message
* \param f the function to be executed when (state, message) combination occurs at the state machine
* \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state
* \post
IRQL = PASSIVE_LEVEL
*/
VOID StateMachineSetAction(
IN STATE_MACHINE *S,
IN ULONG St,
IN ULONG Msg,
IN STATE_MACHINE_FUNC Func)
{
ULONG MsgIdx;
MsgIdx = Msg - S->Base;
if (St < S->NrState && MsgIdx < S->NrMsg)
{
// boundary checking before setting the action
S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
}
}
/*! \brief This function does the state transition
* \param *Adapter the NIC adapter pointer
* \param *S the state machine
* \param *Elem the message to be executed
* \return None
IRQL = DISPATCH_LEVEL
*/
VOID StateMachinePerformAction(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
IN MLME_QUEUE_ELEM *Elem)
{
(*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem);
}
/*
==========================================================================
Description:
The drop function, when machine executes this, the message is simply
ignored. This function does nothing, the message is freed in
StateMachinePerformAction()
==========================================================================
*/
VOID Drop(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
}
// ===========================================================================================
// lfsr.c
// ===========================================================================================
/*
==========================================================================
Description:
IRQL = PASSIVE_LEVEL
==========================================================================
*/
VOID LfsrInit(
IN PRTMP_ADAPTER pAd,
IN ULONG Seed)
{
if (Seed == 0)
pAd->Mlme.ShiftReg = 1;
else
pAd->Mlme.ShiftReg = Seed;
}
/*
==========================================================================
Description:
==========================================================================
*/
UCHAR RandomByte(
IN PRTMP_ADAPTER pAd)
{
ULONG i;
UCHAR R, Result;
R = 0;
if (pAd->Mlme.ShiftReg == 0)
NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg);
for (i = 0; i < 8; i++)
{
if (pAd->Mlme.ShiftReg & 0x00000001)
{
pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
Result = 1;
}
else
{
pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
Result = 0;
}
R = (R << 1) | Result;
}
return R;
}
/*
========================================================================
Routine Description:
Verify the support rate for different PHY type
Arguments:
pAd Pointer to our adapter
Return Value:
None
IRQL = PASSIVE_LEVEL
========================================================================
*/
VOID RTMPCheckRates(
IN PRTMP_ADAPTER pAd,
IN OUT UCHAR SupRate[],
IN OUT UCHAR *SupRateLen)
{
UCHAR RateIdx, i, j;
UCHAR NewRate[12], NewRateLen;
NewRateLen = 0;
if (pAd->CommonCfg.PhyMode == PHY_11B)
RateIdx = 4;
else
RateIdx = 12;
// Check for support rates exclude basic rate bit
for (i = 0; i < *SupRateLen; i++)
for (j = 0; j < RateIdx; j++)
if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
NewRate[NewRateLen++] = SupRate[i];
*SupRateLen = NewRateLen;
NdisMoveMemory(SupRate, NewRate, NewRateLen);
}
#ifdef CONFIG_STA_SUPPORT
#ifdef DOT11_N_SUPPORT
BOOLEAN RTMPCheckChannel(
IN PRTMP_ADAPTER pAd,
IN UCHAR CentralChannel,
IN UCHAR Channel)
{
UCHAR k;
UCHAR UpperChannel = 0, LowerChannel = 0;
UCHAR NoEffectChannelinList = 0;
// Find upper and lower channel according to 40MHz current operation.
if (CentralChannel < Channel)
{
UpperChannel = Channel;
if (CentralChannel > 2)
LowerChannel = CentralChannel - 2;
else
return FALSE;
}
else if (CentralChannel > Channel)
{
UpperChannel = CentralChannel + 2;
LowerChannel = Channel;
}
for (k = 0;k < pAd->ChannelListNum;k++)
{
if (pAd->ChannelList[k].Channel == UpperChannel)
{
NoEffectChannelinList ++;
}
if (pAd->ChannelList[k].Channel == LowerChannel)
{
NoEffectChannelinList ++;
}
}
DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList));
if (NoEffectChannelinList == 2)
return TRUE;
else
return FALSE;
}
/*
========================================================================
Routine Description:
Verify the support rate for HT phy type
Arguments:
pAd Pointer to our adapter
Return Value:
FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode)
IRQL = PASSIVE_LEVEL
========================================================================
*/
BOOLEAN RTMPCheckHt(
IN PRTMP_ADAPTER pAd,
IN UCHAR Wcid,
IN HT_CAPABILITY_IE *pHtCapability,
IN ADD_HT_INFO_IE *pAddHtInfo)
{
if (Wcid >= MAX_LEN_OF_MAC_TABLE)
return FALSE;
// If use AMSDU, set flag.
if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable)
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED);
// Save Peer Capability
if (pHtCapability->HtCapInfo.ShortGIfor20)
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE);
if (pHtCapability->HtCapInfo.ShortGIfor40)
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE);
if (pHtCapability->HtCapInfo.TxSTBC)
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE);
if (pHtCapability->HtCapInfo.RxSTBC)
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE);
if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport)
{
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE);
}
if (Wcid < MAX_LEN_OF_MAC_TABLE)
{
pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity;
}
// Will check ChannelWidth for MCSSet[4] below
pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1;
switch (pAd->CommonCfg.RxStream)
{
case 1:
pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00;
pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
break;
case 2:
pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
break;
case 3:
pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff;
pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
break;
}
pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth;
DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n",
pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth,
pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode));
pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF;
// Send Assoc Req with my HT capability.
pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize;
pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs;
pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20);
pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40);
pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC);
pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC);
pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor;
pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity;
pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC;
pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC;
if (pAd->CommonCfg.bRdg)
{
pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport;
pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1;
}
if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32
COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
return TRUE;
}
#endif // DOT11_N_SUPPORT //
#endif // CONFIG_STA_SUPPORT //
/*
========================================================================
Routine Description:
Verify the support rate for different PHY type
Arguments:
pAd Pointer to our adapter
Return Value:
None
IRQL = PASSIVE_LEVEL
========================================================================
*/
VOID RTMPUpdateMlmeRate(
IN PRTMP_ADAPTER pAd)
{
UCHAR MinimumRate;
UCHAR ProperMlmeRate; //= RATE_54;
UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
BOOLEAN bMatch = FALSE;
switch (pAd->CommonCfg.PhyMode)
{
case PHY_11B:
ProperMlmeRate = RATE_11;
MinimumRate = RATE_1;
break;
case PHY_11BG_MIXED:
#ifdef DOT11_N_SUPPORT
case PHY_11ABGN_MIXED:
case PHY_11BGN_MIXED:
#endif // DOT11_N_SUPPORT //
if ((pAd->MlmeAux.SupRateLen == 4) &&
(pAd->MlmeAux.ExtRateLen == 0))
// B only AP
ProperMlmeRate = RATE_11;
else
ProperMlmeRate = RATE_24;
if (pAd->MlmeAux.Channel <= 14)
MinimumRate = RATE_1;
else
MinimumRate = RATE_6;
break;
case PHY_11A:
#ifdef DOT11_N_SUPPORT
case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n
case PHY_11GN_MIXED:
case PHY_11AGN_MIXED:
case PHY_11AN_MIXED:
case PHY_11N_5G:
#endif // DOT11_N_SUPPORT //
ProperMlmeRate = RATE_24;
MinimumRate = RATE_6;
break;
case PHY_11ABG_MIXED:
ProperMlmeRate = RATE_24;
if (pAd->MlmeAux.Channel <= 14)
MinimumRate = RATE_1;
else
MinimumRate = RATE_6;
break;
default: // error
ProperMlmeRate = RATE_1;
MinimumRate = RATE_1;
break;
}
for (i = 0; i < pAd->MlmeAux.SupRateLen; i++)
{
for (j = 0; j < RateIdx; j++)
{
if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
{
if (j == ProperMlmeRate)
{
bMatch = TRUE;
break;
}
}
}
if (bMatch)
break;
}
if (bMatch == FALSE)
{
for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++)
{
for (j = 0; j < RateIdx; j++)
{
if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j])
{
if (j == ProperMlmeRate)
{
bMatch = TRUE;
break;
}
}
}
if (bMatch)
break;
}
}
if (bMatch == FALSE)
{
ProperMlmeRate = MinimumRate;
}
pAd->CommonCfg.MlmeRate = MinimumRate;
pAd->CommonCfg.RtsRate = ProperMlmeRate;
if (pAd->CommonCfg.MlmeRate >= RATE_6)
{
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM;
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
}
else
{
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate;
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK;
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate;
}
DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word));
}
CHAR RTMPMaxRssi(
IN PRTMP_ADAPTER pAd,
IN CHAR Rssi0,
IN CHAR Rssi1,
IN CHAR Rssi2)
{
CHAR larger = -127;
if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0))
{
larger = Rssi0;
}
if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0))
{
larger = max(Rssi0, Rssi1);
}
if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0))
{
larger = max(larger, Rssi2);
}
if (larger == -127)
larger = 0;
return larger;
}
/*
========================================================================
Routine Description:
Periodic evaluate antenna link status
Arguments:
pAd - Adapter pointer
Return Value:
None
========================================================================
*/
VOID AsicEvaluateRxAnt(
IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_STA_SUPPORT
UCHAR BBPR3 = 0;
#endif // CONFIG_STA_SUPPORT //
#ifdef RALINK_ATE
if (ATE_ON(pAd))
return;
#endif // RALINK_ATE //
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
fRTMP_ADAPTER_HALT_IN_PROGRESS |
fRTMP_ADAPTER_RADIO_OFF |
fRTMP_ADAPTER_NIC_NOT_EXIST |
fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) ||
OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
#ifdef RT3090
|| (pAd->bPCIclkOff == TRUE)
#endif // RT3090 //
#ifdef ANT_DIVERSITY_SUPPORT
|| (pAd->EepromAccess)
#endif // ANT_DIVERSITY_SUPPORT //
)
return;
#ifdef ANT_DIVERSITY_SUPPORT
if ((pAd->NicConfig2.field.AntDiversity) && (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE))
{
// two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove
// one is antenna diversity:there is only one antenna can rx and tx
// the other is failed antenna remove:two physical antenna can rx and tx
DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n",
pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt));
AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt);
pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt
pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE;
pAd->RxAnt.RcvPktNumWhenEvaluate = 0;
// a one-shot timer to end the evalution
// dynamic adjust antenna evaluation period according to the traffic
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100);
else
RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300);
}
else
#endif // ANT_DIVERSITY_SUPPORT //
{
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (pAd->StaCfg.Psm == PWR_SAVE)
return;
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
BBPR3 &= (~0x18);
if(pAd->Antenna.field.RxPath == 3)
{
BBPR3 |= (0x10);
}
else if(pAd->Antenna.field.RxPath == 2)
{
BBPR3 |= (0x8);
}
else if(pAd->Antenna.field.RxPath == 1)
{
BBPR3 |= (0x0);
}
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
#ifdef RTMP_MAC_PCI
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
pAd->StaCfg.BBPR3 = BBPR3;
#endif // RTMP_MAC_PCI //
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
)
{
ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
// dynamic adjust antenna evaluation period according to the traffic
if (TxTotalCnt > 50)
{
RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20);
pAd->Mlme.bLowThroughput = FALSE;
}
else
{
RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300);
pAd->Mlme.bLowThroughput = TRUE;
}
}
}
#endif // CONFIG_STA_SUPPORT //
}
}
/*
========================================================================
Routine Description:
After evaluation, check antenna link status
Arguments:
pAd - Adapter pointer
Return Value:
None
========================================================================
*/
VOID AsicRxAntEvalTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
BOOLEAN bSwapAnt = FALSE;
#ifdef CONFIG_STA_SUPPORT
UCHAR BBPR3 = 0;
CHAR larger = -127, rssi0, rssi1, rssi2;
#endif // CONFIG_STA_SUPPORT //
#ifdef RALINK_ATE
if (ATE_ON(pAd))
return;
#endif // RALINK_ATE //
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
fRTMP_ADAPTER_HALT_IN_PROGRESS |
fRTMP_ADAPTER_RADIO_OFF |
fRTMP_ADAPTER_NIC_NOT_EXIST) ||
OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
#ifdef RT3090
|| (pAd->bPCIclkOff == TRUE)
#endif // RT3090 //
#ifdef ANT_DIVERSITY_SUPPORT
|| (pAd->EepromAccess)
#endif // ANT_DIVERSITY_SUPPORT //
)
return;
#ifdef ANT_DIVERSITY_SUPPORT
if ((pAd->NicConfig2.field.AntDiversity) && (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE))
{
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt]))
bSwapAnt = TRUE;
#endif // CONFIG_STA_SUPPORT //
if (bSwapAnt == TRUE)
{
UCHAR temp;
//
// select PrimaryRxAntPair
// Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair.
// Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt
//
temp = pAd->RxAnt.Pair1PrimaryRxAnt;
pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt;
pAd->RxAnt.Pair1SecondaryRxAnt = temp;
#ifdef CONFIG_STA_SUPPORT
pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3);
#endif // CONFIG_STA_SUPPORT //
// pAd->RxAnt.EvaluateStableCnt = 0;
}
else
{
// if the evaluated antenna is not better than original, switch back to original antenna
AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt);
pAd->RxAnt.EvaluateStableCnt ++;
}
pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt
#ifdef CONFIG_STA_SUPPORT
DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n",
pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate));
#endif // CONFIG_STA_SUPPORT //
}
else
#endif // ANT_DIVERSITY_SUPPORT //
{
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (pAd->StaCfg.Psm == PWR_SAVE)
return;
// if the traffic is low, use average rssi as the criteria
if (pAd->Mlme.bLowThroughput == TRUE)
{
rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
}
else
{
rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
}
if(pAd->Antenna.field.RxPath == 3)
{
larger = max(rssi0, rssi1);
if (larger > (rssi2 + 20))
pAd->Mlme.RealRxPath = 2;
else
pAd->Mlme.RealRxPath = 3;
}
else if(pAd->Antenna.field.RxPath == 2)
{
if (rssi0 > (rssi1 + 20))
pAd->Mlme.RealRxPath = 1;
else
pAd->Mlme.RealRxPath = 2;
}
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
BBPR3 &= (~0x18);
if(pAd->Mlme.RealRxPath == 3)
{
BBPR3 |= (0x10);
}
else if(pAd->Mlme.RealRxPath == 2)
{
BBPR3 |= (0x8);
}
else if(pAd->Mlme.RealRxPath == 1)
{
BBPR3 |= (0x0);
}
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
#ifdef RTMP_MAC_PCI
pAd->StaCfg.BBPR3 = BBPR3;
#endif // RTMP_MAC_PCI //
}
#endif // CONFIG_STA_SUPPORT //
}
}
VOID APSDPeriodicExec(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
return;
pAd->CommonCfg.TriggerTimerCount++;
// Driver should not send trigger frame, it should be send by application layer
/*
if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable
&& (pAd->CommonCfg.bNeedSendTriggerFrame ||
(((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO))))
{
DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n"));
RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
pAd->CommonCfg.bNeedSendTriggerFrame = FALSE;
pAd->CommonCfg.TriggerTimerCount = 0;
pAd->CommonCfg.bInServicePeriod = TRUE;
}*/
}
/*
========================================================================
Routine Description:
Set/reset MAC registers according to bPiggyBack parameter
Arguments:
pAd - Adapter pointer
bPiggyBack - Enable / Disable Piggy-Back
Return Value:
None
========================================================================
*/
VOID RTMPSetPiggyBack(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN bPiggyBack)
{
TX_LINK_CFG_STRUC TxLinkCfg;
RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
TxLinkCfg.field.TxCFAckEn = bPiggyBack;
RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
}
/*
========================================================================
Routine Description:
check if this entry need to switch rate automatically
Arguments:
pAd
pEntry
Return Value:
TURE
FALSE
========================================================================
*/
BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pEntry)
{
BOOLEAN result = TRUE;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
// only associated STA counts
if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC))
{
result = pAd->StaCfg.bAutoTxRateSwitch;
}
else
result = FALSE;
#ifdef QOS_DLS_SUPPORT
if (pEntry && (pEntry->ValidAsDls))
result = pAd->StaCfg.bAutoTxRateSwitch;
#endif // QOS_DLS_SUPPORT //
}
#endif // CONFIG_STA_SUPPORT //
return result;
}
BOOLEAN RTMPAutoRateSwitchCheck(
IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (pAd->StaCfg.bAutoTxRateSwitch)
return TRUE;
}
#endif // CONFIG_STA_SUPPORT //
return FALSE;
}
/*
========================================================================
Routine Description:
check if this entry need to fix tx legacy rate
Arguments:
pAd
pEntry
Return Value:
TURE
FALSE
========================================================================
*/
UCHAR RTMPStaFixedTxMode(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pEntry)
{
UCHAR tx_mode = FIXED_TXMODE_HT;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode;
}
#endif // CONFIG_STA_SUPPORT //
return tx_mode;
}
/*
========================================================================
Routine Description:
Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.
Arguments:
pAd
pEntry
Return Value:
TURE
FALSE
========================================================================
*/
VOID RTMPUpdateLegacyTxSetting(
UCHAR fixed_tx_mode,
PMAC_TABLE_ENTRY pEntry)
{
HTTRANSMIT_SETTING TransmitSetting;
if (fixed_tx_mode == FIXED_TXMODE_HT)
return;
TransmitSetting.word = 0;
TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;
if (fixed_tx_mode == FIXED_TXMODE_CCK)
{
TransmitSetting.field.MODE = MODE_CCK;
// CCK mode allow MCS 0~3
if (TransmitSetting.field.MCS > MCS_3)
TransmitSetting.field.MCS = MCS_3;
}
else
{
TransmitSetting.field.MODE = MODE_OFDM;
// OFDM mode allow MCS 0~7
if (TransmitSetting.field.MCS > MCS_7)
TransmitSetting.field.MCS = MCS_7;
}
if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE)
{
pEntry->HTPhyMode.word = TransmitSetting.word;
DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n",
pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS));
}
}
#ifdef CONFIG_STA_SUPPORT
/*
==========================================================================
Description:
dynamic tune BBP R66 to find a balance between sensibility and
noise isolation
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AsicStaBbpTuning(
IN PRTMP_ADAPTER pAd)
{
UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30;
CHAR Rssi;
// 2860C did not support Fase CCA, therefore can't tune
if (pAd->MACVersion == 0x28600100)
return;
//
// work as a STA
//
if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING
return;
if ((pAd->OpMode == OPMODE_STA)
&& (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
)
&& !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
#ifdef RTMP_MAC_PCI
&& (pAd->bPCIclkOff == FALSE)
#endif // RTMP_MAC_PCI //
)
{
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
R66 = OrigR66Value;
if (pAd->Antenna.field.RxPath > 1)
Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
else
Rssi = pAd->StaCfg.RssiSample.AvgRssi0;
if (pAd->LatchRfRegs.Channel <= 14)
{ //BG band
#ifdef RT30xx
// RT3070 is a no LNA solution, it should have different control regarding to AGC gain control
// Otherwise, it will have some throughput side effect when low RSSI
if (IS_RT3070(pAd)||IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
{
if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
{
R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
else
{
R66 = 0x1C + 2*GET_LNA_GAIN(pAd);
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
}
else
#endif // RT30xx //
{
if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
{
R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
else
{
R66 = 0x2E + GET_LNA_GAIN(pAd);
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
}
}
else
{ //A band
if (pAd->CommonCfg.BBPCurrentBW == BW_20)
{
if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
{
R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
else
{
R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
}
else
{
if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
{
R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
else
{
R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3;
if (OrigR66Value != R66)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
}
}
}
}
#endif // CONFIG_STA_SUPPORT //
VOID RTMPSetAGCInitValue(
IN PRTMP_ADAPTER pAd,
IN UCHAR BandWidth)
{
UCHAR R66 = 0x30;
if (pAd->LatchRfRegs.Channel <= 14)
{ // BG band
#ifdef RT30xx
/* Gary was verified Amazon AP and find that RT307x has BBP_R66 invalid default value */
if (IS_RT3070(pAd)||IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
{
R66 = 0x1C + 2*GET_LNA_GAIN(pAd);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
else
#endif // RT30xx //
{
R66 = 0x2E + GET_LNA_GAIN(pAd);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
}
else
{ //A band
{
if (BandWidth == BW_20)
{
R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
#ifdef DOT11_N_SUPPORT
else
{
R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
}
#endif // DOT11_N_SUPPORT //
}
}
}