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