linux/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "ieee80211.h"
   3#include <linux/etherdevice.h>
   4#include <linux/slab.h>
   5#include "rtl819x_TS.h"
   6
   7static void TsSetupTimeOut(struct timer_list *unused)
   8{
   9        // Not implement yet
  10        // This is used for WMMSA and ACM , that would send ADDTSReq frame.
  11}
  12
  13static void TsInactTimeout(struct timer_list *unused)
  14{
  15        // Not implement yet
  16        // This is used for WMMSA and ACM.
  17        // This function would be call when TS is no Tx/Rx for some period of time.
  18}
  19
  20/********************************************************************************************************************
  21 *function:  I still not understand this function, so wait for further implementation
  22 *   input:  unsigned long       data           //acturally we send struct tx_ts_record or struct rx_ts_record to these timer
  23 *  return:  NULL
  24 *  notice:
  25 ********************************************************************************************************************/
  26static void RxPktPendingTimeout(struct timer_list *t)
  27{
  28        struct rx_ts_record     *pRxTs = from_timer(pRxTs, t, rx_pkt_pending_timer);
  29        struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
  30
  31        PRX_REORDER_ENTRY       pReorderEntry = NULL;
  32
  33        //u32 flags = 0;
  34        unsigned long flags = 0;
  35        u8 index = 0;
  36        bool bPktInBuf = false;
  37
  38        spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
  39        IEEE80211_DEBUG(IEEE80211_DL_REORDER, "==================>%s()\n", __func__);
  40        if(pRxTs->rx_timeout_indicate_seq != 0xffff) {
  41                // Indicate the pending packets sequentially according to SeqNum until meet the gap.
  42                while(!list_empty(&pRxTs->rx_pending_pkt_list)) {
  43                        pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->rx_pending_pkt_list.prev, RX_REORDER_ENTRY, List);
  44                        if(index == 0)
  45                                pRxTs->rx_indicate_seq = pReorderEntry->SeqNum;
  46
  47                        if( SN_LESS(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq) ||
  48                                SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq) ) {
  49                                list_del_init(&pReorderEntry->List);
  50
  51                                if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq))
  52                                        pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 1) % 4096;
  53
  54                                IEEE80211_DEBUG(IEEE80211_DL_REORDER, "RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
  55                                ieee->stats_IndicateArray[index] = pReorderEntry->prxb;
  56                                index++;
  57
  58                                list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
  59                        } else {
  60                                bPktInBuf = true;
  61                                break;
  62                        }
  63                }
  64        }
  65
  66        if(index>0) {
  67                // Set rx_timeout_indicate_seq to 0xffff to indicate no pending packets in buffer now.
  68                pRxTs->rx_timeout_indicate_seq = 0xffff;
  69
  70                // Indicate packets
  71                if(index > REORDER_WIN_SIZE) {
  72                        IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n");
  73                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
  74                        return;
  75                }
  76                ieee80211_indicate_packets(ieee, ieee->stats_IndicateArray, index);
  77        }
  78
  79        if(bPktInBuf && (pRxTs->rx_timeout_indicate_seq == 0xffff)) {
  80                pRxTs->rx_timeout_indicate_seq = pRxTs->rx_indicate_seq;
  81                mod_timer(&pRxTs->rx_pkt_pending_timer,
  82                          jiffies + msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime));
  83        }
  84        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
  85}
  86
  87/********************************************************************************************************************
  88 *function:  Add BA timer function
  89 *   input:  unsigned long       data           //acturally we send struct tx_ts_record or struct rx_ts_record to these timer
  90 *  return:  NULL
  91 *  notice:
  92 ********************************************************************************************************************/
  93static void TsAddBaProcess(struct timer_list *t)
  94{
  95        struct tx_ts_record *pTxTs = from_timer(pTxTs, t, ts_add_ba_timer);
  96        u8 num = pTxTs->num;
  97        struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]);
  98
  99        TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
 100        IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n");
 101}
 102
 103
 104static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
 105{
 106        eth_zero_addr(pTsCommonInfo->addr);
 107        memset(&pTsCommonInfo->t_spec, 0, sizeof(struct tspec_body));
 108        memset(&pTsCommonInfo->t_class, 0, sizeof(union qos_tclas)*TCLAS_NUM);
 109        pTsCommonInfo->t_clas_proc = 0;
 110        pTsCommonInfo->t_clas_num = 0;
 111}
 112
 113static void ResetTxTsEntry(struct tx_ts_record *pTS)
 114{
 115        ResetTsCommonInfo(&pTS->ts_common_info);
 116        pTS->tx_cur_seq = 0;
 117        pTS->add_ba_req_in_progress = false;
 118        pTS->add_ba_req_delayed = false;
 119        pTS->using_ba = false;
 120        ResetBaEntry(&pTS->tx_admitted_ba_record); //For BA Originator
 121        ResetBaEntry(&pTS->tx_pending_ba_record);
 122}
 123
 124static void ResetRxTsEntry(struct rx_ts_record *pTS)
 125{
 126        ResetTsCommonInfo(&pTS->ts_common_info);
 127        pTS->rx_indicate_seq = 0xffff; // This indicate the rx_indicate_seq is not used now!!
 128        pTS->rx_timeout_indicate_seq = 0xffff; // This indicate the rx_timeout_indicate_seq is not used now!!
 129        ResetBaEntry(&pTS->rx_admitted_ba_record);        // For BA Recipient
 130}
 131
 132void TSInitialize(struct ieee80211_device *ieee)
 133{
 134        struct tx_ts_record     *pTxTS  = ieee->TxTsRecord;
 135        struct rx_ts_record     *pRxTS  = ieee->RxTsRecord;
 136        PRX_REORDER_ENTRY       pRxReorderEntry = ieee->RxReorderEntry;
 137        u8                              count = 0;
 138        IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __func__);
 139        // Initialize Tx TS related info.
 140        INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
 141        INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
 142        INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
 143
 144        for(count = 0; count < TOTAL_TS_NUM; count++) {
 145                //
 146                pTxTS->num = count;
 147                // The timers for the operation of Traffic Stream and Block Ack.
 148                // DLS related timer will be add here in the future!!
 149                timer_setup(&pTxTS->ts_common_info.setup_timer, TsSetupTimeOut,
 150                            0);
 151                timer_setup(&pTxTS->ts_common_info.inact_timer, TsInactTimeout,
 152                            0);
 153                timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0);
 154                timer_setup(&pTxTS->tx_pending_ba_record.timer, BaSetupTimeOut,
 155                            0);
 156                timer_setup(&pTxTS->tx_admitted_ba_record.timer,
 157                            TxBaInactTimeout, 0);
 158                ResetTxTsEntry(pTxTS);
 159                list_add_tail(&pTxTS->ts_common_info.list, &ieee->Tx_TS_Unused_List);
 160                pTxTS++;
 161        }
 162
 163        // Initialize Rx TS related info.
 164        INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
 165        INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
 166        INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
 167        for(count = 0; count < TOTAL_TS_NUM; count++) {
 168                pRxTS->num = count;
 169                INIT_LIST_HEAD(&pRxTS->rx_pending_pkt_list);
 170                timer_setup(&pRxTS->ts_common_info.setup_timer, TsSetupTimeOut,
 171                            0);
 172                timer_setup(&pRxTS->ts_common_info.inact_timer, TsInactTimeout,
 173                            0);
 174                timer_setup(&pRxTS->rx_admitted_ba_record.timer,
 175                            RxBaInactTimeout, 0);
 176                timer_setup(&pRxTS->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
 177                ResetRxTsEntry(pRxTS);
 178                list_add_tail(&pRxTS->ts_common_info.list, &ieee->Rx_TS_Unused_List);
 179                pRxTS++;
 180        }
 181        // Initialize unused Rx Reorder List.
 182        INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
 183//#ifdef TO_DO_LIST
 184        for(count = 0; count < REORDER_ENTRY_NUM; count++) {
 185                list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
 186                if(count == (REORDER_ENTRY_NUM-1))
 187                        break;
 188                pRxReorderEntry = &ieee->RxReorderEntry[count+1];
 189        }
 190//#endif
 191}
 192
 193static void AdmitTS(struct ieee80211_device *ieee,
 194                    struct ts_common_info *pTsCommonInfo, u32 InactTime)
 195{
 196        del_timer_sync(&pTsCommonInfo->setup_timer);
 197        del_timer_sync(&pTsCommonInfo->inact_timer);
 198
 199        if(InactTime!=0)
 200                mod_timer(&pTsCommonInfo->inact_timer,
 201                          jiffies + msecs_to_jiffies(InactTime));
 202}
 203
 204
 205static struct ts_common_info *SearchAdmitTRStream(struct ieee80211_device *ieee,
 206                                                  u8 *Addr, u8 TID,
 207                                                  enum tr_select TxRxSelect)
 208{
 209        //DIRECTION_VALUE       dir;
 210        u8      dir;
 211        bool                            search_dir[4] = {0};
 212        struct list_head                *psearch_list; //FIXME
 213        struct ts_common_info   *pRet = NULL;
 214        if(ieee->iw_mode == IW_MODE_MASTER) { //ap mode
 215                if(TxRxSelect == TX_DIR) {
 216                        search_dir[DIR_DOWN] = true;
 217                        search_dir[DIR_BI_DIR]= true;
 218                } else {
 219                        search_dir[DIR_UP]      = true;
 220                        search_dir[DIR_BI_DIR]= true;
 221                }
 222        } else if(ieee->iw_mode == IW_MODE_ADHOC) {
 223                if(TxRxSelect == TX_DIR)
 224                        search_dir[DIR_UP]      = true;
 225                else
 226                        search_dir[DIR_DOWN] = true;
 227        } else {
 228                if(TxRxSelect == TX_DIR) {
 229                        search_dir[DIR_UP]      = true;
 230                        search_dir[DIR_BI_DIR]= true;
 231                        search_dir[DIR_DIRECT]= true;
 232                } else {
 233                        search_dir[DIR_DOWN] = true;
 234                        search_dir[DIR_BI_DIR]= true;
 235                        search_dir[DIR_DIRECT]= true;
 236                }
 237        }
 238
 239        if(TxRxSelect == TX_DIR)
 240                psearch_list = &ieee->Tx_TS_Admit_List;
 241        else
 242                psearch_list = &ieee->Rx_TS_Admit_List;
 243
 244        //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
 245        for(dir = 0; dir <= DIR_BI_DIR; dir++) {
 246                if (!search_dir[dir])
 247                        continue;
 248                list_for_each_entry(pRet, psearch_list, list){
 249        //              IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.ts_info.ucTSID, pRet->TSpec.ts_info.ucDirection);
 250                        if (memcmp(pRet->addr, Addr, 6) == 0)
 251                                if (pRet->t_spec.ts_info.uc_tsid == TID)
 252                                        if(pRet->t_spec.ts_info.uc_direction == dir) {
 253        //                                      printk("Bingo! got it\n");
 254                                                break;
 255                                        }
 256                }
 257                if(&pRet->list  != psearch_list)
 258                        break;
 259        }
 260
 261        if(&pRet->list  != psearch_list)
 262                return pRet ;
 263        else
 264                return NULL;
 265}
 266
 267static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr,
 268                        struct tspec_body *pTSPEC, union qos_tclas *pTCLAS, u8 TCLAS_Num,
 269                        u8 TCLAS_Proc)
 270{
 271        u8      count;
 272
 273        if(pTsCommonInfo == NULL)
 274                return;
 275
 276        memcpy(pTsCommonInfo->addr, Addr, 6);
 277
 278        if(pTSPEC != NULL)
 279                memcpy((u8 *)(&(pTsCommonInfo->t_spec)), (u8 *)pTSPEC, sizeof(struct tspec_body));
 280
 281        for(count = 0; count < TCLAS_Num; count++)
 282                memcpy((u8 *)(&(pTsCommonInfo->t_class[count])), (u8 *)pTCLAS, sizeof(union qos_tclas));
 283
 284        pTsCommonInfo->t_clas_proc = TCLAS_Proc;
 285        pTsCommonInfo->t_clas_num = TCLAS_Num;
 286}
 287
 288
 289bool GetTs(
 290        struct ieee80211_device         *ieee,
 291        struct ts_common_info           **ppTS,
 292        u8                              *Addr,
 293        u8                              TID,
 294        enum tr_select                  TxRxSelect,  //Rx:1, Tx:0
 295        bool                            bAddNewTs
 296        )
 297{
 298        u8      UP = 0;
 299        //
 300        // We do not build any TS for Broadcast or Multicast stream.
 301        // So reject these kinds of search here.
 302        //
 303        if (is_multicast_ether_addr(Addr)) {
 304                IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
 305                return false;
 306        }
 307
 308        if (ieee->current_network.qos_data.supported == 0) {
 309                UP = 0;
 310        } else {
 311                // In WMM case: we use 4 TID only
 312                if (!is_ac_valid(TID)) {
 313                        IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __func__, TID);
 314                        return false;
 315                }
 316
 317                switch (TID) {
 318                case 0:
 319                case 3:
 320                        UP = 0;
 321                        break;
 322
 323                case 1:
 324                case 2:
 325                        UP = 2;
 326                        break;
 327
 328                case 4:
 329                case 5:
 330                        UP = 5;
 331                        break;
 332
 333                case 6:
 334                case 7:
 335                        UP = 7;
 336                        break;
 337                }
 338        }
 339
 340        *ppTS = SearchAdmitTRStream(
 341                        ieee,
 342                        Addr,
 343                        UP,
 344                        TxRxSelect);
 345        if(*ppTS != NULL) {
 346                return true;
 347        } else {
 348                if (!bAddNewTs) {
 349                        IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
 350                        return false;
 351                } else {
 352                        //
 353                        // Create a new Traffic stream for current Tx/Rx
 354                        // This is for EDCA and WMM to add a new TS.
 355                        // For HCCA or WMMSA, TS cannot be addmit without negotiation.
 356                        //
 357                        struct tspec_body       TSpec;
 358                        struct qos_tsinfo       *pTSInfo = &TSpec.ts_info;
 359                        struct list_head        *pUnusedList =
 360                                                                (TxRxSelect == TX_DIR)?
 361                                                                (&ieee->Tx_TS_Unused_List):
 362                                                                (&ieee->Rx_TS_Unused_List);
 363
 364                        struct list_head        *pAddmitList =
 365                                                                (TxRxSelect == TX_DIR)?
 366                                                                (&ieee->Tx_TS_Admit_List):
 367                                                                (&ieee->Rx_TS_Admit_List);
 368
 369                        enum direction_value    Dir =           (ieee->iw_mode == IW_MODE_MASTER)?
 370                                                                ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP):
 371                                                                ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN);
 372                        IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
 373                        if(!list_empty(pUnusedList)) {
 374                                (*ppTS) = list_entry(pUnusedList->next, struct ts_common_info, list);
 375                                list_del_init(&(*ppTS)->list);
 376                                if(TxRxSelect==TX_DIR) {
 377                                        struct tx_ts_record *tmp = container_of(*ppTS, struct tx_ts_record, ts_common_info);
 378                                        ResetTxTsEntry(tmp);
 379                                } else {
 380                                        struct rx_ts_record *tmp = container_of(*ppTS, struct rx_ts_record, ts_common_info);
 381                                        ResetRxTsEntry(tmp);
 382                                }
 383
 384                                IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
 385                                // Prepare TS Info releated field
 386                                pTSInfo->uc_traffic_type = 0;           // Traffic type: WMM is reserved in this field
 387                                pTSInfo->uc_tsid = UP;                  // TSID
 388                                pTSInfo->uc_direction = Dir;            // Direction: if there is DirectLink, this need additional consideration.
 389                                pTSInfo->uc_access_policy = 1;          // Access policy
 390                                pTSInfo->uc_aggregation = 0;            // Aggregation
 391                                pTSInfo->uc_psb = 0;                    // Aggregation
 392                                pTSInfo->uc_up = UP;                    // User priority
 393                                pTSInfo->uc_ts_info_ack_policy = 0;     // Ack policy
 394                                pTSInfo->uc_schedule = 0;               // Schedule
 395
 396                                MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
 397                                AdmitTS(ieee, *ppTS, 0);
 398                                list_add_tail(&((*ppTS)->list), pAddmitList);
 399                                // if there is DirectLink, we need to do additional operation here!!
 400
 401                                return true;
 402                        } else {
 403                                IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __func__);
 404                                return false;
 405                        }
 406                }
 407        }
 408}
 409
 410static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *pTs,
 411                          enum tr_select TxRxSelect)
 412{
 413        //u32 flags = 0;
 414        unsigned long flags = 0;
 415        del_timer_sync(&pTs->setup_timer);
 416        del_timer_sync(&pTs->inact_timer);
 417        TsInitDelBA(ieee, pTs, TxRxSelect);
 418
 419        if(TxRxSelect == RX_DIR) {
 420//#ifdef TO_DO_LIST
 421                PRX_REORDER_ENTRY       pRxReorderEntry;
 422                struct rx_ts_record     *pRxTS = (struct rx_ts_record *)pTs;
 423                if(timer_pending(&pRxTS->rx_pkt_pending_timer))
 424                        del_timer_sync(&pRxTS->rx_pkt_pending_timer);
 425
 426                while(!list_empty(&pRxTS->rx_pending_pkt_list)) {
 427                        spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
 428                        //pRxReorderEntry = list_entry(&pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
 429                        pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->rx_pending_pkt_list.prev, RX_REORDER_ENTRY, List);
 430                        list_del_init(&pRxReorderEntry->List);
 431                        {
 432                                int i = 0;
 433                                struct ieee80211_rxb *prxb = pRxReorderEntry->prxb;
 434                                if (unlikely(!prxb)) {
 435                                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 436                                        return;
 437                                }
 438                                for(i =0; i < prxb->nr_subframes; i++)
 439                                        dev_kfree_skb(prxb->subframes[i]);
 440
 441                                kfree(prxb);
 442                                prxb = NULL;
 443                        }
 444                        list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
 445                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 446                }
 447
 448//#endif
 449        } else {
 450                struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
 451                del_timer_sync(&pTxTS->ts_add_ba_timer);
 452        }
 453}
 454
 455void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
 456{
 457        struct ts_common_info   *pTS, *pTmpTS;
 458
 459        printk("===========>RemovePeerTS,%pM\n", Addr);
 460        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
 461                if (memcmp(pTS->addr, Addr, 6) == 0) {
 462                        RemoveTsEntry(ieee, pTS, TX_DIR);
 463                        list_del_init(&pTS->list);
 464                        list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 465                }
 466        }
 467
 468        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
 469                if (memcmp(pTS->addr, Addr, 6) == 0) {
 470                        printk("====>remove Tx_TS_admin_list\n");
 471                        RemoveTsEntry(ieee, pTS, TX_DIR);
 472                        list_del_init(&pTS->list);
 473                        list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 474                }
 475        }
 476
 477        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
 478                if (memcmp(pTS->addr, Addr, 6) == 0) {
 479                        RemoveTsEntry(ieee, pTS, RX_DIR);
 480                        list_del_init(&pTS->list);
 481                        list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 482                }
 483        }
 484
 485        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
 486                if (memcmp(pTS->addr, Addr, 6) == 0) {
 487                        RemoveTsEntry(ieee, pTS, RX_DIR);
 488                        list_del_init(&pTS->list);
 489                        list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 490                }
 491        }
 492}
 493
 494void RemoveAllTS(struct ieee80211_device *ieee)
 495{
 496        struct ts_common_info *pTS, *pTmpTS;
 497
 498        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
 499                RemoveTsEntry(ieee, pTS, TX_DIR);
 500                list_del_init(&pTS->list);
 501                list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 502        }
 503
 504        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
 505                RemoveTsEntry(ieee, pTS, TX_DIR);
 506                list_del_init(&pTS->list);
 507                list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 508        }
 509
 510        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
 511                RemoveTsEntry(ieee, pTS, RX_DIR);
 512                list_del_init(&pTS->list);
 513                list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 514        }
 515
 516        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
 517                RemoveTsEntry(ieee, pTS, RX_DIR);
 518                list_del_init(&pTS->list);
 519                list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 520        }
 521}
 522
 523void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTxTS)
 524{
 525        if(!pTxTS->add_ba_req_in_progress) {
 526                pTxTS->add_ba_req_in_progress = true;
 527                if(pTxTS->add_ba_req_delayed)   {
 528                        IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
 529                        mod_timer(&pTxTS->ts_add_ba_timer,
 530                                  jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
 531                } else {
 532                        IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
 533                        mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
 534                }
 535        } else {
 536                IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__);
 537        }
 538}
 539