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
   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 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", __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; //FIXME
 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