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