• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rt2860/common/
1/*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
7 *
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify  *
11 * it under the terms of the GNU General Public License as published by  *
12 * the Free Software Foundation; either version 2 of the License, or     *
13 * (at your option) any later version.                                   *
14 *                                                                       *
15 * This program is distributed in the hope that it will be useful,       *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18 * GNU General Public License for more details.                          *
19 *                                                                       *
20 * You should have received a copy of the GNU General Public License     *
21 * along with this program; if not, write to the                         *
22 * Free Software Foundation, Inc.,                                       *
23 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24 *                                                                       *
25 *************************************************************************
26 */
27
28#include "../rt_config.h"
29
30#define BA_ORI_INIT_SEQ		(pEntry->TxSeq[TID])	/*1                        // inital sequence number of BA session */
31
32#define ORI_SESSION_MAX_RETRY	8
33#define ORI_BA_SESSION_TIMEOUT	(2000)	/* ms */
34#define REC_BA_SESSION_IDLE_TIMEOUT	(1000)	/* ms */
35
36#define REORDERING_PACKET_TIMEOUT		((100 * OS_HZ)/1000)	/* system ticks -- 100 ms */
37#define MAX_REORDERING_PACKET_TIMEOUT	((3000 * OS_HZ)/1000)	/* system ticks -- 100 ms */
38
39#define RESET_RCV_SEQ		(0xFFFF)
40
41static void ba_mpdu_blk_free(struct rt_rtmp_adapter *pAd,
42			     struct reordering_mpdu *mpdu_blk);
43
44struct rt_ba_ori_entry *BATableAllocOriEntry(struct rt_rtmp_adapter *pAd, u16 * Idx);
45
46struct rt_ba_rec_entry *BATableAllocRecEntry(struct rt_rtmp_adapter *pAd, u16 * Idx);
47
48void BAOriSessionSetupTimeout(void *SystemSpecific1,
49			      void *FunctionContext,
50			      void *SystemSpecific2,
51			      void *SystemSpecific3);
52
53void BARecSessionIdleTimeout(void *SystemSpecific1,
54			     void *FunctionContext,
55			     void *SystemSpecific2,
56			     void *SystemSpecific3);
57
58BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout);
59BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout);
60
61#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk)	\
62			Announce_Reordering_Packet(_pAd, _mpdu_blk);
63
64void BA_MaxWinSizeReasign(struct rt_rtmp_adapter *pAd,
65			  struct rt_mac_table_entry *pEntryPeer, u8 * pWinSize)
66{
67	u8 MaxSize;
68
69	if (pAd->MACVersion >= RALINK_2883_VERSION)	/* 3*3 */
70	{
71		if (pAd->MACVersion >= RALINK_3070_VERSION) {
72			if (pEntryPeer->WepStatus !=
73			    Ndis802_11EncryptionDisabled)
74				MaxSize = 7;	/* for non-open mode */
75			else
76				MaxSize = 13;
77		} else
78			MaxSize = 31;
79	} else if (pAd->MACVersion >= RALINK_2880E_VERSION)	/* 2880 e */
80	{
81		if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled)
82			MaxSize = 7;	/* for non-open mode */
83		else
84			MaxSize = 13;
85	} else
86		MaxSize = 7;
87
88	DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n",
89				  *pWinSize, MaxSize));
90
91	if ((*pWinSize) > MaxSize) {
92		DBGPRINT(RT_DEBUG_TRACE,
93			 ("ba> reassign max win size from %d to %d\n",
94			  *pWinSize, MaxSize));
95
96		*pWinSize = MaxSize;
97	}
98}
99
100void Announce_Reordering_Packet(struct rt_rtmp_adapter *pAd,
101				IN struct reordering_mpdu *mpdu)
102{
103	void *pPacket;
104
105	pPacket = mpdu->pPacket;
106
107	if (mpdu->bAMSDU) {
108		ASSERT(0);
109		BA_Reorder_AMSDU_Annnounce(pAd, pPacket);
110	} else {
111		/* */
112		/* pass this 802.3 packet to upper layer or forward this packet to WM directly */
113		/* */
114
115		ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket,
116						 RTMP_GET_PACKET_IF(pPacket));
117	}
118}
119
120/*
121 * Insert a reordering mpdu into sorted linked list by sequence no.
122 */
123BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list,
124					struct reordering_mpdu *mpdu)
125{
126
127	struct reordering_mpdu **ppScan = &list->next;
128
129	while (*ppScan != NULL) {
130		if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) {
131			ppScan = &(*ppScan)->next;
132		} else if ((*ppScan)->Sequence == mpdu->Sequence) {
133			/* give up this duplicated frame */
134			return (FALSE);
135		} else {
136			/* find position */
137			break;
138		}
139	}
140
141	mpdu->next = *ppScan;
142	*ppScan = mpdu;
143	list->qlen++;
144	return TRUE;
145}
146
147/*
148 * caller lock critical section if necessary
149 */
150static inline void ba_enqueue(struct reordering_list *list,
151			      struct reordering_mpdu *mpdu_blk)
152{
153	list->qlen++;
154	mpdu_blk->next = list->next;
155	list->next = mpdu_blk;
156}
157
158/*
159 * caller lock critical section if necessary
160 */
161static inline struct reordering_mpdu *ba_dequeue(struct reordering_list *list)
162{
163	struct reordering_mpdu *mpdu_blk = NULL;
164
165	ASSERT(list);
166
167	if (list->qlen) {
168		list->qlen--;
169		mpdu_blk = list->next;
170		if (mpdu_blk) {
171			list->next = mpdu_blk->next;
172			mpdu_blk->next = NULL;
173		}
174	}
175	return mpdu_blk;
176}
177
178static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct
179								 reordering_list
180								 *list)
181{
182	return (ba_dequeue(list));
183}
184
185static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct
186							       reordering_list
187							       *list)
188{
189	ASSERT(list);
190
191	return (list->next);
192}
193
194/*
195 * free all resource for reordering mechanism
196 */
197void ba_reordering_resource_release(struct rt_rtmp_adapter *pAd)
198{
199	struct rt_ba_table *Tab;
200	struct rt_ba_rec_entry *pBAEntry;
201	struct reordering_mpdu *mpdu_blk;
202	int i;
203
204	Tab = &pAd->BATable;
205
206	/* I.  release all pending reordering packet */
207	NdisAcquireSpinLock(&pAd->BATabLock);
208	for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) {
209		pBAEntry = &Tab->BARecEntry[i];
210		if (pBAEntry->REC_BA_Status != Recipient_NONE) {
211			while ((mpdu_blk =
212				ba_reordering_mpdu_dequeue(&pBAEntry->list))) {
213				ASSERT(mpdu_blk->pPacket);
214				RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket,
215						    NDIS_STATUS_FAILURE);
216				ba_mpdu_blk_free(pAd, mpdu_blk);
217			}
218		}
219	}
220	NdisReleaseSpinLock(&pAd->BATabLock);
221
222	ASSERT(pBAEntry->list.qlen == 0);
223	/* II. free memory of reordering mpdu table */
224	NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
225	os_free_mem(pAd, pAd->mpdu_blk_pool.mem);
226	NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
227}
228
229/*
230 * Allocate all resource for reordering mechanism
231 */
232BOOLEAN ba_reordering_resource_init(struct rt_rtmp_adapter *pAd, int num)
233{
234	int i;
235	u8 *mem;
236	struct reordering_mpdu *mpdu_blk;
237	struct reordering_list *freelist;
238
239	/* allocate spinlock */
240	NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock);
241
242	/* initialize freelist */
243	freelist = &pAd->mpdu_blk_pool.freelist;
244	freelist->next = NULL;
245	freelist->qlen = 0;
246
247	DBGPRINT(RT_DEBUG_TRACE,
248		 ("Allocate %d memory for BA reordering\n",
249		  (u32)(num * sizeof(struct reordering_mpdu))));
250
251	/* allocate number of mpdu_blk memory */
252	os_alloc_mem(pAd, (u8 **) & mem,
253		     (num * sizeof(struct reordering_mpdu)));
254
255	pAd->mpdu_blk_pool.mem = mem;
256
257	if (mem == NULL) {
258		DBGPRINT(RT_DEBUG_ERROR,
259			 ("Can't Allocate Memory for BA Reordering\n"));
260		return (FALSE);
261	}
262
263	/* build mpdu_blk free list */
264	for (i = 0; i < num; i++) {
265		/* get mpdu_blk */
266		mpdu_blk = (struct reordering_mpdu *)mem;
267		/* initial mpdu_blk */
268		NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu));
269		/* next mpdu_blk */
270		mem += sizeof(struct reordering_mpdu);
271		/* insert mpdu_blk into freelist */
272		ba_enqueue(freelist, mpdu_blk);
273	}
274
275	return (TRUE);
276}
277
278/*static int blk_count=0; // sample take off, no use */
279
280static struct reordering_mpdu *ba_mpdu_blk_alloc(struct rt_rtmp_adapter *pAd)
281{
282	struct reordering_mpdu *mpdu_blk;
283
284	NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
285	mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist);
286	if (mpdu_blk) {
287/*              blk_count++; */
288		/* reset mpdu_blk */
289		NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu));
290	}
291	NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
292	return mpdu_blk;
293}
294
295static void ba_mpdu_blk_free(struct rt_rtmp_adapter *pAd,
296			     struct reordering_mpdu *mpdu_blk)
297{
298	ASSERT(mpdu_blk);
299
300	NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock);
301/*      blk_count--; */
302	ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk);
303	NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock);
304}
305
306static u16 ba_indicate_reordering_mpdus_in_order(struct rt_rtmp_adapter *pAd,
307						    struct rt_ba_rec_entry *pBAEntry,
308						    u16 StartSeq)
309{
310	struct reordering_mpdu *mpdu_blk;
311	u16 LastIndSeq = RESET_RCV_SEQ;
312
313	NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
314
315	while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) {
316		/* find in-order frame */
317		if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) {
318			break;
319		}
320		/* dequeue in-order frame from reodering list */
321		mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list);
322		/* pass this frame up */
323		ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
324		/* move to next sequence */
325		StartSeq = mpdu_blk->Sequence;
326		LastIndSeq = StartSeq;
327		/* free mpdu_blk */
328		ba_mpdu_blk_free(pAd, mpdu_blk);
329	}
330
331	NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
332
333	/* update last indicated sequence */
334	return LastIndSeq;
335}
336
337static void ba_indicate_reordering_mpdus_le_seq(struct rt_rtmp_adapter *pAd,
338						struct rt_ba_rec_entry *pBAEntry,
339						u16 Sequence)
340{
341	struct reordering_mpdu *mpdu_blk;
342
343	NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
344	while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) {
345		/* find in-order frame */
346		if ((mpdu_blk->Sequence == Sequence)
347		    || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) {
348			/* dequeue in-order frame from reodering list */
349			mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list);
350			/* pass this frame up */
351			ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
352			/* free mpdu_blk */
353			ba_mpdu_blk_free(pAd, mpdu_blk);
354		} else {
355			break;
356		}
357	}
358	NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
359}
360
361static void ba_refresh_reordering_mpdus(struct rt_rtmp_adapter *pAd,
362					struct rt_ba_rec_entry *pBAEntry)
363{
364	struct reordering_mpdu *mpdu_blk;
365
366	NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
367
368	/* dequeue in-order frame from reodering list */
369	while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) {
370		/* pass this frame up */
371		ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk);
372
373		pBAEntry->LastIndSeq = mpdu_blk->Sequence;
374		ba_mpdu_blk_free(pAd, mpdu_blk);
375
376		/* update last indicated sequence */
377	}
378	ASSERT(pBAEntry->list.qlen == 0);
379	pBAEntry->LastIndSeq = RESET_RCV_SEQ;
380	NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
381}
382
383/*static */
384void ba_flush_reordering_timeout_mpdus(struct rt_rtmp_adapter *pAd,
385				       struct rt_ba_rec_entry *pBAEntry,
386				       unsigned long Now32)
387{
388	u16 Sequence;
389
390/*      if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && */
391/*               (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| */
392/*              (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && */
393/*               (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) */
394	if (RTMP_TIME_AFTER
395	    ((unsigned long)Now32,
396	     (unsigned long)(pBAEntry->LastIndSeqAtTimer +
397			     (MAX_REORDERING_PACKET_TIMEOUT / 6)))
398	    && (pBAEntry->list.qlen > 1)
399	    ) {
400		DBGPRINT(RT_DEBUG_TRACE,
401			 ("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ",
402			  pBAEntry->list.qlen, Now32,
403			  (pBAEntry->LastIndSeqAtTimer),
404			  (int)((long)Now32 -
405				(long)(pBAEntry->LastIndSeqAtTimer)),
406			  MAX_REORDERING_PACKET_TIMEOUT, pBAEntry->LastIndSeq));
407		ba_refresh_reordering_mpdus(pAd, pBAEntry);
408		pBAEntry->LastIndSeqAtTimer = Now32;
409	} else
410	    if (RTMP_TIME_AFTER
411		((unsigned long)Now32,
412		 (unsigned long)(pBAEntry->LastIndSeqAtTimer +
413				 (REORDERING_PACKET_TIMEOUT)))
414		&& (pBAEntry->list.qlen > 0)
415	    ) {
416		/* */
417		/* force LastIndSeq to shift to LastIndSeq+1 */
418		/* */
419		Sequence = (pBAEntry->LastIndSeq + 1) & MAXSEQ;
420		ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence);
421		pBAEntry->LastIndSeqAtTimer = Now32;
422		pBAEntry->LastIndSeq = Sequence;
423		/* */
424		/* indicate in-order mpdus */
425		/* */
426		Sequence =
427		    ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry,
428							  Sequence);
429		if (Sequence != RESET_RCV_SEQ) {
430			pBAEntry->LastIndSeq = Sequence;
431		}
432
433		DBGPRINT(RT_DEBUG_OFF,
434			 ("%x, flush one!\n", pBAEntry->LastIndSeq));
435
436	}
437}
438
439/*
440 * generate ADDBA request to
441 * set up BA agreement
442 */
443void BAOriSessionSetUp(struct rt_rtmp_adapter *pAd,
444		       struct rt_mac_table_entry *pEntry,
445		       u8 TID,
446		       u16 TimeOut,
447		       unsigned long DelayTime, IN BOOLEAN isForced)
448{
449	/*struct rt_mlme_addba_req AddbaReq; */
450	struct rt_ba_ori_entry *pBAEntry = NULL;
451	u16 Idx;
452	BOOLEAN Cancelled;
453
454	if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE)
455	    && (isForced == FALSE))
456		return;
457
458	/* if this entry is limited to use legacy tx mode, it doesn't generate BA. */
459	if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT)
460		return;
461
462	if ((pEntry->BADeclineBitmap & (1 << TID)) && (isForced == FALSE)) {
463		/* try again after 3 secs */
464		DelayTime = 3000;
465/*              DBGPRINT(RT_DEBUG_TRACE, ("DeCline BA from Peer\n")); */
466/*              return; */
467	}
468
469	Idx = pEntry->BAOriWcidArray[TID];
470	if (Idx == 0) {
471		/* allocate a BA session */
472		pBAEntry = BATableAllocOriEntry(pAd, &Idx);
473		if (pBAEntry == NULL) {
474			DBGPRINT(RT_DEBUG_TRACE,
475				 ("ADDBA - MlmeADDBAAction() allocate BA session failed \n"));
476			return;
477		}
478	} else {
479		pBAEntry = &pAd->BATable.BAOriEntry[Idx];
480	}
481
482	if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) {
483		return;
484	}
485
486	pEntry->BAOriWcidArray[TID] = Idx;
487
488	/* Initialize BA session */
489	pBAEntry->ORI_BA_Status = Originator_WaitRes;
490	pBAEntry->Wcid = pEntry->Aid;
491	pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit;
492	pBAEntry->Sequence = BA_ORI_INIT_SEQ;
493	pBAEntry->Token = 1;	/* (2008-01-21) Jan Lee recommends it - this token can't be 0 */
494	pBAEntry->TID = TID;
495	pBAEntry->TimeOutValue = TimeOut;
496	pBAEntry->pAdapter = pAd;
497
498	if (!(pEntry->TXBAbitmap & (1 << TID))) {
499		RTMPInitTimer(pAd, &pBAEntry->ORIBATimer,
500			      GET_TIMER_FUNCTION(BAOriSessionSetupTimeout),
501			      pBAEntry, FALSE);
502	} else
503		RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
504
505	/* set timer to send ADDBA request */
506	RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime);
507}
508
509void BAOriSessionAdd(struct rt_rtmp_adapter *pAd,
510		     struct rt_mac_table_entry *pEntry, struct rt_frame_addba_rsp * pFrame)
511{
512	struct rt_ba_ori_entry *pBAEntry = NULL;
513	BOOLEAN Cancelled;
514	u8 TID;
515	u16 Idx;
516	u8 *pOutBuffer2 = NULL;
517	int NStatus;
518	unsigned long FrameLen;
519	struct rt_frame_bar FrameBar;
520
521	TID = pFrame->BaParm.TID;
522	Idx = pEntry->BAOriWcidArray[TID];
523	pBAEntry = &pAd->BATable.BAOriEntry[Idx];
524
525	/* Start fill in parameters. */
526	if ((Idx != 0) && (pBAEntry->TID == TID)
527	    && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) {
528		pBAEntry->BAWinSize =
529		    min(pBAEntry->BAWinSize, ((u8)pFrame->BaParm.BufSize));
530		BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize);
531
532		pBAEntry->TimeOutValue = pFrame->TimeOutValue;
533		pBAEntry->ORI_BA_Status = Originator_Done;
534		pAd->BATable.numDoneOriginator++;
535
536		/* reset sequence number */
537		pBAEntry->Sequence = BA_ORI_INIT_SEQ;
538		/* Set Bitmap flag. */
539		pEntry->TXBAbitmap |= (1 << TID);
540		RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
541
542		pBAEntry->ORIBATimer.TimerValue = 0;	/*pFrame->TimeOutValue; */
543
544		DBGPRINT(RT_DEBUG_TRACE,
545			 ("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n",
546			  __func__, pEntry->TXBAbitmap, pBAEntry->BAWinSize,
547			  pBAEntry->ORIBATimer.TimerValue));
548
549		/* SEND BAR ; */
550		NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2);	/*Get an unused nonpaged memory */
551		if (NStatus != NDIS_STATUS_SUCCESS) {
552			DBGPRINT(RT_DEBUG_TRACE,
553				 ("BA - BAOriSessionAdd() allocate memory failed \n"));
554			return;
555		}
556
557		BarHeaderInit(pAd, &FrameBar,
558			      pAd->MacTab.Content[pBAEntry->Wcid].Addr,
559			      pAd->CurrentAddress);
560
561		FrameBar.StartingSeq.field.FragNum = 0;	/* make sure sequence not clear in DEL function. */
562		FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence;	/* make sure sequence not clear in DEL funciton. */
563		FrameBar.BarControl.TID = pBAEntry->TID;	/* make sure sequence not clear in DEL funciton. */
564		MakeOutgoingFrame(pOutBuffer2, &FrameLen,
565				  sizeof(struct rt_frame_bar), &FrameBar, END_OF_ARGS);
566		MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen);
567		MlmeFreeMemory(pAd, pOutBuffer2);
568
569		if (pBAEntry->ORIBATimer.TimerValue)
570			RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue);	/* in mSec */
571	}
572}
573
574BOOLEAN BARecSessionAdd(struct rt_rtmp_adapter *pAd,
575			struct rt_mac_table_entry *pEntry, struct rt_frame_addba_req * pFrame)
576{
577	struct rt_ba_rec_entry *pBAEntry = NULL;
578	BOOLEAN Status = TRUE;
579	BOOLEAN Cancelled;
580	u16 Idx;
581	u8 TID;
582	u8 BAWinSize;
583	/*u32                  Value; */
584	/*u32                    offset; */
585
586	ASSERT(pEntry);
587
588	/* find TID */
589	TID = pFrame->BaParm.TID;
590
591	BAWinSize =
592	    min(((u8)pFrame->BaParm.BufSize),
593		(u8)pAd->CommonCfg.BACapability.field.RxBAWinLimit);
594
595	/* Intel patch */
596	if (BAWinSize == 0) {
597		BAWinSize = 64;
598	}
599
600	Idx = pEntry->BARecWcidArray[TID];
601
602	if (Idx == 0) {
603		pBAEntry = BATableAllocRecEntry(pAd, &Idx);
604	} else {
605		pBAEntry = &pAd->BATable.BARecEntry[Idx];
606		/* flush all pending reordering mpdus */
607		ba_refresh_reordering_mpdus(pAd, pBAEntry);
608	}
609
610	DBGPRINT(RT_DEBUG_TRACE,
611		 ("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __func__,
612		  pAd->BATable.numAsRecipient, Idx, pFrame->BaParm.BufSize,
613		  BAWinSize));
614
615	/* Start fill in parameters. */
616	if (pBAEntry != NULL) {
617		ASSERT(pBAEntry->list.qlen == 0);
618
619		pBAEntry->REC_BA_Status = Recipient_HandleRes;
620		pBAEntry->BAWinSize = BAWinSize;
621		pBAEntry->Wcid = pEntry->Aid;
622		pBAEntry->TID = TID;
623		pBAEntry->TimeOutValue = pFrame->TimeOutValue;
624		pBAEntry->REC_BA_Status = Recipient_Accept;
625		/* initial sequence number */
626		pBAEntry->LastIndSeq = RESET_RCV_SEQ;	/*pFrame->BaStartSeq.field.StartSeq; */
627
628		DBGPRINT(RT_DEBUG_OFF,
629			 ("Start Seq = %08x\n",
630			  pFrame->BaStartSeq.field.StartSeq));
631
632		if (pEntry->RXBAbitmap & (1 << TID)) {
633			RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled);
634		} else {
635			RTMPInitTimer(pAd, &pBAEntry->RECBATimer,
636				      GET_TIMER_FUNCTION
637				      (BARecSessionIdleTimeout), pBAEntry,
638				      TRUE);
639		}
640
641		/* Set Bitmap flag. */
642		pEntry->RXBAbitmap |= (1 << TID);
643		pEntry->BARecWcidArray[TID] = Idx;
644
645		pEntry->BADeclineBitmap &= ~(1 << TID);
646
647		/* Set BA session mask in WCID table. */
648		RTMP_ADD_BA_SESSION_TO_ASIC(pAd, pEntry->Aid, TID);
649
650		DBGPRINT(RT_DEBUG_TRACE,
651			 ("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n",
652			  pEntry->Aid, pEntry->RXBAbitmap,
653			  pEntry->BARecWcidArray[TID]));
654	} else {
655		Status = FALSE;
656		DBGPRINT(RT_DEBUG_TRACE,
657			 ("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n",
658			  PRINT_MAC(pEntry->Addr), TID));
659	}
660	return (Status);
661}
662
663struct rt_ba_rec_entry *BATableAllocRecEntry(struct rt_rtmp_adapter *pAd, u16 * Idx)
664{
665	int i;
666	struct rt_ba_rec_entry *pBAEntry = NULL;
667
668	NdisAcquireSpinLock(&pAd->BATabLock);
669
670	if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) {
671		DBGPRINT(RT_DEBUG_OFF, ("BA Recipeint Session (%ld) > %d\n",
672					pAd->BATable.numAsRecipient,
673					MAX_BARECI_SESSION));
674		goto done;
675	}
676	/* reserve idx 0 to identify BAWcidArray[TID] as empty */
677	for (i = 1; i < MAX_LEN_OF_BA_REC_TABLE; i++) {
678		pBAEntry = &pAd->BATable.BARecEntry[i];
679		if ((pBAEntry->REC_BA_Status == Recipient_NONE)) {
680			/* get one */
681			pAd->BATable.numAsRecipient++;
682			pBAEntry->REC_BA_Status = Recipient_USED;
683			*Idx = i;
684			break;
685		}
686	}
687
688done:
689	NdisReleaseSpinLock(&pAd->BATabLock);
690	return pBAEntry;
691}
692
693struct rt_ba_ori_entry *BATableAllocOriEntry(struct rt_rtmp_adapter *pAd, u16 * Idx)
694{
695	int i;
696	struct rt_ba_ori_entry *pBAEntry = NULL;
697
698	NdisAcquireSpinLock(&pAd->BATabLock);
699
700	if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) {
701		goto done;
702	}
703	/* reserve idx 0 to identify BAWcidArray[TID] as empty */
704	for (i = 1; i < MAX_LEN_OF_BA_ORI_TABLE; i++) {
705		pBAEntry = &pAd->BATable.BAOriEntry[i];
706		if ((pBAEntry->ORI_BA_Status == Originator_NONE)) {
707			/* get one */
708			pAd->BATable.numAsOriginator++;
709			pBAEntry->ORI_BA_Status = Originator_USED;
710			pBAEntry->pAdapter = pAd;
711			*Idx = i;
712			break;
713		}
714	}
715
716done:
717	NdisReleaseSpinLock(&pAd->BATabLock);
718	return pBAEntry;
719}
720
721void BATableFreeOriEntry(struct rt_rtmp_adapter *pAd, unsigned long Idx)
722{
723	struct rt_ba_ori_entry *pBAEntry = NULL;
724	struct rt_mac_table_entry *pEntry;
725
726	if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE))
727		return;
728
729	pBAEntry = &pAd->BATable.BAOriEntry[Idx];
730
731	if (pBAEntry->ORI_BA_Status != Originator_NONE) {
732		pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
733		pEntry->BAOriWcidArray[pBAEntry->TID] = 0;
734
735		NdisAcquireSpinLock(&pAd->BATabLock);
736		if (pBAEntry->ORI_BA_Status == Originator_Done) {
737			pAd->BATable.numDoneOriginator -= 1;
738			pEntry->TXBAbitmap &= (~(1 << (pBAEntry->TID)));
739			DBGPRINT(RT_DEBUG_TRACE,
740				 ("BATableFreeOriEntry numAsOriginator= %ld\n",
741				  pAd->BATable.numAsRecipient));
742			/* Erase Bitmap flag. */
743		}
744
745		ASSERT(pAd->BATable.numAsOriginator != 0);
746
747		pAd->BATable.numAsOriginator -= 1;
748
749		pBAEntry->ORI_BA_Status = Originator_NONE;
750		pBAEntry->Token = 0;
751		NdisReleaseSpinLock(&pAd->BATabLock);
752	}
753}
754
755void BATableFreeRecEntry(struct rt_rtmp_adapter *pAd, unsigned long Idx)
756{
757	struct rt_ba_rec_entry *pBAEntry = NULL;
758	struct rt_mac_table_entry *pEntry;
759
760	if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE))
761		return;
762
763	pBAEntry = &pAd->BATable.BARecEntry[Idx];
764
765	if (pBAEntry->REC_BA_Status != Recipient_NONE) {
766		pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
767		pEntry->BARecWcidArray[pBAEntry->TID] = 0;
768
769		NdisAcquireSpinLock(&pAd->BATabLock);
770
771		ASSERT(pAd->BATable.numAsRecipient != 0);
772
773		pAd->BATable.numAsRecipient -= 1;
774
775		pBAEntry->REC_BA_Status = Recipient_NONE;
776		NdisReleaseSpinLock(&pAd->BATabLock);
777	}
778}
779
780void BAOriSessionTearDown(struct rt_rtmp_adapter *pAd,
781			  u8 Wcid,
782			  u8 TID,
783			  IN BOOLEAN bPassive, IN BOOLEAN bForceSend)
784{
785	unsigned long Idx = 0;
786	struct rt_ba_ori_entry *pBAEntry;
787	BOOLEAN Cancelled;
788
789	if (Wcid >= MAX_LEN_OF_MAC_TABLE) {
790		return;
791	}
792	/* */
793	/* Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). */
794	/* */
795	Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID];
796	if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) {
797		if (bForceSend == TRUE) {
798			/* force send specified TID DelBA */
799			struct rt_mlme_delba_req DelbaReq;
800			struct rt_mlme_queue_elem *Elem =
801			    (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
802							MEM_ALLOC_FLAG);
803			if (Elem != NULL) {
804				NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
805				NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
806
807				COPY_MAC_ADDR(DelbaReq.Addr,
808					      pAd->MacTab.Content[Wcid].Addr);
809				DelbaReq.Wcid = Wcid;
810				DelbaReq.TID = TID;
811				DelbaReq.Initiator = ORIGINATOR;
812				Elem->MsgLen = sizeof(DelbaReq);
813				NdisMoveMemory(Elem->Msg, &DelbaReq,
814					       sizeof(DelbaReq));
815				MlmeDELBAAction(pAd, Elem);
816				kfree(Elem);
817			} else {
818				DBGPRINT(RT_DEBUG_ERROR,
819					 ("%s(bForceSend):alloc memory failed!\n",
820					  __func__));
821			}
822		}
823
824		return;
825	}
826
827	DBGPRINT(RT_DEBUG_TRACE,
828		 ("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
829
830	pBAEntry = &pAd->BATable.BAOriEntry[Idx];
831	DBGPRINT(RT_DEBUG_TRACE,
832		 ("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx,
833		  Wcid, TID, pBAEntry->ORI_BA_Status));
834	/* */
835	/* Prepare DelBA action frame and send to the peer. */
836	/* */
837	if ((bPassive == FALSE) && (TID == pBAEntry->TID)
838	    && (pBAEntry->ORI_BA_Status == Originator_Done)) {
839		struct rt_mlme_delba_req DelbaReq;
840		struct rt_mlme_queue_elem *Elem =
841		    (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
842						MEM_ALLOC_FLAG);
843		if (Elem != NULL) {
844			NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
845			NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
846
847			COPY_MAC_ADDR(DelbaReq.Addr,
848				      pAd->MacTab.Content[Wcid].Addr);
849			DelbaReq.Wcid = Wcid;
850			DelbaReq.TID = pBAEntry->TID;
851			DelbaReq.Initiator = ORIGINATOR;
852			Elem->MsgLen = sizeof(DelbaReq);
853			NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq));
854			MlmeDELBAAction(pAd, Elem);
855			kfree(Elem);
856		} else {
857			DBGPRINT(RT_DEBUG_ERROR,
858				 ("%s():alloc memory failed!\n", __func__));
859			return;
860		}
861	}
862	RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled);
863	BATableFreeOriEntry(pAd, Idx);
864
865	if (bPassive) {
866		/*BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); */
867	}
868}
869
870void BARecSessionTearDown(struct rt_rtmp_adapter *pAd,
871			  u8 Wcid, u8 TID, IN BOOLEAN bPassive)
872{
873	unsigned long Idx = 0;
874	struct rt_ba_rec_entry *pBAEntry;
875
876	if (Wcid >= MAX_LEN_OF_MAC_TABLE) {
877		return;
878	}
879	/* */
880	/*  Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). */
881	/* */
882	Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
883	if (Idx == 0)
884		return;
885
886	DBGPRINT(RT_DEBUG_TRACE,
887		 ("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
888
889	pBAEntry = &pAd->BATable.BARecEntry[Idx];
890	DBGPRINT(RT_DEBUG_TRACE,
891		 ("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx,
892		  Wcid, TID, pBAEntry->REC_BA_Status));
893	/* */
894	/* Prepare DelBA action frame and send to the peer. */
895	/* */
896	if ((TID == pBAEntry->TID)
897	    && (pBAEntry->REC_BA_Status == Recipient_Accept)) {
898		struct rt_mlme_delba_req DelbaReq;
899		BOOLEAN Cancelled;
900		/*unsigned long   offset; */
901		/*u32  VALUE; */
902
903		RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled);
904
905		/* */
906		/* 1. Send DELBA Action Frame */
907		/* */
908		if (bPassive == FALSE) {
909			struct rt_mlme_queue_elem *Elem =
910			    (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
911							MEM_ALLOC_FLAG);
912			if (Elem != NULL) {
913				NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
914				NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
915
916				COPY_MAC_ADDR(DelbaReq.Addr,
917					      pAd->MacTab.Content[Wcid].Addr);
918				DelbaReq.Wcid = Wcid;
919				DelbaReq.TID = TID;
920				DelbaReq.Initiator = RECIPIENT;
921				Elem->MsgLen = sizeof(DelbaReq);
922				NdisMoveMemory(Elem->Msg, &DelbaReq,
923					       sizeof(DelbaReq));
924				MlmeDELBAAction(pAd, Elem);
925				kfree(Elem);
926			} else {
927				DBGPRINT(RT_DEBUG_ERROR,
928					 ("%s():alloc memory failed!\n",
929					  __func__));
930				return;
931			}
932		}
933
934		/* */
935		/* 2. Free resource of BA session */
936		/* */
937		/* flush all pending reordering mpdus */
938		ba_refresh_reordering_mpdus(pAd, pBAEntry);
939
940		NdisAcquireSpinLock(&pAd->BATabLock);
941
942		/* Erase Bitmap flag. */
943		pBAEntry->LastIndSeq = RESET_RCV_SEQ;
944		pBAEntry->BAWinSize = 0;
945		/* Erase Bitmap flag at software mactable */
946		pAd->MacTab.Content[Wcid].RXBAbitmap &=
947		    (~(1 << (pBAEntry->TID)));
948		pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0;
949
950		RTMP_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID);
951
952		NdisReleaseSpinLock(&pAd->BATabLock);
953
954	}
955
956	BATableFreeRecEntry(pAd, Idx);
957}
958
959void BASessionTearDownALL(struct rt_rtmp_adapter *pAd, u8 Wcid)
960{
961	int i;
962
963	for (i = 0; i < NUM_OF_TID; i++) {
964		BAOriSessionTearDown(pAd, Wcid, i, FALSE, FALSE);
965		BARecSessionTearDown(pAd, Wcid, i, FALSE);
966	}
967}
968
969/*
970	==========================================================================
971	Description:
972		Retry sending ADDBA Reqest.
973
974	IRQL = DISPATCH_LEVEL
975
976	Parametrs:
977	p8023Header: if this is already 802.3 format, p8023Header is NULL
978
979	Return	: TRUE if put into rx reordering buffer, shouldn't indicaterxhere.
980				FALSE , then continue indicaterx at this moment.
981	==========================================================================
982 */
983void BAOriSessionSetupTimeout(void *SystemSpecific1,
984			      void *FunctionContext,
985			      void *SystemSpecific2,
986			      void *SystemSpecific3)
987{
988	struct rt_ba_ori_entry *pBAEntry = (struct rt_ba_ori_entry *)FunctionContext;
989	struct rt_mac_table_entry *pEntry;
990	struct rt_rtmp_adapter *pAd;
991
992	if (pBAEntry == NULL)
993		return;
994
995	pAd = pBAEntry->pAdapter;
996
997	{
998		/* Do nothing if monitor mode is on */
999		if (MONITOR_ON(pAd))
1000			return;
1001	}
1002
1003	pEntry = &pAd->MacTab.Content[pBAEntry->Wcid];
1004
1005	if ((pBAEntry->ORI_BA_Status == Originator_WaitRes)
1006	    && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) {
1007		struct rt_mlme_addba_req AddbaReq;
1008
1009		NdisZeroMemory(&AddbaReq, sizeof(AddbaReq));
1010		COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr);
1011		AddbaReq.Wcid = (u8)(pEntry->Aid);
1012		AddbaReq.TID = pBAEntry->TID;
1013		AddbaReq.BaBufSize =
1014		    pAd->CommonCfg.BACapability.field.RxBAWinLimit;
1015		AddbaReq.TimeOutValue = 0;
1016		AddbaReq.Token = pBAEntry->Token;
1017		MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE,
1018			    sizeof(struct rt_mlme_addba_req), (void *)& AddbaReq);
1019		RTMP_MLME_HANDLER(pAd);
1020		DBGPRINT(RT_DEBUG_TRACE,
1021			 ("BA Ori Session Timeout(%d) : Send ADD BA again\n",
1022			  pBAEntry->Token));
1023
1024		pBAEntry->Token++;
1025		RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT);
1026	} else {
1027		BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]);
1028	}
1029}
1030
1031/*
1032	==========================================================================
1033	Description:
1034		Retry sending ADDBA Reqest.
1035
1036	IRQL = DISPATCH_LEVEL
1037
1038	Parametrs:
1039	p8023Header: if this is already 802.3 format, p8023Header is NULL
1040
1041	Return	: TRUE if put into rx reordering buffer, shouldn't indicaterxhere.
1042				FALSE , then continue indicaterx at this moment.
1043	==========================================================================
1044 */
1045void BARecSessionIdleTimeout(void *SystemSpecific1,
1046			     void *FunctionContext,
1047			     void *SystemSpecific2, void *SystemSpecific3)
1048{
1049
1050	struct rt_ba_rec_entry *pBAEntry = (struct rt_ba_rec_entry *)FunctionContext;
1051	struct rt_rtmp_adapter *pAd;
1052	unsigned long Now32;
1053
1054	if (pBAEntry == NULL)
1055		return;
1056
1057	if ((pBAEntry->REC_BA_Status == Recipient_Accept)) {
1058		NdisGetSystemUpTime(&Now32);
1059
1060		if (RTMP_TIME_AFTER
1061		    ((unsigned long)Now32,
1062		     (unsigned long)(pBAEntry->LastIndSeqAtTimer +
1063				     REC_BA_SESSION_IDLE_TIMEOUT))) {
1064			pAd = pBAEntry->pAdapter;
1065			/* flush all pending reordering mpdus */
1066			ba_refresh_reordering_mpdus(pAd, pBAEntry);
1067			DBGPRINT(RT_DEBUG_OFF,
1068				 ("%ld: REC BA session Timeout\n", Now32));
1069		}
1070	}
1071}
1072
1073void PeerAddBAReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
1074{
1075	/*      7.4.4.1 */
1076	/*unsigned long Idx; */
1077	u8 Status = 1;
1078	u8 pAddr[6];
1079	struct rt_frame_addba_rsp ADDframe;
1080	u8 *pOutBuffer = NULL;
1081	int NStatus;
1082	struct rt_frame_addba_req * pAddreqFrame = NULL;
1083	/*u8         BufSize; */
1084	unsigned long FrameLen;
1085	unsigned long *ptemp;
1086	struct rt_mac_table_entry *pMacEntry;
1087
1088	DBGPRINT(RT_DEBUG_TRACE,
1089		 ("%s ==> (Wcid = %d)\n", __func__, Elem->Wcid));
1090
1091	/*hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); */
1092
1093	/*ADDBA Request from unknown peer, ignore this. */
1094	if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
1095		return;
1096
1097	pMacEntry = &pAd->MacTab.Content[Elem->Wcid];
1098	DBGPRINT(RT_DEBUG_TRACE, ("BA - PeerAddBAReqAction----> \n"));
1099	ptemp = (unsigned long *)Elem->Msg;
1100	/*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))); */
1101
1102	if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) {
1103
1104		if ((pAd->CommonCfg.bBADecline == FALSE)
1105		    && IS_HT_STA(pMacEntry)) {
1106			pAddreqFrame = (struct rt_frame_addba_req *) (&Elem->Msg[0]);
1107			DBGPRINT(RT_DEBUG_OFF,
1108				 ("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid));
1109			if (BARecSessionAdd
1110			    (pAd, &pAd->MacTab.Content[Elem->Wcid],
1111			     pAddreqFrame))
1112				Status = 0;
1113			else
1114				Status = 38;	/* more parameters have invalid values */
1115		} else {
1116			Status = 37;	/* the request has been declined. */
1117		}
1118	}
1119
1120	if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI)
1121		ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC);
1122
1123	pAddreqFrame = (struct rt_frame_addba_req *) (&Elem->Msg[0]);
1124	/* 2. Always send back ADDBA Response */
1125	NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);	/*Get an unused nonpaged memory */
1126	if (NStatus != NDIS_STATUS_SUCCESS) {
1127		DBGPRINT(RT_DEBUG_TRACE,
1128			 ("ACTION - PeerBAAction() allocate memory failed \n"));
1129		return;
1130	}
1131
1132	NdisZeroMemory(&ADDframe, sizeof(struct rt_frame_addba_rsp));
1133
1134	/* 2-1. Prepare ADDBA Response frame. */
1135	{
1136		if (ADHOC_ON(pAd))
1137			ActHeaderInit(pAd, &ADDframe.Hdr, pAddr,
1138				      pAd->CurrentAddress,
1139				      pAd->CommonCfg.Bssid);
1140		else
1141			ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid,
1142				      pAd->CurrentAddress, pAddr);
1143	}
1144
1145	ADDframe.Category = CATEGORY_BA;
1146	ADDframe.Action = ADDBA_RESP;
1147	ADDframe.Token = pAddreqFrame->Token;
1148	/* What is the Status code??  need to check. */
1149	ADDframe.StatusCode = Status;
1150	ADDframe.BaParm.BAPolicy = IMMED_BA;
1151	ADDframe.BaParm.AMSDUSupported = 0;
1152	ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID;
1153	ADDframe.BaParm.BufSize =
1154	    min(((u8)pAddreqFrame->BaParm.BufSize),
1155		(u8)pAd->CommonCfg.BACapability.field.RxBAWinLimit);
1156	if (ADDframe.BaParm.BufSize == 0) {
1157		ADDframe.BaParm.BufSize = 64;
1158	}
1159	ADDframe.TimeOutValue = 0;	/*pAddreqFrame->TimeOutValue; */
1160
1161	*(u16 *) (&ADDframe.BaParm) =
1162	    cpu2le16(*(u16 *) (&ADDframe.BaParm));
1163	ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode);
1164	ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue);
1165
1166	MakeOutgoingFrame(pOutBuffer, &FrameLen,
1167			  sizeof(struct rt_frame_addba_rsp), &ADDframe, END_OF_ARGS);
1168	MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
1169	MlmeFreeMemory(pAd, pOutBuffer);
1170
1171	DBGPRINT(RT_DEBUG_TRACE,
1172		 ("%s(%d): TID(%d), BufSize(%d) <== \n", __func__, Elem->Wcid,
1173		  ADDframe.BaParm.TID, ADDframe.BaParm.BufSize));
1174}
1175
1176void PeerAddBARspAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
1177{
1178	/*u8         Idx, i; */
1179	/*u8 *                  pOutBuffer = NULL; */
1180	struct rt_frame_addba_rsp * pFrame = NULL;
1181	/*struct rt_ba_ori_entry *pBAEntry; */
1182
1183	/*ADDBA Response from unknown peer, ignore this. */
1184	if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
1185		return;
1186
1187	DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __func__, Elem->Wcid));
1188
1189	/*hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); */
1190
1191	if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) {
1192		pFrame = (struct rt_frame_addba_rsp *) (&Elem->Msg[0]);
1193
1194		DBGPRINT(RT_DEBUG_TRACE,
1195			 ("\t\t StatusCode = %d\n", pFrame->StatusCode));
1196		switch (pFrame->StatusCode) {
1197		case 0:
1198			/* I want a BAsession with this peer as an originator. */
1199			BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid],
1200					pFrame);
1201			break;
1202		default:
1203			/* check status == USED ??? */
1204			BAOriSessionTearDown(pAd, Elem->Wcid,
1205					     pFrame->BaParm.TID, TRUE, FALSE);
1206			break;
1207		}
1208		/* Rcv Decline StatusCode */
1209		if ((pFrame->StatusCode == 37)
1210		    || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd)
1211			&& (pFrame->StatusCode != 0))
1212		    ) {
1213			pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |=
1214			    1 << pFrame->BaParm.TID;
1215		}
1216	}
1217}
1218
1219void PeerDelBAAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
1220{
1221	/*u8                         Idx; */
1222	/*u8 *                               pOutBuffer = NULL; */
1223	struct rt_frame_delba_req * pDelFrame = NULL;
1224
1225	DBGPRINT(RT_DEBUG_TRACE, ("%s ==>\n", __func__));
1226	/*DELBA Request from unknown peer, ignore this. */
1227	if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) {
1228		pDelFrame = (struct rt_frame_delba_req *) (&Elem->Msg[0]);
1229		if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) {
1230			DBGPRINT(RT_DEBUG_TRACE,
1231				 ("BA - PeerDelBAAction----> ORIGINATOR\n"));
1232			BARecSessionTearDown(pAd, Elem->Wcid,
1233					     pDelFrame->DelbaParm.TID, TRUE);
1234		} else {
1235			DBGPRINT(RT_DEBUG_TRACE,
1236				 ("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n",
1237				  pDelFrame->ReasonCode));
1238			/*hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); */
1239			BAOriSessionTearDown(pAd, Elem->Wcid,
1240					     pDelFrame->DelbaParm.TID, TRUE,
1241					     FALSE);
1242		}
1243	}
1244}
1245
1246BOOLEAN CntlEnqueueForRecv(struct rt_rtmp_adapter *pAd,
1247			   unsigned long Wcid,
1248			   unsigned long MsgLen, struct rt_frame_ba_req * pMsg)
1249{
1250	struct rt_frame_ba_req * pFrame = pMsg;
1251	/*PRTMP_REORDERBUF      pBuffer; */
1252	/*PRTMP_REORDERBUF      pDmaBuf; */
1253	struct rt_ba_rec_entry *pBAEntry;
1254	/*BOOLEAN       Result; */
1255	unsigned long Idx;
1256	/*u8 NumRxPkt; */
1257	u8 TID;		/*, i; */
1258
1259	TID = (u8)pFrame->BARControl.TID;
1260
1261	DBGPRINT(RT_DEBUG_TRACE,
1262		 ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __func__, Wcid, TID));
1263	/*hex_dump("BAR", (char *)pFrame, MsgLen); */
1264	/* Do nothing if the driver is starting halt state. */
1265	/* This might happen when timer already been fired before cancel timer with mlmehalt */
1266	if (RTMP_TEST_FLAG
1267	    (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
1268		return FALSE;
1269
1270	/* First check the size, it MUST not exceed the mlme queue size */
1271	if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
1272		DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
1273		return FALSE;
1274	} else if (MsgLen != sizeof(struct rt_frame_ba_req)) {
1275		DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
1276		return FALSE;
1277	} else if (MsgLen != sizeof(struct rt_frame_ba_req)) {
1278		DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
1279		return FALSE;
1280	}
1281
1282	if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) {
1283		/* if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. */
1284		Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
1285		pBAEntry = &pAd->BATable.BARecEntry[Idx];
1286	} else {
1287		return FALSE;
1288	}
1289
1290	DBGPRINT(RT_DEBUG_TRACE,
1291		 ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID,
1292		  pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq));
1293
1294	if (SEQ_SMALLER
1295	    (pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq,
1296	     MAXSEQ)) {
1297		/*DBGPRINT(RT_DEBUG_TRACE, ("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq)); */
1298		ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry,
1299						    pFrame->BAStartingSeq.field.
1300						    StartSeq);
1301		pBAEntry->LastIndSeq =
1302		    (pFrame->BAStartingSeq.field.StartSeq ==
1303		     0) ? MAXSEQ : (pFrame->BAStartingSeq.field.StartSeq - 1);
1304	}
1305	/*ba_refresh_reordering_mpdus(pAd, pBAEntry); */
1306	return TRUE;
1307}
1308
1309/*
1310Description : Send PSMP Action frame If PSMP mode switches.
1311*/
1312void SendPSMPAction(struct rt_rtmp_adapter *pAd, u8 Wcid, u8 Psmp)
1313{
1314	u8 *pOutBuffer = NULL;
1315	int NStatus;
1316	/*unsigned long           Idx; */
1317	struct rt_frame_psmp_action Frame;
1318	unsigned long FrameLen;
1319
1320	NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);	/*Get an unused nonpaged memory */
1321	if (NStatus != NDIS_STATUS_SUCCESS) {
1322		DBGPRINT(RT_DEBUG_ERROR,
1323			 ("BA - MlmeADDBAAction() allocate memory failed \n"));
1324		return;
1325	}
1326
1327	ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid,
1328		      pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr);
1329
1330	Frame.Category = CATEGORY_HT;
1331	Frame.Action = SMPS_ACTION;
1332	switch (Psmp) {
1333	case MMPS_ENABLE:
1334#ifdef RT30xx
1335		if (IS_RT30xx(pAd)
1336		    && (pAd->Antenna.field.RxPath > 1
1337			|| pAd->Antenna.field.TxPath > 1)) {
1338			RTMP_ASIC_MMPS_DISABLE(pAd);
1339		}
1340#endif /* RT30xx // */
1341		Frame.Psmp = 0;
1342		break;
1343	case MMPS_DYNAMIC:
1344		Frame.Psmp = 3;
1345		break;
1346	case MMPS_STATIC:
1347#ifdef RT30xx
1348		if (IS_RT30xx(pAd)
1349		    && (pAd->Antenna.field.RxPath > 1
1350			|| pAd->Antenna.field.TxPath > 1)) {
1351			RTMP_ASIC_MMPS_ENABLE(pAd);
1352		}
1353#endif /* RT30xx // */
1354		Frame.Psmp = 1;
1355		break;
1356	}
1357	MakeOutgoingFrame(pOutBuffer, &FrameLen,
1358			  sizeof(struct rt_frame_psmp_action), &Frame, END_OF_ARGS);
1359	MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
1360	MlmeFreeMemory(pAd, pOutBuffer);
1361	DBGPRINT(RT_DEBUG_ERROR, ("HT - SendPSMPAction( %d )  \n", Frame.Psmp));
1362}
1363
1364#define RADIO_MEASUREMENT_REQUEST_ACTION	0
1365
1366struct PACKED rt_beacon_request {
1367	u8 RegulatoryClass;
1368	u8 ChannelNumber;
1369	u16 RandomInterval;
1370	u16 MeasurementDuration;
1371	u8 MeasurementMode;
1372	u8 BSSID[MAC_ADDR_LEN];
1373	u8 ReportingCondition;
1374	u8 Threshold;
1375	u8 SSIDIE[2];	/* 2 byte */
1376};
1377
1378struct PACKED rt_measurement_req {
1379	u8 ID;
1380	u8 Length;
1381	u8 Token;
1382	u8 RequestMode;
1383	u8 Type;
1384};
1385
1386void convert_reordering_packet_to_preAMSDU_or_802_3_packet(struct rt_rtmp_adapter *pAd,
1387							   struct rt_rx_blk *pRxBlk,
1388							   u8
1389							   FromWhichBSSID)
1390{
1391	void *pRxPkt;
1392	u8 Header802_3[LENGTH_802_3];
1393
1394	/* 1. get 802.3 Header */
1395	/* 2. remove LLC */
1396	/*              a. pointer pRxBlk->pData to payload */
1397	/*      b. modify pRxBlk->DataSize */
1398
1399	RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3);
1400
1401	ASSERT(pRxBlk->pRxPacket);
1402	pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket);
1403
1404	SET_OS_PKT_NETDEV(pRxPkt, get_netdev_from_bssid(pAd, FromWhichBSSID));
1405	SET_OS_PKT_DATAPTR(pRxPkt, pRxBlk->pData);
1406	SET_OS_PKT_LEN(pRxPkt, pRxBlk->DataSize);
1407	SET_OS_PKT_DATATAIL(pRxPkt, pRxBlk->pData, pRxBlk->DataSize);
1408
1409	/* */
1410	/* copy 802.3 header, if necessary */
1411	/* */
1412	if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) {
1413		{
1414			NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3),
1415				       Header802_3, LENGTH_802_3);
1416		}
1417	}
1418}
1419
1420#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID)		\
1421	do																	\
1422	{																	\
1423    	if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU))						\
1424    	{																\
1425    		Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID);		\
1426    	}																\
1427		else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP))					\
1428		{																\
1429			Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID);		\
1430		}																\
1431    	else															\
1432    	{																\
1433    		Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID);		\
1434    	}																\
1435	} while (0);
1436
1437static void ba_enqueue_reordering_packet(struct rt_rtmp_adapter *pAd,
1438					 struct rt_ba_rec_entry *pBAEntry,
1439					 struct rt_rx_blk *pRxBlk,
1440					 u8 FromWhichBSSID)
1441{
1442	struct reordering_mpdu *mpdu_blk;
1443	u16 Sequence = (u16)pRxBlk->pHeader->Sequence;
1444
1445	mpdu_blk = ba_mpdu_blk_alloc(pAd);
1446	if ((mpdu_blk != NULL) && (!RX_BLK_TEST_FLAG(pRxBlk, fRX_EAP))) {
1447		/* Write RxD buffer address & allocated buffer length */
1448		NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
1449
1450		mpdu_blk->Sequence = Sequence;
1451
1452		mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU);
1453
1454		convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd,
1455								      pRxBlk,
1456								      FromWhichBSSID);
1457
1458		STATS_INC_RX_PACKETS(pAd, FromWhichBSSID);
1459
1460		/* */
1461		/* it is necessary for reordering packet to record */
1462		/* which BSS it come from */
1463		/* */
1464		RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID);
1465
1466		mpdu_blk->pPacket = pRxBlk->pRxPacket;
1467
1468		if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk)
1469		    == FALSE) {
1470			/* had been already within reordering list */
1471			/* don't indicate */
1472			RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
1473					    NDIS_STATUS_SUCCESS);
1474			ba_mpdu_blk_free(pAd, mpdu_blk);
1475		}
1476
1477		ASSERT((0 <= pBAEntry->list.qlen)
1478		       && (pBAEntry->list.qlen <= pBAEntry->BAWinSize));
1479		NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
1480	} else {
1481		DBGPRINT(RT_DEBUG_ERROR,
1482			 (" (%d) Can't allocate reordering mpdu blk\n",
1483			  pBAEntry->list.qlen));
1484
1485		/*
1486		 * flush all pending reordering mpdus
1487		 * and receving mpdu to upper layer
1488		 * make tcp/ip to take care reordering mechanism
1489		 */
1490		/*ba_refresh_reordering_mpdus(pAd, pBAEntry); */
1491		ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence);
1492
1493		pBAEntry->LastIndSeq = Sequence;
1494		INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
1495	}
1496}
1497
1498/*
1499	==========================================================================
1500	Description:
1501		Indicate this packet to upper layer or put it into reordering buffer
1502
1503	Parametrs:
1504		pRxBlk         : carry necessary packet info 802.11 format
1505		FromWhichBSSID : the packet received from which BSS
1506
1507	Return	:
1508			  none
1509
1510	Note    :
1511	          the packet queued into reordering buffer need to cover to 802.3 format
1512			  or pre_AMSDU format
1513	==========================================================================
1514 */
1515
1516void Indicate_AMPDU_Packet(struct rt_rtmp_adapter *pAd,
1517			   struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
1518{
1519	u16 Idx;
1520	struct rt_ba_rec_entry *pBAEntry = NULL;
1521	u16 Sequence = pRxBlk->pHeader->Sequence;
1522	unsigned long Now32;
1523	u8 Wcid = pRxBlk->pRxWI->WirelessCliID;
1524	u8 TID = pRxBlk->pRxWI->TID;
1525
1526	if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)
1527	    && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) {
1528		/* release packet */
1529		RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
1530				    NDIS_STATUS_FAILURE);
1531		return;
1532	}
1533
1534	if (Wcid < MAX_LEN_OF_MAC_TABLE) {
1535		Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID];
1536		if (Idx == 0) {
1537			/* Rec BA Session had been torn down */
1538			INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
1539			return;
1540		}
1541		pBAEntry = &pAd->BATable.BARecEntry[Idx];
1542	} else {
1543		/* impossible ! */
1544		ASSERT(0);
1545		/* release packet */
1546		RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
1547				    NDIS_STATUS_FAILURE);
1548		return;
1549	}
1550
1551	ASSERT(pBAEntry);
1552
1553	/* update last rx time */
1554	NdisGetSystemUpTime(&Now32);
1555
1556	pBAEntry->rcvSeq = Sequence;
1557
1558	ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32);
1559	pBAEntry->LastIndSeqAtTimer = Now32;
1560
1561	/* */
1562	/* Reset Last Indicate Sequence */
1563	/* */
1564	if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) {
1565		ASSERT((pBAEntry->list.qlen == 0)
1566		       && (pBAEntry->list.next == NULL));
1567
1568		/* reset rcv sequence of BA session */
1569		pBAEntry->LastIndSeq = Sequence;
1570		pBAEntry->LastIndSeqAtTimer = Now32;
1571		INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
1572		return;
1573	}
1574
1575	/* */
1576	/* I. Check if in order. */
1577	/* */
1578	if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) {
1579		u16 LastIndSeq;
1580
1581		pBAEntry->LastIndSeq = Sequence;
1582		INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID);
1583		LastIndSeq =
1584		    ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry,
1585							  pBAEntry->LastIndSeq);
1586		if (LastIndSeq != RESET_RCV_SEQ) {
1587			pBAEntry->LastIndSeq = LastIndSeq;
1588		}
1589		pBAEntry->LastIndSeqAtTimer = Now32;
1590	}
1591	/* */
1592	/* II. Drop Duplicated Packet */
1593	/* */
1594	else if (Sequence == pBAEntry->LastIndSeq) {
1595
1596		/* drop and release packet */
1597		pBAEntry->nDropPacket++;
1598		RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
1599				    NDIS_STATUS_FAILURE);
1600	}
1601	/* */
1602	/* III. Drop Old Received Packet */
1603	/* */
1604	else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) {
1605
1606		/* drop and release packet */
1607		pBAEntry->nDropPacket++;
1608		RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket,
1609				    NDIS_STATUS_FAILURE);
1610	}
1611	/* */
1612	/* IV. Receive Sequence within Window Size */
1613	/* */
1614	else if (SEQ_SMALLER
1615		 (Sequence,
1616		  (((pBAEntry->LastIndSeq + pBAEntry->BAWinSize + 1)) & MAXSEQ),
1617		  MAXSEQ)) {
1618		ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk,
1619					     FromWhichBSSID);
1620	}
1621	/* */
1622	/* V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer */
1623	/* */
1624	else {
1625		long WinStartSeq, TmpSeq;
1626
1627		TmpSeq = Sequence - (pBAEntry->BAWinSize) - 1;
1628		if (TmpSeq < 0) {
1629			TmpSeq = (MAXSEQ + 1) + TmpSeq;
1630		}
1631		WinStartSeq = (TmpSeq + 1) & MAXSEQ;
1632		ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq);
1633		pBAEntry->LastIndSeq = WinStartSeq;	/*TmpSeq; */
1634
1635		pBAEntry->LastIndSeqAtTimer = Now32;
1636
1637		ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk,
1638					     FromWhichBSSID);
1639
1640		TmpSeq =
1641		    ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry,
1642							  pBAEntry->LastIndSeq);
1643		if (TmpSeq != RESET_RCV_SEQ) {
1644			pBAEntry->LastIndSeq = TmpSeq;
1645		}
1646	}
1647}
1648