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        struct rx_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 = list_entry(pRxTs->rx_pending_pkt_list.prev, struct 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, "%s: IndicateSeq: %d\n", __func__, 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, "%s: ADDBA Req is started!! \n", __func__);
 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        struct rx_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        for (count = 0; count < REORDER_ENTRY_NUM; count++) {
 184                list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List);
 185                if (count == (REORDER_ENTRY_NUM - 1))
 186                        break;
 187                pRxReorderEntry = &ieee->RxReorderEntry[count + 1];
 188        }
 189}
 190
 191static void AdmitTS(struct ieee80211_device *ieee,
 192                    struct ts_common_info *pTsCommonInfo, u32 InactTime)
 193{
 194        del_timer_sync(&pTsCommonInfo->setup_timer);
 195        del_timer_sync(&pTsCommonInfo->inact_timer);
 196
 197        if (InactTime != 0)
 198                mod_timer(&pTsCommonInfo->inact_timer,
 199                          jiffies + msecs_to_jiffies(InactTime));
 200}
 201
 202
 203static struct ts_common_info *SearchAdmitTRStream(struct ieee80211_device *ieee,
 204                                                  u8 *Addr, u8 TID,
 205                                                  enum tr_select TxRxSelect)
 206{
 207        //DIRECTION_VALUE       dir;
 208        u8      dir;
 209        bool                            search_dir[4] = {0};
 210        struct list_head                *psearch_list; //FIXME
 211        struct ts_common_info   *pRet = NULL;
 212        if (ieee->iw_mode == IW_MODE_MASTER) { //ap mode
 213                if (TxRxSelect == TX_DIR) {
 214                        search_dir[DIR_DOWN] = true;
 215                        search_dir[DIR_BI_DIR] = true;
 216                } else {
 217                        search_dir[DIR_UP]      = true;
 218                        search_dir[DIR_BI_DIR] = true;
 219                }
 220        } else if (ieee->iw_mode == IW_MODE_ADHOC) {
 221                if (TxRxSelect == TX_DIR)
 222                        search_dir[DIR_UP]      = true;
 223                else
 224                        search_dir[DIR_DOWN] = true;
 225        } else {
 226                if (TxRxSelect == TX_DIR) {
 227                        search_dir[DIR_UP]      = true;
 228                        search_dir[DIR_BI_DIR] = true;
 229                        search_dir[DIR_DIRECT] = true;
 230                } else {
 231                        search_dir[DIR_DOWN] = true;
 232                        search_dir[DIR_BI_DIR] = true;
 233                        search_dir[DIR_DIRECT] = true;
 234                }
 235        }
 236
 237        if (TxRxSelect == TX_DIR)
 238                psearch_list = &ieee->Tx_TS_Admit_List;
 239        else
 240                psearch_list = &ieee->Rx_TS_Admit_List;
 241
 242        //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
 243        for (dir = 0; dir <= DIR_BI_DIR; dir++) {
 244                if (!search_dir[dir])
 245                        continue;
 246                list_for_each_entry(pRet, psearch_list, list) {
 247        //              IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.ts_info.ucTSID, pRet->TSpec.ts_info.ucDirection);
 248                        if (memcmp(pRet->addr, Addr, 6) == 0)
 249                                if (pRet->t_spec.ts_info.uc_tsid == TID)
 250                                        if (pRet->t_spec.ts_info.uc_direction == dir) {
 251        //                                      printk("Bingo! got it\n");
 252                                                break;
 253                                        }
 254                }
 255                if (&pRet->list  != psearch_list)
 256                        break;
 257        }
 258
 259        if (&pRet->list  != psearch_list)
 260                return pRet;
 261        else
 262                return NULL;
 263}
 264
 265static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr,
 266                        struct tspec_body *pTSPEC, union qos_tclas *pTCLAS, u8 TCLAS_Num,
 267                        u8 TCLAS_Proc)
 268{
 269        u8      count;
 270
 271        if (pTsCommonInfo == NULL)
 272                return;
 273
 274        memcpy(pTsCommonInfo->addr, Addr, 6);
 275
 276        if (pTSPEC != NULL)
 277                memcpy((u8 *)(&(pTsCommonInfo->t_spec)), (u8 *)pTSPEC, sizeof(struct tspec_body));
 278
 279        for (count = 0; count < TCLAS_Num; count++)
 280                memcpy((u8 *)(&(pTsCommonInfo->t_class[count])), (u8 *)pTCLAS, sizeof(union qos_tclas));
 281
 282        pTsCommonInfo->t_clas_proc = TCLAS_Proc;
 283        pTsCommonInfo->t_clas_num = TCLAS_Num;
 284}
 285
 286
 287bool GetTs(
 288        struct ieee80211_device         *ieee,
 289        struct ts_common_info           **ppTS,
 290        u8                              *Addr,
 291        u8                              TID,
 292        enum tr_select                  TxRxSelect,  //Rx:1, Tx:0
 293        bool                            bAddNewTs
 294        )
 295{
 296        u8      UP = 0;
 297        //
 298        // We do not build any TS for Broadcast or Multicast stream.
 299        // So reject these kinds of search here.
 300        //
 301        if (is_multicast_ether_addr(Addr)) {
 302                IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
 303                return false;
 304        }
 305
 306        if (ieee->current_network.qos_data.supported == 0) {
 307                UP = 0;
 308        } else {
 309                // In WMM case: we use 4 TID only
 310                if (!is_ac_valid(TID)) {
 311                        IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __func__, TID);
 312                        return false;
 313                }
 314
 315                switch (TID) {
 316                case 0:
 317                case 3:
 318                        UP = 0;
 319                        break;
 320
 321                case 1:
 322                case 2:
 323                        UP = 2;
 324                        break;
 325
 326                case 4:
 327                case 5:
 328                        UP = 5;
 329                        break;
 330
 331                case 6:
 332                case 7:
 333                        UP = 7;
 334                        break;
 335                }
 336        }
 337
 338        *ppTS = SearchAdmitTRStream(
 339                        ieee,
 340                        Addr,
 341                        UP,
 342                        TxRxSelect);
 343        if (*ppTS != NULL) {
 344                return true;
 345        } else {
 346                if (!bAddNewTs) {
 347                        IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
 348                        return false;
 349                } else {
 350                        //
 351                        // Create a new Traffic stream for current Tx/Rx
 352                        // This is for EDCA and WMM to add a new TS.
 353                        // For HCCA or WMMSA, TS cannot be addmit without negotiation.
 354                        //
 355                        struct tspec_body       TSpec;
 356                        struct qos_tsinfo       *pTSInfo = &TSpec.ts_info;
 357                        struct list_head        *pUnusedList =
 358                                                                (TxRxSelect == TX_DIR) ?
 359                                                                (&ieee->Tx_TS_Unused_List) :
 360                                                                (&ieee->Rx_TS_Unused_List);
 361
 362                        struct list_head        *pAddmitList =
 363                                                                (TxRxSelect == TX_DIR) ?
 364                                                                (&ieee->Tx_TS_Admit_List) :
 365                                                                (&ieee->Rx_TS_Admit_List);
 366
 367                        enum direction_value    Dir =           (ieee->iw_mode == IW_MODE_MASTER) ?
 368                                                                ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) :
 369                                                                ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
 370                        IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
 371                        if (!list_empty(pUnusedList)) {
 372                                (*ppTS) = list_entry(pUnusedList->next, struct ts_common_info, list);
 373                                list_del_init(&(*ppTS)->list);
 374                                if (TxRxSelect == TX_DIR) {
 375                                        struct tx_ts_record *tmp = container_of(*ppTS, struct tx_ts_record, ts_common_info);
 376                                        ResetTxTsEntry(tmp);
 377                                } else {
 378                                        struct rx_ts_record *tmp = container_of(*ppTS, struct rx_ts_record, ts_common_info);
 379                                        ResetRxTsEntry(tmp);
 380                                }
 381
 382                                IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
 383                                // Prepare TS Info related field
 384                                pTSInfo->uc_traffic_type = 0;           // Traffic type: WMM is reserved in this field
 385                                pTSInfo->uc_tsid = UP;                  // TSID
 386                                pTSInfo->uc_direction = Dir;            // Direction: if there is DirectLink, this need additional consideration.
 387                                pTSInfo->uc_access_policy = 1;          // Access policy
 388                                pTSInfo->uc_aggregation = 0;            // Aggregation
 389                                pTSInfo->uc_psb = 0;                    // Aggregation
 390                                pTSInfo->uc_up = UP;                    // User priority
 391                                pTSInfo->uc_ts_info_ack_policy = 0;     // Ack policy
 392                                pTSInfo->uc_schedule = 0;               // Schedule
 393
 394                                MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
 395                                AdmitTS(ieee, *ppTS, 0);
 396                                list_add_tail(&((*ppTS)->list), pAddmitList);
 397                                // if there is DirectLink, we need to do additional operation here!!
 398
 399                                return true;
 400                        } else {
 401                                IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __func__);
 402                                return false;
 403                        }
 404                }
 405        }
 406}
 407
 408static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *pTs,
 409                          enum tr_select TxRxSelect)
 410{
 411        //u32 flags = 0;
 412        unsigned long flags = 0;
 413        del_timer_sync(&pTs->setup_timer);
 414        del_timer_sync(&pTs->inact_timer);
 415        TsInitDelBA(ieee, pTs, TxRxSelect);
 416
 417        if (TxRxSelect == RX_DIR) {
 418                struct rx_reorder_entry *pRxReorderEntry;
 419                struct rx_ts_record     *pRxTS = (struct rx_ts_record *)pTs;
 420                if (timer_pending(&pRxTS->rx_pkt_pending_timer))
 421                        del_timer_sync(&pRxTS->rx_pkt_pending_timer);
 422
 423                while (!list_empty(&pRxTS->rx_pending_pkt_list)) {
 424                        spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
 425                        //pRxReorderEntry = list_entry(&pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
 426                        pRxReorderEntry = list_entry(pRxTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List);
 427                        list_del_init(&pRxReorderEntry->List);
 428                        {
 429                                int i = 0;
 430                                struct ieee80211_rxb *prxb = pRxReorderEntry->prxb;
 431                                if (unlikely(!prxb)) {
 432                                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 433                                        return;
 434                                }
 435                                for (i =  0; i < prxb->nr_subframes; i++)
 436                                        dev_kfree_skb(prxb->subframes[i]);
 437
 438                                kfree(prxb);
 439                                prxb = NULL;
 440                        }
 441                        list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List);
 442                        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
 443                }
 444
 445        } else {
 446                struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
 447                del_timer_sync(&pTxTS->ts_add_ba_timer);
 448        }
 449}
 450
 451void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
 452{
 453        struct ts_common_info   *pTS, *pTmpTS;
 454
 455        printk("===========>%s,%pM\n", __func__, Addr);
 456        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
 457                if (memcmp(pTS->addr, Addr, 6) == 0) {
 458                        RemoveTsEntry(ieee, pTS, TX_DIR);
 459                        list_del_init(&pTS->list);
 460                        list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 461                }
 462        }
 463
 464        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
 465                if (memcmp(pTS->addr, Addr, 6) == 0) {
 466                        printk("====>remove Tx_TS_admin_list\n");
 467                        RemoveTsEntry(ieee, pTS, TX_DIR);
 468                        list_del_init(&pTS->list);
 469                        list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 470                }
 471        }
 472
 473        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
 474                if (memcmp(pTS->addr, Addr, 6) == 0) {
 475                        RemoveTsEntry(ieee, pTS, RX_DIR);
 476                        list_del_init(&pTS->list);
 477                        list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 478                }
 479        }
 480
 481        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
 482                if (memcmp(pTS->addr, Addr, 6) == 0) {
 483                        RemoveTsEntry(ieee, pTS, RX_DIR);
 484                        list_del_init(&pTS->list);
 485                        list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 486                }
 487        }
 488}
 489
 490void RemoveAllTS(struct ieee80211_device *ieee)
 491{
 492        struct ts_common_info *pTS, *pTmpTS;
 493
 494        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
 495                RemoveTsEntry(ieee, pTS, TX_DIR);
 496                list_del_init(&pTS->list);
 497                list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 498        }
 499
 500        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
 501                RemoveTsEntry(ieee, pTS, TX_DIR);
 502                list_del_init(&pTS->list);
 503                list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List);
 504        }
 505
 506        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
 507                RemoveTsEntry(ieee, pTS, RX_DIR);
 508                list_del_init(&pTS->list);
 509                list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 510        }
 511
 512        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
 513                RemoveTsEntry(ieee, pTS, RX_DIR);
 514                list_del_init(&pTS->list);
 515                list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List);
 516        }
 517}
 518
 519void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTxTS)
 520{
 521        if (!pTxTS->add_ba_req_in_progress) {
 522                pTxTS->add_ba_req_in_progress = true;
 523                if (pTxTS->add_ba_req_delayed)  {
 524                        IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Delayed Start ADDBA after 60 sec!!\n", __func__);
 525                        mod_timer(&pTxTS->ts_add_ba_timer,
 526                                  jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
 527                } else {
 528                        IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Immediately Start ADDBA now!!\n", __func__);
 529                        mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10); //set 10 ticks
 530                }
 531        } else {
 532                IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__);
 533        }
 534}
 535