linux/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
<<
>>
Prefs
   1#include "ieee80211.h"
   2#include <linux/etherdevice.h>
   3#include <linux/slab.h>
   4#include "rtl819x_TS.h"
   5
   6static void TsSetupTimeOut(unsigned long data)
   7{
   8        // Not implement yet
   9        // This is used for WMMSA and ACM , that would send ADDTSReq frame.
  10}
  11
  12static void 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********************************************************************************************************************/
  25static void 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",__func__);
  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********************************************************************************************************************/
 102static void 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
 113static void 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
 122static void 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
 133static void 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 Recipient
 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", __func__);
 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
 227static void AdmitTS(struct ieee80211_device *ieee,
 228                    PTS_COMMON_INFO pTsCommonInfo, u32 InactTime)
 229{
 230        del_timer_sync(&pTsCommonInfo->SetupTimer);
 231        del_timer_sync(&pTsCommonInfo->InactTimer);
 232
 233        if(InactTime!=0)
 234                mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime));
 235}
 236
 237
 238static PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee,
 239                                           u8 *Addr, u8 TID,
 240                                           TR_SELECT TxRxSelect)
 241{
 242        //DIRECTION_VALUE       dir;
 243        u8      dir;
 244        bool                            search_dir[4] = {0};
 245        struct list_head                *psearch_list; //FIXME
 246        PTS_COMMON_INFO pRet = NULL;
 247        if(ieee->iw_mode == IW_MODE_MASTER) //ap mode
 248        {
 249                if(TxRxSelect == TX_DIR)
 250                {
 251                        search_dir[DIR_DOWN] = true;
 252                        search_dir[DIR_BI_DIR]= true;
 253                }
 254                else
 255                {
 256                        search_dir[DIR_UP]      = true;
 257                        search_dir[DIR_BI_DIR]= true;
 258                }
 259        }
 260        else if(ieee->iw_mode == IW_MODE_ADHOC)
 261        {
 262                if(TxRxSelect == TX_DIR)
 263                        search_dir[DIR_UP]      = true;
 264                else
 265                        search_dir[DIR_DOWN] = true;
 266        }
 267        else
 268        {
 269                if(TxRxSelect == TX_DIR)
 270                {
 271                        search_dir[DIR_UP]      = true;
 272                        search_dir[DIR_BI_DIR]= true;
 273                        search_dir[DIR_DIRECT]= true;
 274                }
 275                else
 276                {
 277                        search_dir[DIR_DOWN] = true;
 278                        search_dir[DIR_BI_DIR]= true;
 279                        search_dir[DIR_DIRECT]= true;
 280                }
 281        }
 282
 283        if(TxRxSelect == TX_DIR)
 284                psearch_list = &ieee->Tx_TS_Admit_List;
 285        else
 286                psearch_list = &ieee->Rx_TS_Admit_List;
 287
 288        //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
 289        for(dir = 0; dir <= DIR_BI_DIR; dir++)
 290        {
 291                if(search_dir[dir] ==false )
 292                        continue;
 293                list_for_each_entry(pRet, psearch_list, List){
 294        //              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);
 295                        if (memcmp(pRet->Addr, Addr, 6) == 0)
 296                                if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
 297                                        if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
 298                                        {
 299        //                                      printk("Bingo! got it\n");
 300                                                break;
 301                                        }
 302
 303                }
 304                if(&pRet->List  != psearch_list)
 305                        break;
 306        }
 307
 308        if(&pRet->List  != psearch_list){
 309                return pRet ;
 310        }
 311        else
 312                return NULL;
 313}
 314
 315static void MakeTSEntry(PTS_COMMON_INFO pTsCommonInfo, u8 *Addr,
 316                        PTSPEC_BODY pTSPEC, PQOS_TCLAS pTCLAS, u8 TCLAS_Num,
 317                        u8 TCLAS_Proc)
 318{
 319        u8      count;
 320
 321        if(pTsCommonInfo == NULL)
 322                return;
 323
 324        memcpy(pTsCommonInfo->Addr, Addr, 6);
 325
 326        if(pTSPEC != NULL)
 327                memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC, sizeof(TSPEC_BODY));
 328
 329        for(count = 0; count < TCLAS_Num; count++)
 330                memcpy((u8 *)(&(pTsCommonInfo->TClass[count])), (u8 *)pTCLAS, sizeof(QOS_TCLAS));
 331
 332        pTsCommonInfo->TClasProc = TCLAS_Proc;
 333        pTsCommonInfo->TClasNum = TCLAS_Num;
 334}
 335
 336
 337bool GetTs(
 338        struct ieee80211_device         *ieee,
 339        PTS_COMMON_INFO                 *ppTS,
 340        u8                              *Addr,
 341        u8                              TID,
 342        TR_SELECT                       TxRxSelect,  //Rx:1, Tx:0
 343        bool                            bAddNewTs
 344        )
 345{
 346        u8      UP = 0;
 347        //
 348        // We do not build any TS for Broadcast or Multicast stream.
 349        // So reject these kinds of search here.
 350        //
 351        if (is_multicast_ether_addr(Addr))
 352        {
 353                IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
 354                return false;
 355        }
 356
 357        if (ieee->current_network.qos_data.supported == 0)
 358                UP = 0;
 359        else
 360        {
 361                // In WMM case: we use 4 TID only
 362                if (!IsACValid(TID))
 363                {
 364                        IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __func__, TID);
 365                        return false;
 366                }
 367
 368                switch (TID)
 369                {
 370                case 0:
 371                case 3:
 372                        UP = 0;
 373                        break;
 374
 375                case 1:
 376                case 2:
 377                        UP = 2;
 378                        break;
 379
 380                case 4:
 381                case 5:
 382                        UP = 5;
 383                        break;
 384
 385                case 6:
 386                case 7:
 387                        UP = 7;
 388                        break;
 389                }
 390        }
 391
 392        *ppTS = SearchAdmitTRStream(
 393                        ieee,
 394                        Addr,
 395                        UP,
 396                        TxRxSelect);
 397        if(*ppTS != NULL)
 398        {
 399                return true;
 400        }
 401        else
 402        {
 403                if(bAddNewTs == false)
 404                {
 405                        IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
 406                        return false;
 407                }
 408                else
 409                {
 410                        //
 411                        // Create a new Traffic stream for current Tx/Rx
 412                        // This is for EDCA and WMM to add a new TS.
 413                        // For HCCA or WMMSA, TS cannot be addmit without negotiation.
 414                        //
 415                        TSPEC_BODY      TSpec;
 416                        PQOS_TSINFO             pTSInfo = &TSpec.f.TSInfo;
 417                        struct list_head        *pUnusedList =
 418                                                                (TxRxSelect == TX_DIR)?
 419                                                                (&ieee->Tx_TS_Unused_List):
 420                                                                (&ieee->Rx_TS_Unused_List);
 421
 422                        struct list_head        *pAddmitList =
 423                                                                (TxRxSelect == TX_DIR)?
 424                                                                (&ieee->Tx_TS_Admit_List):
 425                                                                (&ieee->Rx_TS_Admit_List);
 426
 427                        DIRECTION_VALUE         Dir =           (ieee->iw_mode == IW_MODE_MASTER)?
 428                                                                ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP):
 429                                                                ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN);
 430                        IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
 431                        if(!list_empty(pUnusedList))
 432                        {
 433                                (*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List);
 434                                list_del_init(&(*ppTS)->List);
 435                                if(TxRxSelect==TX_DIR)
 436                                {
 437                                        PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo);
 438                                        ResetTxTsEntry(tmp);
 439                                }
 440                                else{
 441                                        PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo);
 442                                        ResetRxTsEntry(tmp);
 443                                }
 444
 445                                IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
 446                                // Prepare TS Info releated field
 447                                pTSInfo->field.ucTrafficType = 0;                       // Traffic type: WMM is reserved in this field
 448                                pTSInfo->field.ucTSID = UP;                     // TSID
 449                                pTSInfo->field.ucDirection = Dir;                       // Direction: if there is DirectLink, this need additional consideration.
 450                                pTSInfo->field.ucAccessPolicy = 1;              // Access policy
 451                                pTSInfo->field.ucAggregation = 0;               // Aggregation
 452                                pTSInfo->field.ucPSB = 0;                               // Aggregation
 453                                pTSInfo->field.ucUP = UP;                               // User priority
 454                                pTSInfo->field.ucTSInfoAckPolicy = 0;           // Ack policy
 455                                pTSInfo->field.ucSchedule = 0;                  // Schedule
 456
 457                                MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
 458                                AdmitTS(ieee, *ppTS, 0);
 459                                list_add_tail(&((*ppTS)->List), pAddmitList);
 460                                // if there is DirectLink, we need to do additional operation here!!
 461
 462                                return true;
 463                        }
 464                        else
 465                        {
 466                                IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __func__);
 467                                return false;
 468                        }
 469                }
 470        }
 471}
 472
 473static void RemoveTsEntry(struct ieee80211_device *ieee, PTS_COMMON_INFO pTs,
 474                          TR_SELECT TxRxSelect)
 475{
 476        //u32 flags = 0;
 477        unsigned long flags = 0;
 478        del_timer_sync(&pTs->SetupTimer);
 479        del_timer_sync(&pTs->InactTimer);
 480        TsInitDelBA(ieee, pTs, TxRxSelect);
 481
 482        if(TxRxSelect == RX_DIR)
 483        {
 484//#ifdef TO_DO_LIST
 485                PRX_REORDER_ENTRY       pRxReorderEntry;
 486                PRX_TS_RECORD           pRxTS = (PRX_TS_RECORD)pTs;
 487                if(timer_pending(&pRxTS->RxPktPendingTimer))
 488                        del_timer_sync(&pRxTS->RxPktPendingTimer);
 489
 490                while(!list_empty(&pRxTS->RxPendingPktList))
 491                {
 492                //      PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
 493                        spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
 494                        //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
 495                        pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
 496                        list_del_init(&pRxReorderEntry->List);
 497                        {
 498                                int i = 0;
 499                                struct ieee80211_rxb *prxb = pRxReorderEntry->prxb;
 500                                if (unlikely(!prxb))
 501                                {
 502                                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 503                                        return;
 504                                }
 505                                for(i =0; i < prxb->nr_subframes; i++) {
 506                                        dev_kfree_skb(prxb->subframes[i]);
 507                                }
 508                                kfree(prxb);
 509                                prxb = NULL;
 510                        }
 511                        list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
 512                        //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
 513                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 514                }
 515
 516//#endif
 517        }
 518        else
 519        {
 520                PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs;
 521                del_timer_sync(&pTxTS->TsAddBaTimer);
 522        }
 523}
 524
 525void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
 526{
 527        PTS_COMMON_INFO pTS, pTmpTS;
 528
 529        printk("===========>RemovePeerTS,%pM\n", Addr);
 530        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
 531        {
 532                if (memcmp(pTS->Addr, Addr, 6) == 0)
 533                {
 534                        RemoveTsEntry(ieee, pTS, TX_DIR);
 535                        list_del_init(&pTS->List);
 536                        list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 537                }
 538        }
 539
 540        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
 541        {
 542                if (memcmp(pTS->Addr, Addr, 6) == 0)
 543                {
 544                        printk("====>remove Tx_TS_admin_list\n");
 545                        RemoveTsEntry(ieee, pTS, TX_DIR);
 546                        list_del_init(&pTS->List);
 547                        list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 548                }
 549        }
 550
 551        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
 552        {
 553                if (memcmp(pTS->Addr, Addr, 6) == 0)
 554                {
 555                        RemoveTsEntry(ieee, pTS, RX_DIR);
 556                        list_del_init(&pTS->List);
 557                        list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 558                }
 559        }
 560
 561        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
 562        {
 563                if (memcmp(pTS->Addr, Addr, 6) == 0)
 564                {
 565                        RemoveTsEntry(ieee, pTS, RX_DIR);
 566                        list_del_init(&pTS->List);
 567                        list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 568                }
 569        }
 570}
 571
 572void RemoveAllTS(struct ieee80211_device *ieee)
 573{
 574        PTS_COMMON_INFO pTS, pTmpTS;
 575
 576        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
 577        {
 578                RemoveTsEntry(ieee, pTS, TX_DIR);
 579                list_del_init(&pTS->List);
 580                list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 581        }
 582
 583        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
 584        {
 585                RemoveTsEntry(ieee, pTS, TX_DIR);
 586                list_del_init(&pTS->List);
 587                list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 588        }
 589
 590        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
 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        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
 598        {
 599                RemoveTsEntry(ieee, pTS, RX_DIR);
 600                list_del_init(&pTS->List);
 601                list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 602        }
 603}
 604
 605void TsStartAddBaProcess(struct ieee80211_device *ieee, PTX_TS_RECORD   pTxTS)
 606{
 607        if(pTxTS->bAddBaReqInProgress == false)
 608        {
 609                pTxTS->bAddBaReqInProgress = true;
 610                if(pTxTS->bAddBaReqDelayed)
 611                {
 612                        IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
 613                        mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY));
 614                }
 615                else
 616                {
 617                        IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
 618                        mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks
 619                }
 620        }
 621        else
 622                IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__);
 623}
 624