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