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