View | Details | Raw Unified
Collapse All | Expand All

(-) rt2570-1.1.0-b1/CHANGELOG (+11 lines)
 Lines 22-27    Link Here 
 
 
 Changelog for 802.11g rt2570 USB driver
 Changelog for 802.11g rt2570 USB driver
 Version: CVS
	* Bugfix to allow multiple rt2570 devices
	* Fix for module unloading under 2.4 kernel
	* Fix for signal quality reporting (1247985)
	* Enhancement for TX during RFMON (i.e. aireplay support)
	* Prism Headers in RFMON 
	* Added new USB devices (F5D7050, Linksys@Home)
	* Bugfix : race condition between thread stop and incoming mlme commands
		(Mathieu Desnoyers mathieu.desnoyers@polymtl.ca)
 Version: 1.1.0-beta1
 Version: 1.1.0-beta1
 	* Initial baseline code from Ralink (2.0.3.0)
 	* Initial baseline code from Ralink (2.0.3.0)
 	* Added new USB devices (F5D7060,UB801R,C54RU,MSI6861,GN-WBKG)
 	* Added new USB devices (F5D7060,UB801R,C54RU,MSI6861,GN-WBKG)
(-) rt2570-1.1.0-b1/Module/.#assoc.c.1.2 (-919 lines)
 Lines 1-919    Link Here 
/*************************************************************************** 
 * RT2x00 SourceForge Project - http://rt2x00.sourceforge.net              * 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 *   This program is distributed in the hope that it will be useful,       * 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * 
 *   GNU General Public License for more details.                          * 
 *                                                                         * 
 *   You should have received a copy of the GNU General Public License     * 
 *   along with this program; if not, write to the                         * 
 *   Free Software Foundation, Inc.,                                       * 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * 
 *                                                                         * 
 *   Licensed under the GNU GPL                                            * 
 *   Original code supplied under license from RaLink Inc, 2004.           * 
 ***************************************************************************/
/*************************************************************************** 
 *	Module Name:	assoc.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 ***************************************************************************/
#include "rt_config.h"
UCHAR	CipherWpaTemplate[] = {
		0xdd, 					// WPA IE
		0x16,					// Length
		0x00, 0x50, 0xf2, 0x01,	// oui
		0x01, 0x00,				// Version
		0x00, 0x50, 0xf2, 0x02,	// Multicast
		0x01, 0x00,				// Number of unicast
		0x00, 0x50, 0xf2, 0x02,	// unicast
		0x01, 0x00,				// number of authentication method
		0x00, 0x50, 0xf2, 0x01	// authentication
		};
UCHAR	CipherWpa2Template[] = {
		0x30,					// RSN IE
		0x14,					// Length
		0x01, 0x00,				// Version
		0x00, 0x0f, 0xac, 0x02,	// group cipher, TKIP
		0x01, 0x00,				// number of pairwise
		0x00, 0x0f, 0xac, 0x02,	// unicast
		0x01, 0x00,				// number of authentication method
		0x00, 0x0f, 0xac, 0x02,	// authentication
		0x00, 0x00,				// RSN capability
		};
/*  
    ==========================================================================
    Description: 
        association state machine init, including state transition and timer init
    Parameters: 
        S - pointer to the association state machine
    Note:
        The state machine looks like the following 
        
                               ASSOC_IDLE               ASSOC_WAIT_RSP             REASSOC_WAIT_RSP             DISASSOC_WAIT_RSP
    MT2_MLME_ASSOC_REQ       mlme_assoc_req_action    invalid_state_when_assoc   invalid_state_when_assoc       invalid_state_when_assoc
    MT2_MLME_REASSOC_REQ     mlme_reassoc_req_action  invalid_state_when_reassoc invalid_state_when_reassoc     invalid_state_when_reassoc
    MT2_MLME_DISASSOC_REQ    mlme_disassoc_req_action mlme_disassoc_req_action   mlme_disassoc_req_action       mlme_disassoc_req_action
    MT2_PEER_DISASSOC_REQ    peer_disassoc_action     peer_disassoc_action       peer_disassoc_action           peer_disassoc_action
    MT2_PEER_ASSOC_REQ       drop                     drop                       drop                           drop
    MT2_PEER_ASSOC_RSP       drop                     peer_assoc_rsp_action      drop                           drop
    MT2_PEER_REASSOC_REQ     drop                     drop                       drop                           drop
    MT2_PEER_REASSOC_RSP     drop                     drop                       peer_reassoc_rsp_action        drop
    MT2_CLS3ERR              cls3err_action           cls3err_action             cls3err_action                 cls3err_action
    MT2_ASSOC_TIMEOUT        timer_nop                assoc_timeout_action       timer_nop                      timer_nop
    MT2_REASSOC_TIMEOUT      timer_nop                timer_nop                  reassoc_timeout_action         timer_nop
    MT2_DISASSOC_TIMEOUT     timer_nop                timer_nop                  timer_nop                      disassoc_timeout_action
	IRQL = PASSIVE_LEVEL
	
    ==========================================================================
 */
VOID AssocStateMachineInit(
    IN	PRT2570ADAPTER	pAd, 
    IN  STATE_MACHINE *S, 
    OUT STATE_MACHINE_FUNC Trans[]) 
{
	StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE);
	// first column
	StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction);
	StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction);
	StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction);
	StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
	//StateMachineSetAction(S, ASSOC_IDLE, MT2_CLS3ERR, Cls3errAction);
	// second column
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction);
	//StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_CLS3ERR, Cls3errAction);
	StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction);
	// third column
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction);
	// StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_CLS3ERR, Cls3errAction);
	StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction);
	// fourth column
	StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
	StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
	StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
	StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
	//StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_CLS3ERR, Cls3errAction);
	StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction);
	// initialize the timer
	RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.AssocTimer, AssocTimeout);
	RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.ReassocTimer, ReassocTimeout);
	RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.DisassocTimer, DisassocTimeout);
}
/*
    ==========================================================================
    Description:
        Association timeout procedure. After association timeout, this function 
        will be called and it will put a message into the MLME queue
    Parameters:
        Standard timer parameters
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID  AssocTimeout(unsigned long data)
{
	PRT2570ADAPTER	pAd = (PRT2570ADAPTER)data;
	DBGPRINT(RT_DEBUG_TRACE, "ASSOC - enqueue MT2_ASSOC_TIMEOUT \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;
	MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL);
	//KeSetEvent(&pAd->MLMEEvent, 0, FALSE);	
	RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
}
/*
    ==========================================================================
    Description:
        Reassociation timeout procedure. After reassociation timeout, this 
        function will be called and put a message into the MLME queue
    Parameters:
        Standard timer parameters
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID  ReassocTimeout(unsigned long data)
{
	PRT2570ADAPTER	pAd = (PRT2570ADAPTER)data;
	DBGPRINT(RT_DEBUG_TRACE,"ASSOC - enqueue MT2_REASSOC_TIMEOUT \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;
	MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL);
	//KeSetEvent(&pAd->MLMEEvent, 0, FALSE);	
	RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
}
/*
    ==========================================================================
    Description:
        Disassociation timeout procedure. After disassociation timeout, this 
        function will be called and put a message into the MLME queue
    Parameters:
        Standard timer parameters
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID  DisassocTimeout(unsigned long data)
{
	PRT2570ADAPTER	pAd = (PRT2570ADAPTER)data;
	DBGPRINT(RT_DEBUG_TRACE,"ASSOC - enqueue MT2_DISASSOC_TIMEOUT \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;
	MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL);
	//KeSetEvent(&pAd->MLMEEvent, 0, FALSE);	
	RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
}
/*
    ==========================================================================
    Description:
        mlme assoc req handling procedure
    Parameters:
        Adapter - Adapter pointer
        Elem - MLME Queue Element
    Pre:
        the station has been authenticated and the following information is stored in the config
            -# SSID
            -# supported rates and their length
            -# listen interval (Adapter->PortCfg.default_listen_count)
            -# Transmit power  (Adapter->PortCfg.tx_power)
    Post  :
        -# An association request frame is generated and sent to the air
        -# Association timer starts
        -# Association state -> ASSOC_WAIT_RSP
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID MlmeAssocReqAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
	MACADDR          ApAddr;
	MACHDR           AssocHdr;
	UCHAR            SsidIe = IE_SSID, RateIe = IE_SUPP_RATES, ExtRateIe = IE_EXT_SUPP_RATES;
	UCHAR			 CipherTmp[64];
	UCHAR			 CipherTmpLen;
	USHORT           ListenIntv;
	ULONG            Timeout;
	USHORT           CapabilityInfo;
	UCHAR           *OutBuffer = NULL;
	NDIS_STATUS      NStatus;
	ULONG            FrameLen = 0;
	ULONG			 tmp, idx;
	BOOLEAN			 FoundPMK = FALSE;
	UCHAR			 VarIesOffset;
	// Block all authentication request durning WPA block period
	if (pAd->PortCfg.bBlockAssoc == TRUE)
	{
		DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Block Assoc request durning WPA block period!\n");
		pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
		MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT);
	}	
	// check sanity first
	else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, &ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) 
	{
        RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
        COPY_MAC_ADDR(&pAd->Mlme.AssocAux.Addr, &ApAddr);
		// Mask out unnecessary capability information
		CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; // pAd->PortCfg.SupportedCapabilityInfo;
        pAd->Mlme.AssocAux.CapabilityInfo = CapabilityInfo;
        pAd->Mlme.AssocAux.ListenIntv = ListenIntv;
        NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer);  //Get an unused nonpaged memory
        if (NStatus != NDIS_STATUS_SUCCESS) 
        {
            DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeAssocReqAction() allocate memory failed \n");
            pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
            MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_FAIL_NO_RESOURCE);
            return;
        }
        
		// Add by James 03/06/27
		pAd->PortCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
		// Association don't need to report MAC address
		pAd->PortCfg.AssocInfo.AvailableRequestFixedIEs =
			NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL;
		pAd->PortCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo;
		pAd->PortCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv;		
		// Only reassociate need this
		// NdisMoveMemory(pAd->PortCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, &AssocHdr, sizeof(NDIS_802_11_MAC_ADDRESS));
		pAd->PortCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);	
		
		// First add SSID
		VarIesOffset = 0;
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, &pAd->PortCfg.SsidLen, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen);
		VarIesOffset += pAd->PortCfg.SsidLen;
		// Second add Supported rates
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, &RateIe, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, &pAd->PortCfg.SupportedRatesLen, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, pAd->PortCfg.SupportedRates, pAd->PortCfg.SupportedRatesLen);
		VarIesOffset += pAd->PortCfg.SupportedRatesLen;
		// End Add by James
        MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, &ApAddr, &ApAddr);
		
		// Build basic frame first
		MakeOutgoingFrame(
			OutBuffer,					&FrameLen,
						  sizeof(MACHDR),			&AssocHdr,
						  2,						&CapabilityInfo,
						  2,						&ListenIntv,
						  1,						&SsidIe,
						  1,						&pAd->PortCfg.SsidLen, 
						  pAd->PortCfg.SsidLen, 	pAd->PortCfg.Ssid,
						  1,						&RateIe,
						  1,						&pAd->PortCfg.SupRateLen,
						  pAd->PortCfg.SupRateLen,  pAd->PortCfg.SupRate,
						  END_OF_ARGS);
		if (pAd->PortCfg.ExtRateLen != 0)
		{
			MakeOutgoingFrame(
				OutBuffer + FrameLen,		&tmp,
						1,							&ExtRateIe,
						1,							&pAd->PortCfg.ExtRateLen,
						pAd->PortCfg.ExtRateLen,	pAd->PortCfg.ExtRate,							
						END_OF_ARGS);
			FrameLen += tmp;
		}
		
		// For WPA / WPA-PSK
		if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
		{
			// Copy WPA template to buffer
			CipherTmpLen = sizeof(CipherWpaTemplate);
			NdisMoveMemory(CipherTmp, CipherWpaTemplate, CipherTmpLen);
			// Modify Group cipher
			CipherTmp[11] = ((pAd->PortCfg.GroupCipher == Ndis802_11Encryption2Enabled) ? 0x2 : 0x4);			
			// Modify Pairwise cipher
			CipherTmp[17] = ((pAd->PortCfg.PairCipher == Ndis802_11Encryption2Enabled) ? 0x2 : 0x4);
			// Modify AKM
			CipherTmp[23] = ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) ? 0x1 : 0x2);
			// Make outgoing frame
			MakeOutgoingFrame(
				OutBuffer + FrameLen,	&tmp,
				CipherTmpLen,			&CipherTmp[0],
				END_OF_ARGS);
			FrameLen += tmp;
			
			// Append Variable IE
			NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherTmp, CipherTmpLen);
			VarIesOffset += CipherTmpLen;
			
			// Set Variable IEs Length
			pAd->PortCfg.ReqVarIELen = VarIesOffset;
			pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset;
			// OffsetResponseIEs follow ReqVarIE
			pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen;			
		}
		// For WPA2 / WPA2-PSK
		else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
		{
			// Copy WPA2 template to buffer
			CipherTmpLen = sizeof(CipherWpa2Template);
			NdisMoveMemory(CipherTmp, CipherWpa2Template, CipherTmpLen);
			// Modify Group cipher
			CipherTmp[7] = ((pAd->PortCfg.GroupCipher == Ndis802_11Encryption2Enabled) ? 0x2 : 0x4);			
			// Modify Pairwise cipher
			CipherTmp[13] = ((pAd->PortCfg.PairCipher == Ndis802_11Encryption2Enabled) ? 0x2 : 0x4);
			// Modify AKM
			CipherTmp[19] = ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2) ? 0x1 : 0x2);
			// Check for WPA PMK cache list
			if (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2)
			{
				// Search chched PMKID, append it if existed
				for (idx = 0; idx < PMKID_NO; idx++)
				{
					if (NdisEqualMemory(&ApAddr, &pAd->PortCfg.SavedPMK[idx], 6))
					{
						FoundPMK = TRUE;
						break;
					}
						
				}
				if (FoundPMK)
				{
					// Update length within RSN IE
					CipherTmp[1] += 18;
					// Set PMK number
					*(PUSHORT) &CipherTmp[CipherTmpLen] = 1;
					NdisMoveMemory(&CipherTmp[CipherTmpLen + 2], &pAd->PortCfg.SavedPMK[idx].PMKID, 16);
					CipherTmpLen += 18;
				}
			}
			
			// Make outgoing frame
			MakeOutgoingFrame(
				OutBuffer + FrameLen,	&tmp,
				CipherTmpLen,			&CipherTmp[0],
				END_OF_ARGS);
			FrameLen += tmp;
			// Append Variable IE
			NdisMoveMemory(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherTmp, CipherTmpLen);
			VarIesOffset += CipherTmpLen;
			
			// Set Variable IEs Length
			pAd->PortCfg.ReqVarIELen = VarIesOffset;
			pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset;
			// OffsetResponseIEs follow ReqVarIE
			pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen;			
		}
		else
		{
			// Do nothing
			;
		}
        MiniportMMRequest(pAd, OutBuffer, FrameLen);
            
        RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.AssocTimer, Timeout); /* in mSec */
        pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP;
    } 
    else 
    {
        DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n");
        pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
        MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_INVALID_FORMAT);
    }
}
/*
    ==========================================================================
    Description:
        mlme reassoc req handling procedure
    Parameters:
        Elem - 
    Pre:
        -# SSID  (Adapter->PortCfg.ssid[])
        -# BSSID (AP address, Adapter->PortCfg.bssid)
        -# Supported rates (Adapter->PortCfg.supported_rates[])
        -# Supported rates length (Adapter->PortCfg.supported_rates_len)
        -# Tx power (Adapter->PortCfg.tx_power)
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID MlmeReassocReqAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
	MACADDR              ApAddr;
	MACHDR               ReassocHdr;
	UCHAR                SsidIe = IE_SSID, RateIe = IE_SUPP_RATES, ExtRateIe = IE_EXT_SUPP_RATES;
	USHORT               CapabilityInfo, ListenIntv;
	ULONG                Timeout;
	ULONG                FrameLen = 0;
	NDIS_STATUS          NStatus;
	ULONG			 	 tmp;
	UCHAR               *OutBuffer = NULL;
	// Block all authentication request durning WPA block period
	if (pAd->PortCfg.bBlockAssoc == TRUE)
	{
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Block ReAssoc request durning WPA block period!\n");
        pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
        MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT);
	}	
    // the parameters are the same as the association
    else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, &ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) 
    {
        RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
        NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer);  //Get an unused nonpaged memory
        if(NStatus != NDIS_STATUS_SUCCESS) 
        {
            DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeReassocReqAction() allocate memory failed \n");
            pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
            MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_FAIL_NO_RESOURCE);
            return;
        }
		// Mask out unnecessary capability information
		CapabilityInfo &= SUPPORTED_CAPABILITY_INFO;  // pAd->PortCfg.SupportedCapabilityInfo;
        pAd->Mlme.AssocAux.CapabilityInfo = CapabilityInfo;
        COPY_MAC_ADDR(&pAd->Mlme.AssocAux.Addr, &ApAddr);
        pAd->Mlme.AssocAux.ListenIntv = ListenIntv;
        // make frame, use bssid as the AP address??
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Send RE-ASSOC request...\n");
        MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, &ApAddr, &ApAddr);
        MakeOutgoingFrame(OutBuffer,            &FrameLen,
                          sizeof(MACHDR),       &ReassocHdr,
                          2,                    &CapabilityInfo,
                          2,                    &ListenIntv,
                          MAC_ADDR_LEN,         &ApAddr,
                          1,                    &SsidIe,
                          1,                    &pAd->PortCfg.SsidLen, 
                          pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, 
                          1,                    &RateIe,
						  1,						&pAd->PortCfg.SupRateLen,
						  pAd->PortCfg.SupRateLen,  pAd->PortCfg.SupRate,
                          END_OF_ARGS);
		if (pAd->PortCfg.ExtRateLen != 0)
		{
			MakeOutgoingFrame(OutBuffer + FrameLen, &tmp,
						1,							&ExtRateIe,
						1,							&pAd->PortCfg.ExtRateLen,
						pAd->PortCfg.ExtRateLen,	pAd->PortCfg.ExtRate,							
						END_OF_ARGS);
			FrameLen += tmp;
		}
        MiniportMMRequest(pAd, OutBuffer, FrameLen);
            
        RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.ReassocTimer, Timeout); /* in mSec */
        pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP;
    } 
    else 
    {
        DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n");
        pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
        MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_INVALID_FORMAT);
    }
}
/*
    ==========================================================================
    Description:
        Upper layer issues disassoc request
    Parameters:
        Elem -
        
	IRQL = PASSIVE_LEVEL
    ==========================================================================
 */
VOID MlmeDisassocReqAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    MLME_DISASSOC_REQ_STRUCT *DisassocReq;
    MACHDR                DisassocHdr;
    CHAR                 *OutBuffer = NULL;
    ULONG                 FrameLen = 0;
    NDIS_STATUS           NStatus;
    ULONG                       Timeout = 0;
    // skip sanity check
    DisassocReq = (MLME_DISASSOC_REQ_STRUCT *)(Elem->Msg);
    NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer);  //Get an unused nonpaged memory
    if (NStatus != NDIS_STATUS_SUCCESS) 
    {
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - MlmeDisassocReqAction() allocate memory failed\n");
        pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
        MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_FAIL_NO_RESOURCE);
        return;
    }
    
    RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
    
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Send DISASSOC request\n");
    MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, &pAd->PortCfg.Bssid, &pAd->PortCfg.Bssid);
    MakeOutgoingFrame(OutBuffer,            &FrameLen, 
                      sizeof(MACHDR),       &DisassocHdr, 
                      2,                    &DisassocReq->Reason, 
                      END_OF_ARGS);
    MiniportMMRequest(pAd, OutBuffer, FrameLen);
    NdisZeroMemory(&(pAd->PortCfg.Bssid), MAC_ADDR_LEN);
    
    pAd->PortCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING;
    COPY_MAC_ADDR(&pAd->PortCfg.DisassocSta, &DisassocReq->Addr);
    RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.DisassocTimer, Timeout); /* in mSec */
    pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP;
}
/*
    ==========================================================================
    Description:
        peer sends assoc rsp back
    Parameters:
        Elme - MLME message containing the received frame
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID PeerAssocRspAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    USHORT        CapabilityInfo, Status, Aid;
    UCHAR         Rates[MAX_LEN_OF_SUPPORTED_RATES], RatesLen;
    MACADDR       Addr2;
    BOOLEAN       ExtendedRateIeExist;
    if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &CapabilityInfo, &Status, &Aid, Rates, &RatesLen, &ExtendedRateIeExist)) 
    {
        // The frame is for me ?
        if(MAC_ADDR_EQUAL(&Addr2, &pAd->Mlme.AssocAux.Addr)) 
        {
            DBGPRINT(RT_DEBUG_INFO, "ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status);
            RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
            if(Status == MLME_SUCCESS) 
            {
                // go to procedure listed on page 376
				// Mask out unnecessary capability information
				CapabilityInfo &= SUPPORTED_CAPABILITY_INFO;  // pAd->PortCfg.SupportedCapabilityInfo;
                AssocPostProc(pAd, &Addr2, CapabilityInfo, Aid, Rates, RatesLen, ExtendedRateIeExist);
            } 
            pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
            MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, Status);
        } 
    }
    else
    {
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerAssocRspAction() sanity check fail\n");
    }
}
/*
    ==========================================================================
    Description:
        peer sends reassoc rsp
    Parametrs:
        Elem - MLME message cntaining the received frame
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID PeerReassocRspAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    USHORT      CapabilityInfo;
    USHORT      Status;
    USHORT      Aid;
    UCHAR       Rates[MAX_LEN_OF_SUPPORTED_RATES];
    UCHAR       RatesLen;
    MACADDR     Addr2;
    BOOLEAN     ExtendedRateIeExist;
    if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &CapabilityInfo, &Status, &Aid, Rates, &RatesLen, &ExtendedRateIeExist)) 
    {
        if(MAC_ADDR_EQUAL(&Addr2, &pAd->Mlme.AssocAux.Addr)) // The frame is for me ?
        {
            DBGPRINT(RT_DEBUG_TRACE, "ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status);
            RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
            
            if(Status == MLME_SUCCESS) 
            {
				// Mask out unnecessary capability information
				CapabilityInfo &= SUPPORTED_CAPABILITY_INFO;  // pAd->PortCfg.SupportedCapabilityInfo;
                // go to procedure listed on page 376
                AssocPostProc(pAd, &Addr2, CapabilityInfo, Aid, Rates, RatesLen, ExtendedRateIeExist);
            } 
            pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
            MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, Status);
        } 
    }
    else
    {
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerReassocRspAction() sanity check fail\n");
    }
}
/*
    ==========================================================================
    Description:
        procedures on IEEE 802.11/1999 p.376 
    Parametrs:
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID AssocPostProc(
    IN PRT2570ADAPTER pAd, 
    IN PMACADDR Addr2, 
    IN USHORT CapabilityInfo, 
    IN USHORT Aid, 
    IN UCHAR Rates[], 
    IN UCHAR RatesLen,
    IN BOOLEAN ExtendedRateIeExist) 
{
	ULONG Idx;
    UCHAR RateIe = IE_SUPP_RATES;
	UCHAR VarIesOffset;
    // 2003/12/11 -  skip the following because experiment show that we can not 
    // trust the "privacy" bit in AssocRsp. We can only trust "Privacy" bit specified in
    // BEACON and ProbeRsp.
    // pAd->PortCfg.PrivacyInvoked = CAP_IS_PRIVACY_ON(CapabilityInfo);
    
    pAd->PortCfg.Aid = Aid;
    NdisMoveMemory(pAd->PortCfg.SupportedRates, Rates, RatesLen);
    pAd->PortCfg.SupportedRatesLen = RatesLen;
    COPY_MAC_ADDR(&pAd->PortCfg.Bssid, Addr2);
    AsicSetBssid(pAd, &pAd->PortCfg.Bssid);
    // set listen interval
    pAd->PortCfg.DefaultListenCount = pAd->Mlme.AssocAux.ListenIntv;
//  pAd->PortCfg.CurrListenCount = pAd->Mlme.AssocAux.ListenIntv;
	// Set New WPA information
	Idx = BssTableSearch(&pAd->PortCfg.BssTab, Addr2);
	if (Idx == BSS_NOT_FOUND) 
	{
		DBGPRINT(RT_DEBUG_ERROR, "ASSOC - Can't find BSS after receiving Assoc response\n");
	}
	else
	{
		// Mod by James to fix OID_802_11_ASSOCIATION_INFORMATION
		pAd->PortCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); //+ sizeof(NDIS_802_11_FIXED_IEs); 	// Filled in assoc request
		pAd->PortCfg.AssocInfo.AvailableResponseFixedIEs =
			NDIS_802_11_AI_RESFI_CAPABILITIES | NDIS_802_11_AI_RESFI_STATUSCODE | NDIS_802_11_AI_RESFI_ASSOCIATIONID;
		pAd->PortCfg.AssocInfo.ResponseFixedIEs.Capabilities  = CapabilityInfo;
		pAd->PortCfg.AssocInfo.ResponseFixedIEs.StatusCode    = MLME_SUCCESS;		// Should be success, add failed later
		pAd->PortCfg.AssocInfo.ResponseFixedIEs.AssociationId = Aid;
		// Copy BSS VarIEs to PortCfg associnfo structure.
		// First add Supported rates
		VarIesOffset = 0;
		NdisMoveMemory(pAd->PortCfg.ResVarIEs + VarIesOffset, &RateIe, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ResVarIEs + VarIesOffset, &RatesLen, 1);
		VarIesOffset += 1;
		NdisMoveMemory(pAd->PortCfg.ResVarIEs + VarIesOffset, Rates, RatesLen);
		VarIesOffset += RatesLen;
		// Second add RSN
		NdisMoveMemory(pAd->PortCfg.ResVarIEs + VarIesOffset, pAd->PortCfg.BssTab.BssEntry[Idx].VarIEs, pAd->PortCfg.BssTab.BssEntry[Idx].VarIELen);
		VarIesOffset += pAd->PortCfg.BssTab.BssEntry[Idx].VarIELen;
		
		// Set Variable IEs Length
		pAd->PortCfg.ResVarIELen = VarIesOffset;
		pAd->PortCfg.AssocInfo.ResponseIELength = VarIesOffset;
	}
}
/*
    ==========================================================================
    Description:
        left part of IEEE 802.11/1999 p.374 
    Parameters:
        Elem - MLME message containing the received frame
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID PeerDisassocAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    MACADDR       Addr2;
    USHORT        Reason;
    if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &Reason)) 
    {
        if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, &Addr2)) 
        {
			DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(PeerDisassocAction(Reason = %d))\n", Reason);//steven:for debug
            LinkDown(pAd);
            pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
            // 2002/11/21 -
            // patch RT2430/RT2420 hangup issue. We suspect this AP DIS-ASSOCIATE frame
            // is caused by PHY hangup, so we reset PHY, then auto recover the connection.
            // if this attempt fails, then remains in LinkDown and leaves the problem
            // to MlmePeriodicExec()
            // NICPatchRT2430Bug(pAd);
            pAd->RalinkCounters.BeenDisassociatedCount ++;
			// Remove auto recover effort when disassociate by AP, re-enable for patch 2430 only
            DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Disassociated by AP, Auto Recovery attempt #%d\n", pAd->RalinkCounters.BeenDisassociatedCount);
            MlmeAutoReconnectLastSSID(pAd);
        }
    }
    else
    {
        DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerDisassocAction() sanity check fail\n");
    }
}
/*
    ==========================================================================
    Description:
        what the state machine will do after assoc timeout
    Parameters:
        Elme -
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID AssocTimeoutAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - AssocTimeoutAction\n");
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_REJ_TIMEOUT);
}
/*
    ==========================================================================
    Description:
        what the state machine will do after reassoc timeout
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID ReassocTimeoutAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - ReassocTimeoutAction\n");
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_REJ_TIMEOUT);
}
/*
    ==========================================================================
    Description:
        what the state machine will do after disassoc timeout
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID DisassocTimeoutAction(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - DisassocTimeoutAction\n");
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_SUCCESS);
}
VOID InvalidStateWhenAssoc(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenAssoc(state=%d), reset ASSOC state machine\n", 
        pAd->Mlme.AssocMachine.CurrState);
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT);
}
VOID InvalidStateWhenReassoc(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenReassoc(state=%d), reset ASSOC state machine\n", 
        pAd->Mlme.AssocMachine.CurrState);
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_STATE_MACHINE_REJECT);
}
VOID InvalidStateWhenDisassociate(
    IN PRT2570ADAPTER pAd, 
    IN MLME_QUEUE_ELEM *Elem) 
{
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenDisassoc(state=%d), reset ASSOC state machine\n", 
        pAd->Mlme.AssocMachine.CurrState);
    pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
    MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_STATE_MACHINE_REJECT);
}
/*
    ==========================================================================
    Description:
        right part of IEEE 802.11/1999 page 374
    Note: 
        This event should never cause ASSOC state machine perform state
        transition, and has no relationship with CNTL machine. So we separate
        this routine as a service outside of ASSOC state transition table.
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID Cls3errAction(
    IN PRT2570ADAPTER pAd, 
    IN PMACADDR      pAddr) 
{
    MACHDR                DisassocHdr;
    CHAR                 *OutBuffer = NULL;
    ULONG                 FrameLen = 0;
    NDIS_STATUS           NStatus;
    USHORT                Reason = REASON_CLS3ERR;
    NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer);  //Get an unused nonpaged memory
    if (NStatus != NDIS_STATUS_SUCCESS) 
        return;
    
    DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Class 3 Error, Send DISASSOC frame\n");
    MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, &pAd->PortCfg.Bssid);
    MakeOutgoingFrame(OutBuffer,            &FrameLen, 
                      sizeof(MACHDR),       &DisassocHdr, 
                      2,                    &Reason, 
                      END_OF_ARGS);
    MiniportMMRequest(pAd, OutBuffer, FrameLen);
    pAd->PortCfg.DisassocReason = REASON_CLS3ERR;
    COPY_MAC_ADDR(&pAd->PortCfg.DisassocSta, pAddr);
}
(-) rt2570-1.1.0-b1/Module/connect.c (+5 lines)
 Lines 1282-1289    Link Here 
	ULONG			BulkOutLength;
	ULONG			BulkOutLength;
	PTX_CONTEXT		pBeaconContext = &(pAd->BeaconContext[0]);
	PTX_CONTEXT		pBeaconContext = &(pAd->BeaconContext[0]);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	if (pAd->MLMEThr_pid <= 0)
	if (pAd->MLMEThr_pid <= 0)
	    return;
	    return;
#else
	if (!pAd->MLMEThr_active)
	    return;
#endif
    // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
    // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
    // make sure 1,2,5.5,11 are the firt 4 rates in PortCfg.SupportedRates[] array
    // make sure 1,2,5.5,11 are the firt 4 rates in PortCfg.SupportedRates[] array
    if ((pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && (pAd->PortCfg.AdhocMode == 0))
    if ((pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && (pAd->PortCfg.AdhocMode == 0))
(-) rt2570-1.1.0-b1/Module/.#connect.c.1.2 (-1443 lines)
 Lines 1-1443    Link Here 
/*************************************************************************** 
 * RT2x00 SourceForge Project - http://rt2x00.sourceforge.net              * 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 *   This program is distributed in the hope that it will be useful,       * 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * 
 *   GNU General Public License for more details.                          * 
 *                                                                         * 
 *   You should have received a copy of the GNU General Public License     * 
 *   along with this program; if not, write to the                         * 
 *   Free Software Foundation, Inc.,                                       * 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * 
 *                                                                         * 
 *   Licensed under the GNU GPL                                            * 
 *   Original code supplied under license from RaLink Inc, 2004.           * 
 ***************************************************************************/
/*************************************************************************** 
 *	Module Name:	connect.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 ***************************************************************************/
#include "rt_config.h"
UCHAR	CipherSuiteWpaNoneTkip[] = {
		0x00, 0x50, 0xf2, 0x01,	// oui
		0x01, 0x00,				// Version
		0x00, 0x50, 0xf2, 0x02,	// Multicast
		0x01, 0x00,				// Number of unicast
		0x00, 0x50, 0xf2, 0x00,	// unicast
		0x01, 0x00,				// number of authentication method
		0x00, 0x50, 0xf2, 0x00	// authentication
		};
UCHAR	CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR));
UCHAR	CipherSuiteWpaNoneAes[] = {
		0x00, 0x50, 0xf2, 0x01,	// oui
		0x01, 0x00,				// Version
		0x00, 0x50, 0xf2, 0x04,	// Multicast
		0x01, 0x00,				// Number of unicast
		0x00, 0x50, 0xf2, 0x00,	// unicast
		0x01, 0x00,				// number of authentication method
		0x00, 0x50, 0xf2, 0x00	// authentication
		};
UCHAR	CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR));
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID MlmeCntlInit(
	IN PRT2570ADAPTER pAd, 
	IN STATE_MACHINE *S, 
	OUT STATE_MACHINE_FUNC Trans[]) 
{
	// Control state machine differs from other state machines, the interface 
	// follows the standard interface
	pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID MlmeCntlMachinePerformAction(
	IN PRT2570ADAPTER pAd, 
	IN STATE_MACHINE *S, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	switch(pAd->Mlme.CntlMachine.CurrState) 
	{
		case CNTL_IDLE:
			CntlIdleProc(pAd, Elem);
			break;
		case CNTL_WAIT_DISASSOC:
			CntlWaitDisassocProc(pAd, Elem);
			break;
		case CNTL_WAIT_JOIN:
			CntlWaitJoinProc(pAd, Elem);
			break;
			
		// CNTL_WAIT_REASSOC is the only state in CNTL machine that does
		// not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". 
		// Therefore not protected by NDIS's "only one outstanding OID request" 
		// rule. Which means NDIS may SET OID in the middle of ROAMing attempts.
		// Current approach is to block new SET request at RTMPSetInformation()
		// when CntlMachine.CurrState is not CNTL_IDLE
		case CNTL_WAIT_REASSOC:
			CntlWaitReassocProc(pAd, Elem);
			break;
			
		case CNTL_WAIT_START:
			CntlWaitStartProc(pAd, Elem);
			break;
		case CNTL_WAIT_AUTH:
			CntlWaitAuthProc(pAd, Elem);
			break;
		case CNTL_WAIT_AUTH2:
			CntlWaitAuthProc2(pAd, Elem);
			break;
		case CNTL_WAIT_ASSOC:
			CntlWaitAssocProc(pAd, Elem);
			break;
		case CNTL_WAIT_OID_LIST_SCAN:
			if(Elem->MsgType == MT2_SCAN_CONF) 
			{
				// Resume TxRing after SCANING complete. We hope the out-of-service time
				// won't be too long to let upper layer time-out the waiting frames
				RTUSBResumeMsduTransmission(pAd);
				if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
				{
					NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
				}
				pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			}
			//
			// Following line will potentially cause infinite loop
			//
			//if (pAd->MediaState == NdisMediaStateDisconnected)
			//	  MlmeAutoReconnectLastSSID(pAd);
			break;
			
		case CNTL_WAIT_OID_DISASSOC:
			if (Elem->MsgType == MT2_DISASSOC_CONF) 
			{
				DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(MlmeCntlMachinePerformAction)\n");
				LinkDown(pAd);
				
				if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
				{
					NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
				}
				pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			}
			break;
		default:
			DBGPRINT(RT_DEBUG_ERROR, "CNTL - Illegal message type(=%d)", Elem->MsgType);
			break;
	}
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlIdleProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	MLME_DISASSOC_REQ_STRUCT   DisassocReq;
		
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
	{
		if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
		{
			NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_FAILURE);
			pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
		}
		return;
	}
		
	switch(Elem->MsgType) 
	{
		case OID_802_11_SSID:
			CntlOidSsidProc(pAd, Elem);
			break;
		case RT_OID_802_11_BSSID:
			CntlOidRTBssidProc(pAd,Elem);
			break;
		case OID_802_11_BSSID_LIST_SCAN:
			CntlOidScanProc(pAd,Elem);
			break;
		
		case OID_802_11_DISASSOCIATE:
			DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC;
			// Set the control aux SSID to prevent it reconnect to old SSID
			// Since calling this indicate user don't want to connect to that SSID anymore.
			pAd->Mlme.CntlAux.SsidLen = 32;
			NdisZeroMemory(pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
			break;
		case MT2_MLME_ROAMING_REQ:
			CntlMlmeRoamingProc(pAd, Elem);
			break;
			
		default:
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Illegal message in CntlIdleProc(MsgType=%d)\n",Elem->MsgType);
			break;
	}
}
VOID CntlOidScanProc(
	IN PRT2570ADAPTER pAd,
	IN MLME_QUEUE_ELEM *Elem)
{
	MLME_SCAN_REQ_STRUCT	   ScanReq;
	CHAR					   BroadSsid[MAX_LEN_OF_SSID];
	ULONG					   BssIdx = BSS_NOT_FOUND;
	BSS_ENTRY				   CurrBss;
	ULONG		Now;
	// record current BSS if network is connected. 
	// 2003-2-13 do not include current IBSS if this is the only STA in this IBSS.
	if (pAd->MediaState == NdisMediaStateConnected) //	if (INFRA_ON(pAd) || ADHOC_ON(pAd))
	{
		BssIdx = BssTableSearch(&pAd->PortCfg.BssTab, &pAd->PortCfg.Bssid);
		if (BssIdx != BSS_NOT_FOUND)
		{
			NdisMoveMemory(&CurrBss, &pAd->PortCfg.BssTab.BssEntry[BssIdx], sizeof(BSS_ENTRY));
			// 2003-2-20 reset this RSSI to a low value but not zero. In normal case, the coming SCAN
			//	   should return a correct RSSI to overwrite this. If no BEEACON received after SCAN, 
			//	   at least we still report a "greater than 0" RSSI since we claim it's CONNECTED.
			CurrBss.Rssi = 18; // about -82 dB
		}
	}
			
	// clean up previous SCAN result, add current BSS back to table if any
	BssTableInit(&pAd->PortCfg.BssTab); 
	if (BssIdx != BSS_NOT_FOUND)
	{
		// DDK Note: If the NIC is associated with a particular BSSID and SSID 
		//	  that are not contained in the list of BSSIDs generated by this scan, the 
		//	  BSSID description of the currently associated BSSID and SSID should be 
		//	  appended to the list of BSSIDs in the NIC's database.
		// To ensure this, we append this BSS as the first entry in SCAN result
		NdisMoveMemory(&pAd->PortCfg.BssTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY));
		pAd->PortCfg.BssTab.BssNr = 1;
	}
	BroadSsid[0] = '\0';
	ScanParmFill(pAd, &ScanReq, BroadSsid, 0, BSS_ANY, SCAN_PASSIVE);
	MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, 
		sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
	pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
	Now = jiffies;
	pAd->PortCfg.LastScanTime = Now;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlOidSsidProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM * Elem) 
{
	NDIS_802_11_SSID		  *OidSsid = (NDIS_802_11_SSID *)Elem->Msg;
	MLME_DISASSOC_REQ_STRUCT   DisassocReq;
	ULONG					   Now;
	// Step 0. 
	//	  record the desired SSID and all matching BSSes into CntlAux.SsidBssTab for 
	//	  later-on iteration. Sort by RSSI order
	if (OidSsid->Ssid[0] == 0)
	{
		DBGPRINT_RAW(RT_DEBUG_TRACE, "empty string SSID\n");
		pAd->Mlme.CntlAux.SsidLen = 0;
	}
	else
		pAd->Mlme.CntlAux.SsidLen = (UCHAR)OidSsid->SsidLength;
	NdisMoveMemory(pAd->Mlme.CntlAux.Ssid, OidSsid->Ssid, pAd->Mlme.CntlAux.SsidLen);
	BssTableSsidSort(pAd, &pAd->Mlme.CntlAux.SsidBssTab, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
	pAd->Mlme.CntlAux.BssIdx = 0;
	DBGPRINT(RT_DEBUG_TRACE,"CNTL - %d BSS match the desire SSID %s\n",pAd->Mlme.CntlAux.SsidBssTab.BssNr, pAd->Mlme.CntlAux.Ssid);
	Now = jiffies;
	
	if ((pAd->MediaState == NdisMediaStateConnected) &&
		MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, &pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].Bssid))
	{
		if (((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) &&
			(pAd->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
		{
			// For WPA, WPA-PSK, if the 1x port is not secured, we have to redo 
			// connection process
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP...\n");
			DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, 
						sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
		}
		else if (pAd->bConfigChanged == TRUE)
		{
			// Config has changed, we have to reconnect the same AP
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP Because config changed...\n");
			DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, 
						sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
		}
		else
		{
			// We only check if same to the BSSID with highest RSSI.
			// If roaming of same SSID required, we still do the reconnection.
			// same BSSID, go back to idle state directly
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - already with this BSSID. ignore this SET_SSID request\n");
			if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
			{
				NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
			}
			pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
		} 
	} 
	else if (INFRA_ON(pAd)) 
	{
		// case 1. active association existent
		//	  roaming is done within miniport driver, nothing to do with configuration
		//	  utility. so upon a new SET(OID_802_11_SSID) is received, we just 
		//	  disassociate with the current (or previous) associated AP, if any, 
		//	  then perform a new association with this new SSID, no matter the 
		//	  new/old SSID are the same or npt.
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP...\n");
		DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
		MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, 
					sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
		pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
	}
	else
	{	
		if (ADHOC_ON(pAd))
		{
//			  DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n"));
			DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(CntlOidSsidProc)\n");
			LinkDown(pAd);
			pAd->MediaState = NdisMediaStateDisconnected;
			NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
			NdisMIndicateStatusComplete(pAd->AdapterHandle);
			DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event C!\n");
		}
		if ((pAd->Mlme.CntlAux.SsidBssTab.BssNr == 0) &&
			(pAd->PortCfg.AutoReconnect == TRUE) &&
			(pAd->PortCfg.BssType == BSS_INFRA) &&
			(MlmeValidateSSID(pAd) == TRUE))
		{
		    MLME_SCAN_REQ_STRUCT       ScanReq;
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new scan\n");
			// BroadSsid[0] = '\0';
			ScanParmFill(pAd, &ScanReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen, BSS_ANY, SCAN_ACTIVE);
			MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
			// Reset Missed scan number
//			pAd->PortCfg.IgnoredScanNumber = 0;
			pAd->PortCfg.LastScanTime = Now;
		}
		else
		{
			IterateOnBssTab(pAd);
		}
	} 
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlOidRTBssidProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM * Elem) 
{
	ULONG		BssIdx;
	MACADDR 	*pOidBssid = (MACADDR *)Elem->Msg;
	MLME_DISASSOC_REQ_STRUCT	DisassocReq;
	MLME_JOIN_REQ_STRUCT		JoinReq;
 
	COPY_MAC_ADDR(&pAd->Mlme.CntlAux.Bssid, pOidBssid);
	BssIdx = BssTableSearch(&pAd->PortCfg.BssTab, pOidBssid);
	   
	if (BssIdx == BSS_NOT_FOUND) 
	{
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n");
		if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
		{
			//NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_NOT_ACCEPTED);
		}
		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
		return;
	}
	// copy the matched BSS entry from PortCfg.BssTab to CntlAux.SsidBssTab
	pAd->Mlme.CntlAux.BssIdx = 0;
	pAd->Mlme.CntlAux.SsidBssTab.BssNr = 1;
	NdisMoveMemory(&pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0], &pAd->PortCfg.BssTab.BssEntry[BssIdx], sizeof(BSS_ENTRY));
	// Add SSID into Mlme.CntlAux for site surey joining hidden SSID
	pAd->Mlme.CntlAux.SsidLen = pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].SsidLen;
	NdisMoveMemory(pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].Ssid, pAd->Mlme.CntlAux.SsidLen);	
	// 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP
	// we just follow normal procedure. The reason of user doing this may because he/she changed
	// AP to another channel, but we still received BEACON from it thus don't claim Link Down.
	// Since user knows he's chnged AP channel, he'll re-connect again. By skipping the following
	// checking, we'll disassociate then re-do normal association with this AP at the new channel.
	// 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do
	// connection when setting the same BSSID.
	if ( (pAd->MediaState == NdisMediaStateConnected) && //(INFRA_ON(pAd) || ADHOC_ON(pAd)) &&
		MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, pOidBssid))
	{
		// same BSSID, go back to idle state directly
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - already in this BSSID. ignore this SET_BSSID request\n");
		if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
		{
			NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
		}
		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
	} 
	else 
	{
		if (INFRA_ON(pAd))
		{
			// disassoc from current AP first
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP ...\n");
			DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, 
						sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
		}
		else
		{
			if (ADHOC_ON(pAd))
			{
				DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(CntlOidRTBssidProc)\n");
				LinkDown(pAd);
				pAd->MediaState = NdisMediaStateDisconnected;
				NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
				NdisMIndicateStatusComplete(pAd->AdapterHandle);
				DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event C!\n");
			}
			
			// No active association, join the BSS immediately
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n",
				pOidBssid->Octet[0],pOidBssid->Octet[1],pOidBssid->Octet[2],
				pOidBssid->Octet[3],pOidBssid->Octet[4],pOidBssid->Octet[5]);
			JoinParmFill(pAd, &JoinReq, pAd->Mlme.CntlAux.BssIdx);
			MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN;
		}
	} 
}
// Roaming is the only external request triggering CNTL state machine
// despite of other "SET OID" operation. All "SET OID" related oerations 
// happen in sequence, because no other SET OID will be sent to this device
// until the the previous SET operation is complete (successful o failed).
// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"?
// or been corrupted by other "SET OID"?
VOID CntlMlmeRoamingProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	// TODO: 
	// AP in different channel may show lower RSSI than actual value??
	// should we add a weighting factor to compensate it?
	DBGPRINT(RT_DEBUG_TRACE,"CNTL - Roaming in CntlAux.RoamTab...\n");
	BssTableSortByRssi(&pAd->Mlme.CntlAux.RoamTab);
	pAd->Mlme.CntlAux.RoamIdx=0;
	IterateOnBssTab2(pAd);
	
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitDisassocProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	MLME_START_REQ_STRUCT	  StartReq;
	
	if (Elem->MsgType == MT2_DISASSOC_CONF) 
	{
		DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(CntlWaitDisassocProc)\n");
		LinkDown(pAd);
		
		// case 1. no matching BSS, and user wants ADHOC, so we just start a new one		
		if ((pAd->Mlme.CntlAux.SsidBssTab.BssNr==0) && (pAd->PortCfg.BssType == BSS_INDEP))
		{
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->Mlme.CntlAux.Ssid);
			StartParmFill(pAd, &StartReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
			MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
		}
		// case 2. try each matched BSS
		else
		{
			IterateOnBssTab(pAd);
		}
	}
}
			
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitJoinProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT						Reason;
	MLME_AUTH_REQ_STRUCT		AuthReq;
	if (Elem->MsgType == MT2_JOIN_CONF) 
	{
		NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
		if (Reason == MLME_SUCCESS) 
		{
			// 1. joined an IBSS, we are pretty much done here
			if (pAd->PortCfg.BssType == BSS_INDEP)
			{
				LinkUp(pAd, BSS_INDEP);
				if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
				{
					NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
				}
				pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
				RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
			} 
			// 2. joined a new INFRA network, start from authentication
			else 
			{
//				RTUSBWriteMACRegister(pAd, TXRX_CSR2, 0x67e);//steven:for test
				// either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first
				if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeShared) ||
					(pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch))
				{
					AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeShared);
				}
				else
				{
					AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen);
				}
				MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, 
							sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
				pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH;
			}
		}
		else
		{
			// 3. failed, try next BSS
			pAd->Mlme.CntlAux.BssIdx++;
			IterateOnBssTab(pAd);
		} 
	}	 
}
			
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitStartProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT		Result;
	if (Elem->MsgType == MT2_START_CONF) 
	{
		NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT));
		if (Result == MLME_SUCCESS) 
		{
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - We have started a new ADHOC network\n");
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - BSSID %02x:%02x:%02x:%02x:%02x:%02x ...\n", 
				pAd->PortCfg.Bssid.Octet[0],
				pAd->PortCfg.Bssid.Octet[1],
				pAd->PortCfg.Bssid.Octet[2],
				pAd->PortCfg.Bssid.Octet[3],
				pAd->PortCfg.Bssid.Octet[4],
				pAd->PortCfg.Bssid.Octet[5]);
			LinkUp(pAd, BSS_INDEP);
			if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
			{
				NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
			}
			pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
		}
		else
		{
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Start FAIL. BUG!!!!!\n");
			if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
			{
				NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_FAILURE);
			}
			pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
		}
	}
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitAuthProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT						 Reason;
	MLME_ASSOC_REQ_STRUCT		 AssocReq;
	MLME_AUTH_REQ_STRUCT		 AuthReq;
	if (Elem->MsgType == MT2_AUTH_CONF) 
	{
		NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
		if (Reason == MLME_SUCCESS) 
		{
			AssocParmFill(pAd, &AssocReq, &pAd->PortCfg.Bssid, pAd->PortCfg.CapabilityInfo, 
						  ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, 
						sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC;
		} 
		else
		{
			// This fail may because of the AP already keep us in its MAC table without 
			// ageing-out. The previous authentication attempt must have let it remove us.
			// so try Authentication again may help. For D-Link DWL-900AP+ compatibility.
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, try again...\n");
			if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeShared) ||
				(pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch))
			{
				// either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first
				AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeShared);
			}
			else
			{
				AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen);
			}
			
			MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, 
						sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2;
		}
	}	 
}
			
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitAuthProc2(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT						 Reason;
	MLME_ASSOC_REQ_STRUCT		 AssocReq;
	MLME_AUTH_REQ_STRUCT		 AuthReq;
	if (Elem->MsgType == MT2_AUTH_CONF) 
	{
		NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
		if (Reason == MLME_SUCCESS) 
		{
			AssocParmFill(pAd, &AssocReq, &pAd->PortCfg.Bssid, pAd->PortCfg.CapabilityInfo, 
						  ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount);
			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, 
						sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq);
			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC;
		} 
		else
		{
			if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) &&
				 (pAd->Mlme.AuthAux.Alg == Ndis802_11AuthModeShared))
			{
				DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, try OPEN system...\n");
				AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen);
				MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, 
							sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
				pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2;
			}
			else 
			{
				// not success, try next BSS
				DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, give up; try next BSS\n");
				pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //???????
				pAd->Mlme.CntlAux.BssIdx++;
//				RTUSBWriteMACRegister(pAd, TXRX_CSR2, 0x7e);//steven:for test
				IterateOnBssTab(pAd);
			}
		}
	}	 
}
			
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitAssocProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT		Reason;
	if (Elem->MsgType == MT2_ASSOC_CONF) 
	{
		NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
		if (Reason == MLME_SUCCESS) 
		{
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Association successful on BSS #%d\n",pAd->Mlme.CntlAux.BssIdx);
//			RTUSBWriteMACRegister(pAd, TXRX_CSR2, 0x7e);//steven:for test
			LinkUp(pAd, BSS_INFRA);
			if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
			{
				NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
			}
			pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
		} 
		else 
		{
			// not success, try next BSS
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Association fails on BSS #%d\n",pAd->Mlme.CntlAux.BssIdx);
//			  pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;//steven:for test
			pAd->Mlme.CntlAux.BssIdx++;
//			RTUSBWriteMACRegister(pAd, TXRX_CSR2, 0x7e);//steven:for test
			IterateOnBssTab(pAd);
		}
	}
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID CntlWaitReassocProc(
	IN PRT2570ADAPTER pAd, 
	IN MLME_QUEUE_ELEM *Elem) 
{
	USHORT		Result;
	if (Elem->MsgType == MT2_REASSOC_CONF) 
	{
		NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT));
		if (Result == MLME_SUCCESS) 
		{
			BSS_ENTRY *pBss = &pAd->Mlme.CntlAux.RoamTab.BssEntry[pAd->Mlme.CntlAux.RoamIdx];
			// COPY_MAC_ADDR(&pAd->PortCfg.Bssid, &pBss->Bssid);
			// AsicSetBssid(pAd, &pAd->PortCfg.Bssid);
			
			// The following steps are supposed to be done after JOIN in normal procedure
			// But since this RE-ASSOC skips the JOIN procedure, we have to do it after
			// RE-ASSOC succeeds. If RE-ASSOC fails, then stay at original AP without any change
			pAd->PortCfg.BeaconPeriod = pBss->BeaconPeriod;
			pAd->PortCfg.Channel = pBss->Channel;
			// The security setting should always follow upper layer definition, not from frame
			//pAd->PortCfg.PrivacyInvoked = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
			pAd->PortCfg.SupportedRatesLen = pBss->RatesLen;
			NdisMoveMemory(pAd->PortCfg.SupportedRates, pBss->Rates, pBss->RatesLen);
			// Check for 802.11g information, if 802.11 b /g mixed mode.
			pAd->PortCfg.CapabilityInfo = pBss->CapabilityInfo;
			pAd->PortCfg.CfpPeriod = pBss->CfpPeriod;
			pAd->PortCfg.CfpMaxDuration = pBss->CfpMaxDuration;
			pAd->PortCfg.CfpDurRemain = pBss->CfpDurRemaining;
			pAd->PortCfg.CfpCount = pBss->CfpCount;
			// 
			// NDIS requires a new Link UP indication but no Link Down for RE-ASSOC
			//
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Re-assocition successful on BSS #%d\n", pAd->Mlme.CntlAux.RoamIdx);
			LinkUp(pAd, BSS_INFRA);
			pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
			
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
		} 
		else 
		{
			// reassoc failed, try to pick next BSS in the BSS Table
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - Re-assocition fails on BSS #%d\n", pAd->Mlme.CntlAux.RoamIdx);
			pAd->Mlme.CntlAux.RoamIdx++;
			IterateOnBssTab2(pAd);
		}
	}
}
			
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID LinkUp(
	IN PRT2570ADAPTER pAd,
	IN UCHAR BssType) 
{
	ULONG	Now;
	UCHAR			buffer[22];
	
	DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! LINK UP !!!\n");
	MlmeUpdateTxRates(pAd, TRUE);
	RTUSBMultiReadMAC(pAd, STA_CSR0, buffer, 22);
	NdisMoveMemory(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11));
	NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS));
	Now = jiffies;
	pAd->PortCfg.LastBeaconRxTime = Now;   // last RX timestamp
	
	if ((pAd->PortCfg.WindowsTxPreamble != Rt802_11PreambleLong) &&
		CAP_IS_SHORT_PREAMBLE_ON(pAd->PortCfg.CapabilityInfo))
	{
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! Set to short preamble!!!\n");
		MlmeSetTxPreamble(pAd, Rt802_11PreambleShort);
	}
	
	pAd->PortCfg.BssType = BssType;
	if (BssType == BSS_INDEP)
	{
//		USHORT SentBeaconsCount, ReceivedBeaconsCount;
//		RTUSBReadMACRegister(pAd, STA_CSR5, &SentBeaconsCount);
//		RTUSBReadMACRegister(pAd, STA_CSR10, &ReceivedBeaconsCount);
		pAd->PortCfg.Mibss = TRUE;
		pAd->PortCfg.Massoc = FALSE;
		AsicEnableIbssSync(pAd);
		
#ifdef	SINGLE_ADHOC_LINKUP
		// Although this did not follow microsoft's recommendation.
		//Change based on customer's request
		pAd->MediaState = NdisMediaStateConnected;
		NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_CONNECT, (PVOID)NULL, 0);
		NdisMIndicateStatusComplete(pAd->AdapterHandle);
#endif
	}
	else // BSS_INFRA
	{
            // need to check
		//InterlockedExchange(&(pAd->PortCfg.DataPacketsFromAP), 0);
		pAd->PortCfg.Massoc = TRUE;
		pAd->PortCfg.Mibss = FALSE;
		// NOTE:
		// the decision of using "short slot time" or not may change dynamically due to
		// new STA association to the AP. so we have to decide that upon parsing BEACON, not here
		// NOTE:
		// the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically
		// due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here
		
		ComposePsPoll(pAd);
		ComposeNullFrame(pAd);
		AsicEnableBssSync(pAd);
		if (pAd->PortCfg.EnableTxBurst)
		{
			//Set CWmin/CWmax to 0.
			RTUSBWriteMACRegister(pAd, MAC_CSR22, 0x100);
		}
		else
		{
			RTUSBWriteMACRegister(pAd, MAC_CSR22, 0x53);
		}
	
		// only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode
		// should wait until at least 2 active nodes in this BSSID.
		pAd->MediaState = NdisMediaStateConnected;
		NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_CONNECT, (PVOID)NULL, 0);
		NdisMIndicateStatusComplete(pAd->AdapterHandle);
	}
	DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_CONNECT Event B!\n");
	if ((pAd->PortCfg.LedMode != LED_MODE_SINGLE)&&(pAd->PortCfg.LedMode != LED_MODE_TXRX_ACTIVITY))
	{
		ASIC_LED_ACT_ON(pAd);
	}
	if (pAd->PortCfg.LedMode == LED_MODE_ALPHA){
		pAd->PortCfg.LedCntl.fSiteSurvey = FALSE;
		pAd->PortCfg.LedCntl.fLinkUp = TRUE;
	}	
	AsicSetSlotTime(pAd, FALSE);
	pAd->Mlme.PeriodicRound = 0;
	// Reset config flag
	pAd->bConfigChanged = FALSE;
	// Update extra information to link is up
	pAd->ExtraInfo = GENERAL_LINK_UP;
	pAd->PortCfg.WpaState = SS_START;
	RTUSBKickBulkOut(pAd);
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID LinkDown(
	IN PRT2570ADAPTER pAd) 
{
	DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! LINK DOWN !!!\n");
	if (ADHOC_ON(pAd))		// Adhoc mode link down
	{
		pAd->PortCfg.Mibss = FALSE;
#ifdef	SINGLE_ADHOC_LINKUP
		pAd->MediaState = NdisMediaStateDisconnected;
		NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
		NdisMIndicateStatusComplete(pAd->AdapterHandle);
		// clean up previous SCAN result, add current BSS back to table if any
		BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
#else
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
		{
			pAd->MediaState = NdisMediaStateDisconnected;
			NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
			NdisMIndicateStatusComplete(pAd->AdapterHandle);
			// clean up previous SCAN result, add current BSS back to table if any
			BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
		}
#endif
		
	}
	else					// Infra structure mode
	{
		pAd->PortCfg.Massoc = FALSE;
		pAd->MediaState = NdisMediaStateDisconnected;
		DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event A!\n");
		BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
		// restore back to - 
		//		1. long slot (20 us) or short slot (9 us) time
		//		2. turn on/off RTS/CTS and/or CTS-to-self protection
		//		3. short preamble
		if (pAd->PortCfg.BGProtectionInUsed == TRUE)
		{
			pAd->PortCfg.BGProtectionInUsed = FALSE;
			DBGPRINT(RT_DEBUG_TRACE, "Link down - turn off B/G protection\n");
		}
		if (pAd->PortCfg.Pss == PWR_SAVE)
		{
			RTUSBWriteMACRegister(pAd, MAC_CSR1, 1);
			RTUSBWriteMACRegister(pAd, MAC_CSR1, 4);
			pAd->PortCfg.Pss = PWR_ACTIVE;
		}
	}
	
	AsicSetSlotTime(pAd, FALSE);
	RTUSBWriteMACRegister(pAd, MAC_CSR22, 0x53);
	AsicRestoreBbpSensibility(pAd);
	
	if (pAd->PortCfg.WindowsTxPreamble == Rt802_11PreambleShort)
		MlmeSetTxPreamble(pAd, Rt802_11PreambleShort);
	else
		MlmeSetTxPreamble(pAd, Rt802_11PreambleLong);
	if ((pAd->PortCfg.LedMode != LED_MODE_SINGLE) && (pAd->PortCfg.LedMode != LED_MODE_ASUS))
	{
		ASIC_LED_ACT_OFF(pAd);
	}
	else if ((pAd->PortCfg.LedMode == LED_MODE_ASUS) && (pAd->PortCfg.bRadio == TRUE))
	{
		RTUSBWriteMACRegister(pAd, MAC_CSR20, 0x0002);
	}
	AsicDisableSync(pAd);
	pAd->Mlme.PeriodicRound = 0;
	pAd->ScanAllowed = TRUE;
	// Remove PortCfg Information after link down
	NdisZeroMemory(&(pAd->PortCfg.Bssid), MAC_ADDR_LEN);
	NdisZeroMemory(pAd->PortCfg.Ssid, MAX_LEN_OF_SSID);
	pAd->PortCfg.SsidLen = 0;
	
	// Reset WPA-PSK state. Only reset when supplicant enabled
	if (pAd->PortCfg.WpaState != SS_NOTUSE)
	{
		pAd->PortCfg.WpaState = SS_START;
		// Clear Replay counter
		NdisZeroMemory(pAd->PortCfg.ReplayCounter, 8);
	}
	// Remove all WPA keys after link down
	RTMPWPARemoveAllKeys(pAd);
	// 802.1x port control
	pAd->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
	pAd->PortCfg.MicErrCnt = 0;
	if (pAd->PortCfg.LedMode == LED_MODE_ALPHA)
		pAd->PortCfg.LedCntl.fLinkUp = FALSE;
	// Update extra information to link is up
	pAd->ExtraInfo = GENERAL_LINK_DOWN;
	// Start STA supplicant state machine
	//pAd->PortCfg.WpaState = SS_NOTUSE;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID MlmeCntlConfirm(
	IN PRT2570ADAPTER pAd, 
	IN ULONG MsgType, 
	IN USHORT Msg) 
{
	MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg);
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID IterateOnBssTab(
	IN PRT2570ADAPTER pAd) 
{
	MLME_START_REQ_STRUCT	StartReq;
	MLME_JOIN_REQ_STRUCT	JoinReq;
	ULONG					BssIdx;
	BssIdx = pAd->Mlme.CntlAux.BssIdx;
	if (BssIdx < pAd->Mlme.CntlAux.SsidBssTab.BssNr) 
	{
		if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS))
			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - Trying BSSID %02x:%02x:%02x:%02x:%02x:%02x ...\n", 
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[0],
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[1],
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[2],
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[3],
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[4],
			pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[5]);
		JoinParmFill(pAd, &JoinReq, BssIdx);
		MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT),
					&JoinReq);
		pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN;
	}
	else if (pAd->PortCfg.BssType == BSS_INDEP)
	{
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->Mlme.CntlAux.Ssid);
		StartParmFill(pAd, &StartReq, pAd->Mlme.CntlAux.Ssid, (UCHAR)pAd->Mlme.CntlAux.SsidLen);
		MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq);
		pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
	}
	else // no more BSS
	{
		if (pAd->Mlme.CntlAux.CurrReqIsFromNdis)
		{
			DBGPRINT(RT_DEBUG_TRACE, "CNTL - All BSS fail; reply NDIS_STATUS_NOT_ACCEPTED\n");
			NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_SUCCESS);
		}
		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
	} 
}
// for re-association only
VOID IterateOnBssTab2(
	IN PRT2570ADAPTER pAd) 
{
	MLME_REASSOC_REQ_STRUCT ReassocReq;
	ULONG					BssIdx;
	BSS_ENTRY				*pBss;
	
	BssIdx = pAd->Mlme.CntlAux.RoamIdx;
	pBss = &pAd->Mlme.CntlAux.RoamTab.BssEntry[BssIdx];
	if (BssIdx < pAd->Mlme.CntlAux.RoamTab.BssNr)
	{
		if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS))
			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - try BSS #%d %02x:%02x:%02x:%02x:%02x:%02x ...\n", 
			BssIdx, pBss->Bssid.Octet[0],pBss->Bssid.Octet[1],pBss->Bssid.Octet[2],
			pBss->Bssid.Octet[3],pBss->Bssid.Octet[4],pBss->Bssid.Octet[5]);
		AsicSwitchChannel(pAd, pBss->Channel);
		AsicLockChannel(pAd, pBss->Channel);
		
		// reassociate message has the same structure as associate message
		AssocParmFill(pAd, &ReassocReq, &pBss->Bssid, pBss->CapabilityInfo, 
					  ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount);
		MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, 
					sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq);
		
		pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC;
	}
	else // no more BSS
	{
		DBGPRINT(RT_DEBUG_TRACE, "CNTL - All roaming failed, stay with original AP\n");
		AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
		AsicLockChannel(pAd, pAd->PortCfg.Channel);
		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
	} 
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID JoinParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, 
	IN ULONG BssIdx) 
{
	JoinReq->BssIdx = BssIdx;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID AssocParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, 
	IN MACADDR					 *Addr, 
	IN USHORT					  CapabilityInfo, 
	IN ULONG					  Timeout, 
	IN USHORT					  ListenIntv) 
{
	COPY_MAC_ADDR(&AssocReq->Addr, Addr);
	// Add mask to support 802.11b mode only
	AssocReq->CapabilityInfo = CapabilityInfo & 0xfff3; // not cf-pollable, not cf-poll-request
	AssocReq->Timeout = Timeout;
	AssocReq->ListenIntv = ListenIntv;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID ScanParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, 
	IN CHAR Ssid[], 
	IN UCHAR SsidLen, 
	IN UCHAR BssType, 
	IN UCHAR ScanType) 
{
	ScanReq->SsidLen = SsidLen;
	NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen);
	ScanReq->BssType = BssType;
	ScanReq->ScanType = ScanType;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID DisassocParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, 
	IN MACADDR *Addr, 
	IN USHORT Reason) 
{
	COPY_MAC_ADDR(&DisassocReq->Addr, Addr);
	DisassocReq->Reason = Reason;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID StartParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_START_REQ_STRUCT *StartReq, 
	IN CHAR Ssid[], 
	IN UCHAR SsidLen) 
{
	NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); 
	StartReq->SsidLen = SsidLen;
}
/*
	==========================================================================
	Description:
	==========================================================================
*/
VOID AuthParmFill(
	IN PRT2570ADAPTER pAd, 
	IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, 
	IN MACADDR *Addr, 
	IN USHORT Alg) 
{
	COPY_MAC_ADDR(&AuthReq->Addr, Addr);
	AuthReq->Alg = Alg;
	AuthReq->Timeout = AUTH_TIMEOUT;
}
/*
	==========================================================================
	Description:
	==========================================================================
 */
VOID ComposePsPoll(
	IN PRT2570ADAPTER pAd)
{
	PSPOLL_FRAME *pPsPoll = (PSPOLL_FRAME *)&(pAd->PsPollContext.TransferBuffer->WirelessPacket);
	NdisZeroMemory(pPsPoll, sizeof(PSPOLL_FRAME));
	pPsPoll->Type = BTYPE_CNTL;
	pPsPoll->SubType = SUBTYPE_PS_POLL;
	pPsPoll->Aid = pAd->PortCfg.Aid | 0xC000;
	COPY_MAC_ADDR(&(pPsPoll->Bssid), &pAd->PortCfg.Bssid);
	COPY_MAC_ADDR(&(pPsPoll->Ta), &(pAd->CurrentAddress));
}
VOID ComposeNullFrame(
	IN PRT2570ADAPTER pAd)
{
	PHEADER_802_11 pNullFrame = (PHEADER_802_11)&(pAd->NullContext.TransferBuffer->WirelessPacket);
	MgtMacHeaderInit(pAd, (PMACHDR)pNullFrame, SUBTYPE_NULL_FUNC, 1, &pAd->PortCfg.Bssid, &pAd->PortCfg.Bssid);
	pNullFrame->Controlhead.Duration = 0;
	pNullFrame->Controlhead.Frame.Type = BTYPE_DATA;
}
/*
	==========================================================================
	Description:
		Pre-build a BEACON frame in the shared memory
	==========================================================================
*/
VOID MakeIbssBeacon(
	IN PRT2570ADAPTER pAd) 
{
	UCHAR			SsidIe = IE_SSID, DsIe = IE_DS_PARM, IbssIe = IE_IBSS_PARM, SuppIe = IE_SUPP_RATES, 
					DsLen = 1, IbssLen = 2;
	UCHAR			i, ExtRateIe = IE_EXT_SUPP_RATES, ExtRatesLen;
	UCHAR			ErpIe[3] = {IE_ERP, 1, 0x04};
	MACHDR			BcnHdr;
	USHORT			CapabilityInfo;
	LARGE_INTEGER	FakeTimestamp;
	ULONG			FrameLen;
	UCHAR			SupportedRatesLen = 0;
	UCHAR			SupportedRates[MAX_LEN_OF_SUPPORTED_RATES];
	BOOLEAN			Privacy;
	PUCHAR			pBeaconFrame;
	PTXD_STRUC		pTxD;
	ULONG			BulkOutLength;
	PTX_CONTEXT		pBeaconContext = &(pAd->BeaconContext[0]);
	if (pAd->MLMEThr_pid <= 0)
	    return;
    // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
    // make sure 1,2,5.5,11 are the firt 4 rates in PortCfg.SupportedRates[] array
    if ((pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && (pAd->PortCfg.AdhocMode == 0))
    {
	    for (i = 0; i < pAd->PortCfg.SupportedRatesLen; i++)
	    {
	        switch (pAd->PortCfg.SupportedRates[i] & 0x7f)
	        {
	            case 2:
	            case 4:
	            case 11:
	            case 22:
	                SupportedRates[SupportedRatesLen] = pAd->PortCfg.SupportedRates[i];
	                SupportedRatesLen ++;
	                break;
	            default:
	                break;
	        }
	    }
	    // error handling - should never happen
	    if (SupportedRatesLen != 4)
	    {
            SupportedRatesLen = 4;
            SupportedRates[0] = 0x82;
            SupportedRates[1] = 0x84;
            SupportedRates[2] = 0x8b;
            SupportedRates[3] = 0x96;
	    }
    }
    else
    {
        SupportedRatesLen = pAd->PortCfg.SupportedRatesLen;
        NdisMoveMemory(SupportedRates, pAd->PortCfg.SupportedRates, SupportedRatesLen);
    }
	if (pBeaconContext->InUse == TRUE)
		return;
	else
		pBeaconContext->InUse = TRUE;
    pAd->PortCfg.AtimWin = 0;  // ??????
    
    // compose IBSS beacon frame
    MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, &pAd->PortCfg.Broadcast, &pAd->PortCfg.Bssid);
    Privacy = (pAd->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) || 
              (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) || 
              (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled);
    CapabilityInfo = CAP_GENERATE(0, 1, 0, 0, Privacy, (pAd->PortCfg.WindowsTxPreamble == Rt802_11PreambleShort));
	// Prepare beacon frame, this should go to beacon_ring[1] which contains the real body.
	pBeaconFrame = (PUCHAR) pAd->BeaconContext[1].TransferBuffer->WirelessPacket;
	
    if (SupportedRatesLen <= 8)
    {
        MakeOutgoingFrame(pBeaconFrame,                &FrameLen,
                      MAC_HDR_LEN,                     &BcnHdr, 
                      TIMESTAMP_LEN,                   &FakeTimestamp,
                      2,                               &pAd->PortCfg.BeaconPeriod,
                      2,                               &CapabilityInfo,
                      1,                               &SsidIe, 
                      1,                               &pAd->PortCfg.SsidLen, 
                      pAd->PortCfg.SsidLen,             pAd->PortCfg.Ssid,
                      1,                               &SuppIe, 
                      1,                               &SupportedRatesLen,
                      SupportedRatesLen,               SupportedRates, 
                      1,                               &DsIe, 
                      1,                               &DsLen, 
                      1,                               &pAd->PortCfg.Channel,
                      1,                               &IbssIe, 
                      1,                               &IbssLen, 
                      2,                               &pAd->PortCfg.AtimWin,
                      END_OF_ARGS);
    }
    else
    {
        ExtRatesLen = SupportedRatesLen - 8;
        SupportedRatesLen = 8;
        MakeOutgoingFrame(pBeaconFrame,                &FrameLen,
                      MAC_HDR_LEN,                     &BcnHdr, 
                      TIMESTAMP_LEN,                   &FakeTimestamp,
                      2,                               &pAd->PortCfg.BeaconPeriod,
                      2,                               &CapabilityInfo,
                      1,                               &SsidIe, 
                      1,                               &pAd->PortCfg.SsidLen, 
                      pAd->PortCfg.SsidLen,             pAd->PortCfg.Ssid,
                      1,                               &SuppIe, 
                      1,                               &SupportedRatesLen,
                      SupportedRatesLen,                SupportedRates, 
                      1,                               &DsIe, 
                      1,                               &DsLen, 
                      1,                               &pAd->PortCfg.Channel,
                      1,                               &IbssIe, 
                      1,                               &IbssLen, 
                      2,                               &pAd->PortCfg.AtimWin,
                      3,                               ErpIe,
                      1,                               &ExtRateIe,
                      1,                               &ExtRatesLen,
                      ExtRatesLen,                     &SupportedRates[SupportedRatesLen],
                      END_OF_ARGS);
    }
    
	// If adhoc secruity is set for WPA-None, append the cipher suite IE
	if (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPANone)
	{
		ULONG	tmp = 0;
		UCHAR	WpaIe = IE_WPA;
		
		if (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled)		// Tkip
		{
        	MakeOutgoingFrame(pBeaconFrame + FrameLen,                    &tmp,
				1,						  &WpaIe,
				1,						  &CipherSuiteWpaNoneTkipLen,
				CipherSuiteWpaNoneTkipLen,	  &CipherSuiteWpaNoneTkip[0],
				END_OF_ARGS);
			FrameLen += tmp;
		}
		else if (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled)	// Aes
		{
        	MakeOutgoingFrame(pBeaconFrame + FrameLen,                    &tmp,
				1,						  &WpaIe,
				1,						  &CipherSuiteWpaNoneAesLen,
				CipherSuiteWpaNoneAesLen,	  &CipherSuiteWpaNoneAes[0],
				END_OF_ARGS);
			FrameLen += tmp;
		}
	}
	
    BulkOutLength = sizeof(TXD_STRUC) + FrameLen;
	if ((BulkOutLength % 2) == 1)
		BulkOutLength ++;
//	if (BulkOutLength % pAd->BulkOutMaxPacketSize == 0)
//		BulkOutLength += 2;
    for (i = 0; i < BEACON_RING_SIZE; i++)
	{
		pTxD = (PTXD_STRUC) &pAd->BeaconContext[i].TransferBuffer->TxDesc;
		NdisZeroMemory(pTxD, sizeof(TXD_STRUC));
		pBeaconContext = &(pAd->BeaconContext[i]);;
		// Both TxD need to put in the right descriptor
    	RTUSBWriteBeaconDescriptor(pTxD, FrameLen, FrameLen + 4, pAd->PortCfg.MlmeRate, 4, pAd->PortCfg.TxPreambleInUsed);
		if (i == 0)
			pBeaconContext->BulkOutSize = 1;
		else
			pBeaconContext->BulkOutSize = BulkOutLength;			
    DBGPRINT(RT_DEBUG_TRACE, "  (pBeaconContext->BulkOutSize=%d)\n", pBeaconContext->BulkOutSize);
	}
	// The flags will always start from beacon 0
	RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_BEACON_0);
	// Kick bulk out 
	RTUSBKickBulkOut(pAd);
}
(-) rt2570-1.1.0-b1/Module/iwpriv_usage.txt (-146 / +70 lines)
 Lines 1-151    Link Here 
iwpriv
This file provides some basic examples on the configuration of the driver using standard linux wireless tools. Where possible iwconfig should be used to adjust settings. Some settings are currently not avaiable via iwconfig and these include WPA, for these functions it is currently necessary to use iwpriv. 
=================
This is detailed explanation of each parameters for iwpriv.
Before reading this document, make sure you already read README.
Configuration Examples
===================================================================
-------------------------------------------------------------------------------------------------------
Example I: Config STA to link with AP which is OPEN/NONE(Authentication/Encryption)
USAGE:
	1. iwconfig ra0 mode managed
	iwpriv rausb0 set [parameters]=[val]
	2. iwconfig ra0 key open
	3. iwconfig ra0 key off
where
	4. iwconfig ra0 essid "AP's SSID"
	
[parameters]          [val] range                          explaination
Example II: Config STA to link with AP which is SHARED/WEP(Authentication/Encryption)
-----------------   -----------------------              ---------------------------------------------
	1. iwconfig ra0 mode managed
auth			0~2					0:open
	2. iwconfig ra0 key restricted
								1:shared
	3. iwconfig ra0 Key [1] "s:AP's wep key"
								2:wpapsk
	4. iwconfig ra0 key [1]
								3:wpanone
	5. iwconfig ra0 essid "AP's SSID"
								
	
keyid			1~4					wep key id
Example III: Config STA to create/link as adhoc mode
	1. iwconfig ra0 mode ad-hoc
enc			1~3					1:none
	2. iwconfig ra0 key off
								2:wep
	4. iwconfig ra0 essid "AP's SSID"
								3:tkip
	
								
Example IV: Config STA to link with AP which is WPAPSK/TKIP(Authentication/Encryption)
wpapsk			8~63 chars				WPAPSK password
	1. iwconfig ra0 mode managed
	2. iwpriv ra0 set AuthMode=WPAPSK
adhocmode		0~2					0: Plain 11Mbps
	3. iwpriv ra0 set EncrypType=TKIP
								   mode in
	4. iwpriv ra0 set WPAPSK="AP's wpa-preshared key"
								   Ad-Hoc
	5. iwconfig ra0 essid "AP's SSID"
								   (IEEE
	
								   802.11g
Example V: Config STA to link with AP which is WPAPSK/AES(Authentication/Encryption)
								   standard)
	1. iwconfig ra0 mode managed
								1: Auto mode
	2. iwpriv ra0 set AuthMode=WPAPSK
								   in Ad-Hoc
	3. iwpriv ra0 set EncrypType=AES
								   (violates
	5. iwpriv ra0 set WPAPSK="AP's wpa-preshared key"
								   IEEE 802.11g
	6. iwconfig ra0 essid "AP's SSID"
								   standard)
	
								2: 54Mbps only.
Examples
iwpriv
===================================================================
=================
-------------------------------------------------------------------------------------------------------
This is detailed explanation of each parameters for iwpriv.
Example I: Config STA to link with AP which is OPEN/NONE(Authentication/Encryption)
Before reading this document, make sure you already read README.
	1. iwconfig rausb0 mode Managed
	2. iwconfig rausb0 enc none
USAGE:
	3. iwconfig rausb0 essid "AP's SSID"
	iwpriv ra0 set [parameters]=[val]
	
Example II: Config STA to link with AP which is OPEN/WEP(Authentication/Encryption)
where
	1. iwconfig rausb0 enc s:abcde
	2. iwconfig rausb0 essid "AP's SSID"
[parameters]          [val] range                          explaination
CountryRegion       {0~7}                                  Set country region 
	
                                                           0: use 1 ~ 11 Channel
Example III: Config STA to link with AP which is WPAPSK/TKIP(Authentication/Encryption)
                                                           1: use 1 ~ 11 Channel
	1. iwpriv rausb0 enc 3
                                                           2: use 1 ~ 13 Channel
	2. iwconfig rausb0 essid "AP's SSID"
                                                           3: use 10, 11 Channel
	3. iwpriv rausb0 wpapsk 12345678
                                                           4: use 10 ~ 13 Channel
	4. iwconfig rausb0 essid "AP's SSID"
                                                           5: use 14 Channel
	
                                                           6: use 1 ~ 14 Channel
p.s Step 2 is part of generating wpapsk password and is necessary.
                                                           7: use 3 ~ 9 Channel
                                                           
NOTE:
WirelessMode        {0~2}				   Set Wireless Mode 
                                                           0:11b/g mixed, 1:11B only
iwlist
=================
TxRate              {0~12}				   Set TxRate 
This is detailed explanation of each parameters for iwlist.
                                                           0:Auto, 1:1Mbps, 2:2Mbps, 3:5.5Mbps, 4:11Mbps, 
                                                          5:6Mbps, 6:9Mbps, 7:12Mbps, 8:18Mbps, 9:24Mbps, 
-------------------------------------------------------------------------------------------------------
                                                           10:36Mbps, 11:48Mbps, 12:54Mbps
                                                           
iwlist rausb0 scanning		; list the result after scanning(site survey)
BGProtection        {0~2}                                  Set 11B/11G Protection
                                                           0:Auto, 1:Always on, 2:Always off
TxPreamble          {0~2}                                  Set TxPreamble
                                                           0:Preamble Long, 1:Preamble Short, 2:Auto
TxBurst             {0,1}                                  Set TxBurst Enable or Disable
                                                           0:Disable, 1:Enable
TurboRate           {0,1}                                  Set TurboRate Enable or Disable
                                                           0:Disable, 1:Enable
AdhocOfdm           {0, 1}                                 Set Adhoc mode tx rate
							   0: adhere WIFI spec., 1: violate WIFI spec.
							   (802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode)
                                                                                                                                                        AuthMode            {OPEN,SHARED,WPAPSK}                   Set Authentication mode
EncrypType          {NONE,WEP,TKIP,AES}                    Set Encryption Type
WPAPSK              {8~63 ASCII or 64 HEX characters}       WPA Pre-Shared Key 
ApClient	    {0,1}				    Set ApClient mode
							    0:Disable, 1:Enable
							    
iwlist
=================
This is detailed explanation of each parameters for iwlist.
iwlist ra0 scanning		; list the result after scanning(site survey) 
							    
							    
Deprecated iwpriv
=================
*** PLEASE DO NOT USE THESE FUNCTIONS, THIS IS FOR HISTORICAL REFERENCE ONLY ***
As the configuration utility still uses some iwpriv commands they have not been
removed from the driver yet. These commands are likely to dissapear if the utility is
updated.
	
** ALL THESE COMMANDS HAVE A IWCONFIG REPLACEMENT, USE IT ****
SSID                {0~z, less than 32 characters}         Set SoftAP SSID
Channel             {1~14} depends on country region       Set Channel
RTSThreshold        {1~2347}                               Set RTS Threshold                                                           
                                                           
FragThreshold       {256~2346}                             Set Fragment Threshold
NetworkType	    {Infra,Adhoc}			   Set Network type
DefaultKeyID        {1~4}                                  Set Default Key ID
Key1                 {5 ascii characters or                 Set Key1 String
                     10 hex number or 
                     13 ascii characters or 
                     26 hex numbers}                                                                                                                        
Key2                 {5 ascii characters or                 Set Key2 String
                     10 hex number or 
                     13 ascii characters or 
                     26 hex numbers}                                                                                                                        
Key3                 {5 ascii characters or                 Set Key3 String
                     10 hex number or 
                     13 ascii characters or 
                     26 hex numbers}                                                                                                                        
Key4                 {5 ascii characters or                 Set Key4 String
                     10 hex number or 
                     13 ascii characters or 
                     26 hex numbers}                                                                                                                        
(-) rt2570-1.1.0-b1/Module/Makefile (-1 / +23 lines)
 Lines 73-78    Link Here 
 MODULE_ROOT := /lib/modules/$(shell uname -r)/extra
 MODULE_ROOT := /lib/modules/$(shell uname -r)/extra
endif
endif
ifdef KERNOUT
	KERNEL_OUTPUT := KBUILD_OUTPUT=$(KERNOUT)
else
	KERNEL_OUTPUT :=
endif
src ?= .
src ?= .
obj ?= .
obj ?= .
 Lines 89-95    Link Here 
	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $($(MODULE_NAME)-objs)
	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $($(MODULE_NAME)-objs)
endif
endif
KBUILD_PARAMS := -C $(KERNEL_SOURCES) SUBDIRS=$(PWD)
KBUILD_PARAMS := -C $(KERNEL_SOURCES) SUBDIRS=$(PWD) $(KERNEL_OUTPUT)
module:
module:
	@$(MAKE) $(KBUILD_PARAMS) modules; \
	@$(MAKE) $(KBUILD_PARAMS) modules; \
 Lines 98-103    Link Here 
	exit 1; \
	exit 1; \
	fi
	fi
arm:
	@$(MAKE) $(KBUILD_PARAMS) 'EXTRA_CFLAGS=-mstructure-size-boundary=8 -I$(src)' modules;
	if ! [ -f $(MODULE_OBJECT) ]; then \
	echo "$(MODULE_OBJECT) failed to build!"; \
	exit 1; \
	fi
armdebug:
	@$(MAKE) $(KBUILD_PARAMS) 'EXTRA_CFLAGS=-mstructure-size-boundary=8 -I$(src) -DRT2500_DBG' modules;
	if ! [ -f $(MODULE_OBJECT) ]; then \
	echo "$(MODULE_OBJECT) failed to build!"; \
	exit 1; \
	fi
debug:
debug:
	@$(MAKE) $(KBUILD_PARAMS) 'EXTRA_CFLAGS=-I$(src) -DRT2500_DBG' modules; \
	@$(MAKE) $(KBUILD_PARAMS) 'EXTRA_CFLAGS=-I$(src) -DRT2500_DBG' modules; \
	if ! [ -f $(MODULE_OBJECT) ]; then \
	if ! [ -f $(MODULE_OBJECT) ]; then \
 Lines 122-129    Link Here 
else
else
	echo "2.6 module install"
	echo "2.6 module install"
	make $(KBUILD_PARAMS) modules_install
	make $(KBUILD_PARAMS) modules_install
	/sbin/depmod -a
endif
endif
install: modules_install
install: modules_install
	@if ! grep -q 'rausb0' $(MODULE_CONF) ; then \
	@if ! grep -q 'rausb0' $(MODULE_CONF) ; then \
		echo "append 'alias rausb0 rt2570' to $(MODULE_CONF)"; \
		echo "append 'alias rausb0 rt2570' to $(MODULE_CONF)"; \
(-) rt2570-1.1.0-b1/Module/.#md5.c.1.2 (-1369 lines)
 Lines 1-1369    Link Here 
/*************************************************************************** 
 * RT2x00 SourceForge Project - http://rt2x00.sourceforge.net              * 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 *   This program is distributed in the hope that it will be useful,       * 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * 
 *   GNU General Public License for more details.                          * 
 *                                                                         * 
 *   You should have received a copy of the GNU General Public License     * 
 *   along with this program; if not, write to the                         * 
 *   Free Software Foundation, Inc.,                                       * 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * 
 *                                                                         * 
 *   Licensed under the GNU GPL                                            * 
 *   Original code supplied under license from RaLink Inc, 2004.           * 
 ***************************************************************************/
/*************************************************************************** 
 *	Module Name:	md5.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 *	Rita    	11-23-04	Modify MD5 and SHA-1
 ***************************************************************************/
#include "rt_config.h"
/**
 * md5_mac:
 * @key: pointer to	the	key	used for MAC generation
 * @key_len: length	of the key in bytes
 * @data: pointer to the data area for which the MAC is	generated
 * @data_len: length of	the	data in	bytes
 * @mac: pointer to	the	buffer holding space for the MAC; the buffer should
 * have	space for 128-bit (16 bytes) MD5 hash value
 *
 * md5_mac() determines	the	message	authentication code	by using secure	hash
 * MD5(key | data |	key).
 */
void md5_mac(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac)
{
	MD5_CTX	context;
	MD5Init(&context);
	MD5Update(&context,	key, key_len);
	MD5Update(&context,	data, data_len);
	MD5Update(&context,	key, key_len);
	MD5Final(mac, &context);
}
/**
 * hmac_md5:
 * @key: pointer to	the	key	used for MAC generation
 * @key_len: length	of the key in bytes
 * @data: pointer to the data area for which the MAC is	generated
 * @data_len: length of	the	data in	bytes
 * @mac: pointer to	the	buffer holding space for the MAC; the buffer should
 * have	space for 128-bit (16 bytes) MD5 hash value
 *
 * hmac_md5() determines the message authentication	code using HMAC-MD5.
 * This	implementation is based	on the sample code presented in	RFC	2104.
 */
void hmac_md5(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac)
{
	MD5_CTX	context;
	UCHAR k_ipad[65]; /* inner	padding	- key XORd with	ipad */
	UCHAR k_opad[65]; /* outer	padding	- key XORd with	opad */
	UCHAR tk[16];
	int	i;
	//assert(key != NULL && data != NULL && mac != NULL);
	/* if key is longer	than 64	bytes reset	it to key =	MD5(key) */
	if (key_len	> 64) {
		MD5_CTX	ttcontext;
		MD5Init(&ttcontext);
		MD5Update(&ttcontext, key, key_len);
		MD5Final(tk, &ttcontext);
		//key=(PUCHAR)ttcontext.buf;
		key	= tk;
		key_len	= 16;
	}
	/* the HMAC_MD5	transform looks	like:
	 *
	 * MD5(K XOR opad, MD5(K XOR ipad, text))
	 *
	 * where K is an n byte	key
	 * ipad	is the byte	0x36 repeated 64 times
	 * opad	is the byte	0x5c repeated 64 times
	 * and text	is the data	being protected	*/
	/* start out by	storing	key	in pads	*/
	NdisZeroMemory(k_ipad, sizeof(k_ipad));
	NdisZeroMemory(k_opad,	sizeof(k_opad));
	//assert(key_len < sizeof(k_ipad));
	NdisMoveMemory(k_ipad, key,	key_len);
	NdisMoveMemory(k_opad, key,	key_len);
	/* XOR key with	ipad and opad values */
	for	(i = 0;	i <	64;	i++) {
		k_ipad[i] ^= 0x36;
		k_opad[i] ^= 0x5c;
	}
	/* perform inner MD5 */
	MD5Init(&context);					 /*	init context for 1st pass */
	MD5Update(&context,	k_ipad,	64);	 /*	start with inner pad */
	MD5Update(&context,	data, data_len); /*	then text of datagram */
	MD5Final(mac, &context);			 /*	finish up 1st pass */
	/* perform outer MD5 */
	MD5Init(&context);					 /*	init context for 2nd pass */
	MD5Update(&context,	k_opad,	64);	 /*	start with outer pad */
	MD5Update(&context,	mac, 16);		 /*	then results of	1st	hash */
	MD5Final(mac, &context);			 /*	finish up 2nd pass */
}
//#ifndef WORDS_BIGENDIAN
#if	1
#define	byteReverse(buf, len)	/* Nothing */
#else
void byteReverse(unsigned char *buf, unsigned longs);
//#ifndef ASM_MD5
#if	1
/*
 * Note: this code is harmless on little-endian	machines.
 */
void byteReverse(unsigned char *buf, unsigned longs)
{
	u32	t;
		DBGPRINT(RT_DEBUG_TRACE, ("bbjanbb byte	reversee\n"));
	do {
		t =	(u32) ((unsigned) buf[3] <<	8 |	buf[2])	<< 16 |	((unsigned)	buf[1] << 8	| buf[0]);
		*(u32 *) buf = t;
		buf	+= 4;
	} while	(--longs);
}
#endif
#endif
/* ==========================  MD5 implementation =========================== */ 
// four base functions for MD5 
#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) 
#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) 
#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z))
#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z)))
#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s))))
#define	MD5Step(f, w, x, y,	z, data, t, s)	\
	( w	+= f(x,	y, z) +	data + t,  w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w +=	x )
/*
 *  Function Description:
 *      Initiate MD5 Context satisfied in RFC 1321
 *
 *  Arguments:
 *      pCtx        Pointer	to MD5 context
 *
 *  Return Value:
 *      None	    
 */
VOID MD5Init(MD5_CTX *pCtx)
{
    pCtx->Buf[0]=0x67452301;
    pCtx->Buf[1]=0xefcdab89;
    pCtx->Buf[2]=0x98badcfe;
    pCtx->Buf[3]=0x10325476;
    pCtx->LenInBitCount[0]=0;
    pCtx->LenInBitCount[1]=0;
}
/*
 *  Function Description:
 *      Update MD5 Context, allow of an arrary of octets as the next portion 
 *      of the message
 *      
 *  Arguments:
 *      pCtx		Pointer	to MD5 context
 * 	    pData       Pointer to input data
 *      LenInBytes  The length of input data (unit: byte)
 *
 *  Return Value:
 *      None
 *
 *  Note:
 *      Called after MD5Init or MD5Update(itself)   
 */
VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, ULONG LenInBytes)
{
    
    ULONG TfTimes;
    ULONG temp;
	unsigned int i;
    
    temp = pCtx->LenInBitCount[0];
    pCtx->LenInBitCount[0] = (ULONG) (pCtx->LenInBitCount[0] + (LenInBytes << 3));
 
    if (pCtx->LenInBitCount[0] < temp)
        pCtx->LenInBitCount[1]++;   //carry in
    pCtx->LenInBitCount[1] += LenInBytes >> 29;
    // mod 64 bytes
    temp = (temp >> 3) & 0x3f;  
    
    // process lacks of 64-byte data 
    if (temp) 
    {
        UCHAR *pAds = (UCHAR *) pCtx->Input + temp;
        
        if ((temp+LenInBytes) < 64)
        {
            NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes);   
            return;
        }
        
        NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp);               
        byteReverse(pCtx->Input, 16);
        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
        pData += 64-temp;
        LenInBytes -= 64-temp; 
    } // end of if (temp)
    
     
    TfTimes = (LenInBytes >> 6);
    for (i=TfTimes; i>0; i--)
    {
        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64);
        byteReverse(pCtx->Input, 16);
        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
        pData += 64;
        LenInBytes -= 64;
    } // end of for
    // buffering lacks of 64-byte data
    if(LenInBytes)
        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes);   
   
}
/*
 *  Function Description:
 *      Append padding bits and length of original message in the tail 
 *      The message digest has to be completed in the end  
 *  
 *  Arguments:
 *      Digest		Output of Digest-Message for MD5
 *  	pCtx        Pointer	to MD5 context
 * 	
 *  Return Value:
 *      None
 *  
 *  Note:
 *      Called after MD5Update  
 */
VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx)
{
    UCHAR Remainder;
    UCHAR PadLenInBytes;
    UCHAR *pAppend=0;
    unsigned int i;
    
    Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f);
    PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder);
    
    pAppend = (UCHAR *)pCtx->Input + Remainder;
    // padding bits without crossing block(64-byte based) boundary
    if (Remainder < 56)
    {
        *pAppend = 0x80;
        PadLenInBytes --;
        
        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); 
		
		// add data-length field, from low to high
       	for (i=0; i<4; i++)
        {
        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff);
        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff);
      	}
      	
        byteReverse(pCtx->Input, 16);
        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
    } // end of if
    
    // padding bits with crossing block(64-byte based) boundary
    else
    {
        // the first block ===
        *pAppend = 0x80;
        PadLenInBytes --;
       
        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); 
        PadLenInBytes -= (64 - Remainder - 1);
        
        byteReverse(pCtx->Input, 16);
        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
        
        // the second block ===
        NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); 
        // add data-length field
        for (i=0; i<4; i++)
        {
        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff);
        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff);
      	}
        byteReverse(pCtx->Input, 16);
        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
    } // end of else
    NdisMoveMemory((UCHAR *)Digest, (ULONG *)pCtx->Buf, 16); // output
    byteReverse((UCHAR *)Digest, 4);
    NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free 
}
/*
 *  Function Description:
 *      The central algorithm of MD5, consists of four rounds and sixteen 
 *  	steps per round
 * 
 *  Arguments:
 *      Buf     Buffers of four states (output: 16 bytes)		
 * 	    Mes     Input data (input: 64 bytes) 
 *  
 *  Return Value:
 *      None
 *  	
 *  Note:
 *      Called by MD5Update or MD5Final
 */
VOID MD5Transform(ULONG Buf[4], ULONG Mes[16])
{  
    ULONG Reg[4], Temp; 
	unsigned int i;
    
    static UCHAR LShiftVal[16] = 
    { 	
        7, 12, 17, 22, 	
		5, 9 , 14, 20, 
		4, 11, 16, 23, 
 		6, 10, 15, 21, 
 	};
	
	// [equal to 4294967296*abs(sin(index))]
    static ULONG MD5Table[64] = 
	{ 
		0xd76aa478,	0xe8c7b756,	0x242070db,	0xc1bdceee,	
		0xf57c0faf,	0x4787c62a,	0xa8304613, 0xfd469501,	
		0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
    	0x6b901122,	0xfd987193,	0xa679438e,	0x49b40821,
    	
    	0xf61e2562,	0xc040b340,	0x265e5a51,	0xe9b6c7aa,
    	0xd62f105d,	0x02441453,	0xd8a1e681,	0xe7d3fbc8,
    	0x21e1cde6,	0xc33707d6,	0xf4d50d87,	0x455a14ed,
    	0xa9e3e905,	0xfcefa3f8,	0x676f02d9,	0x8d2a4c8a,
    	           
    	0xfffa3942,	0x8771f681,	0x6d9d6122,	0xfde5380c,
    	0xa4beea44,	0x4bdecfa9,	0xf6bb4b60,	0xbebfbc70,
    	0x289b7ec6,	0xeaa127fa,	0xd4ef3085,	0x04881d05,
    	0xd9d4d039,	0xe6db99e5,	0x1fa27cf8,	0xc4ac5665,
    	           
    	0xf4292244,	0x432aff97,	0xab9423a7,	0xfc93a039,
   		0x655b59c3,	0x8f0ccc92,	0xffeff47d,	0x85845dd1,
    	0x6fa87e4f,	0xfe2ce6e0,	0xa3014314,	0x4e0811a1,
    	0xf7537e82,	0xbd3af235,	0x2ad7d2bb,	0xeb86d391
	};
 
				
    for (i=0; i<4; i++)
        Reg[i]=Buf[i];
			
				
    // 64 steps in MD5 algorithm
    for (i=0; i<16; i++)                    
    {
        MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i],               
                MD5Table[i], LShiftVal[i & 0x3]);
        // one-word right shift
        Temp   = Reg[3]; 
        Reg[3] = Reg[2];
        Reg[2] = Reg[1];
        Reg[1] = Reg[0];
        Reg[0] = Temp;            
    }
    for (i=16; i<32; i++)                    
    {
        MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], 
                MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]);    
        // one-word right shift
        Temp   = Reg[3]; 
        Reg[3] = Reg[2];
        Reg[2] = Reg[1];
        Reg[1] = Reg[0];
        Reg[0] = Temp;           
    }
    for (i=32; i<48; i++)                    
    {
        MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], 
                MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]);        
        // one-word right shift
        Temp   = Reg[3]; 
        Reg[3] = Reg[2];
        Reg[2] = Reg[1];
        Reg[1] = Reg[0];
        Reg[0] = Temp;          
    }
    for (i=48; i<64; i++)                    
    {
        MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], 
                MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]);   
        // one-word right shift
        Temp   = Reg[3]; 
        Reg[3] = Reg[2];
        Reg[2] = Reg[1];
        Reg[1] = Reg[0];
        Reg[0] = Temp;           
    }
    
      
    // (temporary)output
    for (i=0; i<4; i++)
        Buf[i] += Reg[i];
}
/* =========================  SHA-1 implementation ========================== */
// four base functions for SHA-1
#define SHA1_F1(b, c, d)    (((b) & (c)) | ((~b) & (d)))         
#define SHA1_F2(b, c, d)    ((b) ^ (c) ^ (d)) 
#define SHA1_F3(b, c, d)    (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
#define SHA1Step(f, a, b, c, d, e, w, k)    \
    ( e	+= ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \
      b = CYCLIC_LEFT_SHIFT(b, 30) )
//Initiate SHA-1 Context satisfied in RFC 3174  
VOID SHAInit(SHA_CTX *pCtx)
{
    pCtx->Buf[0]=0x67452301;
    pCtx->Buf[1]=0xefcdab89;
    pCtx->Buf[2]=0x98badcfe;
    pCtx->Buf[3]=0x10325476;
    pCtx->Buf[4]=0xc3d2e1f0;
    
    pCtx->LenInBitCount[0]=0;
    pCtx->LenInBitCount[1]=0;
}
/*
 *  Function Description:
 *      Update SHA-1 Context, allow of an arrary of octets as the next
 *      portion of the message
 *      
 *  Arguments:
 *      pCtx		Pointer	to SHA-1 context
 * 	    pData       Pointer to input data
 *      LenInBytes  The length of input data (unit: byte)
 *
 *  Return Value:
 *      error       indicate more than pow(2,64) bits of data  
 *
 *  Note:
 *      Called after SHAInit or SHAUpdate(itself)   
 */
UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, ULONG LenInBytes)
{
    ULONG TfTimes;
    ULONG temp1,temp2;
	unsigned int i;
	UCHAR err=1;
    
    temp1 = pCtx->LenInBitCount[0];
    temp2 = pCtx->LenInBitCount[1];
    pCtx->LenInBitCount[0] = (ULONG) (pCtx->LenInBitCount[0] + (LenInBytes << 3));
    if (pCtx->LenInBitCount[0] < temp1)
        pCtx->LenInBitCount[1]++;   //carry in
    pCtx->LenInBitCount[1] = (ULONG) (pCtx->LenInBitCount[1] +(LenInBytes >> 29));
    if (pCtx->LenInBitCount[1] < temp2)
        return (err);   //check total length of original data
 
    // mod 64 bytes
    temp1 = (temp1 >> 3) & 0x3f;  
    
    // process lacks of 64-byte data 
    if (temp1) 
    {
        UCHAR *pAds = (UCHAR *) pCtx->Input + temp1;
        
        if ((temp1+LenInBytes) < 64)
        {
            NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes);   
            return (0);
        }
        
        NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1);              
        
        NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16);
        SHATransform(pCtx->Buf, (ULONG *)pCtx->Input);
        pData += 64-temp1;
        LenInBytes -= 64-temp1; 
    } // end of if (temp1)
    
     
    TfTimes = (LenInBytes >> 6);
    for (i=TfTimes; i>0; i--)
    {
        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64);
        
        NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16);
        SHATransform(pCtx->Buf, (ULONG *)pCtx->Input);
        pData += 64;
        LenInBytes -= 64;
    } // end of for
    // buffering lacks of 64-byte data
    if(LenInBytes)
        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes);
	return (0);
}
// Append padding bits and length of original message in the tail 
// The message digest has to be completed in the end 
VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20])
{
    UCHAR Remainder;
    UCHAR PadLenInBytes;
    UCHAR *pAppend=0;
    unsigned int i;
    Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f);
    pAppend = (UCHAR *)pCtx->Input + Remainder;
    PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder);
    
    // padding bits without crossing block(64-byte based) boundary
    if (Remainder < 56)
    {       
        *pAppend = 0x80;
        PadLenInBytes --;
        
        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); 
		 
		// add data-length field, from high to low
        for (i=0; i<4; i++)
        {
        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff);
        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff);
      	}
      	
        NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14);
        SHATransform(pCtx->Buf, (ULONG *)pCtx->Input);
    } // end of if
    
    // padding bits with crossing block(64-byte based) boundary
    else
    {
        // the first block ===
        *pAppend = 0x80;
        PadLenInBytes --;
        
        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); 
        PadLenInBytes -= (64 - Remainder - 1);
        
        NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16);
        SHATransform(pCtx->Buf, (ULONG *)pCtx->Input);
        // the second block ===
        NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); 
			
		// add data-length field
		for (i=0; i<4; i++)
        {
        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff);
        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff);
      	}
      	
        NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); 
        SHATransform(pCtx->Buf, (ULONG *)pCtx->Input);
    } // end of else
	
		
    //Output, bytereverse
    for (i=0; i<20; i++)
    {
        Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3)));
    }
    
    NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free 
}
// The central algorithm of SHA-1, consists of four rounds and 
// twenty steps per round
VOID SHATransform(ULONG Buf[5], ULONG Mes[20])
{
    ULONG Reg[5],Temp; 
	unsigned int i;
    ULONG W[80]; 
   
    static ULONG SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, 
                                  0x8f1bbcdc, 0xca62c1d6 };
 
    Reg[0]=Buf[0];
	Reg[1]=Buf[1];
	Reg[2]=Buf[2];
	Reg[3]=Buf[3];
	Reg[4]=Buf[4];
    //the first octet of a word is stored in the 0th element, bytereverse
	for(i = 0; i < 16; i++)
    { 
    	W[i]  = (Mes[i] >> 24) & 0xff;
        W[i] |= (Mes[i] >> 8 ) & 0xff00;
        W[i] |= (Mes[i] << 8 ) & 0xff0000;
        W[i] |= (Mes[i] << 24) & 0xff000000;
    }
    
		 
    for	(i = 0; i < 64; i++)
	    W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1);
	    
    
    // 80 steps in SHA-1 algorithm
    for (i=0; i<80; i++)                    
    {
        if (i<20)
            SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], 
                     W[i], SHA1Table[0]);
        
        else if (i>=20 && i<40)
            SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], 
                     W[i], SHA1Table[1]);
			
		else if (i>=40 && i<60)
            SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], 
                      W[i], SHA1Table[2]);
			
        else
            SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], 
                     W[i], SHA1Table[3]);
			
       // one-word right shift
		Temp   = Reg[4];
        Reg[4] = Reg[3];
        Reg[3] = Reg[2];
        Reg[2] = Reg[1];
        Reg[1] = Reg[0];
        Reg[0] = Temp;       
  
    } // end of for-loop
    // (temporary)output
    for (i=0; i<5; i++)
        Buf[i] += Reg[i];
    
}
/* =========================  AES En/Decryption ========================== */
/* forward S-box */
static uint32 FSb[256] =
{
	0x63, 0x7C,	0x77, 0x7B,	0xF2, 0x6B,	0x6F, 0xC5,
	0x30, 0x01,	0x67, 0x2B,	0xFE, 0xD7,	0xAB, 0x76,
	0xCA, 0x82,	0xC9, 0x7D,	0xFA, 0x59,	0x47, 0xF0,
	0xAD, 0xD4,	0xA2, 0xAF,	0x9C, 0xA4,	0x72, 0xC0,
	0xB7, 0xFD,	0x93, 0x26,	0x36, 0x3F,	0xF7, 0xCC,
	0x34, 0xA5,	0xE5, 0xF1,	0x71, 0xD8,	0x31, 0x15,
	0x04, 0xC7,	0x23, 0xC3,	0x18, 0x96,	0x05, 0x9A,
	0x07, 0x12,	0x80, 0xE2,	0xEB, 0x27,	0xB2, 0x75,
	0x09, 0x83,	0x2C, 0x1A,	0x1B, 0x6E,	0x5A, 0xA0,
	0x52, 0x3B,	0xD6, 0xB3,	0x29, 0xE3,	0x2F, 0x84,
	0x53, 0xD1,	0x00, 0xED,	0x20, 0xFC,	0xB1, 0x5B,
	0x6A, 0xCB,	0xBE, 0x39,	0x4A, 0x4C,	0x58, 0xCF,
	0xD0, 0xEF,	0xAA, 0xFB,	0x43, 0x4D,	0x33, 0x85,
	0x45, 0xF9,	0x02, 0x7F,	0x50, 0x3C,	0x9F, 0xA8,
	0x51, 0xA3,	0x40, 0x8F,	0x92, 0x9D,	0x38, 0xF5,
	0xBC, 0xB6,	0xDA, 0x21,	0x10, 0xFF,	0xF3, 0xD2,
	0xCD, 0x0C,	0x13, 0xEC,	0x5F, 0x97,	0x44, 0x17,
	0xC4, 0xA7,	0x7E, 0x3D,	0x64, 0x5D,	0x19, 0x73,
	0x60, 0x81,	0x4F, 0xDC,	0x22, 0x2A,	0x90, 0x88,
	0x46, 0xEE,	0xB8, 0x14,	0xDE, 0x5E,	0x0B, 0xDB,
	0xE0, 0x32,	0x3A, 0x0A,	0x49, 0x06,	0x24, 0x5C,
	0xC2, 0xD3,	0xAC, 0x62,	0x91, 0x95,	0xE4, 0x79,
	0xE7, 0xC8,	0x37, 0x6D,	0x8D, 0xD5,	0x4E, 0xA9,
	0x6C, 0x56,	0xF4, 0xEA,	0x65, 0x7A,	0xAE, 0x08,
	0xBA, 0x78,	0x25, 0x2E,	0x1C, 0xA6,	0xB4, 0xC6,
	0xE8, 0xDD,	0x74, 0x1F,	0x4B, 0xBD,	0x8B, 0x8A,
	0x70, 0x3E,	0xB5, 0x66,	0x48, 0x03,	0xF6, 0x0E,
	0x61, 0x35,	0x57, 0xB9,	0x86, 0xC1,	0x1D, 0x9E,
	0xE1, 0xF8,	0x98, 0x11,	0x69, 0xD9,	0x8E, 0x94,
	0x9B, 0x1E,	0x87, 0xE9,	0xCE, 0x55,	0x28, 0xDF,
	0x8C, 0xA1,	0x89, 0x0D,	0xBF, 0xE6,	0x42, 0x68,
	0x41, 0x99,	0x2D, 0x0F,	0xB0, 0x54,	0xBB, 0x16
};
/* forward table */
#define	FT \
\
	V(C6,63,63,A5),	V(F8,7C,7C,84),	V(EE,77,77,99),	V(F6,7B,7B,8D),	\
	V(FF,F2,F2,0D),	V(D6,6B,6B,BD),	V(DE,6F,6F,B1),	V(91,C5,C5,54),	\
	V(60,30,30,50),	V(02,01,01,03),	V(CE,67,67,A9),	V(56,2B,2B,7D),	\
	V(E7,FE,FE,19),	V(B5,D7,D7,62),	V(4D,AB,AB,E6),	V(EC,76,76,9A),	\
	V(8F,CA,CA,45),	V(1F,82,82,9D),	V(89,C9,C9,40),	V(FA,7D,7D,87),	\
	V(EF,FA,FA,15),	V(B2,59,59,EB),	V(8E,47,47,C9),	V(FB,F0,F0,0B),	\
	V(41,AD,AD,EC),	V(B3,D4,D4,67),	V(5F,A2,A2,FD),	V(45,AF,AF,EA),	\
	V(23,9C,9C,BF),	V(53,A4,A4,F7),	V(E4,72,72,96),	V(9B,C0,C0,5B),	\
	V(75,B7,B7,C2),	V(E1,FD,FD,1C),	V(3D,93,93,AE),	V(4C,26,26,6A),	\
	V(6C,36,36,5A),	V(7E,3F,3F,41),	V(F5,F7,F7,02),	V(83,CC,CC,4F),	\
	V(68,34,34,5C),	V(51,A5,A5,F4),	V(D1,E5,E5,34),	V(F9,F1,F1,08),	\
	V(E2,71,71,93),	V(AB,D8,D8,73),	V(62,31,31,53),	V(2A,15,15,3F),	\
	V(08,04,04,0C),	V(95,C7,C7,52),	V(46,23,23,65),	V(9D,C3,C3,5E),	\
	V(30,18,18,28),	V(37,96,96,A1),	V(0A,05,05,0F),	V(2F,9A,9A,B5),	\
	V(0E,07,07,09),	V(24,12,12,36),	V(1B,80,80,9B),	V(DF,E2,E2,3D),	\
	V(CD,EB,EB,26),	V(4E,27,27,69),	V(7F,B2,B2,CD),	V(EA,75,75,9F),	\
	V(12,09,09,1B),	V(1D,83,83,9E),	V(58,2C,2C,74),	V(34,1A,1A,2E),	\
	V(36,1B,1B,2D),	V(DC,6E,6E,B2),	V(B4,5A,5A,EE),	V(5B,A0,A0,FB),	\
	V(A4,52,52,F6),	V(76,3B,3B,4D),	V(B7,D6,D6,61),	V(7D,B3,B3,CE),	\
	V(52,29,29,7B),	V(DD,E3,E3,3E),	V(5E,2F,2F,71),	V(13,84,84,97),	\
	V(A6,53,53,F5),	V(B9,D1,D1,68),	V(00,00,00,00),	V(C1,ED,ED,2C),	\
	V(40,20,20,60),	V(E3,FC,FC,1F),	V(79,B1,B1,C8),	V(B6,5B,5B,ED),	\
	V(D4,6A,6A,BE),	V(8D,CB,CB,46),	V(67,BE,BE,D9),	V(72,39,39,4B),	\
	V(94,4A,4A,DE),	V(98,4C,4C,D4),	V(B0,58,58,E8),	V(85,CF,CF,4A),	\
	V(BB,D0,D0,6B),	V(C5,EF,EF,2A),	V(4F,AA,AA,E5),	V(ED,FB,FB,16),	\
	V(86,43,43,C5),	V(9A,4D,4D,D7),	V(66,33,33,55),	V(11,85,85,94),	\
	V(8A,45,45,CF),	V(E9,F9,F9,10),	V(04,02,02,06),	V(FE,7F,7F,81),	\
	V(A0,50,50,F0),	V(78,3C,3C,44),	V(25,9F,9F,BA),	V(4B,A8,A8,E3),	\
	V(A2,51,51,F3),	V(5D,A3,A3,FE),	V(80,40,40,C0),	V(05,8F,8F,8A),	\
	V(3F,92,92,AD),	V(21,9D,9D,BC),	V(70,38,38,48),	V(F1,F5,F5,04),	\
	V(63,BC,BC,DF),	V(77,B6,B6,C1),	V(AF,DA,DA,75),	V(42,21,21,63),	\
	V(20,10,10,30),	V(E5,FF,FF,1A),	V(FD,F3,F3,0E),	V(BF,D2,D2,6D),	\
	V(81,CD,CD,4C),	V(18,0C,0C,14),	V(26,13,13,35),	V(C3,EC,EC,2F),	\
	V(BE,5F,5F,E1),	V(35,97,97,A2),	V(88,44,44,CC),	V(2E,17,17,39),	\
	V(93,C4,C4,57),	V(55,A7,A7,F2),	V(FC,7E,7E,82),	V(7A,3D,3D,47),	\
	V(C8,64,64,AC),	V(BA,5D,5D,E7),	V(32,19,19,2B),	V(E6,73,73,95),	\
	V(C0,60,60,A0),	V(19,81,81,98),	V(9E,4F,4F,D1),	V(A3,DC,DC,7F),	\
	V(44,22,22,66),	V(54,2A,2A,7E),	V(3B,90,90,AB),	V(0B,88,88,83),	\
	V(8C,46,46,CA),	V(C7,EE,EE,29),	V(6B,B8,B8,D3),	V(28,14,14,3C),	\
	V(A7,DE,DE,79),	V(BC,5E,5E,E2),	V(16,0B,0B,1D),	V(AD,DB,DB,76),	\
	V(DB,E0,E0,3B),	V(64,32,32,56),	V(74,3A,3A,4E),	V(14,0A,0A,1E),	\
	V(92,49,49,DB),	V(0C,06,06,0A),	V(48,24,24,6C),	V(B8,5C,5C,E4),	\
	V(9F,C2,C2,5D),	V(BD,D3,D3,6E),	V(43,AC,AC,EF),	V(C4,62,62,A6),	\
	V(39,91,91,A8),	V(31,95,95,A4),	V(D3,E4,E4,37),	V(F2,79,79,8B),	\
	V(D5,E7,E7,32),	V(8B,C8,C8,43),	V(6E,37,37,59),	V(DA,6D,6D,B7),	\
	V(01,8D,8D,8C),	V(B1,D5,D5,64),	V(9C,4E,4E,D2),	V(49,A9,A9,E0),	\
	V(D8,6C,6C,B4),	V(AC,56,56,FA),	V(F3,F4,F4,07),	V(CF,EA,EA,25),	\
	V(CA,65,65,AF),	V(F4,7A,7A,8E),	V(47,AE,AE,E9),	V(10,08,08,18),	\
	V(6F,BA,BA,D5),	V(F0,78,78,88),	V(4A,25,25,6F),	V(5C,2E,2E,72),	\
	V(38,1C,1C,24),	V(57,A6,A6,F1),	V(73,B4,B4,C7),	V(97,C6,C6,51),	\
	V(CB,E8,E8,23),	V(A1,DD,DD,7C),	V(E8,74,74,9C),	V(3E,1F,1F,21),	\
	V(96,4B,4B,DD),	V(61,BD,BD,DC),	V(0D,8B,8B,86),	V(0F,8A,8A,85),	\
	V(E0,70,70,90),	V(7C,3E,3E,42),	V(71,B5,B5,C4),	V(CC,66,66,AA),	\
	V(90,48,48,D8),	V(06,03,03,05),	V(F7,F6,F6,01),	V(1C,0E,0E,12),	\
	V(C2,61,61,A3),	V(6A,35,35,5F),	V(AE,57,57,F9),	V(69,B9,B9,D0),	\
	V(17,86,86,91),	V(99,C1,C1,58),	V(3A,1D,1D,27),	V(27,9E,9E,B9),	\
	V(D9,E1,E1,38),	V(EB,F8,F8,13),	V(2B,98,98,B3),	V(22,11,11,33),	\
	V(D2,69,69,BB),	V(A9,D9,D9,70),	V(07,8E,8E,89),	V(33,94,94,A7),	\
	V(2D,9B,9B,B6),	V(3C,1E,1E,22),	V(15,87,87,92),	V(C9,E9,E9,20),	\
	V(87,CE,CE,49),	V(AA,55,55,FF),	V(50,28,28,78),	V(A5,DF,DF,7A),	\
	V(03,8C,8C,8F),	V(59,A1,A1,F8),	V(09,89,89,80),	V(1A,0D,0D,17),	\
	V(65,BF,BF,DA),	V(D7,E6,E6,31),	V(84,42,42,C6),	V(D0,68,68,B8),	\
	V(82,41,41,C3),	V(29,99,99,B0),	V(5A,2D,2D,77),	V(1E,0F,0F,11),	\
	V(7B,B0,B0,CB),	V(A8,54,54,FC),	V(6D,BB,BB,D6),	V(2C,16,16,3A)
#define	V(a,b,c,d) 0x##a##b##c##d
static uint32 FT0[256] = { FT };
#undef V
#define	V(a,b,c,d) 0x##d##a##b##c
static uint32 FT1[256] = { FT };
#undef V
#define	V(a,b,c,d) 0x##c##d##a##b
static uint32 FT2[256] = { FT };
#undef V
#define	V(a,b,c,d) 0x##b##c##d##a
static uint32 FT3[256] = { FT };
#undef V
#undef FT
/* reverse S-box */
static uint32 RSb[256] =
{
	0x52, 0x09,	0x6A, 0xD5,	0x30, 0x36,	0xA5, 0x38,
	0xBF, 0x40,	0xA3, 0x9E,	0x81, 0xF3,	0xD7, 0xFB,
	0x7C, 0xE3,	0x39, 0x82,	0x9B, 0x2F,	0xFF, 0x87,
	0x34, 0x8E,	0x43, 0x44,	0xC4, 0xDE,	0xE9, 0xCB,
	0x54, 0x7B,	0x94, 0x32,	0xA6, 0xC2,	0x23, 0x3D,
	0xEE, 0x4C,	0x95, 0x0B,	0x42, 0xFA,	0xC3, 0x4E,
	0x08, 0x2E,	0xA1, 0x66,	0x28, 0xD9,	0x24, 0xB2,
	0x76, 0x5B,	0xA2, 0x49,	0x6D, 0x8B,	0xD1, 0x25,
	0x72, 0xF8,	0xF6, 0x64,	0x86, 0x68,	0x98, 0x16,
	0xD4, 0xA4,	0x5C, 0xCC,	0x5D, 0x65,	0xB6, 0x92,
	0x6C, 0x70,	0x48, 0x50,	0xFD, 0xED,	0xB9, 0xDA,
	0x5E, 0x15,	0x46, 0x57,	0xA7, 0x8D,	0x9D, 0x84,
	0x90, 0xD8,	0xAB, 0x00,	0x8C, 0xBC,	0xD3, 0x0A,
	0xF7, 0xE4,	0x58, 0x05,	0xB8, 0xB3,	0x45, 0x06,
	0xD0, 0x2C,	0x1E, 0x8F,	0xCA, 0x3F,	0x0F, 0x02,
	0xC1, 0xAF,	0xBD, 0x03,	0x01, 0x13,	0x8A, 0x6B,
	0x3A, 0x91,	0x11, 0x41,	0x4F, 0x67,	0xDC, 0xEA,
	0x97, 0xF2,	0xCF, 0xCE,	0xF0, 0xB4,	0xE6, 0x73,
	0x96, 0xAC,	0x74, 0x22,	0xE7, 0xAD,	0x35, 0x85,
	0xE2, 0xF9,	0x37, 0xE8,	0x1C, 0x75,	0xDF, 0x6E,
	0x47, 0xF1,	0x1A, 0x71,	0x1D, 0x29,	0xC5, 0x89,
	0x6F, 0xB7,	0x62, 0x0E,	0xAA, 0x18,	0xBE, 0x1B,
	0xFC, 0x56,	0x3E, 0x4B,	0xC6, 0xD2,	0x79, 0x20,
	0x9A, 0xDB,	0xC0, 0xFE,	0x78, 0xCD,	0x5A, 0xF4,
	0x1F, 0xDD,	0xA8, 0x33,	0x88, 0x07,	0xC7, 0x31,
	0xB1, 0x12,	0x10, 0x59,	0x27, 0x80,	0xEC, 0x5F,
	0x60, 0x51,	0x7F, 0xA9,	0x19, 0xB5,	0x4A, 0x0D,
	0x2D, 0xE5,	0x7A, 0x9F,	0x93, 0xC9,	0x9C, 0xEF,
	0xA0, 0xE0,	0x3B, 0x4D,	0xAE, 0x2A,	0xF5, 0xB0,
	0xC8, 0xEB,	0xBB, 0x3C,	0x83, 0x53,	0x99, 0x61,
	0x17, 0x2B,	0x04, 0x7E,	0xBA, 0x77,	0xD6, 0x26,
	0xE1, 0x69,	0x14, 0x63,	0x55, 0x21,	0x0C, 0x7D
};
/* reverse table */
#define	RT \
\
	V(51,F4,A7,50),	V(7E,41,65,53),	V(1A,17,A4,C3),	V(3A,27,5E,96),	\
	V(3B,AB,6B,CB),	V(1F,9D,45,F1),	V(AC,FA,58,AB),	V(4B,E3,03,93),	\
	V(20,30,FA,55),	V(AD,76,6D,F6),	V(88,CC,76,91),	V(F5,02,4C,25),	\
	V(4F,E5,D7,FC),	V(C5,2A,CB,D7),	V(26,35,44,80),	V(B5,62,A3,8F),	\
	V(DE,B1,5A,49),	V(25,BA,1B,67),	V(45,EA,0E,98),	V(5D,FE,C0,E1),	\
	V(C3,2F,75,02),	V(81,4C,F0,12),	V(8D,46,97,A3),	V(6B,D3,F9,C6),	\
	V(03,8F,5F,E7),	V(15,92,9C,95),	V(BF,6D,7A,EB),	V(95,52,59,DA),	\
	V(D4,BE,83,2D),	V(58,74,21,D3),	V(49,E0,69,29),	V(8E,C9,C8,44),	\
	V(75,C2,89,6A),	V(F4,8E,79,78),	V(99,58,3E,6B),	V(27,B9,71,DD),	\
	V(BE,E1,4F,B6),	V(F0,88,AD,17),	V(C9,20,AC,66),	V(7D,CE,3A,B4),	\
	V(63,DF,4A,18),	V(E5,1A,31,82),	V(97,51,33,60),	V(62,53,7F,45),	\
	V(B1,64,77,E0),	V(BB,6B,AE,84),	V(FE,81,A0,1C),	V(F9,08,2B,94),	\
	V(70,48,68,58),	V(8F,45,FD,19),	V(94,DE,6C,87),	V(52,7B,F8,B7),	\
	V(AB,73,D3,23),	V(72,4B,02,E2),	V(E3,1F,8F,57),	V(66,55,AB,2A),	\
	V(B2,EB,28,07),	V(2F,B5,C2,03),	V(86,C5,7B,9A),	V(D3,37,08,A5),	\
	V(30,28,87,F2),	V(23,BF,A5,B2),	V(02,03,6A,BA),	V(ED,16,82,5C),	\
	V(8A,CF,1C,2B),	V(A7,79,B4,92),	V(F3,07,F2,F0),	V(4E,69,E2,A1),	\
	V(65,DA,F4,CD),	V(06,05,BE,D5),	V(D1,34,62,1F),	V(C4,A6,FE,8A),	\
	V(34,2E,53,9D),	V(A2,F3,55,A0),	V(05,8A,E1,32),	V(A4,F6,EB,75),	\
	V(0B,83,EC,39),	V(40,60,EF,AA),	V(5E,71,9F,06),	V(BD,6E,10,51),	\
	V(3E,21,8A,F9),	V(96,DD,06,3D),	V(DD,3E,05,AE),	V(4D,E6,BD,46),	\
	V(91,54,8D,B5),	V(71,C4,5D,05),	V(04,06,D4,6F),	V(60,50,15,FF),	\
	V(19,98,FB,24),	V(D6,BD,E9,97),	V(89,40,43,CC),	V(67,D9,9E,77),	\
	V(B0,E8,42,BD),	V(07,89,8B,88),	V(E7,19,5B,38),	V(79,C8,EE,DB),	\
	V(A1,7C,0A,47),	V(7C,42,0F,E9),	V(F8,84,1E,C9),	V(00,00,00,00),	\
	V(09,80,86,83),	V(32,2B,ED,48),	V(1E,11,70,AC),	V(6C,5A,72,4E),	\
	V(FD,0E,FF,FB),	V(0F,85,38,56),	V(3D,AE,D5,1E),	V(36,2D,39,27),	\
	V(0A,0F,D9,64),	V(68,5C,A6,21),	V(9B,5B,54,D1),	V(24,36,2E,3A),	\
	V(0C,0A,67,B1),	V(93,57,E7,0F),	V(B4,EE,96,D2),	V(1B,9B,91,9E),	\
	V(80,C0,C5,4F),	V(61,DC,20,A2),	V(5A,77,4B,69),	V(1C,12,1A,16),	\
	V(E2,93,BA,0A),	V(C0,A0,2A,E5),	V(3C,22,E0,43),	V(12,1B,17,1D),	\
	V(0E,09,0D,0B),	V(F2,8B,C7,AD),	V(2D,B6,A8,B9),	V(14,1E,A9,C8),	\
	V(57,F1,19,85),	V(AF,75,07,4C),	V(EE,99,DD,BB),	V(A3,7F,60,FD),	\
	V(F7,01,26,9F),	V(5C,72,F5,BC),	V(44,66,3B,C5),	V(5B,FB,7E,34),	\
	V(8B,43,29,76),	V(CB,23,C6,DC),	V(B6,ED,FC,68),	V(B8,E4,F1,63),	\
	V(D7,31,DC,CA),	V(42,63,85,10),	V(13,97,22,40),	V(84,C6,11,20),	\
	V(85,4A,24,7D),	V(D2,BB,3D,F8),	V(AE,F9,32,11),	V(C7,29,A1,6D),	\
	V(1D,9E,2F,4B),	V(DC,B2,30,F3),	V(0D,86,52,EC),	V(77,C1,E3,D0),	\
	V(2B,B3,16,6C),	V(A9,70,B9,99),	V(11,94,48,FA),	V(47,E9,64,22),	\
	V(A8,FC,8C,C4),	V(A0,F0,3F,1A),	V(56,7D,2C,D8),	V(22,33,90,EF),	\
	V(87,49,4E,C7),	V(D9,38,D1,C1),	V(8C,CA,A2,FE),	V(98,D4,0B,36),	\
	V(A6,F5,81,CF),	V(A5,7A,DE,28),	V(DA,B7,8E,26),	V(3F,AD,BF,A4),	\
	V(2C,3A,9D,E4),	V(50,78,92,0D),	V(6A,5F,CC,9B),	V(54,7E,46,62),	\
	V(F6,8D,13,C2),	V(90,D8,B8,E8),	V(2E,39,F7,5E),	V(82,C3,AF,F5),	\
	V(9F,5D,80,BE),	V(69,D0,93,7C),	V(6F,D5,2D,A9),	V(CF,25,12,B3),	\
	V(C8,AC,99,3B),	V(10,18,7D,A7),	V(E8,9C,63,6E),	V(DB,3B,BB,7B),	\
	V(CD,26,78,09),	V(6E,59,18,F4),	V(EC,9A,B7,01),	V(83,4F,9A,A8),	\
	V(E6,95,6E,65),	V(AA,FF,E6,7E),	V(21,BC,CF,08),	V(EF,15,E8,E6),	\
	V(BA,E7,9B,D9),	V(4A,6F,36,CE),	V(EA,9F,09,D4),	V(29,B0,7C,D6),	\
	V(31,A4,B2,AF),	V(2A,3F,23,31),	V(C6,A5,94,30),	V(35,A2,66,C0),	\
	V(74,4E,BC,37),	V(FC,82,CA,A6),	V(E0,90,D0,B0),	V(33,A7,D8,15),	\
	V(F1,04,98,4A),	V(41,EC,DA,F7),	V(7F,CD,50,0E),	V(17,91,F6,2F),	\
	V(76,4D,D6,8D),	V(43,EF,B0,4D),	V(CC,AA,4D,54),	V(E4,96,04,DF),	\
	V(9E,D1,B5,E3),	V(4C,6A,88,1B),	V(C1,2C,1F,B8),	V(46,65,51,7F),	\
	V(9D,5E,EA,04),	V(01,8C,35,5D),	V(FA,87,74,73),	V(FB,0B,41,2E),	\
	V(B3,67,1D,5A),	V(92,DB,D2,52),	V(E9,10,56,33),	V(6D,D6,47,13),	\
	V(9A,D7,61,8C),	V(37,A1,0C,7A),	V(59,F8,14,8E),	V(EB,13,3C,89),	\
	V(CE,A9,27,EE),	V(B7,61,C9,35),	V(E1,1C,E5,ED),	V(7A,47,B1,3C),	\
	V(9C,D2,DF,59),	V(55,F2,73,3F),	V(18,14,CE,79),	V(73,C7,37,BF),	\
	V(53,F7,CD,EA),	V(5F,FD,AA,5B),	V(DF,3D,6F,14),	V(78,44,DB,86),	\
	V(CA,AF,F3,81),	V(B9,68,C4,3E),	V(38,24,34,2C),	V(C2,A3,40,5F),	\
	V(16,1D,C3,72),	V(BC,E2,25,0C),	V(28,3C,49,8B),	V(FF,0D,95,41),	\
	V(39,A8,01,71),	V(08,0C,B3,DE),	V(D8,B4,E4,9C),	V(64,56,C1,90),	\
	V(7B,CB,84,61),	V(D5,32,B6,70),	V(48,6C,5C,74),	V(D0,B8,57,42)
#define	V(a,b,c,d) 0x##a##b##c##d
static uint32 RT0[256] = { RT };
#undef V
#define	V(a,b,c,d) 0x##d##a##b##c
static uint32 RT1[256] = { RT };
#undef V
#define	V(a,b,c,d) 0x##c##d##a##b
static uint32 RT2[256] = { RT };
#undef V
#define	V(a,b,c,d) 0x##b##c##d##a
static uint32 RT3[256] = { RT };
#undef V
#undef RT
/* round constants */
static uint32 RCON[10] =
{
	0x01000000,	0x02000000,	0x04000000,	0x08000000,
	0x10000000,	0x20000000,	0x40000000,	0x80000000,
	0x1B000000,	0x36000000
};
/* key schedule	tables */
static int KT_init = 1;
static uint32 KT0[256];
static uint32 KT1[256];
static uint32 KT2[256];
static uint32 KT3[256];
/* platform-independant	32-bit integer manipulation	macros */
#define	GET_UINT32(n,b,i)						\
{												\
	(n)	= (	(uint32) (b)[(i)	] << 24	)		\
		| (	(uint32) (b)[(i) + 1] << 16	)		\
		| (	(uint32) (b)[(i) + 2] <<  8	)		\
		| (	(uint32) (b)[(i) + 3]		);		\
}
#define	PUT_UINT32(n,b,i)						\
{												\
	(b)[(i)	   ] = (uint8) ( (n) >>	24 );		\
	(b)[(i)	+ 1] = (uint8) ( (n) >>	16 );		\
	(b)[(i)	+ 2] = (uint8) ( (n) >>	 8 );		\
	(b)[(i)	+ 3] = (uint8) ( (n)	   );		\
}
/* AES key scheduling routine */
int	aes_set_key( aes_context *ctx, uint8 *key, int nbits )
{
	int	i;
	uint32 *RK,	*SK;
	switch(	nbits )
	{
		case 128: ctx->nr =	10;	break;
		case 192: ctx->nr =	12;	break;
		case 256: ctx->nr =	14;	break;
		default	: return( 1	);
	}
	RK = ctx->erk;
	for( i = 0;	i <	(nbits >> 5); i++ )
	{
		GET_UINT32(	RK[i], key,	i *	4 );
	}
	/* setup encryption	round keys */
	switch(	nbits )
	{
	case 128:
		for( i = 0;	i <	10;	i++, RK	+= 4 )
		{
			RK[4]  = RK[0] ^ RCON[i] ^
						( FSb[ (uint8) ( RK[3] >> 16 ) ] <<	24 ) ^
						( FSb[ (uint8) ( RK[3] >>  8 ) ] <<	16 ) ^
						( FSb[ (uint8) ( RK[3]		 ) ] <<	 8 ) ^
						( FSb[ (uint8) ( RK[3] >> 24 ) ]	   );
			RK[5]  = RK[1] ^ RK[4];
			RK[6]  = RK[2] ^ RK[5];
			RK[7]  = RK[3] ^ RK[6];
		}
		break;
	case 192:
		for( i = 0;	i <	8; i++,	RK += 6	)
		{
			RK[6]  = RK[0] ^ RCON[i] ^
						( FSb[ (uint8) ( RK[5] >> 16 ) ] <<	24 ) ^
						( FSb[ (uint8) ( RK[5] >>  8 ) ] <<	16 ) ^
						( FSb[ (uint8) ( RK[5]		 ) ] <<	 8 ) ^
						( FSb[ (uint8) ( RK[5] >> 24 ) ]	   );
			RK[7]  = RK[1] ^ RK[6];
			RK[8]  = RK[2] ^ RK[7];
			RK[9]  = RK[3] ^ RK[8];
			RK[10] = RK[4] ^ RK[9];
			RK[11] = RK[5] ^ RK[10];
		}
		break;
	case 256:
		for( i = 0;	i <	7; i++,	RK += 8	)
		{
			RK[8]  = RK[0] ^ RCON[i] ^
						( FSb[ (uint8) ( RK[7] >> 16 ) ] <<	24 ) ^
						( FSb[ (uint8) ( RK[7] >>  8 ) ] <<	16 ) ^
						( FSb[ (uint8) ( RK[7]		 ) ] <<	 8 ) ^
						( FSb[ (uint8) ( RK[7] >> 24 ) ]	   );
			RK[9]  = RK[1] ^ RK[8];
			RK[10] = RK[2] ^ RK[9];
			RK[11] = RK[3] ^ RK[10];
			RK[12] = RK[4] ^
						( FSb[ (uint8) ( RK[11]	>> 24 )	] << 24	) ^
						( FSb[ (uint8) ( RK[11]	>> 16 )	] << 16	) ^
						( FSb[ (uint8) ( RK[11]	>>	8 )	] <<  8	) ^
						( FSb[ (uint8) ( RK[11]		  )	]		);
			RK[13] = RK[5] ^ RK[12];
			RK[14] = RK[6] ^ RK[13];
			RK[15] = RK[7] ^ RK[14];
		}
		break;
	}
	/* setup decryption	round keys */
	if(	KT_init	)
	{
		for( i = 0;	i <	256; i++ )
		{
			KT0[i] = RT0[ FSb[i] ];
			KT1[i] = RT1[ FSb[i] ];
			KT2[i] = RT2[ FSb[i] ];
			KT3[i] = RT3[ FSb[i] ];
		}
		KT_init	= 0;
	}
	SK = ctx->drk;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	for( i = 1;	i <	ctx->nr; i++ )
	{
		RK -= 8;
		*SK++ =	KT0[ (uint8) ( *RK >> 24 ) ] ^
				KT1[ (uint8) ( *RK >> 16 ) ] ^
				KT2[ (uint8) ( *RK >>  8 ) ] ^
				KT3[ (uint8) ( *RK		 ) ]; RK++;
		*SK++ =	KT0[ (uint8) ( *RK >> 24 ) ] ^
				KT1[ (uint8) ( *RK >> 16 ) ] ^
				KT2[ (uint8) ( *RK >>  8 ) ] ^
				KT3[ (uint8) ( *RK		 ) ]; RK++;
		*SK++ =	KT0[ (uint8) ( *RK >> 24 ) ] ^
				KT1[ (uint8) ( *RK >> 16 ) ] ^
				KT2[ (uint8) ( *RK >>  8 ) ] ^
				KT3[ (uint8) ( *RK		 ) ]; RK++;
		*SK++ =	KT0[ (uint8) ( *RK >> 24 ) ] ^
				KT1[ (uint8) ( *RK >> 16 ) ] ^
				KT2[ (uint8) ( *RK >>  8 ) ] ^
				KT3[ (uint8) ( *RK		 ) ]; RK++;
	}
	RK -= 8;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	*SK++ =	*RK++;
	return(	0 );
}
/* AES 128-bit block encryption	routine	*/
void aes_encrypt(aes_context *ctx, uint8 input[16],	uint8 output[16] )
{
	uint32 *RK,	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3;
	RK = ctx->erk;
	GET_UINT32(	X0,	input,	0 ); X0	^= RK[0];
	GET_UINT32(	X1,	input,	4 ); X1	^= RK[1];
	GET_UINT32(	X2,	input,	8 ); X2	^= RK[2];
	GET_UINT32(	X3,	input, 12 ); X3	^= RK[3];
#define	AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)		\
{												\
	RK += 4;									\
												\
	X0 = RK[0] ^ FT0[ (uint8) (	Y0 >> 24 ) ] ^	\
				 FT1[ (uint8) (	Y1 >> 16 ) ] ^	\
				 FT2[ (uint8) (	Y2 >>  8 ) ] ^	\
				 FT3[ (uint8) (	Y3		 ) ];	\
												\
	X1 = RK[1] ^ FT0[ (uint8) (	Y1 >> 24 ) ] ^	\
				 FT1[ (uint8) (	Y2 >> 16 ) ] ^	\
				 FT2[ (uint8) (	Y3 >>  8 ) ] ^	\
				 FT3[ (uint8) (	Y0		 ) ];	\
												\
	X2 = RK[2] ^ FT0[ (uint8) (	Y2 >> 24 ) ] ^	\
				 FT1[ (uint8) (	Y3 >> 16 ) ] ^	\
				 FT2[ (uint8) (	Y0 >>  8 ) ] ^	\
				 FT3[ (uint8) (	Y1		 ) ];	\
												\
	X3 = RK[3] ^ FT0[ (uint8) (	Y3 >> 24 ) ] ^	\
				 FT1[ (uint8) (	Y0 >> 16 ) ] ^	\
				 FT2[ (uint8) (	Y1 >>  8 ) ] ^	\
				 FT3[ (uint8) (	Y2		 ) ];	\
}
	AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 1 */
	AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 2 */
	AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 3 */
	AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 4 */
	AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 5 */
	AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 6 */
	AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 7 */
	AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 8 */
	AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 9 */
	if(	ctx->nr	> 10 )
	{
		AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );	/* round 10	*/
		AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );	/* round 11	*/
	}
	if(	ctx->nr	> 12 )
	{
		AES_FROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );	/* round 12	*/
		AES_FROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );	/* round 13	*/
	}
	/* last	round */
	RK += 4;
	X0 = RK[0] ^ ( FSb[	(uint8)	( Y0 >>	24 ) ] << 24 ) ^
				 ( FSb[	(uint8)	( Y1 >>	16 ) ] << 16 ) ^
				 ( FSb[	(uint8)	( Y2 >>	 8 ) ] <<  8 ) ^
				 ( FSb[	(uint8)	( Y3	   ) ]		 );
	X1 = RK[1] ^ ( FSb[	(uint8)	( Y1 >>	24 ) ] << 24 ) ^
				 ( FSb[	(uint8)	( Y2 >>	16 ) ] << 16 ) ^
				 ( FSb[	(uint8)	( Y3 >>	 8 ) ] <<  8 ) ^
				 ( FSb[	(uint8)	( Y0	   ) ]		 );
	X2 = RK[2] ^ ( FSb[	(uint8)	( Y2 >>	24 ) ] << 24 ) ^
				 ( FSb[	(uint8)	( Y3 >>	16 ) ] << 16 ) ^
				 ( FSb[	(uint8)	( Y0 >>	 8 ) ] <<  8 ) ^
				 ( FSb[	(uint8)	( Y1	   ) ]		 );
	X3 = RK[3] ^ ( FSb[	(uint8)	( Y3 >>	24 ) ] << 24 ) ^
				 ( FSb[	(uint8)	( Y0 >>	16 ) ] << 16 ) ^
				 ( FSb[	(uint8)	( Y1 >>	 8 ) ] <<  8 ) ^
				 ( FSb[	(uint8)	( Y2	   ) ]		 );
	PUT_UINT32(	X0,	output,	 0 );
	PUT_UINT32(	X1,	output,	 4 );
	PUT_UINT32(	X2,	output,	 8 );
	PUT_UINT32(	X3,	output,	12 );
}
/* AES 128-bit block decryption	routine	*/
void aes_decrypt( aes_context *ctx,	uint8 input[16], uint8 output[16] )
{
	uint32 *RK,	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3;
	RK = ctx->drk;
	GET_UINT32(	X0,	input,	0 ); X0	^= RK[0];
	GET_UINT32(	X1,	input,	4 ); X1	^= RK[1];
	GET_UINT32(	X2,	input,	8 ); X2	^= RK[2];
	GET_UINT32(	X3,	input, 12 ); X3	^= RK[3];
#define	AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)		\
{												\
	RK += 4;									\
												\
	X0 = RK[0] ^ RT0[ (uint8) (	Y0 >> 24 ) ] ^	\
				 RT1[ (uint8) (	Y3 >> 16 ) ] ^	\
				 RT2[ (uint8) (	Y2 >>  8 ) ] ^	\
				 RT3[ (uint8) (	Y1		 ) ];	\
												\
	X1 = RK[1] ^ RT0[ (uint8) (	Y1 >> 24 ) ] ^	\
				 RT1[ (uint8) (	Y0 >> 16 ) ] ^	\
				 RT2[ (uint8) (	Y3 >>  8 ) ] ^	\
				 RT3[ (uint8) (	Y2		 ) ];	\
												\
	X2 = RK[2] ^ RT0[ (uint8) (	Y2 >> 24 ) ] ^	\
				 RT1[ (uint8) (	Y1 >> 16 ) ] ^	\
				 RT2[ (uint8) (	Y0 >>  8 ) ] ^	\
				 RT3[ (uint8) (	Y3		 ) ];	\
												\
	X3 = RK[3] ^ RT0[ (uint8) (	Y3 >> 24 ) ] ^	\
				 RT1[ (uint8) (	Y2 >> 16 ) ] ^	\
				 RT2[ (uint8) (	Y1 >>  8 ) ] ^	\
				 RT3[ (uint8) (	Y0		 ) ];	\
}
	AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 1 */
	AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 2 */
	AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 3 */
	AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 4 */
	AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 5 */
	AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 6 */
	AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 7 */
	AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );		/* round 8 */
	AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );		/* round 9 */
	if(	ctx->nr	> 10 )
	{
		AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );	/* round 10	*/
		AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );	/* round 11	*/
	}
	if(	ctx->nr	> 12 )
	{
		AES_RROUND(	X0,	X1,	X2,	X3,	Y0,	Y1,	Y2,	Y3 );	/* round 12	*/
		AES_RROUND(	Y0,	Y1,	Y2,	Y3,	X0,	X1,	X2,	X3 );	/* round 13	*/
	}
	/* last	round */
	RK += 4;
	X0 = RK[0] ^ ( RSb[	(uint8)	( Y0 >>	24 ) ] << 24 ) ^
				 ( RSb[	(uint8)	( Y3 >>	16 ) ] << 16 ) ^
				 ( RSb[	(uint8)	( Y2 >>	 8 ) ] <<  8 ) ^
				 ( RSb[	(uint8)	( Y1	   ) ]		 );
	X1 = RK[1] ^ ( RSb[	(uint8)	( Y1 >>	24 ) ] << 24 ) ^
				 ( RSb[	(uint8)	( Y0 >>	16 ) ] << 16 ) ^
				 ( RSb[	(uint8)	( Y3 >>	 8 ) ] <<  8 ) ^
				 ( RSb[	(uint8)	( Y2	   ) ]		 );
	X2 = RK[2] ^ ( RSb[	(uint8)	( Y2 >>	24 ) ] << 24 ) ^
				 ( RSb[	(uint8)	( Y1 >>	16 ) ] << 16 ) ^
				 ( RSb[	(uint8)	( Y0 >>	 8 ) ] <<  8 ) ^
				 ( RSb[	(uint8)	( Y3	   ) ]		 );
	X3 = RK[3] ^ ( RSb[	(uint8)	( Y3 >>	24 ) ] << 24 ) ^
				 ( RSb[	(uint8)	( Y2 >>	16 ) ] << 16 ) ^
				 ( RSb[	(uint8)	( Y1 >>	 8 ) ] <<  8 ) ^
				 ( RSb[	(uint8)	( Y0	   ) ]		 );
	PUT_UINT32(	X0,	output,	 0 );
	PUT_UINT32(	X1,	output,	 4 );
	PUT_UINT32(	X2,	output,	 8 );
	PUT_UINT32(	X3,	output,	12 );
}
/*
* F(P, S, c, i) = U1 xor U2 xor ... Uc 
* U1 = PRF(P, S || Int(i)) 
* U2 = PRF(P, U1) 
* Uc = PRF(P, Uc-1) 
*/ 
void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) 
{ 
    unsigned char digest[36], digest1[SHA_DIGEST_LEN]; 
    int i, j; 
    /* U1 = PRF(P, S || int(i)) */ 
    memcpy(digest, ssid, ssidlength); 
    digest[ssidlength] = (unsigned char)((count>>24) & 0xff); 
    digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); 
    digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); 
    digest[ssidlength+3] = (unsigned char)(count & 0xff); 
    HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update
    /* output = U1 */ 
    memcpy(output, digest1, SHA_DIGEST_LEN); 
    for (i = 1; i < iterations; i++) 
    { 
        /* Un = PRF(P, Un-1) */ 
        HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update
        memcpy(digest1, digest, SHA_DIGEST_LEN); 
        /* output = output xor Un */ 
        for (j = 0; j < SHA_DIGEST_LEN; j++) 
        { 
            output[j] ^= digest[j]; 
        } 
    } 
}/* 
* password - ascii string up to 63 characters in length 
* ssid - octet string up to 32 octets 
* ssidlength - length of ssid in octets 
* output must be 40 octets in length and outputs 256 bits of key 
*/ 
int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) 
{ 
    if ((strlen(password) > 63) || (ssidlength > 32)) 
        return 0; 
    F(password, ssid, ssidlength, 4096, 1, output); 
    F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); 
    return 1; 
}
(-) rt2570-1.1.0-b1/Module/mlme.c (-16 / +26 lines)
 Lines 31-36    Link Here 
 *	Name		Date		Modification logs
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 *	Jan Lee		2005-06-01	Release
 *	MathiasK	09-07-2005	kmalloc ATOMIC fixes
 *	MathiasK	09-07-2005	kmalloc ATOMIC fixes
 *	RobinC		31-08-2005	Block mlme in MONITOR mode to keep from sending probe requests
 ***************************************************************************/
 ***************************************************************************/
#include "rt_config.h"
#include "rt_config.h"
 Lines 368-374    Link Here 
			break;
			break;
		}
		}
		//From message type, determine which state machine I should drive
		//From message type, determine which state machine I should drive
		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) 
		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem) && pAd->PortCfg.BssType!=BSS_MONITOR) 
		{
		{
			// if dequeue success
			// if dequeue success
			switch (Elem->Machine) 
			switch (Elem->Machine) 
 Lines 1083-1089    Link Here 
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					DBGPRINT(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				}
 Lines 1093-1099    Link Here 
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					DBGPRINT(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				}
 Lines 1103-1109    Link Here 
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					DBGPRINT(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				}
 Lines 1114-1120    Link Here 
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_TRACE, ("TXRX_CSR18 = 0x%x\n", Csr18.value));
					DBGPRINT(RT_DEBUG_TRACE, ("TXRX_CSR18 = 0x%x\n", Csr18.value));
					
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				}
 Lines 1123-1129    Link Here 
#if 0
#if 0
			else if (pAd->ReceivedBeaconsCount > 9 * pAd->SentBeaconsCount)
			else if (pAd->ReceivedBeaconsCount > 9 * pAd->SentBeaconsCount)
			{
			{
				DBGPRINT_RAW(RT_DEBUG_TRACE, ("Do Nothing\n"));
				DBGPRINT(RT_DEBUG_TRACE, ("Do Nothing\n"));
			}
			}
#endif
#endif
			else
			else
 Lines 1132-1138    Link Here 
				Csr18.field.Offset = (temp & 0x000F);
				Csr18.field.Offset = (temp & 0x000F);
				Csr18.field.Interval = (temp >> 6);
				Csr18.field.Interval = (temp >> 6);
				RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
				RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
				DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
				DBGPRINT(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
				
				
				pAd->BeaconIntervalChangeAllowed = TRUE;
				pAd->BeaconIntervalChangeAllowed = TRUE;
			}
			}
 Lines 1309-1319    Link Here 
        if (pAd->DrsCounters.fNoisyEnvironment)
        if (pAd->DrsCounters.fNoisyEnvironment)
        {
        {
            DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS(noisy):"); 
            DBGPRINT(RT_DEBUG_TRACE,"DRS(noisy): ");
        }
        }
        else
        else
        {
        {
            DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS:"); 
            DBGPRINT(RT_DEBUG_TRACE,"DRS: ");
        }
        }
        DBGPRINT_RAW(RT_DEBUG_TRACE,"Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n", 
        DBGPRINT_RAW(RT_DEBUG_TRACE,"Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n", 
            RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
            RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
 Lines 1401-1407    Link Here 
    // if rate-up happen, clear all bad history of all TX rates
    // if rate-up happen, clear all bad history of all TX rates
    if (pAd->PortCfg.TxRate > CurrRate)
    if (pAd->PortCfg.TxRate > CurrRate)
    {
    {
       	DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
       	DBGPRINT(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
        pAd->DrsCounters.CurrTxRateStableTime = 0;
        pAd->DrsCounters.CurrTxRateStableTime = 0;
        pAd->DrsCounters.TxRateUpPenalty = 0;
        pAd->DrsCounters.TxRateUpPenalty = 0;
        pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
        pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
 Lines 1411-1417    Link Here 
    // if rate-down happen, only clear DownRate's bad history
    // if rate-down happen, only clear DownRate's bad history
    else if (pAd->PortCfg.TxRate < CurrRate)
    else if (pAd->PortCfg.TxRate < CurrRate)
    {
    {
       	DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
       	DBGPRINT(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
	    // shorter stable time require more penalty in next rate UP criteria
	    // shorter stable time require more penalty in next rate UP criteria
       	if (pAd->DrsCounters.CurrTxRateStableTime < 4)      // less then 4 sec
       	if (pAd->DrsCounters.CurrTxRateStableTime < 4)      // less then 4 sec
       	    pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
       	    pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
 Lines 1775-1785    Link Here 
		RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
		RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
        	DBGPRINT(RT_DEBUG_ERROR, "4Set fRTMP_ADAPTER_RADIO_OFF ");
        	DBGPRINT(RT_DEBUG_ERROR, "4Set fRTMP_ADAPTER_RADIO_OFF ");
	}	
	}	
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  MlmeRadioOff \n" );
	DBGPRINT_RAW(RT_DEBUG_TEMP,"MlmeRadioOff \n");
	RTUSBRejectPendingPackets(pAd);//reject all NDIS packets waiting in TX queue
	RTUSBRejectPendingPackets(pAd);//reject all NDIS packets waiting in TX queue
	RTUSBCleanUpDataBulkOutQueue(pAd);
	RTUSBCleanUpDataBulkOutQueue(pAd);
	MlmeSuspend(pAd);
	MlmeSuspend(pAd);
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  2MlmeRadioOff \n" );
	DBGPRINT_RAW(RT_DEBUG_TEMP,"2MlmeRadioOff \n");
	// Abort Tx
	// Abort Tx
	// Disable Rx
	// Disable Rx
	RTUSBWriteMACRegister(pAd, TXRX_CSR2, 1);
	RTUSBWriteMACRegister(pAd, TXRX_CSR2, 1);
 Lines 1788-1794    Link Here 
	{
	{
		if (atomic_read(&pAd->PendingRx) > 0)
		if (atomic_read(&pAd->PendingRx) > 0)
		{
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkIn IRP Pending!!!\n");
			DBGPRINT(RT_DEBUG_TRACE, "BulkIn IRP Pending!!!\n");
			RTUSB_VendorRequest(pAd,
			RTUSB_VendorRequest(pAd,
				0,
				0,
				DEVICE_VENDOR_REQUEST_OUT,
				DEVICE_VENDOR_REQUEST_OUT,
 Lines 1801-1807    Link Here 
		
		
		if (pAd->BulkOutPending == TRUE)
		if (pAd->BulkOutPending == TRUE)
		{
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkOut IRP Pending!!!\n");
			DBGPRINT(RT_DEBUG_TRACE, "BulkOut IRP Pending!!!\n");
			if (i == 0)
			if (i == 0)
			{
			{
				RTUSBCancelPendingBulkOutIRP(pAd);
				RTUSBCancelPendingBulkOutIRP(pAd);
 Lines 1824-1830    Link Here 
	
	
	// Clean up old bss table
	// Clean up old bss table
	BssTableInit(&pAd->PortCfg.BssTab);
	BssTableInit(&pAd->PortCfg.BssTab);
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  <==MlmeRadioOff \n" );
	DBGPRINT(RT_DEBUG_TEMP,"<==MlmeRadioOff \n" );
#endif
#endif
}
}
 Lines 2727-2733    Link Here 
	INT Tail;
	INT Tail;
	MLME_QUEUE	*Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
	MLME_QUEUE	*Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	if (pAd->MLMEThr_pid > 0)
	if (pAd->MLMEThr_pid > 0)
#else
	if (pAd->MLMEThr_active)
#endif
	{
	{
		if (MlmeQueueFull(Queue)) 
		if (MlmeQueueFull(Queue)) 
 Lines 2783-2790    Link Here 
    ULONG        MsgType;
    ULONG        MsgType;
	//DBGPRINT(RT_DEBUG_ERROR,"MlmeEnqueueForRecv ");
	//DBGPRINT(RT_DEBUG_ERROR,"MlmeEnqueueForRecv ");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	if((pAd->MLMEThr_pid <= 0))
	if((pAd->MLMEThr_pid <= 0))
		return FALSE;
		return FALSE;
#else
	if(!pAd->MLMEThr_active)
		return FALSE;
#endif
	// First check the size, it MUST not exceed the mlme queue size
	// First check the size, it MUST not exceed the mlme queue size
	if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
	if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
	{
	{
(-) rt2570-1.1.0-b1/Module/.#mlme.c.1.4 (-4497 lines)
 Lines 1-4497    Link Here 
/*************************************************************************** 
 * RT2x00 SourceForge Project - http://rt2x00.sourceforge.net              * 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 *   This program is distributed in the hope that it will be useful,       * 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * 
 *   GNU General Public License for more details.                          * 
 *                                                                         * 
 *   You should have received a copy of the GNU General Public License     * 
 *   along with this program; if not, write to the                         * 
 *   Free Software Foundation, Inc.,                                       * 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * 
 *                                                                         * 
 *   Licensed under the GNU GPL                                            * 
 *   Original code supplied under license from RaLink Inc, 2004.           * 
 ***************************************************************************/
/*************************************************************************** 
 *	Module Name:	mlme.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 *	MathiasK	09-07-2005	kmalloc ATOMIC fixes
 ***************************************************************************/
#include "rt_config.h"
                                  //  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 };
                                  //  1      2       5.5      11  
UCHAR Phy11BNextRateDownward[] = {RATE_1, RATE_1,   RATE_2,  RATE_5_5};
UCHAR Phy11BNextRateUpward[]   = {RATE_2, RATE_5_5, RATE_11, RATE_11};
                                  //  1      2       5.5      11        6        9        12      18       24       36       48       54
UCHAR Phy11BGNextRateDownward[]= {RATE_1, RATE_1,   RATE_2,  RATE_5_5,RATE_11,  RATE_6,  RATE_11, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48};
UCHAR Phy11BGNextRateUpward[]  = {RATE_2, RATE_5_5, RATE_11, RATE_12, RATE_9,   RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54};
                                  //  1      2       5.5      11        6        9        12      18       24       36       48       54
UCHAR Phy11ANextRateDownward[] = {RATE_6, RATE_6,   RATE_6,  RATE_6,  RATE_6,   RATE_6,  RATE_9,  RATE_12, RATE_18, RATE_24, RATE_36, RATE_48};
UCHAR Phy11ANextRateUpward[]   = {RATE_9, RATE_9,   RATE_9,  RATE_9,  RATE_9,   RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54};
// 2560D and after has implemented ASIC-based OFDM rate switching, but not
// 2560C and before. thus software use different PER for rate switching
//                          RATE_1,  2, 5.5, 11,  6,  9, 12, 18, 24, 36, 48, 54
USHORT NewRateUpPER[]   = {    40,  40,  35, 20, 20, 20, 20, 16, 10, 16, 10,  6 }; // in percentage
USHORT NewRateDownPER[] = {    50,  50,  45, 45, 35, 35, 35, 35, 25, 25, 25, 13 }; // in percentage
USHORT OldRateUpPER[]   = {    40,  40,  40, 40, 30, 30, 30, 30, 20, 20, 10, 10 }; // in percentage
USHORT OldRateDownPER[] = {    45,  45,  45, 45, 35, 35, 35, 35, 25, 25, 25, 12 }; // in percentage
    
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};
    
RTMP_RF_REGS RF2522RegTable[] = {
//      ch   R1          R2          R3(TX0~4=0) R4
        {1,  0x94002050, 0x940c1fda, 0x94000101, 0},
        {2,  0x94002050, 0x940c1fee, 0x94000101, 0},
        {3,  0x94002050, 0x940c2002, 0x94000101, 0},
        {4,  0x94002050, 0x940c2016, 0x94000101, 0},
        {5,  0x94002050, 0x940c202a, 0x94000101, 0},
        {6,  0x94002050, 0x940c203e, 0x94000101, 0},
        {7,  0x94002050, 0x940c2052, 0x94000101, 0},
        {8,  0x94002050, 0x940c2066, 0x94000101, 0},
        {9,  0x94002050, 0x940c207a, 0x94000101, 0},
        {10, 0x94002050, 0x940c208e, 0x94000101, 0},
        {11, 0x94002050, 0x940c20a2, 0x94000101, 0},
        {12, 0x94002050, 0x940c20b6, 0x94000101, 0},
        {13, 0x94002050, 0x940c20ca, 0x94000101, 0},
        {14, 0x94002050, 0x940c20fa, 0x94000101, 0}
};
#define	NUM_OF_2522_CHNL	(sizeof(RF2522RegTable) / sizeof(RTMP_RF_REGS))
RTMP_RF_REGS RF2523RegTable[] = {
//      ch   R1          R2          R3(TX0~4=0) R4
        {1,  0x94022010, 0x94000c9e, 0x940e0111, 0x94000a1b},
        {2,  0x94022010, 0x94000ca2, 0x940e0111, 0x94000a1b},
        {3,  0x94022010, 0x94000ca6, 0x940e0111, 0x94000a1b},
        {4,  0x94022010, 0x94000caa, 0x940e0111, 0x94000a1b},
        {5,  0x94022010, 0x94000cae, 0x940e0111, 0x94000a1b},
        {6,  0x94022010, 0x94000cb2, 0x940e0111, 0x94000a1b},
        {7,  0x94022010, 0x94000cb6, 0x940e0111, 0x94000a1b},
        {8,  0x94022010, 0x94000cba, 0x940e0111, 0x94000a1b},
        {9,  0x94022010, 0x94000cbe, 0x940e0111, 0x94000a1b},
        {10, 0x94022010, 0x94000d02, 0x940e0111, 0x94000a1b},
        {11, 0x94022010, 0x94000d06, 0x940e0111, 0x94000a1b},
        {12, 0x94022010, 0x94000d0a, 0x940e0111, 0x94000a1b},
        {13, 0x94022010, 0x94000d0e, 0x940e0111, 0x94000a1b},
        {14, 0x94022010, 0x94000d1a, 0x940e0111, 0x94000a03}
};
#define	NUM_OF_2523_CHNL	(sizeof(RF2523RegTable) / sizeof(RTMP_RF_REGS))
RTMP_RF_REGS RF2524RegTable[] = {
//      ch   R1          R2          R3(TX0~4=0) R4
        {1,  0x94032020, 0x94000c9e, 0x94000101, 0x94000a1b},
        {2,  0x94032020, 0x94000ca2, 0x94000101, 0x94000a1b},
        {3,  0x94032020, 0x94000ca6, 0x94000101, 0x94000a1b},
        {4,  0x94032020, 0x94000caa, 0x94000101, 0x94000a1b},
        {5,  0x94032020, 0x94000cae, 0x94000101, 0x94000a1b},
        {6,  0x94032020, 0x94000cb2, 0x94000101, 0x94000a1b},
        {7,  0x94032020, 0x94000cb6, 0x94000101, 0x94000a1b},
        {8,  0x94032020, 0x94000cba, 0x94000101, 0x94000a1b},
        {9,  0x94032020, 0x94000cbe, 0x94000101, 0x94000a1b},
        {10, 0x94032020, 0x94000d02, 0x94000101, 0x94000a1b},
        {11, 0x94032020, 0x94000d06, 0x94000101, 0x94000a1b},
        {12, 0x94032020, 0x94000d0a, 0x94000101, 0x94000a1b},
        {13, 0x94032020, 0x94000d0e, 0x94000101, 0x94000a1b},
        {14, 0x94032020, 0x94000d1a, 0x94000101, 0x94000a03}
};
#define	NUM_OF_2524_CHNL	(sizeof(RF2524RegTable) / sizeof(RTMP_RF_REGS))
            
RTMP_RF_REGS_1 RF2525RegTable[] = {
//      ch   TempR2		 R1          R2          R3(TX0~4=0) R4
        {1,  0x94080cbe, 0x94022020, 0x94080c9e, 0x94060111, 0x94000a1b}, // {1,  0x94022010, 0x9408062e, 0x94060111, 0x94000a23}, 
        {2,  0x94080d02, 0x94022020, 0x94080ca2, 0x94060111, 0x94000a1b},
        {3,  0x94080d06, 0x94022020, 0x94080ca6, 0x94060111, 0x94000a1b},
        {4,  0x94080d0a, 0x94022020, 0x94080caa, 0x94060111, 0x94000a1b},
        {5,  0x94080d0e, 0x94022020, 0x94080cae, 0x94060111, 0x94000a1b},
        {6,  0x94080d12, 0x94022020, 0x94080cb2, 0x94060111, 0x94000a1b},
        {7,  0x94080d16, 0x94022020, 0x94080cb6, 0x94060111, 0x94000a1b},
        {8,  0x94080d1a, 0x94022020, 0x94080cba, 0x94060111, 0x94000a1b},
        {9,  0x94080d1e, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b},
        {10, 0x94080d22, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b},
        {11, 0x94080d26, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b}, // {11, 0x94022010, 0x94080682, 0x94060111, 0x94000a23}, 
        {12, 0x94080d2a, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b},
        {13, 0x94080d2e, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b}, // {13, 0x94022010, 0x94080686, 0x94060111, 0x94000a23}, 
        {14, 0x94080d3a, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a03}
};
#define	NUM_OF_2525_CHNL	(sizeof(RF2525RegTable) / sizeof(RTMP_RF_REGS_1))
RTMP_RF_REGS_1 RF2525eRegTable[] = {
// using 10 Mhz reference clock
//      ch   TempR2		 R1          R2          R3(TX0~4=0) R4
        {1,  0x940008aa, 0x94022010, 0x9400089a, 0x94060111, 0x94000e1b},
        {2,  0x940008ae, 0x94022010, 0x9400089e, 0x94060111, 0x94000e07},
        {3,  0x940008ae, 0x94022010, 0x9400089e, 0x94060111, 0x94000e1b},
        {4,  0x940008b2, 0x94022010, 0x940008a2, 0x94060111, 0x94000e07},
        {5,  0x940008b2, 0x94022010, 0x940008a2, 0x94060111, 0x94000e1b},
        {6,  0x940008b6, 0x94022010, 0x940008a6, 0x94060111, 0x94000e07},
        {7,  0x940008b6, 0x94022010, 0x940008a6, 0x94060111, 0x94000e1b},
        {8,  0x940008ba, 0x94022010, 0x940008aa, 0x94060111, 0x94000e07},
        {9,  0x940008ba, 0x94022010, 0x940008aa, 0x94060111, 0x94000e1b},
        {10, 0x940008be, 0x94022010, 0x940008ae, 0x94060111, 0x94000e07},
        {11, 0x940008b7, 0x94022010, 0x940008ae, 0x94060111, 0x94000e1b}, 
        {12, 0x94000902, 0x94022010, 0x940008b2, 0x94060111, 0x94000e07},
        {13, 0x94000902, 0x94022010, 0x940008b2, 0x94060111, 0x94000e1b},
        {14, 0x94000906, 0x94022010, 0x940008b6, 0x94060111, 0x94000e23}
};
#define	NUM_OF_2525E_CHNL	(sizeof(RF2525eRegTable) / sizeof(RTMP_RF_REGS_1))
RTMP_RF_REGS RF5222RegTable[] = {
//      ch   R1          R2          R3(TX0~4=0) R4
        {1,  0x94022020, 0x94001136, 0x94000101, 0x94000a0b},
        {2,  0x94022020, 0x9400113a, 0x94000101, 0x94000a0b},
        {3,  0x94022020, 0x9400113e, 0x94000101, 0x94000a0b},
        {4,  0x94022020, 0x94001182, 0x94000101, 0x94000a0b},
        {5,  0x94022020, 0x94001186, 0x94000101, 0x94000a0b},
        {6,  0x94022020, 0x9400118a, 0x94000101, 0x94000a0b},
        {7,  0x94022020, 0x9400118e, 0x94000101, 0x94000a0b},
        {8,  0x94022020, 0x94001192, 0x94000101, 0x94000a0b},
        {9,  0x94022020, 0x94001196, 0x94000101, 0x94000a0b},
        {10, 0x94022020, 0x9400119a, 0x94000101, 0x94000a0b},
        {11, 0x94022020, 0x9400119e, 0x94000101, 0x94000a0b},
        {12, 0x94022020, 0x940011a2, 0x94000101, 0x94000a0b},
        {13, 0x94022020, 0x940011a6, 0x94000101, 0x94000a0b},
        {14, 0x94022020, 0x940011ae, 0x94000101, 0x94000a1b},
        // still lack of MMAC(Japan) ch 34,38,42,46
        
        {36, 0x94022010, 0x94018896, 0x94000101, 0x94000a1f},
        {40, 0x94022010, 0x9401889a, 0x94000101, 0x94000a1f},
        {44, 0x94022010, 0x9401889e, 0x94000101, 0x94000a1f},
        {48, 0x94022010, 0x940188a2, 0x94000101, 0x94000a1f},
        {52, 0x94022010, 0x940188a6, 0x94000101, 0x94000a1f},
        {66, 0x94022010, 0x940188aa, 0x94000101, 0x94000a1f},
        {60, 0x94022010, 0x940188ae, 0x94000101, 0x94000a1f},
        {64, 0x94022010, 0x940188b2, 0x94000101, 0x94000a1f},
        
        {100, 0x94022010, 0x94008802, 0x94000101, 0x94000a0f},
        {104, 0x94022010, 0x94008806, 0x94000101, 0x94000a0f},
        {108, 0x94022010, 0x9400880a, 0x94000101, 0x94000a0f},
        {112, 0x94022010, 0x9400880e, 0x94000101, 0x94000a0f},
        {116, 0x94022010, 0x94008812, 0x94000101, 0x94000a0f},
        {120, 0x94022010, 0x94008816, 0x94000101, 0x94000a0f},
        {124, 0x94022010, 0x9400881a, 0x94000101, 0x94000a0f},
        {128, 0x94022010, 0x9400881e, 0x94000101, 0x94000a0f},
        {132, 0x94022010, 0x94008822, 0x94000101, 0x94000a0f},
        {136, 0x94022010, 0x94008826, 0x94000101, 0x94000a0f},
        {140, 0x94022010, 0x9400882a, 0x94000101, 0x94000a0f},
        
        {149, 0x94022020, 0x940090a6, 0x94000101, 0x94000a07},
        {153, 0x94022020, 0x940090ae, 0x94000101, 0x94000a07},
        {157, 0x94022020, 0x940090b6, 0x94000101, 0x94000a07},
        {161, 0x94022020, 0x940090be, 0x94000101, 0x94000a07}
};
#define	NUM_OF_5222_CHNL	(sizeof(RF5222RegTable) / sizeof(RTMP_RF_REGS))
/*
	==========================================================================
	Description:
		initialize the MLME task and its data structure (queue, spinlock, 
		timer, state machines).
	Return:
		always return NDIS_STATUS_SUCCESS
	==========================================================================
*/
NDIS_STATUS MlmeInit(
	IN PRT2570ADAPTER pAd) 
{
	NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
	DBGPRINT(RT_DEBUG_TRACE,"--> MLME Initialize\n");
	
	do 
	{
		Status = MlmeQueueInit(&pAd->Mlme.Queue);
		if(Status != NDIS_STATUS_SUCCESS) 
		{
			break;
		}
		// Initialize Mlme Memory Handler
		// Allocate 20 nonpaged memory pool which size are MAX_LEN_OF_MLME_BUFFER for use
		Status = MlmeInitMemoryHandler(pAd, 20, MAX_LEN_OF_MLME_BUFFER);
		if(Status != NDIS_STATUS_SUCCESS) 
		{
			break;
		}
		pAd->Mlme.Running = FALSE;
		NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
		// initialize the two tables
		// MacTableInit(pAd);
		BssTableInit(&pAd->PortCfg.BssTab);
		// init state machines
		ASSERT(ASSOC_FUNC_SIZE == MAX_ASSOC_MSG * MAX_ASSOC_STATE);
		AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc);
		
		ASSERT(AUTH_FUNC_SIZE == MAX_AUTH_MSG * MAX_AUTH_STATE);
		AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc);
		
		ASSERT(AUTH_RSP_FUNC_SIZE == MAX_AUTH_RSP_MSG * MAX_AUTH_RSP_STATE);
		AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc);
		ASSERT(WPA_PSK_FUNC_SIZE == MAX_WPA_PSK_MSG * MAX_WPA_PSK_STATE);
		WpaPskStateMachineInit(pAd,&pAd->Mlme.WpaPskMachine,pAd->Mlme.WpaPskFunc);
		ASSERT(SYNC_FUNC_SIZE == MAX_SYNC_MSG * MAX_SYNC_STATE);
		SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc);
		// Since we are using switch/case to implement it, the init is different from the above 
		// state machine init
		MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
		RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, &MlmePeriodicExec);
		//pAd->Mlme.PeriodicTimer.data = (unsigned long)pAd;
		//pAd->Mlme.PeriodicTimer.function = &MlmePeriodicExec;
		pAd->Mlme.PeriodicTimer.Timer.expires = jiffies + MLME_TASK_EXEC_INTV;
		// delay first mlme timer
		RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, 2*MLME_TASK_EXEC_INTV);
		if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)
		{
			RTMPInitTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, &AsicLedPeriodicExec);
			//pAd->PortCfg.LedCntl.BlinkTimer.data = (unsigned long)pAd;
			//pAd->PortCfg.LedCntl.BlinkTimer.function = &AsicLedPeriodicExec;
			pAd->PortCfg.LedCntl.BlinkTimer.Timer.expires = jiffies + (70 * HZ)/1000;
			RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70);
		}
	
	} while (FALSE);
	DBGPRINT(RT_DEBUG_TRACE,"<-- MLME Initialize\n");
	return Status;
}
/*
    ==========================================================================
    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 PRT2570ADAPTER pAd) 
{
    DBGPRINT(RT_DEBUG_TRACE, "==> MlmeHalt\n");
	// Cancel pending timers
	RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
	RTMPCancelTimer(&pAd->Mlme.PeriodicTimer);
	if ((pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)||(pAd->PortCfg.LedMode == LED_MODE_ALPHA))
		RTMPCancelTimer(&pAd->PortCfg.LedCntl.BlinkTimer);
	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS))
	{
		ASIC_LED_ACT_OFF(pAd);
	}
	// for timer callback routine to finish.
	NdisMSleep(1000);
	MlmeQueueDestroy(&pAd->Mlme.Queue);
	StateMachineDestroy(&pAd->Mlme.AssocMachine);
	StateMachineDestroy(&pAd->Mlme.AuthMachine);
	StateMachineDestroy(&pAd->Mlme.AuthRspMachine);
	StateMachineDestroy(&pAd->Mlme.SyncMachine);
	StateMachineDestroy(&pAd->Mlme.WpaPskMachine);
	//    StateMachineDestroy(&pAd->Mlme.CntlMachine);
	// no need free spinlock of pAd->Mlme.TaskLock
	MlmeFreeMemoryHandler(pAd); //Free MLME memory handler
	DBGPRINT(RT_DEBUG_TRACE, "<== MlmeHalt\n");
}
VOID MlmeHandler(
    IN PRT2570ADAPTER pAd) 
{
	MLME_QUEUE_ELEM        *Elem = NULL;
	// Only accept MLME and Frame from peer side, no other (control/data) frame should
	// get into this state machine
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	if(pAd->Mlme.Running) 
	{
	    NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	    return;
	} 
	else 
	{
	    pAd->Mlme.Running = 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_REMOVE_IN_PROGRESS))
		{
			DBGPRINT(RT_DEBUG_TRACE, "Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %d)\n", pAd->Mlme.Queue.Num);
			break;
		}
		//From message type, determine which state machine I should drive
		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) 
		{
			// if dequeue success
			switch (Elem->Machine) 
			{
				case ASSOC_STATE_MACHINE:
				    StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem);
				    break;
				case AUTH_STATE_MACHINE:
				    StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem);
				    break;
				case AUTH_RSP_STATE_MACHINE:
				    StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem);
				    break;
				case SYNC_STATE_MACHINE:
				    StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem);
				    break;
				case MLME_CNTL_STATE_MACHINE:
				    MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem);
				    break;
				case WPA_PSK_STATE_MACHINE:
					StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem);
					break;
				default:
				    DBGPRINT(RT_DEBUG_TRACE, "ERROR: Illegal machine %d in MlmeHandler()\n",Elem->Machine);
				    break;
			} // end of switch
			// free MLME element
			Elem->Occupied = FALSE;
			Elem->MsgLen = 0;
            
		}
		else
		{
			DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
		}
	}
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS))
	{
		DBGPRINT(RT_DEBUG_TRACE, "MlmeHandler, Reset Mlme! (queue num = %d)\n", pAd->Mlme.Queue.Num);
		MlmeQueueDestroy(&pAd->Mlme.Queue);
		// Cancel all timer events
		// Be careful to cancel new added timer
		RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
		RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
		RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
		RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
		//    RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer, &Cancelled);
		RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
		RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
		// Set all state machines back IDLE
		pAd->Mlme.CntlMachine.CurrState    = CNTL_IDLE;
		pAd->Mlme.AssocMachine.CurrState   = ASSOC_IDLE;
		pAd->Mlme.AuthMachine.CurrState    = AUTH_REQ_IDLE;
		pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
		pAd->Mlme.SyncMachine.CurrState    = SYNC_IDLE;
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS))
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS))
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS);   
	}
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	pAd->Mlme.Running = FALSE;
	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
}
VOID MlmeSuspend(
    IN PRT2570ADAPTER pAd) 
{
    MLME_QUEUE_ELEM		*Elem = NULL;
	DBGPRINT(RT_DEBUG_TRACE, "==>MlmeSuspend\n");
	// Cancel pending timers
	RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
	// RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer, &Cancelled);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	if(pAd->Mlme.Running) 
	{
	    NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	    return;
	} 
	else 
	{
	    pAd->Mlme.Running = TRUE;
	}
	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	// Remove all Mlme queues elements
	while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) 
	{
		//From message type, determine which state machine I should drive
		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) 
		{
		    // free MLME element
		    Elem->Occupied = FALSE;
		    Elem->MsgLen = 0;
		    
		}
		else 
		{
		    DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
		}
	}
	
	// Remove running state
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	pAd->Mlme.Running = FALSE;
	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	RTUSBCleanUpMLMEWaitQueue(pAd);
	RTUSBCleanUpMLMEBulkOutQueue(pAd);
	// Set all state machines back IDLE
	pAd->Mlme.CntlMachine.CurrState    = CNTL_IDLE;
	pAd->Mlme.AssocMachine.CurrState   = ASSOC_IDLE;
	pAd->Mlme.AuthMachine.CurrState    = AUTH_REQ_IDLE;
	pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
	pAd->Mlme.SyncMachine.CurrState    = SYNC_IDLE;
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);//steven:for test
	DBGPRINT(RT_DEBUG_TRACE, "<==MlmeSuspend\n");
}
VOID	MlmeResume(
    IN	PRT2570ADAPTER	pAd)
{
    DBGPRINT(RT_DEBUG_TRACE, "==>MlmeResume\n");
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);//steven:for test
	// Set all state machines back IDLE
	pAd->Mlme.CntlMachine.CurrState    = CNTL_IDLE;
	pAd->Mlme.AssocMachine.CurrState   = ASSOC_IDLE;
	pAd->Mlme.AuthMachine.CurrState    = AUTH_REQ_IDLE;
	pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
	pAd->Mlme.SyncMachine.CurrState    = SYNC_IDLE;
	DBGPRINT(RT_DEBUG_TRACE, "<==MlmeResume\n");
}
/*
    ==========================================================================
    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      10000  // 10 sec
VOID MlmePeriodicExec(
    IN	unsigned long data)
{
	PRT2570ADAPTER pAd = (PRT2570ADAPTER)data;
	ULONG Now32;
	// Timer need to reset every time, so using do-while loop
	do
	{
		if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) ||
			(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ||
			(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS)) ||
			(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "<---MlmePeriodicExec\n");
			break;
		}
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_PENDING))
		{
			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_PENDING);
			NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
			NdisMIndicateStatusComplete(pAd->AdapterHandle);			
			DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event B!\n");
		}
		if (pAd->PortCfg.bHardwareRadio == TRUE)
		{
			RTUSBEnqueueInternalCmd(pAd, RT_OID_CHECK_GPIO);
		}
		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "<---RADIO OFF\n");
			break;
		}
		
		if (pAd->RalinkCounters.MgmtRingFullCount >= 2)
		{
			PCmdQElmt	cmdqelmt;
			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS);
			
			NdisAcquireSpinLock(&pAd->CmdQLock);
			while (pAd->CmdQ.size > 0)
			{
				RTUSBDequeueCmd(&pAd->CmdQ, &cmdqelmt);
				if (cmdqelmt->CmdFromNdis == TRUE)
				{
					if ((cmdqelmt->command != OID_802_11_BSSID_LIST_SCAN) &&
						(cmdqelmt->command != RT_OID_802_11_BSSID) &&
						(cmdqelmt->command != OID_802_11_SSID) &&
						(cmdqelmt->command != OID_802_11_DISASSOCIATE))
					{
#if 0
						if (cmdqelmt->SetOperation)
							NdisMSetInformationComplete(pAd->AdapterHandle, NDIS_STATUS_NOT_ACCEPTED);
						else
							NdisMQueryInformationComplete(pAd->AdapterHandle, NDIS_STATUS_NOT_ACCEPTED);
#endif
					}
					if ((cmdqelmt->command != RT_OID_SINGLE_READ_MAC) &&
						(cmdqelmt->command != RT_OID_MULTI_READ_MAC) &&
						(cmdqelmt->command != RT_OID_VENDOR_READ_BBP) &&
						(cmdqelmt->command != RT_OID_USB_VENDOR_EEPROM_READ))
					{
						if (cmdqelmt->buffer != NULL)
							kfree(cmdqelmt->buffer);
					}
					kfree(cmdqelmt);
				}
				else
					cmdqelmt->InUse = FALSE;
			}
			NdisReleaseSpinLock(&pAd->CmdQLock);
			
			RTUSBEnqueueInternalCmd(pAd, RT_OID_RESET_FROM_ERROR);
			DBGPRINT_RAW(RT_DEBUG_ERROR, "<---MlmePeriodicExec (Mgmt Ring Full)\n");
			break;
		}
		pAd->RalinkCounters.MgmtRingFullCount = 0;
		if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS)) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS)))
		{
			break;//steven:for test
		}
		pAd->Mlme.PeriodicRound ++;
		RTUSBEnqueueInternalCmd(pAd, RT_OID_PERIODIC_EXECUT);
		Now32 = jiffies;
		if (INFRA_ON(pAd))
		{
			// Check for EAPOL frame sent after MIC countermeasures
			if (pAd->PortCfg.MicErrCnt >= 3)
			{
				MLME_DISASSOC_REQ_STRUCT	DisassocReq;
				
				// disassoc from current AP first
				DBGPRINT(RT_DEBUG_TRACE, "MLME - disassociate with current AP after sending second continuous EAPOL frame\n");
				DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_MIC_FAILURE);
				MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
					sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
				pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
				pAd->PortCfg.bBlockAssoc = TRUE;
			}
			else if ((pAd->PortCfg.LastBeaconRxTime + BEACON_LOST_TIME < Now32) )
			{
				DBGPRINT(RT_DEBUG_TRACE, "BEACON lost for more than %d msec, let CQI = 0\n", BEACON_LOST_TIME);
				pAd->Mlme.ChannelQuality = 0;
				
				// Lost AP, send disconnect & link down event
				RTUSBEnqueueInternalCmd(pAd, RT_OID_LINK_DOWN);
			}
			else
			{
				atomic_set(&(pAd->PortCfg.DataPacketsFromAP), 0);	
				MlmeCheckForPsmChange(pAd);
			}
		}
		else if (ADHOC_ON(pAd))
		{
			// If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState
			// to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can
			// join later.
			if ((pAd->PortCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < Now32) &&
				(pAd->MediaState == NdisMediaStateConnected))
			{
				DBGPRINT(RT_DEBUG_TRACE, "MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n");
				
				pAd->MediaState = NdisMediaStateDisconnected;
				NdisMIndicateStatus(pAd->AdapterHandle, NDIS_STATUS_MEDIA_DISCONNECT, (PVOID)NULL, 0);
				NdisMIndicateStatusComplete(pAd->AdapterHandle);
				
				// clean up previous SCAN result, add current BSS back to table if any
				BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
				pAd->PortCfg.LastScanTime = Now32;
			}
			else
			{
				// if all 11b peers leave this BSS more than 5 seconds, update Tx rate
				if ((pAd->PortCfg.Channel <= 14)	&&
					(pAd->PortCfg.MaxTxRate <= RATE_11)	&&
					(pAd->PortCfg.MaxDesiredRate > RATE_11)	&&
					((pAd->PortCfg.Last11bBeaconRxTime + 5000) < Now32))
				{
					DBGPRINT(RT_DEBUG_TRACE, "last 11B peer left, update Tx rates\n");
					
					NdisMoveMemory(pAd->PortCfg.SupportedRates, pAd->PortCfg.IbssConfig.SupportedRates, MAX_LEN_OF_SUPPORTED_RATES);
					pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen;
					RTUSBEnqueueInternalCmd(pAd, RT_OID_UPDATE_TX_RATE);
				}
			}
		}
		else
		{
			if ((pAd->PortCfg.bBlockAssoc == TRUE) && (pAd->PortCfg.LastMicErrorTime + (60 * 1000) < Now32))
			{
				pAd->PortCfg.bBlockAssoc = FALSE;
			}
			if ((pAd->PortCfg.AutoReconnect == TRUE) &&
				(pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
				(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS)) &&
				(MlmeValidateSSID(pAd) == TRUE))
			{
				if (pAd->PortCfg.BssTab.BssNr==0)
				{
					MLME_SCAN_REQ_STRUCT	   ScanReq;
					CHAR					   BroadSsid[MAX_LEN_OF_SSID];
				
					if ((pAd->PortCfg.LastScanTime + 10 * 1000) < Now32)
					{
						DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new scan\n");
	//					BroadSsid[0] = '\0';
						ScanParmFill(pAd, &ScanReq, BroadSsid, 0, BSS_ANY, SCAN_ACTIVE);
						MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
						pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
						// Reset Missed scan number
	//					pAd->PortCfg.IgnoredScanNumber = 0;
						pAd->PortCfg.LastScanTime = Now32;
					}
					else if (pAd->PortCfg.BssType == BSS_INDEP)	// Quit the forever scan when in a very clean room
						MlmeAutoReconnectLastSSID(pAd);					
				}
				else
				{
					if ((pAd->Mlme.PeriodicRound % 10) == 7)
					{
						if ((pAd->PortCfg.LastScanTime + 10 * 1000) < Now32)
						{
							//MlmeAutoScan(pAd);
							pAd->PortCfg.LastScanTime = Now32;
						}
						MlmeAutoReconnectLastSSID(pAd);
					}
					else if ((pAd->Mlme.PeriodicRound % 30) == 8)
					{
						MlmeEnqueue(pAd, 
								MLME_CNTL_STATE_MACHINE, 
								OID_802_11_BSSID_LIST_SCAN, 
								0, 
								NULL);
					}
					
				}
			}
		}
		RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
	}while(0);
	if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
	{
		RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
	}
}
// IRQL = DISPATCH_LEVEL
VOID MlmeAutoScan(
    IN PRT2570ADAPTER pAd)
{
    // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
    if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
    {
        DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto scan\n");
        // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
        // this request, because this request is initiated by driver itself.
        pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; 
        MlmeEnqueue(pAd, 
                    MLME_CNTL_STATE_MACHINE, 
                    OID_802_11_BSSID_LIST_SCAN, 
                    0, 
                    NULL);
	RTUSBUp(pAd, &pAd->mlme_semaphore);
    }
}
// IRQL = DISPATCH_LEVEL
VOID MlmeAutoRecoverNetwork(
    IN PRT2570ADAPTER pAd)
{
    // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
    if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
    {
        NDIS_802_11_SSID OidSsid;
        OidSsid.SsidLength = pAd->PortCfg.SsidLen;
        NdisMoveMemory(OidSsid.Ssid, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen);
        DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto recovering network - %s\n", pAd->PortCfg.Ssid);
        // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
        // this request, because this request is initiated by driver itself.
        pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; 
                    
        MlmeEnqueue(pAd, 
                    MLME_CNTL_STATE_MACHINE, 
                    OID_802_11_SSID, 
                    sizeof(NDIS_802_11_SSID), 
                    &OidSsid);
	RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
	//KeSetEvent(&pAd->MLMEEvent, 0, FALSE);			
    }
}
// IRQL = DISPATCH_LEVEL
VOID MlmeAutoReconnectLastSSID(
    IN PRT2570ADAPTER pAd)
{
    // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
    if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && (MlmeValidateSSID(pAd) == TRUE))
    {
        NDIS_802_11_SSID OidSsid;
        OidSsid.SsidLength = pAd->Mlme.CntlAux.SsidLen;
        NdisMoveMemory(OidSsid.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
        DBGPRINT(RT_DEBUG_TRACE, "Driver auto reconnect to last OID_802_11_SSID setting - %s\n", pAd->Mlme.CntlAux.Ssid);
		// We will only try this attemp once, therefore change the AutoReconnect flag afterwards.
        pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; 
                    
        MlmeEnqueue(pAd, 
                    MLME_CNTL_STATE_MACHINE, 
                    OID_802_11_SSID, 
                    sizeof(NDIS_802_11_SSID), 
                    &OidSsid);
	RTUSBUp(pAd, &pAd->mlme_semaphore);
    }
}
// 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 PRT2570ADAPTER pAd)
{
	NDIS_802_11_SSID OidSsid;
	ULONG	index;
	
	// Copy the SSID into local buffer
	OidSsid.SsidLength = pAd->Mlme.CntlAux.SsidLen;
	NdisMoveMemory(OidSsid.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
	// First check the zero length "ANY" SSID
	if (OidSsid.SsidLength == 0)
		return (TRUE);
	else if (OidSsid.SsidLength > NDIS_802_11_LENGTH_SSID)
		return (FALSE);
	// Check each character value
	for (index = 0; index < OidSsid.SsidLength; index++)
	{
		if (OidSsid.Ssid[index] < 0x20)
			return (FALSE);
	}
	// All checked
	return (TRUE);
}
/*
    ==========================================================================
    Description:
        This routine checks if there're other APs out there capable for
        roaming. Caller should call this routine only when Massoc=TRUE and
        channel quality is below CQI_GOOD_THRESHOLD.
        
	IRQL = DISPATCH_LEVEL
    Output:
    ==========================================================================
 */
VOID MlmeCheckForRoaming(
    IN PRT2570ADAPTER pAd,
    IN ULONG    Now32)
{
	USHORT     i;
	BSS_TABLE  *pBssTab = &pAd->PortCfg.BssTab;
	BSS_TABLE  *pRoamTab = &pAd->Mlme.CntlAux.RoamTab;
	BSS_ENTRY  *pBss;
	DBGPRINT(RT_DEBUG_TRACE, "==> MlmeCheckForRoaming\n");
	// put all roaming candidates into RoamTab, and sort in RSSI order
	BssTableInit(pRoamTab);
	for (i = 0; i < pBssTab->BssNr; i++)
	{
		pBss = &pBssTab->BssEntry[i];
		if ((pBssTab->BssEntry[i].LastBeaconRxTime + BEACON_LOST_TIME) < Now32) 
			continue;    // AP disappear
		if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
			continue;    // RSSI too weak. forget it.
		if (MAC_ADDR_EQUAL(&pBssTab->BssEntry[i].Bssid, &pAd->PortCfg.Bssid))
			continue;    // skip current AP
		if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) && (pAd->PortCfg.LastRssi + RSSI_DELTA > pBss->Rssi)) 
			continue;    // we're still okay, only AP with stronger RSSI is eligible for roaming
		// AP passing all above rules is put into roaming candidate table        
		NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY));
		pRoamTab->BssNr += 1;
	}
	if (pRoamTab->BssNr > 0)
	{
		// check CntlMachine.CurrState to avoid collision with NDIS SetOID request
		if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS)))
		{
		// tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
		// this request, because this request is initiated by driver itself, not from NDIS.
		pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; 
		pAd->RalinkCounters.PoorCQIRoamingCount ++;
		DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Roaming attempt #%d\n", pAd->RalinkCounters.PoorCQIRoamingCount);
		MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL);
		RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
		//KeSetEvent(&pAd->MLMEEvent, 0, FALSE);
		}
	}
	DBGPRINT(RT_DEBUG_TRACE, "<== MlmeCheckForRoaming\n");   
}
VOID PeriodicExec(
    IN PRT2570ADAPTER pAd)
{
    USHORT TxFailCount, TxNoRetryCnt, TxOneRetryCnt, TxMRetryCnt, TxRetryOkCount, TxOkCount, TxTotalCnt, TxPER, TxPRR = 0, TxRealOkCount;
	USHORT RxFailCnt;
    ULONG RxOkCnt, RxCnt, RxPER;
	ULONG Now32;
	ULONG OldValue;
	UCHAR UpRate, DownRate, CurrRate;
	if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) ||
		(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ||
		(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
	{
		DBGPRINT(RT_DEBUG_TRACE, "PeriodicExec not execute! (pAd->Flags=0x%08x)\n", pAd->Flags);
		return ;
	}
	AsicAdjustTxPower(pAd);
 	RTUSBMultiReadMAC(pAd, STA_CSR0, (PUCHAR)pAd->MACCounters, 22);
	OldValue = pAd->WlanCounters.FCSErrorCount.vv.LowPart;
	pAd->WlanCounters.FCSErrorCount.vv.LowPart += pAd->MACCounters[0];
	if (pAd->WlanCounters.FCSErrorCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.FCSErrorCount.vv.HighPart++;
	}
	OldValue = pAd->WlanCounters.NoRetryCount.vv.LowPart;
	pAd->WlanCounters.NoRetryCount.vv.LowPart += pAd->MACCounters[6];
	if (pAd->WlanCounters.NoRetryCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.NoRetryCount.vv.HighPart++;
	}
	OldValue = pAd->WlanCounters.RetryCount.vv.LowPart;
	pAd->WlanCounters.RetryCount.vv.LowPart += pAd->MACCounters[7];
	if (pAd->WlanCounters.RetryCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.RetryCount.vv.HighPart++;
	}
	OldValue = pAd->WlanCounters.MultipleRetryCount.vv.LowPart;
	pAd->WlanCounters.MultipleRetryCount.vv.LowPart += pAd->MACCounters[8];
	if (pAd->WlanCounters.MultipleRetryCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.MultipleRetryCount.vv.HighPart++;
	}
	OldValue = pAd->WlanCounters.FailedCount.vv.LowPart;
	pAd->WlanCounters.FailedCount.vv.LowPart += pAd->MACCounters[9];
	if (pAd->WlanCounters.FailedCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.FailedCount.vv.HighPart++;
	}
	OldValue = pAd->QACounters.RXOverFlowCount.vv.LowPart;
	pAd->QACounters.RXOverFlowCount.vv.LowPart += pAd->MACCounters[4];
	if (pAd->QACounters.RXOverFlowCount.vv.LowPart < OldValue)
	{
		pAd->QACounters.RXOverFlowCount.vv.HighPart++;
	}
    //
    // monitor TX counters change for the past period
    //
    TxFailCount = pAd->MACCounters[9];
    TxNoRetryCnt = pAd->MACCounters[6];
    TxOneRetryCnt = pAd->MACCounters[7];
    TxMRetryCnt = pAd->MACCounters[8];
	TxRetryOkCount = TxOneRetryCnt + TxMRetryCnt;
	TxOkCount = TxNoRetryCnt + TxRetryOkCount;
	TxTotalCnt = TxOkCount + TxFailCount;
	if (TxTotalCnt > 100)
	{
		pAd->ScanAllowed = FALSE;
	}
	else
	{
		pAd->ScanAllowed = TRUE;
	}
#if 1//steven:exclude CTS
	if ((pAd->PortCfg.TxRate >= RATE_FIRST_OFDM_RATE) && (pAd->PortCfg.BGProtectionInUsed))
		TxTotalCnt = TxTotalCnt / 2;
#endif
	if (TxTotalCnt > TxFailCount)
		TxRealOkCount = TxTotalCnt - TxFailCount;
	else
		TxRealOkCount = 0;
	OldValue = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart;
	pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart += TxRealOkCount;
	if (pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart < OldValue)
	{
		pAd->WlanCounters.TransmittedFragmentCount.vv.HighPart++;
	}
	AsicBbpTuning(pAd);
	if (pAd->MediaState == NdisMediaStateConnected)
	{
    if (TxTotalCnt < 5) // if too few TX samples, skip TX related statistics
    {
        TxPER = 0;  // don't take TxPER into CQI consideration if too few sample
        TxPRR = 0;
    }
    else 
    {
		if (TxFailCount < TxTotalCnt)
		{
			USHORT temp = TxOneRetryCnt + TxMRetryCnt + TxFailCount;
			TxPER = (TxFailCount * 100) / TxTotalCnt;
			if (temp < TxTotalCnt)
				TxPRR = (temp * 100) / TxTotalCnt;
			else
				TxPRR = 100;
		}
		else
			TxPER = 100;
    }
    //
    // calculate RX PER
    //
	RxFailCnt = pAd->MACCounters[0];
    RxOkCnt   = pAd->WlanCounters.ReceivedFragmentCount.vv.LowPart - 
                pAd->Mlme.PrevWlanCounters.ReceivedFragmentCount.vv.LowPart;
    RxCnt = RxOkCnt + RxFailCnt;
    if (RxCnt < 5)
        RxPER = 0;  // don't take RxPER into ChannelQuality consideration if too few sample
    else
        RxPER = (RxFailCnt * 100) / RxCnt;
	if ((ADHOC_ON(pAd)) && (pAd->MediaState == NdisMediaStateConnected))
	{
		pAd->SentBeaconsCount += pAd->MACCounters[5];
		pAd->ReceivedBeaconsCount += pAd->MACCounters[10];
		if ((pAd->Mlme.PeriodicRound % 2) == 1)
		{
			TXRX_CSR18_STRUC Csr18;
			USHORT temp;
			DBGPRINT(RT_DEBUG_INFO, "SentBeaconsCount = %d ReceivedBeaconsCount = %d\n", pAd->SentBeaconsCount, pAd->ReceivedBeaconsCount);
			if (pAd->BeaconIntervalChangeAllowed == TRUE)
			{
				if (2 * pAd->SentBeaconsCount > pAd->ReceivedBeaconsCount)
				{
					temp = (pAd->PortCfg.BeaconPeriod << 8) + 1;
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				else if (pAd->ReceivedBeaconsCount > 9 * pAd->SentBeaconsCount)
				{
					temp = (pAd->PortCfg.BeaconPeriod << 8) - 5;
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
				else if (pAd->ReceivedBeaconsCount > 3 * pAd->SentBeaconsCount)
				{
					temp = (pAd->PortCfg.BeaconPeriod << 8) - 1;
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
#if 0
				else if (pAd->ReceivedBeaconsCount > 2 * pAd->SentBeaconsCount)
				{
					temp = (pAd->PortCfg.BeaconPeriod << 8) - 1;
					Csr18.field.Offset = (temp & 0x000F);
					Csr18.field.Interval = (temp >> 6);
					RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
					DBGPRINT_RAW(RT_DEBUG_TRACE, ("TXRX_CSR18 = 0x%x\n", Csr18.value));
					
					pAd->BeaconIntervalChangeAllowed = FALSE;
				}
#endif
			}
#if 0
			else if (pAd->ReceivedBeaconsCount > 9 * pAd->SentBeaconsCount)
			{
				DBGPRINT_RAW(RT_DEBUG_TRACE, ("Do Nothing\n"));
			}
#endif
			else
			{
				temp = (pAd->PortCfg.BeaconPeriod << 8);
				Csr18.field.Offset = (temp & 0x000F);
				Csr18.field.Interval = (temp >> 6);
				RTUSBWriteMACRegister(pAd, TXRX_CSR18, Csr18.value);
				DBGPRINT_RAW(RT_DEBUG_INFO, "TXRX_CSR18 = 0x%x\n", Csr18.value);
				
				pAd->BeaconIntervalChangeAllowed = TRUE;
			}
			
			pAd->SentBeaconsCount = 0;
			pAd->ReceivedBeaconsCount = 0;
		}
	}
	Now32 = jiffies;
	{
	    // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER    (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
	    pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * pAd->PortCfg.LastRssi + 
	                         TX_WEIGHTING * (100 - TxPRR) + 
	                         RX_WEIGHTING* (100 - RxPER)) / 100;
	    if (pAd->Mlme.ChannelQuality >= 100)
	        pAd->Mlme.ChannelQuality = 100;
	}
    
    DBGPRINT(RT_DEBUG_INFO, "MMCHK - CQI= %d, (Tx Fail=%d/Retry=%d/Total=%d, Rx Fail=%d/Total=%d, RSSI=%d dbm)\n", 
        pAd->Mlme.ChannelQuality, TxFailCount, TxRetryOkCount, TxTotalCnt, RxFailCnt, RxCnt, pAd->PortCfg.LastRssi - pAd->BBPTuningParameters.RSSIToDbmOffset);
    // latch current WLAN counters for next check-for-roaming usage
    NdisMoveMemory(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11));
#if 1//steven:move this from MlmePeriodicExec
	if (INFRA_ON(pAd))
	{
		if (CQI_IS_BAD(pAd->Mlme.ChannelQuality))
		{
			pAd->RalinkCounters.BadCQIAutoRecoveryCount ++;
           	DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Bad CQI. Auto Recovery attempt #%d\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount);
			MlmeAutoRecoverNetwork(pAd);
		}
		else if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) || CQI_IS_POOR(pAd->Mlme.ChannelQuality))
		{
			// perform aggresive roaming only when SECURITY OFF or WEP64/128;
			// WPA and WPA-PSK has no aggresive roaming because re-negotiation
			// between 802.1x supplicant and authenticator/AAA server is required
			// but can't be guaranteed.
			if (pAd->PortCfg.AuthMode < Ndis802_11AuthModeWPA)
				MlmeCheckForRoaming(pAd, Now32);
		}
	}
#endif
	pAd->PortCfg.CurrTxRateStableTime++;
	CurrRate = pAd->PortCfg.TxRate;
    do
    {
		USHORT TxErrorRatio;
		BOOLEAN fUpgradeQuality = FALSE;
		USHORT  *pRateUpPER, *pRateDownPER;
        if (pAd->PortCfg.EnableAutoRateSwitching == FALSE)
            break;
            
        // do nothing if no traffic in the past period
        if (TxTotalCnt == 0)
        {
            // TxRateUpPenalty maybe too large, we don't want this penalty to affect
            // next Chariot throughput test too much therefore zero it here.
            pAd->PortCfg.TxRateUpPenalty = 0;
            NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
            NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
            break;
        }
        // decide the next upgrade rate and downgrade rate, if any
        if (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)
        {
            UpRate = Phy11BGNextRateUpward[CurrRate];
            DownRate = Phy11BGNextRateDownward[CurrRate];
        }
        else if (pAd->PortCfg.PhyMode == PHY_11B)
        {
            UpRate = Phy11BNextRateUpward[CurrRate];
            DownRate = Phy11BNextRateDownward[CurrRate];
        }
        else if (pAd->PortCfg.PhyMode == PHY_11A)
        {
            UpRate = Phy11ANextRateUpward[CurrRate];
            DownRate = Phy11ANextRateDownward[CurrRate];
        }
        else // PHY_11ABG_MIXED
        {
            if (pAd->PortCfg.Channel > 14)  
            {
                UpRate = Phy11ANextRateUpward[CurrRate];
                DownRate = Phy11ANextRateDownward[CurrRate];
            }
            else
            {
                UpRate = Phy11BGNextRateUpward[CurrRate];
                DownRate = Phy11BGNextRateDownward[CurrRate];
            }
        }
        if (UpRate > pAd->PortCfg.MaxTxRate)
            UpRate = pAd->PortCfg.MaxTxRate;
    
        // decide TX quality based on Tx retry ratio when enough samples are available
        if (TxTotalCnt > 15)
        {
			USHORT temp = TxRetryOkCount + TxFailCount;
			if (temp < TxTotalCnt)
				TxErrorRatio = (temp *100) / TxTotalCnt;
			else
				TxErrorRatio = 100;
			pRateUpPER = &NewRateUpPER[0];
			pRateDownPER = &NewRateDownPER[0];
            // downgrade TX quality if retry+error ratio reached
            if (TxErrorRatio >= pRateDownPER[CurrRate])
            {
                pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
            }
            // upgrade TX quality if retry+error ratio reached
            else if (TxErrorRatio <= pRateUpPER[CurrRate])
            {
                fUpgradeQuality = TRUE;
                if (pAd->DrsCounters.TxQuality[CurrRate])
                    pAd->DrsCounters.TxQuality[CurrRate] --;  // quality very good in CurrRate
                    
                if (pAd->PortCfg.TxRateUpPenalty)
                    pAd->PortCfg.TxRateUpPenalty --;
                else if (pAd->DrsCounters.TxQuality[UpRate])
                    pAd->DrsCounters.TxQuality[UpRate] --;    // may improve next UP rate's quality
            }
            
        }
        
        // if not enough TX samples, decide by heuristic rules
        else
        {
            TxErrorRatio = 0;
            
            // Downgrade TX quality upon -
            // 1. any TX failure in the past second
            // 2. TX retry ratio too high when enough TX samples are available
            if (TxFailCount)
            {
                if ((TxFailCount <= 1) &&
                    (TxRealOkCount + TxRetryOkCount))
                {
                    pAd->DrsCounters.TxQuality[CurrRate] += 2;   // degrade quality
                    if (pAd->DrsCounters.TxQuality[CurrRate] > DRS_TX_QUALITY_WORST_BOUND)
                        pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
                }
                else // more than 2 failure, or no TX ok cases
                {
                    pAd->DrsCounters.TxQuality[CurrRate]  = DRS_TX_QUALITY_WORST_BOUND;   // quality bad
                }
            }
            // upgrade TX quality if -
            // 1. no TX failure but do have TX ok case, and
            // 2. there's more one-time-ok cases than retry-ok cases in the past second
            // 3. current rate's Tx retry ratio <= 10%
            else if ((TxRealOkCount > TxRetryOkCount))
            {
                fUpgradeQuality = TRUE;
                if (pAd->DrsCounters.TxQuality[CurrRate])
                    pAd->DrsCounters.TxQuality[CurrRate] --;  // quality very good in CurrRate
                if (pAd->PortCfg.TxRateUpPenalty)
                    pAd->PortCfg.TxRateUpPenalty --;
                else if (pAd->DrsCounters.TxQuality[UpRate])
                    pAd->DrsCounters.TxQuality[UpRate] --;    // may improve next UP rate's quality
            }
        }
        pAd->DrsCounters.PER[CurrRate] = (UCHAR)TxErrorRatio;
        if (pAd->DrsCounters.fNoisyEnvironment)
        {
            DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS(noisy):"); 
        }
        else
        {
            DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS:"); 
        }
        DBGPRINT_RAW(RT_DEBUG_TRACE,"Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n", 
            RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
            TxErrorRatio,
            pAd->DrsCounters.CurrTxRateStableTime,
            RateIdToMbps[UpRate], pAd->DrsCounters.TxQuality[UpRate],
            pAd->DrsCounters.TxRateUpPenalty);
        
        // 2004-3-13 special case: Claim noisy environment
        //   decide if there was a false "rate down" in the past 2 sec due to noisy 
        //   environment. if so, we would rather switch back to the higher TX rate. 
        //   criteria -
        //     1. there's a higher rate available, AND
        //     2. there was a rate-down happened, AND
        //     3. current rate has 75% > PER > 25%, AND
        //     4. comparing to UpRate, current rate didn't improve PER more than 5 %
        if ((UpRate != CurrRate)                              &&
            (pAd->DrsCounters.LastSecTxRateChangeAction == 2) &&
            (((pAd->DrsCounters.PER[CurrRate] > 20) || (pAd->DrsCounters.fNoisyEnvironment)) && 
			(pAd->DrsCounters.PER[CurrRate] < 75)) && 
            ((pAd->DrsCounters.PER[CurrRate]+5) > pAd->DrsCounters.PER[UpRate]))
        {
            // we believe this is a noisy environment. better stay at UpRate
            DBGPRINT(RT_DEBUG_TRACE,"DRS: #### enter Noisy environment ####\n");
            pAd->DrsCounters.fNoisyEnvironment = TRUE;
            // 2004-3-14 when claiming noisy environment, we're not only switch back
            //   to UpRate, but can be more aggressive to use one more rate up
            UpRate++;
//          if (UpRate>RATE_54) UpRate=RATE_54;
            if ((UpRate==RATE_6) || (UpRate==RATE_9)) UpRate=RATE_12;
            if (UpRate > pAd->PortCfg.MaxTxRate)
                UpRate = pAd->PortCfg.MaxTxRate;
            pAd->PortCfg.TxRate = UpRate;
            break;
        }
        // 2004-3-12 special case: Leave noisy environment
        //   The interference has gone suddenly. reset TX rate to
        //   the theoritical value according to RSSI. Criteria -
        //     1. it's currently in noisy environment
        //     2. PER drops to be below 12%
        if ((pAd->DrsCounters.fNoisyEnvironment == TRUE) &&
            (TxTotalCnt > 15) && (pAd->DrsCounters.PER[CurrRate] <= 12))
        {
            UCHAR JumpUpRate;
            pAd->DrsCounters.fNoisyEnvironment = FALSE;
            for (JumpUpRate = RATE_54; JumpUpRate > RATE_1; JumpUpRate--)
            {
                if (pAd->PortCfg.AvgRssi > (RssiSafeLevelForTxRate[JumpUpRate] + pAd->BBPTuningParameters.RSSIToDbmOffset))
                    break;
            }
            if (JumpUpRate > pAd->PortCfg.MaxTxRate)
                JumpUpRate = pAd->PortCfg.MaxTxRate;
            
            DBGPRINT(RT_DEBUG_TRACE,"DRS: #### leave Noisy environment ####, RSSI=%d, JumpUpRate=%d\n",
                pAd->PortCfg.AvgRssi - pAd->BBPTuningParameters.RSSIToDbmOffset, RateIdToMbps[JumpUpRate]);
            
            if (JumpUpRate > CurrRate)
            {
                pAd->PortCfg.TxRate = JumpUpRate;
               	break;
            }
        }
        
        // perform DRS - consider TxRate Down first, then rate up.
        //     1. rate down, if current TX rate's quality is not good
        //     2. rate up, if UPRate's quality is very good
        if ((pAd->DrsCounters.TxQuality[CurrRate] >= DRS_TX_QUALITY_WORST_BOUND) &&
            (CurrRate != DownRate))
        {
			pAd->PortCfg.TxRate = DownRate;
        }
        else if ((pAd->DrsCounters.TxQuality[CurrRate] <= 0) && 
            (pAd->DrsCounters.TxQuality[UpRate] <=0)         &&
            (CurrRate != UpRate))
        {
            pAd->PortCfg.TxRate = UpRate;
        }
    }while (FALSE);
    // if rate-up happen, clear all bad history of all TX rates
    if (pAd->PortCfg.TxRate > CurrRate)
    {
       	DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
        pAd->DrsCounters.CurrTxRateStableTime = 0;
        pAd->DrsCounters.TxRateUpPenalty = 0;
        pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
        NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
        NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
    }
    // if rate-down happen, only clear DownRate's bad history
    else if (pAd->PortCfg.TxRate < CurrRate)
    {
       	DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
	    // shorter stable time require more penalty in next rate UP criteria
       	if (pAd->DrsCounters.CurrTxRateStableTime < 4)      // less then 4 sec
       	    pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
       	else if (pAd->DrsCounters.CurrTxRateStableTime < 8) // less then 8 sec
       	    pAd->DrsCounters.TxRateUpPenalty = 2;           // add 2 sec penalty
       	else                                                // >= 8 sec
       	    pAd->DrsCounters.TxRateUpPenalty = 0;           // no penalty
       	    
        pAd->DrsCounters.CurrTxRateStableTime = 0;
        pAd->DrsCounters.LastSecTxRateChangeAction = 2; // rate DOWN
       	pAd->DrsCounters.TxQuality[pAd->PortCfg.TxRate] = 0;
       	pAd->DrsCounters.PER[pAd->PortCfg.TxRate] = 0;
    }
    else
        pAd->DrsCounters.LastSecTxRateChangeAction = 0; // rate no change
	}
}
/*
    ==========================================================================
    Description:
        This routine is executed periodically inside MlmePeriodicExec() after 
        association with an AP.
        It checks if PortCfg.Psm is consistent with user policy (recorded in
        PortCfg.WindowsPowerMode). If not, enforce user policy. However, 
        there're some conditions to consider:
        1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
           the time when Mibss==TRUE
        2. When Massoc==TRUE (INFRA mode), Psm should not be switch to PWR_SAVE
           if outgoing traffic available in TxRing or PrioRing.
    Output:
        1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched
        
	IRQL = DISPATCH_LEVEL
    ==========================================================================
 */
VOID MlmeCheckForPsmChange(
    IN PRT2570ADAPTER pAd)
{
	ULONG	PowerMode;
    // condition -
    // 1. Psm maybe ON only happen in INFRASTRUCTURE mode
    // 2. user wants either MAX_PSP or FAST_PSP
    // 3. but current psm is not in PWR_SAVE
    // 4. CNTL state machine is not doing SCANning
    // 5. no TX SUCCESS event for the past period
    	PowerMode = pAd->PortCfg.WindowsPowerMode;
    
    if (INFRA_ON(pAd) &&
        (PowerMode != Ndis802_11PowerModeCAM) &&
		(pAd->BulkOutPending == FALSE) &&
		(LOCAL_TX_RING_EMPTY(pAd)) &&
		(pAd->SendTxWaitQueue.Number == 0) &&
        (pAd->PortCfg.Psm == PWR_ACTIVE) &&
        (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
        (pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart == pAd->Mlme.PrevTxCnt))
    {
		RTUSBEnqueueInternalCmd(pAd, RT_OID_SET_PSM_BIT_SAVE);
    }
    
    // latch current count for next-time comparison
    pAd->Mlme.PrevTxCnt = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart;
}
// IRQL = PASSIVE_LEVEL
// IRQL = DISPATCH_LEVEL
VOID MlmeSetPsmBit(
    IN PRT2570ADAPTER pAd, 
    IN USHORT psm)
{
    pAd->PortCfg.Psm = psm;    
    
    DBGPRINT(RT_DEBUG_TEMP, "MMCHK - change PSM bit to %d <<<\n", psm);
}
// IRQL = DISPATCH_LEVEL
// IRQL = DISPATCH_LEVEL
VOID MlmeSetTxPreamble(
    IN PRT2570ADAPTER pAd, 
    IN USHORT TxPreamble)
{
	USHORT	value;
    RTUSBReadMACRegister(pAd, TXRX_CSR10, &value);
    if (TxPreamble == Rt802_11PreambleShort)
    {
        DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= SHORT PREAMBLE)\n");
		value |= 0x0004;
        pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleShort;
    }
    else
    {
        DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= LONG PREAMBLE)\n");
		value &= 0xFFFB;
        pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleLong;
    }
    RTUSBWriteMACRegister(pAd, TXRX_CSR10, value);
}
    
// 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 PRT2570ADAPTER pAd,
    IN BOOLEAN		 bLinkUp)
{
    int i, num;
    UCHAR Rate, MaxDesire = RATE_1, MaxSupport = RATE_1;
    USHORT BasicRateBitmap = 0;
    UCHAR CurrBasicRate = RATE_1;
    // find max desired rate
    num = 0;
    for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
    {
        switch (pAd->PortCfg.DesiredRates[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;
		// Fixed the Maximum rate of 2426 to b only
		if (pAd->PortCfg.RfType == RFIC_2426)
			if (MaxDesire > RATE_11)
				MaxDesire = RATE_11;
    }
    // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
    if ((pAd->PortCfg.BssType == BSS_INDEP)        &&
        (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)   && 
        (pAd->PortCfg.AdhocMode == 0) &&
        (MaxDesire > RATE_11))
        MaxDesire = RATE_11;
    
    pAd->PortCfg.MaxDesiredRate = MaxDesire;
    
    // Auto rate switching is enabled only if more than one DESIRED RATES are 
    // specified; otherwise disabled
    if (num <= 1)
        pAd->PortCfg.EnableAutoRateSwitching = FALSE;
    else
        pAd->PortCfg.EnableAutoRateSwitching = TRUE;
    // find max supported rate
    for (i=0; i<pAd->PortCfg.SupportedRatesLen; i++)
    {
        switch (pAd->PortCfg.SupportedRates[i] & 0x7f)
        {
            case 2: Rate = RATE_1;   
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0001;  
                    break;
            case 4: Rate = RATE_2;   
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0002;  
                    break;
            case 11: 
                    Rate = RATE_5_5; 
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0004;  
                    break;
            case 22: 
                    Rate = RATE_11;  
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0008;  
                    break;
            case 12: 
                    Rate = RATE_6;   
//                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0010;  
                    break;
            case 18: 
                    Rate = RATE_9;   
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0020;  
                    break;
            case 24: 
                    Rate = RATE_12;  
//                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0040;  
                    break;
            case 36: 
                    Rate = RATE_18;  
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0080;  
                    break;
            case 48: 
                    Rate = RATE_24;  
//                  if (pAd->PortCfg.SupportedRates[i] & 0x80) 
						BasicRateBitmap |= 0x0100;  
                    break;
            case 72: 
                    Rate = RATE_36;  
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0200;  
                    break;
            case 96: 
                    Rate = RATE_48;  
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0400;  
                    break;
            case 108: 
                    Rate = RATE_54; 
                    if (pAd->PortCfg.SupportedRates[i] & 0x80) 
                        BasicRateBitmap |= 0x0800;  
                    break;
            default:  
                    Rate = RATE_1;   
                    break;
        }
        if (MaxSupport < Rate)  MaxSupport = Rate;
    }
	// Limit the max support rate and basic rate map to 11b only
	if (pAd->PortCfg.RfType == RFIC_2426)
	{
		if (MaxSupport > RATE_11)
		{
			MaxSupport = RATE_11;
			BasicRateBitmap &= 0x000f;
		}
	}
	
	RTUSBWriteMACRegister(pAd, TXRX_CSR11, BasicRateBitmap);
    // calculate the exptected ACK rate for each TX rate. This info is used to caculate
    // the DURATION field of outgoing uniicast DATA/MGMT frame
    for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
    {
        if (BasicRateBitmap & (0x01 << i))
            CurrBasicRate = (UCHAR)i;
        pAd->PortCfg.ExpectedACKRate[i] = CurrBasicRate;
        DBGPRINT(RT_DEBUG_INFO,"Exptected ACK rate[%d] = %d Mbps\n", RateIdToMbps[i], RateIdToMbps[CurrBasicRate]);
    }
    // max tx rate = min {max desire rate, max supported rate}
    if (MaxSupport < MaxDesire)
        pAd->PortCfg.MaxTxRate = MaxSupport;
    else
        pAd->PortCfg.MaxTxRate = MaxDesire;
    // 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
    if (pAd->PortCfg.EnableAutoRateSwitching)
    {
        if (pAd->PortCfg.Channel > 14)
            pAd->PortCfg.TxRate = RATE_6; // 802.11a
        else 
		{
			int dbm = pAd->PortCfg.AvgRssi - pAd->BBPTuningParameters.RSSIToDbmOffset;
			if (dbm > -70)
			{
				pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
			}
			else if (dbm > -75)
			{
				pAd->PortCfg.TxRate = min((INT)(pAd->PortCfg.MaxTxRate), RATE_36);
			}
			else
			{
				pAd->PortCfg.TxRate = min((INT)(pAd->PortCfg.MaxTxRate), RATE_11);
			}
		}
    }
    else
        pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
    switch (pAd->PortCfg.PhyMode) {
        case PHY_11BG_MIXED:
        case PHY_11B:
            pAd->PortCfg.MlmeRate = RATE_2;
#ifdef	WIFI_TEST			
            pAd->PortCfg.RtsRate = RATE_11;
#else
            pAd->PortCfg.RtsRate = RATE_2;
#endif
            break;
        case PHY_11A:
            pAd->PortCfg.MlmeRate = RATE_6;
            pAd->PortCfg.RtsRate = RATE_6;
            break;
        case PHY_11ABG_MIXED:
            if (pAd->PortCfg.Channel <= 14)
            {
                pAd->PortCfg.MlmeRate = RATE_2;
                pAd->PortCfg.RtsRate = RATE_2;
            }
            else
            {
                pAd->PortCfg.MlmeRate = RATE_6;
                pAd->PortCfg.RtsRate = RATE_6;
            }
            break;
        default: // error
            pAd->PortCfg.MlmeRate = RATE_2;
            pAd->PortCfg.RtsRate = RATE_2;
            break;
    }
    
    DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, Rate Switching =%d)\n", 
             RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->PortCfg.MaxTxRate], pAd->PortCfg.EnableAutoRateSwitching);
    DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04x)\n", 
             RateIdToMbps[pAd->PortCfg.TxRate], RateIdToMbps[pAd->PortCfg.RtsRate], BasicRateBitmap);
}
// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOff(
    IN PRT2570ADAPTER pAd)
{
	MLME_DISASSOC_REQ_STRUCT DisReq;
	MLME_QUEUE_ELEM          MsgElem;
	UINT	i = 0;
	//
	// Since set flag fRTMP_ADAPTER_RADIO_OFF will diable RTUSBKickBulkOut function.
	// So before set flag fRTMP_ADAPTER_RADIO_OFF, 
	// we should send a disassoc frame to our AP if neend.
	//
	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS))
	{
		if (INFRA_ON(pAd)) 
		{
			COPY_MAC_ADDR(&DisReq.Addr, &pAd->PortCfg.Bssid);
			DisReq.Reason =  REASON_DISASSOC_STA_LEAVING;
			MsgElem.Machine = ASSOC_STATE_MACHINE;
			MsgElem.MsgType = MT2_MLME_DISASSOC_REQ;
			MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
			NdisMoveMemory(MsgElem.Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));
			MlmeDisassocReqAction(pAd, &MsgElem);
			NdisMSleep(1);
		}
		// Set Radio off flag will turn off RTUSBKickBulkOut function
		RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
        	DBGPRINT(RT_DEBUG_ERROR, "3Set fRTMP_ADAPTER_RADIO_OFF ");
	
		LinkDown(pAd);
	}
	else
	{
		// Set Radio off flag will turn off RTUSBKickBulkOut function
		RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
        	DBGPRINT(RT_DEBUG_ERROR, "4Set fRTMP_ADAPTER_RADIO_OFF ");
	}	
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  MlmeRadioOff \n" );
	RTUSBRejectPendingPackets(pAd);//reject all NDIS packets waiting in TX queue
	RTUSBCleanUpDataBulkOutQueue(pAd);
	MlmeSuspend(pAd);
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  2MlmeRadioOff \n" );
	// Abort Tx
	// Disable Rx
	RTUSBWriteMACRegister(pAd, TXRX_CSR2, 1);
	//Ask our device to complete any pending bulk in IRP.
	while (( atomic_read(&pAd->PendingRx) > 0) || (pAd->BulkOutPending == TRUE))
	{
		if (atomic_read(&pAd->PendingRx) > 0)
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkIn IRP Pending!!!\n");
			RTUSB_VendorRequest(pAd,
				0,
				DEVICE_VENDOR_REQUEST_OUT,
				0x0C,
				0x0,
				0x0,
				NULL,
				0);
		}
		
		if (pAd->BulkOutPending == TRUE)
		{
			DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkOut IRP Pending!!!\n");
			if (i == 0)
			{
				RTUSBCancelPendingBulkOutIRP(pAd);
				i++;
			}
		}
		
		NdisMSleep(5);
	}
#if 1
	// Turn off radio
	RTUSBWriteMACRegister(pAd, MAC_CSR13, 0x2121);
	RTUSBWriteMACRegister(pAd, MAC_CSR14, 0x2121);
	if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
	{
		RTUSBWriteMACRegister(pAd, MAC_CSR20, 0x0001); 		
	}
	
	// Clean up old bss table
	BssTableInit(&pAd->PortCfg.BssTab);
	DBGPRINT_RAW(RT_DEBUG_TEMP,"  <==MlmeRadioOff \n" );
#endif
}
// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOn(
    IN PRT2570ADAPTER pAd)
{	
	// Turn on radio
	RTUSBWriteMACRegister(pAd, MAC_CSR13, 0x3100);
	RTUSBWriteMACRegister(pAd, MAC_CSR14, 0x3f3b);
	// Abort Tx
	//steven:don't have this	RTMP_IO_WRITE32(pAd, TXCSR0, 0x08);
	// Disable Rx
	RTUSBWriteMACRegister(pAd, TXRX_CSR2, 1);
	NICResetFromError(pAd);
	// Clear Radio off flag
	RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
	MlmeResume(pAd);
	RTUSBBulkReceive(pAd);
	RTUSBWriteMACRegister(pAd, TXRX_CSR2, 0x7e);
	if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
	{
		RTUSBWriteMACRegister(pAd, MAC_CSR20, 0x0003);
	}
}
// ===========================================================================================
// 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;
    for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) 
    {
        NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
    }
}
/*! \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 PMACADDR Bssid) 
{
    UCHAR i;
    
    for (i = 0; i < Tab->BssNr; i++) 
    {
        //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
        if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid)) 
        { 
            return i;
        }
    }
    return (ULONG)BSS_NOT_FOUND;
}
// IRQL = DISPATCH_LEVEL
VOID BssTableDeleteEntry(
    IN OUT	BSS_TABLE *Tab, 
    IN		PMACADDR Bssid) 
{
    UCHAR i, j;
    
    for (i = 0; i < Tab->BssNr; i++) 
    {
        //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
        if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid)) 
        {
        	for (j = i; j < Tab->BssNr - 1; j++)
        	{
        		NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
        	}
	        Tab->BssNr -= 1;
            return;
        }
    }
}
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};
/*! \brief
 *  \param 
 *  \return
 *  \pre
 *  \post
	 
 IRQL = DISPATCH_LEVEL
 
 */
VOID BssEntrySet(
    IN	PRT2570ADAPTER	pAd, 
    OUT BSS_ENTRY *pBss, 
    IN MACADDR *pBssid, 
    IN CHAR Ssid[], 
    IN UCHAR SsidLen, 
    IN UCHAR BssType, 
    IN USHORT BeaconPeriod, 
    IN BOOLEAN CfExist,
    IN CF_PARM *pCfParm, 
    IN USHORT AtimWin, 
    IN USHORT CapabilityInfo, 
    IN UCHAR Rates[], 
    IN UCHAR RatesLen,
    IN BOOLEAN ExtendedRateIeExist,
    IN UCHAR Channel,
    IN UCHAR Rssi,
    IN LARGE_INTEGER TimeStamp,
    IN UCHAR 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)
		{
    		NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
    		pBss->SsidLen = SsidLen;
			pBss->Hidden = 0;
		}
	}
    pBss->BssType = BssType;
    pBss->BeaconPeriod = BeaconPeriod;
    if (BssType == BSS_INFRA) 
    {
        if (CfExist) 
        {
            pBss->CfpCount = pCfParm->CfpCount;
            pBss->CfpPeriod = pCfParm->CfpPeriod;
            pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
            pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
        }
    } 
    else 
    {
        pBss->AtimWin = AtimWin;
    }
    pBss->CapabilityInfo = CapabilityInfo;
	// The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
	// Combine with AuthMode, they will decide the connection methods.
    pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
    NdisMoveMemory(pBss->Rates, Rates, RatesLen);
    pBss->RatesLen = RatesLen;
    pBss->ExtendedRateIeExist = ExtendedRateIeExist;
    pBss->Channel = Channel;
    pBss->Rssi = Rssi;
	// 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);
		BssCipherParse(pBss);
	}
	else
	{
		pBss->VarIELen = 0;
		// No SSN ID, if security is on, this is WEP algorithm
		if  (pBss->Privacy)
			pBss->WepStatus = Ndis802_11WEPEnabled;
		// No SSN ID, security is also off.
		else
			pBss->WepStatus = Ndis802_11WEPDisabled;
	}
}
/*! 
 *  \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	PRT2570ADAPTER	pAd, 
    OUT BSS_TABLE *Tab, 
    IN MACADDR *Bssid, 
    IN CHAR Ssid[], 
    IN UCHAR SsidLen, 
    IN UCHAR BssType, 
    IN USHORT BeaconPeriod, 
    IN BOOLEAN CfExist, 
    IN CF_PARM *CfParm, 
    IN USHORT AtimWin, 
    IN USHORT CapabilityInfo, 
    IN UCHAR Rates[],
    IN UCHAR RatesLen,
    IN BOOLEAN ExtendedRateIeExist,
    IN UCHAR ChannelNo,
    IN UCHAR Rssi,
    IN LARGE_INTEGER TimeStamp,
    IN UCHAR LengthVIE,
    IN PNDIS_802_11_VARIABLE_IEs pVIE)
{
    ULONG   Idx;
    Idx = BssTableSearch(Tab, Bssid);
    if (Idx == BSS_NOT_FOUND) 
    {
        if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE)
            return BSS_NOT_FOUND;
        Idx = Tab->BssNr;
        BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
                    CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
                    ChannelNo, Rssi, TimeStamp, LengthVIE, pVIE);
        Tab->BssNr++;
    } 
    else
    {
        BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
                    CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
                    ChannelNo, Rssi, TimeStamp, LengthVIE, pVIE);
    }
	//DBGPRINT_RAW(RT_DEBUG_TEMP," %s   Wep %d auth %d \n",Ssid, Tab->BssEntry[Idx].WepStatus, Tab->BssEntry[Idx].AuthMode);
    
    return Idx;
}
// IRQL = DISPATCH_LEVEL
VOID BssTableSsidSort(
    IN	PRT2570ADAPTER	pAd, 
    OUT BSS_TABLE *OutTab, 
    IN  CHAR Ssid[], 
    IN  UCHAR SsidLen) 
{
    INT i;
    
    BssTableInit(OutTab);
    for (i = 0; i < pAd->PortCfg.BssTab.BssNr; i++) 
    {
        BSS_ENTRY *pInBss = &pAd->PortCfg.BssTab.BssEntry[i];
        
        if ((pInBss->BssType == pAd->PortCfg.BssType) && 
			((pInBss->SsidLen==SsidLen) && RTMPEqualMemory(pInBss->Ssid, Ssid, (ULONG) SsidLen)))
        {
            BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
			// New for WPA2
			// Check the Authmode first
			if (pAd->PortCfg.AuthMode >= Ndis802_11AuthModeWPA)
			{
				// Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
				if ((pAd->PortCfg.AuthMode != pInBss->AuthMode) && (pAd->PortCfg.AuthMode != pInBss->AuthModeAux))
					// None matched
					continue;
				
				// Check cipher suite, AP must have more secured cipher than station setting
				if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
				{
					// If it's not mixed mode, we should only let BSS pass with the same encryption
					if (pInBss->WPA.bMixMode == FALSE)
						if (pAd->PortCfg.WepStatus != pInBss->WPA.GroupCipher)
							continue;						
				
					// check group cipher
					if (pAd->PortCfg.WepStatus < pInBss->WPA.GroupCipher)
						continue;
					// check pairwise cipher, skip if none matched
					// If profile set to AES, let it pass without question.
					// If profile set to TKIP, we must find one mateched
					if ((pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA.PairCipher) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA.PairCipherAux))
						continue;						
				}
				else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
				{
					// If it's not mixed mode, we should only let BSS pass with the same encryption
					if (pInBss->WPA2.bMixMode == FALSE)
						if (pAd->PortCfg.WepStatus != pInBss->WPA2.GroupCipher)
							continue;						
				
					// check group cipher
					if (pAd->PortCfg.WepStatus < pInBss->WPA2.GroupCipher)
						continue;
					// check pairwise cipher, skip if none matched
					// If profile set to AES, let it pass without question.
					// If profile set to TKIP, we must find one mateched
					if ((pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA2.PairCipher) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA2.PairCipherAux))
						continue;						
				}
			}			
			// Bss Type matched, SSID matched. 
			// We will check wepstatus for qualification Bss
			else if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
					continue;
			
			// Since the AP is using hidden SSID, and we are trying to connect to ANY
			// It definitely will fail. So, skip it.
			// CCX also require not even try to connect it!!
			if (SsidLen == 0)
				continue;
			
            // copy matching BSS from InTab to OutTab
            NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
            
            OutTab->BssNr++;
        }
        else if ((pInBss->BssType == pAd->PortCfg.BssType) && (SsidLen == 0))
        {
            BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
			// New for WPA2
			// Check the Authmode first
			if (pAd->PortCfg.AuthMode >= Ndis802_11AuthModeWPA)
			{
				// Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
				if ((pAd->PortCfg.AuthMode != pInBss->AuthMode) && (pAd->PortCfg.AuthMode != pInBss->AuthModeAux))
					// None matched
					continue;
			
				// Check cipher suite, AP must have more secured cipher than station setting
				if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
				{
					// If it's not mixed mode, we should only let BSS pass with the same encryption
					if (pInBss->WPA.bMixMode == FALSE)
						if (pAd->PortCfg.WepStatus != pInBss->WPA.GroupCipher)
							continue;						
				
					// check group cipher
					if (pAd->PortCfg.WepStatus < pInBss->WPA.GroupCipher)
						continue;
            
					// check pairwise cipher, skip if none matched
					// If profile set to AES, let it pass without question.
					// If profile set to TKIP, we must find one mateched
					if ((pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA.PairCipher) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA.PairCipherAux))
						continue;						
				}
				else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
				{
					// If it's not mixed mode, we should only let BSS pass with the same encryption
					if (pInBss->WPA2.bMixMode == FALSE)
						if (pAd->PortCfg.WepStatus != pInBss->WPA2.GroupCipher)
							continue;
				
					// check group cipher
					if (pAd->PortCfg.WepStatus < pInBss->WPA2.GroupCipher)
						continue;
					// check pairwise cipher, skip if none matched
					// If profile set to AES, let it pass without question.
					// If profile set to TKIP, we must find one mateched
					if ((pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA2.PairCipher) && 
						(pAd->PortCfg.WepStatus != pInBss->WPA2.PairCipherAux))
						continue;						
				}
			}
			// Bss Type matched, SSID matched. 
			// We will check wepstatus for qualification Bss
			else if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
					continue;
			
            // copy matching BSS from InTab to OutTab
            NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
            
            OutTab->BssNr++;
        }
		
		if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
			break;
		
    }
    BssTableSortByRssi(OutTab);
}
// IRQL = DISPATCH_LEVEL
VOID BssTableSortByRssi(
    IN OUT BSS_TABLE *OutTab) 
{
    INT       i, j;
    BSS_ENTRY TmpBss;
    for (i = 0; i < OutTab->BssNr - 1; i++) 
    {
        for (j = i+1; j < OutTab->BssNr; j++) 
        {
            if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) 
            {
                NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY));
                NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY));
                NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY));
            }
        }
    }
}
extern	UCHAR	RSN_OUI[];		// in sanity.c
VOID		BssCipherParse(
	IN OUT	PBSS_ENTRY	pBss)
{
#if 1
	PBEACON_EID_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;
	// Set default to disable & open authentication before parsing variable IE
	pBss->WepStatus     = Ndis802_11WEPDisabled;
	pBss->AuthMode      = Ndis802_11AuthModeOpen;
	pBss->AuthModeAux   = Ndis802_11AuthModeOpen;
	// Init WPA setting
	pBss->WPA.PairCipher    = Ndis802_11WEPDisabled;
	pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
	pBss->WPA.GroupCipher   = Ndis802_11WEPDisabled;
	pBss->WPA.RsnCapability = 0;
	pBss->WPA.bMixMode      = FALSE;
	// Init WPA2 setting
	pBss->WPA2.PairCipher    = Ndis802_11WEPDisabled;
	pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
	pBss->WPA2.GroupCipher   = Ndis802_11WEPDisabled;
	pBss->WPA2.RsnCapability = 0;
	pBss->WPA2.bMixMode      = FALSE;
	Length = (INT) pBss->VarIELen;
	while (Length > 0)
	{
		// Parse cipher suite base on WPA1 & WPA2, they should be parsed differently
		pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length;
		pEid = (PBEACON_EID_STRUCT) pTmp;
		switch (pEid->Eid)
		{
			case IE_WPA:
				// 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:
					case 5:	// Although WEP is not allowed in WPA related auth mode, we parse it anyway
						pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled;
						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;				
				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;
				pTmp   += sizeof(USHORT);
				pTmp   += 3;
				
				switch (*pTmp)
				{
					case 1:
						// Set AP support WPA mode
						if (pBss->AuthMode == Ndis802_11AuthModeOpen)
							pBss->AuthMode = Ndis802_11AuthModeWPA;
						else
							pBss->AuthModeAux = Ndis802_11AuthModeWPA;
						break;
					case 2:
						// Set AP support WPA 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_INDEP)
				{
					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 (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:
					case 5:	// Although WEP is not allowed in WPA related auth mode, we parse it anyway
						pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled;
						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;
				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;
				pTmp   += sizeof(USHORT);
				// 5. Get AKM ciphers
				pAKM = (PAKM_SUITE_STRUCT) pTmp;
				if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
					break;
				switch (pAKM->Type)
				{
					case 1:
						// Set AP support WPA mode
						if (pBss->AuthMode == Ndis802_11AuthModeOpen)
							pBss->AuthMode = Ndis802_11AuthModeWPA2;
						else
							pBss->AuthModeAux = Ndis802_11AuthModeWPA2;
						break;
					case 2:
						// Set AP support WPA mode
						if (pBss->AuthMode == Ndis802_11AuthModeOpen)
							pBss->AuthMode = Ndis802_11AuthModeWPA2PSK;
						else
							pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK;
						break;
					default:
						break;
				}
				pTmp   += (Count * sizeof(AKM_SUITE_STRUCT));
				
				// Fixed for WPA-None
				if (pBss->BssType == BSS_INDEP)
				{
					pBss->AuthMode = Ndis802_11AuthModeWPANone;
					pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
					pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux;
					pBss->WPA.GroupCipher   = pBss->WPA2.GroupCipher;
					pBss->WepStatus         = pBss->WPA.GroupCipher;
					// Patched bugs for old driver
					if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled)
						pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher;
				}
				pBss->WepStatus   = pBss->WPA2.PairCipher;					
				
				// 6. Get RSN capability
				pBss->WPA2.RsnCapability = *(PUSHORT) pTmp;
				pTmp += sizeof(USHORT);
				
				// Check the Pair & Group, if different, turn on mixed mode flag
				if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
					pBss->WPA2.bMixMode = TRUE;
				
				break;
			default:
				break;
		}
		Length -= (pEid->Len + 2);
	}
#endif
	return;
}
// ===========================================================================================
// 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 PRT2570ADAPTER pAd, 
    OUT MACADDR *Addr) 
{
    INT i;
    for (i = 0; i < MAC_ADDR_LEN; i++) 
    {
        Addr->Octet[i] = RandomByte(pAd);
    }
    
    Addr->Octet[0] = (Addr->Octet[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->PortCfg
 *   - bssid
 *   - station address
 *  \post
 *  \note this function initializes the following field
 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL
  
 */
VOID MgtMacHeaderInit(
    IN	PRT2570ADAPTER	pAd, 
    IN OUT PMACHDR Hdr, 
    IN UCHAR Subtype, 
    IN UCHAR ToDs, 
    IN PMACADDR Ds, 
    IN PMACADDR Bssid) 
{
    NdisZeroMemory(Hdr, sizeof(MACHDR));
    Hdr->Type = BTYPE_MGMT;
    Hdr->SubType = Subtype;
    Hdr->Tods = ToDs;
    COPY_MAC_ADDR(&Hdr->Addr1, Ds);
    COPY_MAC_ADDR(&Hdr->Addr2, &pAd->CurrentAddress);
    COPY_MAC_ADDR(&Hdr->Addr3, Bssid);
}
// ===========================================================================================
// 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 CHAR *Buffer, 
    OUT ULONG *FrameLen, ...) 
{
    CHAR   *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
 */
NDIS_STATUS MlmeQueueInit(
	IN MLME_QUEUE *Queue) 
{
	INT i;
	DBGPRINT(RT_DEBUG_INFO,"--> MlmeQueueInit\n");
	NdisAllocateSpinLock(&Queue->Lock);
	Queue->Num	= 0;
	Queue->Head = 0;
	Queue->Tail = 0;
	for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) 
	{
		Queue->Entry[i].Occupied = FALSE;
		Queue->Entry[i].MsgLen = 0;
		NdisZeroMemory(Queue->Entry[i].Msg, MAX_LEN_OF_MLME_BUFFER);
	}
	DBGPRINT(RT_DEBUG_INFO,"<-- MlmeQueueInit\n");
	return NDIS_STATUS_SUCCESS;
}
BOOLEAN MlmeEnqueue(
    IN PRT2570ADAPTER pAd, 
	IN ULONG Machine, 
	IN ULONG MsgType, 
	IN ULONG MsgLen, 
	IN VOID *Msg) 
{
	INT Tail;
	MLME_QUEUE	*Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;
	if (pAd->MLMEThr_pid > 0)
	{
		if (MlmeQueueFull(Queue)) 
		{
			DBGPRINT(RT_DEBUG_ERROR,"MlmeEnqueue full, msg dropped and may corrupt MLME\n");
			return FALSE;
		}
		NdisAcquireSpinLock(&(Queue->Lock));
		Tail = Queue->Tail;
		Queue->Tail++;
		Queue->Num++;
		if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) 
		{
			Queue->Tail = 0;
		}
		NdisReleaseSpinLock(&(Queue->Lock));
		DBGPRINT(RT_DEBUG_INFO,"MlmeEnqueue, num=%d\n",Queue->Num);
	 
		Queue->Entry[Tail].Occupied = TRUE;
		Queue->Entry[Tail].Machine = Machine;
		Queue->Entry[Tail].MsgType = MsgType;
		Queue->Entry[Tail].MsgLen  = MsgLen;
		NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
	}
	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 PRT2570ADAPTER	pAd, 
    OUT MLME_QUEUE *Queue, 
    IN UCHAR Rssi, 
    IN ULONG MsgLen, 
    IN VOID *Msg) 
{
    INT          Tail, Machine;
    MACFRAME    *Fr = (MACFRAME *)Msg;
    ULONG        MsgType;
	//DBGPRINT(RT_DEBUG_ERROR,"MlmeEnqueueForRecv ");
	if((pAd->MLMEThr_pid <= 0))
		return FALSE;
	// First check the size, it MUST not exceed the mlme queue size
	if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
	{
		DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen);
		return FALSE;
	}
	
	if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) ||
		(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_REMOVE_IN_PROGRESS)))
	{
		DBGPRINT(RT_DEBUG_TRACE, "MlmeEnqueueForRecv (not in operation) Flag = 0x%x\n", pAd->Flags);
		return FALSE;
	}
    if (MlmeQueueFull(Queue)) 
    {
        //DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (queue full error) \n");
        return FALSE;
    }
    if (!MsgTypeSubst(pAd, Fr, &Machine, &MsgType)) 
    {
        DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (drop mgmt->subtype=%d)\n",Fr->Hdr.SubType);
        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;
    }
    NdisReleaseSpinLock(&(Queue->Lock));
    DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueueForRecv, num=%d\n",Queue->Num);
    
    Queue->Entry[Tail].Occupied = TRUE;
    Queue->Entry[Tail].Machine = Machine;
    Queue->Entry[Tail].MsgType = MsgType;
    Queue->Entry[Tail].MsgLen  = MsgLen;
    Queue->Entry[Tail].Rssi = Rssi;
    NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
    
	RTUSBUp(pAd, (&(pAd->mlme_semaphore)));
    return TRUE;
}
/*! \brief   Dequeue a message from the MLME Queue
 *  \param  *Queue    The MLME Queue
 *  \param  *Elem     The message dequeued from MLME Queue
 *  \return  TRUE if the Elem contains something, FALSE otherwise
 *  \pre
 *  \post
 
 IRQL = DISPATCH_LEVEL
 
 */
BOOLEAN MlmeDequeue(
    IN MLME_QUEUE *Queue, 
    OUT MLME_QUEUE_ELEM **Elem) 
{
    NdisAcquireSpinLock(&(Queue->Lock));
	if (Queue->Num == 0)
	{
		NdisReleaseSpinLock(&(Queue->Lock));
		return FALSE; //Empty
	}
    *Elem = &(Queue->Entry[Queue->Head]);
    Queue->Num--;
    Queue->Head++;
    if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) 
    {
        Queue->Head = 0;
    }
    
    NdisReleaseSpinLock(&(Queue->Lock));
    DBGPRINT(RT_DEBUG_INFO, "MlmeDequeue, num=%d\n",Queue->Num);
    return TRUE;
}
// IRQL = DISPATCH_LEVEL
VOID	MlmeRestartStateMachine(
    IN	PRT2570ADAPTER	pAd)
{
	DBGPRINT(RT_DEBUG_TRACE, "==> MlmeRestartStateMachine\n");
	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS);
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	if(pAd->Mlme.Running) 
	{
		DBGPRINT(RT_DEBUG_TRACE, "<== MlmeRestartStateMachine, Mlme is Runing[Queue=%d]!\n", pAd->Mlme.Queue.Num);
		NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
		return;
	} 
	pAd->Mlme.Running = TRUE;
	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	MlmeQueueDestroy(&pAd->Mlme.Queue);
	// Cancel all timer events
	// Be careful to cancel new added timer
	RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
	RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
	//    RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer, &Cancelled);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
	RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
	// Set all state machines back IDLE
	pAd->Mlme.CntlMachine.CurrState    = CNTL_IDLE;
	pAd->Mlme.AssocMachine.CurrState   = ASSOC_IDLE;
	pAd->Mlme.AuthMachine.CurrState    = AUTH_REQ_IDLE;
	pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
	pAd->Mlme.SyncMachine.CurrState    = SYNC_IDLE;
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_JOIN_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REASSOC_IN_PROGRESS);//steven:for test
	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);//steven:for test
	RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS);
	// Remove running state
	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
	pAd->Mlme.Running = FALSE;
	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
	DBGPRINT(RT_DEBUG_TRACE, "<== MlmeRestartStateMachine\n");
}
VOID	MlmePostRestartStateMachine(
    IN	PRT2570ADAPTER	pAd)
{
	//
	// Flag fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS will be clear at MlmeHandler
	// when required to do MLME Reset!
	// Since MlmeRestartStateMachine will do nothing when Mlme is running.
	//
	while (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS))
		NdisMSleep(100);
	// Change back to original channel in case of doing scan
	AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
	AsicLockChannel(pAd, pAd->PortCfg.Channel);
	// Resume MSDU which is turned off durning scan
	RTUSBResumeMsduTransmission(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;