• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/rtl8192u/ieee80211/
1#include "ieee80211.h"
2#include <linux/etherdevice.h>
3#include <linux/slab.h>
4#include "rtl819x_TS.h"
5
6void TsSetupTimeOut(unsigned long data)
7{
8	// Not implement yet
9	// This is used for WMMSA and ACM , that would send ADDTSReq frame.
10}
11
12void TsInactTimeout(unsigned long data)
13{
14	// Not implement yet
15	// This is used for WMMSA and ACM.
16	// This function would be call when TS is no Tx/Rx for some period of time.
17}
18
19/********************************************************************************************************************
20 *function:  I still not understand this function, so wait for further implementation
21 *   input:  unsigned long	 data		//acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
22 *  return:  NULL
23 *  notice:
24********************************************************************************************************************/
25void RxPktPendingTimeout(unsigned long data)
26{
27	PRX_TS_RECORD	pRxTs = (PRX_TS_RECORD)data;
28	struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
29
30	PRX_REORDER_ENTRY 	pReorderEntry = NULL;
31
32	//u32 flags = 0;
33	unsigned long flags = 0;
34	struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
35	u8 index = 0;
36	bool bPktInBuf = false;
37
38
39	spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
40	//PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
41	IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__);
42	if(pRxTs->RxTimeoutIndicateSeq != 0xffff)
43	{
44		// Indicate the pending packets sequentially according to SeqNum until meet the gap.
45		while(!list_empty(&pRxTs->RxPendingPktList))
46		{
47			pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
48			if(index == 0)
49				pRxTs->RxIndicateSeq = pReorderEntry->SeqNum;
50
51			if( SN_LESS(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) ||
52				SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq)	)
53			{
54				list_del_init(&pReorderEntry->List);
55
56				if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq))
57					pRxTs->RxIndicateSeq = (pRxTs->RxIndicateSeq + 1) % 4096;
58
59				IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
60				stats_IndicateArray[index] = pReorderEntry->prxb;
61				index++;
62
63				list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
64			}
65			else
66			{
67				bPktInBuf = true;
68				break;
69			}
70		}
71	}
72
73	if(index>0)
74	{
75		// Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
76		pRxTs->RxTimeoutIndicateSeq = 0xffff;
77
78		// Indicate packets
79		if(index > REORDER_WIN_SIZE){
80			IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n");
81			spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
82			return;
83		}
84		ieee80211_indicate_packets(ieee, stats_IndicateArray, index);
85	}
86
87	if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff))
88	{
89		pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq;
90		mod_timer(&pRxTs->RxPktPendingTimer,  jiffies + MSECS(ieee->pHTInfo->RxReorderPendingTime));
91	}
92	spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
93	//PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
94}
95
96/********************************************************************************************************************
97 *function:  Add BA timer function
98 *   input:  unsigned long	 data		//acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
99 *  return:  NULL
100 *  notice:
101********************************************************************************************************************/
102void TsAddBaProcess(unsigned long data)
103{
104	PTX_TS_RECORD	pTxTs = (PTX_TS_RECORD)data;
105	u8 num = pTxTs->num;
106	struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]);
107
108	TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
109	IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n");
110}
111
112
113void ResetTsCommonInfo(PTS_COMMON_INFO	pTsCommonInfo)
114{
115	memset(pTsCommonInfo->Addr, 0, 6);
116	memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY));
117	memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM);
118	pTsCommonInfo->TClasProc = 0;
119	pTsCommonInfo->TClasNum = 0;
120}
121
122void ResetTxTsEntry(PTX_TS_RECORD pTS)
123{
124	ResetTsCommonInfo(&pTS->TsCommonInfo);
125	pTS->TxCurSeq = 0;
126	pTS->bAddBaReqInProgress = false;
127	pTS->bAddBaReqDelayed = false;
128	pTS->bUsingBa = false;
129	ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator
130	ResetBaEntry(&pTS->TxPendingBARecord);
131}
132
133void ResetRxTsEntry(PRX_TS_RECORD pTS)
134{
135	ResetTsCommonInfo(&pTS->TsCommonInfo);
136	pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!!
137	pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!!
138	ResetBaEntry(&pTS->RxAdmittedBARecord);	  // For BA Recepient
139}
140
141void TSInitialize(struct ieee80211_device *ieee)
142{
143	PTX_TS_RECORD		pTxTS  = ieee->TxTsRecord;
144	PRX_TS_RECORD		pRxTS  = ieee->RxTsRecord;
145	PRX_REORDER_ENTRY	pRxReorderEntry = ieee->RxReorderEntry;
146	u8				count = 0;
147	IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __FUNCTION__);
148	// Initialize Tx TS related info.
149	INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
150	INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
151	INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
152
153	for(count = 0; count < TOTAL_TS_NUM; count++)
154	{
155		//
156		pTxTS->num = count;
157		// The timers for the operation of Traffic Stream and Block Ack.
158		// DLS related timer will be add here in the future!!
159		init_timer(&pTxTS->TsCommonInfo.SetupTimer);
160		pTxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pTxTS;
161		pTxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut;
162
163		init_timer(&pTxTS->TsCommonInfo.InactTimer);
164		pTxTS->TsCommonInfo.InactTimer.data = (unsigned long)pTxTS;
165		pTxTS->TsCommonInfo.InactTimer.function = TsInactTimeout;
166
167		init_timer(&pTxTS->TsAddBaTimer);
168		pTxTS->TsAddBaTimer.data = (unsigned long)pTxTS;
169		pTxTS->TsAddBaTimer.function = TsAddBaProcess;
170
171		init_timer(&pTxTS->TxPendingBARecord.Timer);
172		pTxTS->TxPendingBARecord.Timer.data = (unsigned long)pTxTS;
173		pTxTS->TxPendingBARecord.Timer.function = BaSetupTimeOut;
174
175		init_timer(&pTxTS->TxAdmittedBARecord.Timer);
176		pTxTS->TxAdmittedBARecord.Timer.data = (unsigned long)pTxTS;
177		pTxTS->TxAdmittedBARecord.Timer.function = TxBaInactTimeout;
178
179		ResetTxTsEntry(pTxTS);
180		list_add_tail(&pTxTS->TsCommonInfo.List, &ieee->Tx_TS_Unused_List);
181		pTxTS++;
182	}
183
184	// Initialize Rx TS related info.
185	INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
186	INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
187	INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
188	for(count = 0; count < TOTAL_TS_NUM; count++)
189	{
190		pRxTS->num = count;
191		INIT_LIST_HEAD(&pRxTS->RxPendingPktList);
192
193		init_timer(&pRxTS->TsCommonInfo.SetupTimer);
194		pRxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pRxTS;
195		pRxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut;
196
197		init_timer(&pRxTS->TsCommonInfo.InactTimer);
198		pRxTS->TsCommonInfo.InactTimer.data = (unsigned long)pRxTS;
199		pRxTS->TsCommonInfo.InactTimer.function = TsInactTimeout;
200
201		init_timer(&pRxTS->RxAdmittedBARecord.Timer);
202		pRxTS->RxAdmittedBARecord.Timer.data = (unsigned long)pRxTS;
203		pRxTS->RxAdmittedBARecord.Timer.function = RxBaInactTimeout;
204
205		init_timer(&pRxTS->RxPktPendingTimer);
206		pRxTS->RxPktPendingTimer.data = (unsigned long)pRxTS;
207		pRxTS->RxPktPendingTimer.function = RxPktPendingTimeout;
208
209		ResetRxTsEntry(pRxTS);
210		list_add_tail(&pRxTS->TsCommonInfo.List, &ieee->Rx_TS_Unused_List);
211		pRxTS++;
212	}
213	// Initialize unused Rx Reorder List.
214	INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
215//#ifdef TO_DO_LIST
216	for(count = 0; count < REORDER_ENTRY_NUM; count++)
217	{
218		list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
219		if(count == (REORDER_ENTRY_NUM-1))
220			break;
221		pRxReorderEntry = &ieee->RxReorderEntry[count+1];
222	}
223//#endif
224
225}
226
227void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime)
228{
229	del_timer_sync(&pTsCommonInfo->SetupTimer);
230	del_timer_sync(&pTsCommonInfo->InactTimer);
231
232	if(InactTime!=0)
233		mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime));
234}
235
236
237PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8*	Addr, u8 TID, TR_SELECT	TxRxSelect)
238{
239	//DIRECTION_VALUE 	dir;
240	u8 	dir;
241	bool				search_dir[4] = {0, 0, 0, 0};
242	struct list_head*		psearch_list;
243	PTS_COMMON_INFO	pRet = NULL;
244	if(ieee->iw_mode == IW_MODE_MASTER) //ap mode
245	{
246		if(TxRxSelect == TX_DIR)
247		{
248			search_dir[DIR_DOWN] = true;
249			search_dir[DIR_BI_DIR]= true;
250		}
251		else
252		{
253			search_dir[DIR_UP] 	= true;
254			search_dir[DIR_BI_DIR]= true;
255		}
256	}
257	else if(ieee->iw_mode == IW_MODE_ADHOC)
258	{
259		if(TxRxSelect == TX_DIR)
260			search_dir[DIR_UP] 	= true;
261		else
262			search_dir[DIR_DOWN] = true;
263	}
264	else
265	{
266		if(TxRxSelect == TX_DIR)
267		{
268			search_dir[DIR_UP] 	= true;
269			search_dir[DIR_BI_DIR]= true;
270			search_dir[DIR_DIRECT]= true;
271		}
272		else
273		{
274			search_dir[DIR_DOWN] = true;
275			search_dir[DIR_BI_DIR]= true;
276			search_dir[DIR_DIRECT]= true;
277		}
278	}
279
280	if(TxRxSelect == TX_DIR)
281		psearch_list = &ieee->Tx_TS_Admit_List;
282	else
283		psearch_list = &ieee->Rx_TS_Admit_List;
284
285	//for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
286	for(dir = 0; dir <= DIR_BI_DIR; dir++)
287	{
288		if(search_dir[dir] ==false )
289			continue;
290		list_for_each_entry(pRet, psearch_list, List){
291	//		IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
292			if (memcmp(pRet->Addr, Addr, 6) == 0)
293				if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
294					if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
295					{
296	//					printk("Bingo! got it\n");
297						break;
298					}
299
300		}
301		if(&pRet->List  != psearch_list)
302			break;
303	}
304
305	if(&pRet->List  != psearch_list){
306		return pRet ;
307	}
308	else
309		return NULL;
310}
311
312void MakeTSEntry(
313		PTS_COMMON_INFO	pTsCommonInfo,
314		u8*		Addr,
315		PTSPEC_BODY	pTSPEC,
316		PQOS_TCLAS	pTCLAS,
317		u8		TCLAS_Num,
318		u8		TCLAS_Proc
319	)
320{
321	u8	count;
322
323	if(pTsCommonInfo == NULL)
324		return;
325
326	memcpy(pTsCommonInfo->Addr, Addr, 6);
327
328	if(pTSPEC != NULL)
329		memcpy((u8*)(&(pTsCommonInfo->TSpec)), (u8*)pTSPEC, sizeof(TSPEC_BODY));
330
331	for(count = 0; count < TCLAS_Num; count++)
332		memcpy((u8*)(&(pTsCommonInfo->TClass[count])), (u8*)pTCLAS, sizeof(QOS_TCLAS));
333
334	pTsCommonInfo->TClasProc = TCLAS_Proc;
335	pTsCommonInfo->TClasNum = TCLAS_Num;
336}
337
338
339bool GetTs(
340	struct ieee80211_device*	ieee,
341	PTS_COMMON_INFO			*ppTS,
342	u8*				Addr,
343	u8				TID,
344	TR_SELECT			TxRxSelect,  //Rx:1, Tx:0
345	bool				bAddNewTs
346	)
347{
348	u8	UP = 0;
349	//
350	// We do not build any TS for Broadcast or Multicast stream.
351	// So reject these kinds of search here.
352	//
353	if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
354	{
355		IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
356		return false;
357	}
358
359	if (ieee->current_network.qos_data.supported == 0)
360		UP = 0;
361	else
362	{
363		// In WMM case: we use 4 TID only
364		if (!IsACValid(TID))
365		{
366			IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID);
367			return false;
368		}
369
370		switch(TID)
371		{
372		case 0:
373		case 3:
374			UP = 0;
375			break;
376
377		case 1:
378		case 2:
379			UP = 2;
380			break;
381
382		case 4:
383		case 5:
384			UP = 5;
385			break;
386
387		case 6:
388		case 7:
389			UP = 7;
390			break;
391		}
392	}
393
394	*ppTS = SearchAdmitTRStream(
395			ieee,
396			Addr,
397			UP,
398			TxRxSelect);
399	if(*ppTS != NULL)
400	{
401		return true;
402	}
403	else
404	{
405		if(bAddNewTs == false)
406		{
407			IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
408			return false;
409		}
410		else
411		{
412			//
413			// Create a new Traffic stream for current Tx/Rx
414			// This is for EDCA and WMM to add a new TS.
415			// For HCCA or WMMSA, TS cannot be addmit without negotiation.
416			//
417			TSPEC_BODY	TSpec;
418			PQOS_TSINFO		pTSInfo = &TSpec.f.TSInfo;
419			struct list_head*	pUnusedList =
420								(TxRxSelect == TX_DIR)?
421								(&ieee->Tx_TS_Unused_List):
422								(&ieee->Rx_TS_Unused_List);
423
424			struct list_head*	pAddmitList =
425								(TxRxSelect == TX_DIR)?
426								(&ieee->Tx_TS_Admit_List):
427								(&ieee->Rx_TS_Admit_List);
428
429			DIRECTION_VALUE		Dir =		(ieee->iw_mode == IW_MODE_MASTER)?
430								((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP):
431								((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN);
432			IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
433			if(!list_empty(pUnusedList))
434			{
435				(*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List);
436				list_del_init(&(*ppTS)->List);
437				if(TxRxSelect==TX_DIR)
438				{
439					PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo);
440					ResetTxTsEntry(tmp);
441				}
442				else{
443					PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo);
444					ResetRxTsEntry(tmp);
445				}
446
447				IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
448				// Prepare TS Info releated field
449				pTSInfo->field.ucTrafficType = 0;			// Traffic type: WMM is reserved in this field
450				pTSInfo->field.ucTSID = UP;			// TSID
451				pTSInfo->field.ucDirection = Dir;			// Direction: if there is DirectLink, this need additional consideration.
452				pTSInfo->field.ucAccessPolicy = 1;		// Access policy
453				pTSInfo->field.ucAggregation = 0; 		// Aggregation
454				pTSInfo->field.ucPSB = 0; 				// Aggregation
455				pTSInfo->field.ucUP = UP;				// User priority
456				pTSInfo->field.ucTSInfoAckPolicy = 0;		// Ack policy
457				pTSInfo->field.ucSchedule = 0;			// Schedule
458
459				MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
460				AdmitTS(ieee, *ppTS, 0);
461				list_add_tail(&((*ppTS)->List), pAddmitList);
462				// if there is DirectLink, we need to do additional operation here!!
463
464				return true;
465			}
466			else
467			{
468				IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __FUNCTION__);
469				return false;
470			}
471		}
472	}
473}
474
475void RemoveTsEntry(
476	struct ieee80211_device*	ieee,
477	PTS_COMMON_INFO			pTs,
478	TR_SELECT			TxRxSelect
479	)
480{
481	//u32 flags = 0;
482	unsigned long flags = 0;
483	del_timer_sync(&pTs->SetupTimer);
484	del_timer_sync(&pTs->InactTimer);
485	TsInitDelBA(ieee, pTs, TxRxSelect);
486
487	if(TxRxSelect == RX_DIR)
488	{
489//#ifdef TO_DO_LIST
490		PRX_REORDER_ENTRY	pRxReorderEntry;
491		PRX_TS_RECORD 		pRxTS = (PRX_TS_RECORD)pTs;
492		if(timer_pending(&pRxTS->RxPktPendingTimer))
493			del_timer_sync(&pRxTS->RxPktPendingTimer);
494
495		while(!list_empty(&pRxTS->RxPendingPktList))
496		{
497		//      PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
498			spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
499			//pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
500			pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
501			list_del_init(&pRxReorderEntry->List);
502			{
503				int i = 0;
504				struct ieee80211_rxb * prxb = pRxReorderEntry->prxb;
505				if (unlikely(!prxb))
506				{
507					spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
508					return;
509				}
510				for(i =0; i < prxb->nr_subframes; i++) {
511					dev_kfree_skb(prxb->subframes[i]);
512				}
513				kfree(prxb);
514				prxb = NULL;
515			}
516			list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
517			//PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
518			spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
519		}
520
521//#endif
522	}
523	else
524	{
525		PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs;
526		del_timer_sync(&pTxTS->TsAddBaTimer);
527	}
528}
529
530void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr)
531{
532	PTS_COMMON_INFO	pTS, pTmpTS;
533
534	printk("===========>RemovePeerTS,%pM\n", Addr);
535	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
536	{
537		if (memcmp(pTS->Addr, Addr, 6) == 0)
538		{
539			RemoveTsEntry(ieee, pTS, TX_DIR);
540			list_del_init(&pTS->List);
541			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
542		}
543	}
544
545	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
546	{
547		if (memcmp(pTS->Addr, Addr, 6) == 0)
548		{
549			printk("====>remove Tx_TS_admin_list\n");
550			RemoveTsEntry(ieee, pTS, TX_DIR);
551			list_del_init(&pTS->List);
552			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
553		}
554	}
555
556	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
557	{
558		if (memcmp(pTS->Addr, Addr, 6) == 0)
559		{
560			RemoveTsEntry(ieee, pTS, RX_DIR);
561			list_del_init(&pTS->List);
562			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
563		}
564	}
565
566	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
567	{
568		if (memcmp(pTS->Addr, Addr, 6) == 0)
569		{
570			RemoveTsEntry(ieee, pTS, RX_DIR);
571			list_del_init(&pTS->List);
572			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
573		}
574	}
575}
576
577void RemoveAllTS(struct ieee80211_device* ieee)
578{
579	PTS_COMMON_INFO pTS, pTmpTS;
580
581	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
582	{
583		RemoveTsEntry(ieee, pTS, TX_DIR);
584		list_del_init(&pTS->List);
585		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
586	}
587
588	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
589	{
590		RemoveTsEntry(ieee, pTS, TX_DIR);
591		list_del_init(&pTS->List);
592		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
593	}
594
595	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
596	{
597		RemoveTsEntry(ieee, pTS, RX_DIR);
598		list_del_init(&pTS->List);
599		list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
600	}
601
602	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
603	{
604		RemoveTsEntry(ieee, pTS, RX_DIR);
605		list_del_init(&pTS->List);
606		list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
607	}
608}
609
610void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD	pTxTS)
611{
612	if(pTxTS->bAddBaReqInProgress == false)
613	{
614		pTxTS->bAddBaReqInProgress = true;
615		if(pTxTS->bAddBaReqDelayed)
616		{
617			IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
618			mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY));
619		}
620		else
621		{
622			IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
623			mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks
624		}
625	}
626	else
627		IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __FUNCTION__);
628}
629