summaryrefslogtreecommitdiff
path: root/cleopatre/devkit/rt5572drv/MODULE/common/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/devkit/rt5572drv/MODULE/common/mlme.c')
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/common/mlme.c4135
1 files changed, 4135 insertions, 0 deletions
diff --git a/cleopatre/devkit/rt5572drv/MODULE/common/mlme.c b/cleopatre/devkit/rt5572drv/MODULE/common/mlme.c
new file mode 100644
index 0000000000..0e5bed1a40
--- /dev/null
+++ b/cleopatre/devkit/rt5572drv/MODULE/common/mlme.c
@@ -0,0 +1,4135 @@
+/*
+ ***************************************************************************
+ * Ralink Tech Inc.
+ * 4F, No. 2 Technology 5th Rd.
+ * Science-based Industrial Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2004, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************
+
+ Module Name:
+ 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 RALINK_OUI[] = {0x00, 0x0c, 0x43};
+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 BROADCOM_OUI[] = {0x00, 0x90, 0x4c};
+UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
+
+#ifdef CONFIG_APSTA_MIXED_SUPPORT
+UINT32 CW_MAX_IN_BITS;
+#endif /* CONFIG_APSTA_MIXED_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;
+UCHAR BssCoexistIe = IE_2040_BSS_COEXIST;
+UCHAR ExtHtCapIe = IE_EXT_CAPABILITY;
+#endif /* DOT11_N_SUPPORT */
+UCHAR ExtCapIe = IE_EXT_CAPABILITY;
+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 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};
+
+
+#ifdef INF_AMAZON_SE
+UINT16 MaxBulkOutsSizeLimit[5][4] =
+{
+ /* Priority high -> low*/
+ { 24576, 2048, 2048, 2048 }, /* 0 AC */
+ { 24576, 2048, 2048, 2048 }, /* 1 AC */
+ { 24576, 2048, 2048, 2048 }, /* 2 ACs*/
+ { 24576, 6144, 2048, 2048 }, /* 3 ACs*/
+ { 24576, 6144, 4096, 2048 } /* 4 ACs*/
+};
+
+VOID SoftwareFlowControl(
+ IN PRTMP_ADAPTER pAd)
+{
+
+ BOOLEAN ResetBulkOutSize=FALSE;
+ UCHAR i=0,RunningQueueNo=0,QueIdx=0,HighWorkingAcCount=0;
+ UINT PacketsInQueueSize=0;
+ UCHAR Priority[]={1,0,2,3};
+
+ for (i=0;i<NUM_OF_TX_RING;i++)
+ {
+
+ if (pAd->TxContext[i].CurWritePosition>=pAd->TxContext[i].NextBulkOutPosition)
+ {
+ PacketsInQueueSize=pAd->TxContext[i].CurWritePosition-pAd->TxContext[i].NextBulkOutPosition;
+ }
+ else
+ {
+ PacketsInQueueSize=MAX_TXBULK_SIZE-pAd->TxContext[i].NextBulkOutPosition+pAd->TxContext[i].CurWritePosition;
+ }
+
+ if (pAd->BulkOutDataSizeCount[i]>20480 || PacketsInQueueSize>6144)
+ {
+ RunningQueueNo++;
+ pAd->BulkOutDataFlag[i]=TRUE;
+ }
+ else
+ pAd->BulkOutDataFlag[i]=FALSE;
+
+ pAd->BulkOutDataSizeCount[i]=0;
+ }
+
+ if (RunningQueueNo>pAd->LastRunningQueueNo)
+ {
+ DBGPRINT(RT_DEBUG_INFO,("SoftwareFlowControl reset %d > %d \n",RunningQueueNo,pAd->LastRunningQueueNo));
+
+ResetBulkOutSize=TRUE;
+ pAd->RunningQueueNoCount=0;
+ pAd->LastRunningQueueNo=RunningQueueNo;
+ }
+ else if (RunningQueueNo==pAd->LastRunningQueueNo)
+ {
+pAd->RunningQueueNoCount=0;
+ }
+ else if (RunningQueueNo<pAd->LastRunningQueueNo)
+ {
+ DBGPRINT(RT_DEBUG_INFO,("SoftwareFlowControl reset %d < %d \n",RunningQueueNo,pAd->LastRunningQueueNo));
+ pAd->RunningQueueNoCount++;
+ if (pAd->RunningQueueNoCount>=6)
+ {
+ ResetBulkOutSize=TRUE;
+ pAd->RunningQueueNoCount=0;
+ pAd->LastRunningQueueNo=RunningQueueNo;
+ }
+ }
+
+ if (ResetBulkOutSize==TRUE)
+ {
+ for (QueIdx=0;QueIdx<NUM_OF_TX_RING;QueIdx++)
+ {
+ HighWorkingAcCount=0;
+ for (i=0;i<NUM_OF_TX_RING;i++)
+ {
+ if (QueIdx==i)
+ continue;
+
+ if (pAd->BulkOutDataFlag[i]==TRUE && Priority[i]>Priority[QueIdx])
+ HighWorkingAcCount++;
+
+ }
+ pAd->BulkOutDataSizeLimit[QueIdx]=MaxBulkOutsSizeLimit[RunningQueueNo][HighWorkingAcCount];
+ }
+
+ DBGPRINT(RT_DEBUG_TRACE, ("Reset bulkout size AC0(BE):%7d AC1(BK):%7d AC2(VI):%7d AC3(VO):%7d %d\n",pAd->BulkOutDataSizeLimit[0]
+ ,pAd->BulkOutDataSizeLimit[1]
+ ,pAd->BulkOutDataSizeLimit[2]
+ ,pAd->BulkOutDataSizeLimit[3]
+ ,RunningQueueNo));
+ }
+
+}
+#endif /* INF_AMAZON_SE */
+
+/*
+ ==========================================================================
+ 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, &pAd->Mlme.Queue);
+ if(Status != NDIS_STATUS_SUCCESS)
+ break;
+
+ pAd->Mlme.bRunning = FALSE;
+ NdisAllocateSpinLock(pAd, &pAd->Mlme.TaskLock);
+
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ /* init AP state machines*/
+ APAssocStateMachineInit(pAd, &pAd->Mlme.ApAssocMachine, pAd->Mlme.ApAssocFunc);
+ APAuthStateMachineInit(pAd, &pAd->Mlme.ApAuthMachine, pAd->Mlme.ApAuthFunc);
+ APSyncStateMachineInit(pAd, &pAd->Mlme.ApSyncMachine, pAd->Mlme.ApSyncFunc);
+
+#ifdef APCLI_SUPPORT
+ /* init apcli state machines*/
+ ASSERT(APCLI_AUTH_FUNC_SIZE == APCLI_MAX_AUTH_MSG * APCLI_MAX_AUTH_STATE);
+ ApCliAuthStateMachineInit(pAd, &pAd->Mlme.ApCliAuthMachine, pAd->Mlme.ApCliAuthFunc);
+
+ ASSERT(APCLI_ASSOC_FUNC_SIZE == APCLI_MAX_ASSOC_MSG * APCLI_MAX_ASSOC_STATE);
+ ApCliAssocStateMachineInit(pAd, &pAd->Mlme.ApCliAssocMachine, pAd->Mlme.ApCliAssocFunc);
+
+ ASSERT(APCLI_SYNC_FUNC_SIZE == APCLI_MAX_SYNC_MSG * APCLI_MAX_SYNC_STATE);
+ ApCliSyncStateMachineInit(pAd, &pAd->Mlme.ApCliSyncMachine, pAd->Mlme.ApCliSyncFunc);
+
+ ASSERT(APCLI_CTRL_FUNC_SIZE == APCLI_MAX_CTRL_MSG * APCLI_MAX_CTRL_STATE);
+ ApCliCtrlStateMachineInit(pAd, &pAd->Mlme.ApCliCtrlMachine, pAd->Mlme.ApCliCtrlFunc);
+
+#endif /* APCLI_SUPPORT */
+ }
+
+#endif /* CONFIG_AP_SUPPORT */
+
+#ifdef WSC_INCLUDED
+ /* Init Wsc state machine */
+ ASSERT(WSC_FUNC_SIZE == MAX_WSC_MSG * MAX_WSC_STATE);
+ WscStateMachineInit(pAd, &pAd->Mlme.WscMachine, pAd->Mlme.WscFunc);
+#endif /* WSC_INCLUDED */
+
+ 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_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ /* Init APSD periodic timer*/
+ RTMPInitTimer(pAd, &pAd->Mlme.APSDPeriodicTimer, GET_TIMER_FUNCTION(APSDPeriodicExec), pAd, TRUE);
+ RTMPSetTimer(&pAd->Mlme.APSDPeriodicTimer, 50);
+
+ /* Init APQuickResponseForRateUp timer.*/
+ RTMPInitTimer(pAd, &pAd->ApCfg.ApQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(APQuickResponeForRateUpExec), pAd, FALSE);
+ pAd->ApCfg.ApQuickResponeForRateUpTimerRunning = FALSE;
+ }
+#endif /* CONFIG_AP_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))
+ {
+#ifdef RTMP_MAC_USB
+ if (Elem->MsgType == MT2_RESET_CONF)
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n"));
+ MlmeRestartStateMachine(pAd);
+ Elem->Occupied = FALSE;
+ Elem->MsgLen = 0;
+ continue;
+ }
+#endif /* RTMP_MAC_USB */
+
+ /* if dequeue success*/
+ switch (Elem->Machine)
+ {
+ /* STA state machines*/
+
+ case ACTION_STATE_MACHINE:
+ StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine,
+ Elem, pAd->Mlme.ActMachine.CurrState);
+ break;
+
+#ifdef CONFIG_AP_SUPPORT
+ /* AP state amchines*/
+
+ case AP_ASSOC_STATE_MACHINE:
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApAssocMachine,
+ Elem, pAd->Mlme.ApAssocMachine.CurrState);
+ break;
+
+ case AP_AUTH_STATE_MACHINE:
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApAuthMachine,
+ Elem, pAd->Mlme.ApAuthMachine.CurrState);
+ break;
+
+ case AP_SYNC_STATE_MACHINE:
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApSyncMachine,
+ Elem, pAd->Mlme.ApSyncMachine.CurrState);
+ break;
+
+#ifdef APCLI_SUPPORT
+ case APCLI_AUTH_STATE_MACHINE:
+ apcliIfIndex = Elem->Priv;
+ if(isValidApCliIf(apcliIfIndex))
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApCliAuthMachine, Elem,
+ (pAd->ApCfg.ApCliTab[apcliIfIndex].AuthCurrState));
+ break;
+
+ case APCLI_ASSOC_STATE_MACHINE:
+ apcliIfIndex = Elem->Priv;
+ if(isValidApCliIf(apcliIfIndex))
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApCliAssocMachine, Elem,
+ (pAd->ApCfg.ApCliTab[apcliIfIndex].AssocCurrState));
+ break;
+
+ case APCLI_SYNC_STATE_MACHINE:
+ apcliIfIndex = Elem->Priv;
+ if(isValidApCliIf(apcliIfIndex))
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApCliSyncMachine, Elem,
+ (pAd->ApCfg.ApCliTab[apcliIfIndex].SyncCurrState));
+ break;
+
+ case APCLI_CTRL_STATE_MACHINE:
+ apcliIfIndex = Elem->Priv;
+ if(isValidApCliIf(apcliIfIndex))
+ StateMachinePerformAction(pAd, &pAd->Mlme.ApCliCtrlMachine, Elem,
+ (pAd->ApCfg.ApCliTab[apcliIfIndex].CtrlCurrState));
+ break;
+#endif /* APCLI_SUPPORT */
+
+#endif /* CONFIG_AP_SUPPORT */
+ case WPA_STATE_MACHINE:
+ StateMachinePerformAction(pAd, &pAd->Mlme.WpaMachine, Elem, pAd->Mlme.WpaMachine.CurrState);
+ break;
+#ifdef WSC_INCLUDED
+ case WSC_STATE_MACHINE:
+ if (pAd->pWscElme)
+ {
+ RTMP_SEM_LOCK(&pAd->WscElmeLock);
+ NdisMoveMemory(pAd->pWscElme, Elem, sizeof(MLME_QUEUE_ELEM));
+ RTMP_SEM_UNLOCK(&pAd->WscElmeLock);
+/*#ifdef KTHREAD_SUPPORT*/
+/* WAKE_UP(&(pAd->wscTask));*/
+/*#else*/
+/* RTMP_SEM_EVENT_UP(&(pAd->wscTask.taskSema));*/
+/*#endif*/
+ RtmpOsTaskWakeUp(&(pAd->wscTask));
+ }
+ break;
+#endif /* WSC_INCLUDED */
+
+
+ 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);
+ }
+
+ RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled);
+
+
+ RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled);
+
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ RTMPCancelTimer(&pAd->Mlme.APSDPeriodicTimer, &Cancelled);
+
+ if (pAd->ApCfg.ApQuickResponeForRateUpTimerRunning == TRUE)
+ RTMPCancelTimer(&pAd->ApCfg.ApQuickResponeForRateUpTimer, &Cancelled);
+
+#ifdef APCLI_SUPPORT
+ RTMPCancelTimer(&pAd->ApCliMlmeAux.ProbeTimer, &Cancelled);
+ RTMPCancelTimer(&pAd->ApCliMlmeAux.ApCliAssocTimer, &Cancelled);
+ RTMPCancelTimer(&pAd->ApCliMlmeAux.ApCliAuthTimer, &Cancelled);
+
+#ifdef WSC_AP_SUPPORT
+ if (pAd->ApCfg.ApCliTab[BSS0].WscControl.WscProfileRetryTimerRunning)
+ {
+ pAd->ApCfg.ApCliTab[BSS0].WscControl.WscProfileRetryTimerRunning = FALSE;
+ RTMPCancelTimer(&pAd->ApCfg.ApCliTab[BSS0].WscControl.WscProfileRetryTimer, &Cancelled);
+ }
+#endif /* WSC_AP_SUPPORT */
+#endif /* APCLI_SUPPORT */
+ RTMPCancelTimer(&pAd->MlmeAux.APScanTimer, &Cancelled);
+ }
+
+#endif /* CONFIG_AP_SUPPORT */
+
+
+
+ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
+ {
+ RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
+
+#ifdef LED_CONTROL_SUPPORT
+ /* Set LED*/
+ RTMPSetLED(pAd, LED_HALT);
+ RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware is not done it.*/
+#ifdef RTMP_MAC_USB
+ {
+ LED_CFG_STRUC LedCfg;
+ RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word);
+ LedCfg.field.LedPolar = 0;
+ LedCfg.field.RLedMode = 0;
+ LedCfg.field.GLedMode = 0;
+ LedCfg.field.YLedMode = 0;
+ RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word);
+ }
+#endif /* RTMP_MAC_USB */
+#endif /* LED_CONTROL_SUPPORT */
+
+#if defined(WOW_SUPPORT) && defined(RTMP_MAC_USB)
+ if (pAd->WOW_Cfg.bEnable == FALSE)
+#endif /* WOW_SUPPORT */
+ 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;
+
+#ifdef RALINK_ATE
+ if (!ATE_ON(pAd))
+#endif /* RALINK_ATE */
+ /* for performace enchanement */
+ NdisZeroMemory(&pAd->RalinkCounters,
+ (UINT32)&pAd->RalinkCounters.OneSecEnd -
+ (UINT32)&pAd->RalinkCounters.OneSecStart);
+
+ 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;
+
+ /* No More 0x84 MCU CMD from v.30 FW*/
+
+#ifdef INF_AMAZON_SE
+ SoftwareFlowControl(pAd);
+#endif /* INF_AMAZON_SE */
+
+
+ /* 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 |
+ fRTMP_ADAPTER_NIC_NOT_EXIST))))
+ return;
+
+
+ pAd->bUpdateBcnCntDone = FALSE;
+
+/* RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3);*/
+ pAd->Mlme.PeriodicRound ++;
+ pAd->Mlme.GPIORound++;
+
+#ifdef RTMP_MAC_USB
+ /* execute every 100ms, update the Tx FIFO Cnt for update Tx Rate.*/
+ NICUpdateFifoStaCounters(pAd);
+#ifdef CONFIG_AP_SUPPORT
+#ifdef CARRIER_DETECTION_FIRMWARE_SUPPORT
+ if (pAd->CommonCfg.CarrierDetect.Enable)
+ CarrierDetectionPeriodicStateCtrl(pAd);
+#endif /* CARRIER_DETECTION_FIRMWARE_SUPPORT */
+#endif /* CONFIG_AP_SUPPORT */
+#endif /* RTMP_MAC_USB */
+
+ /* by default, execute every 500ms */
+ if ((pAd->ra_interval) &&
+ ((pAd->Mlme.PeriodicRound % (pAd->ra_interval / 100)) == 0) &&
+ RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/
+ )
+ {
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ APMlmeDynamicTxRateSwitching(pAd);
+#endif /* CONFIG_AP_SUPPORT */
+ }
+
+#ifdef DFS_SUPPORT
+#ifdef CONFIG_AP_SUPPORT
+#ifdef RTMP_MAC_USB
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+
+ if ((pAd->CommonCfg.Channel > 14) && (pAd->CommonCfg.bIEEE80211H == TRUE))
+ NewUsbTimerCB_Radar(pAd);
+ }
+#endif /* RTMP_MAC_USB */
+#endif /* CONFIG_AP_SUPPORT */
+#endif /* DFS_SUPPORT */
+
+
+#ifdef RTMP_FREQ_CALIBRATION_SUPPORT
+#endif /* RTMP_FREQ_CALIBRATION_SUPPORT */
+
+ /* Normal 1 second Mlme PeriodicExec.*/
+ if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0)
+ {
+ pAd->Mlme.OneSecPeriodicRound ++;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ dynamic_tune_be_tx_op(pAd, 50); /* change form 100 to 50 for WMM WiFi test @20070504*/
+#endif /* CONFIG_AP_SUPPORT */
+
+
+ /*ORIBATimerTimeout(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*/
+ /* Hint: throughput impact is very serious in the function */
+ NICUpdateRawCounters(pAd);
+
+#ifdef RTMP_MAC_USB
+#ifndef INF_AMAZON_SE
+ RTUSBWatchDog(pAd);
+#endif /* INF_AMAZON_SE */
+#endif /* RTMP_MAC_USB */
+
+#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*/
+ {
+ 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 VIDEO_TURBINE_SUPPORT
+ /*VideoTurbineUpdate(pAd);*/
+ /*VideoTurbineDynamicTune(pAd);*/
+#endif /* VIDEO_TURBINE_SUPPORT */
+
+#ifdef VCORECAL_SUPPORT
+ {
+ if ((pAd->Mlme.OneSecPeriodicRound % 10) == 0)
+ AsicVCORecalibration(pAd);
+ }
+#endif /* VCORECAL_SUPPORT */
+
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ APMlmePeriodicExec(pAd);
+
+ if ((pAd->RalinkCounters.OneSecBeaconSentCnt == 0)
+ && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
+ && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
+ && ((pAd->CommonCfg.bIEEE80211H != 1)
+ || (pAd->Dot11_H.RDMode != RD_SILENCE_MODE))
+#ifdef WDS_SUPPORT
+ && (pAd->WdsTab.Mode != WDS_BRIDGE_MODE)
+#endif /* WDS_SUPPORT */
+#ifdef CARRIER_DETECTION_SUPPORT
+ && (isCarrierDetectExist(pAd) == FALSE)
+#endif /* CARRIER_DETECTION_SUPPORT */
+ )
+ pAd->macwd ++;
+ else
+ pAd->macwd = 0;
+
+ if (pAd->macwd > 1)
+ {
+ int count = 0;
+ BOOLEAN MAC_ready = FALSE;
+ UINT32 MacCsr12 = 0;
+
+ /* Disable MAC*/
+ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0);
+
+ /* polling MAC status*/
+ while (count < 10)
+ {
+ RTMPusecDelay(1000); /* 1 ms*/
+ RTMP_IO_READ32(pAd, MAC_STATUS_CFG, &MacCsr12);
+
+ /* if MAC is idle*/
+ if ((MacCsr12 & 0x03) == 0)
+ {
+ MAC_ready = TRUE;
+ break;
+ }
+ count ++;
+ }
+
+ if (MAC_ready)
+ {
+ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1);
+ RTMPusecDelay(1);
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_WARN, ("Warning, MAC isn't ready \n"));
+ }
+
+ {
+ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC);
+ }
+
+ DBGPRINT(RT_DEBUG_WARN, ("MAC specific condition \n"));
+
+#ifdef AP_QLOAD_SUPPORT
+ Show_QoSLoad_Proc(pAd, NULL);
+#endif /* AP_QLOAD_SUPPORT */
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+#if defined(RT5370) || defined(RT5372) || defined(RT5390) || defined(RT5392)
+ if (IS_RT5392(pAd) && ((pAd->MACVersion & 0x0000FFFF) < 0x0223))
+ {
+ if (pAd->BbpResetFlag == 1)
+ {
+ pAd->BbpResetFlagCount++;
+
+ if (pAd->BbpResetFlagCount > pAd->BbpResetFlagCountVale)
+ {
+ pAd->BbpResetFlagCount = 0;
+ pAd->BbpResetFlag = 0;
+ }
+ }
+
+ AsicCheckForHwRecovery(pAd);
+ }
+#endif /* defined(RT5370) || defined(RT5372) || defined(RT5390) || defined(RT5392) */
+
+
+ MlmeResetRalinkCounters(pAd);
+
+
+ RTMP_MLME_HANDLER(pAd);
+ }
+
+#ifdef WSC_INCLUDED
+ WSC_HDR_BTN_MR_HANDLE(pAd);
+#endif /* WSC_INCLUDED */
+
+
+
+ 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);
+}
+
+
+
+/*
+ ==========================================================================
+ 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*/
+
+
+
+ if (pMacEntry != NULL)
+ {
+ pRssiSample = &pMacEntry->RssiSample;
+ OneSecTxNoRetryOkCount = pMacEntry->OneSecTxNoRetryOkCount;
+ OneSecTxRetryOkCount = pMacEntry->OneSecTxRetryOkCount;
+ OneSecTxFailCount = pMacEntry->OneSecTxFailCount;
+ OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
+ OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
+ }
+ else
+ {
+ pRssiSample = &pAd->MacTab.Content[0].RssiSample;
+ OneSecTxNoRetryOkCount = pAd->RalinkCounters.OneSecTxNoRetryOkCount;
+ OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount;
+ OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount;
+ OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
+ OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
+ }
+
+ if (pRssiSample == NULL)
+ return;
+ 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*/
+ {
+ /* 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_AP_SUPPORT
+ if (pAd->OpMode == OPMODE_AP)
+ {
+ if (pMacEntry != NULL)
+ pMacEntry->ChannelQuality = (ChannelQuality > 100) ? 100 : ChannelQuality;
+ }
+#endif /* CONFIG_AP_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)
+ {
+ if (pAdapter->CommonCfg.BasicRateBitmap & 0xF)
+ {
+ /* no 11b rate in 5G band */
+ pAdapter->CommonCfg.BasicRateBitmapOld = \
+ pAdapter->CommonCfg.BasicRateBitmap;
+ pAdapter->CommonCfg.BasicRateBitmap &= (~0xF); /* no 11b */
+ }
+
+ /* force to 6,12,24M in a-band */
+ pAdapter->CommonCfg.BasicRateBitmap |= 0x150; /* 6, 12, 24M */
+ }
+ else
+ {
+ /* no need to modify in 2.4G (bg mixed) */
+ pAdapter->CommonCfg.BasicRateBitmap = \
+ pAdapter->CommonCfg.BasicRateBitmapOld;
+ } /* 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;
+ }
+
+/*===========================================================================*/
+/*===========================================================================*/
+ do
+ {
+#ifdef CONFIG_AP_SUPPORT
+#ifdef APCLI_SUPPORT
+ if (apidx >= MIN_NET_DEVICE_FOR_APCLI)
+ {
+ UCHAR idx = apidx - MIN_NET_DEVICE_FOR_APCLI;
+
+ if (idx < MAX_APCLI_NUM)
+ {
+ pHtPhy = &pAd->ApCfg.ApCliTab[idx].HTPhyMode;
+ pMaxHtPhy = &pAd->ApCfg.ApCliTab[idx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->ApCfg.ApCliTab[idx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->ApCfg.ApCliTab[idx].bAutoTxRateSwitch;
+ HtMcs = pAd->ApCfg.ApCliTab[idx].DesiredTransmitSetting.field.MCS;
+ break;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateTxRates: invalid idx(%d)\n", idx));
+ return;
+ }
+ }
+#endif /* APCLI_SUPPORT */
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef WDS_SUPPORT
+ if (apidx >= MIN_NET_DEVICE_FOR_WDS)
+ {
+ UCHAR idx = apidx - MIN_NET_DEVICE_FOR_WDS;
+
+ if (idx < MAX_WDS_ENTRY)
+ {
+ pHtPhy = &pAd->WdsTab.WdsEntry[idx].HTPhyMode;
+ pMaxHtPhy = &pAd->WdsTab.WdsEntry[idx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->WdsTab.WdsEntry[idx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->WdsTab.WdsEntry[idx].bAutoTxRateSwitch;
+ HtMcs = pAd->WdsTab.WdsEntry[idx].DesiredTransmitSetting.field.MCS;
+ break;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateTxRates: invalid apidx(%d)\n", apidx));
+ return;
+ }
+ }
+#endif /* WDS_SUPPORT */
+
+ if ((apidx < pAd->ApCfg.BssidNum) &&
+ (apidx < MAX_MBSSID_NUM(pAd)) &&
+ (apidx < HW_BEACON_MAX_NUM))
+ {
+ pHtPhy = &pAd->ApCfg.MBSSID[apidx].HTPhyMode;
+ pMaxHtPhy = &pAd->ApCfg.MBSSID[apidx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->ApCfg.MBSSID[apidx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->ApCfg.MBSSID[apidx].bAutoTxRateSwitch;
+ HtMcs = pAd->ApCfg.MBSSID[apidx].DesiredTransmitSetting.field.MCS;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateTxRates: invalid apidx(%d)\n", apidx));
+ }
+ break;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ } while(FALSE);
+
+
+ pAd->CommonCfg.MaxDesiredRate = MaxDesire;
+
+ if (pMinHtPhy == NULL)
+ return;
+ 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;
+ }
+
+ {
+ 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);
+
+ 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 (*auto_rate_cur_p)
+ {
+ short dbm = 0;
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ dbm =0;
+#endif /* CONFIG_AP_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;*/
+
+ /* Choose the Desire Tx MCS in CCK/OFDM mode */
+ if (num > RATE_6)
+ {
+ if (HtMcs <= MCS_7)
+ MaxDesire = RxwiMCSToOfdmRate[HtMcs];
+ else
+ MaxDesire = MinSupport;
+ }
+ else
+ {
+ if (HtMcs <= MCS_3)
+ MaxDesire = HtMcs;
+ else
+ MaxDesire = MinSupport;
+ }
+
+ 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;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ pMaxHtPhy->field.MCS = MaxDesire;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ }
+ else
+ {
+ pMaxHtPhy->field.MODE = MODE_OFDM;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[MaxDesire];
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ }
+
+ 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;
+
+#ifdef CONFIG_AP_SUPPORT
+#ifdef MCAST_RATE_SPECIFIC
+ {
+ /* set default value if MCastPhyMode is not initialized */
+ HTTRANSMIT_SETTING tPhyMode;
+
+ memset(&tPhyMode, 0, sizeof(HTTRANSMIT_SETTING));
+ if (memcmp(&pAd->CommonCfg.MCastPhyMode, &tPhyMode, sizeof(HTTRANSMIT_SETTING)) == 0)
+ {
+ memmove(&pAd->CommonCfg.MCastPhyMode, &pAd->MacTab.Content[MCAST_WCID].HTPhyMode,
+ sizeof(HTTRANSMIT_SETTING));
+ }
+ }
+#endif /* MCAST_RATE_SPECIFIC */
+#endif /* CONFIG_AP_SUPPORT */
+ }
+
+ 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;
+
+ do
+ {
+#ifdef CONFIG_AP_SUPPORT
+
+#ifdef APCLI_SUPPORT
+ if (apidx >= MIN_NET_DEVICE_FOR_APCLI)
+ {
+ UCHAR idx = apidx - MIN_NET_DEVICE_FOR_APCLI;
+
+ if (idx < MAX_APCLI_NUM)
+ {
+ pDesireHtPhy = &pAd->ApCfg.ApCliTab[idx].DesiredHtPhyInfo;
+ pActiveHtPhy = &pAd->ApCfg.ApCliTab[idx].DesiredHtPhyInfo;
+ pHtPhy = &pAd->ApCfg.ApCliTab[idx].HTPhyMode;
+ pMaxHtPhy = &pAd->ApCfg.ApCliTab[idx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->ApCfg.ApCliTab[idx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->ApCfg.ApCliTab[idx].bAutoTxRateSwitch;
+ break;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateHtTxRates: invalid idx(%d)\n", idx));
+ return;
+ }
+ }
+#endif /* APCLI_SUPPORT */
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef WDS_SUPPORT
+ if (apidx >= MIN_NET_DEVICE_FOR_WDS)
+ {
+ UCHAR idx = apidx - MIN_NET_DEVICE_FOR_WDS;
+
+ if (idx < MAX_WDS_ENTRY)
+ {
+ pDesireHtPhy = &pAd->WdsTab.WdsEntry[idx].DesiredHtPhyInfo;
+ pActiveHtPhy = &pAd->WdsTab.WdsEntry[idx].DesiredHtPhyInfo;
+ pHtPhy = &pAd->WdsTab.WdsEntry[idx].HTPhyMode;
+ pMaxHtPhy = &pAd->WdsTab.WdsEntry[idx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->WdsTab.WdsEntry[idx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->WdsTab.WdsEntry[idx].bAutoTxRateSwitch;
+ break;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateHtTxRates: invalid apidx(%d)\n", apidx));
+ return;
+ }
+ }
+#endif /* WDS_SUPPORT */
+
+ if ((apidx < pAd->ApCfg.BssidNum) && (apidx < HW_BEACON_MAX_NUM))
+ {
+ pDesireHtPhy = &pAd->ApCfg.MBSSID[apidx].DesiredHtPhyInfo;
+ pActiveHtPhy = &pAd->ApCfg.MBSSID[apidx].DesiredHtPhyInfo;
+ pHtPhy = &pAd->ApCfg.MBSSID[apidx].HTPhyMode;
+ pMaxHtPhy = &pAd->ApCfg.MBSSID[apidx].MaxHTPhyMode;
+ pMinHtPhy = &pAd->ApCfg.MBSSID[apidx].MinHTPhyMode;
+
+ auto_rate_cur_p = &pAd->ApCfg.MBSSID[apidx].bAutoTxRateSwitch;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MlmeUpdateHtTxRates: invalid apidx(%d)\n", apidx));
+ }
+ break;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ } while (FALSE);
+
+
+ {
+ if ((!pDesireHtPhy) || 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) && (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.*/
+
+
+ /* 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, &pAd->BATabLock);
+ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++)
+ {
+ Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
+ NdisAllocateSpinLock(pAd, &(Tab->BARecEntry[i].RxReRingLock));
+ }
+ for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++)
+ {
+ Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
+ }
+}
+
+VOID BATableExit(
+ IN RTMP_ADAPTER *pAd)
+{
+ int i;
+
+ for(i=0; i<MAX_LEN_OF_BA_REC_TABLE; i++)
+ {
+ NdisFreeSpinLock(&pAd->BATable.BARecEntry[i].RxReRingLock);
+ }
+ NdisFreeSpinLock(&pAd->BATabLock);
+}
+#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++)
+ {
+ UCHAR *pOldAddr = Tab->BssEntry[i].pVarIeFromProbRsp;
+
+ NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
+
+ Tab->BssEntry[i].Rssi = -127; /* initial the rssi as a minimum value */
+ if (pOldAddr)
+ {
+ RTMPZeroMemory(pOldAddr, MAX_VIE_LEN);
+ Tab->BssEntry[i].pVarIeFromProbRsp = pOldAddr;
+ }
+ }
+}
+
+
+/*! \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)))
+ {
+ UCHAR *pOldAddr = NULL;
+
+ for (j = i; j < Tab->BssNr - 1; j++)
+ {
+ pOldAddr = Tab->BssEntry[j].pVarIeFromProbRsp;
+ NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
+ if (pOldAddr)
+ {
+ RTMPZeroMemory(pOldAddr, MAX_VIE_LEN);
+ NdisMoveMemory(pOldAddr,
+ Tab->BssEntry[j + 1].pVarIeFromProbRsp,
+ Tab->BssEntry[j + 1].VarIeFromProbeRspLen);
+ Tab->BssEntry[j].pVarIeFromProbRsp = pOldAddr;
+ }
+ }
+
+ pOldAddr = Tab->BssEntry[Tab->BssNr - 1].pVarIeFromProbRsp;
+ NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY));
+ if (pOldAddr)
+ {
+ RTMPZeroMemory(pOldAddr, MAX_VIE_LEN);
+ Tab->BssEntry[Tab->BssNr - 1].pVarIeFromProbRsp = pOldAddr;
+ }
+
+ Tab->BssNr -= 1;
+ return;
+ }
+ }
+}
+
+
+/*! \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
+ {
+ /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */
+ if (NdisEqualMemory(pBss->Ssid, ZeroSsid, pBss->SsidLen))
+ {
+ NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
+ 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;
+ }
+
+ NdisGetSystemUpTime(&pBss->LastBeaconRxTime);
+ 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);
+ if (ExtRateLen > MAX_LEN_OF_SUPPORTED_RATES)
+ 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;
+
+ {
+ PEID_STRUCT pEid;
+ USHORT Length = 0;
+
+#ifdef WSC_INCLUDED
+ pBss->WpsAP = 0x00;
+ pBss->WscDPIDFromWpsAP = 0xFFFF;
+#endif /* WSC_INCLUDED */
+
+ pEid = (PEID_STRUCT) pVIE;
+ while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE)
+ {
+#define WPS_AP 0x01
+ switch(pEid->Eid)
+ {
+ case IE_WPA:
+ if (NdisEqualMemory(pEid->Octet, WPS_OUI, 4)
+ )
+ {
+#ifdef WSC_INCLUDED
+ pBss->WpsAP |= WPS_AP;
+ WscCheckWpsIeFromWpsAP(pAd,
+ pEid,
+ &pBss->WscDPIDFromWpsAP);
+#endif /* WSC_INCLUDED */
+ break;
+ }
+ break;
+
+ }
+ Length = Length + 2 + (USHORT)pEid->Len; /* Eid[1] + Len[1]+ content[Len]*/
+ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
+ }
+ }
+}
+
+/*!
+ * \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);*/
+ Idx = BssTableSearch(Tab, pBssid, 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) ||
+ !OPSTATUS_TEST_FLAG(pAd, fOP_AP_STATUS_MEDIA_STATE_CONNECTED))
+ {
+ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) ||
+ SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)
+#ifdef APCLI_SUPPORT
+ || MAC_ADDR_EQUAL(pAd->ApCliMlmeAux.Bssid, pBssid)
+ || SSID_EQUAL(pAd->ApCliMlmeAux.Ssid, pAd->ApCliMlmeAux.SsidLen, Ssid, SsidLen)
+#endif /* APCLI_SUPPORT */
+ )
+ {
+ Idx = Tab->BssOverlapNr;
+ NdisZeroMemory(&(Tab->BssEntry[Idx]), sizeof(BSS_ENTRY));
+ 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 + 1;
+ 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
+ {
+ 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;
+}
+
+
+
+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;
+
+#ifdef WAPI_SUPPORT
+ /* Init WAPI setting*/
+ pBss->WAPI.PairCipher = Ndis802_11WEPDisabled;
+ pBss->WAPI.PairCipherAux = Ndis802_11WEPDisabled;
+ pBss->WAPI.GroupCipher = Ndis802_11WEPDisabled;
+ pBss->WAPI.RsnCapability = 0;
+ pBss->WAPI.bMixMode = FALSE;
+#endif /* WAPI_SUPPORT */
+
+ 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 0:
+ if (pBss->AuthMode == Ndis802_11AuthModeOpen)
+ pBss->AuthMode = Ndis802_11AuthModeWPANone;
+ else
+ pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
+ break;
+ 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 += sizeof(AKM_SUITE_STRUCT);
+ Count--;
+ }
+
+ /* Fixed for WPA-None*/
+ if (pBss->BssType == BSS_ADHOC)
+ {
+ 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;
+#ifdef WAPI_SUPPORT
+ case IE_WAPI:
+ pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp;
+
+ /* 0. The version number must be 1*/
+ if (le2cpu16(pRsnHeader->Version) != 1)
+ break;
+ pTmp += sizeof(RSN_IE_HEADER_STRUCT);
+
+ /* 1. Get AKM suite counts*/
+ NdisMoveMemory(&Count, pTmp, sizeof(USHORT));
+ Count = cpu2le16(Count);
+ pTmp += sizeof(USHORT);
+
+ /* 2. Get AKM ciphers*/
+ pAKM = (PAKM_SUITE_STRUCT) pTmp;
+ if (!RTMPEqualMemory(pTmp, WAPI_OUI, 3))
+ break;
+
+ switch (pAKM->Type)
+ {
+ case 1:
+ /* Support WAI certificate authentication*/
+ pBss->AuthMode = Ndis802_11AuthModeWAICERT;
+ break;
+ case 2:
+ /* Support WAI PSK*/
+ pBss->AuthMode = Ndis802_11AuthModeWAIPSK;
+ break;
+ default:
+ break;
+ }
+ pTmp += (Count * sizeof(AKM_SUITE_STRUCT));
+
+ /* 3. Get pairwise cipher counts*/
+ NdisMoveMemory(&Count, pTmp, sizeof(USHORT));
+ Count = cpu2le16(Count);
+ pTmp += sizeof(USHORT);
+
+ /* 4. Get pairwise cipher*/
+ /* Parsing all unicast cipher suite*/
+ while (Count > 0)
+ {
+ if (!RTMPEqualMemory(pTmp, WAPI_OUI, 3))
+ break;
+
+ /* Skip OUI*/
+ pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
+ TmpCipher = Ndis802_11WEPDisabled;
+ switch (pCipher->Type)
+ {
+ case 1:
+ TmpCipher = Ndis802_11EncryptionSMS4Enabled;
+ break;
+ default:
+ break;
+ }
+
+ if (TmpCipher > pBss->WAPI.PairCipher)
+ {
+ /* Move the lower cipher suite to PairCipherAux*/
+ pBss->WAPI.PairCipherAux = pBss->WAPI.PairCipher;
+ pBss->WAPI.PairCipher = TmpCipher;
+ }
+ else
+ {
+ pBss->WAPI.PairCipherAux = TmpCipher;
+ }
+ pTmp += sizeof(CIPHER_SUITE_STRUCT);
+ Count--;
+ }
+
+ /* 5. Check group cipher*/
+ if (!RTMPEqualMemory(pTmp, WAPI_OUI, 3))
+ break;
+
+ pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
+ /* Parse group cipher*/
+ switch (pCipher->Type)
+ {
+ case 1:
+ pBss->WAPI.GroupCipher = Ndis802_11EncryptionSMS4Enabled;
+ break;
+ default:
+ break;
+ }
+ /* set to correct offset for next parsing*/
+ pTmp += sizeof(CIPHER_SUITE_STRUCT);
+
+ /* update the encryption type*/
+ pBss->WepStatus = pBss->WAPI.PairCipher;
+
+ /* update the WAPI capability*/
+ pBss->WAPI.RsnCapability = (pTmp[1]<<8) + pTmp[0];
+ pTmp += sizeof(USHORT);
+
+ break;
+#endif /* WAPI_SUPPORT */
+ 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_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ COPY_MAC_ADDR(pHdr80211->Addr2, pBssid);
+#endif /* CONFIG_AP_SUPPORT */
+ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
+}
+
+VOID MgtMacHeaderInitExt(
+ IN PRTMP_ADAPTER pAd,
+ IN OUT PHEADER_802_11 pHdr80211,
+ IN UCHAR SubType,
+ IN UCHAR ToDs,
+ IN PUCHAR pAddr1,
+ IN PUCHAR pAddr2,
+ IN PUCHAR pAddr3)
+{
+ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
+
+ pHdr80211->FC.Type = BTYPE_MGMT;
+ pHdr80211->FC.SubType = SubType;
+ pHdr80211->FC.ToDs = ToDs;
+ COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1);
+ COPY_MAC_ADDR(pHdr80211->Addr2, pAddr2);
+ COPY_MAC_ADDR(pHdr80211->Addr3, pAddr3);
+}
+
+
+/* ===========================================================================================*/
+/* 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 PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE *Queue)
+{
+ INT i;
+
+ NdisAllocateSpinLock(pAd, &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,
+ IN ULONG Priv)
+{
+ 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, 1))
+ {
+ 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;
+ Queue->Entry[Tail].Priv = Priv;
+
+ 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,
+ IN UCHAR OpMode)
+{
+ INT Tail, Machine = 0xff;
+ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg;
+ INT MsgType = 0x0;
+ 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, 0))
+ {
+ return FALSE;
+ }
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ /* Beacon must be handled by ap-sync state machine.*/
+ /* Probe-rsp must be handled by apcli-sync state machine.*/
+ /* Those packets don't need to check its MAC address.*/
+ do
+ {
+ /*
+ 1. When P2P GO On and receive Probe Response, preCheckMsgTypeSubset function will
+ enquene Probe response to APCli sync state machine
+ Solution: when GO On skip preCheckMsgTypeSubset redirect to APMsgTypeSubst
+ 2. When P2P Cli On and receive Probe Response, preCheckMsgTypeSubset function will
+ enquene Probe response to APCli sync state machine
+ Solution: handle MsgType == APCLI_MT2_PEER_PROBE_RSP on ApCli Sync state machine
+ when ApCli on idle state.
+ */
+
+ if (!MAC_ADDR_EQUAL(pFrame->Hdr.Addr1, pAd->CurrentAddress) &&
+ preCheckMsgTypeSubset(pAd, pFrame, &Machine, &MsgType))
+ break;
+
+ if (!MAC_ADDR_EQUAL(pFrame->Hdr.Addr1, pAd->CurrentAddress) &&
+ !MAC_ADDR_EQUAL(pAd->ApCliMlmeAux.Bssid, ZERO_MAC_ADDR)
+ && MAC_ADDR_EQUAL(pAd->ApCliMlmeAux.Bssid, pFrame->Hdr.Addr2))
+ {
+ if (ApCliMsgTypeSubst(pAd, pFrame, &Machine, &MsgType))
+ break;
+ }
+ else
+ {
+ if (APMsgTypeSubst(pAd, pFrame, &Machine, &MsgType))
+ break;
+ }
+
+ DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d, STA-%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pFrame->Hdr.FC.SubType, pFrame->Hdr.Addr2[0], pFrame->Hdr.Addr2[1], pFrame->Hdr.Addr2[2],
+ pFrame->Hdr.Addr2[3], pFrame->Hdr.Addr2[4], pFrame->Hdr.Addr2[5]));
+ return FALSE;
+
+ } while (FALSE);
+#else
+ if (!APMsgTypeSubst(pAd, pFrame, &Machine, &MsgType))
+ {
+ DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType));
+ return FALSE;
+ }
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_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].OpMode = (ULONG)OpMode;
+ Queue->Entry[Tail].Priv = 0;
+
+ 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;
+}
+
+#ifdef WSC_INCLUDED
+/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
+ * \param *Queue The MLME Queue
+ * \param TimeStampLow The lower 32 bit of timestamp, here we used for eventID.
+ * \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
+ */
+BOOLEAN MlmeEnqueueForWsc(
+ IN PRTMP_ADAPTER pAd,
+ IN ULONG eventID,
+ IN LONG senderID,
+ IN ULONG Machine,
+ IN ULONG MsgType,
+ IN ULONG MsgLen,
+ IN VOID *Msg)
+{
+ INT Tail;
+ /*ULONG IrqFlags;*/
+ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("-----> MlmeEnqueueForWsc\n"));
+ /* 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))
+ return FALSE;
+
+ /* First check the size, it MUST not exceed the mlme queue size*/
+ if (MsgLen > MGMT_DMA_BUFFER_SIZE)
+ {
+ DBGPRINT_ERR(("MlmeEnqueueForWsc: msg too large, size = %ld \n", MsgLen));
+ return FALSE;
+ }
+
+ if (MlmeQueueFull(Queue, 1))
+ {
+
+ return FALSE;
+ }
+
+ /* 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 = eventID;
+ Queue->Entry[Tail].TimeStamp.u.HighPart = senderID;
+ if (Msg != NULL)
+ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
+
+ NdisReleaseSpinLock(&(Queue->Lock));
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<----- MlmeEnqueueForWsc\n"));
+
+ return TRUE;
+}
+#endif /* WSC_INCLUDED */
+
+/*! \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)
+{
+
+ DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
+
+
+
+ /* 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);
+
+
+}
+
+/*! \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,
+ IN UCHAR SendId)
+{
+ BOOLEAN Ans;
+
+ NdisAcquireSpinLock(&(Queue->Lock));
+ if (SendId == 0)
+ Ans = ((Queue->Num >= (MAX_LEN_OF_MLME_QUEUE / 2)) || Queue->Entry[Queue->Tail].Occupied);
+ else
+ Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE);
+ 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
+
+ */
+
+/* ===========================================================================================*/
+/* 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,
+ IN ULONG CurrState)
+{
+
+ if (S->TransFunc[(CurrState) * S->NrMsg + Elem->MsgType - S->Base])
+ (*(S->TransFunc[(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)
+{
+}
+
+/*
+ ==========================================================================
+ 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;
+}
+
+
+UCHAR RandomByte2(
+ IN PRTMP_ADAPTER pAd)
+{
+ UINT32 a,b;
+ UCHAR value, value1 = 0, value2 = 0, value3 = 0, value4 = 0, value5 = 0;
+
+ /*MAC statistic related*/
+ RTMP_IO_READ32(pAd, RX_STA_CNT1, &a);
+ a &= 0x0000ffff;
+ RTMP_IO_READ32(pAd, RX_STA_CNT0, &b);
+ b &= 0x0000ffff;
+ value = (a<<16)|b;
+
+ /*R50~R54: RSSI or SNR related*/
+ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &value1);
+ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &value2);
+ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &value3);
+ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R53, &value4);
+ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R54, &value5);
+
+ return value^value1^value2^value3^value4^value5^RandomByte(pAd);
+}
+
+
+/*
+ ========================================================================
+
+ 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);
+}
+
+
+/*
+ ========================================================================
+
+ 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 RTMPAvgRssi(
+ IN PRTMP_ADAPTER pAd,
+ IN RSSI_SAMPLE *pRssi)
+{
+ CHAR Rssi;
+
+ if(pAd->Antenna.field.RxPath == 3)
+ {
+ Rssi = (pRssi->AvgRssi0 + pRssi->AvgRssi1 + pRssi->AvgRssi2)/3;
+ }
+ else if(pAd->Antenna.field.RxPath == 2)
+ {
+ Rssi = (pRssi->AvgRssi0 + pRssi->AvgRssi1)>>1;
+ }
+ else
+ {
+ Rssi = pRssi->AvgRssi0;
+ }
+
+ return Rssi;
+}
+
+
+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;
+}
+
+
+CHAR RTMPMinSnr(
+ IN PRTMP_ADAPTER pAd,
+ IN CHAR Snr0,
+ IN CHAR Snr1)
+{
+ CHAR smaller = Snr0;
+
+ if (pAd->Antenna.field.RxPath == 1)
+ {
+ smaller = Snr0;
+ }
+
+ if ((pAd->Antenna.field.RxPath >= 2) && (Snr1 != 0))
+ {
+ smaller = min(Snr0, Snr1);
+ }
+
+ return smaller;
+}
+
+/*
+ ========================================================================
+ Routine Description:
+ Periodic evaluate antenna link status
+
+ Arguments:
+ pAd - Adapter pointer
+
+ Return Value:
+ None
+
+ ========================================================================
+*/
+VOID AsicEvaluateRxAnt(
+ IN PRTMP_ADAPTER pAd)
+{
+
+#ifdef RALINK_ATE
+ if (ATE_ON(pAd))
+ return;
+#endif /* RALINK_ATE */
+
+#ifdef RTMP_MAC_USB
+#endif /* RTMP_MAC_USB */
+
+ 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)
+ )
+ return;
+
+#ifdef RT3290
+ if (IS_RT3290(pAd) && (pAd->RalinkCounters.OneSecTransmittedByteCount >= 500))
+ return;
+#endif /* RT3290 */
+
+ {
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+/* if (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_DISABLE)*/
+ /* for SmartBit 64-byte stream test */
+ if (pAd->MacTab.Size > 0)
+ APAsicEvaluateRxAnt(pAd);
+ return;
+ }
+#endif /* CONFIG_AP_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;
+
+
+
+#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)
+ )
+ return;
+
+ {
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+/* if (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_DISABLE)*/
+ APAsicRxAntEvalTimeout(pAd);
+ return;
+ }
+#endif /* CONFIG_AP_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) &&
+ !OPSTATUS_TEST_FLAG(pAd, fOP_AP_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_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ if (pEntry)
+ {
+ if (IS_ENTRY_CLIENT(pEntry))
+ result = pAd->ApCfg.MBSSID[pEntry->apidx].bAutoTxRateSwitch;
+#ifdef WDS_SUPPORT
+ else if (IS_ENTRY_WDS(pEntry))
+ result = pAd->WdsTab.WdsEntry[pEntry->MatchWDSTabIdx].bAutoTxRateSwitch;
+#endif /* WDS_SUPPORT */
+#ifdef APCLI_SUPPORT
+ else if (IS_ENTRY_APCLI(pEntry))
+ result = pAd->ApCfg.ApCliTab[pEntry->MatchAPCLITabIdx].bAutoTxRateSwitch;
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+
+
+
+ return result;
+}
+
+
+BOOLEAN RTMPAutoRateSwitchCheck(
+ IN PRTMP_ADAPTER pAd)
+{
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ INT apidx = 0;
+
+ for (apidx = 0; apidx < pAd->ApCfg.BssidNum; apidx++)
+ {
+ if (pAd->ApCfg.MBSSID[apidx].bAutoTxRateSwitch)
+ return TRUE;
+ }
+#ifdef WDS_SUPPORT
+ for (apidx = 0; apidx < MAX_WDS_ENTRY; apidx++)
+ {
+ if (pAd->WdsTab.WdsEntry[apidx].bAutoTxRateSwitch)
+ return TRUE;
+ }
+#endif /* WDS_SUPPORT */
+#ifdef APCLI_SUPPORT
+ for (apidx = 0; apidx < MAX_APCLI_NUM; apidx++)
+ {
+ if (pAd->ApCfg.ApCliTab[apidx].bAutoTxRateSwitch)
+ return TRUE;
+ }
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_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_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ if (pEntry)
+ {
+ if (IS_ENTRY_CLIENT(pEntry))
+ tx_mode = (UCHAR)pAd->ApCfg.MBSSID[pEntry->apidx].DesiredTransmitSetting.field.FixedTxMode;
+#ifdef WDS_SUPPORT
+ else if (IS_ENTRY_WDS(pEntry))
+ tx_mode = (UCHAR)pAd->WdsTab.WdsEntry[pEntry->MatchWDSTabIdx].DesiredTransmitSetting.field.FixedTxMode;
+#endif /* WDS_SUPPORT */
+#ifdef APCLI_SUPPORT
+ else if (IS_ENTRY_APCLI(pEntry))
+ tx_mode = (UCHAR)pAd->ApCfg.ApCliTab[pEntry->MatchAPCLITabIdx].DesiredTransmitSetting.field.FixedTxMode;
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_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));
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : the fixed TxMode is invalid \n", __FUNCTION__));
+ }
+}
+
+
+VOID RTMPSetAGCInitValue(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR BandWidth)
+{
+ RTMP_CHIP_ASIC_AGC_INIT(pAd, BandWidth);
+
+}
+
+
+/*
+========================================================================
+Routine Description:
+ Check if the channel has the property.
+
+Arguments:
+ pAd - WLAN control block pointer
+ ChanNum - channel number
+ Property - channel property, CHANNEL_PASSIVE_SCAN, etc.
+
+Return Value:
+ TRUE - YES
+ FALSE - NO
+
+Note:
+========================================================================
+*/
+BOOLEAN CHAN_PropertyCheck(
+ IN PRTMP_ADAPTER pAd,
+ IN UINT32 ChanNum,
+ IN UCHAR Property)
+{
+ UINT32 IdChan;
+
+
+ /* look for all registered channels */
+ for(IdChan=0; IdChan<pAd->ChannelListNum; IdChan++)
+ {
+ if (pAd->ChannelList[IdChan].Channel == ChanNum)
+ {
+ if ((pAd->ChannelList[IdChan].Flags & Property) == Property)
+ return TRUE; /* same property */
+ /* End of if */
+
+ break;
+ } /* End of if */
+ } /* End of for */
+
+ return FALSE;
+}
+
+
+#if defined(RT5370) || defined(RT5372) || defined(RT5390) || defined(RT5392)
+VOID AsicCheckForHwRecovery(
+ IN PRTMP_ADAPTER pAd)
+{
+ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
+ {
+ if (pAd->RalinkCounters.LastReceivedByteCount == pAd->RalinkCounters.ReceivedByteCount)
+ {
+ /* If ReceiveByteCount doesn't change, increase SameRxByteCount by 1 */
+ pAd->SameRxByteCount++;
+ }
+ else
+ {
+ pAd->SameRxByteCount = 0;
+ pAd->BbpResetCount = 0;
+ }
+
+ /*
+ If SameRxByteCount keeps happening :
+ for 3 second in infra mode
+ for 5 seconds in idle mode
+ for 1 second in P2PGO
+ */
+ if (
+#ifdef CONFIG_AP_SUPPORT
+ (pAd->SameRxByteCount > 0)
+#endif /* CONFIG_AP_SUPPORT */
+ )
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("AsicCheckForHwRecovery!!\n"));
+
+
+ if (IS_RT5392(pAd))
+ {
+ UCHAR RfValue = 0;
+
+ RT30xxReadRFRegister(pAd, RF_R42, &RfValue);
+ RfValue = (RfValue | 0xC0); /* rx_ctb_en, rx_mix2_en */
+ RT30xxWriteRFRegister(pAd, RF_R42, RfValue);
+ }
+
+ if (pAd->BbpResetFlag == 0)
+ {
+ AsicResetBBPAgent(pAd);
+ pAd->BbpResetFlag = 1;
+ }
+
+ pAd->SameRxByteCount = 0;
+ pAd->BbpResetCount++;
+ }
+ }
+
+ /* Update lastReceiveByteCount */
+ pAd->RalinkCounters.LastReceivedByteCount = pAd->RalinkCounters.ReceivedByteCount;
+}
+#endif /* defined(RT5370) || defined(RT5372) || defined(RT5390) || defined(RT5392) */
+
+
+/* End of mlme.c */
+