xref: /linux/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c (revision 6396bb221514d2876fd6dc0aa2a1f240d99b37bb) !
15e6e3a92SBing Zhao /*
25e6e3a92SBing Zhao  * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
35e6e3a92SBing Zhao  *
465da33f5SXinming Hu  * Copyright (C) 2011-2014, Marvell International Ltd.
55e6e3a92SBing Zhao  *
65e6e3a92SBing Zhao  * This software file (the "File") is distributed by Marvell International
75e6e3a92SBing Zhao  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
85e6e3a92SBing Zhao  * (the "License").  You may use, redistribute and/or modify this File in
95e6e3a92SBing Zhao  * accordance with the terms and conditions of the License, a copy of which
105e6e3a92SBing Zhao  * is available by writing to the Free Software Foundation, Inc.,
115e6e3a92SBing Zhao  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
125e6e3a92SBing Zhao  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
135e6e3a92SBing Zhao  *
145e6e3a92SBing Zhao  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
155e6e3a92SBing Zhao  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
165e6e3a92SBing Zhao  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
175e6e3a92SBing Zhao  * this warranty disclaimer.
185e6e3a92SBing Zhao  */
195e6e3a92SBing Zhao 
205e6e3a92SBing Zhao #include "decl.h"
215e6e3a92SBing Zhao #include "ioctl.h"
225e6e3a92SBing Zhao #include "util.h"
235e6e3a92SBing Zhao #include "fw.h"
245e6e3a92SBing Zhao #include "main.h"
255e6e3a92SBing Zhao #include "wmm.h"
265e6e3a92SBing Zhao #include "11n.h"
275e6e3a92SBing Zhao #include "11n_rxreorder.h"
285e6e3a92SBing Zhao 
294c9f9fb2SAmitkumar Karwar /* This function will dispatch amsdu packet and forward it to kernel/upper
304c9f9fb2SAmitkumar Karwar  * layer.
314c9f9fb2SAmitkumar Karwar  */
324c9f9fb2SAmitkumar Karwar static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
334c9f9fb2SAmitkumar Karwar 					  struct sk_buff *skb)
344c9f9fb2SAmitkumar Karwar {
354c9f9fb2SAmitkumar Karwar 	struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
364c9f9fb2SAmitkumar Karwar 	int ret;
374c9f9fb2SAmitkumar Karwar 
384c9f9fb2SAmitkumar Karwar 	if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
394c9f9fb2SAmitkumar Karwar 		struct sk_buff_head list;
404c9f9fb2SAmitkumar Karwar 		struct sk_buff *rx_skb;
414c9f9fb2SAmitkumar Karwar 
424c9f9fb2SAmitkumar Karwar 		__skb_queue_head_init(&list);
434c9f9fb2SAmitkumar Karwar 
444c9f9fb2SAmitkumar Karwar 		skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
454c9f9fb2SAmitkumar Karwar 		skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
464c9f9fb2SAmitkumar Karwar 
474c9f9fb2SAmitkumar Karwar 		ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
488b935ee2SJohannes Berg 					 priv->wdev.iftype, 0, NULL, NULL);
494c9f9fb2SAmitkumar Karwar 
504c9f9fb2SAmitkumar Karwar 		while (!skb_queue_empty(&list)) {
51776f7420SAmitkumar Karwar 			struct rx_packet_hdr *rx_hdr;
52776f7420SAmitkumar Karwar 
534c9f9fb2SAmitkumar Karwar 			rx_skb = __skb_dequeue(&list);
54776f7420SAmitkumar Karwar 			rx_hdr = (struct rx_packet_hdr *)rx_skb->data;
55776f7420SAmitkumar Karwar 			if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
56776f7420SAmitkumar Karwar 			    ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
57776f7420SAmitkumar Karwar 				mwifiex_process_tdls_action_frame(priv,
58776f7420SAmitkumar Karwar 								  (u8 *)rx_hdr,
59776f7420SAmitkumar Karwar 								  skb->len);
60776f7420SAmitkumar Karwar 			}
61776f7420SAmitkumar Karwar 
62bf00dc22SXinming Hu 			if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
63bf00dc22SXinming Hu 				ret = mwifiex_uap_recv_packet(priv, rx_skb);
64bf00dc22SXinming Hu 			else
654c9f9fb2SAmitkumar Karwar 				ret = mwifiex_recv_packet(priv, rx_skb);
664c9f9fb2SAmitkumar Karwar 			if (ret == -1)
67acebe8c1SZhaoyang Liu 				mwifiex_dbg(priv->adapter, ERROR,
684c9f9fb2SAmitkumar Karwar 					    "Rx of A-MSDU failed");
694c9f9fb2SAmitkumar Karwar 		}
704c9f9fb2SAmitkumar Karwar 		return 0;
714c9f9fb2SAmitkumar Karwar 	}
724c9f9fb2SAmitkumar Karwar 
734c9f9fb2SAmitkumar Karwar 	return -1;
744c9f9fb2SAmitkumar Karwar }
754c9f9fb2SAmitkumar Karwar 
765e6e43ebSAmitkumar Karwar /* This function will process the rx packet and forward it to kernel/upper
775e6e43ebSAmitkumar Karwar  * layer.
785e6e43ebSAmitkumar Karwar  */
795e6e43ebSAmitkumar Karwar static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
805e6e43ebSAmitkumar Karwar {
814c9f9fb2SAmitkumar Karwar 
8299ffe72cSXinming Hu 	int ret;
8399ffe72cSXinming Hu 
8499ffe72cSXinming Hu 	if (!payload) {
8599ffe72cSXinming Hu 		mwifiex_dbg(priv->adapter, INFO, "info: fw drop data\n");
8699ffe72cSXinming Hu 		return 0;
8799ffe72cSXinming Hu 	}
8899ffe72cSXinming Hu 
8999ffe72cSXinming Hu 	ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
904c9f9fb2SAmitkumar Karwar 	if (!ret)
914c9f9fb2SAmitkumar Karwar 		return 0;
924c9f9fb2SAmitkumar Karwar 
935e6e43ebSAmitkumar Karwar 	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
945e6e43ebSAmitkumar Karwar 		return mwifiex_handle_uap_rx_forward(priv, payload);
955e6e43ebSAmitkumar Karwar 
965e6e43ebSAmitkumar Karwar 	return mwifiex_process_rx_packet(priv, payload);
975e6e43ebSAmitkumar Karwar }
985e6e43ebSAmitkumar Karwar 
995e6e3a92SBing Zhao /*
1008c00228eSYogesh Ashok Powar  * This function dispatches all packets in the Rx reorder table until the
1018c00228eSYogesh Ashok Powar  * start window.
1025e6e3a92SBing Zhao  *
1035e6e3a92SBing Zhao  * There could be holes in the buffer, which are skipped by the function.
1045e6e3a92SBing Zhao  * Since the buffer is linear, the function uses rotation to simulate
1055e6e3a92SBing Zhao  * circular buffer.
1065e6e3a92SBing Zhao  */
107ab581472SYogesh Ashok Powar static void
1085e6e43ebSAmitkumar Karwar mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
1095e6e43ebSAmitkumar Karwar 					 struct mwifiex_rx_reorder_tbl *tbl,
1105e6e43ebSAmitkumar Karwar 					 int start_win)
1115e6e3a92SBing Zhao {
1128c00228eSYogesh Ashok Powar 	int pkt_to_send, i;
113270e58e8SYogesh Ashok Powar 	void *rx_tmp_ptr;
1145e6e3a92SBing Zhao 	unsigned long flags;
1155e6e3a92SBing Zhao 
1168c00228eSYogesh Ashok Powar 	pkt_to_send = (start_win > tbl->start_win) ?
1178c00228eSYogesh Ashok Powar 		      min((start_win - tbl->start_win), tbl->win_size) :
1188c00228eSYogesh Ashok Powar 		      tbl->win_size;
1195e6e3a92SBing Zhao 
1208c00228eSYogesh Ashok Powar 	for (i = 0; i < pkt_to_send; ++i) {
1215e6e3a92SBing Zhao 		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
1225e6e3a92SBing Zhao 		rx_tmp_ptr = NULL;
1238c00228eSYogesh Ashok Powar 		if (tbl->rx_reorder_ptr[i]) {
1248c00228eSYogesh Ashok Powar 			rx_tmp_ptr = tbl->rx_reorder_ptr[i];
1258c00228eSYogesh Ashok Powar 			tbl->rx_reorder_ptr[i] = NULL;
1265e6e3a92SBing Zhao 		}
1275e6e3a92SBing Zhao 		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1285e6e43ebSAmitkumar Karwar 		if (rx_tmp_ptr)
1295e6e43ebSAmitkumar Karwar 			mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
1305e6e3a92SBing Zhao 	}
1315e6e3a92SBing Zhao 
1325e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
1335e6e3a92SBing Zhao 	/*
1345e6e3a92SBing Zhao 	 * We don't have a circular buffer, hence use rotation to simulate
1355e6e3a92SBing Zhao 	 * circular buffer
1365e6e3a92SBing Zhao 	 */
1378c00228eSYogesh Ashok Powar 	for (i = 0; i < tbl->win_size - pkt_to_send; ++i) {
1388c00228eSYogesh Ashok Powar 		tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i];
1398c00228eSYogesh Ashok Powar 		tbl->rx_reorder_ptr[pkt_to_send + i] = NULL;
1405e6e3a92SBing Zhao 	}
1415e6e3a92SBing Zhao 
1428c00228eSYogesh Ashok Powar 	tbl->start_win = start_win;
1435e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1445e6e3a92SBing Zhao }
1455e6e3a92SBing Zhao 
1465e6e3a92SBing Zhao /*
1475e6e3a92SBing Zhao  * This function dispatches all packets in the Rx reorder table until
1485e6e3a92SBing Zhao  * a hole is found.
1495e6e3a92SBing Zhao  *
1505e6e3a92SBing Zhao  * The start window is adjusted automatically when a hole is located.
1515e6e3a92SBing Zhao  * Since the buffer is linear, the function uses rotation to simulate
1525e6e3a92SBing Zhao  * circular buffer.
1535e6e3a92SBing Zhao  */
154ab581472SYogesh Ashok Powar static void
1555e6e3a92SBing Zhao mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
1568c00228eSYogesh Ashok Powar 			      struct mwifiex_rx_reorder_tbl *tbl)
1575e6e3a92SBing Zhao {
1585e6e3a92SBing Zhao 	int i, j, xchg;
159270e58e8SYogesh Ashok Powar 	void *rx_tmp_ptr;
1605e6e3a92SBing Zhao 	unsigned long flags;
1615e6e3a92SBing Zhao 
1628c00228eSYogesh Ashok Powar 	for (i = 0; i < tbl->win_size; ++i) {
1635e6e3a92SBing Zhao 		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
1648c00228eSYogesh Ashok Powar 		if (!tbl->rx_reorder_ptr[i]) {
1655e6e3a92SBing Zhao 			spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1665e6e3a92SBing Zhao 			break;
1675e6e3a92SBing Zhao 		}
1688c00228eSYogesh Ashok Powar 		rx_tmp_ptr = tbl->rx_reorder_ptr[i];
1698c00228eSYogesh Ashok Powar 		tbl->rx_reorder_ptr[i] = NULL;
1705e6e3a92SBing Zhao 		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1715e6e43ebSAmitkumar Karwar 		mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
1725e6e3a92SBing Zhao 	}
1735e6e3a92SBing Zhao 
1745e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
1755e6e3a92SBing Zhao 	/*
1765e6e3a92SBing Zhao 	 * We don't have a circular buffer, hence use rotation to simulate
1775e6e3a92SBing Zhao 	 * circular buffer
1785e6e3a92SBing Zhao 	 */
1795e6e3a92SBing Zhao 	if (i > 0) {
1808c00228eSYogesh Ashok Powar 		xchg = tbl->win_size - i;
1815e6e3a92SBing Zhao 		for (j = 0; j < xchg; ++j) {
1828c00228eSYogesh Ashok Powar 			tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j];
1838c00228eSYogesh Ashok Powar 			tbl->rx_reorder_ptr[i + j] = NULL;
1845e6e3a92SBing Zhao 		}
1855e6e3a92SBing Zhao 	}
1868c00228eSYogesh Ashok Powar 	tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
1875e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1885e6e3a92SBing Zhao }
1895e6e3a92SBing Zhao 
1905e6e3a92SBing Zhao /*
1915e6e3a92SBing Zhao  * This function deletes the Rx reorder table and frees the memory.
1925e6e3a92SBing Zhao  *
1935e6e3a92SBing Zhao  * The function stops the associated timer and dispatches all the
1945e6e3a92SBing Zhao  * pending packets in the Rx reorder table before deletion.
1955e6e3a92SBing Zhao  */
1965e6e3a92SBing Zhao static void
1978c00228eSYogesh Ashok Powar mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
1988c00228eSYogesh Ashok Powar 			     struct mwifiex_rx_reorder_tbl *tbl)
1995e6e3a92SBing Zhao {
2005e6e3a92SBing Zhao 	unsigned long flags;
20163410c37SAmitkumar Karwar 	int start_win;
2025e6e3a92SBing Zhao 
2038c00228eSYogesh Ashok Powar 	if (!tbl)
2045e6e3a92SBing Zhao 		return;
2055e6e3a92SBing Zhao 
2066e251174SAvinash Patil 	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
2076e251174SAvinash Patil 	priv->adapter->rx_locked = true;
2086e251174SAvinash Patil 	if (priv->adapter->rx_processing) {
2096e251174SAvinash Patil 		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
2106e251174SAvinash Patil 		flush_workqueue(priv->adapter->rx_workqueue);
2116e251174SAvinash Patil 	} else {
2126e251174SAvinash Patil 		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
2136e251174SAvinash Patil 	}
2146e251174SAvinash Patil 
21563410c37SAmitkumar Karwar 	start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
2165e6e43ebSAmitkumar Karwar 	mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
2175e6e3a92SBing Zhao 
218629873f2SAvinash Patil 	del_timer_sync(&tbl->timer_context.timer);
2193a8fede1SMarc Yang 	tbl->timer_context.timer_is_set = false;
2205e6e3a92SBing Zhao 
2215e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2228c00228eSYogesh Ashok Powar 	list_del(&tbl->list);
2235e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
2245e6e3a92SBing Zhao 
2258c00228eSYogesh Ashok Powar 	kfree(tbl->rx_reorder_ptr);
2268c00228eSYogesh Ashok Powar 	kfree(tbl);
2276e251174SAvinash Patil 
2286e251174SAvinash Patil 	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
2296e251174SAvinash Patil 	priv->adapter->rx_locked = false;
2306e251174SAvinash Patil 	spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
2316e251174SAvinash Patil 
2325e6e3a92SBing Zhao }
2335e6e3a92SBing Zhao 
2345e6e3a92SBing Zhao /*
2355e6e3a92SBing Zhao  * This function returns the pointer to an entry in Rx reordering
2365e6e3a92SBing Zhao  * table which matches the given TA/TID pair.
2375e6e3a92SBing Zhao  */
238d1cf3b95SAvinash Patil struct mwifiex_rx_reorder_tbl *
2395e6e3a92SBing Zhao mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
2405e6e3a92SBing Zhao {
2418c00228eSYogesh Ashok Powar 	struct mwifiex_rx_reorder_tbl *tbl;
2425e6e3a92SBing Zhao 	unsigned long flags;
2435e6e3a92SBing Zhao 
2445e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2458c00228eSYogesh Ashok Powar 	list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
2468c00228eSYogesh Ashok Powar 		if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
2475e6e3a92SBing Zhao 			spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
2485e6e3a92SBing Zhao 					       flags);
2498c00228eSYogesh Ashok Powar 			return tbl;
2505e6e3a92SBing Zhao 		}
2515e6e3a92SBing Zhao 	}
2525e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
2535e6e3a92SBing Zhao 
2545e6e3a92SBing Zhao 	return NULL;
2555e6e3a92SBing Zhao }
2565e6e3a92SBing Zhao 
2573e238a11SAvinash Patil /* This function retrieves the pointer to an entry in Rx reordering
2583e238a11SAvinash Patil  * table which matches the given TA and deletes it.
2593e238a11SAvinash Patil  */
2603e238a11SAvinash Patil void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
2613e238a11SAvinash Patil {
2623e238a11SAvinash Patil 	struct mwifiex_rx_reorder_tbl *tbl, *tmp;
2633e238a11SAvinash Patil 	unsigned long flags;
2643e238a11SAvinash Patil 
2653e238a11SAvinash Patil 	if (!ta)
2663e238a11SAvinash Patil 		return;
2673e238a11SAvinash Patil 
2683e238a11SAvinash Patil 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2693e238a11SAvinash Patil 	list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
2703e238a11SAvinash Patil 		if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
2713e238a11SAvinash Patil 			spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
2723e238a11SAvinash Patil 					       flags);
2733e238a11SAvinash Patil 			mwifiex_del_rx_reorder_entry(priv, tbl);
2743e238a11SAvinash Patil 			spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2753e238a11SAvinash Patil 		}
2763e238a11SAvinash Patil 	}
2773e238a11SAvinash Patil 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
2783e238a11SAvinash Patil 
2793e238a11SAvinash Patil 	return;
2803e238a11SAvinash Patil }
2813e238a11SAvinash Patil 
2825e6e3a92SBing Zhao /*
2835e6e3a92SBing Zhao  * This function finds the last sequence number used in the packets
2845e6e3a92SBing Zhao  * buffered in Rx reordering table.
2855e6e3a92SBing Zhao  */
2865e6e3a92SBing Zhao static int
2872d702830SAmitkumar Karwar mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
2885e6e3a92SBing Zhao {
2892d702830SAmitkumar Karwar 	struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
2902d702830SAmitkumar Karwar 	struct mwifiex_private *priv = ctx->priv;
2912d702830SAmitkumar Karwar 	unsigned long flags;
2925e6e3a92SBing Zhao 	int i;
2935e6e3a92SBing Zhao 
2942d702830SAmitkumar Karwar 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2952d702830SAmitkumar Karwar 	for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
2962d702830SAmitkumar Karwar 		if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
2972d702830SAmitkumar Karwar 			spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
2982d702830SAmitkumar Karwar 					       flags);
2995e6e3a92SBing Zhao 			return i;
3002d702830SAmitkumar Karwar 		}
3012d702830SAmitkumar Karwar 	}
3022d702830SAmitkumar Karwar 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
3035e6e3a92SBing Zhao 
3045e6e3a92SBing Zhao 	return -1;
3055e6e3a92SBing Zhao }
3065e6e3a92SBing Zhao 
3075e6e3a92SBing Zhao /*
3085e6e3a92SBing Zhao  * This function flushes all the packets in Rx reordering table.
3095e6e3a92SBing Zhao  *
3105e6e3a92SBing Zhao  * The function checks if any packets are currently buffered in the
3115e6e3a92SBing Zhao  * table or not. In case there are packets available, it dispatches
3125e6e3a92SBing Zhao  * them and then dumps the Rx reordering table.
3135e6e3a92SBing Zhao  */
3145e6e3a92SBing Zhao static void
31508c2eb8eSKees Cook mwifiex_flush_data(struct timer_list *t)
3165e6e3a92SBing Zhao {
3178c00228eSYogesh Ashok Powar 	struct reorder_tmr_cnxt *ctx =
31808c2eb8eSKees Cook 		from_timer(ctx, t, timer);
31963410c37SAmitkumar Karwar 	int start_win, seq_num;
3205e6e3a92SBing Zhao 
3213a8fede1SMarc Yang 	ctx->timer_is_set = false;
3222d702830SAmitkumar Karwar 	seq_num = mwifiex_11n_find_last_seq_num(ctx);
323bb7de2baSYogesh Ashok Powar 
32463410c37SAmitkumar Karwar 	if (seq_num < 0)
325bb7de2baSYogesh Ashok Powar 		return;
326bb7de2baSYogesh Ashok Powar 
327acebe8c1SZhaoyang Liu 	mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
32863410c37SAmitkumar Karwar 	start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
3295e6e43ebSAmitkumar Karwar 	mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
3305e6e43ebSAmitkumar Karwar 						 start_win);
3315e6e3a92SBing Zhao }
3325e6e3a92SBing Zhao 
3335e6e3a92SBing Zhao /*
3345e6e3a92SBing Zhao  * This function creates an entry in Rx reordering table for the
3355e6e3a92SBing Zhao  * given TA/TID.
3365e6e3a92SBing Zhao  *
3375e6e3a92SBing Zhao  * The function also initializes the entry with sequence number, window
3385e6e3a92SBing Zhao  * size as well as initializes the timer.
3395e6e3a92SBing Zhao  *
3405e6e3a92SBing Zhao  * If the received TA/TID pair is already present, all the packets are
3415e6e3a92SBing Zhao  * dispatched and the window size is moved until the SSN.
3425e6e3a92SBing Zhao  */
3435e6e3a92SBing Zhao static void
3445e6e3a92SBing Zhao mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
3455e6e3a92SBing Zhao 				  int tid, int win_size, int seq_num)
3465e6e3a92SBing Zhao {
3475e6e3a92SBing Zhao 	int i;
3488c00228eSYogesh Ashok Powar 	struct mwifiex_rx_reorder_tbl *tbl, *new_node;
3495e6e3a92SBing Zhao 	u16 last_seq = 0;
3505e6e3a92SBing Zhao 	unsigned long flags;
3515a009adfSAvinash Patil 	struct mwifiex_sta_node *node;
3525e6e3a92SBing Zhao 
3535e6e3a92SBing Zhao 	/*
3545e6e3a92SBing Zhao 	 * If we get a TID, ta pair which is already present dispatch all the
3555e6e3a92SBing Zhao 	 * the packets and move the window size until the ssn
3565e6e3a92SBing Zhao 	 */
3578c00228eSYogesh Ashok Powar 	tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
3588c00228eSYogesh Ashok Powar 	if (tbl) {
3595e6e43ebSAmitkumar Karwar 		mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
3605e6e3a92SBing Zhao 		return;
3615e6e3a92SBing Zhao 	}
3628c00228eSYogesh Ashok Powar 	/* if !tbl then create one */
3635e6e3a92SBing Zhao 	new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
3640d2e7a5cSJoe Perches 	if (!new_node)
3655e6e3a92SBing Zhao 		return;
3665e6e3a92SBing Zhao 
3675e6e3a92SBing Zhao 	INIT_LIST_HEAD(&new_node->list);
3685e6e3a92SBing Zhao 	new_node->tid = tid;
3695e6e3a92SBing Zhao 	memcpy(new_node->ta, ta, ETH_ALEN);
3705e6e3a92SBing Zhao 	new_node->start_win = seq_num;
3718acbea61SPaul Stewart 	new_node->init_win = seq_num;
3728acbea61SPaul Stewart 	new_node->flags = 0;
3735a009adfSAvinash Patil 
374c11fb985SAvinash Patil 	spin_lock_irqsave(&priv->sta_list_spinlock, flags);
3755a009adfSAvinash Patil 	if (mwifiex_queuing_ra_based(priv)) {
3765a009adfSAvinash Patil 		if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
3775a009adfSAvinash Patil 			node = mwifiex_get_sta_entry(priv, ta);
3785a009adfSAvinash Patil 			if (node)
3795a009adfSAvinash Patil 				last_seq = node->rx_seq[tid];
3805a009adfSAvinash Patil 		}
3815a009adfSAvinash Patil 	} else {
382daeb5bb4SAvinash Patil 		node = mwifiex_get_sta_entry(priv, ta);
383daeb5bb4SAvinash Patil 		if (node)
384daeb5bb4SAvinash Patil 			last_seq = node->rx_seq[tid];
385daeb5bb4SAvinash Patil 		else
3865e6e3a92SBing Zhao 			last_seq = priv->rx_seq[tid];
3875a009adfSAvinash Patil 	}
388c11fb985SAvinash Patil 	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
3895e6e3a92SBing Zhao 
390acebe8c1SZhaoyang Liu 	mwifiex_dbg(priv->adapter, INFO,
391acebe8c1SZhaoyang Liu 		    "info: last_seq=%d start_win=%d\n",
39209bd1976SAvinash Patil 		    last_seq, new_node->start_win);
39309bd1976SAvinash Patil 
39492583924SStone Piao 	if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
3958acbea61SPaul Stewart 	    last_seq >= new_node->start_win) {
3965e6e3a92SBing Zhao 		new_node->start_win = last_seq + 1;
3978acbea61SPaul Stewart 		new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
3988acbea61SPaul Stewart 	}
3995e6e3a92SBing Zhao 
4005e6e3a92SBing Zhao 	new_node->win_size = win_size;
4015e6e3a92SBing Zhao 
402*6396bb22SKees Cook 	new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *),
4035e6e3a92SBing Zhao 					   GFP_KERNEL);
4045e6e3a92SBing Zhao 	if (!new_node->rx_reorder_ptr) {
4055e6e3a92SBing Zhao 		kfree((u8 *) new_node);
406acebe8c1SZhaoyang Liu 		mwifiex_dbg(priv->adapter, ERROR,
4075e6e3a92SBing Zhao 			    "%s: failed to alloc reorder_ptr\n", __func__);
4085e6e3a92SBing Zhao 		return;
4095e6e3a92SBing Zhao 	}
4105e6e3a92SBing Zhao 
4115e6e3a92SBing Zhao 	new_node->timer_context.ptr = new_node;
4125e6e3a92SBing Zhao 	new_node->timer_context.priv = priv;
4133a8fede1SMarc Yang 	new_node->timer_context.timer_is_set = false;
4145e6e3a92SBing Zhao 
41508c2eb8eSKees Cook 	timer_setup(&new_node->timer_context.timer, mwifiex_flush_data, 0);
4165e6e3a92SBing Zhao 
4175e6e3a92SBing Zhao 	for (i = 0; i < win_size; ++i)
4185e6e3a92SBing Zhao 		new_node->rx_reorder_ptr[i] = NULL;
4195e6e3a92SBing Zhao 
4205e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
4215e6e3a92SBing Zhao 	list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
4225e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
4235e6e3a92SBing Zhao }
4245e6e3a92SBing Zhao 
4253a8fede1SMarc Yang static void
4263a8fede1SMarc Yang mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
4273a8fede1SMarc Yang {
4283a8fede1SMarc Yang 	u32 min_flush_time;
4293a8fede1SMarc Yang 
4303a8fede1SMarc Yang 	if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
4313a8fede1SMarc Yang 		min_flush_time = MIN_FLUSH_TIMER_15_MS;
4323a8fede1SMarc Yang 	else
4333a8fede1SMarc Yang 		min_flush_time = MIN_FLUSH_TIMER_MS;
4343a8fede1SMarc Yang 
4353a8fede1SMarc Yang 	mod_timer(&tbl->timer_context.timer,
4363a8fede1SMarc Yang 		  jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
4373a8fede1SMarc Yang 
4383a8fede1SMarc Yang 	tbl->timer_context.timer_is_set = true;
4393a8fede1SMarc Yang }
4403a8fede1SMarc Yang 
4415e6e3a92SBing Zhao /*
4425e6e3a92SBing Zhao  * This function prepares command for adding a BA request.
4435e6e3a92SBing Zhao  *
4445e6e3a92SBing Zhao  * Preparation includes -
4455e6e3a92SBing Zhao  *      - Setting command ID and proper size
4465e6e3a92SBing Zhao  *      - Setting add BA request buffer
4475e6e3a92SBing Zhao  *      - Ensuring correct endian-ness
4485e6e3a92SBing Zhao  */
449572e8f3eSAmitkumar Karwar int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
4505e6e3a92SBing Zhao {
4512c208890SJoe Perches 	struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
4525e6e3a92SBing Zhao 
4535e6e3a92SBing Zhao 	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
4545e6e3a92SBing Zhao 	cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
4555e6e3a92SBing Zhao 	memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
4565e6e3a92SBing Zhao 
4575e6e3a92SBing Zhao 	return 0;
4585e6e3a92SBing Zhao }
4595e6e3a92SBing Zhao 
4605e6e3a92SBing Zhao /*
4615e6e3a92SBing Zhao  * This function prepares command for adding a BA response.
4625e6e3a92SBing Zhao  *
4635e6e3a92SBing Zhao  * Preparation includes -
4645e6e3a92SBing Zhao  *      - Setting command ID and proper size
4655e6e3a92SBing Zhao  *      - Setting add BA response buffer
4665e6e3a92SBing Zhao  *      - Ensuring correct endian-ness
4675e6e3a92SBing Zhao  */
4685e6e3a92SBing Zhao int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
4695e6e3a92SBing Zhao 				  struct host_cmd_ds_command *cmd,
470a5ffddb7SAmitkumar Karwar 				  struct host_cmd_ds_11n_addba_req
471a5ffddb7SAmitkumar Karwar 				  *cmd_addba_req)
4725e6e3a92SBing Zhao {
4732c208890SJoe Perches 	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
474b06c5321SAvinash Patil 	struct mwifiex_sta_node *sta_ptr;
475b06c5321SAvinash Patil 	u32 rx_win_size = priv->add_ba_param.rx_win_size;
476270e58e8SYogesh Ashok Powar 	u8 tid;
477270e58e8SYogesh Ashok Powar 	int win_size;
478c11fb985SAvinash Patil 	unsigned long flags;
4795e6e3a92SBing Zhao 	uint16_t block_ack_param_set;
4805e6e3a92SBing Zhao 
481b06c5321SAvinash Patil 	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
482b06c5321SAvinash Patil 	    ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
483b06c5321SAvinash Patil 	    priv->adapter->is_hw_11ac_capable &&
484b06c5321SAvinash Patil 	    memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
485c11fb985SAvinash Patil 		spin_lock_irqsave(&priv->sta_list_spinlock, flags);
486b06c5321SAvinash Patil 		sta_ptr = mwifiex_get_sta_entry(priv,
487b06c5321SAvinash Patil 						cmd_addba_req->peer_mac_addr);
488b06c5321SAvinash Patil 		if (!sta_ptr) {
48909bd1976SAvinash Patil 			spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
490acebe8c1SZhaoyang Liu 			mwifiex_dbg(priv->adapter, ERROR,
491b06c5321SAvinash Patil 				    "BA setup with unknown TDLS peer %pM!\n",
492b06c5321SAvinash Patil 				    cmd_addba_req->peer_mac_addr);
493b06c5321SAvinash Patil 			return -1;
494b06c5321SAvinash Patil 		}
495b06c5321SAvinash Patil 		if (sta_ptr->is_11ac_enabled)
496b06c5321SAvinash Patil 			rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
497c11fb985SAvinash Patil 		spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
498b06c5321SAvinash Patil 	}
499b06c5321SAvinash Patil 
5005e6e3a92SBing Zhao 	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
5015e6e3a92SBing Zhao 	cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
5025e6e3a92SBing Zhao 
5035e6e3a92SBing Zhao 	memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
5045e6e3a92SBing Zhao 	       ETH_ALEN);
5055e6e3a92SBing Zhao 	add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
5065e6e3a92SBing Zhao 	add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
5075e6e3a92SBing Zhao 	add_ba_rsp->ssn = cmd_addba_req->ssn;
5085e6e3a92SBing Zhao 
5095e6e3a92SBing Zhao 	block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
5105e6e3a92SBing Zhao 	tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
5115e6e3a92SBing Zhao 		>> BLOCKACKPARAM_TID_POS;
5125e6e3a92SBing Zhao 	add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
5135e6e3a92SBing Zhao 	block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
5144c9f9fb2SAmitkumar Karwar 
5154c9f9fb2SAmitkumar Karwar 	/* If we don't support AMSDU inside AMPDU, reset the bit */
5164c9f9fb2SAmitkumar Karwar 	if (!priv->add_ba_param.rx_amsdu ||
5174c9f9fb2SAmitkumar Karwar 	    (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
5185e6e3a92SBing Zhao 		block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
519b06c5321SAvinash Patil 	block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
5205e6e3a92SBing Zhao 	add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
5215e6e3a92SBing Zhao 	win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
5225e6e3a92SBing Zhao 					& IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
5235e6e3a92SBing Zhao 					>> BLOCKACKPARAM_WINSIZE_POS;
5245e6e3a92SBing Zhao 	cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
5255e6e3a92SBing Zhao 
5265e6e3a92SBing Zhao 	mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
52784266841SYogesh Ashok Powar 					  tid, win_size,
52884266841SYogesh Ashok Powar 					  le16_to_cpu(cmd_addba_req->ssn));
5295e6e3a92SBing Zhao 	return 0;
5305e6e3a92SBing Zhao }
5315e6e3a92SBing Zhao 
5325e6e3a92SBing Zhao /*
5335e6e3a92SBing Zhao  * This function prepares command for deleting a BA request.
5345e6e3a92SBing Zhao  *
5355e6e3a92SBing Zhao  * Preparation includes -
5365e6e3a92SBing Zhao  *      - Setting command ID and proper size
5375e6e3a92SBing Zhao  *      - Setting del BA request buffer
5385e6e3a92SBing Zhao  *      - Ensuring correct endian-ness
5395e6e3a92SBing Zhao  */
540572e8f3eSAmitkumar Karwar int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
5415e6e3a92SBing Zhao {
5422c208890SJoe Perches 	struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
5435e6e3a92SBing Zhao 
5445e6e3a92SBing Zhao 	cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
5455e6e3a92SBing Zhao 	cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
5465e6e3a92SBing Zhao 	memcpy(del_ba, data_buf, sizeof(*del_ba));
5475e6e3a92SBing Zhao 
5485e6e3a92SBing Zhao 	return 0;
5495e6e3a92SBing Zhao }
5505e6e3a92SBing Zhao 
5515e6e3a92SBing Zhao /*
5525e6e3a92SBing Zhao  * This function identifies if Rx reordering is needed for a received packet.
5535e6e3a92SBing Zhao  *
5545e6e3a92SBing Zhao  * In case reordering is required, the function will do the reordering
5555e6e3a92SBing Zhao  * before sending it to kernel.
5565e6e3a92SBing Zhao  *
5575e6e3a92SBing Zhao  * The Rx reorder table is checked first with the received TID/TA pair. If
5585e6e3a92SBing Zhao  * not found, the received packet is dispatched immediately. But if found,
5595e6e3a92SBing Zhao  * the packet is reordered and all the packets in the updated Rx reordering
5605e6e3a92SBing Zhao  * table is dispatched until a hole is found.
5615e6e3a92SBing Zhao  *
5625e6e3a92SBing Zhao  * For sequence number less than the starting window, the packet is dropped.
5635e6e3a92SBing Zhao  */
5645e6e3a92SBing Zhao int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
5655e6e3a92SBing Zhao 				u16 seq_num, u16 tid,
5665e6e3a92SBing Zhao 				u8 *ta, u8 pkt_type, void *payload)
5675e6e3a92SBing Zhao {
5688c00228eSYogesh Ashok Powar 	struct mwifiex_rx_reorder_tbl *tbl;
5693a8fede1SMarc Yang 	int prev_start_win, start_win, end_win, win_size;
570270e58e8SYogesh Ashok Powar 	u16 pkt_index;
5718acbea61SPaul Stewart 	bool init_window_shift = false;
5723a8fede1SMarc Yang 	int ret = 0;
5735e6e3a92SBing Zhao 
5742c208890SJoe Perches 	tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
5758c00228eSYogesh Ashok Powar 	if (!tbl) {
5765e6e43ebSAmitkumar Karwar 		if (pkt_type != PKT_TYPE_BAR)
5775e6e43ebSAmitkumar Karwar 			mwifiex_11n_dispatch_pkt(priv, payload);
5783a8fede1SMarc Yang 		return ret;
5795e6e3a92SBing Zhao 	}
5804c9f9fb2SAmitkumar Karwar 
5814c9f9fb2SAmitkumar Karwar 	if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
5824c9f9fb2SAmitkumar Karwar 		mwifiex_11n_dispatch_pkt(priv, payload);
5833a8fede1SMarc Yang 		return ret;
5844c9f9fb2SAmitkumar Karwar 	}
5854c9f9fb2SAmitkumar Karwar 
5868c00228eSYogesh Ashok Powar 	start_win = tbl->start_win;
5873a8fede1SMarc Yang 	prev_start_win = start_win;
5888c00228eSYogesh Ashok Powar 	win_size = tbl->win_size;
5895e6e3a92SBing Zhao 	end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
5908acbea61SPaul Stewart 	if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
5918acbea61SPaul Stewart 		init_window_shift = true;
5928acbea61SPaul Stewart 		tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
5938acbea61SPaul Stewart 	}
5945e6e3a92SBing Zhao 
5952db96c3dSAvinash Patil 	if (tbl->flags & RXREOR_FORCE_NO_DROP) {
596acebe8c1SZhaoyang Liu 		mwifiex_dbg(priv->adapter, INFO,
5972db96c3dSAvinash Patil 			    "RXREOR_FORCE_NO_DROP when HS is activated\n");
5982db96c3dSAvinash Patil 		tbl->flags &= ~RXREOR_FORCE_NO_DROP;
5998acbea61SPaul Stewart 	} else if (init_window_shift && seq_num < start_win &&
6008acbea61SPaul Stewart 		   seq_num >= tbl->init_win) {
601acebe8c1SZhaoyang Liu 		mwifiex_dbg(priv->adapter, INFO,
6028acbea61SPaul Stewart 			    "Sender TID sequence number reset %d->%d for SSN %d\n",
6038acbea61SPaul Stewart 			    start_win, seq_num, tbl->init_win);
6048acbea61SPaul Stewart 		tbl->start_win = start_win = seq_num;
6058acbea61SPaul Stewart 		end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
6062db96c3dSAvinash Patil 	} else {
6078acbea61SPaul Stewart 		/*
6088acbea61SPaul Stewart 		 * If seq_num is less then starting win then ignore and drop
6098acbea61SPaul Stewart 		 * the packet
6108acbea61SPaul Stewart 		 */
6112db96c3dSAvinash Patil 		if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
61284266841SYogesh Ashok Powar 			if (seq_num >= ((start_win + TWOPOW11) &
6132db96c3dSAvinash Patil 					(MAX_TID_VALUE - 1)) &&
6143a8fede1SMarc Yang 			    seq_num < start_win) {
6153a8fede1SMarc Yang 				ret = -1;
6163a8fede1SMarc Yang 				goto done;
6173a8fede1SMarc Yang 			}
61884266841SYogesh Ashok Powar 		} else if ((seq_num < start_win) ||
6193a8fede1SMarc Yang 			   (seq_num >= (start_win + TWOPOW11))) {
6203a8fede1SMarc Yang 			ret = -1;
6213a8fede1SMarc Yang 			goto done;
6225e6e3a92SBing Zhao 		}
6232db96c3dSAvinash Patil 	}
6245e6e3a92SBing Zhao 
6255e6e3a92SBing Zhao 	/*
6265e6e3a92SBing Zhao 	 * If this packet is a BAR we adjust seq_num as
6275e6e3a92SBing Zhao 	 * WinStart = seq_num
6285e6e3a92SBing Zhao 	 */
6295e6e3a92SBing Zhao 	if (pkt_type == PKT_TYPE_BAR)
6305e6e3a92SBing Zhao 		seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
6315e6e3a92SBing Zhao 
63284266841SYogesh Ashok Powar 	if (((end_win < start_win) &&
6332db96c3dSAvinash Patil 	     (seq_num < start_win) && (seq_num > end_win)) ||
63484266841SYogesh Ashok Powar 	    ((end_win > start_win) && ((seq_num > end_win) ||
63584266841SYogesh Ashok Powar 				       (seq_num < start_win)))) {
6365e6e3a92SBing Zhao 		end_win = seq_num;
637cc751498SAndrzej Hajda 		if (((end_win - win_size) + 1) >= 0)
6385e6e3a92SBing Zhao 			start_win = (end_win - win_size) + 1;
6395e6e3a92SBing Zhao 		else
640cc751498SAndrzej Hajda 			start_win = (MAX_TID_VALUE - (win_size - end_win)) + 1;
6415e6e43ebSAmitkumar Karwar 		mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
6425e6e3a92SBing Zhao 	}
6435e6e3a92SBing Zhao 
6445e6e3a92SBing Zhao 	if (pkt_type != PKT_TYPE_BAR) {
6455e6e3a92SBing Zhao 		if (seq_num >= start_win)
6465e6e3a92SBing Zhao 			pkt_index = seq_num - start_win;
6475e6e3a92SBing Zhao 		else
6485e6e3a92SBing Zhao 			pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
6495e6e3a92SBing Zhao 
6503a8fede1SMarc Yang 		if (tbl->rx_reorder_ptr[pkt_index]) {
6513a8fede1SMarc Yang 			ret = -1;
6523a8fede1SMarc Yang 			goto done;
6533a8fede1SMarc Yang 		}
6545e6e3a92SBing Zhao 
6558c00228eSYogesh Ashok Powar 		tbl->rx_reorder_ptr[pkt_index] = payload;
6565e6e3a92SBing Zhao 	}
6575e6e3a92SBing Zhao 
6585e6e3a92SBing Zhao 	/*
6595e6e3a92SBing Zhao 	 * Dispatch all packets sequentially from start_win until a
6605e6e3a92SBing Zhao 	 * hole is found and adjust the start_win appropriately
6615e6e3a92SBing Zhao 	 */
6628c00228eSYogesh Ashok Powar 	mwifiex_11n_scan_and_dispatch(priv, tbl);
6635e6e3a92SBing Zhao 
6643a8fede1SMarc Yang done:
6653a8fede1SMarc Yang 	if (!tbl->timer_context.timer_is_set ||
6663a8fede1SMarc Yang 	    prev_start_win != tbl->start_win)
6673a8fede1SMarc Yang 		mwifiex_11n_rxreorder_timer_restart(tbl);
6683a8fede1SMarc Yang 	return ret;
6695e6e3a92SBing Zhao }
6705e6e3a92SBing Zhao 
6715e6e3a92SBing Zhao /*
6725e6e3a92SBing Zhao  * This function deletes an entry for a given TID/TA pair.
6735e6e3a92SBing Zhao  *
6745e6e3a92SBing Zhao  * The TID/TA are taken from del BA event body.
6755e6e3a92SBing Zhao  */
6765e6e3a92SBing Zhao void
6773e822635SYogesh Ashok Powar mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
6783e822635SYogesh Ashok Powar 		   u8 type, int initiator)
6795e6e3a92SBing Zhao {
6808c00228eSYogesh Ashok Powar 	struct mwifiex_rx_reorder_tbl *tbl;
6815e6e3a92SBing Zhao 	struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
68239df5e82SZhaoyang Liu 	struct mwifiex_ra_list_tbl *ra_list;
6835e6e3a92SBing Zhao 	u8 cleanup_rx_reorder_tbl;
6845e6e3a92SBing Zhao 	unsigned long flags;
685719a25e3SXinming Hu 	int tid_down;
6865e6e3a92SBing Zhao 
6875e6e3a92SBing Zhao 	if (type == TYPE_DELBA_RECEIVE)
6885e6e3a92SBing Zhao 		cleanup_rx_reorder_tbl = (initiator) ? true : false;
6895e6e3a92SBing Zhao 	else
6905e6e3a92SBing Zhao 		cleanup_rx_reorder_tbl = (initiator) ? false : true;
6915e6e3a92SBing Zhao 
692acebe8c1SZhaoyang Liu 	mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
69384266841SYogesh Ashok Powar 		    peer_mac, tid, initiator);
6945e6e3a92SBing Zhao 
6955e6e3a92SBing Zhao 	if (cleanup_rx_reorder_tbl) {
6968c00228eSYogesh Ashok Powar 		tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
6975e6e3a92SBing Zhao 								 peer_mac);
6988c00228eSYogesh Ashok Powar 		if (!tbl) {
699acebe8c1SZhaoyang Liu 			mwifiex_dbg(priv->adapter, EVENT,
7005e6e3a92SBing Zhao 				    "event: TID, TA not found in table\n");
7015e6e3a92SBing Zhao 			return;
7025e6e3a92SBing Zhao 		}
7038c00228eSYogesh Ashok Powar 		mwifiex_del_rx_reorder_entry(priv, tbl);
7045e6e3a92SBing Zhao 	} else {
7053e822635SYogesh Ashok Powar 		ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
7065e6e3a92SBing Zhao 		if (!ptx_tbl) {
707acebe8c1SZhaoyang Liu 			mwifiex_dbg(priv->adapter, EVENT,
7085e6e3a92SBing Zhao 				    "event: TID, RA not found in table\n");
7095e6e3a92SBing Zhao 			return;
7105e6e3a92SBing Zhao 		}
711719a25e3SXinming Hu 
712719a25e3SXinming Hu 		tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
713719a25e3SXinming Hu 		ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
71439df5e82SZhaoyang Liu 		if (ra_list) {
71539df5e82SZhaoyang Liu 			ra_list->amsdu_in_ampdu = false;
71639df5e82SZhaoyang Liu 			ra_list->ba_status = BA_SETUP_NONE;
71739df5e82SZhaoyang Liu 		}
7185e6e3a92SBing Zhao 		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
7195e6e3a92SBing Zhao 		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
7205e6e3a92SBing Zhao 		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
7215e6e3a92SBing Zhao 	}
7225e6e3a92SBing Zhao }
7235e6e3a92SBing Zhao 
7245e6e3a92SBing Zhao /*
7255e6e3a92SBing Zhao  * This function handles the command response of an add BA response.
7265e6e3a92SBing Zhao  *
7275e6e3a92SBing Zhao  * Handling includes changing the header fields into CPU format and
7285e6e3a92SBing Zhao  * creating the stream, provided the add BA is accepted.
7295e6e3a92SBing Zhao  */
7305e6e3a92SBing Zhao int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
7315e6e3a92SBing Zhao 			       struct host_cmd_ds_command *resp)
7325e6e3a92SBing Zhao {
7332c208890SJoe Perches 	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
7345e6e3a92SBing Zhao 	int tid, win_size;
7358c00228eSYogesh Ashok Powar 	struct mwifiex_rx_reorder_tbl *tbl;
7365e6e3a92SBing Zhao 	uint16_t block_ack_param_set;
7375e6e3a92SBing Zhao 
7385e6e3a92SBing Zhao 	block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
7395e6e3a92SBing Zhao 
7405e6e3a92SBing Zhao 	tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
7415e6e3a92SBing Zhao 		>> BLOCKACKPARAM_TID_POS;
7425e6e3a92SBing Zhao 	/*
7435e6e3a92SBing Zhao 	 * Check if we had rejected the ADDBA, if yes then do not create
7445e6e3a92SBing Zhao 	 * the stream
7455e6e3a92SBing Zhao 	 */
74663410c37SAmitkumar Karwar 	if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
747acebe8c1SZhaoyang Liu 		mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
7485e6e3a92SBing Zhao 			    add_ba_rsp->peer_mac_addr, tid);
7495e6e3a92SBing Zhao 
7508c00228eSYogesh Ashok Powar 		tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
7518c00228eSYogesh Ashok Powar 						     add_ba_rsp->peer_mac_addr);
7528c00228eSYogesh Ashok Powar 		if (tbl)
7538c00228eSYogesh Ashok Powar 			mwifiex_del_rx_reorder_entry(priv, tbl);
75463410c37SAmitkumar Karwar 
75563410c37SAmitkumar Karwar 		return 0;
7565e6e3a92SBing Zhao 	}
7575e6e3a92SBing Zhao 
75863410c37SAmitkumar Karwar 	win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
75963410c37SAmitkumar Karwar 		    >> BLOCKACKPARAM_WINSIZE_POS;
76063410c37SAmitkumar Karwar 
7614c9f9fb2SAmitkumar Karwar 	tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
7624c9f9fb2SAmitkumar Karwar 					     add_ba_rsp->peer_mac_addr);
7634c9f9fb2SAmitkumar Karwar 	if (tbl) {
7644c9f9fb2SAmitkumar Karwar 		if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
7654c9f9fb2SAmitkumar Karwar 		    priv->add_ba_param.rx_amsdu &&
7664c9f9fb2SAmitkumar Karwar 		    (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
7674c9f9fb2SAmitkumar Karwar 			tbl->amsdu = true;
7684c9f9fb2SAmitkumar Karwar 		else
7694c9f9fb2SAmitkumar Karwar 			tbl->amsdu = false;
7704c9f9fb2SAmitkumar Karwar 	}
7714c9f9fb2SAmitkumar Karwar 
772acebe8c1SZhaoyang Liu 	mwifiex_dbg(priv->adapter, CMD,
77363410c37SAmitkumar Karwar 		    "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
77463410c37SAmitkumar Karwar 		add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
77563410c37SAmitkumar Karwar 
7765e6e3a92SBing Zhao 	return 0;
7775e6e3a92SBing Zhao }
7785e6e3a92SBing Zhao 
7795e6e3a92SBing Zhao /*
7805e6e3a92SBing Zhao  * This function handles BA stream timeout event by preparing and sending
7815e6e3a92SBing Zhao  * a command to the firmware.
7825e6e3a92SBing Zhao  */
7835e6e3a92SBing Zhao void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
7845e6e3a92SBing Zhao 				   struct host_cmd_ds_11n_batimeout *event)
7855e6e3a92SBing Zhao {
7865e6e3a92SBing Zhao 	struct host_cmd_ds_11n_delba delba;
7875e6e3a92SBing Zhao 
7885e6e3a92SBing Zhao 	memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
7895e6e3a92SBing Zhao 	memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
7905e6e3a92SBing Zhao 
7915e6e3a92SBing Zhao 	delba.del_ba_param_set |=
7925e6e3a92SBing Zhao 		cpu_to_le16((u16) event->tid << DELBA_TID_POS);
7935e6e3a92SBing Zhao 	delba.del_ba_param_set |= cpu_to_le16(
7945e6e3a92SBing Zhao 		(u16) event->origninator << DELBA_INITIATOR_POS);
7955e6e3a92SBing Zhao 	delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
796fa0ecbb9SBing Zhao 	mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
7975e6e3a92SBing Zhao }
7985e6e3a92SBing Zhao 
7995e6e3a92SBing Zhao /*
8005e6e3a92SBing Zhao  * This function cleans up the Rx reorder table by deleting all the entries
8015e6e3a92SBing Zhao  * and re-initializing.
8025e6e3a92SBing Zhao  */
8035e6e3a92SBing Zhao void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
8045e6e3a92SBing Zhao {
8055e6e3a92SBing Zhao 	struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
8065e6e3a92SBing Zhao 	unsigned long flags;
8075e6e3a92SBing Zhao 
8085e6e3a92SBing Zhao 	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
8095e6e3a92SBing Zhao 	list_for_each_entry_safe(del_tbl_ptr, tmp_node,
8105e6e3a92SBing Zhao 				 &priv->rx_reorder_tbl_ptr, list) {
8115e6e3a92SBing Zhao 		spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
8128c00228eSYogesh Ashok Powar 		mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
8135e6e3a92SBing Zhao 		spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
8145e6e3a92SBing Zhao 	}
8152d702830SAmitkumar Karwar 	INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
8165e6e3a92SBing Zhao 	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
8175e6e3a92SBing Zhao 
81892583924SStone Piao 	mwifiex_reset_11n_rx_seq_num(priv);
8195e6e3a92SBing Zhao }
8202db96c3dSAvinash Patil 
8212db96c3dSAvinash Patil /*
8222db96c3dSAvinash Patil  * This function updates all rx_reorder_tbl's flags.
8232db96c3dSAvinash Patil  */
8242db96c3dSAvinash Patil void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
8252db96c3dSAvinash Patil {
8262db96c3dSAvinash Patil 	struct mwifiex_private *priv;
8272db96c3dSAvinash Patil 	struct mwifiex_rx_reorder_tbl *tbl;
8282db96c3dSAvinash Patil 	unsigned long lock_flags;
8292db96c3dSAvinash Patil 	int i;
8302db96c3dSAvinash Patil 
8312db96c3dSAvinash Patil 	for (i = 0; i < adapter->priv_num; i++) {
8322db96c3dSAvinash Patil 		priv = adapter->priv[i];
8332db96c3dSAvinash Patil 		if (!priv)
8342db96c3dSAvinash Patil 			continue;
8352db96c3dSAvinash Patil 
8362db96c3dSAvinash Patil 		spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
8372db96c3dSAvinash Patil 		list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
8382db96c3dSAvinash Patil 			tbl->flags = flags;
8392db96c3dSAvinash Patil 		spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
8402db96c3dSAvinash Patil 	}
8412db96c3dSAvinash Patil 
8422db96c3dSAvinash Patil 	return;
8432db96c3dSAvinash Patil }
844d219b7ebSChunfan Chen 
845d219b7ebSChunfan Chen /* This function update all the rx_win_size based on coex flag
846d219b7ebSChunfan Chen  */
847d219b7ebSChunfan Chen static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
848d219b7ebSChunfan Chen 					   bool coex_flag)
849d219b7ebSChunfan Chen {
850d219b7ebSChunfan Chen 	u8 i;
851d219b7ebSChunfan Chen 	u32 rx_win_size;
852d219b7ebSChunfan Chen 	struct mwifiex_private *priv;
853d219b7ebSChunfan Chen 
854d219b7ebSChunfan Chen 	dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
855d219b7ebSChunfan Chen 
856d219b7ebSChunfan Chen 	for (i = 0; i < adapter->priv_num; i++) {
857d219b7ebSChunfan Chen 		if (!adapter->priv[i])
858d219b7ebSChunfan Chen 			continue;
859d219b7ebSChunfan Chen 		priv = adapter->priv[i];
860d219b7ebSChunfan Chen 		rx_win_size = priv->add_ba_param.rx_win_size;
861d219b7ebSChunfan Chen 		if (coex_flag) {
862d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
863d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
864d219b7ebSChunfan Chen 					MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
865d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
866d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
867d219b7ebSChunfan Chen 					MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
868d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
869d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
870d219b7ebSChunfan Chen 					MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
871d219b7ebSChunfan Chen 		} else {
872d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
873d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
874d219b7ebSChunfan Chen 					MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
875d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
876d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
877d219b7ebSChunfan Chen 					MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
878d219b7ebSChunfan Chen 			if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
879d219b7ebSChunfan Chen 				priv->add_ba_param.rx_win_size =
880d219b7ebSChunfan Chen 					MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
881d219b7ebSChunfan Chen 		}
882d219b7ebSChunfan Chen 
883d219b7ebSChunfan Chen 		if (adapter->coex_win_size && adapter->coex_rx_win_size)
884d219b7ebSChunfan Chen 			priv->add_ba_param.rx_win_size =
885d219b7ebSChunfan Chen 					adapter->coex_rx_win_size;
886d219b7ebSChunfan Chen 
887d219b7ebSChunfan Chen 		if (rx_win_size != priv->add_ba_param.rx_win_size) {
888d219b7ebSChunfan Chen 			if (!priv->media_connected)
889d219b7ebSChunfan Chen 				continue;
890d219b7ebSChunfan Chen 			for (i = 0; i < MAX_NUM_TID; i++)
891d219b7ebSChunfan Chen 				mwifiex_11n_delba(priv, i);
892d219b7ebSChunfan Chen 		}
893d219b7ebSChunfan Chen 	}
894d219b7ebSChunfan Chen }
895d219b7ebSChunfan Chen 
896d219b7ebSChunfan Chen /* This function check coex for RX BA
897d219b7ebSChunfan Chen  */
898d219b7ebSChunfan Chen void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
899d219b7ebSChunfan Chen {
900d219b7ebSChunfan Chen 	u8 i;
901d219b7ebSChunfan Chen 	struct mwifiex_private *priv;
902d219b7ebSChunfan Chen 	u8 count = 0;
903d219b7ebSChunfan Chen 
904d219b7ebSChunfan Chen 	for (i = 0; i < adapter->priv_num; i++) {
905d219b7ebSChunfan Chen 		if (adapter->priv[i]) {
906d219b7ebSChunfan Chen 			priv = adapter->priv[i];
907d219b7ebSChunfan Chen 			if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
908d219b7ebSChunfan Chen 				if (priv->media_connected)
909d219b7ebSChunfan Chen 					count++;
910d219b7ebSChunfan Chen 			}
911d219b7ebSChunfan Chen 			if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
912d219b7ebSChunfan Chen 				if (priv->bss_started)
913d219b7ebSChunfan Chen 					count++;
914d219b7ebSChunfan Chen 			}
915d219b7ebSChunfan Chen 		}
916d219b7ebSChunfan Chen 		if (count >= MWIFIEX_BSS_COEX_COUNT)
917d219b7ebSChunfan Chen 			break;
918d219b7ebSChunfan Chen 	}
919d219b7ebSChunfan Chen 	if (count >= MWIFIEX_BSS_COEX_COUNT)
920d219b7ebSChunfan Chen 		mwifiex_update_ampdu_rxwinsize(adapter, true);
921d219b7ebSChunfan Chen 	else
922d219b7ebSChunfan Chen 		mwifiex_update_ampdu_rxwinsize(adapter, false);
923d219b7ebSChunfan Chen }
92499ffe72cSXinming Hu 
92599ffe72cSXinming Hu /* This function handles rxba_sync event
92699ffe72cSXinming Hu  */
92799ffe72cSXinming Hu void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
92899ffe72cSXinming Hu 				 u8 *event_buf, u16 len)
92999ffe72cSXinming Hu {
93099ffe72cSXinming Hu 	struct mwifiex_ie_types_rxba_sync *tlv_rxba = (void *)event_buf;
93199ffe72cSXinming Hu 	u16 tlv_type, tlv_len;
93299ffe72cSXinming Hu 	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
93399ffe72cSXinming Hu 	u8 i, j;
93499ffe72cSXinming Hu 	u16 seq_num, tlv_seq_num, tlv_bitmap_len;
93599ffe72cSXinming Hu 	int tlv_buf_left = len;
93699ffe72cSXinming Hu 	int ret;
93799ffe72cSXinming Hu 	u8 *tmp;
93899ffe72cSXinming Hu 
93999ffe72cSXinming Hu 	mwifiex_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:",
94099ffe72cSXinming Hu 			 event_buf, len);
94199ffe72cSXinming Hu 	while (tlv_buf_left >= sizeof(*tlv_rxba)) {
94299ffe72cSXinming Hu 		tlv_type = le16_to_cpu(tlv_rxba->header.type);
94399ffe72cSXinming Hu 		tlv_len  = le16_to_cpu(tlv_rxba->header.len);
94499ffe72cSXinming Hu 		if (tlv_type != TLV_TYPE_RXBA_SYNC) {
94599ffe72cSXinming Hu 			mwifiex_dbg(priv->adapter, ERROR,
94699ffe72cSXinming Hu 				    "Wrong TLV id=0x%x\n", tlv_type);
94799ffe72cSXinming Hu 			return;
94899ffe72cSXinming Hu 		}
94999ffe72cSXinming Hu 
95099ffe72cSXinming Hu 		tlv_seq_num = le16_to_cpu(tlv_rxba->seq_num);
95199ffe72cSXinming Hu 		tlv_bitmap_len = le16_to_cpu(tlv_rxba->bitmap_len);
95299ffe72cSXinming Hu 		mwifiex_dbg(priv->adapter, INFO,
95399ffe72cSXinming Hu 			    "%pM tid=%d seq_num=%d bitmap_len=%d\n",
95499ffe72cSXinming Hu 			    tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
95599ffe72cSXinming Hu 			    tlv_bitmap_len);
95699ffe72cSXinming Hu 
95799ffe72cSXinming Hu 		rx_reor_tbl_ptr =
95899ffe72cSXinming Hu 			mwifiex_11n_get_rx_reorder_tbl(priv, tlv_rxba->tid,
95999ffe72cSXinming Hu 						       tlv_rxba->mac);
96099ffe72cSXinming Hu 		if (!rx_reor_tbl_ptr) {
96199ffe72cSXinming Hu 			mwifiex_dbg(priv->adapter, ERROR,
96299ffe72cSXinming Hu 				    "Can not find rx_reorder_tbl!");
96399ffe72cSXinming Hu 			return;
96499ffe72cSXinming Hu 		}
96599ffe72cSXinming Hu 
96699ffe72cSXinming Hu 		for (i = 0; i < tlv_bitmap_len; i++) {
96799ffe72cSXinming Hu 			for (j = 0 ; j < 8; j++) {
96899ffe72cSXinming Hu 				if (tlv_rxba->bitmap[i] & (1 << j)) {
96999ffe72cSXinming Hu 					seq_num = (MAX_TID_VALUE - 1) &
97099ffe72cSXinming Hu 						(tlv_seq_num + i * 8 + j);
97199ffe72cSXinming Hu 
97299ffe72cSXinming Hu 					mwifiex_dbg(priv->adapter, ERROR,
97399ffe72cSXinming Hu 						    "drop packet,seq=%d\n",
97499ffe72cSXinming Hu 						    seq_num);
97599ffe72cSXinming Hu 
97699ffe72cSXinming Hu 					ret = mwifiex_11n_rx_reorder_pkt
97799ffe72cSXinming Hu 					(priv, seq_num, tlv_rxba->tid,
97899ffe72cSXinming Hu 					 tlv_rxba->mac, 0, NULL);
97999ffe72cSXinming Hu 
98099ffe72cSXinming Hu 					if (ret)
98199ffe72cSXinming Hu 						mwifiex_dbg(priv->adapter,
98299ffe72cSXinming Hu 							    ERROR,
98399ffe72cSXinming Hu 							    "Fail to drop packet");
98499ffe72cSXinming Hu 				}
98599ffe72cSXinming Hu 			}
98699ffe72cSXinming Hu 		}
98799ffe72cSXinming Hu 
98899ffe72cSXinming Hu 		tlv_buf_left -= (sizeof(*tlv_rxba) + tlv_len);
98999ffe72cSXinming Hu 		tmp = (u8 *)tlv_rxba + tlv_len + sizeof(*tlv_rxba);
99099ffe72cSXinming Hu 		tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp;
99199ffe72cSXinming Hu 	}
99299ffe72cSXinming Hu }
993