root/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mwifiex_11n_dispatch_amsdu_pkt
  2. mwifiex_11n_dispatch_pkt
  3. mwifiex_11n_dispatch_pkt_until_start_win
  4. mwifiex_11n_scan_and_dispatch
  5. mwifiex_del_rx_reorder_entry
  6. mwifiex_11n_get_rx_reorder_tbl
  7. mwifiex_11n_del_rx_reorder_tbl_by_ta
  8. mwifiex_11n_find_last_seq_num
  9. mwifiex_flush_data
  10. mwifiex_11n_create_rx_reorder_tbl
  11. mwifiex_11n_rxreorder_timer_restart
  12. mwifiex_cmd_11n_addba_req
  13. mwifiex_cmd_11n_addba_rsp_gen
  14. mwifiex_cmd_11n_delba
  15. mwifiex_11n_rx_reorder_pkt
  16. mwifiex_del_ba_tbl
  17. mwifiex_ret_11n_addba_resp
  18. mwifiex_11n_ba_stream_timeout
  19. mwifiex_11n_cleanup_reorder_tbl
  20. mwifiex_update_rxreor_flags
  21. mwifiex_update_ampdu_rxwinsize
  22. mwifiex_coex_ampdu_rxwinsize
  23. mwifiex_11n_rxba_sync_event

   1 /*
   2  * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
   3  *
   4  * Copyright (C) 2011-2014, Marvell International Ltd.
   5  *
   6  * This software file (the "File") is distributed by Marvell International
   7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8  * (the "License").  You may use, redistribute and/or modify this File in
   9  * accordance with the terms and conditions of the License, a copy of which
  10  * is available by writing to the Free Software Foundation, Inc.,
  11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13  *
  14  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17  * this warranty disclaimer.
  18  */
  19 
  20 #include "decl.h"
  21 #include "ioctl.h"
  22 #include "util.h"
  23 #include "fw.h"
  24 #include "main.h"
  25 #include "wmm.h"
  26 #include "11n.h"
  27 #include "11n_rxreorder.h"
  28 
  29 /* This function will dispatch amsdu packet and forward it to kernel/upper
  30  * layer.
  31  */
  32 static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
  33                                           struct sk_buff *skb)
  34 {
  35         struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
  36         int ret;
  37 
  38         if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
  39                 struct sk_buff_head list;
  40                 struct sk_buff *rx_skb;
  41 
  42                 __skb_queue_head_init(&list);
  43 
  44                 skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
  45                 skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
  46 
  47                 ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
  48                                          priv->wdev.iftype, 0, NULL, NULL);
  49 
  50                 while (!skb_queue_empty(&list)) {
  51                         struct rx_packet_hdr *rx_hdr;
  52 
  53                         rx_skb = __skb_dequeue(&list);
  54                         rx_hdr = (struct rx_packet_hdr *)rx_skb->data;
  55                         if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
  56                             ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
  57                                 mwifiex_process_tdls_action_frame(priv,
  58                                                                   (u8 *)rx_hdr,
  59                                                                   skb->len);
  60                         }
  61 
  62                         if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
  63                                 ret = mwifiex_uap_recv_packet(priv, rx_skb);
  64                         else
  65                                 ret = mwifiex_recv_packet(priv, rx_skb);
  66                         if (ret == -1)
  67                                 mwifiex_dbg(priv->adapter, ERROR,
  68                                             "Rx of A-MSDU failed");
  69                 }
  70                 return 0;
  71         }
  72 
  73         return -1;
  74 }
  75 
  76 /* This function will process the rx packet and forward it to kernel/upper
  77  * layer.
  78  */
  79 static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
  80                                     struct sk_buff *payload)
  81 {
  82 
  83         int ret;
  84 
  85         if (!payload) {
  86                 mwifiex_dbg(priv->adapter, INFO, "info: fw drop data\n");
  87                 return 0;
  88         }
  89 
  90         ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
  91         if (!ret)
  92                 return 0;
  93 
  94         if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
  95                 return mwifiex_handle_uap_rx_forward(priv, payload);
  96 
  97         return mwifiex_process_rx_packet(priv, payload);
  98 }
  99 
 100 /*
 101  * This function dispatches all packets in the Rx reorder table until the
 102  * start window.
 103  *
 104  * There could be holes in the buffer, which are skipped by the function.
 105  * Since the buffer is linear, the function uses rotation to simulate
 106  * circular buffer.
 107  */
 108 static void
 109 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
 110                                          struct mwifiex_rx_reorder_tbl *tbl,
 111                                          int start_win)
 112 {
 113         struct sk_buff_head list;
 114         struct sk_buff *skb;
 115         int pkt_to_send, i;
 116 
 117         __skb_queue_head_init(&list);
 118         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 119 
 120         pkt_to_send = (start_win > tbl->start_win) ?
 121                       min((start_win - tbl->start_win), tbl->win_size) :
 122                       tbl->win_size;
 123 
 124         for (i = 0; i < pkt_to_send; ++i) {
 125                 if (tbl->rx_reorder_ptr[i]) {
 126                         skb = tbl->rx_reorder_ptr[i];
 127                         __skb_queue_tail(&list, skb);
 128                         tbl->rx_reorder_ptr[i] = NULL;
 129                 }
 130         }
 131 
 132         /*
 133          * We don't have a circular buffer, hence use rotation to simulate
 134          * circular buffer
 135          */
 136         for (i = 0; i < tbl->win_size - pkt_to_send; ++i) {
 137                 tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i];
 138                 tbl->rx_reorder_ptr[pkt_to_send + i] = NULL;
 139         }
 140 
 141         tbl->start_win = start_win;
 142         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 143 
 144         while ((skb = __skb_dequeue(&list)))
 145                 mwifiex_11n_dispatch_pkt(priv, skb);
 146 }
 147 
 148 /*
 149  * This function dispatches all packets in the Rx reorder table until
 150  * a hole is found.
 151  *
 152  * The start window is adjusted automatically when a hole is located.
 153  * Since the buffer is linear, the function uses rotation to simulate
 154  * circular buffer.
 155  */
 156 static void
 157 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
 158                               struct mwifiex_rx_reorder_tbl *tbl)
 159 {
 160         struct sk_buff_head list;
 161         struct sk_buff *skb;
 162         int i, j, xchg;
 163 
 164         __skb_queue_head_init(&list);
 165         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 166 
 167         for (i = 0; i < tbl->win_size; ++i) {
 168                 if (!tbl->rx_reorder_ptr[i])
 169                         break;
 170                 skb = tbl->rx_reorder_ptr[i];
 171                 __skb_queue_tail(&list, skb);
 172                 tbl->rx_reorder_ptr[i] = NULL;
 173         }
 174 
 175         /*
 176          * We don't have a circular buffer, hence use rotation to simulate
 177          * circular buffer
 178          */
 179         if (i > 0) {
 180                 xchg = tbl->win_size - i;
 181                 for (j = 0; j < xchg; ++j) {
 182                         tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j];
 183                         tbl->rx_reorder_ptr[i + j] = NULL;
 184                 }
 185         }
 186         tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
 187 
 188         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 189 
 190         while ((skb = __skb_dequeue(&list)))
 191                 mwifiex_11n_dispatch_pkt(priv, skb);
 192 }
 193 
 194 /*
 195  * This function deletes the Rx reorder table and frees the memory.
 196  *
 197  * The function stops the associated timer and dispatches all the
 198  * pending packets in the Rx reorder table before deletion.
 199  */
 200 static void
 201 mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
 202                              struct mwifiex_rx_reorder_tbl *tbl)
 203 {
 204         int start_win;
 205 
 206         if (!tbl)
 207                 return;
 208 
 209         spin_lock_bh(&priv->adapter->rx_proc_lock);
 210         priv->adapter->rx_locked = true;
 211         if (priv->adapter->rx_processing) {
 212                 spin_unlock_bh(&priv->adapter->rx_proc_lock);
 213                 flush_workqueue(priv->adapter->rx_workqueue);
 214         } else {
 215                 spin_unlock_bh(&priv->adapter->rx_proc_lock);
 216         }
 217 
 218         start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
 219         mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
 220 
 221         del_timer_sync(&tbl->timer_context.timer);
 222         tbl->timer_context.timer_is_set = false;
 223 
 224         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 225         list_del(&tbl->list);
 226         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 227 
 228         kfree(tbl->rx_reorder_ptr);
 229         kfree(tbl);
 230 
 231         spin_lock_bh(&priv->adapter->rx_proc_lock);
 232         priv->adapter->rx_locked = false;
 233         spin_unlock_bh(&priv->adapter->rx_proc_lock);
 234 
 235 }
 236 
 237 /*
 238  * This function returns the pointer to an entry in Rx reordering
 239  * table which matches the given TA/TID pair.
 240  */
 241 struct mwifiex_rx_reorder_tbl *
 242 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
 243 {
 244         struct mwifiex_rx_reorder_tbl *tbl;
 245 
 246         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 247         list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
 248                 if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
 249                         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 250                         return tbl;
 251                 }
 252         }
 253         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 254 
 255         return NULL;
 256 }
 257 
 258 /* This function retrieves the pointer to an entry in Rx reordering
 259  * table which matches the given TA and deletes it.
 260  */
 261 void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
 262 {
 263         struct mwifiex_rx_reorder_tbl *tbl, *tmp;
 264 
 265         if (!ta)
 266                 return;
 267 
 268         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 269         list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
 270                 if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
 271                         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 272                         mwifiex_del_rx_reorder_entry(priv, tbl);
 273                         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 274                 }
 275         }
 276         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 277 
 278         return;
 279 }
 280 
 281 /*
 282  * This function finds the last sequence number used in the packets
 283  * buffered in Rx reordering table.
 284  */
 285 static int
 286 mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
 287 {
 288         struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
 289         struct mwifiex_private *priv = ctx->priv;
 290         int i;
 291 
 292         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 293         for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
 294                 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
 295                         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 296                         return i;
 297                 }
 298         }
 299         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 300 
 301         return -1;
 302 }
 303 
 304 /*
 305  * This function flushes all the packets in Rx reordering table.
 306  *
 307  * The function checks if any packets are currently buffered in the
 308  * table or not. In case there are packets available, it dispatches
 309  * them and then dumps the Rx reordering table.
 310  */
 311 static void
 312 mwifiex_flush_data(struct timer_list *t)
 313 {
 314         struct reorder_tmr_cnxt *ctx =
 315                 from_timer(ctx, t, timer);
 316         int start_win, seq_num;
 317 
 318         ctx->timer_is_set = false;
 319         seq_num = mwifiex_11n_find_last_seq_num(ctx);
 320 
 321         if (seq_num < 0)
 322                 return;
 323 
 324         mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
 325         start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
 326         mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
 327                                                  start_win);
 328 }
 329 
 330 /*
 331  * This function creates an entry in Rx reordering table for the
 332  * given TA/TID.
 333  *
 334  * The function also initializes the entry with sequence number, window
 335  * size as well as initializes the timer.
 336  *
 337  * If the received TA/TID pair is already present, all the packets are
 338  * dispatched and the window size is moved until the SSN.
 339  */
 340 static void
 341 mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
 342                                   int tid, int win_size, int seq_num)
 343 {
 344         int i;
 345         struct mwifiex_rx_reorder_tbl *tbl, *new_node;
 346         u16 last_seq = 0;
 347         struct mwifiex_sta_node *node;
 348 
 349         /*
 350          * If we get a TID, ta pair which is already present dispatch all the
 351          * the packets and move the window size until the ssn
 352          */
 353         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
 354         if (tbl) {
 355                 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
 356                 return;
 357         }
 358         /* if !tbl then create one */
 359         new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
 360         if (!new_node)
 361                 return;
 362 
 363         INIT_LIST_HEAD(&new_node->list);
 364         new_node->tid = tid;
 365         memcpy(new_node->ta, ta, ETH_ALEN);
 366         new_node->start_win = seq_num;
 367         new_node->init_win = seq_num;
 368         new_node->flags = 0;
 369 
 370         spin_lock_bh(&priv->sta_list_spinlock);
 371         if (mwifiex_queuing_ra_based(priv)) {
 372                 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
 373                         node = mwifiex_get_sta_entry(priv, ta);
 374                         if (node)
 375                                 last_seq = node->rx_seq[tid];
 376                 }
 377         } else {
 378                 node = mwifiex_get_sta_entry(priv, ta);
 379                 if (node)
 380                         last_seq = node->rx_seq[tid];
 381                 else
 382                         last_seq = priv->rx_seq[tid];
 383         }
 384         spin_unlock_bh(&priv->sta_list_spinlock);
 385 
 386         mwifiex_dbg(priv->adapter, INFO,
 387                     "info: last_seq=%d start_win=%d\n",
 388                     last_seq, new_node->start_win);
 389 
 390         if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
 391             last_seq >= new_node->start_win) {
 392                 new_node->start_win = last_seq + 1;
 393                 new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
 394         }
 395 
 396         new_node->win_size = win_size;
 397 
 398         new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *),
 399                                            GFP_KERNEL);
 400         if (!new_node->rx_reorder_ptr) {
 401                 kfree((u8 *) new_node);
 402                 mwifiex_dbg(priv->adapter, ERROR,
 403                             "%s: failed to alloc reorder_ptr\n", __func__);
 404                 return;
 405         }
 406 
 407         new_node->timer_context.ptr = new_node;
 408         new_node->timer_context.priv = priv;
 409         new_node->timer_context.timer_is_set = false;
 410 
 411         timer_setup(&new_node->timer_context.timer, mwifiex_flush_data, 0);
 412 
 413         for (i = 0; i < win_size; ++i)
 414                 new_node->rx_reorder_ptr[i] = NULL;
 415 
 416         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 417         list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
 418         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 419 }
 420 
 421 static void
 422 mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
 423 {
 424         u32 min_flush_time;
 425 
 426         if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
 427                 min_flush_time = MIN_FLUSH_TIMER_15_MS;
 428         else
 429                 min_flush_time = MIN_FLUSH_TIMER_MS;
 430 
 431         mod_timer(&tbl->timer_context.timer,
 432                   jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
 433 
 434         tbl->timer_context.timer_is_set = true;
 435 }
 436 
 437 /*
 438  * This function prepares command for adding a BA request.
 439  *
 440  * Preparation includes -
 441  *      - Setting command ID and proper size
 442  *      - Setting add BA request buffer
 443  *      - Ensuring correct endian-ness
 444  */
 445 int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
 446 {
 447         struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
 448 
 449         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
 450         cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
 451         memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
 452 
 453         return 0;
 454 }
 455 
 456 /*
 457  * This function prepares command for adding a BA response.
 458  *
 459  * Preparation includes -
 460  *      - Setting command ID and proper size
 461  *      - Setting add BA response buffer
 462  *      - Ensuring correct endian-ness
 463  */
 464 int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
 465                                   struct host_cmd_ds_command *cmd,
 466                                   struct host_cmd_ds_11n_addba_req
 467                                   *cmd_addba_req)
 468 {
 469         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
 470         struct mwifiex_sta_node *sta_ptr;
 471         u32 rx_win_size = priv->add_ba_param.rx_win_size;
 472         u8 tid;
 473         int win_size;
 474         uint16_t block_ack_param_set;
 475 
 476         if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
 477             ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
 478             priv->adapter->is_hw_11ac_capable &&
 479             memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
 480                 spin_lock_bh(&priv->sta_list_spinlock);
 481                 sta_ptr = mwifiex_get_sta_entry(priv,
 482                                                 cmd_addba_req->peer_mac_addr);
 483                 if (!sta_ptr) {
 484                         spin_unlock_bh(&priv->sta_list_spinlock);
 485                         mwifiex_dbg(priv->adapter, ERROR,
 486                                     "BA setup with unknown TDLS peer %pM!\n",
 487                                     cmd_addba_req->peer_mac_addr);
 488                         return -1;
 489                 }
 490                 if (sta_ptr->is_11ac_enabled)
 491                         rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
 492                 spin_unlock_bh(&priv->sta_list_spinlock);
 493         }
 494 
 495         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
 496         cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
 497 
 498         memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
 499                ETH_ALEN);
 500         add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
 501         add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
 502         add_ba_rsp->ssn = cmd_addba_req->ssn;
 503 
 504         block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
 505         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
 506                 >> BLOCKACKPARAM_TID_POS;
 507         add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
 508         block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
 509 
 510         /* If we don't support AMSDU inside AMPDU, reset the bit */
 511         if (!priv->add_ba_param.rx_amsdu ||
 512             (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
 513                 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
 514         block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
 515         add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
 516         win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
 517                                         & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
 518                                         >> BLOCKACKPARAM_WINSIZE_POS;
 519         cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
 520 
 521         mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
 522                                           tid, win_size,
 523                                           le16_to_cpu(cmd_addba_req->ssn));
 524         return 0;
 525 }
 526 
 527 /*
 528  * This function prepares command for deleting a BA request.
 529  *
 530  * Preparation includes -
 531  *      - Setting command ID and proper size
 532  *      - Setting del BA request buffer
 533  *      - Ensuring correct endian-ness
 534  */
 535 int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
 536 {
 537         struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
 538 
 539         cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
 540         cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
 541         memcpy(del_ba, data_buf, sizeof(*del_ba));
 542 
 543         return 0;
 544 }
 545 
 546 /*
 547  * This function identifies if Rx reordering is needed for a received packet.
 548  *
 549  * In case reordering is required, the function will do the reordering
 550  * before sending it to kernel.
 551  *
 552  * The Rx reorder table is checked first with the received TID/TA pair. If
 553  * not found, the received packet is dispatched immediately. But if found,
 554  * the packet is reordered and all the packets in the updated Rx reordering
 555  * table is dispatched until a hole is found.
 556  *
 557  * For sequence number less than the starting window, the packet is dropped.
 558  */
 559 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
 560                                 u16 seq_num, u16 tid,
 561                                 u8 *ta, u8 pkt_type, void *payload)
 562 {
 563         struct mwifiex_rx_reorder_tbl *tbl;
 564         int prev_start_win, start_win, end_win, win_size;
 565         u16 pkt_index;
 566         bool init_window_shift = false;
 567         int ret = 0;
 568 
 569         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
 570         if (!tbl) {
 571                 if (pkt_type != PKT_TYPE_BAR)
 572                         mwifiex_11n_dispatch_pkt(priv, payload);
 573                 return ret;
 574         }
 575 
 576         if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
 577                 mwifiex_11n_dispatch_pkt(priv, payload);
 578                 return ret;
 579         }
 580 
 581         start_win = tbl->start_win;
 582         prev_start_win = start_win;
 583         win_size = tbl->win_size;
 584         end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
 585         if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
 586                 init_window_shift = true;
 587                 tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
 588         }
 589 
 590         if (tbl->flags & RXREOR_FORCE_NO_DROP) {
 591                 mwifiex_dbg(priv->adapter, INFO,
 592                             "RXREOR_FORCE_NO_DROP when HS is activated\n");
 593                 tbl->flags &= ~RXREOR_FORCE_NO_DROP;
 594         } else if (init_window_shift && seq_num < start_win &&
 595                    seq_num >= tbl->init_win) {
 596                 mwifiex_dbg(priv->adapter, INFO,
 597                             "Sender TID sequence number reset %d->%d for SSN %d\n",
 598                             start_win, seq_num, tbl->init_win);
 599                 tbl->start_win = start_win = seq_num;
 600                 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
 601         } else {
 602                 /*
 603                  * If seq_num is less then starting win then ignore and drop
 604                  * the packet
 605                  */
 606                 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
 607                         if (seq_num >= ((start_win + TWOPOW11) &
 608                                         (MAX_TID_VALUE - 1)) &&
 609                             seq_num < start_win) {
 610                                 ret = -1;
 611                                 goto done;
 612                         }
 613                 } else if ((seq_num < start_win) ||
 614                            (seq_num >= (start_win + TWOPOW11))) {
 615                         ret = -1;
 616                         goto done;
 617                 }
 618         }
 619 
 620         /*
 621          * If this packet is a BAR we adjust seq_num as
 622          * WinStart = seq_num
 623          */
 624         if (pkt_type == PKT_TYPE_BAR)
 625                 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
 626 
 627         if (((end_win < start_win) &&
 628              (seq_num < start_win) && (seq_num > end_win)) ||
 629             ((end_win > start_win) && ((seq_num > end_win) ||
 630                                        (seq_num < start_win)))) {
 631                 end_win = seq_num;
 632                 if (((end_win - win_size) + 1) >= 0)
 633                         start_win = (end_win - win_size) + 1;
 634                 else
 635                         start_win = (MAX_TID_VALUE - (win_size - end_win)) + 1;
 636                 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
 637         }
 638 
 639         if (pkt_type != PKT_TYPE_BAR) {
 640                 if (seq_num >= start_win)
 641                         pkt_index = seq_num - start_win;
 642                 else
 643                         pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
 644 
 645                 if (tbl->rx_reorder_ptr[pkt_index]) {
 646                         ret = -1;
 647                         goto done;
 648                 }
 649 
 650                 tbl->rx_reorder_ptr[pkt_index] = payload;
 651         }
 652 
 653         /*
 654          * Dispatch all packets sequentially from start_win until a
 655          * hole is found and adjust the start_win appropriately
 656          */
 657         mwifiex_11n_scan_and_dispatch(priv, tbl);
 658 
 659 done:
 660         if (!tbl->timer_context.timer_is_set ||
 661             prev_start_win != tbl->start_win)
 662                 mwifiex_11n_rxreorder_timer_restart(tbl);
 663         return ret;
 664 }
 665 
 666 /*
 667  * This function deletes an entry for a given TID/TA pair.
 668  *
 669  * The TID/TA are taken from del BA event body.
 670  */
 671 void
 672 mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
 673                    u8 type, int initiator)
 674 {
 675         struct mwifiex_rx_reorder_tbl *tbl;
 676         struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
 677         struct mwifiex_ra_list_tbl *ra_list;
 678         u8 cleanup_rx_reorder_tbl;
 679         int tid_down;
 680 
 681         if (type == TYPE_DELBA_RECEIVE)
 682                 cleanup_rx_reorder_tbl = (initiator) ? true : false;
 683         else
 684                 cleanup_rx_reorder_tbl = (initiator) ? false : true;
 685 
 686         mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
 687                     peer_mac, tid, initiator);
 688 
 689         if (cleanup_rx_reorder_tbl) {
 690                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
 691                                                                  peer_mac);
 692                 if (!tbl) {
 693                         mwifiex_dbg(priv->adapter, EVENT,
 694                                     "event: TID, TA not found in table\n");
 695                         return;
 696                 }
 697                 mwifiex_del_rx_reorder_entry(priv, tbl);
 698         } else {
 699                 ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
 700                 if (!ptx_tbl) {
 701                         mwifiex_dbg(priv->adapter, EVENT,
 702                                     "event: TID, RA not found in table\n");
 703                         return;
 704                 }
 705 
 706                 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
 707                 ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
 708                 if (ra_list) {
 709                         ra_list->amsdu_in_ampdu = false;
 710                         ra_list->ba_status = BA_SETUP_NONE;
 711                 }
 712                 spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
 713                 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
 714                 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
 715         }
 716 }
 717 
 718 /*
 719  * This function handles the command response of an add BA response.
 720  *
 721  * Handling includes changing the header fields into CPU format and
 722  * creating the stream, provided the add BA is accepted.
 723  */
 724 int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
 725                                struct host_cmd_ds_command *resp)
 726 {
 727         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
 728         int tid, win_size;
 729         struct mwifiex_rx_reorder_tbl *tbl;
 730         uint16_t block_ack_param_set;
 731 
 732         block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
 733 
 734         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
 735                 >> BLOCKACKPARAM_TID_POS;
 736         /*
 737          * Check if we had rejected the ADDBA, if yes then do not create
 738          * the stream
 739          */
 740         if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
 741                 mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
 742                             add_ba_rsp->peer_mac_addr, tid);
 743 
 744                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
 745                                                      add_ba_rsp->peer_mac_addr);
 746                 if (tbl)
 747                         mwifiex_del_rx_reorder_entry(priv, tbl);
 748 
 749                 return 0;
 750         }
 751 
 752         win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
 753                     >> BLOCKACKPARAM_WINSIZE_POS;
 754 
 755         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
 756                                              add_ba_rsp->peer_mac_addr);
 757         if (tbl) {
 758                 if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
 759                     priv->add_ba_param.rx_amsdu &&
 760                     (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
 761                         tbl->amsdu = true;
 762                 else
 763                         tbl->amsdu = false;
 764         }
 765 
 766         mwifiex_dbg(priv->adapter, CMD,
 767                     "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
 768                 add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
 769 
 770         return 0;
 771 }
 772 
 773 /*
 774  * This function handles BA stream timeout event by preparing and sending
 775  * a command to the firmware.
 776  */
 777 void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
 778                                    struct host_cmd_ds_11n_batimeout *event)
 779 {
 780         struct host_cmd_ds_11n_delba delba;
 781 
 782         memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
 783         memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
 784 
 785         delba.del_ba_param_set |=
 786                 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
 787         delba.del_ba_param_set |= cpu_to_le16(
 788                 (u16) event->origninator << DELBA_INITIATOR_POS);
 789         delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
 790         mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
 791 }
 792 
 793 /*
 794  * This function cleans up the Rx reorder table by deleting all the entries
 795  * and re-initializing.
 796  */
 797 void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
 798 {
 799         struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
 800 
 801         spin_lock_bh(&priv->rx_reorder_tbl_lock);
 802         list_for_each_entry_safe(del_tbl_ptr, tmp_node,
 803                                  &priv->rx_reorder_tbl_ptr, list) {
 804                 spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 805                 mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
 806                 spin_lock_bh(&priv->rx_reorder_tbl_lock);
 807         }
 808         INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
 809         spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 810 
 811         mwifiex_reset_11n_rx_seq_num(priv);
 812 }
 813 
 814 /*
 815  * This function updates all rx_reorder_tbl's flags.
 816  */
 817 void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
 818 {
 819         struct mwifiex_private *priv;
 820         struct mwifiex_rx_reorder_tbl *tbl;
 821         int i;
 822 
 823         for (i = 0; i < adapter->priv_num; i++) {
 824                 priv = adapter->priv[i];
 825                 if (!priv)
 826                         continue;
 827 
 828                 spin_lock_bh(&priv->rx_reorder_tbl_lock);
 829                 list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
 830                         tbl->flags = flags;
 831                 spin_unlock_bh(&priv->rx_reorder_tbl_lock);
 832         }
 833 
 834         return;
 835 }
 836 
 837 /* This function update all the rx_win_size based on coex flag
 838  */
 839 static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
 840                                            bool coex_flag)
 841 {
 842         u8 i;
 843         u32 rx_win_size;
 844         struct mwifiex_private *priv;
 845 
 846         dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
 847 
 848         for (i = 0; i < adapter->priv_num; i++) {
 849                 if (!adapter->priv[i])
 850                         continue;
 851                 priv = adapter->priv[i];
 852                 rx_win_size = priv->add_ba_param.rx_win_size;
 853                 if (coex_flag) {
 854                         if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
 855                                 priv->add_ba_param.rx_win_size =
 856                                         MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
 857                         if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
 858                                 priv->add_ba_param.rx_win_size =
 859                                         MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
 860                         if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
 861                                 priv->add_ba_param.rx_win_size =
 862                                         MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
 863                 } else {
 864                         if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
 865                                 priv->add_ba_param.rx_win_size =
 866                                         MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
 867                         if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
 868                                 priv->add_ba_param.rx_win_size =
 869                                         MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
 870                         if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
 871                                 priv->add_ba_param.rx_win_size =
 872                                         MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
 873                 }
 874 
 875                 if (adapter->coex_win_size && adapter->coex_rx_win_size)
 876                         priv->add_ba_param.rx_win_size =
 877                                         adapter->coex_rx_win_size;
 878 
 879                 if (rx_win_size != priv->add_ba_param.rx_win_size) {
 880                         if (!priv->media_connected)
 881                                 continue;
 882                         for (i = 0; i < MAX_NUM_TID; i++)
 883                                 mwifiex_11n_delba(priv, i);
 884                 }
 885         }
 886 }
 887 
 888 /* This function check coex for RX BA
 889  */
 890 void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
 891 {
 892         u8 i;
 893         struct mwifiex_private *priv;
 894         u8 count = 0;
 895 
 896         for (i = 0; i < adapter->priv_num; i++) {
 897                 if (adapter->priv[i]) {
 898                         priv = adapter->priv[i];
 899                         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
 900                                 if (priv->media_connected)
 901                                         count++;
 902                         }
 903                         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
 904                                 if (priv->bss_started)
 905                                         count++;
 906                         }
 907                 }
 908                 if (count >= MWIFIEX_BSS_COEX_COUNT)
 909                         break;
 910         }
 911         if (count >= MWIFIEX_BSS_COEX_COUNT)
 912                 mwifiex_update_ampdu_rxwinsize(adapter, true);
 913         else
 914                 mwifiex_update_ampdu_rxwinsize(adapter, false);
 915 }
 916 
 917 /* This function handles rxba_sync event
 918  */
 919 void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
 920                                  u8 *event_buf, u16 len)
 921 {
 922         struct mwifiex_ie_types_rxba_sync *tlv_rxba = (void *)event_buf;
 923         u16 tlv_type, tlv_len;
 924         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
 925         u8 i, j;
 926         u16 seq_num, tlv_seq_num, tlv_bitmap_len;
 927         int tlv_buf_left = len;
 928         int ret;
 929         u8 *tmp;
 930 
 931         mwifiex_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:",
 932                          event_buf, len);
 933         while (tlv_buf_left >= sizeof(*tlv_rxba)) {
 934                 tlv_type = le16_to_cpu(tlv_rxba->header.type);
 935                 tlv_len  = le16_to_cpu(tlv_rxba->header.len);
 936                 if (tlv_type != TLV_TYPE_RXBA_SYNC) {
 937                         mwifiex_dbg(priv->adapter, ERROR,
 938                                     "Wrong TLV id=0x%x\n", tlv_type);
 939                         return;
 940                 }
 941 
 942                 tlv_seq_num = le16_to_cpu(tlv_rxba->seq_num);
 943                 tlv_bitmap_len = le16_to_cpu(tlv_rxba->bitmap_len);
 944                 mwifiex_dbg(priv->adapter, INFO,
 945                             "%pM tid=%d seq_num=%d bitmap_len=%d\n",
 946                             tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
 947                             tlv_bitmap_len);
 948 
 949                 rx_reor_tbl_ptr =
 950                         mwifiex_11n_get_rx_reorder_tbl(priv, tlv_rxba->tid,
 951                                                        tlv_rxba->mac);
 952                 if (!rx_reor_tbl_ptr) {
 953                         mwifiex_dbg(priv->adapter, ERROR,
 954                                     "Can not find rx_reorder_tbl!");
 955                         return;
 956                 }
 957 
 958                 for (i = 0; i < tlv_bitmap_len; i++) {
 959                         for (j = 0 ; j < 8; j++) {
 960                                 if (tlv_rxba->bitmap[i] & (1 << j)) {
 961                                         seq_num = (MAX_TID_VALUE - 1) &
 962                                                 (tlv_seq_num + i * 8 + j);
 963 
 964                                         mwifiex_dbg(priv->adapter, ERROR,
 965                                                     "drop packet,seq=%d\n",
 966                                                     seq_num);
 967 
 968                                         ret = mwifiex_11n_rx_reorder_pkt
 969                                         (priv, seq_num, tlv_rxba->tid,
 970                                          tlv_rxba->mac, 0, NULL);
 971 
 972                                         if (ret)
 973                                                 mwifiex_dbg(priv->adapter,
 974                                                             ERROR,
 975                                                             "Fail to drop packet");
 976                                 }
 977                         }
 978                 }
 979 
 980                 tlv_buf_left -= (sizeof(*tlv_rxba) + tlv_len);
 981                 tmp = (u8 *)tlv_rxba + tlv_len + sizeof(*tlv_rxba);
 982                 tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp;
 983         }
 984 }

/* [<][>][^][v][top][bottom][index][help] */