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