/*************************************************************************** 
 * 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:	rtusb_data.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 *	RobinC		02-06-2005	RFMON Mode added
 *	MathiasK	04-07-2005	big endian fix from gglomm
 ***************************************************************************/

#include	"rt_config.h"

static  UCHAR PlcpSignal[12] = { 
	 0, /* RATE_1 */    1, /* RATE_2 */     2, /* RATE_5_5 */   3, /* RATE_11 */    // see BBP spec
	11, /* RATE_6 */   15, /* RATE_9 */    10, /* RATE_12 */   14, /* RATE_18 */    // see IEEE802.11a-1999 p.14
	 9, /* RATE_24 */  13, /* RATE_36 */    8, /* RATE_48 */    12  /* RATE_54 */ }; // see IEEE802.11a-1999 p.14
static	UINT	_11G_RATES[12] = { 0, 0, 0, 0, 6, 9, 12, 18, 24, 36, 48, 54 };
static	UCHAR	SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
static	UCHAR	SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
static	UCHAR	EAPOL[] = {0x88, 0x8e};
static	UCHAR	IPX[] = {0x81, 0x37};
static	UCHAR	APPLE_TALK[] = {0x80, 0xf3};
UCHAR	ARP[]={0x08, 0x06};
////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION
//		RTUSBSendPackets
//		
//	DESCRIPTION
//	  VNETMultipleSend handler is called by NDIS to transmit packets
//	  through the adapter. If there are packets in the Q and the device
//	  can accept the Tx requests initiate a transmission and queue the
//	  rest of the packets (if any...). If we can not transmit or the
//	  station is not ready we imediatelly complete the request
//		
//	INPUT
//	  MiniportAdapterContext		Context registered with the wrapper
//									(Ptr to to the Adapter object)
//	  PacketArray					Array of Ptrs to NDIS_PACKET structs
//	  NumberOfPackets				Number of packets in PacketArray
//		
//	OUTPUT
//		-
//		
////////////////////////////////////////////////////////////////////////////
int RTUSBSendPackets(struct sk_buff *skb, struct net_device *net_dev)
{

	NDIS_STATUS 	Status = NDIS_STATUS_SUCCESS;
	PRT2570ADAPTER	pAdapter = net_dev->priv;
	
	skb->data_len = skb->len;
	if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
		RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ||
		RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF) ||
		RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS))
	{
		RTUSBFreeSkbBuffer(skb);
		return 0;
	}
	// Drop packets if no associations
	else if (!INFRA_ON(pAdapter) && !ADHOC_ON(pAdapter) && 
		   !( pAdapter->PortCfg.BssType == BSS_MONITOR && pAdapter->PortCfg.MallowRFMONTx == TRUE )
		 )
	{
		RTUSBFreeSkbBuffer(skb);
		return 0;
	}
	else
	{
		Status = RTUSBSendPacket(pAdapter, skb);
	        if (Status != NDIS_STATUS_SUCCESS)
	        {
			// Errors before enqueue stage
			RTUSBFreeSkbBuffer(skb);
			DBGPRINT(RT_DEBUG_TRACE,"<---RTUSBSendPackets not dequeue\n");
			return 0;
	        }
	}
	// Dequeue one frame from SendTxWait queue and process it
	// There are two place calling dequeue for TX ring.
	// 1. Here, right after queueing the frame.
	// 2. At the end of TxRingTxDone service routine.
	if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && 
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)))
	{
	    //RTMPDeQueuePacket(pAdapter, &pAdapter->TxSwQueue0);
	    // Call dequeue without selected queue, let the subroutine select the right priority
	    // Tx software queue
	    RTUSBDeQueuePacket(pAdapter);
	}

	// Kick bulk out
	RTUSBKickBulkOut(pAdapter);
	return 0;
}

NDIS_STATUS	RTUSBSendPacket(
	IN	PRT2570ADAPTER	pAdapter,
	IN  struct sk_buff  *skb)
{


	PVOID			pVirtualAddress;
	struct sk_buff_head     *pTxQueue;
	ULONG					Priority;
	UCHAR			NumberOfFrag;
	UCHAR			RTSRequired;
	UINT			AllowFragSize;
	UCHAR                   AccessCategory;
	NDIS_STATUS		Status = NDIS_STATUS_FAILURE;
	UCHAR			PsMode;

	// Init priority value
	Priority = 0;
	AccessCategory = 0;

	if (skb && pAdapter->PortCfg.BssType == BSS_MONITOR &&
		   pAdapter->PortCfg.MallowRFMONTx == TRUE)
	{
		NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
		skb_queue_tail(&pAdapter->SendTxWaitQueue, skb);
		NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
		return (NDIS_STATUS_SUCCESS);
	}
	
	if (skb)
	{
		Priority = skb->priority;
		// 802.11e/d4.4 June, 2003
		if (Priority <=2)
		    AccessCategory = 0;
		else if (Priority == 3)
		    AccessCategory = 1;
		else if (Priority <= 5)
		    AccessCategory = 2;
		else
		    AccessCategory = 3;
		DBGPRINT(RT_DEBUG_INFO, "Priority = %d, AC = %d\n", Priority, AccessCategory);
	}
	// For TKIP, MIC value is treated as payload, it might be fragmented through
	// different MPDUs.
	if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled)
	{
		skb->data_len += 8;
	}

	pVirtualAddress = (PVOID)skb->data;
	// Check for virtual address allocation, it might fail !!!
	if (pVirtualAddress == NULL)
	{
		DBGPRINT(RT_DEBUG_TRACE,"<---RTUSBSendPacket NULL pVirtualAddress\n");
		// Resourece is low, system did not allocation virtual address
		// return NDIS_STATUS_FAILURE directly to upper layer
		return (Status);
	}

	//
	// Check for multicast or broadcast (First byte of DA)
	//
	if ((*((PUCHAR) pVirtualAddress) & 0x01) != 0)
	{
		// For multicast & broadcast, there is no fragment allowed
		NumberOfFrag = 1;
	}
	else
	{
		// Check for payload allowed for each fragment
		AllowFragSize = (pAdapter->PortCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC;

		// Calculate fragments required
		NumberOfFrag = ((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1;
		// Minus 1 if the size just match to allowable fragment size
		if (((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0)
		{
			NumberOfFrag--;
		}
	}
	
	// Check for requirement of RTS 
	if (NumberOfFrag > 1)
	{
		// If multiple fragment required, RTS is required only for the first fragment
		// if the fragment size large than RTS threshold
		RTSRequired = (pAdapter->PortCfg.FragmentThreshold > pAdapter->PortCfg.RtsThreshold) ? 1 : 0;
	}
	else
	{
		RTSRequired = (skb->data_len > pAdapter->PortCfg.RtsThreshold) ? 1 : 0;
	}

	// RTS/CTS may also be required in order to protect OFDM frame
	if ((pAdapter->PortCfg.TxRate >= RATE_FIRST_OFDM_RATE) && pAdapter->PortCfg.BGProtectionInUsed)
		RTSRequired = 1;
	//DBGPRINT(RT_DEBUG_TEMP, "Number of fragments :%d , include RTS :%d\n", NumberOfFrag, NumberOfFrag + RTSRequired);
        
	// Save framnet number to Ndis packet reserved field
	RTMP_SET_PACKET_FRAGMENTS(skb, NumberOfFrag);	     

	// Save RTS requirement to Ndis packet reserved field
	RTMP_SET_PACKET_RTS(skb, RTSRequired);

	// Make sure SendTxWait queue resource won't be used by other threads
	NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);

	pTxQueue = &pAdapter->SendTxWaitQueue;
	if (INFRA_ON(pAdapter))
	{
		// In infrastructure mode, simply enqueue the packet into Tx waiting queue.
		DBGPRINT(RT_DEBUG_INFO, "Infrastructure -> Enqueue one frame\n");

		// Enqueue Ndis packet to end of Tx wait queue
		skb_queue_tail(pTxQueue, skb);
		Status = NDIS_STATUS_SUCCESS;
	}
	else
	{
		// In IBSS mode, power state of destination should be considered.
		PsMode = PWR_ACTIVE;		// Faked
		if (PsMode == PWR_ACTIVE)
		{
			// Enqueue Ndis packet to end of Tx wait queue
			skb_queue_tail(pTxQueue, skb);
			Status = NDIS_STATUS_SUCCESS;
		}
	}
	
	NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
	return Status;
}

VOID	RTUSBDeQueuePacket(
	IN	PRT2570ADAPTER	pAdapter)
{

	UCHAR			FragmentRequired;
	NDIS_STATUS		Status = NDIS_STATUS_SUCCESS;
	struct sk_buff  	*skb;
	struct sk_buff_head     *pQueue;
	UCHAR			Count = 0;
	// Make sure SendTxWait queue resource won't be used by other threads
	NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);

	// Select Queue
	pQueue = &pAdapter->SendTxWaitQueue;

	// Check queue before dequeue
	while (!skb_queue_empty(pQueue) && (Count < MAX_TX_PROCESS))
	{
		// Reset is in progress, stop immediately
		if ( RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
			 RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ||
		     RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS))
		{
			break;
		}
			
		// Dequeue the first entry from head of queue list
		skb = skb_dequeue(pQueue);


		// RTS or CTS-to-self for B/G protection mode has been set already.
		// There is no need to re-do it here. 
		// Total fragment required = number of fragment + RST if required
		FragmentRequired = RTMP_GET_PACKET_FRAGMENTS(skb) + RTMP_GET_PACKET_RTS(skb);
		
		if (RTUSBFreeDescriptorRequest(pAdapter, TX_RING, FragmentRequired) == NDIS_STATUS_SUCCESS)
		{
			// Avaliable ring descriptors are enough for this frame
			// Call hard transmit
			// Nitro mode / Normal mode selection
			NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
			if (pAdapter->PortCfg.EnableTxBurst == 1)
				Status = RTUSBHardEncrypt(pAdapter, skb, FragmentRequired, TRUE);
			else				
				Status = RTUSBHardEncrypt(pAdapter, skb, FragmentRequired, FALSE);
			//
			// Acquire the resource again, snice we may need to process it in this while-loop.
			//
			NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
			if (Status == NDIS_STATUS_FAILURE)
			{
				// Packet failed due to various Ndis Packet error
				RTUSBFreeSkbBuffer(skb);
				break;
			}
			else if (Status == NDIS_STATUS_RESOURCES)
			{
				// Not enough free tx ring, it might happen due to free descriptor inquery might be not correct
				// It also might change to NDIS_STATUS_FAILURE to simply drop the frame
				// Put the frame back into head of queue
				skb_queue_head(pQueue, skb);
				break;
			}			
			Count++;
		}	
		else
		{
			skb_queue_head(pQueue, skb);
			break;
		}
	}
	
	NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
	return;
	
}

NDIS_STATUS	RTUSBFreeDescriptorRequest(
	IN		PRT2570ADAPTER	pAdapter,
	IN		UCHAR			RingType,
	IN		UCHAR			NumberRequired)
{
	UCHAR			FreeNumber = 0;
	UINT			Index;
	NDIS_STATUS		Status = NDIS_STATUS_FAILURE;

	switch (RingType)
	{
		case TX_RING:
			Index = pAdapter->NextTxIndex;
			do
			{
				PTX_CONTEXT	pTxD  = &pAdapter->TxContext[Index];
				
				// While Owner bit is NIC, obviously ASIC still need it.
				// If valid bit is TRUE, indicate that TxDone has not process yet
				// We should not use it until TxDone finish cleanup job
				if (pTxD->InUse == FALSE)
				{
					// This one is free
					FreeNumber++;
				}
				else
				{
					break;
				}					
				Index = (Index + 1) % TX_RING_SIZE;				
			}	while (FreeNumber < NumberRequired);	// Quit here ! Free number is enough !
			
			if (FreeNumber >= NumberRequired)
			{
				Status = NDIS_STATUS_SUCCESS;
			}
			
			break;
			
		case PRIO_RING:
			Index = pAdapter->NextMLMEIndex;
			do
			{
				PTX_CONTEXT	pTxD  = &pAdapter->MLMEContext[Index];
				
				// While Owner bit is NIC, obviously ASIC still need it.
				// If valid bit is TRUE, indicate that TxDone has not process yet
				// We should not use it until TxDone finish cleanup job
				if (pTxD->InUse == FALSE)
				{
					// This one is free
					FreeNumber++;
				}
				else
				{
					break;
				}
					
				Index = (Index + 1) % PRIO_RING_SIZE;				
			}	while (FreeNumber < NumberRequired);	// Quit here ! Free number is enough !
			
			if (FreeNumber >= NumberRequired)
			{
				Status = NDIS_STATUS_SUCCESS;
			}
			break;

		default:
			break;


	
	}

	return (Status);

}
/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBRejectPendingPackets(
	IN	PRT2570ADAPTER	pAdapter)
{
	DBGPRINT_RAW(RT_DEBUG_TRACE, "--->RejectPendingPackets\n");

	NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
	DBGPRINT_RAW(RT_DEBUG_TRACE, "Purge SendTxWaitQueue\n");
	skb_queue_purge(&pAdapter->SendTxWaitQueue);
	NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);

	DBGPRINT_RAW(RT_DEBUG_TRACE, "<---RejectPendingPackets\n");
}

/*
	========================================================================

	Routine	Description:
		Suspend MSDU transmission
		
	Arguments:
		pAdapter		Pointer	to our adapter
		
	Return Value:
		None
		
	Note:
	
	========================================================================
*/
VOID    RTUSBSuspendMsduTransmission(
	IN	PRT2570ADAPTER	pAdapter)
{
	DBGPRINT(RT_DEBUG_TRACE,"SCANNING, suspend MSDU transmission ...\n");
	RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
}

/*
	========================================================================

	Routine	Description:
		Resume MSDU transmission
		
	Arguments:
		pAdapter		Pointer	to our adapter
		
	Return Value:
		None
		
	Note:
	
	========================================================================
*/
VOID    RTUSBResumeMsduTransmission(
	IN	PRT2570ADAPTER	pAdapter)
{
	DBGPRINT(RT_DEBUG_TRACE,"SCANNING, resume MSDU transmission ...\n");
	RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
	if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)))
	{
		// Call dequeue without selected queue, let the subroutine select the right priority
		// Tx software queue
		RTUSBDeQueuePacket(pAdapter);
	}

	// Kick bulk out
	RTUSBKickBulkOut(pAdapter);

}
/*
	========================================================================

	Routine	Description:
		
	Arguments:
		
	Return Value:
		
	Note:
	
	========================================================================
*/
USHORT	RTUSBCalcDuration(
	IN	PRT2570ADAPTER	pAdapter,
	IN	UCHAR			Rate,
	IN	ULONG			Size)
{
	ULONG	Duration = 0;

	if (Rate < RATE_FIRST_OFDM_RATE) // CCK
	{
	    if ((Rate > RATE_1) && (pAdapter->PortCfg.TxPreambleInUsed == Rt802_11PreambleShort))
		Duration = 96;  // 72+24 preamble+plcp
		else
	    Duration = 192; // 144+48 preamble+plcp
		
		Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]);
		if ((Size << 4) % RateIdTo500Kbps[Rate])
			Duration ++;
	}
	else // OFDM rates
	{
		Duration = 20 + 6;      // 16+4 preamble+plcp + Signal Extension
		Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]);
		if ((11 + Size * 4) % RateIdTo500Kbps[Rate])
			Duration += 4;
	}
	
	return (USHORT)Duration;	
}

/*
	========================================================================
	
	Routine	Description:
		Calculates the duration which is required to transmit out frames 
	with given size and specified rate.
		
	Arguments:
		pTxD		Pointer to transmit descriptor
		Ack			Setting for Ack requirement bit
		Fragment	Setting for Fragment bit
		RetryMode	Setting for retry mode
		Ifs			Setting for IFS gap
		Rate		Setting for transmit rate
		Service		Setting for service
		Length		Frame length
		
	Return Value:
		None
		
	========================================================================
*/
VOID	RTUSBWriteTxDescriptor(
	IN	PTXD_STRUC	pTxD,
	IN	BOOLEAN		Fragment,
	IN	UCHAR		RetryLimit,
	IN	BOOLEAN		Ack,
	IN  BOOLEAN     InsTimestamp,
	IN  BOOLEAN     new_seq,
	IN	UCHAR		Ifs,
	IN	UINT		Length,
	IN	BOOLEAN		Cipher,
	IN	UCHAR		KeyID,
	IN	UCHAR		CWMin,
	IN	UCHAR		CWMax,
	IN	UINT		PLCPLength,
	IN	UINT		Rate,
	IN	UCHAR		Service,
	IN  USHORT      TxPreamble)
{
	UINT	Residual;

	pTxD->RetryLimit  = RetryLimit;
	pTxD->MoreFrag    = Fragment;
	pTxD->ACK         = Ack;
	pTxD->Timestamp   = InsTimestamp;
	pTxD->newseq      = new_seq;
	pTxD->IFS         = Ifs;
	pTxD->DataByteCnt = Length;
	pTxD->Cipher	  = Cipher;
	pTxD->KeyID		  = KeyID;
	pTxD->CWmin       = CWMin;   // 2^5-1 = 31
	pTxD->CWmax       = CWMax;  // 2^10 -1 = 1023
	pTxD->Aifs        = 2;   // TC0: SIFS + 2*Slot + Random(CWmin,CWmax)*Slot
		
	if (Rate < RATE_FIRST_OFDM_RATE)
		pTxD->Ofdm = 0;
	else
		pTxD->Ofdm = 1;

	// fill up PLCP SIGNAL field
	pTxD->PlcpSignal = PlcpSignal[Rate];
	if (((Rate == RATE_2) || (Rate == RATE_5_5) || (Rate == RATE_11)) && (TxPreamble == Rt802_11PreambleShort)) // no short preamble for RATE_1
	{
		pTxD->PlcpSignal |= 0x0008;
	}

	// fill up PLCP SERVICE field, not used for OFDM rates
	pTxD->PlcpService = Service;

	// file up PLCP LENGTH_LOW and LENGTH_HIGH fields
	if (Rate < RATE_FIRST_OFDM_RATE)    // 11b - RATE_1, RATE_2, RATE_5_5, RATE_11
	{
		if ((Rate == RATE_1) || ( Rate == RATE_2))
		{
			PLCPLength = PLCPLength * 8 / (Rate + 1);
		}
		else
		{
			Residual = ((PLCPLength * 16) % (11 * (1 + Rate - RATE_5_5)));
			PLCPLength = PLCPLength * 16 / (11 * (1 + Rate - RATE_5_5));
			if (Residual != 0)
			{
				PLCPLength++;
			}
			if (Rate == RATE_11)
			{
			if ((Residual <= (3 * (1 + Rate - RATE_5_5))) && (Residual != 0))
			{
				pTxD->PlcpService |= 0x80; // 11b's PLCP Length extension bit
			}
			}
		}

		pTxD->PlcpLengthHigh = PLCPLength / 256;
		pTxD->PlcpLengthLow = PLCPLength % 256;
	}
	else    // OFDM - RATE_6, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54
	{
		pTxD->PlcpLengthHigh = PLCPLength / 64;  // high 6-bit of total byte count
		pTxD->PlcpLengthLow = PLCPLength % 64;   // low 6-bit of total byte count
	}
}

/*
	========================================================================
	
	Routine	Description:
		Calculates the duration which is required to transmit out frames 
	with given size and specified rate.
		
	Arguments:
		pTxD		Pointer to transmit descriptor
		Ack			Setting for Ack requirement bit
		Fragment	Setting for Fragment bit
		RetryMode	Setting for retry mode
		Ifs			Setting for IFS gap
		Rate		Setting for transmit rate
		Service		Setting for service
		Length		Frame length
		
	Return Value:
		None
		
	========================================================================
*/
VOID	RTUSBWriteBeaconDescriptor(
	IN	PTXD_STRUC	pTxD,
	IN	UINT		Length,
	IN	UINT		PLCPLength,
	IN	UINT		Rate,
	IN	UCHAR		Service,
	IN  USHORT      TxPreamble)
{
	UINT	Residual;

	pTxD->RetryLimit	= 0;
	pTxD->MoreFrag    = 0;
	pTxD->ACK         = 0;
	pTxD->Timestamp   = 1;
	pTxD->newseq      = 1;
	pTxD->IFS         = IFS_NEW_BACKOFF;
	pTxD->DataByteCnt = Length;
	pTxD->Cipher	  = 0;
	pTxD->KeyID		  = 0;
	pTxD->CWmin       = BEACON_CW_IN_BITS;   // 2^5-1 = 31
	pTxD->CWmax       = BEACON_CW_IN_BITS;  // 2^10 -1 = 1023
	pTxD->Aifs        = 2;   // TC0: SIFS + 2*Slot + Random(CWmin,CWmax)*Slot
		
	if (Rate < RATE_FIRST_OFDM_RATE)
		pTxD->Ofdm = 0;
	else
		pTxD->Ofdm = 1;

	// fill up PLCP SIGNAL field
	pTxD->PlcpSignal = PlcpSignal[Rate];
	if (((Rate == RATE_2) || (Rate == RATE_5_5) || (Rate == RATE_11)) && (TxPreamble == Rt802_11PreambleShort)) // no short preamble for RATE_1
	{
		pTxD->PlcpSignal |= 0x0008;
	}

	// fill up PLCP SERVICE field, not used for OFDM rates
	pTxD->PlcpService = Service;

	// file up PLCP LENGTH_LOW and LENGTH_HIGH fields
	if (Rate < RATE_FIRST_OFDM_RATE)    // 11b - RATE_1, RATE_2, RATE_5_5, RATE_11
	{
		if ((Rate == RATE_1) || ( Rate == RATE_2))
		{
			PLCPLength = PLCPLength * 8 / (Rate + 1);
		}
		else
		{
			Residual = ((PLCPLength * 16) % (11 * (1 + Rate - RATE_5_5)));
			PLCPLength = PLCPLength * 16 / (11 * (1 + Rate - RATE_5_5));
			if (Residual != 0)
			{
				PLCPLength++;
			}
			if ((Residual <= (3 * (1 + Rate - RATE_5_5))) && (Residual != 0))
			{
				pTxD->PlcpService |= 0x80; // 11b's PLCP Length extension bit
			}
		}

		pTxD->PlcpLengthHigh = PLCPLength / 256;
		pTxD->PlcpLengthLow = PLCPLength % 256;
	}
	else    // OFDM - RATE_6, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54
	{
		pTxD->PlcpLengthHigh = PLCPLength / 64;  // high 6-bit of total byte count
		pTxD->PlcpLengthLow = PLCPLength % 64;   // low 6-bit of total byte count
	}
}

/*
	========================================================================

	Routine	Description:
		Copy frame from waiting queue into relative ring buffer and set 
	appropriate ASIC register to kick hardware encryption before really
	sent out to air.
		
	Arguments:
		pAdapter		Pointer	to our adapter
		PNDIS_PACKET	Pointer to outgoing Ndis frame
		NumberOfFrag	Number of fragment required
		
	Return Value:
		None

	IRQL = DISPATCH_LEVEL
	
	Note:
	
	========================================================================
*/
NDIS_STATUS	RTUSBHardEncrypt(
	IN	PRT2570ADAPTER	pAdapter,
	IN  struct sk_buff  *skb,
	IN	UCHAR			NumberRequired,
	IN	ULONG			EnableTxBurst)
{
	PVOID			pVirtualAddress;
	UINT			NdisBufferLength;
	UINT			BytesCopied;
	UINT			TxSize, PLCPLength;
	UINT			FreeFragSize;
	UINT			RemainSize;
	USHORT			Protocol;
	UCHAR			FrameGap;
	HEADER_802_11	Header_802_11;
	PUCHAR			pDest;
	PUCHAR			pSrc;
	PUCHAR			pEncap = NULL;
	PTX_CONTEXT		pTxContext;
	PTXD_STRUC		pTxD;
	BOOLEAN			StartOfFrame;
	BOOLEAN			EAPOLFrame;
	BOOLEAN			Encapped;
	ULONG			Iv16;
	ULONG			Iv32;
	BOOLEAN			MICFrag;
	PWPA_KEY		pWpaKey = (PWPA_KEY) NULL;
	BOOLEAN			Cipher;
	UCHAR			KeyID = 0;
	ULONG			TransferBufferLength;
	BOOLEAN			MoreFragment;
    UCHAR           AckRate = RATE_2;
    USHORT          AckDuration = 0;
    USHORT          EncryptionOverhead = 0;
	BOOLEAN			Bcast_8023;
	BOOLEAN			SingleFrag;
//for re-calculating the number of Fragment required.
	UINT			AllowFragSize;
	UCHAR			NumberOfFrag;
	UINT			TotalPacketLength; 
	// To indicate cipher used for this packet
	NDIS_802_11_ENCRYPTION_STATUS	CipherSuite;
	
	CipherSuite = pAdapter->PortCfg.WepStatus;
	if (EnableTxBurst == 1)
		FrameGap = IFS_SIFS;
	else
		FrameGap = IFS_BACKOFF;		// Default frame gap mode
	// Sequence Number is identical for all fragments belonged to the same frame
	// Sequence is 0 - 4095
	pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER);
	AckRate = pAdapter->PortCfg.ExpectedACKRate[pAdapter->PortCfg.TxRate];
	AckDuration = RTUSBCalcDuration(pAdapter, AckRate, 14);

	pVirtualAddress = skb->data;
	NdisBufferLength = skb->len;
	if(pVirtualAddress == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, "Error, Null skb data buffer!!!\n");
		return (NDIS_STATUS_FAILURE);
	}

	if (pAdapter->PortCfg.BssType == BSS_MONITOR && pAdapter->PortCfg.MallowRFMONTx == TRUE)
	{
		pTxContext  = &pAdapter->TxContext[pAdapter->NextTxIndex];
		pTxContext->InUse   = TRUE;
		pTxContext->LastOne = TRUE;
		
		pAdapter->NextTxIndex++;
		if (pAdapter->NextTxIndex >= TX_RING_SIZE)
			pAdapter->NextTxIndex = 0;

		pTxD  = &(pTxContext->TransferBuffer->TxDesc);
		memset(pTxD, 0, sizeof(TXD_STRUC));
		pDest = pTxContext->TransferBuffer->WirelessPacket;

		memcpy( pDest, skb->data, skb->len );

		RTUSBWriteTxDescriptor(pTxD, FALSE, 0, FALSE, FALSE, TRUE, IFS_BACKOFF, skb->len, FALSE, 0, CW_MIN_IN_BITS, CW_MAX_IN_BITS, skb->len + 4, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);

		TransferBufferLength = skb->len + sizeof(TXD_STRUC);
		if ((TransferBufferLength % 2) == 1)
			TransferBufferLength++;

		pTxContext->BulkOutSize = TransferBufferLength;
		atomic_inc(&pAdapter->TxCount);
		RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_FRAG);
		RTUSBFreeSkbBuffer(skb);
		return (NDIS_STATUS_SUCCESS);
	}

	if (NdisBufferLength < 14)
	{
		DBGPRINT_RAW(RT_DEBUG_ERROR, "RTUSBHardEncrypt --> Ndis Packet buffer error !!!\n");
		return (NDIS_STATUS_FAILURE);
	}
	if ((*((PUCHAR) pVirtualAddress) & 0x01) != 0)	// Multicast or Broadcast
	{
		INC_COUNTER(pAdapter->WlanCounters.MulticastTransmittedFrameCount);
		Bcast_8023 = TRUE;
	}
	else
	{
		Bcast_8023 = FALSE;
	}

	// New control flag for sending DHCP & BOOTP usinf 1MB rate
	if ((NumberRequired - RTUSB_GET_PACKET_RTS(skb)) == 1)
	{
		SingleFrag = TRUE;
	}
	else
	{
		SingleFrag = FALSE;
	}

	// Add 802.11x protocol check.
	// For non-WPA network, 802.11x message should not encrypt even
	// the privacy is on.
	if ((memcmp(EAPOL, ((PUCHAR) pVirtualAddress) + 12, 2) == 0))
	{
		EAPOLFrame = TRUE;
		if (pAdapter->PortCfg.MicErrCnt >= 2)//steven:???
			pAdapter->PortCfg.MicErrCnt++;
	}
	else
	{
		EAPOLFrame = FALSE;
	}	// Initialize 802.11 header for each frame

	// WPA 802.1x secured port control
	if (((pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || 
		 (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) &&
		((pAdapter->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || 
		 (pAdapter->PortCfg.MicErrCnt >= 2)) &&
		(EAPOLFrame == FALSE))
	{
		DBGPRINT_RAW(RT_DEBUG_INFO, "RTUSBHardEncrypt --> Drop packet before port secured !!!\n");
		return (NDIS_STATUS_FAILURE);
	}		
	
	memset(&Header_802_11, 0, sizeof(HEADER_802_11));
	//
	// Start making 802.11 frame header
	//
	if (INFRA_ON(pAdapter))
	{
		// In BSS mode, AP's address(BSSID) is the destination address of all outgoing packets
		// Address 1 - BSSID
		memcpy(&Header_802_11.Controlhead.Addr1, &pAdapter->PortCfg.Bssid, ETH_LENGTH_OF_ADDRESS);
		// Address 3 - DA
		memcpy(&Header_802_11.Addr3, (PUCHAR) pVirtualAddress, ETH_LENGTH_OF_ADDRESS);
		Header_802_11.Controlhead.Frame.ToDs = 1;
	}
	else 
	{
		// Address 1 - DA
		memcpy(&Header_802_11.Controlhead.Addr1, (PUCHAR) pVirtualAddress, ETH_LENGTH_OF_ADDRESS);
		// Address 3 - BSSID
		memcpy(&Header_802_11.Addr3, &pAdapter->PortCfg.Bssid, ETH_LENGTH_OF_ADDRESS);
	}
	// Address 2 - SA in both infrastructure & ad-hoc modes
	memcpy(&Header_802_11.Controlhead.Addr2, pAdapter->CurrentAddress, ETH_LENGTH_OF_ADDRESS);
	
//	Header_802_11.Sequence = pAdapter->Sequence;		// Sequence number
	Header_802_11.Controlhead.Frame.Type = BTYPE_DATA;	// Frame type
	Header_802_11.Controlhead.Frame.PwrMgt = (pAdapter->PortCfg.Psm == PWR_SAVE);
	
	// For the purpose to calculate duration for the second last fragment
	RemainSize = skb->data_len - LENGTH_802_3 + LENGTH_CRC;

	MICFrag = FALSE;	// Flag to indicate MIC shall spread into two MPDUs
	Encapped = FALSE;
	pEncap = NULL;
	pSrc = (PUCHAR)pVirtualAddress;
	Protocol = *(pSrc + 12) * 256 + *(pSrc + 13);

	if (Protocol > 1500)	// CHeck for LLC encaped
	{
		//
		// Large than 1500 means it's a type field, and thus a D/I/X packet.
		//
		pEncap = SNAP_802_1H;
		Encapped = TRUE;
		if ((memcmp(IPX, pSrc + 12, 2) == 0) || 
		    (memcmp(APPLE_TALK, pSrc + 12, 2) == 0))
		{
			pEncap = SNAP_BRIDGE_TUNNEL;
		}
	}
	else
	{
		//
		//means it's a length field, thus an 802.3 packet
		//And we need to re-calculate the number of Fragment required.
		TotalPacketLength = skb->data_len;
		//
		//means it's a length field, thus an 802.3 packet
		//And we need to re-calculate the number of Fragment required.
		//
		// For TKIP, MIC value is treated as payload, it might be fragmented through
		// different MPDUs.
		if (pAdapter->PortCfg.GroupCipher == Ndis802_11Encryption2Enabled)
		{
			TotalPacketLength = skb->data_len + 8;
		}
		
		// Check for payload allowed for each fragment
		AllowFragSize = (pAdapter->PortCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC;

		// Calculate fragments required
		NumberOfFrag = ((TotalPacketLength - LENGTH_802_3) / AllowFragSize) + 1;
		// Minus 1 if the size just match to allowable fragment size
		if (((skb->data_len - LENGTH_802_3) % AllowFragSize) == 0)
		{
			NumberOfFrag--;
		}

		
		if (NumberOfFrag != RTUSB_GET_PACKET_FRAGMENTS(skb))
		{
			DBGPRINT(RT_DEBUG_TRACE, "Original fragment required = %d, new fragment required = %d\n",
						RTUSB_GET_PACKET_FRAGMENTS(skb), NumberOfFrag);	
			//
			// Update number of Fragment
			//
			RTUSB_SET_PACKET_FRAGMENTS(skb, NumberOfFrag);
			NumberRequired = RTUSB_GET_PACKET_FRAGMENTS(skb) + RTUSB_GET_PACKET_RTS(skb);	
		}		
	}

	//
    // calcuate the overhead bytes that encryption algorithm may add. This
    // affects the calculate of "duration" field
    //
	if ((CipherSuite == Ndis802_11Encryption1Enabled) && 
		(pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0))
		EncryptionOverhead = 8;     // WEP: IV + ICV			
	else if (CipherSuite == Ndis802_11Encryption2Enabled)
		EncryptionOverhead = 12;    // TKIP: IV + EIV + ICV, MIC already added to TotalPacketLength
	else if (CipherSuite == Ndis802_11Encryption3Enabled)
		EncryptionOverhead = 16;    // AES: IV + EIV + Hardware MIC
	else
	    EncryptionOverhead = 0;

	//
	// Make RTS frame if required
	//
	if (RTUSB_GET_PACKET_RTS(skb))
	{
		PCONTROL_HEADER		pControlHeader;
		ULONG				NextFragSize;
		//UINT				RTSFrameSize; //used only to calculate duration
		
		DBGPRINT_RAW(RT_DEBUG_INFO, "Making RTS Frame\n");

		pTxContext  = &pAdapter->TxContext[pAdapter->NextTxIndex];
		pTxContext->InUse   = TRUE;
		pTxContext->LastOne = FALSE;
		
		// Increase & maintain Tx Ring Index
		pAdapter->NextTxIndex++;
		if (pAdapter->NextTxIndex >= TX_RING_SIZE)
		{
			pAdapter->NextTxIndex = 0;
		}

		pTxD  = &(pTxContext->TransferBuffer->TxDesc);
		memset(pTxD, 0, sizeof(TXD_STRUC));
		pDest = pTxContext->TransferBuffer->WirelessPacket;              
				
		pControlHeader = (PCONTROL_HEADER)pDest;
		memset(pControlHeader, 0, sizeof(CONTROL_HEADER));

		//FrameControl
		pControlHeader->Frame.Type    = BTYPE_CNTL;
		if (pAdapter->PortCfg.BGProtectionInUsed == 1)
		{
			pControlHeader->Frame.Subtype = SUBTYPE_CTS;
			memcpy(&pControlHeader->Addr1, pAdapter->CurrentAddress, ETH_LENGTH_OF_ADDRESS);
		}
		else
		{
			pControlHeader->Frame.Subtype = SUBTYPE_RTS;
			// RA
			if (INFRA_ON(pAdapter))
			{
				memcpy(&pControlHeader->Addr1, &pAdapter->PortCfg.Bssid, ETH_LENGTH_OF_ADDRESS);
			}
			else
			{
				memcpy(&pControlHeader->Addr1, (PUCHAR) pVirtualAddress, ETH_LENGTH_OF_ADDRESS);
			}
			// TA
			memcpy(&pControlHeader->Addr2, pAdapter->CurrentAddress, ETH_LENGTH_OF_ADDRESS);
		}

		// Calculate duration = 2 SIFS + CTS + Data Frame size
		if (RTUSB_GET_PACKET_FRAGMENTS(skb) > 1)
		{
			// If fragment required, size is maximum fragment size
			NextFragSize = pAdapter->PortCfg.FragmentThreshold;
		}
		else
		{
			// Size should be frame with 802.11 header & CRC
			NextFragSize = skb->data_len + LENGTH_802_11 + LENGTH_CRC - LENGTH_802_3;

			if (Encapped)
				NextFragSize += LENGTH_802_1_H;
		}
		pControlHeader->Duration = 2 * (pAdapter->PortCfg.Dsifs)
			+ RTUSBCalcDuration(pAdapter, pAdapter->PortCfg.TxRate, NextFragSize + EncryptionOverhead)
			+ AckDuration; 

		// Write Tx descriptor
		// Don't kick tx start until all frames are prepared
		// RTS has to set more fragment bit for fragment burst
		// RTS did not encrypt		
		if (pAdapter->PortCfg.BGProtectionInUsed == 1)
		{
			RTUSBWriteTxDescriptor(pTxD, FALSE, 7, FALSE, FALSE, FALSE, FrameGap, 10, FALSE, 0, CW_MIN_IN_BITS, CW_MAX_IN_BITS, 14, pAdapter->PortCfg.RtsRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
		}
		else
		{
			RTUSBWriteTxDescriptor(pTxD, FALSE, 7, TRUE, FALSE, FALSE, FrameGap, sizeof(CONTROL_HEADER), FALSE, 0, CW_MIN_IN_BITS, CW_MAX_IN_BITS, sizeof(CONTROL_HEADER) + 4, pAdapter->PortCfg.RtsRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
//steven:should we need this?			pTxD->RTS = 1;
		}

		TransferBufferLength = sizeof(CONTROL_HEADER) + sizeof(TXD_STRUC);
		if ((TransferBufferLength % 2) == 1)
			TransferBufferLength++;

		pTxContext->BulkOutSize = TransferBufferLength;

		NumberRequired--;
		//
		// Increase BulkOut stanby count.
		//
		atomic_inc(&pAdapter->TxCount);

		RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NORMAL);
	}
	// Find the WPA key, either Group or Pairwise Key//steven:according to Controlhead.Addr1 (only when AuthMode >= Ndis802_11AuthModeWPA)
	if (pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA)
	{
		INT 	idx;
			
		pWpaKey = (PWPA_KEY) NULL;
		// First lokup the DA, if it's a group address, use GROUP key
		if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01)
		{
			if (pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)
			{
				pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId];
				pWpaKey->Type = GROUP_KEY;
				KeyID = pAdapter->PortCfg.DefaultKeyId;//for Tx descriptor
				DBGPRINT(RT_DEBUG_INFO, "Tx Use Group Key\n");
			}
		}
		// Try to find the Pairwise Key
		else
		{
			for (idx = 0; idx < PAIRWISE_KEY_NO; idx++)
			{
				if (((memcmp(&Header_802_11.Controlhead.Addr1, pAdapter->PortCfg.PairwiseKey[idx].BssId, 6)== 0)) &&
					(pAdapter->PortCfg.PairwiseKey[idx].KeyLen != 0))
				{
					pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[idx];
					pWpaKey->Type = PAIRWISE_KEY;
					KeyID = (UCHAR)idx;
					DBGPRINT(RT_DEBUG_INFO, "Tx Use Pairwise Key\n");
					break;
				}
			}
			// Use default Group Key if there is no Pairwise key present
			if ((pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0) && (pWpaKey == NULL))
			{
				pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId];
				pWpaKey->Type = GROUP_KEY;
				KeyID = pAdapter->PortCfg.DefaultKeyId;//for Tx descriptor
				DBGPRINT(RT_DEBUG_INFO, "Tx Use Group Key\n");
			}
		}
	}

		if (pWpaKey != NULL)
		{
			INT i;
				
			DBGPRINT(RT_DEBUG_INFO, "RTMPHardEncrypt TKIP Key = ");
			for (i = 0; i < 16; i++)
			{
				DBGPRINT_RAW(RT_DEBUG_INFO, "%02x:", pWpaKey->Key[i]);
			}
			DBGPRINT_RAW(RT_DEBUG_INFO, "\n");						
			DBGPRINT(RT_DEBUG_INFO, "RTMPHardEncrypt TKIP TxMic = ");
			for (i = 0; i < 8; i++)
			{
				DBGPRINT_RAW(RT_DEBUG_INFO, "%02x:", pWpaKey->TxMic[i]);
			}
			DBGPRINT_RAW(RT_DEBUG_INFO, "\n");						
			DBGPRINT(RT_DEBUG_INFO, "RTMPHardEncrypt TKIP TxTsc = ");
			for (i = 0; i < 6; i++)
			{
				DBGPRINT_RAW(RT_DEBUG_INFO, "%02x:", pWpaKey->TxTsc[i]);
			}
			DBGPRINT_RAW(RT_DEBUG_INFO, "\n");						
		}

	StartOfFrame = TRUE;
	// Start Copy Ndis Packet into Ring buffer.
	// For frame required more than one ring buffer (fragment), all ring buffers
	// have to be filled before kicking start tx bit.
	do
	{
//		NdisAcquireSpinLock(&pAdapter->TxRingLock);
		// Get the Tx Ring descriptor & Dma Buffer address
		pTxContext  = &pAdapter->TxContext[pAdapter->NextTxIndex];
		pTxContext->InUse   = TRUE;
		pTxContext->LastOne = FALSE;
		
		// Increase & maintain Tx Ring Index
		pAdapter->NextTxIndex++;
		if (pAdapter->NextTxIndex >= TX_RING_SIZE)
		{
			pAdapter->NextTxIndex = 0;
		}
//		NdisReleaseSpinLock(&pAdapter->TxRingLock);

		pTxD  = &(pTxContext->TransferBuffer->TxDesc);
		memset(pTxD, 0, sizeof(TXD_STRUC));
		pDest = pTxContext->TransferBuffer->WirelessPacket;              
		// Maximum allowable payload with one ring buffer, bound by fragment size
		FreeFragSize = pAdapter->PortCfg.FragmentThreshold - LENGTH_CRC;
		
		// Make fragment number & more fragment bit of 802.11 header
		if (StartOfFrame == TRUE)
		{
			Header_802_11.Frag = 0;			// Start of fragment burst / Single Frame
		}
		else
		{
			Header_802_11.Frag++;			// Rest of fragmented frames.
		}
		
		// Turn on with no frames after this one
		if (NumberRequired > 1)
		{
		    ULONG NextFragSize;
//		    ULONG FragSize;
		    
			Header_802_11.Controlhead.Frame.MoreFrag = 1;
			MoreFragment = TRUE;
			
			if (NumberRequired == 2)
			NextFragSize = RemainSize - pAdapter->PortCfg.FragmentThreshold + LENGTH_802_11 + LENGTH_802_11 + LENGTH_CRC;
			else
			    NextFragSize = pAdapter->PortCfg.FragmentThreshold;
			
			Header_802_11.Controlhead.Duration = 3 * pAdapter->PortCfg.Dsifs
				+ 2 * AckDuration
				+ RTUSBCalcDuration(pAdapter, pAdapter->PortCfg.TxRate, NextFragSize + EncryptionOverhead);
		}
		else
		{
			Header_802_11.Controlhead.Frame.MoreFrag = 0;
			MoreFragment = FALSE;
			
			if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01)
			{
				// No ACK expected for multicast frame		
				Header_802_11.Controlhead.Duration = 0;
			}
			else
			{
				// ACK size is 14 include CRC, and its rate is 2Mb
				Header_802_11.Controlhead.Duration = pAdapter->PortCfg.Dsifs + AckDuration;
			}
		}

		// Check for WEP enable bit and prepare for software WEP
		if ((CipherSuite == Ndis802_11Encryption1Enabled) && (EAPOLFrame == FALSE) &&
			(pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0))
		{
			Header_802_11.Controlhead.Frame.Wep = 1;
			Cipher = TRUE;
		}
		else if ((CipherSuite == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL))
		{
			Header_802_11.Controlhead.Frame.Wep = 1;
			Cipher = TRUE;
		}
		else if ((CipherSuite == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL))
		{
			Header_802_11.Controlhead.Frame.Wep = 1;
			Cipher = TRUE;
		}
		else
		{
			Header_802_11.Controlhead.Frame.Wep = 0;
			Cipher = FALSE;
		}
		
		// Copy 802.11 header to Tx ring buffer
		memcpy(pDest, &Header_802_11, sizeof(Header_802_11));
		pDest        += sizeof(Header_802_11);
		FreeFragSize -= sizeof(Header_802_11);

		if ((CipherSuite == Ndis802_11Encryption1Enabled) && (EAPOLFrame == FALSE) &&
			(pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0))
		{
			// Prepare IV, IV offset, Key for Hardware encryption
			RTMPInitWepEngine(
				pAdapter,
				pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].Key,
				pAdapter->PortCfg.DefaultKeyId,
				pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen,
				(PUCHAR) &pTxD->Iv);
			KeyID = pAdapter->PortCfg.DefaultKeyId;
			// Set Iv offset in TxD
			pTxD->IvOffset = LENGTH_802_11;

			memcpy(pDest, &pTxD->Iv, 4);
			pDest += 4;
		}
		else if ((CipherSuite == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL))
		{
			INT		i;

			i = 0;
			// Prepare IV, EIV, IV offset, Key for hardware encryption
			RTMPInitTkipEngine(
				pAdapter,
				pWpaKey->Key,
				pAdapter->PortCfg.DefaultKeyId,		// This might cause problem when using peer key
				Header_802_11.Controlhead.Addr2.Octet,
				pWpaKey->TxMic,
				pWpaKey->TxTsc,
				0,
				&Iv16,
				&Iv32,
				pDest);

			// Increase TxTsc value for next transmission
			while (++pWpaKey->TxTsc[i] == 0x0)
			{
				i++;
				if (i == 6)
					break;
			}
			if (i == 6)
			{
				// TODO: TSC has done one full cycle, do re-keying stuff follow specs
				// Should send a special event microsoft defined to request re-key
			}
			
			// Copy IV
			memcpy(&pTxD->Iv, &Iv16, 4);
			
			// Copy EIV
			memcpy(&pTxD->Eiv, &Iv32, 4);
			
			// Set IV offset
			pTxD->IvOffset = LENGTH_802_11;

			memcpy(pDest, &Iv16, 4);
			pDest += 4;
			memcpy(pDest, &Iv32, 4);
			pDest += 4;
			
		}
		else if ((CipherSuite == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL))
		{
			INT		i;
			PUCHAR	pTmp;

			i = 0;
			pTmp = (PUCHAR) &Iv16;
			*pTmp       = pWpaKey->TxTsc[0];
			*(pTmp + 1) = pWpaKey->TxTsc[1];
			*(pTmp + 2) = 0;
			*(pTmp + 3) = (pAdapter->PortCfg.DefaultKeyId << 6) | 0x20;
			
			Iv32 = *(PULONG)(&pWpaKey->TxTsc[2]);
			
			// Increase TxTsc value for next transmission
			while (++pWpaKey->TxTsc[i] == 0x0)
			{
				i++;
				if (i == 6)
					break;
			}
			if (i == 6)
			{
				// TODO: TSC has done one full cycle, do re-keying stuff follow specs
				// Should send a special event microsoft defined to request re-key
			}
			
			// Copy IV
			memcpy(&pTxD->Iv, &Iv16, 4);
			
			// Copy EIV
			memcpy(&pTxD->Eiv, &Iv32, 4);
			
			// Set IV offset
			pTxD->IvOffset = LENGTH_802_11;

			memcpy(pDest, &Iv16, 4);
			pDest += 4;
			memcpy(pDest, &Iv32, 4);
			pDest += 4;

		}
		
		//
		// Only the first fragment required LLC-SNAP header !!!
		//
		if ((StartOfFrame == TRUE) && (Encapped == TRUE))
		{
			// For WEP & no encryption required frame, just copy LLC header into buffer,
			// Hardware will do the encryption job.
			// For TKIP, we have to calculate MIC and store it first
			if ((CipherSuite == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL))
			{
				// Calculate MSDU MIC Value
				RTMPCalculateMICValue(pAdapter, skb, pEncap, 6, pWpaKey);
			}
			// For WEP & no encryption required frame, just copy LLC header into buffer,
			// Hardware will do the encryption job.
			// For TKIP, we have to calculate MIC and store it first
			
			// Copy LLC header
			memcpy(pDest, pEncap, 6);
			pDest += 6;

			// Copy protocol type
			pSrc = (PUCHAR) pVirtualAddress;
			memcpy(pDest, pSrc + 12, 2);
			pDest += 2;
			
			// Exclude 802.3 header size, we will recalculate the size at
			// the end of fragment preparation.
			NdisBufferLength -= LENGTH_802_3;
			pSrc += LENGTH_802_3;
			FreeFragSize -= LENGTH_802_1_H;
		}
		else if ((StartOfFrame == TRUE) && (Encapped == FALSE))
		{
			if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL))
			{
				// Calculate MSDU MIC Value
				RTMPCalculateMICValue(pAdapter, skb, pEncap, 0, pWpaKey);
			}
			
   			pSrc = (PUCHAR) pVirtualAddress + LENGTH_802_3;
	    		NdisBufferLength -= LENGTH_802_3;
		}
		
		// Start copying payload
		BytesCopied = 0;
		do
		{
			if (NdisBufferLength >= FreeFragSize)
			{
				// Copy only the free fragment size, and save the pointer
				// of current buffer descriptor for next fragment buffer.
				memcpy(pDest, pSrc, FreeFragSize);
				BytesCopied += FreeFragSize;
				pSrc        += FreeFragSize;
				pDest       += FreeFragSize;
				NdisBufferLength      -= FreeFragSize;
				break;
			}
			else
			{
				// Copy the rest of this buffer descriptor pointed data
				// into ring buffer.
				memcpy(pDest, pSrc, NdisBufferLength);
				BytesCopied  += NdisBufferLength;
				pDest        += NdisBufferLength;
				FreeFragSize -= NdisBufferLength;
			}
				// No more buffer descriptor
				// Add MIC value if needed
				if ((CipherSuite == Ndis802_11Encryption2Enabled) && 
					(MICFrag == FALSE) &&
					(pWpaKey != NULL))
				{
					INT i;

					NdisBufferLength = 8;		// Set length to MIC length
					DBGPRINT(RT_DEBUG_INFO, "Calculated TX MIC value = ");  
					for (i = 0; i < 8; i++)
					{
						DBGPRINT_RAW(RT_DEBUG_INFO, "%02x:", pAdapter->PrivateInfo.Tx.MIC[i]);  
					}
					DBGPRINT_RAW(RT_DEBUG_INFO, "\n"); 
								
					if (FreeFragSize >= NdisBufferLength)
					{
						memcpy(pDest, pAdapter->PrivateInfo.Tx.MIC, NdisBufferLength);
						BytesCopied  += NdisBufferLength;
						pDest		 += NdisBufferLength;
						FreeFragSize -= NdisBufferLength;
						NdisBufferLength = 0;
						RemainSize   += 8;	// Need to add MIC as payload
					}
					else
					{
						memcpy(pDest, pAdapter->PrivateInfo.Tx.MIC, FreeFragSize);
						BytesCopied  += FreeFragSize;
						pSrc		  = pAdapter->PrivateInfo.Tx.MIC + FreeFragSize;
						pDest		 += FreeFragSize;
						NdisBufferLength		 -= FreeFragSize;
						MICFrag 	  = TRUE;
						RemainSize   += (8 - FreeFragSize);	// Need to add MIC as payload
					}
				}
		}	while (FALSE);		// End of copying payload
				
		// Real packet size, No 802.1H header for fragments except the first one.
		if ((StartOfFrame == TRUE) && (Encapped == TRUE))
		{
			TxSize = BytesCopied + LENGTH_802_11 + LENGTH_802_1_H;
		}
		else
		{
			TxSize = BytesCopied + LENGTH_802_11;
		}

		RemainSize = RemainSize - BytesCopied;
			
		if ((CipherSuite == Ndis802_11Encryption1Enabled) && (Header_802_11.Controlhead.Frame.Wep == 1))
		{
			// IV + ICV which ASIC added after encryption done
			TxSize += 4;
			PLCPLength = TxSize + 8;
		}
		else if ((CipherSuite == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL))
		{
			// IV + EIV + ICV which ASIC added after encryption done
			TxSize += 8;
			PLCPLength = TxSize + 8;
		}
		else if ((CipherSuite == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL))
		{
			// IV + EIV + HW MIC
			TxSize += 8;
			PLCPLength = TxSize + 12;
		}
		else
		{
			PLCPLength = TxSize + 4;
		}
		DBGPRINT_RAW(RT_DEBUG_INFO, "TxSize = %d, PLCPLength = %d\n", TxSize, PLCPLength);//steven:for debug
				
		// Prepare Tx descriptors before kicking tx.
		// The BBP register index in Tx descriptor has to be configured too.
		if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01)
		{
			INC_COUNTER(pAdapter->WlanCounters.MulticastTransmittedFrameCount);
			// Multicast, retry bit is off
			if (StartOfFrame == TRUE)
			{
				if (RTUSB_GET_PACKET_RTS(skb) != 1)
					RTUSBWriteTxDescriptor(pTxD, FALSE, 0, FALSE, FALSE, TRUE, FrameGap, TxSize, Cipher, KeyID, CW_MIN_IN_BITS, CW_MAX_IN_BITS, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
				else
					RTUSBWriteTxDescriptor(pTxD, FALSE, 0, FALSE, FALSE, TRUE, FrameGap, TxSize, Cipher, KeyID, 0, 0, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
			}
			else
				RTUSBWriteTxDescriptor(pTxD, FALSE, 0, FALSE, FALSE, FALSE, FrameGap, TxSize, Cipher, KeyID, 0, 0, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
		}
		else
		{
			if (StartOfFrame == TRUE)
			{
				if (RTUSB_GET_PACKET_RTS(skb) != 1)
					RTUSBWriteTxDescriptor(pTxD, MoreFragment, 7, TRUE, FALSE, TRUE, FrameGap, TxSize, Cipher, KeyID, CW_MIN_IN_BITS, CW_MAX_IN_BITS, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
				else
					RTUSBWriteTxDescriptor(pTxD, MoreFragment, 7, TRUE, FALSE, TRUE, FrameGap, TxSize, Cipher, KeyID, 0, 0, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
			}
			else
				RTUSBWriteTxDescriptor(pTxD, MoreFragment, 7, TRUE, FALSE, FALSE, FrameGap, TxSize, Cipher, KeyID, 0, 0, PLCPLength, pAdapter->PortCfg.TxRate, 4, pAdapter->PortCfg.TxPreambleInUsed);
		}

		TransferBufferLength = TxSize + sizeof(TXD_STRUC);
		if ((TransferBufferLength % 2) == 1)//always bulk out even number of bytes
			TransferBufferLength++;
		if ((TransferBufferLength % pAdapter->BulkOutMaxPacketSize) == 0)
			TransferBufferLength += 2;

		pTxContext->BulkOutSize = TransferBufferLength;
		RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NORMAL);
		
		// Set frame gap for the rest of fragment burst.
		// It won't matter if there is only one fragment (single fragment frame).
		StartOfFrame = FALSE;
		NumberRequired--;
		if (NumberRequired == 0)
		{
			pTxContext->LastOne = TRUE;
		}
		else
		{
			pTxContext->LastOne = FALSE;
		}
//steven:use ASIC counters to derive this count instead		INC_COUNTER(pAdapter->WlanCounters.TransmittedFragmentCount);
		//
		// Increase BulkOut stanby count.
		//		
		atomic_inc(&pAdapter->TxCount);
	}	while (NumberRequired > 0);

#if 0
	// Add duplicate 1mb broadcast frames
	do
	{
		if ((pAdapter->PortCfg.TxRate != RATE_1) && (Bcast_8023 == TRUE) && (SingleFrag == TRUE))
		{
			PTX_CONTEXT		pTmpContext;
			PTXD_STRUC		pTmpTxD;
			ULONG			DataOffset = 0;

			pSrc = pTxContext->TransferBuffer->WirelessPacket;
			//
			// Check the offset of the original 802.3 data packet
			//
			if (CipherSuite == Ndis802_11EncryptionDisabled)
				DataOffset = 0;
			else if (CipherSuite == Ndis802_11Encryption1Enabled)
				DataOffset += 4; //Add IV
			else if (CipherSuite == Ndis802_11Encryption2Enabled)
				DataOffset += 8; //Add EIV
			else if (CipherSuite == Ndis802_11Encryption3Enabled)	
				DataOffset += 8; //Add EIV
				
			// Check for DHCP & BOOTP protocol
			if ((*(pSrc + 0x35 + DataOffset) != 0x44) || (*(pSrc + 0x37 + DataOffset) != 0x43))
			{
				// 
				// 2054 (hex 0806) for ARP datagrams
				// if this packet is not ARP datagrams, then do nothing
				// ARP datagrams will also be duplicate at 1mb broadcast frames
				//
				if (Protocol != 0x0806 )
					break;
			}

			// Get the Tx Ring descriptor & Dma Buffer address
			pTmpContext = &pAdapter->TxContext[pAdapter->NextTxIndex];
			pDest = pTmpContext->TransferBuffer->WirelessPacket;
			
			if (pTmpContext->InUse == TRUE)
				break;  //No available Tx Ring for Send 1mb broadcast frames.

			// Increase & maintain Tx Ring Index
			pAdapter->NextTxIndex++;
			if (pAdapter->NextTxIndex >= TX_RING_SIZE)
			{
				pAdapter->NextTxIndex = 0;
			}
			
			//
			// Reset LastOne Tx Ring descriptor
			//
			pTmpContext->InUse   = TRUE;
			pTmpContext->LastOne = TRUE;

			pTmpTxD  = &(pTmpContext->TransferBuffer->TxDesc);
			//
			// Duplicate TxD descriptor, and we will reset the its value later.
			//
			memcpy(pTmpTxD, pTxD, sizeof(TXD_STRUC));
			// Start coping data to new ring 
			memcpy(pDest, pSrc, pTxContext->BulkOutSize);
			pTmpContext->BulkOutSize = pTxContext->BulkOutSize;
			RTUSBWriteTxDescriptor(pTmpTxD, FALSE, 7, TRUE, FALSE, FALSE, FrameGap, TxSize, Cipher, KeyID, 0, 0, PLCPLength, RATE_1, 4, pAdapter->PortCfg.TxPreambleInUsed);	
			//
			// Increase BulkOut stanby count.
			//			
			atomic_inc(&pAdapter->TxCount);
			DBGPRINT(RT_DEBUG_TRACE, "Send 1M broadcast frame!\n");
		}
	} while (FALSE);
#endif

	// Acknowledge protocol send complete of pending packet.
	RTUSBFreeSkbBuffer(skb);
	return (NDIS_STATUS_SUCCESS);

}

VOID RTUSBRxPacket(unsigned long data)
//VOID RTUSBRxPacket(purbb_t pUrb)
{
	//PRT2570ADAPTER pAdapter = (PRT2570ADAPTER)data;
	purbb_t pUrb = (purbb_t)data;
	PRT2570ADAPTER pAdapter;
	PRX_CONTEXT pRxContext;
	PRXD_STRUC		pRxD;
	NDIS_STATUS		Status;
	PHEADER_802_11	pHeader;
	PUCHAR			pData;
	PUCHAR			pDestMac, pSrcMac;
	UCHAR			KeyIdx;
	ULONG			i;
	UINT			PacketSize = 0;
	PUCHAR			pEncap;
	UCHAR			LLC_Len[2];
	UCHAR			Header802_3[14];
	PWPA_KEY		pWpaKey = NULL;
	// To indicate cipher used for this packet
	NDIS_802_11_ENCRYPTION_STATUS	Cipher;
	struct sk_buff  *skb;
	PVOID			pManage;
	wlan_ng_prism2_header	*ph;

	pRxContext= (PRX_CONTEXT)pUrb->context;
	pAdapter = pRxContext->pAdapter;
	
	if( RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS) )
		return;

	do
	{
		if (pRxContext->pUrb->actual_length >= (sizeof(RXD_STRUC) + LENGTH_802_11))//blue
		{
			pData = pRxContext->TransferBuffer;
			pManage = (PVOID) pData;

			pRxD = (PRXD_STRUC)(pData + pRxContext->pUrb->actual_length - sizeof(RXD_STRUC));
			pHeader	= (PHEADER_802_11)pData;
			

			if (pRxD->DataByteCnt < 4)
				Status = NDIS_STATUS_FAILURE;
			else
			{
				pAdapter->PortCfg.Pss = PWR_ACTIVE;

				// Increase Total receive byte counter after real data received no mater any error or not
				pAdapter->RalinkCounters.ReceivedByteCount += (pRxD->DataByteCnt - 4);

				// Check for all RxD errors
				Status = RTMPCheckRxDescriptor(pAdapter, pRxD);
			}

			/* Only recieve valid packets in to monitor mode */
			if (pAdapter->PortCfg.BssType == BSS_MONITOR && Status == NDIS_STATUS_SUCCESS)
         		{
 	        		struct sk_buff  *skb;
 	       			if ((skb = __dev_alloc_skb(2048, GFP_DMA|GFP_ATOMIC)) != NULL)
 	        		{
					if (pAdapter->PortCfg.MallowRFMONTx == TRUE)
						goto rfmontx_80211_receive;

					// setup the wlan-ng prismheader

					if (skb_headroom(skb) < sizeof(wlan_ng_prism2_header))
						pskb_expand_head(skb, sizeof(wlan_ng_prism2_header), 0, GFP_ATOMIC);

					ph = (wlan_ng_prism2_header *)
						skb_push(skb, sizeof(wlan_ng_prism2_header));
					memset(ph, 0, sizeof(wlan_ng_prism2_header));

					ph->msgcode	= DIDmsg_lnxind_wlansniffrm;
					ph->msglen	= sizeof(wlan_ng_prism2_header);
					strcpy(ph->devname, pAdapter->net->name);

					ph->hosttime.did	= DIDmsg_lnxind_wlansniffrm_hosttime;
					ph->mactime.did		= DIDmsg_lnxind_wlansniffrm_mactime;
					ph->channel.did		= DIDmsg_lnxind_wlansniffrm_channel;
					ph->rssi.did		= DIDmsg_lnxind_wlansniffrm_rssi;
					ph->signal.did		= DIDmsg_lnxind_wlansniffrm_signal;
					ph->noise.did		= DIDmsg_lnxind_wlansniffrm_noise;
					ph->rate.did		= DIDmsg_lnxind_wlansniffrm_rate;
					ph->istx.did		= DIDmsg_lnxind_wlansniffrm_istx;
					ph->frmlen.did		= DIDmsg_lnxind_wlansniffrm_frmlen;

					ph->hosttime.len	= 4;
					ph->mactime.len		= 4;
					ph->channel.len		= 4;
					ph->rssi.len		= 4;
					ph->signal.len		= 4;
					ph->noise.len		= 4;
					ph->rate.len		= 4;
					ph->istx.len		= 4;
					ph->frmlen.len		= 4;
		
					ph->hosttime.data	= jiffies;
					ph->channel.data	= pAdapter->PortCfg.IbssConfig.Channel;
					ph->signal.data		= pRxD->BBR1;
					ph->noise.data		= pAdapter->PortCfg.LastR17Value;
					ph->rssi.data		= ph->signal.data - ph->noise.data;
					ph->frmlen.data		= pRxD->DataByteCnt;

					if (pRxD->Ofdm == 1)
					{
						for (i = 4; i < 12; i++)
							if (pRxD->BBR0 == PlcpSignal[i])
								ph->rate.data = _11G_RATES[i] * 2;
					}
					else
						ph->rate.data = pRxD->BBR0 / 5;

					// end prismheader setup

				rfmontx_80211_receive:

 	      				skb->dev = pAdapter->net;
 	      				memcpy(skb_put(skb, pRxD->DataByteCnt-4), pData, pRxD->DataByteCnt-4);
 	       				skb->mac.raw = skb->data;
 	      				skb->pkt_type = PACKET_OTHERHOST;
 	     				skb->protocol = htons(ETH_P_802_2);
 	        			skb->ip_summed = CHECKSUM_NONE;
 	                		netif_rx(skb);
 	            		}	
                   	
				if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
				RTUSBBulkReceive(pAdapter);
         			continue;
			}
			
			if (Status == NDIS_STATUS_SUCCESS)
			{
				// Apply packet filtering rule based on microsoft requirements.
				Status = RTMPApplyPacketFilter(pAdapter, pRxD, pHeader);
			}	
		
			// Add receive counters
			if (Status == NDIS_STATUS_SUCCESS)
			{
				// Increase 802.11 counters & general receive counters
				INC_COUNTER(pAdapter->WlanCounters.ReceivedFragmentCount);
			}
			else
			{
				// Increase general counters
				pAdapter->Counters.RxErrors++;
			}
			

			// Check for retry bit, if this bit is on, search the cache with SA & sequence
			// as index, if matched, discard this frame, otherwise, update cache
			// This check only apply to unicast data & management frames
			if ((pRxD->U2M) && (Status == NDIS_STATUS_SUCCESS) && (pHeader->Controlhead.Frame.Type != BTYPE_CNTL))
			{
				if (pHeader->Controlhead.Frame.Retry)
				{
					if (RTMPSearchTupleCache(pAdapter, pHeader) == TRUE)
					{
						// Found retry frame in tuple cache, Discard this frame / fragment
						// Increase 802.11 counters
						INC_COUNTER(pAdapter->WlanCounters.FrameDuplicateCount);
						DBGPRINT_RAW(RT_DEBUG_INFO, "duplicate frame\n");//steven:for debug
						Status = NDIS_STATUS_FAILURE;
					}
					else
					{
						RTMPUpdateTupleCache(pAdapter, pHeader);
					}
				}
				else	// Update Tuple Cache
				{
					RTMPUpdateTupleCache(pAdapter, pHeader);
				}
			}
			
			// Check and set the cipher variable
			if (pRxD->U2M)
				Cipher = pAdapter->PortCfg.PairCipher;
			else
				Cipher = pAdapter->PortCfg.GroupCipher;		
				Cipher = pAdapter->PortCfg.WepStatus;

			//
			// Do RxD release operation	for	all	failure	frames
			//
			if (Status == NDIS_STATUS_SUCCESS)
			{
				//
				// Start of	main loop to parse receiving frames.
				// The sequence	will be	Type first,	then subtype...
				//
				switch (pHeader->Controlhead.Frame.Type)
					{
						// Frame with data type
						case BTYPE_DATA:
							// pData : Pointer skip	the	first 24 bytes,	802.11 HEADER
							pData += LENGTH_802_11;

							PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 4;	 //Minus FCS[4].  default for NoneWep.
							// Drop not my BSS frame
							if (INFRA_ON(pAdapter))
							{
								// Infrastructure mode, check address 2 for BSSID
								if (memcmp(&pHeader->Controlhead.Addr2, &pAdapter->PortCfg.Bssid, 6) != 0)
									break;	// Receive frame not my BSSID
								else
									atomic_inc(&(pAdapter->PortCfg.DataPacketsFromAP));
							}
							else	// Ad-Hoc mode or Not associated
							{
								// Ad-Hoc mode, check address 3 for BSSID
								if (memcmp(&pHeader->Addr3, &pAdapter->PortCfg.Bssid, 6) != 0)
									break;	// Receive frame not my BSSID

								// Drop frame from AP while we are in Ad-hoc mode or not associated
								if (pHeader->Controlhead.Frame.FrDs)
									break;
							}

							// Drop Null data frame, or CF with NULL data frame
							if ((pHeader->Controlhead.Frame.Subtype == SUBTYPE_NULL_FUNC) ||
								(pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFACK)     ||
								(pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFPOLL)    ||
								(pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFACK_CFPOLL))
							{
								break;
							}

							// Process Broadcast & Multicast data frame
							if (pRxD->Bcast || pRxD->Mcast)
							{
								// Multicast 802.11 Counter
								INC_COUNTER(pAdapter->WlanCounters.MulticastReceivedFrameCount);
								DBGPRINT(RT_DEBUG_INFO,"Receiving multicast frame\n");
								// Drop Mcast / Bcast frame with fragment bit on
								if (pHeader->Controlhead.Frame.MoreFrag)
								{
									DBGPRINT_RAW(RT_DEBUG_ERROR,"Receiving multicast frame with fragment bit on\n");							
									break;
								}	
								
								// Filter out Bcast frame which AP relayed for us
								if (((memcmp(&pHeader->Addr3, pAdapter->CurrentAddress, 6) == 0)) && pHeader->Controlhead.Frame.FrDs)
									break;
								
								// WEP encrypted frame
								if (pHeader->Controlhead.Frame.Wep)
								{
									// Check our WEP setting, if no WEP turning on, just drop this frame
									if (Cipher == Ndis802_11Encryption1Enabled)	// WEP
									{
										if (pRxD->CiErr)
											break;
										else
										{
											pData = pData + 4;  //Offset skip IV[4]
											pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //Minus ICV[4] & FCS[4].
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 4;	//Minus IV[4].
									}
									else if (Cipher == Ndis802_11Encryption2Enabled)	// TKIP
									{
										if (pRxD->CiErr)
											{
									DBGPRINT_RAW(RT_DEBUG_ERROR,"pRxD->CiErr\n");							
											break;
											}
										else
										{
											pData = pData + 8; //Offset skip IV[8]
											//
											// the MIC is stored on the last one no more Fragment.
											// that is only last MPDU only need to check MIC.
											//
											if (pHeader->Controlhead.Frame.MoreFrag == TRUE)
											{									
												// No MIC here.
												pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //ICV[4] &FCS[4].
											}
											else
											{
												if (pHeader->Frag != 0)
													pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //MIC been frag ICV[4] & FCS[4]
												else										
													pRxD->DataByteCnt = pRxD->DataByteCnt - 16; //Minus MIC[8] & ICV[4] &FCS[4].
											}								
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 8;	//Minus IV+EIV[8].
									}
									else if (Cipher == Ndis802_11Encryption3Enabled)	// AES
									{
										if (pRxD->CiErr)
											break;
										else
										{
											pData = pData + 8; //Offset skip RSN[8]
											pRxD->DataByteCnt = pRxD->DataByteCnt - 12;  //Minus MIC[8] & ICV[4]
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 8;	//Minus RSN[8]
									}
									else
										break;
								}
							}//if (pRxD->Bcast || pRxD->Mcast)				
							// Begin process unicast to	me frame
							else if	(pRxD->U2M)
							{					
								//
								// Begin frame processing
								//
								// DA is always	address	1
								pDestMac = (PUCHAR)	&(pHeader->Controlhead.Addr1);
								// Seclect SA by different mode
								if (INFRA_ON(pAdapter))		// For infrastructure, SA is address 3
								{
									pSrcMac	= (PUCHAR) &(pHeader->Addr3);
								}
								else									// For IBSS	mode, SA is	address	2
								{
									pSrcMac	= (PUCHAR) &(pHeader->Controlhead.Addr2);
								}
								// WEP encrypted frame
								if (Cipher == Ndis802_11Encryption1Enabled)	// WEP
								{
									if (pHeader->Controlhead.Frame.Wep)
									{
										if (pRxD->CiErr)
											break;
										else
										{
											pData = pData + 4; //Offset skip IV[4]
											pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //Minus ICV[4] & FCS[4].
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 4;	//Minus IV[4].
									}
									else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) &&
											 (pHeader->Frag == 0))
									{
										// Check 802.1x frame, if not drop it.
										if (memcmp(EAPOL, pData + 6, 2))
										{
											// Not 802.1X frames
											// Add error counter
											break;
										}							
									}						
								}
								else if (Cipher == Ndis802_11Encryption2Enabled)	// TKIP
								{
									if (pHeader->Controlhead.Frame.Wep)
									{
										if (pRxD->CiErr)
											{										
								DBGPRINT(RT_DEBUG_TEMP,"pRxD->CiErr\n");
											break;


											}
										else
										{
											pData = pData + 8;  //Offset skip IV[8]
											//
											// the MIC is stored on the last one no more Fragment.
											// that is only last MPDU only need to check MIC.
											//
											if (pHeader->Controlhead.Frame.MoreFrag == TRUE)
											{
												//No MIC here.
												pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //ICV[4] &FCS[4].
											}
											else
											{
												if (pHeader->Frag != 0)
													pRxD->DataByteCnt = pRxD->DataByteCnt - 8; //MIC been frag ICV[4] & FCS[4]
												else
													pRxD->DataByteCnt = pRxD->DataByteCnt - 16; //Minus MIC[8] & ICV[4] & FCS[4].
											}
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 8;	//Minus IV+EIV[8].
									}
									else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) &&
											 (pHeader->Frag == 0))
									{
										// Check 802.1x frame, if not drop it.
										if (memcmp(EAPOL, pData + 6, 2) != 0)
										{
								DBGPRINT(RT_DEBUG_TEMP,"Not 802.1X frames\n");
											// Not 802.1X frames
											// Add error counter
											break;
										}
										DBGPRINT(RT_DEBUG_TEMP," 802.1X EAPOL frames\n");
									}
								}
								else if (Cipher == Ndis802_11Encryption3Enabled)	// AES
								{
									if (pHeader->Controlhead.Frame.Wep)
									{
										if (pRxD->CiErr)
											break;
										else
										{
											pData = pData + 8; //Offset skip IV[8]
											pRxD->DataByteCnt = pRxD->DataByteCnt - 12;  //Minus MIC[8] & ICV[4]
										}

										PacketSize = pRxD->DataByteCnt - LENGTH_802_11 - 8;	//Minus RSN[8]
									}
									else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) &&
											 (pHeader->Frag == 0))
									{
										// Check 802.1x frame, if not drop it.
										if (memcmp(EAPOL, pData + 6, 2) != 0)
										{
											// Not 802.1X frames
											// Add error counter
											break;
										}
									}
								}
								else if (pHeader->Controlhead.Frame.Wep)
								{
									// Drop WEP frame when PrivacyInvoked is FALSE
									break;
								}						
							}//else if	(pRxD->U2M)
			
							// The total available payload should exclude 24-byte 802.11 Header
							//packetSize = pRxD->DataByteCnt - LENGTH_802_11 - 4;					

							// Find the WPA key, either Group or Pairwise Key
							// Although the data has been decrypted by ASIC,
							// driver has to calculate the RxMIC which required the key.
							// The failed case should not happen. If it did, drop it.
							if ((pAdapter->PortCfg.CipherAlg == CIPHER_TKIP) && (pHeader->Controlhead.Frame.Wep))
							{
								INT 	idx;

								pWpaKey = (PWPA_KEY) NULL;
								// First lookup the DA, if it's a group address, use GROUP key
								if (pRxD->Bcast || pRxD->Mcast)
								{
#ifdef BIG_ENDIAN
									idx = (pRxD->Iv & 0xc0000000) >> 30;
#else
									idx = (pRxD->Iv & 0x000000c0) >> 6;
#endif
									if ((pAdapter->PortCfg.GroupKey[idx].KeyLen != 0) && 
										((INFRA_ON(pAdapter) && ((memcmp(&pHeader->Controlhead.Addr2, &pAdapter->PortCfg.Bssid, 6) == 0))) ||
										(ADHOC_ON(pAdapter) && ((memcmp(&pHeader->Addr3, &pAdapter->PortCfg.Bssid, 6) == 0)))))
									{
										pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[idx];
										pWpaKey->Type = GROUP_KEY;
										DBGPRINT(RT_DEBUG_INFO, "Rx Use Group Key %d\n", idx);
									}
								}
								// Try to find the Pairwise Key
								else
								{
									for (idx = 0; idx < PAIRWISE_KEY_NO; idx++)
									{
										if (((memcmp(&pHeader->Controlhead.Addr2, pAdapter->PortCfg.PairwiseKey[idx].BssId, 6) == 0)) &&
											(pAdapter->PortCfg.PairwiseKey[idx].KeyLen != 0))
										{
											pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[idx];
											pWpaKey->Type = PAIRWISE_KEY;
											DBGPRINT(RT_DEBUG_LOUD, "Rx Use Pairwise Key %d\n",idx);
											break;
										}
									}
									// Use default Group Key if there is no Pairwise key present
									if ((pWpaKey == NULL) && (pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0))
									{
										pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId];
										pWpaKey->Type = GROUP_KEY;
										DBGPRINT(RT_DEBUG_INFO, "Rx Use Group Key\n");
									}
								}
								
								if (pWpaKey == NULL)
									break;
							}

							// DA is always address 1
							pDestMac = (PUCHAR) &(pHeader->Controlhead.Addr1);
							// Seclect SA by different mode
							if (INFRA_ON(pAdapter))
							{
								// For infrastructure, SA is address 3
								pSrcMac = (PUCHAR) &(pHeader->Addr3);
							}
							else
							{
								// For IBSS mode, SA is address 2
								pSrcMac = (PUCHAR) &(pHeader->Controlhead.Addr2);
							}
			
							// Process Broadcast & Multicast data frame
							if (pRxD->Bcast || pRxD->Mcast)
							{							
								// Save encapaturation starting pointer
								pEncap = pData;

								// For TKIP frame, calculate the MIC value
								if ((pAdapter->PortCfg.CipherAlg == CIPHER_TKIP) && (pHeader->Controlhead.Frame.Wep))
								{
									i = 0;

									if (RTMPTkipCompareMICValue(pAdapter,															
																pData,
																pDestMac,
																pSrcMac,
																pWpaKey->RxMic,
																PacketSize) == FALSE)
									{
										DBGPRINT_RAW(RT_DEBUG_ERROR,"BroadCast/Multicast Rx MIC Value error\n");
										RTMPReportMicError(pAdapter, pWpaKey);
										Status = NDIS_STATUS_FAILURE;
										break;
									}

									// Second, increase RxTsc value for next transmission
									while (++pWpaKey->RxTsc[i] == 0x0)
									{
										i++;
										if (i == 6)
											break;
									}
									// Rx TSC has done one full cycle, since re-key is done by transmitter
									// We did not do anything for Rx path
								}
								// For WPA2 mixer mode PairCipher = AES, GroupCipher = TKIP
								else if ((pAdapter->PortCfg.PairCipher  == Ndis802_11Encryption3Enabled) && 
										 (pAdapter->PortCfg.GroupCipher == Ndis802_11Encryption2Enabled) &&
										 (pHeader->Controlhead.Frame.Wep))
								{
									//Use Software to decript TKIP packet.
									if (RTMPSoftDecryptTKIP(pAdapter, pRxContext->TransferBuffer, pRxD->DataByteCnt + 12, pAdapter->PortCfg.GroupKey))
									{
										DBGPRINT(RT_DEBUG_INFO, "WPA2::RTMPSoftDecryptTKIP Complete\n");
										pData = pRxContext->TransferBuffer + LENGTH_802_11;
										PacketSize = pRxD->DataByteCnt - 8 - LENGTH_802_11;  //8 bytes MIC, 4 bytes ICV
										pEncap = pData;								
									}
								}
							
								// Check for encapsulataion other than RFC1042 & Bridge tunnel
								if ((memcmp(SNAP_802_1H, pEncap, 6) != 0) && (memcmp(SNAP_BRIDGE_TUNNEL, pEncap, 6) != 0))
								{
									LLC_Len[0] = PacketSize / 256;
									LLC_Len[1] = PacketSize % 256;
									MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len));
								}
								else
								{
									// Remove 802.11 H header & reconstruct 802.3 header
									pData += (LENGTH_802_1_H - LENGTH_802_3_TYPE);
									// Patch for WHQl only, which did not turn on Netbios but use IPX within its payload
									if (((memcmp(IPX, pData, 2) == 0) || (memcmp(APPLE_TALK, pData, 2) == 0)) && (memcmp(SNAP_802_1H, pEncap, 6) == 0))
									{
										LLC_Len[0] = PacketSize / 256;
										LLC_Len[1] = PacketSize % 256;
										pData = pData - LENGTH_802_1_H;
										MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len));
									}
									else
									{
										MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, pData);
										// The total available payload should exclude 24-byte 802.11 Header
										// and 8-byte 802.2 LLC
										PacketSize -= LENGTH_802_1_H;
									}
								
									// Point to read 802.3 payload
									pData += LENGTH_802_3_TYPE;
								}
			
								// For miniportTransferData
								pAdapter->pRxData = pData;

								pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; // for RX ACTIVITY LED

								// Acknolwdge upper layer the received frame
								// Copy header to head of data for compatibility with older protocol
								// eariler than W2K
								//memcpy(pData - LENGTH_802_3, Header802_3, LENGTH_802_3);
								// Acknowledge upper layer the received frame
								if ((skb = dev_alloc_skb(PacketSize + LENGTH_802_3 + 2)) != NULL)
								{
								    skb->dev = pAdapter->net;
								    skb_reserve(skb, 2);    // 16 byte align the IP header
								    memcpy(skb_put(skb, LENGTH_802_3), Header802_3, LENGTH_802_3);
								    memcpy(skb_put(skb, PacketSize), pData, PacketSize);
								    skb->protocol = eth_type_trans(skb, pAdapter->net);
								    netif_rx(skb);
								    pAdapter->net->last_rx = jiffies;
								    pAdapter->netstats.rx_packets++;
								}
								//memset(Header802_3, 0, LENGTH_802_3);
								DBGPRINT_RAW(RT_DEBUG_INFO, "!!! Broadcast Ethernet rx Indicated !!!\n");
							} //if (pRxD->Bcast || pRxD->Mcast)											
							// Begin process unicast to me frame
							else if (pRxD->U2M) 
							{
								// Update Rx data rate first.
								if (pRxD->Ofdm == 1)
								{
									for (i = 4; i < 12; i++)
									{
										if (pRxD->BBR0 == PlcpSignal[i])
											break;
									}
									if (i < 12)
										pAdapter->LastRxRate = i;
								}
								else	// receive CCK encoding
								{
									if (pRxD->BBR0 == 10)
										pAdapter->LastRxRate = 0;
									else if (pRxD->BBR0 == 20)
										pAdapter->LastRxRate = 1;
									else if (pRxD->BBR0 == 55)
										pAdapter->LastRxRate = 2;
									else if (pRxD->BBR0 == 110)
										pAdapter->LastRxRate = 3;
								}

								// Send PS-Poll for AP to send next data frame					
								if ((pHeader->Controlhead.Frame.MoreData) && INFRA_ON(pAdapter) && (pAdapter->PortCfg.Psm == PWR_SAVE))
								{
									//Send PS-Poll frame
									EnqueuePsPoll(pAdapter);
									DBGPRINT(RT_DEBUG_TRACE, "Sending PS-POLL\n");
								}

								//
								// Begin frame processing
								//
								if (pHeader->Frag == 0) // First or Only fragment
								{
									// For TKIP frame, calculate the MIC value
									if (pHeader->Controlhead.Frame.MoreFrag == FALSE)
									{
										if ((pAdapter->PortCfg.CipherAlg == CIPHER_TKIP) && (pHeader->Controlhead.Frame.Wep))
										{
											//
											// Use Software to descrypt if transmition keyID not 0 on ADHOC mode.
											// Since ASIC allows hardware descrypt only KeyID=0 as their pairwisekey.
											//
											// Check U2M and KeyID not pairwise key, used Software decypt 
											//
											KeyIdx= *((PUCHAR)(pRxContext->TransferBuffer + LENGTH_802_11 + 3));
											KeyIdx = KeyIdx >> 6;

											if(KeyIdx != 0)
											{
												//Use Software to decript TKIP packet.
												if (RTMPSoftDecryptTKIP(pAdapter, pRxContext->TransferBuffer, pRxD->DataByteCnt + 12, pAdapter->PortCfg.GroupKey))
												{
													DBGPRINT(RT_DEBUG_TEMP, "U2M Use Groupkey RTMPSoftDecryptTKIP Complete\n");
													pData = pRxContext->TransferBuffer + LENGTH_802_11;
													PacketSize = pRxD->DataByteCnt - 8 - LENGTH_802_11;  //8 bytes MIC, 4 bytes ICV
												}
												else
												{
													DBGPRINT(RT_DEBUG_TEMP, "RTMPSoftDecryptTKIP failed\n");
													break;
												}
											}
											else
											{
												if (RTMPTkipCompareMICValue(pAdapter,																		
																			pData,
																			pDestMac,
																			pSrcMac,
																			pWpaKey->RxMic,//steven:where is this from in RT2570
																			PacketSize) == FALSE)
												{
													DBGPRINT_RAW(RT_DEBUG_ERROR,"U2M Rx MIC Value error1\n");
													RTMPReportMicError(pAdapter, pWpaKey);
													Status = NDIS_STATUS_FAILURE;
													break;
												}
											}

											// TODO:
											// Getting RxTSC from Rx descriptor
										}
									}
									
									// Save encapaturation starting pointer
									pEncap = pData;								
									pAdapter->FragFrame.Flags &= 0xFFFFFFFE;
									
									// Check for encapsulataion other than RFC1042 & Bridge tunnel
									if ((memcmp(SNAP_802_1H, pEncap, 6) != 0) && (memcmp(SNAP_BRIDGE_TUNNEL, pEncap, 6) != 0))
									{
										LLC_Len[0] = PacketSize / 256;
										LLC_Len[1] = PacketSize % 256;
										MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len));
									}
									else
									{
										// Remove 802.11 H header & reconstruct 802.3 header
										pData += (LENGTH_802_1_H - LENGTH_802_3_TYPE);
								if ((memcmp(EAPOL, pData, 2) == 0))
								{
									PacketSize += LENGTH_802_11;
							DBGPRINT_RAW(RT_DEBUG_TEMP, "indicated packet EAPOL  PacketSize%d\n", PacketSize);//steven:for debug
									// Enqueue this frame to MLME engine
									MlmeEnqueueForRecv(
										pAdapter,
										&pAdapter->Mlme.Queue,	
										(UCHAR)pRxD->BBR1, 
										PacketSize + LENGTH_802_1_H, 
										pManage);					
									break;
								}
										// Patch for WHQl only, which did not turn on Netbios but use IPX within its payload
										if ((((memcmp(IPX, pData, 2) == 0) || (memcmp(APPLE_TALK, pData, 2) == 0)) && memcmp(SNAP_802_1H, pEncap, 6) == 0))
										{
											LLC_Len[0] = PacketSize / 256;
											LLC_Len[1] = PacketSize % 256;
											pData = pData - LENGTH_802_1_H;
											MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len));
										}
										else
										{
												
											MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, pData);
											// The total available payload should exclude 24-byte 802.11 Header
											// and 8-byte 802.2 LLC
											PacketSize -= LENGTH_802_1_H;
											memcpy(pAdapter->FragFrame.Header_LLC, pEncap, 8);
											pAdapter->FragFrame.Flags |= 0x01;
										}
										
										// Point to read 802.3 payload
										pData += LENGTH_802_3_TYPE;								
									}
										
									// One & The only fragment
									if (pHeader->Controlhead.Frame.MoreFrag == FALSE)
									{
										// For miniportTransferData
										pAdapter->pRxData = pData;

										pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; // for RX ACTIVITY LED

										DBGPRINT_RAW(RT_DEBUG_INFO, "indicated packet size = %d\n", PacketSize);//steven:for debug
										// Acknolwdge upper layer the received frame
										//memcpy((PUCHAR) pData - LENGTH_802_3, Header802_3, LENGTH_802_3);

										if ((skb = dev_alloc_skb(PacketSize + LENGTH_802_3 + 2)) != NULL)
										{
										    skb->dev = pAdapter->net;
										    skb_reserve(skb, 2);    // 16 byte align the IP header
										    memcpy(skb_put(skb, LENGTH_802_3), Header802_3, LENGTH_802_3);
										    memcpy(skb_put(skb, PacketSize), pData, PacketSize);
										    skb->protocol = eth_type_trans(skb, pAdapter->net);
										    netif_rx(skb);
										    pAdapter->net->last_rx = jiffies;
										    pAdapter->netstats.rx_packets++;
										}
										// Increase general counters
										pAdapter->Counters.GoodReceives++;

										DBGPRINT_RAW(RT_DEBUG_INFO, "!!! Frame without Fragment Indicated	!!!\n");
									}
									// First fragment of fragmented frames
									else
									{
										memcpy(pAdapter->FragFrame.Buffer,	pData, PacketSize);
										memcpy(pAdapter->FragFrame.Header802_3, Header802_3, LENGTH_802_3);
										pAdapter->FragFrame.RxSize	 = PacketSize;
										pAdapter->FragFrame.Sequence = pHeader->Sequence;
										pAdapter->FragFrame.LastFrag = pHeader->Frag;		// Should be 0
									}
								}
								// Middle & End of fragment burst fragments
								else
								{
									// No LLC-SNAP header in except the first fragment frame

									if ((pHeader->Sequence != pAdapter->FragFrame.Sequence) ||
										(pHeader->Frag != (pAdapter->FragFrame.LastFrag + 1)))
									{
										// Fragment is not the same sequence or out of fragment number order
										// Clear Fragment frame contents
										memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME));
										Status = NDIS_STATUS_FAILURE;
										break;
									}	
									else if ((pAdapter->FragFrame.RxSize + PacketSize) > MAX_FRAME_SIZE)
									{
										// Fragment frame is too large, it exeeds the maximum frame size.
										// We have to drop it.
										// Clear Fragment frame contents
										memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME));
										Status = NDIS_STATUS_FAILURE;
										break;
									}

									memcpy(&pAdapter->FragFrame.Buffer[pAdapter->FragFrame.RxSize], pData, PacketSize);
									pAdapter->FragFrame.RxSize	+= PacketSize;
									pData += PacketSize;
									pAdapter->FragFrame.LastFrag = pHeader->Frag;		// Update fragment number
										
									// Last fragment
									if (pHeader->Controlhead.Frame.MoreFrag == FALSE)
									{
										// For miniportTransferData
										pAdapter->pRxData = pAdapter->FragFrame.Buffer;

										pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; // for RX ACTIVITY LED

										// For TKIP frame, calculate the MIC value
										if ((pAdapter->PortCfg.CipherAlg == CIPHER_TKIP) && (pHeader->Controlhead.Frame.Wep))
										{
											if (pWpaKey == NULL)
											{
												DBGPRINT_RAW(RT_DEBUG_ERROR,"No matched TKIP in decryption done calculate MIC routine!!!\n"); 						
												Status = NDIS_STATUS_FAILURE;
												break;
											}

											//
											// For the last fragment, we also need to copy the MIC 
											// to the end of pAdapter->FragFrame.Buffer
											// for RTMPTkipCompareMICValueWithLLC used.
											//
											pAdapter->FragFrame.RxSize -= 8; //We need to Minus MIC[8] on Fragment case.
												
											if (pAdapter->FragFrame.Flags & 0x00000001)
											{
												if (RTMPTkipCompareMICValueWithLLC(pAdapter,																				
																					pAdapter->FragFrame.Header_LLC,
																					pAdapter->FragFrame.Buffer,
																					pDestMac,
																					pSrcMac,
																					pWpaKey->RxMic,
																					pAdapter->FragFrame.RxSize) == FALSE)
												{
												DBGPRINT_RAW(RT_DEBUG_ERROR,"Rx MIC Value error 2\n");							
												RTMPReportMicError(pAdapter, pWpaKey);
												Status = NDIS_STATUS_FAILURE;
												break;
												}
											}
											else
											{
												if (RTMPTkipCompareMICValue(pAdapter,																		
																			pAdapter->FragFrame.Buffer,
																			pDestMac,
																			pSrcMac,
																			pWpaKey->RxMic,
																			pAdapter->FragFrame.RxSize) == FALSE)
												{
													DBGPRINT_RAW(RT_DEBUG_ERROR,"Rx MIC Value error 2\n");							
													RTMPReportMicError(pAdapter, pWpaKey);
													Status = NDIS_STATUS_FAILURE;
													break;
												}
											}
										}		

										// Acknolwdge upper layer the received frame
	                                if ((skb = dev_alloc_skb(pAdapter->FragFrame.RxSize + LENGTH_802_3 + 2)) != NULL)
	                                {

	                                    skb->dev = pAdapter->net;
	                                    skb_reserve(skb, 2);    /* 16 byte align the IP header */
	                                    memcpy(skb_put(skb, LENGTH_802_3), (PVOID) pAdapter->FragFrame.Header802_3, LENGTH_802_3);
	                                    memcpy(skb_put(skb, pAdapter->FragFrame.RxSize), (PVOID) &pAdapter->FragFrame.Buffer[0], pAdapter->FragFrame.RxSize);
	                                    skb->protocol = eth_type_trans(skb, pAdapter->net);
	                                    netif_rx(skb);
	                                    pAdapter->net->last_rx = jiffies;
	                                    pAdapter->netstats.rx_packets++;
	                                }
										// Increase general counters
										pAdapter->Counters.GoodReceives++;

										// Clear Fragment frame contents
										//memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME));
										DBGPRINT_RAW(RT_DEBUG_INFO, "!!! Frame with Fragment Indicated !!!\n");
									} //Last fragment //if (pHeader->Controlhead.Frame.MoreFrag == FALSE)
								} //Middle & End of fragment burst fragments
							}//else if (pRxD->U2M)
							break;

						case BTYPE_MGMT:
							// Enqueue this frame to MLME engine
							MlmeEnqueueForRecv(pAdapter,
												&pAdapter->Mlme.Queue,
												(UCHAR)pRxD->BBR1,
												pRxD->DataByteCnt - 4,
												pData);
							break;
				
						case BTYPE_CNTL:
							// Ignore ???
							break;
				
						default	:
							break;
					}//switch (pHeader->Controlhead.Frame.Type)	
				pAdapter->RalinkCounters.RxCount ++;

			}
			else if (Status == NDIS_STATUS_RESET)
			{
				RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_IN);
				return;
			}
		}

		pRxContext->InUse = FALSE;

	if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
		(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
			RTUSBBulkReceive(pAdapter);
	}while(0);
	

}
/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBDequeueMLMEPacket(
	IN	PRT2570ADAPTER	pAdapter)
{
	PMGMT_STRUC		pMgmt;

	DBGPRINT(RT_DEBUG_INFO, "RTUSBDequeueMLMEPacket\n");
	NdisAcquireSpinLock(&pAdapter->MLMEWaitQueueLock);
	while ((pAdapter->PopMgmtIndex != pAdapter->PushMgmtIndex) || (atomic_read(&pAdapter->MgmtQueueSize) > 0))
	{
		pMgmt = &pAdapter->MgmtRing[pAdapter->PopMgmtIndex];

		if (RTUSBFreeDescriptorRequest(pAdapter, PRIO_RING, 1) == NDIS_STATUS_SUCCESS)
		{
			atomic_dec(&pAdapter->MgmtQueueSize);
			pAdapter->PopMgmtIndex = (pAdapter->PopMgmtIndex + 1) % MGMT_RING_SIZE;
			NdisReleaseSpinLock(&pAdapter->MLMEWaitQueueLock);

			RTUSBMlmeHardTransmit(pAdapter, pMgmt);

			MlmeFreeMemory(pAdapter, pMgmt->pBuffer);
			pMgmt->pBuffer = NULL;
			pMgmt->Valid = FALSE;

			NdisAcquireSpinLock(&pAdapter->MLMEWaitQueueLock);
		}
		else
		{
			DBGPRINT(RT_DEBUG_TRACE, "RTUSBDequeueMLMEPacket::PrioRingFirstIndex = %d, PrioRingTxCnt = %d, PopMgmtIndex = %d, PushMgmtIndex = %d, NextMLMEIndex = %d\n", 
			pAdapter->PrioRingFirstIndex, pAdapter->PrioRingTxCnt, 
			pAdapter->PopMgmtIndex, pAdapter->PushMgmtIndex, pAdapter->NextMLMEIndex);	
			break;
		}
	}
	NdisReleaseSpinLock(&pAdapter->MLMEWaitQueueLock);
}    

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCleanUpMLMEWaitQueue(
	IN	PRT2570ADAPTER	pAdapter)
{
	PMGMT_STRUC		pMgmt;

	DBGPRINT(RT_DEBUG_TRACE, "--->CleanUpMLMEWaitQueue\n");

	NdisAcquireSpinLock(&pAdapter->MLMEWaitQueueLock);
	while (pAdapter->PopMgmtIndex != pAdapter->PushMgmtIndex)
	{
		pMgmt = (PMGMT_STRUC)&pAdapter->MgmtRing[pAdapter->PopMgmtIndex];
		MlmeFreeMemory(pAdapter, pMgmt->pBuffer);
		pMgmt->pBuffer = NULL;
		pMgmt->Valid = FALSE;
		atomic_dec(&pAdapter->MgmtQueueSize);

		pAdapter->PopMgmtIndex++;
		if (pAdapter->PopMgmtIndex >= MGMT_RING_SIZE)
		{
			pAdapter->PopMgmtIndex = 0;
		}
	}
	NdisReleaseSpinLock(&pAdapter->MLMEWaitQueueLock);

	DBGPRINT(RT_DEBUG_TRACE, "<---CleanUpMLMEWaitQueue\n");
}


/*
	========================================================================

	Routine	Description:
		API for MLME to transmit management frame to AP (BSS Mode)
	or station (IBSS Mode)
	
	Arguments:
		pAdapter	Pointer	to our adapter
		Buffer		Pointer to  memory of outgoing frame
		Length		Size of outgoing management frame
		
	Return Value:
		NDIS_STATUS_FAILURE
		NDIS_STATUS_PENDING
		NDIS_STATUS_SUCCESS

	Note:
	
	========================================================================
*/
VOID	MiniportMMRequest(
	IN	PRT2570ADAPTER	pAdapter,
	IN	PVOID			pBuffer,
	IN	ULONG			Length)
{

	if (pBuffer)
	{
		PMGMT_STRUC	pMgmt;

		// Check management ring free avaliability
		NdisAcquireSpinLock(&pAdapter->MLMEWaitQueueLock);
		pMgmt = (PMGMT_STRUC)&pAdapter->MgmtRing[pAdapter->PushMgmtIndex];
		// This management cell has been occupied
		if (pMgmt->Valid == TRUE)
		{
			NdisReleaseSpinLock(&pAdapter->MLMEWaitQueueLock);
			MlmeFreeMemory(pAdapter, pBuffer);
			pAdapter->RalinkCounters.MgmtRingFullCount++;
			DBGPRINT_RAW(RT_DEBUG_WARN, "MiniportMMRequest (error:: MgmtRing full)\n");
		}
		// Insert this request into software managemnet ring
		else
		{
			pMgmt->pBuffer = pBuffer;
			pMgmt->Length  = Length;
			pMgmt->Valid   = TRUE;
			pAdapter->PushMgmtIndex++;
			atomic_inc(&pAdapter->MgmtQueueSize);
			if (pAdapter->PushMgmtIndex >= MGMT_RING_SIZE)
			{
				pAdapter->PushMgmtIndex = 0;
			}
			NdisReleaseSpinLock(&pAdapter->MLMEWaitQueueLock);
		}
	}
	else
		DBGPRINT(RT_DEBUG_WARN, "MiniportMMRequest (error:: NULL msg)\n");
	
	RTUSBDequeueMLMEPacket(pAdapter);
	
	// If pAdapter->PrioRingTxCnt is larger than 0, this means that prio_ring have something to transmit.
	// Then call KickBulkOut to transmit it
	if (pAdapter->PrioRingTxCnt > 0)
	{
		DBGPRINT(RT_DEBUG_INFO, "MiniportMMRequest::PrioRingFirstIndex = %d, PrioRingTxCnt = %d, PopMgmtIndex = %d, PushMgmtIndex = %d, NextMLMEIndex = %d\n", 
		pAdapter->PrioRingFirstIndex, pAdapter->PrioRingTxCnt, 
		pAdapter->PopMgmtIndex, pAdapter->PushMgmtIndex, pAdapter->NextMLMEIndex);	

		AsicForceWakeup(pAdapter);
		RTUSBKickBulkOut(pAdapter);
	}
	
}

/*
	========================================================================

	Routine	Description:
		Search tuple cache for receive duplicate frame from unicast frames.
		
	Arguments:
		pAdapter		Pointer	to our adapter
		pHeader			802.11 header of receiving frame
		
	Return Value:
		TRUE			found matched tuple cache
		FALSE			no matched found

	Note:
	
	========================================================================
*/
BOOLEAN	RTMPSearchTupleCache(
	IN	PRT2570ADAPTER	pAdapter,
	IN	PHEADER_802_11	pHeader)
{
	INT	Index;

	for (Index = 0; Index < MAX_CLIENT; Index++)
	{
		if (pAdapter->TupleCache[Index].Valid == FALSE)
		    continue;
		
		if ((memcmp(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6)== 0) &&
			(pAdapter->TupleCache[Index].Sequence == pHeader->Sequence) &&
			(pAdapter->TupleCache[Index].Frag == pHeader->Frag))
		{
			return (TRUE);
		}
	}
	return (FALSE);
}

/*
	========================================================================

	Routine	Description:
		Update tuple cache for new received unicast frames.
		
	Arguments:
		pAdapter		Pointer	to our adapter
		pHeader			802.11 header of receiving frame
		
	Return Value:
		None
		
	Note:
	
	========================================================================
*/
VOID	RTMPUpdateTupleCache(
	IN	PRT2570ADAPTER	pAdapter,
	IN	PHEADER_802_11	pHeader)
{
	UCHAR	Index;

	for (Index = 0; Index < MAX_CLIENT; Index++)
	{
		if (pAdapter->TupleCache[Index].Valid == FALSE)
		{
			// Add new entry
			memcpy(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6);
			pAdapter->TupleCache[Index].Sequence = pHeader->Sequence;
			pAdapter->TupleCache[Index].Frag     = pHeader->Frag;
			pAdapter->TupleCache[Index].Valid    = TRUE;
			pAdapter->TupleCacheLastUpdateIndex  = Index;
			DBGPRINT(RT_DEBUG_INFO,"DUPCHECK - Add Entry %d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", 
			    Index, pAdapter->TupleCache[Index].MAC.Octet[0], pAdapter->TupleCache[Index].MAC.Octet[1],
			    pAdapter->TupleCache[Index].MAC.Octet[2], pAdapter->TupleCache[Index].MAC.Octet[3],
			    pAdapter->TupleCache[Index].MAC.Octet[4], pAdapter->TupleCache[Index].MAC.Octet[5]);
			return;
		}
		else if ((memcmp(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6)== 0))
		{
			// Update old entry
			pAdapter->TupleCache[Index].Sequence = pHeader->Sequence;
			pAdapter->TupleCache[Index].Frag     = pHeader->Frag;
			return;
		}
	}

    // tuple cache full, replace the first inserted one (even though it may not be
    // least referenced one)
	if (Index == MAX_CLIENT)
	{
	    pAdapter->TupleCacheLastUpdateIndex ++;
	    if (pAdapter->TupleCacheLastUpdateIndex >= MAX_CLIENT)
		pAdapter->TupleCacheLastUpdateIndex = 0;
	    Index = pAdapter->TupleCacheLastUpdateIndex;

		// replace with new entry
		memcpy(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6);
		pAdapter->TupleCache[Index].Sequence = pHeader->Sequence;
		pAdapter->TupleCache[Index].Frag     = pHeader->Frag;
		pAdapter->TupleCache[Index].Valid    = TRUE;
		DBGPRINT(RT_DEBUG_INFO,"DUPCHECK - replace Entry %d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", 
		    Index, pAdapter->TupleCache[Index].MAC.Octet[0], pAdapter->TupleCache[Index].MAC.Octet[1],
		    pAdapter->TupleCache[Index].MAC.Octet[2], pAdapter->TupleCache[Index].MAC.Octet[3],
		    pAdapter->TupleCache[Index].MAC.Octet[4], pAdapter->TupleCache[Index].MAC.Octet[5]);
	}
}

/*
	========================================================================

	Routine	Description:
		Apply packet filter policy, return NDIS_STATUS_FAILURE if this frame
		should be dropped.
		
	Arguments:
		pAdapter		Pointer	to our adapter
		pRxD			Pointer	to the Rx descriptor
		pHeader			Pointer to the 802.11 frame header
		
	Return Value:
		NDIS_STATUS_SUCCESS		Accept frame
		NDIS_STATUS_FAILURE		Drop Frame
		
	Note:
		Maganement frame should bypass this filtering rule.
	
	========================================================================
*/
NDIS_STATUS	RTMPApplyPacketFilter(
	IN	PRT2570ADAPTER	pAdapter, 
	IN	PRXD_STRUC		pRxD, 
	IN	PHEADER_802_11	pHeader)
{
	UCHAR	i;
	
	// 0. Management frame should bypass all these filtering rules.
	if (pHeader->Controlhead.Frame.Type == BTYPE_MGMT)
	{
		if ((pRxD->U2M) || (pRxD->Bcast) || (pRxD->Mcast))//steven:for ASIC Bug Workaround
		return(NDIS_STATUS_SUCCESS);
	}
	
	// 0.1	Drop all Rx frames if MIC countermeasures kicks in
	if (pAdapter->PortCfg.MicErrCnt >= 2)
	{
		return(NDIS_STATUS_FAILURE);
	}
	
	// 1. Drop unicast to me packet if NDIS_PACKET_TYPE_DIRECTED is FALSE
	if (pRxD->U2M)
	{
		if (pAdapter->bAcceptDirect == FALSE)
		{
			DBGPRINT_RAW(RT_DEBUG_INFO, "unicast not accepted\n");//steven:for debug
			return(NDIS_STATUS_FAILURE);
		}
	}
		
	// 2. Drop broadcast packet if NDIS_PACKET_TYPE_BROADCAST is FALSE
	else if (pRxD->Bcast)
	{
		if (pAdapter->bAcceptBroadcast == FALSE)
		{
			DBGPRINT(RT_DEBUG_INFO, "broadcast not accepted\n");//steven:for debug
			return(NDIS_STATUS_FAILURE);
		}
	}
			
	// 3. Drop multicast packet if NDIS_PACKET_TYPE_ALL_MULTICAST is false
	//    and NDIS_PACKET_TYPE_MULTICAST is false.
	//    If NDIS_PACKET_TYPE_MULTICAST is true, but NDIS_PACKET_TYPE_ALL_MULTICAST is false.
	//    We have to deal with multicast table lookup & drop not matched packets.
	else if (pRxD->Mcast)
	{
		if (pAdapter->bAcceptAllMulticast == FALSE)
		{
			if (pAdapter->bAcceptMulticast == FALSE)
			{
				DBGPRINT_RAW(RT_DEBUG_INFO, "multicast not accepted\n");//steven:for debug
				return(NDIS_STATUS_FAILURE);
			}
			else
			{
				// Selected accept multicast packet based on multicast table
				for (i = 0; i < pAdapter->NumberOfMcAddresses; i++)
				{
					if ((memcmp(&pHeader->Controlhead.Addr1, pAdapter->McastTable[i], ETH_LENGTH_OF_ADDRESS)== 0))
					{
						break;		// Matched
					}
				}

				// Not matched
				if (i == pAdapter->NumberOfMcAddresses)
				{
					DBGPRINT(RT_DEBUG_INFO,"Drop multicast %02x:%02x:%02x:%02x:%02x:%02x\n",
						pHeader->Controlhead.Addr1.Octet[0], pHeader->Controlhead.Addr1.Octet[1],
						pHeader->Controlhead.Addr1.Octet[2], pHeader->Controlhead.Addr1.Octet[3],
						pHeader->Controlhead.Addr1.Octet[4], pHeader->Controlhead.Addr1.Octet[5]);
					DBGPRINT(RT_DEBUG_LOUD, "multicast not matched\n");
					return(NDIS_STATUS_FAILURE);
				}
				else
				{
					DBGPRINT(RT_DEBUG_INFO,"Accept multicast %02x:%02x:%02x:%02x:%02x:%02x\n",
						pHeader->Controlhead.Addr1.Octet[0], pHeader->Controlhead.Addr1.Octet[1],
						pHeader->Controlhead.Addr1.Octet[2], pHeader->Controlhead.Addr1.Octet[3],
						pHeader->Controlhead.Addr1.Octet[4], pHeader->Controlhead.Addr1.Octet[5]);
				}
			}
		}
	}

	// 4. Not U2M, not Mcast, not Bcast, must be unicast to other DA.
	//    Since we did not implement promiscuous mode, just drop this kind of packet for now.
	else
	{
		DBGPRINT_RAW(RT_DEBUG_TRACE, "not-to-me unicast\n");//steven:for debug
		return(NDIS_STATUS_FAILURE);
	}
	
	return(NDIS_STATUS_SUCCESS);	
}

/*
	========================================================================

	Routine	Description:
		Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
		
	Arguments:
		pRxD		Pointer	to the Rx descriptor
		
	Return Value:
		NDIS_STATUS_SUCCESS		No err
		NDIS_STATUS_FAILURE		Error
		
	Note:
	
	========================================================================
*/
NDIS_STATUS	RTMPCheckRxDescriptor(
	IN	PRT2570ADAPTER	pAdapter,
	IN	PRXD_STRUC	pRxD)
{
	// Phy errors
	if (pRxD->PhyErr)
	{
		DBGPRINT_RAW(RT_DEBUG_ERROR, "pRxD->PhyErr 0x%x, 0x%x, 0x%x, 0x%x\n", *(ULONG*)pRxD, *((ULONG*)pRxD+1), *((ULONG*)pRxD+2), *((ULONG*)pRxD+3));
		return(NDIS_STATUS_FAILURE);
	}
	
	// CRC errors
	if (pRxD->Crc)
	{
		DBGPRINT_RAW(RT_DEBUG_ERROR, "pRxD->Crc\n");
		return(NDIS_STATUS_FAILURE);
	}
	
	// Paul 04-03 for OFDM Rx length issue
	if (pRxD->DataByteCnt > 1604)
	{
		DBGPRINT_RAW(RT_DEBUG_ERROR, "received too long, DataByteCnt = %d\n", pRxD->DataByteCnt);
		return NDIS_STATUS_RESET;
	}

	return(NDIS_STATUS_SUCCESS);
}

/*
	========================================================================

	Routine	Description:
		Process MIC error indication and record MIC error timer.
		
	Arguments:
		pAdapter		Pointer	to our adapter
		pWpaKey			Pointer	to the WPA key structure
		
	Return Value:
		None
		
	Note:
	
	========================================================================
*/
VOID	RTMPReportMicError(
	IN	PRT2570ADAPTER	pAdapter, 
	IN	PWPA_KEY		pWpaKey)
{
	ULONG	Now;
	struct
	{
		NDIS_802_11_STATUS_INDICATION		Status;
		NDIS_802_11_AUTHENTICATION_REQUEST	Request;
	}	Report;

	// 0. Set Status to indicate auth error
	Report.Status.StatusType = Ndis802_11StatusType_Authentication;
	
	// 1. Check for Group or Pairwise MIC error
	if (pWpaKey->Type == PAIRWISE_KEY)
		Report.Request.Flags = NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR;
	else
		Report.Request.Flags = NDIS_802_11_AUTH_REQUEST_GROUP_ERROR;

	// 2. Copy AP MAC address
	memcpy(Report.Request.Bssid, pWpaKey->BssId, 6);

	// 3. Calculate length
	Report.Request.Length = sizeof(NDIS_802_11_AUTHENTICATION_REQUEST);

	// 4. Indicate to NDIS
	NdisMIndicateStatus(pAdapter->AdapterHandle, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID) &Report, sizeof(Report));
	NdisMIndicateStatusComplete(pAdapter->AdapterHandle);

	// 5. Record Last MIC error time and count
	Now = jiffies;
	if (pAdapter->PortCfg.MicErrCnt == 0)
	{
		pAdapter->PortCfg.MicErrCnt++;
		pAdapter->PortCfg.LastMicErrorTime = Now;
	}
	else if (pAdapter->PortCfg.MicErrCnt == 1)
	{
		if ((pAdapter->PortCfg.LastMicErrorTime + (60 * 1000)) < Now)
		{
			// Update Last MIC error time, this did not violate two MIC errors within 60 seconds
			pAdapter->PortCfg.LastMicErrorTime = Now;			
		}
		else
		{
			pAdapter->PortCfg.LastMicErrorTime = Now;			
			// Violate MIC error counts, MIC countermeasures kicks in
			pAdapter->PortCfg.MicErrCnt++;			
			// We shall block all reception
			// We shall clean all Tx ring and disassoicate from AP after next EAPOL frame
			RTUSBRejectPendingPackets(pAdapter);
			RTUSBCleanUpDataBulkOutQueue(pAdapter);
		}
	}
	else
	{
		// MIC error count >= 2
		// This should not happen
		;
	}
}
/*
	========================================================================

	Routine	Description:
		Copy frame from waiting queue into relative ring buffer and set 
	appropriate ASIC register to kick hardware transmit function
	
	Arguments:
		pAdapter	Pointer	to our adapter
		pBuffer		Pointer to  memory of outgoing frame
		Length		Size of outgoing management frame
		
	Return Value:
		NDIS_STATUS_FAILURE
		NDIS_STATUS_PENDING
		NDIS_STATUS_SUCCESS

	Note:
	
	========================================================================
*/
VOID	RTUSBMlmeHardTransmit(
	IN	PRT2570ADAPTER	pAdapter,
	IN	PMGMT_STRUC		pMgmt)
{
	PTX_CONTEXT		pMLMEContext;
	PTXD_STRUC		pTxD;
	PUCHAR			pDest;	
	PHEADER_802_11	pHeader_802_11;
	BOOLEAN         AckRequired, InsertTimestamp;
	ULONG			TransferBufferLength;
	PVOID			pBuffer = pMgmt->pBuffer;
	ULONG			Length = pMgmt->Length;
	
	DBGPRINT_RAW(RT_DEBUG_INFO, "--->MlmeHardTransmit\n");
	
	pAdapter->PrioRingTxCnt++;

	pMLMEContext = &pAdapter->MLMEContext[pAdapter->NextMLMEIndex];
	pMLMEContext->InUse = TRUE;

	// Increase & maintain Tx Ring Index
	pAdapter->NextMLMEIndex++;
	if (pAdapter->NextMLMEIndex >= PRIO_RING_SIZE)
	{
		pAdapter->NextMLMEIndex = 0;
	}

	pDest				= pMLMEContext->TransferBuffer->WirelessPacket;              
	pTxD				= (PTXD_STRUC)(pMLMEContext->TransferBuffer);
	memset(pTxD, 0, sizeof(TXD_STRUC));
	
	pHeader_802_11 = (PHEADER_802_11) pBuffer;
	InsertTimestamp = FALSE;
	if (pHeader_802_11->Controlhead.Frame.Type == BTYPE_CNTL) // must be PS-POLL
	{
		AckRequired = FALSE;
	}
	else // BTYPE_MGMT or BMGMT_DATA(must be NULL frame)
	{
		pAdapter->Sequence       = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER);
		pHeader_802_11->Sequence = pAdapter->Sequence;

		if (pHeader_802_11->Controlhead.Addr1.Octet[0] & 0x01) // MULTICAST, BROADCAST
		{
			INC_COUNTER(pAdapter->WlanCounters.MulticastTransmittedFrameCount);
			AckRequired = FALSE;
			pHeader_802_11->Controlhead.Duration = 0;
		}
		else
		{
			AckRequired = TRUE;
			pHeader_802_11->Controlhead.Duration = RTUSBCalcDuration(pAdapter, pAdapter->PortCfg.MlmeRate, 14);
			if (pHeader_802_11->Controlhead.Frame.Subtype == SUBTYPE_PROBE_RSP)
			{
				InsertTimestamp = TRUE;
			}
		}
	}
	
	memcpy(pDest, pBuffer, Length);
   
	// Initialize Priority Descriptor
	// For inter-frame gap, the number is for this frame and next frame
	// For MLME rate, we will fix as 2Mb to match other vendor's implement
	RTUSBWriteTxDescriptor(pTxD, FALSE, 0, AckRequired, InsertTimestamp,
		TRUE, IFS_BACKOFF, Length, FALSE, 0, CW_MIN_IN_BITS, CW_MAX_IN_BITS,
		Length + 4, pAdapter->PortCfg.MlmeRate, 4, pAdapter->PortCfg.TxPreambleInUsed);

	// Build our URB for USBD
	TransferBufferLength = sizeof(TXD_STRUC) + Length;
	if ((TransferBufferLength % 2) == 1)
		TransferBufferLength++;
	if ((TransferBufferLength % pAdapter->BulkOutMaxPacketSize) == 0)
		TransferBufferLength += 2;
	
	pMLMEContext->BulkOutSize = TransferBufferLength;
	RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_MLME);
	
	DBGPRINT(RT_DEBUG_INFO, "<---MlmeHardTransmit\n");
}   

