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