1828c91f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25e6e3a92SBing Zhao /*
3932183aaSGanapathi Bhat * NXP Wireless LAN device driver: 802.11n RX Re-ordering
45e6e3a92SBing Zhao *
5932183aaSGanapathi Bhat * Copyright 2011-2020 NXP
65e6e3a92SBing Zhao */
75e6e3a92SBing Zhao
85e6e3a92SBing Zhao #include "decl.h"
95e6e3a92SBing Zhao #include "ioctl.h"
105e6e3a92SBing Zhao #include "util.h"
115e6e3a92SBing Zhao #include "fw.h"
125e6e3a92SBing Zhao #include "main.h"
135e6e3a92SBing Zhao #include "wmm.h"
145e6e3a92SBing Zhao #include "11n.h"
155e6e3a92SBing Zhao #include "11n_rxreorder.h"
165e6e3a92SBing Zhao
174c9f9fb2SAmitkumar Karwar /* This function will dispatch amsdu packet and forward it to kernel/upper
184c9f9fb2SAmitkumar Karwar * layer.
194c9f9fb2SAmitkumar Karwar */
mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private * priv,struct sk_buff * skb)204c9f9fb2SAmitkumar Karwar static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
214c9f9fb2SAmitkumar Karwar struct sk_buff *skb)
224c9f9fb2SAmitkumar Karwar {
234c9f9fb2SAmitkumar Karwar struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
244c9f9fb2SAmitkumar Karwar int ret;
254c9f9fb2SAmitkumar Karwar
264c9f9fb2SAmitkumar Karwar if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
274c9f9fb2SAmitkumar Karwar struct sk_buff_head list;
284c9f9fb2SAmitkumar Karwar struct sk_buff *rx_skb;
294c9f9fb2SAmitkumar Karwar
304c9f9fb2SAmitkumar Karwar __skb_queue_head_init(&list);
314c9f9fb2SAmitkumar Karwar
324c9f9fb2SAmitkumar Karwar skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
334c9f9fb2SAmitkumar Karwar skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
344c9f9fb2SAmitkumar Karwar
354c9f9fb2SAmitkumar Karwar ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
36986e43b1SFelix Fietkau priv->wdev.iftype, 0, NULL, NULL, false);
374c9f9fb2SAmitkumar Karwar
384c9f9fb2SAmitkumar Karwar while (!skb_queue_empty(&list)) {
39776f7420SAmitkumar Karwar struct rx_packet_hdr *rx_hdr;
40776f7420SAmitkumar Karwar
414c9f9fb2SAmitkumar Karwar rx_skb = __skb_dequeue(&list);
42776f7420SAmitkumar Karwar rx_hdr = (struct rx_packet_hdr *)rx_skb->data;
43776f7420SAmitkumar Karwar if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
44776f7420SAmitkumar Karwar ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
45776f7420SAmitkumar Karwar mwifiex_process_tdls_action_frame(priv,
46776f7420SAmitkumar Karwar (u8 *)rx_hdr,
47776f7420SAmitkumar Karwar skb->len);
48776f7420SAmitkumar Karwar }
49776f7420SAmitkumar Karwar
50bf00dc22SXinming Hu if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
51bf00dc22SXinming Hu ret = mwifiex_uap_recv_packet(priv, rx_skb);
52bf00dc22SXinming Hu else
534c9f9fb2SAmitkumar Karwar ret = mwifiex_recv_packet(priv, rx_skb);
544c9f9fb2SAmitkumar Karwar if (ret == -1)
55acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, ERROR,
564c9f9fb2SAmitkumar Karwar "Rx of A-MSDU failed");
574c9f9fb2SAmitkumar Karwar }
584c9f9fb2SAmitkumar Karwar return 0;
594c9f9fb2SAmitkumar Karwar }
604c9f9fb2SAmitkumar Karwar
614c9f9fb2SAmitkumar Karwar return -1;
624c9f9fb2SAmitkumar Karwar }
634c9f9fb2SAmitkumar Karwar
645e6e43ebSAmitkumar Karwar /* This function will process the rx packet and forward it to kernel/upper
655e6e43ebSAmitkumar Karwar * layer.
665e6e43ebSAmitkumar Karwar */
mwifiex_11n_dispatch_pkt(struct mwifiex_private * priv,struct sk_buff * payload)67ce2e942eSBrian Norris static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
68ce2e942eSBrian Norris struct sk_buff *payload)
695e6e43ebSAmitkumar Karwar {
704c9f9fb2SAmitkumar Karwar
7199ffe72cSXinming Hu int ret;
7299ffe72cSXinming Hu
7399ffe72cSXinming Hu if (!payload) {
7499ffe72cSXinming Hu mwifiex_dbg(priv->adapter, INFO, "info: fw drop data\n");
7599ffe72cSXinming Hu return 0;
7699ffe72cSXinming Hu }
7799ffe72cSXinming Hu
7899ffe72cSXinming Hu ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
794c9f9fb2SAmitkumar Karwar if (!ret)
804c9f9fb2SAmitkumar Karwar return 0;
814c9f9fb2SAmitkumar Karwar
825e6e43ebSAmitkumar Karwar if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
835e6e43ebSAmitkumar Karwar return mwifiex_handle_uap_rx_forward(priv, payload);
845e6e43ebSAmitkumar Karwar
855e6e43ebSAmitkumar Karwar return mwifiex_process_rx_packet(priv, payload);
865e6e43ebSAmitkumar Karwar }
875e6e43ebSAmitkumar Karwar
885e6e3a92SBing Zhao /*
898c00228eSYogesh Ashok Powar * This function dispatches all packets in the Rx reorder table until the
908c00228eSYogesh Ashok Powar * start window.
915e6e3a92SBing Zhao *
925e6e3a92SBing Zhao * There could be holes in the buffer, which are skipped by the function.
935e6e3a92SBing Zhao * Since the buffer is linear, the function uses rotation to simulate
945e6e3a92SBing Zhao * circular buffer.
955e6e3a92SBing Zhao */
96ab581472SYogesh Ashok Powar static void
mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private * priv,struct mwifiex_rx_reorder_tbl * tbl,int start_win)975e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
985e6e43ebSAmitkumar Karwar struct mwifiex_rx_reorder_tbl *tbl,
995e6e43ebSAmitkumar Karwar int start_win)
1005e6e3a92SBing Zhao {
101ce2e942eSBrian Norris struct sk_buff_head list;
102ce2e942eSBrian Norris struct sk_buff *skb;
1038c00228eSYogesh Ashok Powar int pkt_to_send, i;
1045e6e3a92SBing Zhao
105ce2e942eSBrian Norris __skb_queue_head_init(&list);
1068a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
107ce2e942eSBrian Norris
1088c00228eSYogesh Ashok Powar pkt_to_send = (start_win > tbl->start_win) ?
1098c00228eSYogesh Ashok Powar min((start_win - tbl->start_win), tbl->win_size) :
1108c00228eSYogesh Ashok Powar tbl->win_size;
1115e6e3a92SBing Zhao
1128c00228eSYogesh Ashok Powar for (i = 0; i < pkt_to_send; ++i) {
1138c00228eSYogesh Ashok Powar if (tbl->rx_reorder_ptr[i]) {
114ce2e942eSBrian Norris skb = tbl->rx_reorder_ptr[i];
115ce2e942eSBrian Norris __skb_queue_tail(&list, skb);
1168c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[i] = NULL;
1175e6e3a92SBing Zhao }
1185e6e3a92SBing Zhao }
1195e6e3a92SBing Zhao
1205e6e3a92SBing Zhao /*
1215e6e3a92SBing Zhao * We don't have a circular buffer, hence use rotation to simulate
1225e6e3a92SBing Zhao * circular buffer
1235e6e3a92SBing Zhao */
1248c00228eSYogesh Ashok Powar for (i = 0; i < tbl->win_size - pkt_to_send; ++i) {
1258c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i];
1268c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[pkt_to_send + i] = NULL;
1275e6e3a92SBing Zhao }
1285e6e3a92SBing Zhao
1298c00228eSYogesh Ashok Powar tbl->start_win = start_win;
1308a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
131ce2e942eSBrian Norris
132ce2e942eSBrian Norris while ((skb = __skb_dequeue(&list)))
133ce2e942eSBrian Norris mwifiex_11n_dispatch_pkt(priv, skb);
1345e6e3a92SBing Zhao }
1355e6e3a92SBing Zhao
1365e6e3a92SBing Zhao /*
1375e6e3a92SBing Zhao * This function dispatches all packets in the Rx reorder table until
1385e6e3a92SBing Zhao * a hole is found.
1395e6e3a92SBing Zhao *
1405e6e3a92SBing Zhao * The start window is adjusted automatically when a hole is located.
1415e6e3a92SBing Zhao * Since the buffer is linear, the function uses rotation to simulate
1425e6e3a92SBing Zhao * circular buffer.
1435e6e3a92SBing Zhao */
144ab581472SYogesh Ashok Powar static void
mwifiex_11n_scan_and_dispatch(struct mwifiex_private * priv,struct mwifiex_rx_reorder_tbl * tbl)1455e6e3a92SBing Zhao mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
1468c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl)
1475e6e3a92SBing Zhao {
148ce2e942eSBrian Norris struct sk_buff_head list;
149ce2e942eSBrian Norris struct sk_buff *skb;
1505e6e3a92SBing Zhao int i, j, xchg;
1515e6e3a92SBing Zhao
152ce2e942eSBrian Norris __skb_queue_head_init(&list);
1538a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
154ce2e942eSBrian Norris
155ce2e942eSBrian Norris for (i = 0; i < tbl->win_size; ++i) {
156ce2e942eSBrian Norris if (!tbl->rx_reorder_ptr[i])
1575e6e3a92SBing Zhao break;
158ce2e942eSBrian Norris skb = tbl->rx_reorder_ptr[i];
159ce2e942eSBrian Norris __skb_queue_tail(&list, skb);
1608c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[i] = NULL;
1615e6e3a92SBing Zhao }
1625e6e3a92SBing Zhao
1635e6e3a92SBing Zhao /*
1645e6e3a92SBing Zhao * We don't have a circular buffer, hence use rotation to simulate
1655e6e3a92SBing Zhao * circular buffer
1665e6e3a92SBing Zhao */
1675e6e3a92SBing Zhao if (i > 0) {
1688c00228eSYogesh Ashok Powar xchg = tbl->win_size - i;
1695e6e3a92SBing Zhao for (j = 0; j < xchg; ++j) {
1708c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j];
1718c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[i + j] = NULL;
1725e6e3a92SBing Zhao }
1735e6e3a92SBing Zhao }
1748c00228eSYogesh Ashok Powar tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
175ce2e942eSBrian Norris
1768a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
177ce2e942eSBrian Norris
178ce2e942eSBrian Norris while ((skb = __skb_dequeue(&list)))
179ce2e942eSBrian Norris mwifiex_11n_dispatch_pkt(priv, skb);
1805e6e3a92SBing Zhao }
1815e6e3a92SBing Zhao
1825e6e3a92SBing Zhao /*
1835e6e3a92SBing Zhao * This function deletes the Rx reorder table and frees the memory.
1845e6e3a92SBing Zhao *
1855e6e3a92SBing Zhao * The function stops the associated timer and dispatches all the
1865e6e3a92SBing Zhao * pending packets in the Rx reorder table before deletion.
1875e6e3a92SBing Zhao */
1885e6e3a92SBing Zhao static void
mwifiex_del_rx_reorder_entry(struct mwifiex_private * priv,struct mwifiex_rx_reorder_tbl * tbl)1898c00228eSYogesh Ashok Powar mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
1908c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl)
1915e6e3a92SBing Zhao {
19263410c37SAmitkumar Karwar int start_win;
1935e6e3a92SBing Zhao
1948c00228eSYogesh Ashok Powar if (!tbl)
1955e6e3a92SBing Zhao return;
1965e6e3a92SBing Zhao
1978a7f9fd8SBrian Norris spin_lock_bh(&priv->adapter->rx_proc_lock);
1986e251174SAvinash Patil priv->adapter->rx_locked = true;
1996e251174SAvinash Patil if (priv->adapter->rx_processing) {
2008a7f9fd8SBrian Norris spin_unlock_bh(&priv->adapter->rx_proc_lock);
2016e251174SAvinash Patil flush_workqueue(priv->adapter->rx_workqueue);
2026e251174SAvinash Patil } else {
2038a7f9fd8SBrian Norris spin_unlock_bh(&priv->adapter->rx_proc_lock);
2046e251174SAvinash Patil }
2056e251174SAvinash Patil
20663410c37SAmitkumar Karwar start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
2075e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
2085e6e3a92SBing Zhao
2098fa7292fSThomas Gleixner timer_delete_sync(&tbl->timer_context.timer);
2103a8fede1SMarc Yang tbl->timer_context.timer_is_set = false;
2111aa48f08SBrian Norris
2128a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
2138c00228eSYogesh Ashok Powar list_del(&tbl->list);
2148a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2151aa48f08SBrian Norris
2168c00228eSYogesh Ashok Powar kfree(tbl->rx_reorder_ptr);
2178c00228eSYogesh Ashok Powar kfree(tbl);
2186e251174SAvinash Patil
2198a7f9fd8SBrian Norris spin_lock_bh(&priv->adapter->rx_proc_lock);
2206e251174SAvinash Patil priv->adapter->rx_locked = false;
2218a7f9fd8SBrian Norris spin_unlock_bh(&priv->adapter->rx_proc_lock);
2226e251174SAvinash Patil
2235e6e3a92SBing Zhao }
2245e6e3a92SBing Zhao
2255e6e3a92SBing Zhao /*
2265e6e3a92SBing Zhao * This function returns the pointer to an entry in Rx reordering
2275e6e3a92SBing Zhao * table which matches the given TA/TID pair.
2285e6e3a92SBing Zhao */
229d1cf3b95SAvinash Patil struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private * priv,int tid,u8 * ta)2305e6e3a92SBing Zhao mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
2315e6e3a92SBing Zhao {
2328c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl;
2335e6e3a92SBing Zhao
2348a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
2351aa48f08SBrian Norris list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
2361aa48f08SBrian Norris if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
2378a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2388c00228eSYogesh Ashok Powar return tbl;
2391aa48f08SBrian Norris }
2401aa48f08SBrian Norris }
2418a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2425e6e3a92SBing Zhao
2435e6e3a92SBing Zhao return NULL;
2445e6e3a92SBing Zhao }
2455e6e3a92SBing Zhao
2463e238a11SAvinash Patil /* This function retrieves the pointer to an entry in Rx reordering
2473e238a11SAvinash Patil * table which matches the given TA and deletes it.
2483e238a11SAvinash Patil */
mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private * priv,u8 * ta)2493e238a11SAvinash Patil void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
2503e238a11SAvinash Patil {
2513e238a11SAvinash Patil struct mwifiex_rx_reorder_tbl *tbl, *tmp;
2523e238a11SAvinash Patil
2533e238a11SAvinash Patil if (!ta)
2543e238a11SAvinash Patil return;
2553e238a11SAvinash Patil
2568a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
2571aa48f08SBrian Norris list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
2581aa48f08SBrian Norris if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
2598a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2603e238a11SAvinash Patil mwifiex_del_rx_reorder_entry(priv, tbl);
2618a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
2621aa48f08SBrian Norris }
2631aa48f08SBrian Norris }
2648a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2653e238a11SAvinash Patil
2663e238a11SAvinash Patil return;
2673e238a11SAvinash Patil }
2683e238a11SAvinash Patil
2695e6e3a92SBing Zhao /*
2705e6e3a92SBing Zhao * This function finds the last sequence number used in the packets
2715e6e3a92SBing Zhao * buffered in Rx reordering table.
2725e6e3a92SBing Zhao */
2735e6e3a92SBing Zhao static int
mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt * ctx)2742d702830SAmitkumar Karwar mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
2755e6e3a92SBing Zhao {
2762d702830SAmitkumar Karwar struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
2771aa48f08SBrian Norris struct mwifiex_private *priv = ctx->priv;
2785e6e3a92SBing Zhao int i;
2795e6e3a92SBing Zhao
2808a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
2811aa48f08SBrian Norris for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
2821aa48f08SBrian Norris if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
2838a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2845e6e3a92SBing Zhao return i;
2851aa48f08SBrian Norris }
2861aa48f08SBrian Norris }
2878a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
2885e6e3a92SBing Zhao
2895e6e3a92SBing Zhao return -1;
2905e6e3a92SBing Zhao }
2915e6e3a92SBing Zhao
2925e6e3a92SBing Zhao /*
2935e6e3a92SBing Zhao * This function flushes all the packets in Rx reordering table.
2945e6e3a92SBing Zhao *
2955e6e3a92SBing Zhao * The function checks if any packets are currently buffered in the
2965e6e3a92SBing Zhao * table or not. In case there are packets available, it dispatches
2975e6e3a92SBing Zhao * them and then dumps the Rx reordering table.
2985e6e3a92SBing Zhao */
2995e6e3a92SBing Zhao static void
mwifiex_flush_data(struct timer_list * t)30008c2eb8eSKees Cook mwifiex_flush_data(struct timer_list *t)
3015e6e3a92SBing Zhao {
3028c00228eSYogesh Ashok Powar struct reorder_tmr_cnxt *ctx =
303*41cb0855SIngo Molnar timer_container_of(ctx, t, timer);
30463410c37SAmitkumar Karwar int start_win, seq_num;
3055e6e3a92SBing Zhao
3063a8fede1SMarc Yang ctx->timer_is_set = false;
3072d702830SAmitkumar Karwar seq_num = mwifiex_11n_find_last_seq_num(ctx);
308bb7de2baSYogesh Ashok Powar
3091aa48f08SBrian Norris if (seq_num < 0)
310bb7de2baSYogesh Ashok Powar return;
311bb7de2baSYogesh Ashok Powar
312acebe8c1SZhaoyang Liu mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
31363410c37SAmitkumar Karwar start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
3145e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
3155e6e43ebSAmitkumar Karwar start_win);
3165e6e3a92SBing Zhao }
3175e6e3a92SBing Zhao
3185e6e3a92SBing Zhao /*
3195e6e3a92SBing Zhao * This function creates an entry in Rx reordering table for the
3205e6e3a92SBing Zhao * given TA/TID.
3215e6e3a92SBing Zhao *
3225e6e3a92SBing Zhao * The function also initializes the entry with sequence number, window
3235e6e3a92SBing Zhao * size as well as initializes the timer.
3245e6e3a92SBing Zhao *
3255e6e3a92SBing Zhao * If the received TA/TID pair is already present, all the packets are
3265e6e3a92SBing Zhao * dispatched and the window size is moved until the SSN.
3275e6e3a92SBing Zhao */
3285e6e3a92SBing Zhao static void
mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private * priv,u8 * ta,int tid,int win_size,int seq_num)3295e6e3a92SBing Zhao mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
3305e6e3a92SBing Zhao int tid, int win_size, int seq_num)
3315e6e3a92SBing Zhao {
3325e6e3a92SBing Zhao int i;
3338c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl, *new_node;
3345e6e3a92SBing Zhao u16 last_seq = 0;
3355a009adfSAvinash Patil struct mwifiex_sta_node *node;
3365e6e3a92SBing Zhao
3375e6e3a92SBing Zhao /*
338ed03a2afSJason Wang * If we get a TID, ta pair which is already present dispatch all
3395e6e3a92SBing Zhao * the packets and move the window size until the ssn
3405e6e3a92SBing Zhao */
3418c00228eSYogesh Ashok Powar tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
3428c00228eSYogesh Ashok Powar if (tbl) {
3435e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
3445e6e3a92SBing Zhao return;
3455e6e3a92SBing Zhao }
3468c00228eSYogesh Ashok Powar /* if !tbl then create one */
3475e6e3a92SBing Zhao new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
3480d2e7a5cSJoe Perches if (!new_node)
3495e6e3a92SBing Zhao return;
3505e6e3a92SBing Zhao
3515e6e3a92SBing Zhao INIT_LIST_HEAD(&new_node->list);
3525e6e3a92SBing Zhao new_node->tid = tid;
3535e6e3a92SBing Zhao memcpy(new_node->ta, ta, ETH_ALEN);
3545e6e3a92SBing Zhao new_node->start_win = seq_num;
3558acbea61SPaul Stewart new_node->init_win = seq_num;
3568acbea61SPaul Stewart new_node->flags = 0;
3575a009adfSAvinash Patil
3588a7f9fd8SBrian Norris spin_lock_bh(&priv->sta_list_spinlock);
3595a009adfSAvinash Patil if (mwifiex_queuing_ra_based(priv)) {
3605a009adfSAvinash Patil if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
3615a009adfSAvinash Patil node = mwifiex_get_sta_entry(priv, ta);
3625a009adfSAvinash Patil if (node)
3635a009adfSAvinash Patil last_seq = node->rx_seq[tid];
3645a009adfSAvinash Patil }
3655a009adfSAvinash Patil } else {
366daeb5bb4SAvinash Patil node = mwifiex_get_sta_entry(priv, ta);
367daeb5bb4SAvinash Patil if (node)
368daeb5bb4SAvinash Patil last_seq = node->rx_seq[tid];
369daeb5bb4SAvinash Patil else
3705e6e3a92SBing Zhao last_seq = priv->rx_seq[tid];
3715a009adfSAvinash Patil }
3728a7f9fd8SBrian Norris spin_unlock_bh(&priv->sta_list_spinlock);
3735e6e3a92SBing Zhao
374acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, INFO,
375acebe8c1SZhaoyang Liu "info: last_seq=%d start_win=%d\n",
37609bd1976SAvinash Patil last_seq, new_node->start_win);
37709bd1976SAvinash Patil
37892583924SStone Piao if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
3798acbea61SPaul Stewart last_seq >= new_node->start_win) {
3805e6e3a92SBing Zhao new_node->start_win = last_seq + 1;
3818acbea61SPaul Stewart new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
3828acbea61SPaul Stewart }
3835e6e3a92SBing Zhao
3845e6e3a92SBing Zhao new_node->win_size = win_size;
3855e6e3a92SBing Zhao
3866396bb22SKees Cook new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *),
3875e6e3a92SBing Zhao GFP_KERNEL);
3885e6e3a92SBing Zhao if (!new_node->rx_reorder_ptr) {
38961494648SXu Wang kfree(new_node);
390acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, ERROR,
3915e6e3a92SBing Zhao "%s: failed to alloc reorder_ptr\n", __func__);
3925e6e3a92SBing Zhao return;
3935e6e3a92SBing Zhao }
3945e6e3a92SBing Zhao
3955e6e3a92SBing Zhao new_node->timer_context.ptr = new_node;
3965e6e3a92SBing Zhao new_node->timer_context.priv = priv;
3973a8fede1SMarc Yang new_node->timer_context.timer_is_set = false;
3985e6e3a92SBing Zhao
39908c2eb8eSKees Cook timer_setup(&new_node->timer_context.timer, mwifiex_flush_data, 0);
4005e6e3a92SBing Zhao
4015e6e3a92SBing Zhao for (i = 0; i < win_size; ++i)
4025e6e3a92SBing Zhao new_node->rx_reorder_ptr[i] = NULL;
4035e6e3a92SBing Zhao
4048a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
4055e6e3a92SBing Zhao list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
4068a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
4075e6e3a92SBing Zhao }
4085e6e3a92SBing Zhao
4093a8fede1SMarc Yang static void
mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl * tbl)4103a8fede1SMarc Yang mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
4113a8fede1SMarc Yang {
4123a8fede1SMarc Yang u32 min_flush_time;
4133a8fede1SMarc Yang
4143a8fede1SMarc Yang if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
4153a8fede1SMarc Yang min_flush_time = MIN_FLUSH_TIMER_15_MS;
4163a8fede1SMarc Yang else
4173a8fede1SMarc Yang min_flush_time = MIN_FLUSH_TIMER_MS;
4183a8fede1SMarc Yang
4193a8fede1SMarc Yang mod_timer(&tbl->timer_context.timer,
4203a8fede1SMarc Yang jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
4213a8fede1SMarc Yang
4223a8fede1SMarc Yang tbl->timer_context.timer_is_set = true;
4233a8fede1SMarc Yang }
4243a8fede1SMarc Yang
4255e6e3a92SBing Zhao /*
4265e6e3a92SBing Zhao * This function prepares command for adding a BA request.
4275e6e3a92SBing Zhao *
4285e6e3a92SBing Zhao * Preparation includes -
4295e6e3a92SBing Zhao * - Setting command ID and proper size
4305e6e3a92SBing Zhao * - Setting add BA request buffer
4315e6e3a92SBing Zhao * - Ensuring correct endian-ness
4325e6e3a92SBing Zhao */
mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command * cmd,void * data_buf)433572e8f3eSAmitkumar Karwar int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
4345e6e3a92SBing Zhao {
4352c208890SJoe Perches struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
4365e6e3a92SBing Zhao
4375e6e3a92SBing Zhao cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
4385e6e3a92SBing Zhao cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
4395e6e3a92SBing Zhao memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
4405e6e3a92SBing Zhao
4415e6e3a92SBing Zhao return 0;
4425e6e3a92SBing Zhao }
4435e6e3a92SBing Zhao
4445e6e3a92SBing Zhao /*
4455e6e3a92SBing Zhao * This function prepares command for adding a BA response.
4465e6e3a92SBing Zhao *
4475e6e3a92SBing Zhao * Preparation includes -
4485e6e3a92SBing Zhao * - Setting command ID and proper size
4495e6e3a92SBing Zhao * - Setting add BA response buffer
4505e6e3a92SBing Zhao * - Ensuring correct endian-ness
4515e6e3a92SBing Zhao */
mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private * priv,struct host_cmd_ds_command * cmd,struct host_cmd_ds_11n_addba_req * cmd_addba_req)4525e6e3a92SBing Zhao int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
4535e6e3a92SBing Zhao struct host_cmd_ds_command *cmd,
454a5ffddb7SAmitkumar Karwar struct host_cmd_ds_11n_addba_req
455a5ffddb7SAmitkumar Karwar *cmd_addba_req)
4565e6e3a92SBing Zhao {
4572c208890SJoe Perches struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
458b06c5321SAvinash Patil struct mwifiex_sta_node *sta_ptr;
459b06c5321SAvinash Patil u32 rx_win_size = priv->add_ba_param.rx_win_size;
460270e58e8SYogesh Ashok Powar u8 tid;
461270e58e8SYogesh Ashok Powar int win_size;
4625e6e3a92SBing Zhao uint16_t block_ack_param_set;
4635e6e3a92SBing Zhao
464b06c5321SAvinash Patil if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
465b06c5321SAvinash Patil ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
466b06c5321SAvinash Patil priv->adapter->is_hw_11ac_capable &&
467b06c5321SAvinash Patil memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
4688a7f9fd8SBrian Norris spin_lock_bh(&priv->sta_list_spinlock);
469b06c5321SAvinash Patil sta_ptr = mwifiex_get_sta_entry(priv,
470b06c5321SAvinash Patil cmd_addba_req->peer_mac_addr);
471b06c5321SAvinash Patil if (!sta_ptr) {
4728a7f9fd8SBrian Norris spin_unlock_bh(&priv->sta_list_spinlock);
473acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, ERROR,
474b06c5321SAvinash Patil "BA setup with unknown TDLS peer %pM!\n",
475b06c5321SAvinash Patil cmd_addba_req->peer_mac_addr);
476b06c5321SAvinash Patil return -1;
477b06c5321SAvinash Patil }
478b06c5321SAvinash Patil if (sta_ptr->is_11ac_enabled)
479b06c5321SAvinash Patil rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
4808a7f9fd8SBrian Norris spin_unlock_bh(&priv->sta_list_spinlock);
481b06c5321SAvinash Patil }
482b06c5321SAvinash Patil
4835e6e3a92SBing Zhao cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
4845e6e3a92SBing Zhao cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
4855e6e3a92SBing Zhao
4865e6e3a92SBing Zhao memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
4875e6e3a92SBing Zhao ETH_ALEN);
4885e6e3a92SBing Zhao add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
4895e6e3a92SBing Zhao add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
4905e6e3a92SBing Zhao add_ba_rsp->ssn = cmd_addba_req->ssn;
4915e6e3a92SBing Zhao
4925e6e3a92SBing Zhao block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
4935e6e3a92SBing Zhao tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
4945e6e3a92SBing Zhao >> BLOCKACKPARAM_TID_POS;
4955e6e3a92SBing Zhao add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
4965e6e3a92SBing Zhao block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
4974c9f9fb2SAmitkumar Karwar
4984c9f9fb2SAmitkumar Karwar /* If we don't support AMSDU inside AMPDU, reset the bit */
4994c9f9fb2SAmitkumar Karwar if (!priv->add_ba_param.rx_amsdu ||
5004c9f9fb2SAmitkumar Karwar (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
5015e6e3a92SBing Zhao block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
502b06c5321SAvinash Patil block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
5035e6e3a92SBing Zhao add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
5045e6e3a92SBing Zhao win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
5055e6e3a92SBing Zhao & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
5065e6e3a92SBing Zhao >> BLOCKACKPARAM_WINSIZE_POS;
5075e6e3a92SBing Zhao cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
5085e6e3a92SBing Zhao
5095e6e3a92SBing Zhao mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
51084266841SYogesh Ashok Powar tid, win_size,
51184266841SYogesh Ashok Powar le16_to_cpu(cmd_addba_req->ssn));
5125e6e3a92SBing Zhao return 0;
5135e6e3a92SBing Zhao }
5145e6e3a92SBing Zhao
5155e6e3a92SBing Zhao /*
5165e6e3a92SBing Zhao * This function prepares command for deleting a BA request.
5175e6e3a92SBing Zhao *
5185e6e3a92SBing Zhao * Preparation includes -
5195e6e3a92SBing Zhao * - Setting command ID and proper size
5205e6e3a92SBing Zhao * - Setting del BA request buffer
5215e6e3a92SBing Zhao * - Ensuring correct endian-ness
5225e6e3a92SBing Zhao */
mwifiex_cmd_11n_delba(struct host_cmd_ds_command * cmd,void * data_buf)523572e8f3eSAmitkumar Karwar int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
5245e6e3a92SBing Zhao {
5252c208890SJoe Perches struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
5265e6e3a92SBing Zhao
5275e6e3a92SBing Zhao cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
5285e6e3a92SBing Zhao cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
5295e6e3a92SBing Zhao memcpy(del_ba, data_buf, sizeof(*del_ba));
5305e6e3a92SBing Zhao
5315e6e3a92SBing Zhao return 0;
5325e6e3a92SBing Zhao }
5335e6e3a92SBing Zhao
5345e6e3a92SBing Zhao /*
5355e6e3a92SBing Zhao * This function identifies if Rx reordering is needed for a received packet.
5365e6e3a92SBing Zhao *
5375e6e3a92SBing Zhao * In case reordering is required, the function will do the reordering
5385e6e3a92SBing Zhao * before sending it to kernel.
5395e6e3a92SBing Zhao *
5405e6e3a92SBing Zhao * The Rx reorder table is checked first with the received TID/TA pair. If
5415e6e3a92SBing Zhao * not found, the received packet is dispatched immediately. But if found,
5425e6e3a92SBing Zhao * the packet is reordered and all the packets in the updated Rx reordering
5435e6e3a92SBing Zhao * table is dispatched until a hole is found.
5445e6e3a92SBing Zhao *
5455e6e3a92SBing Zhao * For sequence number less than the starting window, the packet is dropped.
5465e6e3a92SBing Zhao */
mwifiex_11n_rx_reorder_pkt(struct mwifiex_private * priv,u16 seq_num,u16 tid,u8 * ta,u8 pkt_type,void * payload)5475e6e3a92SBing Zhao int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
5485e6e3a92SBing Zhao u16 seq_num, u16 tid,
5495e6e3a92SBing Zhao u8 *ta, u8 pkt_type, void *payload)
5505e6e3a92SBing Zhao {
5518c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl;
5523a8fede1SMarc Yang int prev_start_win, start_win, end_win, win_size;
553270e58e8SYogesh Ashok Powar u16 pkt_index;
5548acbea61SPaul Stewart bool init_window_shift = false;
5553a8fede1SMarc Yang int ret = 0;
5565e6e3a92SBing Zhao
5572c208890SJoe Perches tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
5588c00228eSYogesh Ashok Powar if (!tbl) {
5595e6e43ebSAmitkumar Karwar if (pkt_type != PKT_TYPE_BAR)
5605e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt(priv, payload);
5613a8fede1SMarc Yang return ret;
5625e6e3a92SBing Zhao }
5634c9f9fb2SAmitkumar Karwar
5644c9f9fb2SAmitkumar Karwar if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
5654c9f9fb2SAmitkumar Karwar mwifiex_11n_dispatch_pkt(priv, payload);
5663a8fede1SMarc Yang return ret;
5674c9f9fb2SAmitkumar Karwar }
5684c9f9fb2SAmitkumar Karwar
5698c00228eSYogesh Ashok Powar start_win = tbl->start_win;
5703a8fede1SMarc Yang prev_start_win = start_win;
5718c00228eSYogesh Ashok Powar win_size = tbl->win_size;
5725e6e3a92SBing Zhao end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
5738acbea61SPaul Stewart if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
5748acbea61SPaul Stewart init_window_shift = true;
5758acbea61SPaul Stewart tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
5768acbea61SPaul Stewart }
5775e6e3a92SBing Zhao
5782db96c3dSAvinash Patil if (tbl->flags & RXREOR_FORCE_NO_DROP) {
579acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, INFO,
5802db96c3dSAvinash Patil "RXREOR_FORCE_NO_DROP when HS is activated\n");
5812db96c3dSAvinash Patil tbl->flags &= ~RXREOR_FORCE_NO_DROP;
5828acbea61SPaul Stewart } else if (init_window_shift && seq_num < start_win &&
5838acbea61SPaul Stewart seq_num >= tbl->init_win) {
584acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, INFO,
5858acbea61SPaul Stewart "Sender TID sequence number reset %d->%d for SSN %d\n",
5868acbea61SPaul Stewart start_win, seq_num, tbl->init_win);
5878acbea61SPaul Stewart tbl->start_win = start_win = seq_num;
5888acbea61SPaul Stewart end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
5892db96c3dSAvinash Patil } else {
5908acbea61SPaul Stewart /*
5918acbea61SPaul Stewart * If seq_num is less then starting win then ignore and drop
5928acbea61SPaul Stewart * the packet
5938acbea61SPaul Stewart */
5942db96c3dSAvinash Patil if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
59584266841SYogesh Ashok Powar if (seq_num >= ((start_win + TWOPOW11) &
5962db96c3dSAvinash Patil (MAX_TID_VALUE - 1)) &&
5973a8fede1SMarc Yang seq_num < start_win) {
5983a8fede1SMarc Yang ret = -1;
5993a8fede1SMarc Yang goto done;
6003a8fede1SMarc Yang }
60184266841SYogesh Ashok Powar } else if ((seq_num < start_win) ||
6023a8fede1SMarc Yang (seq_num >= (start_win + TWOPOW11))) {
6033a8fede1SMarc Yang ret = -1;
6043a8fede1SMarc Yang goto done;
6055e6e3a92SBing Zhao }
6062db96c3dSAvinash Patil }
6075e6e3a92SBing Zhao
6085e6e3a92SBing Zhao /*
6095e6e3a92SBing Zhao * If this packet is a BAR we adjust seq_num as
6105e6e3a92SBing Zhao * WinStart = seq_num
6115e6e3a92SBing Zhao */
6125e6e3a92SBing Zhao if (pkt_type == PKT_TYPE_BAR)
6135e6e3a92SBing Zhao seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
6145e6e3a92SBing Zhao
61584266841SYogesh Ashok Powar if (((end_win < start_win) &&
6162db96c3dSAvinash Patil (seq_num < start_win) && (seq_num > end_win)) ||
61784266841SYogesh Ashok Powar ((end_win > start_win) && ((seq_num > end_win) ||
61884266841SYogesh Ashok Powar (seq_num < start_win)))) {
6195e6e3a92SBing Zhao end_win = seq_num;
620cc751498SAndrzej Hajda if (((end_win - win_size) + 1) >= 0)
6215e6e3a92SBing Zhao start_win = (end_win - win_size) + 1;
6225e6e3a92SBing Zhao else
623cc751498SAndrzej Hajda start_win = (MAX_TID_VALUE - (win_size - end_win)) + 1;
6245e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
6255e6e3a92SBing Zhao }
6265e6e3a92SBing Zhao
6275e6e3a92SBing Zhao if (pkt_type != PKT_TYPE_BAR) {
6285e6e3a92SBing Zhao if (seq_num >= start_win)
6295e6e3a92SBing Zhao pkt_index = seq_num - start_win;
6305e6e3a92SBing Zhao else
6315e6e3a92SBing Zhao pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
6325e6e3a92SBing Zhao
6333a8fede1SMarc Yang if (tbl->rx_reorder_ptr[pkt_index]) {
6343a8fede1SMarc Yang ret = -1;
6353a8fede1SMarc Yang goto done;
6363a8fede1SMarc Yang }
6375e6e3a92SBing Zhao
6388c00228eSYogesh Ashok Powar tbl->rx_reorder_ptr[pkt_index] = payload;
6395e6e3a92SBing Zhao }
6405e6e3a92SBing Zhao
6415e6e3a92SBing Zhao /*
6425e6e3a92SBing Zhao * Dispatch all packets sequentially from start_win until a
6435e6e3a92SBing Zhao * hole is found and adjust the start_win appropriately
6445e6e3a92SBing Zhao */
6458c00228eSYogesh Ashok Powar mwifiex_11n_scan_and_dispatch(priv, tbl);
6465e6e3a92SBing Zhao
6473a8fede1SMarc Yang done:
6483a8fede1SMarc Yang if (!tbl->timer_context.timer_is_set ||
6493a8fede1SMarc Yang prev_start_win != tbl->start_win)
6503a8fede1SMarc Yang mwifiex_11n_rxreorder_timer_restart(tbl);
6513a8fede1SMarc Yang return ret;
6525e6e3a92SBing Zhao }
6535e6e3a92SBing Zhao
6545e6e3a92SBing Zhao /*
6555e6e3a92SBing Zhao * This function deletes an entry for a given TID/TA pair.
6565e6e3a92SBing Zhao *
6575e6e3a92SBing Zhao * The TID/TA are taken from del BA event body.
6585e6e3a92SBing Zhao */
6595e6e3a92SBing Zhao void
mwifiex_del_ba_tbl(struct mwifiex_private * priv,int tid,u8 * peer_mac,u8 type,int initiator)6603e822635SYogesh Ashok Powar mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
6613e822635SYogesh Ashok Powar u8 type, int initiator)
6625e6e3a92SBing Zhao {
6638c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl;
6645e6e3a92SBing Zhao struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
66539df5e82SZhaoyang Liu struct mwifiex_ra_list_tbl *ra_list;
6665e6e3a92SBing Zhao u8 cleanup_rx_reorder_tbl;
667719a25e3SXinming Hu int tid_down;
6685e6e3a92SBing Zhao
6695e6e3a92SBing Zhao if (type == TYPE_DELBA_RECEIVE)
6705e6e3a92SBing Zhao cleanup_rx_reorder_tbl = (initiator) ? true : false;
6715e6e3a92SBing Zhao else
6725e6e3a92SBing Zhao cleanup_rx_reorder_tbl = (initiator) ? false : true;
6735e6e3a92SBing Zhao
674acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
67584266841SYogesh Ashok Powar peer_mac, tid, initiator);
6765e6e3a92SBing Zhao
6775e6e3a92SBing Zhao if (cleanup_rx_reorder_tbl) {
6788c00228eSYogesh Ashok Powar tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
6795e6e3a92SBing Zhao peer_mac);
6808c00228eSYogesh Ashok Powar if (!tbl) {
681acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, EVENT,
6825e6e3a92SBing Zhao "event: TID, TA not found in table\n");
6835e6e3a92SBing Zhao return;
6845e6e3a92SBing Zhao }
6858c00228eSYogesh Ashok Powar mwifiex_del_rx_reorder_entry(priv, tbl);
6865e6e3a92SBing Zhao } else {
6873e822635SYogesh Ashok Powar ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
6885e6e3a92SBing Zhao if (!ptx_tbl) {
689acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, EVENT,
6905e6e3a92SBing Zhao "event: TID, RA not found in table\n");
6915e6e3a92SBing Zhao return;
6925e6e3a92SBing Zhao }
693719a25e3SXinming Hu
694719a25e3SXinming Hu tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
695719a25e3SXinming Hu ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
69639df5e82SZhaoyang Liu if (ra_list) {
69739df5e82SZhaoyang Liu ra_list->amsdu_in_ampdu = false;
69839df5e82SZhaoyang Liu ra_list->ba_status = BA_SETUP_NONE;
69939df5e82SZhaoyang Liu }
7008a7f9fd8SBrian Norris spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
7015e6e3a92SBing Zhao mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
7028a7f9fd8SBrian Norris spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
7035e6e3a92SBing Zhao }
7045e6e3a92SBing Zhao }
7055e6e3a92SBing Zhao
7065e6e3a92SBing Zhao /*
7075e6e3a92SBing Zhao * This function handles the command response of an add BA response.
7085e6e3a92SBing Zhao *
7095e6e3a92SBing Zhao * Handling includes changing the header fields into CPU format and
7105e6e3a92SBing Zhao * creating the stream, provided the add BA is accepted.
7115e6e3a92SBing Zhao */
mwifiex_ret_11n_addba_resp(struct mwifiex_private * priv,struct host_cmd_ds_command * resp)7125e6e3a92SBing Zhao int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
7135e6e3a92SBing Zhao struct host_cmd_ds_command *resp)
7145e6e3a92SBing Zhao {
7152c208890SJoe Perches struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
7165e6e3a92SBing Zhao int tid, win_size;
7178c00228eSYogesh Ashok Powar struct mwifiex_rx_reorder_tbl *tbl;
7185e6e3a92SBing Zhao uint16_t block_ack_param_set;
7195e6e3a92SBing Zhao
7205e6e3a92SBing Zhao block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
7215e6e3a92SBing Zhao
7225e6e3a92SBing Zhao tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
7235e6e3a92SBing Zhao >> BLOCKACKPARAM_TID_POS;
7245e6e3a92SBing Zhao /*
7255e6e3a92SBing Zhao * Check if we had rejected the ADDBA, if yes then do not create
7265e6e3a92SBing Zhao * the stream
7275e6e3a92SBing Zhao */
72863410c37SAmitkumar Karwar if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
729acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
7305e6e3a92SBing Zhao add_ba_rsp->peer_mac_addr, tid);
7315e6e3a92SBing Zhao
7328c00228eSYogesh Ashok Powar tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
7338c00228eSYogesh Ashok Powar add_ba_rsp->peer_mac_addr);
7348c00228eSYogesh Ashok Powar if (tbl)
7358c00228eSYogesh Ashok Powar mwifiex_del_rx_reorder_entry(priv, tbl);
73663410c37SAmitkumar Karwar
73763410c37SAmitkumar Karwar return 0;
7385e6e3a92SBing Zhao }
7395e6e3a92SBing Zhao
74063410c37SAmitkumar Karwar win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
74163410c37SAmitkumar Karwar >> BLOCKACKPARAM_WINSIZE_POS;
74263410c37SAmitkumar Karwar
7434c9f9fb2SAmitkumar Karwar tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
7444c9f9fb2SAmitkumar Karwar add_ba_rsp->peer_mac_addr);
7454c9f9fb2SAmitkumar Karwar if (tbl) {
7464c9f9fb2SAmitkumar Karwar if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
7474c9f9fb2SAmitkumar Karwar priv->add_ba_param.rx_amsdu &&
7484c9f9fb2SAmitkumar Karwar (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
7494c9f9fb2SAmitkumar Karwar tbl->amsdu = true;
7504c9f9fb2SAmitkumar Karwar else
7514c9f9fb2SAmitkumar Karwar tbl->amsdu = false;
7524c9f9fb2SAmitkumar Karwar }
7534c9f9fb2SAmitkumar Karwar
754acebe8c1SZhaoyang Liu mwifiex_dbg(priv->adapter, CMD,
75563410c37SAmitkumar Karwar "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
75663410c37SAmitkumar Karwar add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
75763410c37SAmitkumar Karwar
7585e6e3a92SBing Zhao return 0;
7595e6e3a92SBing Zhao }
7605e6e3a92SBing Zhao
7615e6e3a92SBing Zhao /*
7625e6e3a92SBing Zhao * This function handles BA stream timeout event by preparing and sending
7635e6e3a92SBing Zhao * a command to the firmware.
7645e6e3a92SBing Zhao */
mwifiex_11n_ba_stream_timeout(struct mwifiex_private * priv,struct host_cmd_ds_11n_batimeout * event)7655e6e3a92SBing Zhao void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
7665e6e3a92SBing Zhao struct host_cmd_ds_11n_batimeout *event)
7675e6e3a92SBing Zhao {
7685e6e3a92SBing Zhao struct host_cmd_ds_11n_delba delba;
7695e6e3a92SBing Zhao
7705e6e3a92SBing Zhao memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
7715e6e3a92SBing Zhao memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
7725e6e3a92SBing Zhao
7735e6e3a92SBing Zhao delba.del_ba_param_set |=
7745e6e3a92SBing Zhao cpu_to_le16((u16) event->tid << DELBA_TID_POS);
7755e6e3a92SBing Zhao delba.del_ba_param_set |= cpu_to_le16(
7765e6e3a92SBing Zhao (u16) event->origninator << DELBA_INITIATOR_POS);
7775e6e3a92SBing Zhao delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
778fa0ecbb9SBing Zhao mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
7795e6e3a92SBing Zhao }
7805e6e3a92SBing Zhao
7815e6e3a92SBing Zhao /*
7825e6e3a92SBing Zhao * This function cleans up the Rx reorder table by deleting all the entries
7835e6e3a92SBing Zhao * and re-initializing.
7845e6e3a92SBing Zhao */
mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private * priv)7855e6e3a92SBing Zhao void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
7865e6e3a92SBing Zhao {
7875e6e3a92SBing Zhao struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
7885e6e3a92SBing Zhao
7898a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
7905e6e3a92SBing Zhao list_for_each_entry_safe(del_tbl_ptr, tmp_node,
7911aa48f08SBrian Norris &priv->rx_reorder_tbl_ptr, list) {
7928a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
7938c00228eSYogesh Ashok Powar mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
7948a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
7951aa48f08SBrian Norris }
7962d702830SAmitkumar Karwar INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
7978a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
7985e6e3a92SBing Zhao
79992583924SStone Piao mwifiex_reset_11n_rx_seq_num(priv);
8005e6e3a92SBing Zhao }
8012db96c3dSAvinash Patil
8022db96c3dSAvinash Patil /*
8032db96c3dSAvinash Patil * This function updates all rx_reorder_tbl's flags.
8042db96c3dSAvinash Patil */
mwifiex_update_rxreor_flags(struct mwifiex_adapter * adapter,u8 flags)8052db96c3dSAvinash Patil void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
8062db96c3dSAvinash Patil {
8072db96c3dSAvinash Patil struct mwifiex_private *priv;
8082db96c3dSAvinash Patil struct mwifiex_rx_reorder_tbl *tbl;
8092db96c3dSAvinash Patil int i;
8102db96c3dSAvinash Patil
8112db96c3dSAvinash Patil for (i = 0; i < adapter->priv_num; i++) {
8122db96c3dSAvinash Patil priv = adapter->priv[i];
8132db96c3dSAvinash Patil
8148a7f9fd8SBrian Norris spin_lock_bh(&priv->rx_reorder_tbl_lock);
8152db96c3dSAvinash Patil list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
8162db96c3dSAvinash Patil tbl->flags = flags;
8178a7f9fd8SBrian Norris spin_unlock_bh(&priv->rx_reorder_tbl_lock);
8182db96c3dSAvinash Patil }
8192db96c3dSAvinash Patil
8202db96c3dSAvinash Patil return;
8212db96c3dSAvinash Patil }
822d219b7ebSChunfan Chen
823d219b7ebSChunfan Chen /* This function update all the rx_win_size based on coex flag
824d219b7ebSChunfan Chen */
mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter * adapter,bool coex_flag)825d219b7ebSChunfan Chen static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
826d219b7ebSChunfan Chen bool coex_flag)
827d219b7ebSChunfan Chen {
828d219b7ebSChunfan Chen u8 i;
829d219b7ebSChunfan Chen u32 rx_win_size;
830d219b7ebSChunfan Chen struct mwifiex_private *priv;
831d219b7ebSChunfan Chen
832d219b7ebSChunfan Chen dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
833d219b7ebSChunfan Chen
834d219b7ebSChunfan Chen for (i = 0; i < adapter->priv_num; i++) {
835d219b7ebSChunfan Chen priv = adapter->priv[i];
836d219b7ebSChunfan Chen rx_win_size = priv->add_ba_param.rx_win_size;
837d219b7ebSChunfan Chen if (coex_flag) {
838d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
839d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
840d219b7ebSChunfan Chen MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
841d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
842d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
843d219b7ebSChunfan Chen MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
844d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
845d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
846d219b7ebSChunfan Chen MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
847d219b7ebSChunfan Chen } else {
848d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
849d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
850d219b7ebSChunfan Chen MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
851d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
852d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
853d219b7ebSChunfan Chen MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
854d219b7ebSChunfan Chen if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
855d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
856d219b7ebSChunfan Chen MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
857d219b7ebSChunfan Chen }
858d219b7ebSChunfan Chen
859d219b7ebSChunfan Chen if (adapter->coex_win_size && adapter->coex_rx_win_size)
860d219b7ebSChunfan Chen priv->add_ba_param.rx_win_size =
861d219b7ebSChunfan Chen adapter->coex_rx_win_size;
862d219b7ebSChunfan Chen
863d219b7ebSChunfan Chen if (rx_win_size != priv->add_ba_param.rx_win_size) {
864d219b7ebSChunfan Chen if (!priv->media_connected)
865d219b7ebSChunfan Chen continue;
866d219b7ebSChunfan Chen for (i = 0; i < MAX_NUM_TID; i++)
867d219b7ebSChunfan Chen mwifiex_11n_delba(priv, i);
868d219b7ebSChunfan Chen }
869d219b7ebSChunfan Chen }
870d219b7ebSChunfan Chen }
871d219b7ebSChunfan Chen
872d219b7ebSChunfan Chen /* This function check coex for RX BA
873d219b7ebSChunfan Chen */
mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter * adapter)874d219b7ebSChunfan Chen void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
875d219b7ebSChunfan Chen {
876d219b7ebSChunfan Chen u8 i;
877d219b7ebSChunfan Chen struct mwifiex_private *priv;
878d219b7ebSChunfan Chen u8 count = 0;
879d219b7ebSChunfan Chen
880d219b7ebSChunfan Chen for (i = 0; i < adapter->priv_num; i++) {
881d219b7ebSChunfan Chen priv = adapter->priv[i];
882d219b7ebSChunfan Chen if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
883d219b7ebSChunfan Chen if (priv->media_connected)
884d219b7ebSChunfan Chen count++;
885d219b7ebSChunfan Chen }
886d219b7ebSChunfan Chen if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
887d219b7ebSChunfan Chen if (priv->bss_started)
888d219b7ebSChunfan Chen count++;
889d219b7ebSChunfan Chen }
89067a72043SSascha Hauer
891d219b7ebSChunfan Chen if (count >= MWIFIEX_BSS_COEX_COUNT)
892d219b7ebSChunfan Chen break;
893d219b7ebSChunfan Chen }
894d219b7ebSChunfan Chen if (count >= MWIFIEX_BSS_COEX_COUNT)
895d219b7ebSChunfan Chen mwifiex_update_ampdu_rxwinsize(adapter, true);
896d219b7ebSChunfan Chen else
897d219b7ebSChunfan Chen mwifiex_update_ampdu_rxwinsize(adapter, false);
898d219b7ebSChunfan Chen }
89999ffe72cSXinming Hu
90099ffe72cSXinming Hu /* This function handles rxba_sync event
90199ffe72cSXinming Hu */
mwifiex_11n_rxba_sync_event(struct mwifiex_private * priv,u8 * event_buf,u16 len)90299ffe72cSXinming Hu void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
90399ffe72cSXinming Hu u8 *event_buf, u16 len)
90499ffe72cSXinming Hu {
90599ffe72cSXinming Hu struct mwifiex_ie_types_rxba_sync *tlv_rxba = (void *)event_buf;
90699ffe72cSXinming Hu u16 tlv_type, tlv_len;
90799ffe72cSXinming Hu struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
90899ffe72cSXinming Hu u8 i, j;
90999ffe72cSXinming Hu u16 seq_num, tlv_seq_num, tlv_bitmap_len;
91099ffe72cSXinming Hu int tlv_buf_left = len;
91199ffe72cSXinming Hu int ret;
91299ffe72cSXinming Hu u8 *tmp;
91399ffe72cSXinming Hu
91499ffe72cSXinming Hu mwifiex_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:",
91599ffe72cSXinming Hu event_buf, len);
916c7847241SGustavo A. R. Silva while (tlv_buf_left > sizeof(*tlv_rxba)) {
91799ffe72cSXinming Hu tlv_type = le16_to_cpu(tlv_rxba->header.type);
91899ffe72cSXinming Hu tlv_len = le16_to_cpu(tlv_rxba->header.len);
919d5a93b7dSGustavo A. R. Silva if (size_add(sizeof(tlv_rxba->header), tlv_len) > tlv_buf_left) {
920d5a93b7dSGustavo A. R. Silva mwifiex_dbg(priv->adapter, WARN,
921d5a93b7dSGustavo A. R. Silva "TLV size (%zu) overflows event_buf buf_left=%d\n",
922d5a93b7dSGustavo A. R. Silva size_add(sizeof(tlv_rxba->header), tlv_len),
923d5a93b7dSGustavo A. R. Silva tlv_buf_left);
924d5a93b7dSGustavo A. R. Silva return;
925d5a93b7dSGustavo A. R. Silva }
926d5a93b7dSGustavo A. R. Silva
92799ffe72cSXinming Hu if (tlv_type != TLV_TYPE_RXBA_SYNC) {
92899ffe72cSXinming Hu mwifiex_dbg(priv->adapter, ERROR,
92999ffe72cSXinming Hu "Wrong TLV id=0x%x\n", tlv_type);
93099ffe72cSXinming Hu return;
93199ffe72cSXinming Hu }
93299ffe72cSXinming Hu
93399ffe72cSXinming Hu tlv_seq_num = le16_to_cpu(tlv_rxba->seq_num);
93499ffe72cSXinming Hu tlv_bitmap_len = le16_to_cpu(tlv_rxba->bitmap_len);
935d5a93b7dSGustavo A. R. Silva if (size_add(sizeof(*tlv_rxba), tlv_bitmap_len) > tlv_buf_left) {
936d5a93b7dSGustavo A. R. Silva mwifiex_dbg(priv->adapter, WARN,
937d5a93b7dSGustavo A. R. Silva "TLV size (%zu) overflows event_buf buf_left=%d\n",
938d5a93b7dSGustavo A. R. Silva size_add(sizeof(*tlv_rxba), tlv_bitmap_len),
939d5a93b7dSGustavo A. R. Silva tlv_buf_left);
940d5a93b7dSGustavo A. R. Silva return;
941d5a93b7dSGustavo A. R. Silva }
942d5a93b7dSGustavo A. R. Silva
94399ffe72cSXinming Hu mwifiex_dbg(priv->adapter, INFO,
94499ffe72cSXinming Hu "%pM tid=%d seq_num=%d bitmap_len=%d\n",
94599ffe72cSXinming Hu tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
94699ffe72cSXinming Hu tlv_bitmap_len);
94799ffe72cSXinming Hu
94899ffe72cSXinming Hu rx_reor_tbl_ptr =
94999ffe72cSXinming Hu mwifiex_11n_get_rx_reorder_tbl(priv, tlv_rxba->tid,
95099ffe72cSXinming Hu tlv_rxba->mac);
95199ffe72cSXinming Hu if (!rx_reor_tbl_ptr) {
95299ffe72cSXinming Hu mwifiex_dbg(priv->adapter, ERROR,
95399ffe72cSXinming Hu "Can not find rx_reorder_tbl!");
95499ffe72cSXinming Hu return;
95599ffe72cSXinming Hu }
95699ffe72cSXinming Hu
95799ffe72cSXinming Hu for (i = 0; i < tlv_bitmap_len; i++) {
95899ffe72cSXinming Hu for (j = 0 ; j < 8; j++) {
95999ffe72cSXinming Hu if (tlv_rxba->bitmap[i] & (1 << j)) {
96099ffe72cSXinming Hu seq_num = (MAX_TID_VALUE - 1) &
96199ffe72cSXinming Hu (tlv_seq_num + i * 8 + j);
96299ffe72cSXinming Hu
96399ffe72cSXinming Hu mwifiex_dbg(priv->adapter, ERROR,
96499ffe72cSXinming Hu "drop packet,seq=%d\n",
96599ffe72cSXinming Hu seq_num);
96699ffe72cSXinming Hu
96799ffe72cSXinming Hu ret = mwifiex_11n_rx_reorder_pkt
96899ffe72cSXinming Hu (priv, seq_num, tlv_rxba->tid,
96999ffe72cSXinming Hu tlv_rxba->mac, 0, NULL);
97099ffe72cSXinming Hu
97199ffe72cSXinming Hu if (ret)
97299ffe72cSXinming Hu mwifiex_dbg(priv->adapter,
97399ffe72cSXinming Hu ERROR,
97499ffe72cSXinming Hu "Fail to drop packet");
97599ffe72cSXinming Hu }
97699ffe72cSXinming Hu }
97799ffe72cSXinming Hu }
97899ffe72cSXinming Hu
979eec679e4SGustavo A. R. Silva tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len);
980eec679e4SGustavo A. R. Silva tmp = (u8 *)tlv_rxba + sizeof(tlv_rxba->header) + tlv_len;
98199ffe72cSXinming Hu tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp;
98299ffe72cSXinming Hu }
98399ffe72cSXinming Hu }
984