rtl819x_TSProc.c revision e406322b4b963e622f41d76193d8ca9e5435adb8
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 // Not implement yet 15 // This is used for WMMSA and ACM , that would send ADDTSReq frame. 16} 17 18void TsInactTimeout(unsigned long data) 19{ 20 // Not implement yet 21 // This is used for WMMSA and ACM. 22 // This function would be call when TS is no Tx/Rx for some period of time. 23} 24 25/******************************************************************************************************************** 26 *function: I still not understand this function, so wait for further implementation 27 * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer 28 * return: NULL 29 * notice: 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 //u32 flags = 0; 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 //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); 48 IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__); 49 if(pRxTs->RxTimeoutIndicateSeq != 0xffff) 50 { 51 // Indicate the pending packets sequentially according to SeqNum until meet the gap. 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 // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now. 83 pRxTs->RxTimeoutIndicateSeq = 0xffff; 84 85 // Indicate packets 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 } 93 94 if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff)) 95 { 96 pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; 97 if(timer_pending(&pRxTs->RxPktPendingTimer)) 98 del_timer_sync(&pRxTs->RxPktPendingTimer); 99 pRxTs->RxPktPendingTimer.expires = jiffies + ieee->pHTInfo->RxReorderPendingTime; 100 add_timer(&pRxTs->RxPktPendingTimer); 101 } 102 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); 103 //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); 104} 105#endif 106 107/******************************************************************************************************************** 108 *function: Add BA timer function 109 * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer 110 * return: NULL 111 * notice: 112********************************************************************************************************************/ 113void TsAddBaProcess(unsigned long data) 114{ 115 PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; 116 u8 num = pTxTs->num; 117 struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]); 118 119 TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); 120 IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n"); 121} 122 123 124void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo) 125{ 126 memset(pTsCommonInfo->Addr, 0, 6); 127 memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY)); 128 memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM); 129 pTsCommonInfo->TClasProc = 0; 130 pTsCommonInfo->TClasNum = 0; 131} 132 133void ResetTxTsEntry(PTX_TS_RECORD pTS) 134{ 135 ResetTsCommonInfo(&pTS->TsCommonInfo); 136 pTS->TxCurSeq = 0; 137 pTS->bAddBaReqInProgress = false; 138 pTS->bAddBaReqDelayed = false; 139 pTS->bUsingBa = false; 140 ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator 141 ResetBaEntry(&pTS->TxPendingBARecord); 142} 143 144void ResetRxTsEntry(PRX_TS_RECORD pTS) 145{ 146 ResetTsCommonInfo(&pTS->TsCommonInfo); 147 pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!! 148 pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!! 149 ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recepient 150} 151 152void TSInitialize(struct ieee80211_device *ieee) 153{ 154 PTX_TS_RECORD pTxTS = ieee->TxTsRecord; 155 PRX_TS_RECORD pRxTS = ieee->RxTsRecord; 156 PRX_REORDER_ENTRY pRxReorderEntry = ieee->RxReorderEntry; 157 u8 count = 0; 158 IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __FUNCTION__); 159 // Initialize Tx TS related info. 160 INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); 161 INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); 162 INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); 163 164 for(count = 0; count < TOTAL_TS_NUM; count++) 165 { 166 // 167 pTxTS->num = count; 168 // The timers for the operation of Traffic Stream and Block Ack. 169 // DLS related timer will be add here in the future!! 170 init_timer(&pTxTS->TsCommonInfo.SetupTimer); 171 pTxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pTxTS; 172 pTxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; 173 174 init_timer(&pTxTS->TsCommonInfo.InactTimer); 175 pTxTS->TsCommonInfo.InactTimer.data = (unsigned long)pTxTS; 176 pTxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; 177 178 init_timer(&pTxTS->TsAddBaTimer); 179 pTxTS->TsAddBaTimer.data = (unsigned long)pTxTS; 180 pTxTS->TsAddBaTimer.function = TsAddBaProcess; 181 182 init_timer(&pTxTS->TxPendingBARecord.Timer); 183 pTxTS->TxPendingBARecord.Timer.data = (unsigned long)pTxTS; 184 pTxTS->TxPendingBARecord.Timer.function = BaSetupTimeOut; 185 186 init_timer(&pTxTS->TxAdmittedBARecord.Timer); 187 pTxTS->TxAdmittedBARecord.Timer.data = (unsigned long)pTxTS; 188 pTxTS->TxAdmittedBARecord.Timer.function = TxBaInactTimeout; 189 190 ResetTxTsEntry(pTxTS); 191 list_add_tail(&pTxTS->TsCommonInfo.List, &ieee->Tx_TS_Unused_List); 192 pTxTS++; 193 } 194 195 // Initialize Rx TS related info. 196 INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); 197 INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); 198 INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); 199 for(count = 0; count < TOTAL_TS_NUM; count++) 200 { 201 pRxTS->num = count; 202 INIT_LIST_HEAD(&pRxTS->RxPendingPktList); 203 204 init_timer(&pRxTS->TsCommonInfo.SetupTimer); 205 pRxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pRxTS; 206 pRxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; 207 208 init_timer(&pRxTS->TsCommonInfo.InactTimer); 209 pRxTS->TsCommonInfo.InactTimer.data = (unsigned long)pRxTS; 210 pRxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; 211 212 init_timer(&pRxTS->RxAdmittedBARecord.Timer); 213 pRxTS->RxAdmittedBARecord.Timer.data = (unsigned long)pRxTS; 214 pRxTS->RxAdmittedBARecord.Timer.function = RxBaInactTimeout; 215 216 init_timer(&pRxTS->RxPktPendingTimer); 217 pRxTS->RxPktPendingTimer.data = (unsigned long)pRxTS; 218 pRxTS->RxPktPendingTimer.function = RxPktPendingTimeout; 219 220 ResetRxTsEntry(pRxTS); 221 list_add_tail(&pRxTS->TsCommonInfo.List, &ieee->Rx_TS_Unused_List); 222 pRxTS++; 223 } 224 // Initialize unused Rx Reorder List. 225 INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); 226//#ifdef TO_DO_LIST 227 for(count = 0; count < REORDER_ENTRY_NUM; count++) 228 { 229 list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List); 230 if(count == (REORDER_ENTRY_NUM-1)) 231 break; 232 pRxReorderEntry = &ieee->RxReorderEntry[count+1]; 233 } 234//#endif 235 236} 237 238void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime) 239{ 240 del_timer_sync(&pTsCommonInfo->SetupTimer); 241 del_timer_sync(&pTsCommonInfo->InactTimer); 242 243 if(InactTime!=0) 244 mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime)); 245} 246 247 248PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8 TID, TR_SELECT TxRxSelect) 249{ 250 //DIRECTION_VALUE dir; 251 u8 dir; 252 bool search_dir[4] = {0, 0, 0, 0}; 253 struct list_head* psearch_list; //FIXME 254 PTS_COMMON_INFO pRet = NULL; 255 if(ieee->iw_mode == IW_MODE_MASTER) //ap mode 256 { 257 if(TxRxSelect == TX_DIR) 258 { 259 search_dir[DIR_DOWN] = true; 260 search_dir[DIR_BI_DIR]= true; 261 } 262 else 263 { 264 search_dir[DIR_UP] = true; 265 search_dir[DIR_BI_DIR]= true; 266 } 267 } 268 else if(ieee->iw_mode == IW_MODE_ADHOC) 269 { 270 if(TxRxSelect == TX_DIR) 271 search_dir[DIR_UP] = true; 272 else 273 search_dir[DIR_DOWN] = true; 274 } 275 else 276 { 277 if(TxRxSelect == TX_DIR) 278 { 279 search_dir[DIR_UP] = true; 280 search_dir[DIR_BI_DIR]= true; 281 search_dir[DIR_DIRECT]= true; 282 } 283 else 284 { 285 search_dir[DIR_DOWN] = true; 286 search_dir[DIR_BI_DIR]= true; 287 search_dir[DIR_DIRECT]= true; 288 } 289 } 290 291 if(TxRxSelect == TX_DIR) 292 psearch_list = &ieee->Tx_TS_Admit_List; 293 else 294 psearch_list = &ieee->Rx_TS_Admit_List; 295 296 //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++) 297 for(dir = 0; dir <= DIR_BI_DIR; dir++) 298 { 299 if(search_dir[dir] ==false ) 300 continue; 301 list_for_each_entry(pRet, psearch_list, List){ 302 // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection); 303 if (memcmp(pRet->Addr, Addr, 6) == 0) 304 if (pRet->TSpec.f.TSInfo.field.ucTSID == TID) 305 if(pRet->TSpec.f.TSInfo.field.ucDirection == dir) 306 { 307 // printk("Bingo! got it\n"); 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, "get TS for Broadcast or Multicast\n"); 367 return false; 368 } 369#if 0 370 if(ieee->pStaQos->CurrentQosMode == QOS_DISABLE) 371 { UP = 0; } //only use one TS 372 else if(ieee->pStaQos->CurrentQosMode & QOS_WMM) 373 { 374#else 375 if (ieee->current_network.qos_data.supported == 0) 376 UP = 0; 377 else 378 { 379#endif 380 // In WMM case: we use 4 TID only 381 if (!IsACValid(TID)) 382 { 383 IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID); 384 return false; 385 } 386 387 switch(TID) 388 { 389 case 0: 390 case 3: 391 UP = 0; 392 break; 393 394 case 1: 395 case 2: 396 UP = 2; 397 break; 398 399 case 4: 400 case 5: 401 UP = 5; 402 break; 403 404 case 6: 405 case 7: 406 UP = 7; 407 break; 408 } 409 } 410 411 *ppTS = SearchAdmitTRStream( 412 ieee, 413 Addr, 414 UP, 415 TxRxSelect); 416 if(*ppTS != NULL) 417 { 418 return true; 419 } 420 else 421 { 422 if(bAddNewTs == false) 423 { 424 IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP); 425 return false; 426 } 427 else 428 { 429 // 430 // Create a new Traffic stream for current Tx/Rx 431 // This is for EDCA and WMM to add a new TS. 432 // For HCCA or WMMSA, TS cannot be addmit without negotiation. 433 // 434 TSPEC_BODY TSpec; 435 PQOS_TSINFO pTSInfo = &TSpec.f.TSInfo; 436 struct list_head* pUnusedList = 437 (TxRxSelect == TX_DIR)? 438 (&ieee->Tx_TS_Unused_List): 439 (&ieee->Rx_TS_Unused_List); 440 441 struct list_head* pAddmitList = 442 (TxRxSelect == TX_DIR)? 443 (&ieee->Tx_TS_Admit_List): 444 (&ieee->Rx_TS_Admit_List); 445 446 DIRECTION_VALUE Dir = (ieee->iw_mode == IW_MODE_MASTER)? 447 ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP): 448 ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN); 449 IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n"); 450 if(!list_empty(pUnusedList)) 451 { 452 (*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List); 453 list_del_init(&(*ppTS)->List); 454 if(TxRxSelect==TX_DIR) 455 { 456 PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo); 457 ResetTxTsEntry(tmp); 458 } 459 else{ 460 PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo); 461 ResetRxTsEntry(tmp); 462 } 463 464 IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr)); 465 // Prepare TS Info releated field 466 pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field 467 pTSInfo->field.ucTSID = UP; // TSID 468 pTSInfo->field.ucDirection = Dir; // Direction: if there is DirectLink, this need additional consideration. 469 pTSInfo->field.ucAccessPolicy = 1; // Access policy 470 pTSInfo->field.ucAggregation = 0; // Aggregation 471 pTSInfo->field.ucPSB = 0; // Aggregation 472 pTSInfo->field.ucUP = UP; // User priority 473 pTSInfo->field.ucTSInfoAckPolicy = 0; // Ack policy 474 pTSInfo->field.ucSchedule = 0; // Schedule 475 476 MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); 477 AdmitTS(ieee, *ppTS, 0); 478 list_add_tail(&((*ppTS)->List), pAddmitList); 479 // if there is DirectLink, we need to do additional operation here!! 480 481 return true; 482 } 483 else 484 { 485 IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __FUNCTION__); 486 return false; 487 } 488 } 489 } 490} 491 492void RemoveTsEntry( 493 struct ieee80211_device* ieee, 494 PTS_COMMON_INFO pTs, 495 TR_SELECT TxRxSelect 496 ) 497{ 498 //u32 flags = 0; 499 unsigned long flags = 0; 500 del_timer_sync(&pTs->SetupTimer); 501 del_timer_sync(&pTs->InactTimer); 502 TsInitDelBA(ieee, pTs, TxRxSelect); 503 504 if(TxRxSelect == RX_DIR) 505 { 506//#ifdef TO_DO_LIST 507 PRX_REORDER_ENTRY pRxReorderEntry; 508 PRX_TS_RECORD pRxTS = (PRX_TS_RECORD)pTs; 509 if(timer_pending(&pRxTS->RxPktPendingTimer)) 510 del_timer_sync(&pRxTS->RxPktPendingTimer); 511 512 while(!list_empty(&pRxTS->RxPendingPktList)) 513 { 514 // PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); 515 spin_lock_irqsave(&(ieee->reorder_spinlock), flags); 516 //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); 517 pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); 518 list_del_init(&pRxReorderEntry->List); 519 { 520 int i = 0; 521 struct ieee80211_rxb * prxb = pRxReorderEntry->prxb; 522 if (unlikely(!prxb)) 523 { 524 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); 525 return; 526 } 527 for(i =0; i < prxb->nr_subframes; i++) { 528 dev_kfree_skb(prxb->subframes[i]); 529 } 530 kfree(prxb); 531 prxb = NULL; 532 } 533 list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List); 534 //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); 535 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); 536 } 537 538//#endif 539 } 540 else 541 { 542 PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs; 543 del_timer_sync(&pTxTS->TsAddBaTimer); 544 } 545} 546 547void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr) 548{ 549 PTS_COMMON_INFO pTS, pTmpTS; 550 printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr)); 551#if 1 552 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) 553 { 554 if (memcmp(pTS->Addr, Addr, 6) == 0) 555 { 556 RemoveTsEntry(ieee, pTS, TX_DIR); 557 list_del_init(&pTS->List); 558 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); 559 } 560 } 561 562 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) 563 { 564 if (memcmp(pTS->Addr, Addr, 6) == 0) 565 { 566 printk("====>remove Tx_TS_admin_list\n"); 567 RemoveTsEntry(ieee, pTS, TX_DIR); 568 list_del_init(&pTS->List); 569 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); 570 } 571 } 572 573 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) 574 { 575 if (memcmp(pTS->Addr, Addr, 6) == 0) 576 { 577 RemoveTsEntry(ieee, pTS, RX_DIR); 578 list_del_init(&pTS->List); 579 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); 580 } 581 } 582 583 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) 584 { 585 if (memcmp(pTS->Addr, Addr, 6) == 0) 586 { 587 RemoveTsEntry(ieee, pTS, RX_DIR); 588 list_del_init(&pTS->List); 589 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); 590 } 591 } 592#endif 593} 594 595void RemoveAllTS(struct ieee80211_device* ieee) 596{ 597 PTS_COMMON_INFO pTS, pTmpTS; 598#if 1 599 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) 600 { 601 RemoveTsEntry(ieee, pTS, TX_DIR); 602 list_del_init(&pTS->List); 603 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); 604 } 605 606 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) 607 { 608 RemoveTsEntry(ieee, pTS, TX_DIR); 609 list_del_init(&pTS->List); 610 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); 611 } 612 613 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) 614 { 615 RemoveTsEntry(ieee, pTS, RX_DIR); 616 list_del_init(&pTS->List); 617 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); 618 } 619 620 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) 621 { 622 RemoveTsEntry(ieee, pTS, RX_DIR); 623 list_del_init(&pTS->List); 624 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); 625 } 626#endif 627} 628 629void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS) 630{ 631 if(pTxTS->bAddBaReqInProgress == false) 632 { 633 pTxTS->bAddBaReqInProgress = true; 634#if 1 635 if(pTxTS->bAddBaReqDelayed) 636 { 637 IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n"); 638 mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY)); 639 } 640 else 641 { 642 IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n"); 643 mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks 644 } 645#endif 646 } 647 else 648 IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __FUNCTION__); 649} 650#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 651EXPORT_SYMBOL_NOVERS(RemovePeerTS); 652#else 653EXPORT_SYMBOL(RemovePeerTS); 654#endif 655