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