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