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