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