]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/rt3070/common/ba_action.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / rt3070 / common / ba_action.c
diff --git a/drivers/staging/rt3070/common/ba_action.c b/drivers/staging/rt3070/common/ba_action.c
new file mode 100644 (file)
index 0000000..17e1f87
--- /dev/null
@@ -0,0 +1,1810 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * This program is distributed in the hope that it will be useful,       *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ * GNU General Public License for more details.                          *
+ *                                                                       *
+ * You should have received a copy of the GNU General Public License     *
+ * along with this program; if not, write to the                         *
+ * Free Software Foundation, Inc.,                                       *
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                       *
+ *************************************************************************
+ */
+
+
+#ifdef DOT11_N_SUPPORT
+
+#include "../rt_config.h"
+
+
+
+#define BA_ORI_INIT_SEQ                (pEntry->TxSeq[TID]) //1                        // inital sequence number of BA session
+
+#define ORI_SESSION_MAX_RETRY  8
+#define ORI_BA_SESSION_TIMEOUT (2000)  // ms
+#define REC_BA_SESSION_IDLE_TIMEOUT    (1000)  // ms
+
+#define REORDERING_PACKET_TIMEOUT              ((100 * HZ)/1000)       // system ticks -- 100 ms
+#define MAX_REORDERING_PACKET_TIMEOUT  ((3000 * HZ)/1000)      // system ticks -- 100 ms
+
+#define RESET_RCV_SEQ          (0xFFFF)
+
+static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk);
+
+
+BA_ORI_ENTRY *BATableAllocOriEntry(
+                                                                 IN  PRTMP_ADAPTER   pAd,
+                                                                 OUT USHORT          *Idx);
+
+BA_REC_ENTRY *BATableAllocRecEntry(
+                                                                 IN  PRTMP_ADAPTER   pAd,
+                                                                 OUT USHORT          *Idx);
+
+VOID BAOriSessionSetupTimeout(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3);
+
+VOID BARecSessionIdleTimeout(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3);
+
+
+BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout);
+BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout);
+
+#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk)    \
+                       Announce_Reordering_Packet(_pAd, _mpdu_blk);
+
+VOID BA_MaxWinSizeReasign(
+       IN PRTMP_ADAPTER        pAd,
+       IN MAC_TABLE_ENTRY  *pEntryPeer,
+       OUT UCHAR                       *pWinSize)
+{
+       UCHAR MaxSize;
+
+
+       if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3
+       {
+               if (pAd->MACVersion >= RALINK_3070_VERSION)
+               {
+                       if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled)
+                               MaxSize = 7; // for non-open mode
+                       else
+                               MaxSize = 13;
+               }
+               else
+                       MaxSize = 31;
+       }
+       else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e
+       {
+               if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled)
+                       MaxSize = 7; // for non-open mode
+               else
+                       MaxSize = 13;
+       }
+       else
+               MaxSize = 7;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n",
+                       *pWinSize, MaxSize));
+
+       if ((*pWinSize) > MaxSize)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n",
+                               *pWinSize, MaxSize));
+
+               *pWinSize = MaxSize;
+       }
+}
+
+void Announce_Reordering_Packet(IN PRTMP_ADAPTER                       pAd,
+                                                               IN struct reordering_mpdu       *mpdu)
+{
+       PNDIS_PACKET    pPacket;
+
+       pPacket = mpdu->pPacket;
+
+       if (mpdu->bAMSDU)
+       {
+               ASSERT(0);
+               BA_Reorder_AMSDU_Annnounce(pAd, pPacket);
+       }
+       else
+       {
+               //
+               // pass this 802.3 packet to upper layer or forward this packet to WM directly
+               //
+
+#ifdef CONFIG_STA_SUPPORT
+               IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+                       ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket));
+#endif // CONFIG_STA_SUPPORT //
+       }
+}
+
+/*
+ * Insert a reordering mpdu into sorted linked list by sequence no.
+ */
+BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu)
+{
+
+       struct reordering_mpdu **ppScan = &list->next;
+
+       while (*ppScan != NULL)
+       {
+               if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ))
+               {
+                       ppScan = &(*ppScan)->next;
+               }
+               else if ((*ppScan)->Sequence == mpdu->Sequence)
+               {
+                       /* give up this duplicated frame */
+                       return(FALSE);
+               }
+               else
+               {
+                       /* find position */
+                       break;
+               }
+       }
+
+       mpdu->next = *ppScan;
+       *ppScan = mpdu;
+       list->qlen++;
+       return TRUE;
+}
+
+
+/*
+ * caller lock critical section if necessary
+ */
+static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk)
+{
+       list->qlen++;
+       mpdu_blk->next = list->next;
+       list->next = mpdu_blk;
+}
+
+/*
+ * caller lock critical section if necessary
+ */
+static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list)
+{
+       struct reordering_mpdu *mpdu_blk = NULL;
+
+       ASSERT(list);
+
+               if (list->qlen)
+               {
+                       list->qlen--;
+                       mpdu_blk = list->next;
+                       if (mpdu_blk)
+                       {
+                               list->next = mpdu_blk->next;
+                               mpdu_blk->next = NULL;
+                       }
+               }
+       return mpdu_blk;
+}
+
+
+static inline struct reordering_mpdu  *ba_reordering_mpdu_dequeue(struct reordering_list *list)
+{
+       return(ba_dequeue(list));
+}
+
+
+static inline struct reordering_mpdu  *ba_reordering_mpdu_probe(struct reordering_list *list)
+       {
+       ASSERT(list);
+
+               return(list->next);
+       }
+
+
+/*
+ * free all resource for reordering mechanism
+ */
+void ba_reordering_resource_release(PRTMP_ADAPTER pAd)
+{
+       BA_TABLE        *Tab;
+       PBA_REC_ENTRY   pBAEntry;
+       struct reordering_mpdu *mpdu_blk;
+       int i;
+
+       Tab = &pAd->BATable;
+
+       /* I.  release all pending reordering packet */
+       NdisAcquireSpinLock(&pAd->BATabLock);
+       for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++)
+       {
+               pBAEntry = &Tab->BARecEntry[i];
+               if (pBAEntry->REC_BA_Status != Recipient_NONE)
+               {
+                       while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list)))
+                       {
+                               ASSERT(mpdu_blk->pPacket);
+                               RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE);
+                               ba_mpdu_blk_free(pAd, mpdu_blk);
+                       }
+               }
+       }
+       NdisReleaseSpinLock(&pAd->BATabLock);
+
+       ASSERT(pBAEntry->list.qlen == 0);
+       /* II. free memory of reordering mpdu table */
+       NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
+       os_free_mem(pAd, pAd->mpdu_blk_pool.mem);
+       NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
+}
+
+
+
+/*
+ * Allocate all resource for reordering mechanism
+ */
+BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num)
+{
+       int     i;
+       PUCHAR  mem;
+       struct reordering_mpdu *mpdu_blk;
+       struct reordering_list *freelist;
+
+       /* allocate spinlock */
+       NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock);
+
+       /* initialize freelist */
+       freelist = &pAd->mpdu_blk_pool.freelist;
+       freelist->next = NULL;
+       freelist->qlen = 0;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu))));
+
+       /* allocate number of mpdu_blk memory */
+       os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu)));
+
+       pAd->mpdu_blk_pool.mem = mem;
+
+       if (mem == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n"));
+               return(FALSE);
+       }
+
+       /* build mpdu_blk free list */
+       for (i=0; i<num; i++)
+       {
+               /* get mpdu_blk */
+               mpdu_blk = (struct reordering_mpdu *) mem;
+               /* initial mpdu_blk */
+               NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu));
+               /* next mpdu_blk */
+               mem += sizeof(struct reordering_mpdu);
+               /* insert mpdu_blk into freelist */
+               ba_enqueue(freelist, mpdu_blk);
+       }
+
+       return(TRUE);
+}
+
+//static int blk_count=0; // sample take off, no use
+
+static struct reordering_mpdu *ba_mpdu_blk_alloc(PRTMP_ADAPTER pAd)
+{
+       struct reordering_mpdu *mpdu_blk;
+
+       NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
+       mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist);
+       if (mpdu_blk)
+       {
+//             blk_count++;
+               /* reset mpdu_blk */
+               NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu));
+       }
+       NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
+       return mpdu_blk;
+}
+
+static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk)
+{
+       ASSERT(mpdu_blk);
+
+       NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
+//     blk_count--;
+       ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk);
+       NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
+}
+
+
+static USHORT ba_indicate_reordering_mpdus_in_order(
+                                                                                                  IN PRTMP_ADAPTER    pAd,
+                                                                                                  IN PBA_REC_ENTRY    pBAEntry,
+                                                                                                  IN USHORT           StartSeq)
+{
+       struct reordering_mpdu *mpdu_blk;
+       USHORT  LastIndSeq = RESET_RCV_SEQ;
+
+       NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
+
+       while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list)))
+               {
+                       /* find in-order frame */
+               if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ))
+                       {
+                               break;
+                       }
+                       /* dequeue in-order frame from reodering list */
+                       mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list);
+                       /* pass this frame up */
+               ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
+               /* move to next sequence */
+                       StartSeq = mpdu_blk->Sequence;
+               LastIndSeq = StartSeq;
+               /* free mpdu_blk */
+                       ba_mpdu_blk_free(pAd, mpdu_blk);
+       }
+
+       NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
+
+       /* update last indicated sequence */
+       return LastIndSeq;
+}
+
+static void ba_indicate_reordering_mpdus_le_seq(
+                                                                                          IN PRTMP_ADAPTER    pAd,
+                                                                                          IN PBA_REC_ENTRY    pBAEntry,
+                                                                                          IN USHORT           Sequence)
+{
+       struct reordering_mpdu *mpdu_blk;
+
+       NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
+       while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list)))
+               {
+                       /* find in-order frame */
+               if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ))
+               {
+                       /* dequeue in-order frame from reodering list */
+                       mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list);
+                       /* pass this frame up */
+                       ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
+                       /* free mpdu_blk */
+                       ba_mpdu_blk_free(pAd, mpdu_blk);
+               }
+               else
+                       {
+                               break;
+                       }
+       }
+       NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
+}
+
+
+static void ba_refresh_reordering_mpdus(
+                                                                          IN PRTMP_ADAPTER    pAd,
+                                                                          PBA_REC_ENTRY       pBAEntry)
+{
+       struct reordering_mpdu *mpdu_blk;
+
+       NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
+
+                       /* dequeue in-order frame from reodering list */
+       while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list)))
+       {
+                       /* pass this frame up */
+               ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
+
+               pBAEntry->LastIndSeq = mpdu_blk->Sequence;
+                       ba_mpdu_blk_free(pAd, mpdu_blk);
+
+               /* update last indicated sequence */
+       }
+       ASSERT(pBAEntry->list.qlen == 0);
+       pBAEntry->LastIndSeq = RESET_RCV_SEQ;
+       NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
+}
+
+
+//static
+void ba_flush_reordering_timeout_mpdus(
+                                                                       IN PRTMP_ADAPTER    pAd,
+                                                                       IN PBA_REC_ENTRY    pBAEntry,
+                                                                       IN ULONG            Now32)
+
+{
+       USHORT Sequence;
+
+//     if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) &&
+//              (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //||
+//             (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) &&
+//              (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8)))
+       if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6)))
+                &&(pBAEntry->list.qlen > 1)
+               )
+       {
+               DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer),
+                          (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT,
+                          pBAEntry->LastIndSeq));
+               ba_refresh_reordering_mpdus(pAd, pBAEntry);
+               pBAEntry->LastIndSeqAtTimer = Now32;
+       }
+       else
+       if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT)))
+               && (pBAEntry->list.qlen > 0)
+          )
+               {
+//             printk("timeout[%d] (%lx-%lx = %d > %d): %x, ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer),
+//                        (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), REORDERING_PACKET_TIMEOUT,
+//                        pBAEntry->LastIndSeq);
+               //
+               // force LastIndSeq to shift to LastIndSeq+1
+               //
+               Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ;
+               ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence);
+               pBAEntry->LastIndSeqAtTimer = Now32;
+                       pBAEntry->LastIndSeq = Sequence;
+               //
+               // indicate in-order mpdus
+               //
+               Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence);
+               if (Sequence != RESET_RCV_SEQ)
+               {
+                       pBAEntry->LastIndSeq = Sequence;
+               }
+
+               //printk("%x, flush one!\n", pBAEntry->LastIndSeq);
+
+       }
+}
+
+
+/*
+ * generate ADDBA request to
+ * set up BA agreement
+ */
+VOID BAOriSessionSetUp(
+                                         IN PRTMP_ADAPTER    pAd,
+                                         IN MAC_TABLE_ENTRY  *pEntry,
+                                         IN UCHAR            TID,
+                                         IN USHORT           TimeOut,
+                                         IN ULONG            DelayTime,
+                                         IN BOOLEAN          isForced)
+
+{
+       //MLME_ADDBA_REQ_STRUCT AddbaReq;
+       BA_ORI_ENTRY            *pBAEntry = NULL;
+       USHORT                  Idx;
+       BOOLEAN                 Cancelled;
+
+       if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE)  &&  (isForced == FALSE))
+               return;
+
+       // if this entry is limited to use legacy tx mode, it doesn't generate BA.
+       if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT)
+               return;
+
+       if ((pEntry->BADeclineBitmap & (1<<TID)) && (isForced == FALSE))
+       {
+               // try again after 3 secs
+               DelayTime = 3000;
+//             printk("DeCline BA from Peer\n");
+//             return;
+       }
+
+
+       Idx = pEntry->BAOriWcidArray[TID];
+       if (Idx == 0)
+       {
+               // allocate a BA session
+               pBAEntry = BATableAllocOriEntry(pAd, &Idx);
+               if (pBAEntry == NULL)
+               {
+                       DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n"));
+                       return;
+               }
+       }
+       else
+       {
+               pBAEntry =&pAd->BATable.BAOriEntry[Idx];
+       }
+
+       if (pBAEntry->ORI_BA_Status >= Originator_WaitRes)
+       {
+               return;
+       }
+
+       pEntry->BAOriWcidArray[TID] = Idx;
+
+       // Initialize BA session
+       pBAEntry->ORI_BA_Status = Originator_WaitRes;
+       pBAEntry->Wcid = pEntry->Aid;
+       pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit;
+       pBAEntry->Sequence = BA_ORI_INIT_SEQ;
+       pBAEntry->Token = 1;    // (2008-01-21) Jan Lee recommends it - this token can't be 0
+       pBAEntry->TID = TID;
+       pBAEntry->TimeOutValue = TimeOut;
+       pBAEntry->pAdapter = pAd;
+
+       DBGPRINT(RT_DEBUG_TRACE,("Send AddBA to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d isForced:%d Wcid:%d\n"
+               ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2]
+               ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5]
+               ,TID,isForced,pEntry->Aid));
+
+       if (!(pEntry->TXBAbitmap & (1<<TID)))
+       {
+               RTMPInitTimer(pAd, &pBAEntry->ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE);
+       }
+       else
+               RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
+
+       // set timer to send ADDBA request
+       RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime);
+}
+
+VOID BAOriSessionAdd(
+                       IN PRTMP_ADAPTER    pAd,
+                                       IN MAC_TABLE_ENTRY  *pEntry,
+                       IN PFRAME_ADDBA_RSP pFrame)
+{
+       BA_ORI_ENTRY  *pBAEntry = NULL;
+       BOOLEAN       Cancelled;
+       UCHAR         TID;
+       USHORT        Idx;
+       PUCHAR          pOutBuffer2 = NULL;
+       NDIS_STATUS     NStatus;
+       ULONG           FrameLen;
+       FRAME_BAR       FrameBar;
+
+       TID = pFrame->BaParm.TID;
+       Idx = pEntry->BAOriWcidArray[TID];
+       pBAEntry =&pAd->BATable.BAOriEntry[Idx];
+
+       // Start fill in parameters.
+       if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes))
+       {
+               pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize));
+               BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize);
+
+               pBAEntry->TimeOutValue = pFrame->TimeOutValue;
+               pBAEntry->ORI_BA_Status = Originator_Done;
+               // reset sequence number
+               pBAEntry->Sequence = BA_ORI_INIT_SEQ;
+               // Set Bitmap flag.
+               pEntry->TXBAbitmap |= (1<<TID);
+                               RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
+
+               pBAEntry->ORIBATimer.TimerValue = 0;    //pFrame->TimeOutValue;
+
+               DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap,
+                                                                pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue));
+
+               // SEND BAR ;
+               NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2);  //Get an unused nonpaged memory
+               if (NStatus != NDIS_STATUS_SUCCESS)
+               {
+                       DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n"));
+                       return;
+               }
+
+
+#ifdef CONFIG_STA_SUPPORT
+               IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+                       BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress);
+#endif // CONFIG_STA_SUPPORT //
+
+               FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function.
+               FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton.
+               FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton.
+               MakeOutgoingFrame(pOutBuffer2,              &FrameLen,
+                                                 sizeof(FRAME_BAR),      &FrameBar,
+                                         END_OF_ARGS);
+               MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen);
+               MlmeFreeMemory(pAd, pOutBuffer2);
+
+
+               if (pBAEntry->ORIBATimer.TimerValue)
+                       RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec
+       }
+}
+
+BOOLEAN BARecSessionAdd(
+                                          IN PRTMP_ADAPTER    pAd,
+                                          IN MAC_TABLE_ENTRY  *pEntry,
+                                          IN PFRAME_ADDBA_REQ pFrame)
+{
+       BA_REC_ENTRY            *pBAEntry = NULL;
+       BOOLEAN                 Status = TRUE;
+       BOOLEAN                 Cancelled;
+       USHORT                  Idx;
+       UCHAR                   TID;
+       UCHAR                   BAWinSize;
+       //UINT32                  Value;
+       //UINT                    offset;
+
+
+       ASSERT(pEntry);
+
+       // find TID
+       TID = pFrame->BaParm.TID;
+
+       BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit);
+
+       // Intel patch
+       if (BAWinSize == 0)
+       {
+               BAWinSize = 64;
+       }
+
+       Idx = pEntry->BARecWcidArray[TID];
+
+
+       if (Idx == 0)
+       {
+               pBAEntry = BATableAllocRecEntry(pAd, &Idx);
+       }
+       else
+       {
+               pBAEntry = &pAd->BATable.BARecEntry[Idx];
+               // flush all pending reordering mpdus
+               ba_refresh_reordering_mpdus(pAd, pBAEntry);
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx,
+                                                        pFrame->BaParm.BufSize, BAWinSize));
+
+       // Start fill in parameters.
+       if (pBAEntry != NULL)
+       {
+               ASSERT(pBAEntry->list.qlen == 0);
+
+               pBAEntry->REC_BA_Status = Recipient_HandleRes;
+               pBAEntry->BAWinSize = BAWinSize;
+               pBAEntry->Wcid = pEntry->Aid;
+               pBAEntry->TID = TID;
+               pBAEntry->TimeOutValue = pFrame->TimeOutValue;
+               pBAEntry->REC_BA_Status = Recipient_Accept;
+               // initial sequence number
+               pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq;
+
+               printk("Start Seq = %08x\n",  pFrame->BaStartSeq.field.StartSeq);
+
+               if (pEntry->RXBAbitmap & (1<<TID))
+               {
+                       RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled);
+               }
+               else
+               {
+                       RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE);
+               }
+
+               // Set Bitmap flag.
+               pEntry->RXBAbitmap |= (1<<TID);
+               pEntry->BARecWcidArray[TID] = Idx;
+
+               pEntry->BADeclineBitmap &= ~(1<<TID);
+
+               // Set BA session mask in WCID table.
+               RT28XX_ADD_BA_SESSION_TO_ASIC(pAd, pEntry->Aid, TID);
+
+               DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n",
+                               pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID]));
+       }
+       else
+       {
+               Status = FALSE;
+               DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n",
+                               PRINT_MAC(pEntry->Addr), TID));
+       }
+       return(Status);
+}
+
+
+BA_REC_ENTRY *BATableAllocRecEntry(
+                                                                 IN  PRTMP_ADAPTER   pAd,
+                                                                 OUT USHORT          *Idx)
+{
+       int             i;
+       BA_REC_ENTRY    *pBAEntry = NULL;
+
+
+       NdisAcquireSpinLock(&pAd->BATabLock);
+
+       if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION)
+       {
+               printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient,
+                       MAX_BARECI_SESSION);
+               goto done;
+       }
+
+       // reserve idx 0 to identify BAWcidArray[TID] as empty
+       for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++)
+       {
+               pBAEntry =&pAd->BATable.BARecEntry[i];
+               if ((pBAEntry->REC_BA_Status == Recipient_NONE))
+               {
+                       // get one
+                       pAd->BATable.numAsRecipient++;
+                       pBAEntry->REC_BA_Status = Recipient_USED;
+                       *Idx = i;
+                       break;
+               }
+       }
+
+done:
+       NdisReleaseSpinLock(&pAd->BATabLock);
+       return pBAEntry;
+}
+
+BA_ORI_ENTRY *BATableAllocOriEntry(
+                                                                 IN  PRTMP_ADAPTER   pAd,
+                                                                 OUT USHORT          *Idx)
+{
+       int             i;
+       BA_ORI_ENTRY    *pBAEntry = NULL;
+
+       NdisAcquireSpinLock(&pAd->BATabLock);
+
+       if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE))
+       {
+               goto done;
+       }
+
+       // reserve idx 0 to identify BAWcidArray[TID] as empty
+       for (i=1; i<MAX_LEN_OF_BA_ORI_TABLE; i++)
+       {
+               pBAEntry =&pAd->BATable.BAOriEntry[i];
+               if ((pBAEntry->ORI_BA_Status == Originator_NONE))
+               {
+                       // get one
+                       pAd->BATable.numAsOriginator++;
+                       pBAEntry->ORI_BA_Status = Originator_USED;
+                       pBAEntry->pAdapter = pAd;
+                       *Idx = i;
+                       break;
+               }
+       }
+
+done:
+       NdisReleaseSpinLock(&pAd->BATabLock);
+       return pBAEntry;
+}
+
+
+VOID BATableFreeOriEntry(
+                                               IN  PRTMP_ADAPTER   pAd,
+                                               IN  ULONG           Idx)
+{
+       BA_ORI_ENTRY    *pBAEntry = NULL;
+       MAC_TABLE_ENTRY *pEntry;
+
+
+       if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE))
+               return;
+
+       pBAEntry =&pAd->BATable.BAOriEntry[Idx];
+
+       if (pBAEntry->ORI_BA_Status != Originator_NONE)
+       {
+               pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
+               pEntry->BAOriWcidArray[pBAEntry->TID] = 0;
+
+
+               NdisAcquireSpinLock(&pAd->BATabLock);
+               if (pBAEntry->ORI_BA_Status == Originator_Done)
+               {
+                       pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) ));
+                       DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient));
+                       // Erase Bitmap flag.
+               }
+
+               ASSERT(pAd->BATable.numAsOriginator != 0);
+
+               pAd->BATable.numAsOriginator -= 1;
+
+               pBAEntry->ORI_BA_Status = Originator_NONE;
+               pBAEntry->Token = 0;
+               NdisReleaseSpinLock(&pAd->BATabLock);
+       }
+}
+
+
+VOID BATableFreeRecEntry(
+                                               IN  PRTMP_ADAPTER   pAd,
+                                               IN  ULONG           Idx)
+{
+       BA_REC_ENTRY    *pBAEntry = NULL;
+       MAC_TABLE_ENTRY *pEntry;
+
+
+       if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE))
+               return;
+
+       pBAEntry =&pAd->BATable.BARecEntry[Idx];
+
+       if (pBAEntry->REC_BA_Status != Recipient_NONE)
+       {
+               pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
+               pEntry->BARecWcidArray[pBAEntry->TID] = 0;
+
+               NdisAcquireSpinLock(&pAd->BATabLock);
+
+               ASSERT(pAd->BATable.numAsRecipient != 0);
+
+               pAd->BATable.numAsRecipient -= 1;
+
+               pBAEntry->REC_BA_Status = Recipient_NONE;
+               NdisReleaseSpinLock(&pAd->BATabLock);
+       }
+}
+
+
+VOID BAOriSessionTearDown(
+                                                IN OUT  PRTMP_ADAPTER   pAd,
+                                                IN      UCHAR           Wcid,
+                                                IN      UCHAR           TID,
+                                                IN      BOOLEAN         bPassive,
+                                                IN      BOOLEAN         bForceSend)
+{
+       ULONG           Idx = 0;
+       BA_ORI_ENTRY    *pBAEntry;
+       BOOLEAN         Cancelled;
+
+       if (Wcid >= MAX_LEN_OF_MAC_TABLE)
+       {
+               return;
+       }
+
+       //
+       // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID).
+       //
+       Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID];
+       if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE))
+       {
+               if (bForceSend == TRUE)
+               {
+                       // force send specified TID DelBA
+                       MLME_DELBA_REQ_STRUCT   DelbaReq;
+                       MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
+
+                       NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
+                       NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM));
+
+                       COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr);
+                       DelbaReq.Wcid = Wcid;
+                       DelbaReq.TID = TID;
+                       DelbaReq.Initiator = ORIGINATOR;
+#if 1
+                       Elem->MsgLen  = sizeof(DelbaReq);
+                       NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq));
+                       MlmeDELBAAction(pAd, Elem);
+                       kfree(Elem);
+#else
+                       MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq);
+                       RT28XX_MLME_HANDLER(pAd);
+#endif
+               }
+
+               return;
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+
+       pBAEntry = &pAd->BATable.BAOriEntry[Idx];
+       DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status));
+       //
+       // Prepare DelBA action frame and send to the peer.
+       //
+       if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done))
+       {
+               MLME_DELBA_REQ_STRUCT   DelbaReq;
+               MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
+
+               NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
+               NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM));
+
+               COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr);
+               DelbaReq.Wcid = Wcid;
+               DelbaReq.TID = pBAEntry->TID;
+               DelbaReq.Initiator = ORIGINATOR;
+#if 1
+               Elem->MsgLen  = sizeof(DelbaReq);
+               NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq));
+               MlmeDELBAAction(pAd, Elem);
+               kfree(Elem);
+#else
+               MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq);
+               RT28XX_MLME_HANDLER(pAd);
+#endif
+       }
+       RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
+       BATableFreeOriEntry(pAd, Idx);
+
+       if (bPassive)
+       {
+               //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE);
+       }
+}
+
+VOID BARecSessionTearDown(
+                                                IN OUT  PRTMP_ADAPTER   pAd,
+                                                IN      UCHAR           Wcid,
+                                                IN      UCHAR           TID,
+                                                IN      BOOLEAN         bPassive)
+{
+       ULONG           Idx = 0;
+       BA_REC_ENTRY    *pBAEntry;
+
+       if (Wcid >= MAX_LEN_OF_MAC_TABLE)
+       {
+               return;
+       }
+
+       //
+       //  Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID).
+       //
+       Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
+       if (Idx == 0)
+               return;
+
+       DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+
+
+       pBAEntry = &pAd->BATable.BARecEntry[Idx];
+       DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status));
+       //
+       // Prepare DelBA action frame and send to the peer.
+       //
+       if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept))
+       {
+               MLME_DELBA_REQ_STRUCT   DelbaReq;
+               BOOLEAN                                 Cancelled;
+               MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
+               //ULONG   offset;
+               //UINT32  VALUE;
+
+               RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled);
+
+               //
+               // 1. Send DELBA Action Frame
+               //
+               if (bPassive == FALSE)
+               {
+                       NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
+                       NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM));
+
+                       COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr);
+                       DelbaReq.Wcid = Wcid;
+                       DelbaReq.TID = TID;
+                       DelbaReq.Initiator = RECIPIENT;
+#if 1
+                       Elem->MsgLen  = sizeof(DelbaReq);
+                       NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq));
+                       MlmeDELBAAction(pAd, Elem);
+                       kfree(Elem);
+#else
+                       MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq);
+                       RT28XX_MLME_HANDLER(pAd);
+#endif
+               }
+
+
+               //
+               // 2. Free resource of BA session
+               //
+               // flush all pending reordering mpdus
+               ba_refresh_reordering_mpdus(pAd, pBAEntry);
+
+               NdisAcquireSpinLock(&pAd->BATabLock);
+
+               // Erase Bitmap flag.
+               pBAEntry->LastIndSeq = RESET_RCV_SEQ;
+               pBAEntry->BAWinSize = 0;
+               // Erase Bitmap flag at software mactable
+               pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID)));
+               pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0;
+
+               RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID);
+
+               NdisReleaseSpinLock(&pAd->BATabLock);
+
+       }
+
+       BATableFreeRecEntry(pAd, Idx);
+}
+
+VOID BASessionTearDownALL(
+                                                IN OUT  PRTMP_ADAPTER pAd,
+                                                IN      UCHAR Wcid)
+{
+       int i;
+
+       for (i=0; i<NUM_OF_TID; i++)
+       {
+               BAOriSessionTearDown(pAd, Wcid, i, FALSE, FALSE);
+               BARecSessionTearDown(pAd, Wcid, i, FALSE);
+       }
+}
+
+
+/*
+       ==========================================================================
+       Description:
+               Retry sending ADDBA Reqest.
+
+       IRQL = DISPATCH_LEVEL
+
+       Parametrs:
+       p8023Header: if this is already 802.3 format, p8023Header is NULL
+
+       Return  : TRUE if put into rx reordering buffer, shouldn't indicaterxhere.
+                               FALSE , then continue indicaterx at this moment.
+       ==========================================================================
+ */
+VOID BAOriSessionSetupTimeout(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3)
+{
+       BA_ORI_ENTRY    *pBAEntry = (BA_ORI_ENTRY *)FunctionContext;
+       MAC_TABLE_ENTRY *pEntry;
+       PRTMP_ADAPTER   pAd;
+
+       if (pBAEntry == NULL)
+               return;
+
+       pAd = pBAEntry->pAdapter;
+
+#ifdef CONFIG_STA_SUPPORT
+       IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+       {
+               // Do nothing if monitor mode is on
+               if (MONITOR_ON(pAd))
+                       return;
+       }
+#endif // CONFIG_STA_SUPPORT //
+
+#ifdef RALINK_ATE
+       // Nothing to do in ATE mode.
+       if (ATE_ON(pAd))
+               return;
+#endif // RALINK_ATE //
+
+       pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
+
+       if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY))
+       {
+               MLME_ADDBA_REQ_STRUCT    AddbaReq;
+
+               NdisZeroMemory(&AddbaReq, sizeof(AddbaReq));
+               COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr);
+               AddbaReq.Wcid = (UCHAR)(pEntry->Aid);
+               AddbaReq.TID = pBAEntry->TID;
+               AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit;
+               AddbaReq.TimeOutValue = 0;
+               AddbaReq.Token = pBAEntry->Token;
+               MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq);
+               RT28XX_MLME_HANDLER(pAd);
+               //DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token));
+
+               DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d Wcid:%d\n"
+               ,pBAEntry->Token
+               ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2]
+               ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5]
+               ,pBAEntry->TID,pEntry->Aid));
+
+               pBAEntry->Token++;
+               RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT);
+       }
+       else
+       {
+               BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]);
+       }
+}
+
+/*
+       ==========================================================================
+       Description:
+               Retry sending ADDBA Reqest.
+
+       IRQL = DISPATCH_LEVEL
+
+       Parametrs:
+       p8023Header: if this is already 802.3 format, p8023Header is NULL
+
+       Return  : TRUE if put into rx reordering buffer, shouldn't indicaterxhere.
+                               FALSE , then continue indicaterx at this moment.
+       ==========================================================================
+ */
+VOID BARecSessionIdleTimeout(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3)
+{
+
+       BA_REC_ENTRY    *pBAEntry = (BA_REC_ENTRY *)FunctionContext;
+       PRTMP_ADAPTER   pAd;
+       ULONG           Now32;
+
+       if (pBAEntry == NULL)
+               return;
+
+       if ((pBAEntry->REC_BA_Status == Recipient_Accept))
+       {
+               NdisGetSystemUpTime(&Now32);
+
+               if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT)))
+               {
+                       pAd = pBAEntry->pAdapter;
+                       // flush all pending reordering mpdus
+                       ba_refresh_reordering_mpdus(pAd, pBAEntry);
+                       printk("%ld: REC BA session Timeout\n", Now32);
+               }
+       }
+}
+
+
+VOID PeerAddBAReqAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+
+{
+       //      7.4.4.1
+       //ULONG Idx;
+       UCHAR   Status = 1;
+       UCHAR   pAddr[6];
+       FRAME_ADDBA_RSP ADDframe;
+       PUCHAR         pOutBuffer = NULL;
+       NDIS_STATUS     NStatus;
+       PFRAME_ADDBA_REQ  pAddreqFrame = NULL;
+       //UCHAR         BufSize;
+       ULONG       FrameLen;
+       PULONG      ptemp;
+       PMAC_TABLE_ENTRY        pMacEntry;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid));
+
+       //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen);
+
+       //ADDBA Request from unknown peer, ignore this.
+       if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
+               return;
+
+       pMacEntry = &pAd->MacTab.Content[Elem->Wcid];
+       DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n"));
+       ptemp = (PULONG)Elem->Msg;
+       //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8)));
+
+       if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr))
+       {
+
+               if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry))
+               {
+                       pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]);
+                       printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid);
+                       if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame))
+                               Status = 0;
+                       else
+                               Status = 38; // more parameters have invalid values
+               }
+               else
+               {
+                       Status = 37; // the request has been declined.
+               }
+       }
+
+       if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI)
+               ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC);
+
+       pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]);
+       // 2. Always send back ADDBA Response
+       NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
+       if (NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n"));
+               return;
+       }
+
+       NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP));
+       // 2-1. Prepare ADDBA Response frame.
+#ifdef CONFIG_STA_SUPPORT
+       IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+       {
+               if (ADHOC_ON(pAd))
+                       ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid);
+               else
+                       ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr);
+       }
+#endif // CONFIG_STA_SUPPORT //
+       ADDframe.Category = CATEGORY_BA;
+       ADDframe.Action = ADDBA_RESP;
+       ADDframe.Token = pAddreqFrame->Token;
+       // What is the Status code??  need to check.
+       ADDframe.StatusCode = Status;
+       ADDframe.BaParm.BAPolicy = IMMED_BA;
+       ADDframe.BaParm.AMSDUSupported = 0;
+       ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID;
+       ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit);
+       if (ADDframe.BaParm.BufSize == 0)
+       {
+               ADDframe.BaParm.BufSize = 64;
+       }
+       ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue;
+
+       *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm));
+       ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode);
+       ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue);
+
+       MakeOutgoingFrame(pOutBuffer,               &FrameLen,
+                                         sizeof(FRAME_ADDBA_RSP),  &ADDframe,
+                         END_OF_ARGS);
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID,
+                                                         ADDframe.BaParm.BufSize));
+}
+
+
+VOID PeerAddBARspAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+
+{
+       //UCHAR         Idx, i;
+       //PUCHAR                   pOutBuffer = NULL;
+       PFRAME_ADDBA_RSP    pFrame = NULL;
+       //PBA_ORI_ENTRY         pBAEntry;
+
+       //ADDBA Response from unknown peer, ignore this.
+       if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
+               return;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid));
+
+       //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen);
+
+       if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen))
+       {
+               pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]);
+
+               DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode));
+               switch (pFrame->StatusCode)
+               {
+                       case 0:
+                               // I want a BAsession with this peer as an originator.
+                               BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame);
+                               break;
+                       default:
+                               // check status == USED ???
+                               BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE);
+                               break;
+               }
+               // Rcv Decline StatusCode
+               if ((pFrame->StatusCode == 37)
+#ifdef CONFIG_STA_SUPPORT
+            || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0))
+#endif // CONFIG_STA_SUPPORT //
+            )
+               {
+                       pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<<pFrame->BaParm.TID;
+               }
+       }
+}
+
+VOID PeerDelBAAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+
+{
+       //UCHAR                         Idx;
+       //PUCHAR                                pOutBuffer = NULL;
+       PFRAME_DELBA_REQ    pDelFrame = NULL;
+
+       DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__));
+       //DELBA Request from unknown peer, ignore this.
+       if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen))
+       {
+               pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]);
+               if (pDelFrame->DelbaParm.Initiator == ORIGINATOR)
+               {
+                       DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n"));
+                       BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE);
+               }
+               else
+               {
+                       DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n",  pDelFrame->ReasonCode));
+                       //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen);
+                       BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE);
+               }
+       }
+}
+
+
+BOOLEAN CntlEnqueueForRecv(
+                                                 IN PRTMP_ADAPTER              pAd,
+                                                 IN ULONG                              Wcid,
+                                                 IN ULONG                              MsgLen,
+                                                 IN PFRAME_BA_REQ              pMsg)
+{
+       PFRAME_BA_REQ   pFrame = pMsg;
+       //PRTMP_REORDERBUF      pBuffer;
+       //PRTMP_REORDERBUF      pDmaBuf;
+       PBA_REC_ENTRY pBAEntry;
+       //BOOLEAN       Result;
+       ULONG   Idx;
+       //UCHAR NumRxPkt;
+       UCHAR   TID;//, i;
+
+       TID = (UCHAR)pFrame->BARControl.TID;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID));
+       //hex_dump("BAR", (PCHAR) pFrame, MsgLen);
+       // Do nothing if the driver is starting halt state.
+       // This might happen when timer already been fired before cancel timer with mlmehalt
+       if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
+               return FALSE;
+
+       // First check the size, it MUST not exceed the mlme queue size
+       if (MsgLen > MGMT_DMA_BUFFER_SIZE)
+       {
+               DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
+               return FALSE;
+       }
+       else if (MsgLen != sizeof(FRAME_BA_REQ))
+       {
+               DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
+               return FALSE;
+       }
+       else if (MsgLen != sizeof(FRAME_BA_REQ))
+       {
+               DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
+               return FALSE;
+       }
+
+       if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8))
+               {
+               // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search.
+               Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
+               pBAEntry = &pAd->BATable.BARecEntry[Idx];
+               }
+               else
+               {
+               return FALSE;
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq ));
+
+       if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ))
+       {
+               //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq);
+               ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq);
+               pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1);
+       }
+       //ba_refresh_reordering_mpdus(pAd, pBAEntry);
+       return TRUE;
+}
+
+/*
+Description : Send PSMP Action frame If PSMP mode switches.
+*/
+VOID SendPSMPAction(
+                                  IN PRTMP_ADAPTER             pAd,
+                                  IN UCHAR                             Wcid,
+                                  IN UCHAR                             Psmp)
+{
+       PUCHAR          pOutBuffer = NULL;
+       NDIS_STATUS     NStatus;
+       //ULONG           Idx;
+       FRAME_PSMP_ACTION   Frame;
+       ULONG           FrameLen;
+#ifdef RT30xx
+       UCHAR                   bbpdata=0;
+       UINT32                  macdata;
+#endif // RT30xx //
+
+       NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
+       if (NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n"));
+               return;
+       }
+#ifdef CONFIG_STA_SUPPORT
+       IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+               ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr);
+#endif // CONFIG_STA_SUPPORT //
+
+       Frame.Category = CATEGORY_HT;
+       Frame.Action = SMPS_ACTION;
+       switch (Psmp)
+       {
+               case MMPS_ENABLE:
+#ifdef RT30xx
+                       if (IS_RT3090(pAd))
+                       {
+                               // disable MMPS BBP control register
+                               RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata);
+                               bbpdata &= ~(0x04);     //bit 2
+                               RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata);
+
+                               // disable MMPS MAC control register
+                               RTMP_IO_READ32(pAd, 0x1210, &macdata);
+                               macdata &= ~(0x09);     //bit 0, 3
+                               RTMP_IO_WRITE32(pAd, 0x1210, macdata);
+                       }
+#endif // RT30xx //
+                       Frame.Psmp = 0;
+                       break;
+               case MMPS_DYNAMIC:
+#ifdef RT30xx
+                       if (IS_RT3090(pAd))
+                       {
+                               // enable MMPS BBP control register
+                               RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata);
+                               bbpdata |= 0x04;        //bit 2
+                               RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata);
+
+                               // enable MMPS MAC control register
+                               RTMP_IO_READ32(pAd, 0x1210, &macdata);
+                               macdata |= 0x09;        //bit 0, 3
+                               RTMP_IO_WRITE32(pAd, 0x1210, macdata);
+                       }
+#endif // RT30xx //
+                       Frame.Psmp = 3;
+                       break;
+               case MMPS_STATIC:
+#ifdef RT30xx
+                       if (IS_RT3090(pAd))
+                       {
+                               // enable MMPS BBP control register
+                               RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata);
+                               bbpdata |= 0x04;        //bit 2
+                               RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata);
+
+                               // enable MMPS MAC control register
+                               RTMP_IO_READ32(pAd, 0x1210, &macdata);
+                               macdata |= 0x09;        //bit 0, 3
+                               RTMP_IO_WRITE32(pAd, 0x1210, macdata);
+                       }
+#endif // RT30xx //
+                       Frame.Psmp = 1;
+                       break;
+       }
+       MakeOutgoingFrame(pOutBuffer,               &FrameLen,
+                                         sizeof(FRAME_PSMP_ACTION),      &Frame,
+                                         END_OF_ARGS);
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+       DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d )  \n", Frame.Psmp));
+}
+
+
+#define RADIO_MEASUREMENT_REQUEST_ACTION       0
+
+typedef struct PACKED
+{
+       UCHAR   RegulatoryClass;
+       UCHAR   ChannelNumber;
+       USHORT  RandomInterval;
+       USHORT  MeasurementDuration;
+       UCHAR   MeasurementMode;
+       UCHAR   BSSID[MAC_ADDR_LEN];
+       UCHAR   ReportingCondition;
+       UCHAR   Threshold;
+       UCHAR   SSIDIE[2];                      // 2 byte
+} BEACON_REQUEST;
+
+typedef struct PACKED
+{
+       UCHAR   ID;
+       UCHAR   Length;
+       UCHAR   Token;
+       UCHAR   RequestMode;
+       UCHAR   Type;
+} MEASUREMENT_REQ;
+
+
+
+
+void convert_reordering_packet_to_preAMSDU_or_802_3_packet(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      RX_BLK                  *pRxBlk,
+       IN  UCHAR                       FromWhichBSSID)
+{
+       PNDIS_PACKET    pRxPkt;
+       UCHAR                   Header802_3[LENGTH_802_3];
+
+       // 1. get 802.3 Header
+       // 2. remove LLC
+       //              a. pointer pRxBlk->pData to payload
+       //      b. modify pRxBlk->DataSize
+
+#ifdef CONFIG_STA_SUPPORT
+       IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+               RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3);
+#endif // CONFIG_STA_SUPPORT //
+
+       ASSERT(pRxBlk->pRxPacket);
+       pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket);
+
+       RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
+       RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData;
+       RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize;
+       RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len;
+
+       //
+       // copy 802.3 header, if necessary
+       //
+       if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU))
+       {
+
+#ifdef CONFIG_STA_SUPPORT
+               IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+               {
+#ifdef LINUX
+                       NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3);
+#endif
+#ifdef UCOS
+                       NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3);
+#endif
+               }
+#endif // CONFIG_STA_SUPPORT //
+       }
+}
+
+
+#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID)               \
+       do                                                                                                                                      \
+       {                                                                                                                                       \
+       if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU))                                               \
+       {                                                                                                                               \
+               Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID);          \
+       }                                                                                                                               \
+               else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP))                                    \
+               {                                                                                                                               \
+                       Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID);          \
+               }                                                                                                                               \
+       else                                                                                                                    \
+       {                                                                                                                               \
+               Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID);         \
+       }                                                                                                                               \
+       } while (0);
+
+
+
+static VOID ba_enqueue_reordering_packet(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      PBA_REC_ENTRY   pBAEntry,
+       IN      RX_BLK                  *pRxBlk,
+       IN      UCHAR                   FromWhichBSSID)
+{
+       struct reordering_mpdu *mpdu_blk;
+       UINT16  Sequence = (UINT16) pRxBlk->pHeader->Sequence;
+
+       mpdu_blk = ba_mpdu_blk_alloc(pAd);
+       if (mpdu_blk != NULL)
+       {
+               // Write RxD buffer address & allocated buffer length
+               NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
+
+               mpdu_blk->Sequence = Sequence;
+
+               mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU);
+
+               convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID);
+
+               STATS_INC_RX_PACKETS(pAd, FromWhichBSSID);
+
+        //
+               // it is necessary for reordering packet to record
+               // which BSS it come from
+               //
+               RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID);
+
+               mpdu_blk->pPacket = pRxBlk->pRxPacket;
+
+               if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE)
+               {
+                       // had been already within reordering list
+                       // don't indicate
+                       RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS);
+                       ba_mpdu_blk_free(pAd, mpdu_blk);
+               }
+
+               ASSERT((0<= pBAEntry->list.qlen)  && (pBAEntry->list.qlen <= pBAEntry->BAWinSize));
+               NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
+       }
+       else
+       {
+               DBGPRINT(RT_DEBUG_ERROR,  ("!!! (%d) Can't allocate reordering mpdu blk\n",
+                                                                  pBAEntry->list.qlen));
+               /*
+                * flush all pending reordering mpdus
+                * and receving mpdu to upper layer
+                * make tcp/ip to take care reordering mechanism
+                */
+               //ba_refresh_reordering_mpdus(pAd, pBAEntry);
+               ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence);
+
+               pBAEntry->LastIndSeq = Sequence;
+               INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
+       }
+}
+
+
+/*
+       ==========================================================================
+       Description:
+               Indicate this packet to upper layer or put it into reordering buffer
+
+       Parametrs:
+               pRxBlk         : carry necessary packet info 802.11 format
+               FromWhichBSSID : the packet received from which BSS
+
+       Return  :
+                         none
+
+       Note    :
+                 the packet queued into reordering buffer need to cover to 802.3 format
+                         or pre_AMSDU format
+       ==========================================================================
+ */
+
+VOID Indicate_AMPDU_Packet(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      RX_BLK                  *pRxBlk,
+       IN      UCHAR                   FromWhichBSSID)
+{
+       USHORT                          Idx;
+       PBA_REC_ENTRY           pBAEntry = NULL;
+       UINT16                          Sequence = pRxBlk->pHeader->Sequence;
+       ULONG                           Now32;
+       UCHAR                           Wcid = pRxBlk->pRxWI->WirelessCliID;
+       UCHAR                           TID = pRxBlk->pRxWI->TID;
+
+
+       if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) &&  (pRxBlk->DataSize > MAX_RX_PKT_LEN))
+       {
+               // release packet
+               RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
+               return;
+       }
+
+       if (Wcid < MAX_LEN_OF_MAC_TABLE)
+       {
+               Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
+               if (Idx == 0)
+               {
+                       /* Rec BA Session had been torn down */
+                       INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
+                       return;
+               }
+               pBAEntry = &pAd->BATable.BARecEntry[Idx];
+       }
+       else
+       {
+               // impossible !!!
+               ASSERT(0);
+               // release packet
+               RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
+               return;
+       }
+
+       ASSERT(pBAEntry);
+
+       // update last rx time
+       NdisGetSystemUpTime(&Now32);
+
+       pBAEntry->rcvSeq = Sequence;
+
+
+       ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32);
+       pBAEntry->LastIndSeqAtTimer = Now32;
+
+       //
+       // Reset Last Indicate Sequence
+       //
+       if (pBAEntry->LastIndSeq == RESET_RCV_SEQ)
+       {
+               ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL));
+
+               // reset rcv sequence of BA session
+               pBAEntry->LastIndSeq = Sequence;
+               pBAEntry->LastIndSeqAtTimer = Now32;
+               INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
+               return;
+       }
+
+
+       //
+       // I. Check if in order.
+       //
+       if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ))
+       {
+               USHORT  LastIndSeq;
+
+               pBAEntry->LastIndSeq = Sequence;
+               INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
+               LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq);
+               if (LastIndSeq != RESET_RCV_SEQ)
+               {
+                       pBAEntry->LastIndSeq = LastIndSeq;
+               }
+               pBAEntry->LastIndSeqAtTimer = Now32;
+       }
+       //
+       // II. Drop Duplicated Packet
+       //
+       else if (Sequence == pBAEntry->LastIndSeq)
+       {
+
+               // drop and release packet
+               pBAEntry->nDropPacket++;
+               RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
+       }
+       //
+       // III. Drop Old Received Packet
+       //
+       else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ))
+       {
+
+               // drop and release packet
+               pBAEntry->nDropPacket++;
+               RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
+       }
+       //
+       // IV. Receive Sequence within Window Size
+       //
+       else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ))
+       {
+               ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID);
+       }
+       //
+       // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer
+       //
+       else
+       {
+               LONG WinStartSeq, TmpSeq;
+
+
+               TmpSeq = Sequence - (pBAEntry->BAWinSize) -1;
+               if (TmpSeq < 0)
+               {
+                       TmpSeq = (MAXSEQ+1) + TmpSeq;
+               }
+               WinStartSeq = (TmpSeq+1) & MAXSEQ;
+               ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq);
+               pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq;
+
+               pBAEntry->LastIndSeqAtTimer = Now32;
+
+               ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID);
+
+               TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq);
+               if (TmpSeq != RESET_RCV_SEQ)
+               {
+                       pBAEntry->LastIndSeq = TmpSeq;
+               }
+       }
+}
+
+#endif // DOT11_N_SUPPORT //
+