GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / rtl8192u / ieee80211 / rtl819x_TSProc.c
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
7 static void TsSetupTimeOut(struct timer_list *unused)
8 {
9         // Not implement yet
10         // This is used for WMMSA and ACM , that would send ADDTSReq frame.
11 }
12
13 static void TsInactTimeout(struct timer_list *unused)
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 struct tx_ts_record or struct rx_ts_record to these timer
23  *  return:  NULL
24  *  notice:
25  ********************************************************************************************************************/
26 static void RxPktPendingTimeout(struct timer_list *t)
27 {
28         struct rx_ts_record     *pRxTs = from_timer(pRxTs, t, rx_pkt_pending_timer);
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->rx_timeout_indicate_seq != 0xffff) {
41                 // Indicate the pending packets sequentially according to SeqNum until meet the gap.
42                 while(!list_empty(&pRxTs->rx_pending_pkt_list)) {
43                         pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
44                         if(index == 0)
45                                 pRxTs->rx_indicate_seq = pReorderEntry->SeqNum;
46
47                         if( SN_LESS(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq) ||
48                                 SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq) ) {
49                                 list_del_init(&pReorderEntry->List);
50
51                                 if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq))
52                                         pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 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 rx_timeout_indicate_seq to 0xffff to indicate no pending packets in buffer now.
68                 pRxTs->rx_timeout_indicate_seq = 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->rx_timeout_indicate_seq == 0xffff)) {
80                 pRxTs->rx_timeout_indicate_seq = pRxTs->rx_indicate_seq;
81                 mod_timer(&pRxTs->rx_pkt_pending_timer,
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 struct tx_ts_record or struct rx_ts_record to these timer
90  *  return:  NULL
91  *  notice:
92  ********************************************************************************************************************/
93 static void TsAddBaProcess(struct timer_list *t)
94 {
95         struct tx_ts_record *pTxTs = from_timer(pTxTs, t, ts_add_ba_timer);
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
104 static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
105 {
106         eth_zero_addr(pTsCommonInfo->addr);
107         memset(&pTsCommonInfo->t_spec, 0, sizeof(struct tspec_body));
108         memset(&pTsCommonInfo->t_class, 0, sizeof(union qos_tclas)*TCLAS_NUM);
109         pTsCommonInfo->t_clas_proc = 0;
110         pTsCommonInfo->t_clas_num = 0;
111 }
112
113 static void ResetTxTsEntry(struct tx_ts_record *pTS)
114 {
115         ResetTsCommonInfo(&pTS->ts_common_info);
116         pTS->tx_cur_seq = 0;
117         pTS->add_ba_req_in_progress = false;
118         pTS->add_ba_req_delayed = false;
119         pTS->using_ba = false;
120         ResetBaEntry(&pTS->tx_admitted_ba_record); //For BA Originator
121         ResetBaEntry(&pTS->tx_pending_ba_record);
122 }
123
124 static void ResetRxTsEntry(struct rx_ts_record *pTS)
125 {
126         ResetTsCommonInfo(&pTS->ts_common_info);
127         pTS->rx_indicate_seq = 0xffff; // This indicate the rx_indicate_seq is not used now!!
128         pTS->rx_timeout_indicate_seq = 0xffff; // This indicate the rx_timeout_indicate_seq is not used now!!
129         ResetBaEntry(&pTS->rx_admitted_ba_record);        // For BA Recipient
130 }
131
132 void TSInitialize(struct ieee80211_device *ieee)
133 {
134         struct tx_ts_record     *pTxTS  = ieee->TxTsRecord;
135         struct rx_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                 timer_setup(&pTxTS->ts_common_info.setup_timer, TsSetupTimeOut,
150                             0);
151                 timer_setup(&pTxTS->ts_common_info.inact_timer, TsInactTimeout,
152                             0);
153                 timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0);
154                 timer_setup(&pTxTS->tx_pending_ba_record.Timer, BaSetupTimeOut,
155                             0);
156                 timer_setup(&pTxTS->tx_admitted_ba_record.Timer,
157                             TxBaInactTimeout, 0);
158                 ResetTxTsEntry(pTxTS);
159                 list_add_tail(&pTxTS->ts_common_info.list, &ieee->Tx_TS_Unused_List);
160                 pTxTS++;
161         }
162
163         // Initialize Rx TS related info.
164         INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
165         INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
166         INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
167         for(count = 0; count < TOTAL_TS_NUM; count++) {
168                 pRxTS->num = count;
169                 INIT_LIST_HEAD(&pRxTS->rx_pending_pkt_list);
170                 timer_setup(&pRxTS->ts_common_info.setup_timer, TsSetupTimeOut,
171                             0);
172                 timer_setup(&pRxTS->ts_common_info.inact_timer, TsInactTimeout,
173                             0);
174                 timer_setup(&pRxTS->rx_admitted_ba_record.Timer,
175                             RxBaInactTimeout, 0);
176                 timer_setup(&pRxTS->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
177                 ResetRxTsEntry(pRxTS);
178                 list_add_tail(&pRxTS->ts_common_info.list, &ieee->Rx_TS_Unused_List);
179                 pRxTS++;
180         }
181         // Initialize unused Rx Reorder List.
182         INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
183 //#ifdef TO_DO_LIST
184         for(count = 0; count < REORDER_ENTRY_NUM; count++) {
185                 list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
186                 if(count == (REORDER_ENTRY_NUM-1))
187                         break;
188                 pRxReorderEntry = &ieee->RxReorderEntry[count+1];
189         }
190 //#endif
191 }
192
193 static void AdmitTS(struct ieee80211_device *ieee,
194                     struct ts_common_info *pTsCommonInfo, u32 InactTime)
195 {
196         del_timer_sync(&pTsCommonInfo->setup_timer);
197         del_timer_sync(&pTsCommonInfo->inact_timer);
198
199         if(InactTime!=0)
200                 mod_timer(&pTsCommonInfo->inact_timer,
201                           jiffies + msecs_to_jiffies(InactTime));
202 }
203
204
205 static struct ts_common_info *SearchAdmitTRStream(struct ieee80211_device *ieee,
206                                                   u8 *Addr, u8 TID,
207                                                   enum tr_select TxRxSelect)
208 {
209         //DIRECTION_VALUE       dir;
210         u8      dir;
211         bool                            search_dir[4] = {0};
212         struct list_head                *psearch_list; //FIXME
213         struct ts_common_info   *pRet = NULL;
214         if(ieee->iw_mode == IW_MODE_MASTER) { //ap mode
215                 if(TxRxSelect == TX_DIR) {
216                         search_dir[DIR_DOWN] = true;
217                         search_dir[DIR_BI_DIR]= true;
218                 } else {
219                         search_dir[DIR_UP]      = true;
220                         search_dir[DIR_BI_DIR]= true;
221                 }
222         } else if(ieee->iw_mode == IW_MODE_ADHOC) {
223                 if(TxRxSelect == TX_DIR)
224                         search_dir[DIR_UP]      = true;
225                 else
226                         search_dir[DIR_DOWN] = true;
227         } else {
228                 if(TxRxSelect == TX_DIR) {
229                         search_dir[DIR_UP]      = true;
230                         search_dir[DIR_BI_DIR]= true;
231                         search_dir[DIR_DIRECT]= true;
232                 } else {
233                         search_dir[DIR_DOWN] = true;
234                         search_dir[DIR_BI_DIR]= true;
235                         search_dir[DIR_DIRECT]= true;
236                 }
237         }
238
239         if(TxRxSelect == TX_DIR)
240                 psearch_list = &ieee->Tx_TS_Admit_List;
241         else
242                 psearch_list = &ieee->Rx_TS_Admit_List;
243
244         //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
245         for(dir = 0; dir <= DIR_BI_DIR; dir++) {
246                 if (!search_dir[dir])
247                         continue;
248                 list_for_each_entry(pRet, psearch_list, list){
249         //              IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.ts_info.ucTSID, pRet->TSpec.ts_info.ucDirection);
250                         if (memcmp(pRet->addr, Addr, 6) == 0)
251                                 if (pRet->t_spec.ts_info.uc_tsid == TID)
252                                         if(pRet->t_spec.ts_info.uc_direction == dir) {
253         //                                      printk("Bingo! got it\n");
254                                                 break;
255                                         }
256                 }
257                 if(&pRet->list  != psearch_list)
258                         break;
259         }
260
261         if(&pRet->list  != psearch_list)
262                 return pRet ;
263         else
264                 return NULL;
265 }
266
267 static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr,
268                         struct tspec_body *pTSPEC, union qos_tclas *pTCLAS, u8 TCLAS_Num,
269                         u8 TCLAS_Proc)
270 {
271         u8      count;
272
273         if(pTsCommonInfo == NULL)
274                 return;
275
276         memcpy(pTsCommonInfo->addr, Addr, 6);
277
278         if(pTSPEC != NULL)
279                 memcpy((u8 *)(&(pTsCommonInfo->t_spec)), (u8 *)pTSPEC, sizeof(struct tspec_body));
280
281         for(count = 0; count < TCLAS_Num; count++)
282                 memcpy((u8 *)(&(pTsCommonInfo->t_class[count])), (u8 *)pTCLAS, sizeof(union qos_tclas));
283
284         pTsCommonInfo->t_clas_proc = TCLAS_Proc;
285         pTsCommonInfo->t_clas_num = TCLAS_Num;
286 }
287
288
289 bool GetTs(
290         struct ieee80211_device         *ieee,
291         struct ts_common_info           **ppTS,
292         u8                              *Addr,
293         u8                              TID,
294         enum tr_select                  TxRxSelect,  //Rx:1, Tx:0
295         bool                            bAddNewTs
296         )
297 {
298         u8      UP = 0;
299         //
300         // We do not build any TS for Broadcast or Multicast stream.
301         // So reject these kinds of search here.
302         //
303         if (is_multicast_ether_addr(Addr)) {
304                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
305                 return false;
306         }
307
308         if (ieee->current_network.qos_data.supported == 0) {
309                 UP = 0;
310         } else {
311                 // In WMM case: we use 4 TID only
312                 if (!is_ac_valid(TID)) {
313                         IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __func__, TID);
314                         return false;
315                 }
316
317                 switch (TID) {
318                 case 0:
319                 case 3:
320                         UP = 0;
321                         break;
322
323                 case 1:
324                 case 2:
325                         UP = 2;
326                         break;
327
328                 case 4:
329                 case 5:
330                         UP = 5;
331                         break;
332
333                 case 6:
334                 case 7:
335                         UP = 7;
336                         break;
337                 }
338         }
339
340         *ppTS = SearchAdmitTRStream(
341                         ieee,
342                         Addr,
343                         UP,
344                         TxRxSelect);
345         if(*ppTS != NULL) {
346                 return true;
347         } else {
348                 if (!bAddNewTs) {
349                         IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
350                         return false;
351                 } else {
352                         //
353                         // Create a new Traffic stream for current Tx/Rx
354                         // This is for EDCA and WMM to add a new TS.
355                         // For HCCA or WMMSA, TS cannot be addmit without negotiation.
356                         //
357                         struct tspec_body       TSpec;
358                         struct qos_tsinfo       *pTSInfo = &TSpec.ts_info;
359                         struct list_head        *pUnusedList =
360                                                                 (TxRxSelect == TX_DIR)?
361                                                                 (&ieee->Tx_TS_Unused_List):
362                                                                 (&ieee->Rx_TS_Unused_List);
363
364                         struct list_head        *pAddmitList =
365                                                                 (TxRxSelect == TX_DIR)?
366                                                                 (&ieee->Tx_TS_Admit_List):
367                                                                 (&ieee->Rx_TS_Admit_List);
368
369                         enum direction_value    Dir =           (ieee->iw_mode == IW_MODE_MASTER)?
370                                                                 ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP):
371                                                                 ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN);
372                         IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
373                         if(!list_empty(pUnusedList)) {
374                                 (*ppTS) = list_entry(pUnusedList->next, struct ts_common_info, list);
375                                 list_del_init(&(*ppTS)->list);
376                                 if(TxRxSelect==TX_DIR) {
377                                         struct tx_ts_record *tmp = container_of(*ppTS, struct tx_ts_record, ts_common_info);
378                                         ResetTxTsEntry(tmp);
379                                 } else {
380                                         struct rx_ts_record *tmp = container_of(*ppTS, struct rx_ts_record, ts_common_info);
381                                         ResetRxTsEntry(tmp);
382                                 }
383
384                                 IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
385                                 // Prepare TS Info releated field
386                                 pTSInfo->uc_traffic_type = 0;           // Traffic type: WMM is reserved in this field
387                                 pTSInfo->uc_tsid = UP;                  // TSID
388                                 pTSInfo->uc_direction = Dir;            // Direction: if there is DirectLink, this need additional consideration.
389                                 pTSInfo->uc_access_policy = 1;          // Access policy
390                                 pTSInfo->uc_aggregation = 0;            // Aggregation
391                                 pTSInfo->uc_psb = 0;                    // Aggregation
392                                 pTSInfo->uc_up = UP;                    // User priority
393                                 pTSInfo->uc_ts_info_ack_policy = 0;     // Ack policy
394                                 pTSInfo->uc_schedule = 0;               // Schedule
395
396                                 MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
397                                 AdmitTS(ieee, *ppTS, 0);
398                                 list_add_tail(&((*ppTS)->list), pAddmitList);
399                                 // if there is DirectLink, we need to do additional operation here!!
400
401                                 return true;
402                         } else {
403                                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __func__);
404                                 return false;
405                         }
406                 }
407         }
408 }
409
410 static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *pTs,
411                           enum tr_select TxRxSelect)
412 {
413         //u32 flags = 0;
414         unsigned long flags = 0;
415         del_timer_sync(&pTs->setup_timer);
416         del_timer_sync(&pTs->inact_timer);
417         TsInitDelBA(ieee, pTs, TxRxSelect);
418
419         if(TxRxSelect == RX_DIR) {
420 //#ifdef TO_DO_LIST
421                 PRX_REORDER_ENTRY       pRxReorderEntry;
422                 struct rx_ts_record     *pRxTS = (struct rx_ts_record *)pTs;
423                 if(timer_pending(&pRxTS->rx_pkt_pending_timer))
424                         del_timer_sync(&pRxTS->rx_pkt_pending_timer);
425
426                 while(!list_empty(&pRxTS->rx_pending_pkt_list)) {
427                         spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
428                         //pRxReorderEntry = list_entry(&pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
429                         pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
430                         list_del_init(&pRxReorderEntry->List);
431                         {
432                                 int i = 0;
433                                 struct ieee80211_rxb *prxb = pRxReorderEntry->prxb;
434                                 if (unlikely(!prxb)) {
435                                         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
436                                         return;
437                                 }
438                                 for(i =0; i < prxb->nr_subframes; i++)
439                                         dev_kfree_skb(prxb->subframes[i]);
440
441                                 kfree(prxb);
442                                 prxb = NULL;
443                         }
444                         list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
445                         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
446                 }
447
448 //#endif
449         } else {
450                 struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
451                 del_timer_sync(&pTxTS->ts_add_ba_timer);
452         }
453 }
454
455 void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
456 {
457         struct ts_common_info   *pTS, *pTmpTS;
458
459         printk("===========>RemovePeerTS,%pM\n", Addr);
460         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
461                 if (memcmp(pTS->addr, Addr, 6) == 0) {
462                         RemoveTsEntry(ieee, pTS, TX_DIR);
463                         list_del_init(&pTS->list);
464                         list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
465                 }
466         }
467
468         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
469                 if (memcmp(pTS->addr, Addr, 6) == 0) {
470                         printk("====>remove Tx_TS_admin_list\n");
471                         RemoveTsEntry(ieee, pTS, TX_DIR);
472                         list_del_init(&pTS->list);
473                         list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
474                 }
475         }
476
477         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
478                 if (memcmp(pTS->addr, Addr, 6) == 0) {
479                         RemoveTsEntry(ieee, pTS, RX_DIR);
480                         list_del_init(&pTS->list);
481                         list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
482                 }
483         }
484
485         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
486                 if (memcmp(pTS->addr, Addr, 6) == 0) {
487                         RemoveTsEntry(ieee, pTS, RX_DIR);
488                         list_del_init(&pTS->list);
489                         list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
490                 }
491         }
492 }
493
494 void RemoveAllTS(struct ieee80211_device *ieee)
495 {
496         struct ts_common_info *pTS, *pTmpTS;
497
498         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
499                 RemoveTsEntry(ieee, pTS, TX_DIR);
500                 list_del_init(&pTS->list);
501                 list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
502         }
503
504         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
505                 RemoveTsEntry(ieee, pTS, TX_DIR);
506                 list_del_init(&pTS->list);
507                 list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
508         }
509
510         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
511                 RemoveTsEntry(ieee, pTS, RX_DIR);
512                 list_del_init(&pTS->list);
513                 list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
514         }
515
516         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
517                 RemoveTsEntry(ieee, pTS, RX_DIR);
518                 list_del_init(&pTS->list);
519                 list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
520         }
521 }
522
523 void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTxTS)
524 {
525         if(!pTxTS->add_ba_req_in_progress) {
526                 pTxTS->add_ba_req_in_progress = true;
527                 if(pTxTS->add_ba_req_delayed)   {
528                         IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
529                         mod_timer(&pTxTS->ts_add_ba_timer,
530                                   jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
531                 } else {
532                         IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
533                         mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
534                 }
535         } else {
536                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__);
537         }
538 }