1/* 2 * Marvell Wireless LAN device driver: 802.11n RX Re-ordering 3 * 4 * Copyright (C) 2011, 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/* 30 * This function dispatches all packets in the Rx reorder table until the 31 * start window. 32 * 33 * There could be holes in the buffer, which are skipped by the function. 34 * Since the buffer is linear, the function uses rotation to simulate 35 * circular buffer. 36 */ 37static void 38mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, 39 struct mwifiex_rx_reorder_tbl *tbl, int start_win) 40{ 41 int pkt_to_send, i; 42 void *rx_tmp_ptr; 43 unsigned long flags; 44 45 pkt_to_send = (start_win > tbl->start_win) ? 46 min((start_win - tbl->start_win), tbl->win_size) : 47 tbl->win_size; 48 49 for (i = 0; i < pkt_to_send; ++i) { 50 spin_lock_irqsave(&priv->rx_pkt_lock, flags); 51 rx_tmp_ptr = NULL; 52 if (tbl->rx_reorder_ptr[i]) { 53 rx_tmp_ptr = tbl->rx_reorder_ptr[i]; 54 tbl->rx_reorder_ptr[i] = NULL; 55 } 56 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 57 if (rx_tmp_ptr) 58 mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); 59 } 60 61 spin_lock_irqsave(&priv->rx_pkt_lock, flags); 62 /* 63 * We don't have a circular buffer, hence use rotation to simulate 64 * circular buffer 65 */ 66 for (i = 0; i < tbl->win_size - pkt_to_send; ++i) { 67 tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i]; 68 tbl->rx_reorder_ptr[pkt_to_send + i] = NULL; 69 } 70 71 tbl->start_win = start_win; 72 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 73} 74 75/* 76 * This function dispatches all packets in the Rx reorder table until 77 * a hole is found. 78 * 79 * The start window is adjusted automatically when a hole is located. 80 * Since the buffer is linear, the function uses rotation to simulate 81 * circular buffer. 82 */ 83static void 84mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, 85 struct mwifiex_rx_reorder_tbl *tbl) 86{ 87 int i, j, xchg; 88 void *rx_tmp_ptr; 89 unsigned long flags; 90 91 for (i = 0; i < tbl->win_size; ++i) { 92 spin_lock_irqsave(&priv->rx_pkt_lock, flags); 93 if (!tbl->rx_reorder_ptr[i]) { 94 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 95 break; 96 } 97 rx_tmp_ptr = tbl->rx_reorder_ptr[i]; 98 tbl->rx_reorder_ptr[i] = NULL; 99 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 100 mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); 101 } 102 103 spin_lock_irqsave(&priv->rx_pkt_lock, flags); 104 /* 105 * We don't have a circular buffer, hence use rotation to simulate 106 * circular buffer 107 */ 108 if (i > 0) { 109 xchg = tbl->win_size - i; 110 for (j = 0; j < xchg; ++j) { 111 tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j]; 112 tbl->rx_reorder_ptr[i + j] = NULL; 113 } 114 } 115 tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1); 116 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 117} 118 119/* 120 * This function deletes the Rx reorder table and frees the memory. 121 * 122 * The function stops the associated timer and dispatches all the 123 * pending packets in the Rx reorder table before deletion. 124 */ 125static void 126mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, 127 struct mwifiex_rx_reorder_tbl *tbl) 128{ 129 unsigned long flags; 130 131 if (!tbl) 132 return; 133 134 mwifiex_11n_dispatch_pkt(priv, tbl, (tbl->start_win + tbl->win_size) & 135 (MAX_TID_VALUE - 1)); 136 137 del_timer(&tbl->timer_context.timer); 138 139 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 140 list_del(&tbl->list); 141 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 142 143 kfree(tbl->rx_reorder_ptr); 144 kfree(tbl); 145} 146 147/* 148 * This function returns the pointer to an entry in Rx reordering 149 * table which matches the given TA/TID pair. 150 */ 151static struct mwifiex_rx_reorder_tbl * 152mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) 153{ 154 struct mwifiex_rx_reorder_tbl *tbl; 155 unsigned long flags; 156 157 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 158 list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) { 159 if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) { 160 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, 161 flags); 162 return tbl; 163 } 164 } 165 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 166 167 return NULL; 168} 169 170/* 171 * This function finds the last sequence number used in the packets 172 * buffered in Rx reordering table. 173 */ 174static int 175mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) 176{ 177 int i; 178 179 for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) 180 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 181 return i; 182 183 return -1; 184} 185 186/* 187 * This function flushes all the packets in Rx reordering table. 188 * 189 * The function checks if any packets are currently buffered in the 190 * table or not. In case there are packets available, it dispatches 191 * them and then dumps the Rx reordering table. 192 */ 193static void 194mwifiex_flush_data(unsigned long context) 195{ 196 struct reorder_tmr_cnxt *ctx = 197 (struct reorder_tmr_cnxt *) context; 198 int start_win; 199 200 start_win = mwifiex_11n_find_last_seq_num(ctx->ptr); 201 202 if (start_win < 0) 203 return; 204 205 dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", start_win); 206 mwifiex_11n_dispatch_pkt(ctx->priv, ctx->ptr, 207 (ctx->ptr->start_win + start_win + 1) & 208 (MAX_TID_VALUE - 1)); 209} 210 211/* 212 * This function creates an entry in Rx reordering table for the 213 * given TA/TID. 214 * 215 * The function also initializes the entry with sequence number, window 216 * size as well as initializes the timer. 217 * 218 * If the received TA/TID pair is already present, all the packets are 219 * dispatched and the window size is moved until the SSN. 220 */ 221static void 222mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, 223 int tid, int win_size, int seq_num) 224{ 225 int i; 226 struct mwifiex_rx_reorder_tbl *tbl, *new_node; 227 u16 last_seq = 0; 228 unsigned long flags; 229 230 /* 231 * If we get a TID, ta pair which is already present dispatch all the 232 * the packets and move the window size until the ssn 233 */ 234 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); 235 if (tbl) { 236 mwifiex_11n_dispatch_pkt(priv, tbl, seq_num); 237 return; 238 } 239 /* if !tbl then create one */ 240 new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); 241 if (!new_node) { 242 dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", 243 __func__); 244 return; 245 } 246 247 INIT_LIST_HEAD(&new_node->list); 248 new_node->tid = tid; 249 memcpy(new_node->ta, ta, ETH_ALEN); 250 new_node->start_win = seq_num; 251 if (mwifiex_queuing_ra_based(priv)) 252 /* TODO for adhoc */ 253 dev_dbg(priv->adapter->dev, 254 "info: ADHOC:last_seq=%d start_win=%d\n", 255 last_seq, new_node->start_win); 256 else 257 last_seq = priv->rx_seq[tid]; 258 259 if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && 260 last_seq >= new_node->start_win) 261 new_node->start_win = last_seq + 1; 262 263 new_node->win_size = win_size; 264 265 new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, 266 GFP_KERNEL); 267 if (!new_node->rx_reorder_ptr) { 268 kfree((u8 *) new_node); 269 dev_err(priv->adapter->dev, 270 "%s: failed to alloc reorder_ptr\n", __func__); 271 return; 272 } 273 274 new_node->timer_context.ptr = new_node; 275 new_node->timer_context.priv = priv; 276 277 init_timer(&new_node->timer_context.timer); 278 new_node->timer_context.timer.function = mwifiex_flush_data; 279 new_node->timer_context.timer.data = 280 (unsigned long) &new_node->timer_context; 281 282 for (i = 0; i < win_size; ++i) 283 new_node->rx_reorder_ptr[i] = NULL; 284 285 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 286 list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); 287 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 288} 289 290/* 291 * This function prepares command for adding a BA request. 292 * 293 * Preparation includes - 294 * - Setting command ID and proper size 295 * - Setting add BA request buffer 296 * - Ensuring correct endian-ness 297 */ 298int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) 299{ 300 struct host_cmd_ds_11n_addba_req *add_ba_req = 301 (struct host_cmd_ds_11n_addba_req *) 302 &cmd->params.add_ba_req; 303 304 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); 305 cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); 306 memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); 307 308 return 0; 309} 310 311/* 312 * This function prepares command for adding a BA response. 313 * 314 * Preparation includes - 315 * - Setting command ID and proper size 316 * - Setting add BA response buffer 317 * - Ensuring correct endian-ness 318 */ 319int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, 320 struct host_cmd_ds_command *cmd, 321 struct host_cmd_ds_11n_addba_req 322 *cmd_addba_req) 323{ 324 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 325 (struct host_cmd_ds_11n_addba_rsp *) 326 &cmd->params.add_ba_rsp; 327 u8 tid; 328 int win_size; 329 uint16_t block_ack_param_set; 330 331 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); 332 cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); 333 334 memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, 335 ETH_ALEN); 336 add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; 337 add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; 338 add_ba_rsp->ssn = cmd_addba_req->ssn; 339 340 block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); 341 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 342 >> BLOCKACKPARAM_TID_POS; 343 add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); 344 block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; 345 /* We donot support AMSDU inside AMPDU, hence reset the bit */ 346 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; 347 block_ack_param_set |= (priv->add_ba_param.rx_win_size << 348 BLOCKACKPARAM_WINSIZE_POS); 349 add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); 350 win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) 351 & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) 352 >> BLOCKACKPARAM_WINSIZE_POS; 353 cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); 354 355 mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, 356 tid, win_size, 357 le16_to_cpu(cmd_addba_req->ssn)); 358 return 0; 359} 360 361/* 362 * This function prepares command for deleting a BA request. 363 * 364 * Preparation includes - 365 * - Setting command ID and proper size 366 * - Setting del BA request buffer 367 * - Ensuring correct endian-ness 368 */ 369int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) 370{ 371 struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) 372 &cmd->params.del_ba; 373 374 cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); 375 cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); 376 memcpy(del_ba, data_buf, sizeof(*del_ba)); 377 378 return 0; 379} 380 381/* 382 * This function identifies if Rx reordering is needed for a received packet. 383 * 384 * In case reordering is required, the function will do the reordering 385 * before sending it to kernel. 386 * 387 * The Rx reorder table is checked first with the received TID/TA pair. If 388 * not found, the received packet is dispatched immediately. But if found, 389 * the packet is reordered and all the packets in the updated Rx reordering 390 * table is dispatched until a hole is found. 391 * 392 * For sequence number less than the starting window, the packet is dropped. 393 */ 394int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, 395 u16 seq_num, u16 tid, 396 u8 *ta, u8 pkt_type, void *payload) 397{ 398 struct mwifiex_rx_reorder_tbl *tbl; 399 int start_win, end_win, win_size; 400 u16 pkt_index; 401 402 tbl = mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, 403 tid, ta); 404 if (!tbl) { 405 if (pkt_type != PKT_TYPE_BAR) 406 mwifiex_process_rx_packet(priv->adapter, payload); 407 return 0; 408 } 409 start_win = tbl->start_win; 410 win_size = tbl->win_size; 411 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); 412 del_timer(&tbl->timer_context.timer); 413 mod_timer(&tbl->timer_context.timer, 414 jiffies + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); 415 416 /* 417 * If seq_num is less then starting win then ignore and drop the 418 * packet 419 */ 420 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ 421 if (seq_num >= ((start_win + TWOPOW11) & 422 (MAX_TID_VALUE - 1)) && (seq_num < start_win)) 423 return -1; 424 } else if ((seq_num < start_win) || 425 (seq_num > (start_win + TWOPOW11))) { 426 return -1; 427 } 428 429 /* 430 * If this packet is a BAR we adjust seq_num as 431 * WinStart = seq_num 432 */ 433 if (pkt_type == PKT_TYPE_BAR) 434 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); 435 436 if (((end_win < start_win) && 437 (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) && 438 (seq_num > end_win)) || 439 ((end_win > start_win) && ((seq_num > end_win) || 440 (seq_num < start_win)))) { 441 end_win = seq_num; 442 if (((seq_num - win_size) + 1) >= 0) 443 start_win = (end_win - win_size) + 1; 444 else 445 start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; 446 mwifiex_11n_dispatch_pkt(priv, tbl, start_win); 447 } 448 449 if (pkt_type != PKT_TYPE_BAR) { 450 if (seq_num >= start_win) 451 pkt_index = seq_num - start_win; 452 else 453 pkt_index = (seq_num+MAX_TID_VALUE) - start_win; 454 455 if (tbl->rx_reorder_ptr[pkt_index]) 456 return -1; 457 458 tbl->rx_reorder_ptr[pkt_index] = payload; 459 } 460 461 /* 462 * Dispatch all packets sequentially from start_win until a 463 * hole is found and adjust the start_win appropriately 464 */ 465 mwifiex_11n_scan_and_dispatch(priv, tbl); 466 467 return 0; 468} 469 470/* 471 * This function deletes an entry for a given TID/TA pair. 472 * 473 * The TID/TA are taken from del BA event body. 474 */ 475void 476mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, 477 u8 type, int initiator) 478{ 479 struct mwifiex_rx_reorder_tbl *tbl; 480 struct mwifiex_tx_ba_stream_tbl *ptx_tbl; 481 u8 cleanup_rx_reorder_tbl; 482 unsigned long flags; 483 484 if (type == TYPE_DELBA_RECEIVE) 485 cleanup_rx_reorder_tbl = (initiator) ? true : false; 486 else 487 cleanup_rx_reorder_tbl = (initiator) ? false : true; 488 489 dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d initiator=%d\n", 490 peer_mac, tid, initiator); 491 492 if (cleanup_rx_reorder_tbl) { 493 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, 494 peer_mac); 495 if (!tbl) { 496 dev_dbg(priv->adapter->dev, 497 "event: TID, TA not found in table\n"); 498 return; 499 } 500 mwifiex_del_rx_reorder_entry(priv, tbl); 501 } else { 502 ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac); 503 if (!ptx_tbl) { 504 dev_dbg(priv->adapter->dev, 505 "event: TID, RA not found in table\n"); 506 return; 507 } 508 509 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 510 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); 511 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 512 } 513} 514 515/* 516 * This function handles the command response of an add BA response. 517 * 518 * Handling includes changing the header fields into CPU format and 519 * creating the stream, provided the add BA is accepted. 520 */ 521int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, 522 struct host_cmd_ds_command *resp) 523{ 524 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 525 (struct host_cmd_ds_11n_addba_rsp *) 526 &resp->params.add_ba_rsp; 527 int tid, win_size; 528 struct mwifiex_rx_reorder_tbl *tbl; 529 uint16_t block_ack_param_set; 530 531 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); 532 533 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 534 >> BLOCKACKPARAM_TID_POS; 535 /* 536 * Check if we had rejected the ADDBA, if yes then do not create 537 * the stream 538 */ 539 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { 540 win_size = (block_ack_param_set & 541 IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) 542 >> BLOCKACKPARAM_WINSIZE_POS; 543 544 dev_dbg(priv->adapter->dev, 545 "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n", 546 add_ba_rsp->peer_mac_addr, tid, 547 add_ba_rsp->ssn, win_size); 548 } else { 549 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", 550 add_ba_rsp->peer_mac_addr, tid); 551 552 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, 553 add_ba_rsp->peer_mac_addr); 554 if (tbl) 555 mwifiex_del_rx_reorder_entry(priv, tbl); 556 } 557 558 return 0; 559} 560 561/* 562 * This function handles BA stream timeout event by preparing and sending 563 * a command to the firmware. 564 */ 565void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, 566 struct host_cmd_ds_11n_batimeout *event) 567{ 568 struct host_cmd_ds_11n_delba delba; 569 570 memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); 571 memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); 572 573 delba.del_ba_param_set |= 574 cpu_to_le16((u16) event->tid << DELBA_TID_POS); 575 delba.del_ba_param_set |= cpu_to_le16( 576 (u16) event->origninator << DELBA_INITIATOR_POS); 577 delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); 578 mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); 579} 580 581/* 582 * This function cleans up the Rx reorder table by deleting all the entries 583 * and re-initializing. 584 */ 585void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) 586{ 587 struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; 588 unsigned long flags; 589 590 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 591 list_for_each_entry_safe(del_tbl_ptr, tmp_node, 592 &priv->rx_reorder_tbl_ptr, list) { 593 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 594 mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr); 595 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 596 } 597 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 598 599 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); 600 mwifiex_reset_11n_rx_seq_num(priv); 601} 602