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