18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: AP TX and RX data handling
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP
78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991
88c2ecf20Sopenharmony_ci * (the "License").  You may use, redistribute and/or modify this File in
98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which
108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc.,
118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
178c2ecf20Sopenharmony_ci * this warranty disclaimer.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "decl.h"
218c2ecf20Sopenharmony_ci#include "ioctl.h"
228c2ecf20Sopenharmony_ci#include "main.h"
238c2ecf20Sopenharmony_ci#include "wmm.h"
248c2ecf20Sopenharmony_ci#include "11n_aggr.h"
258c2ecf20Sopenharmony_ci#include "11n_rxreorder.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* This function checks if particular RA list has packets more than low bridge
288c2ecf20Sopenharmony_ci * packet threshold and then deletes packet from this RA list.
298c2ecf20Sopenharmony_ci * Function deletes packets from such RA list and returns true. If no such list
308c2ecf20Sopenharmony_ci * is found, false is returned.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistatic bool
338c2ecf20Sopenharmony_cimwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv,
348c2ecf20Sopenharmony_ci				  struct list_head *ra_list_head,
358c2ecf20Sopenharmony_ci				  int tid)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct mwifiex_ra_list_tbl *ra_list;
388c2ecf20Sopenharmony_ci	struct sk_buff *skb, *tmp;
398c2ecf20Sopenharmony_ci	bool pkt_deleted = false;
408c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info;
418c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	list_for_each_entry(ra_list, ra_list_head, list) {
448c2ecf20Sopenharmony_ci		if (skb_queue_empty(&ra_list->skb_head))
458c2ecf20Sopenharmony_ci			continue;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci		skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
488c2ecf20Sopenharmony_ci			tx_info = MWIFIEX_SKB_TXCB(skb);
498c2ecf20Sopenharmony_ci			if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
508c2ecf20Sopenharmony_ci				__skb_unlink(skb, &ra_list->skb_head);
518c2ecf20Sopenharmony_ci				mwifiex_write_data_complete(adapter, skb, 0,
528c2ecf20Sopenharmony_ci							    -1);
538c2ecf20Sopenharmony_ci				if (ra_list->tx_paused)
548c2ecf20Sopenharmony_ci					priv->wmm.pkts_paused[tid]--;
558c2ecf20Sopenharmony_ci				else
568c2ecf20Sopenharmony_ci					atomic_dec(&priv->wmm.tx_pkts_queued);
578c2ecf20Sopenharmony_ci				pkt_deleted = true;
588c2ecf20Sopenharmony_ci			}
598c2ecf20Sopenharmony_ci			if ((atomic_read(&adapter->pending_bridged_pkts) <=
608c2ecf20Sopenharmony_ci					     MWIFIEX_BRIDGED_PKTS_THR_LOW))
618c2ecf20Sopenharmony_ci				break;
628c2ecf20Sopenharmony_ci		}
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return pkt_deleted;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* This function deletes packets from particular RA List. RA list index
698c2ecf20Sopenharmony_ci * from which packets are deleted is preserved so that packets from next RA
708c2ecf20Sopenharmony_ci * list are deleted upon subsequent call thus maintaining fairness.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct list_head *ra_list;
758c2ecf20Sopenharmony_ci	int i;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	spin_lock_bh(&priv->wmm.ra_list_spinlock);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) {
808c2ecf20Sopenharmony_ci		if (priv->del_list_idx == MAX_NUM_TID)
818c2ecf20Sopenharmony_ci			priv->del_list_idx = 0;
828c2ecf20Sopenharmony_ci		ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list;
838c2ecf20Sopenharmony_ci		if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list, i)) {
848c2ecf20Sopenharmony_ci			priv->del_list_idx++;
858c2ecf20Sopenharmony_ci			break;
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	spin_unlock_bh(&priv->wmm.ra_list_spinlock);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
948c2ecf20Sopenharmony_ci					 struct sk_buff *skb)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
978c2ecf20Sopenharmony_ci	struct uap_rxpd *uap_rx_pd;
988c2ecf20Sopenharmony_ci	struct rx_packet_hdr *rx_pkt_hdr;
998c2ecf20Sopenharmony_ci	struct sk_buff *new_skb;
1008c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info;
1018c2ecf20Sopenharmony_ci	int hdr_chop;
1028c2ecf20Sopenharmony_ci	struct ethhdr *p_ethhdr;
1038c2ecf20Sopenharmony_ci	struct mwifiex_sta_node *src_node;
1048c2ecf20Sopenharmony_ci	int index;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	uap_rx_pd = (struct uap_rxpd *)(skb->data);
1078c2ecf20Sopenharmony_ci	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if ((atomic_read(&adapter->pending_bridged_pkts) >=
1108c2ecf20Sopenharmony_ci					     MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
1118c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
1128c2ecf20Sopenharmony_ci			    "Tx: Bridge packet limit reached. Drop packet!\n");
1138c2ecf20Sopenharmony_ci		kfree_skb(skb);
1148c2ecf20Sopenharmony_ci		mwifiex_uap_cleanup_tx_queues(priv);
1158c2ecf20Sopenharmony_ci		return;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (sizeof(*rx_pkt_hdr) +
1198c2ecf20Sopenharmony_ci	    le16_to_cpu(uap_rx_pd->rx_pkt_offset) > skb->len) {
1208c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
1218c2ecf20Sopenharmony_ci			    "wrong rx packet offset: len=%d,rx_pkt_offset=%d\n",
1228c2ecf20Sopenharmony_ci			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
1238c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
1248c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
1258c2ecf20Sopenharmony_ci		return;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
1298c2ecf20Sopenharmony_ci		     sizeof(bridge_tunnel_header))) ||
1308c2ecf20Sopenharmony_ci	    (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
1318c2ecf20Sopenharmony_ci		     sizeof(rfc1042_header)) &&
1328c2ecf20Sopenharmony_ci	     ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP &&
1338c2ecf20Sopenharmony_ci	     ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX)) {
1348c2ecf20Sopenharmony_ci		/* Replace the 803 header and rfc1042 header (llc/snap) with
1358c2ecf20Sopenharmony_ci		 * an Ethernet II header, keep the src/dst and snap_type
1368c2ecf20Sopenharmony_ci		 * (ethertype).
1378c2ecf20Sopenharmony_ci		 *
1388c2ecf20Sopenharmony_ci		 * The firmware only passes up SNAP frames converting all RX
1398c2ecf20Sopenharmony_ci		 * data from 802.11 to 802.2/LLC/SNAP frames.
1408c2ecf20Sopenharmony_ci		 *
1418c2ecf20Sopenharmony_ci		 * To create the Ethernet II, just move the src, dst address
1428c2ecf20Sopenharmony_ci		 * right before the snap_type.
1438c2ecf20Sopenharmony_ci		 */
1448c2ecf20Sopenharmony_ci		p_ethhdr = (struct ethhdr *)
1458c2ecf20Sopenharmony_ci			((u8 *)(&rx_pkt_hdr->eth803_hdr)
1468c2ecf20Sopenharmony_ci			 + sizeof(rx_pkt_hdr->eth803_hdr)
1478c2ecf20Sopenharmony_ci			 + sizeof(rx_pkt_hdr->rfc1042_hdr)
1488c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
1498c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
1508c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
1518c2ecf20Sopenharmony_ci		memcpy(p_ethhdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
1528c2ecf20Sopenharmony_ci		       sizeof(p_ethhdr->h_source));
1538c2ecf20Sopenharmony_ci		memcpy(p_ethhdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
1548c2ecf20Sopenharmony_ci		       sizeof(p_ethhdr->h_dest));
1558c2ecf20Sopenharmony_ci		/* Chop off the rxpd + the excess memory from
1568c2ecf20Sopenharmony_ci		 * 802.2/llc/snap header that was removed.
1578c2ecf20Sopenharmony_ci		 */
1588c2ecf20Sopenharmony_ci		hdr_chop = (u8 *)p_ethhdr - (u8 *)uap_rx_pd;
1598c2ecf20Sopenharmony_ci	} else {
1608c2ecf20Sopenharmony_ci		/* Chop off the rxpd */
1618c2ecf20Sopenharmony_ci		hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/* Chop off the leading header bytes so that it points
1658c2ecf20Sopenharmony_ci	 * to the start of either the reconstructed EthII frame
1668c2ecf20Sopenharmony_ci	 * or the 802.2/llc/snap frame.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	skb_pull(skb, hdr_chop);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
1718c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
1728c2ecf20Sopenharmony_ci			    "data: Tx: insufficient skb headroom %d\n",
1738c2ecf20Sopenharmony_ci			    skb_headroom(skb));
1748c2ecf20Sopenharmony_ci		/* Insufficient skb headroom - allocate a new skb */
1758c2ecf20Sopenharmony_ci		new_skb =
1768c2ecf20Sopenharmony_ci			skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
1778c2ecf20Sopenharmony_ci		if (unlikely(!new_skb)) {
1788c2ecf20Sopenharmony_ci			mwifiex_dbg(priv->adapter, ERROR,
1798c2ecf20Sopenharmony_ci				    "Tx: cannot allocate new_skb\n");
1808c2ecf20Sopenharmony_ci			kfree_skb(skb);
1818c2ecf20Sopenharmony_ci			priv->stats.tx_dropped++;
1828c2ecf20Sopenharmony_ci			return;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		kfree_skb(skb);
1868c2ecf20Sopenharmony_ci		skb = new_skb;
1878c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, INFO,
1888c2ecf20Sopenharmony_ci			    "info: new skb headroom %d\n",
1898c2ecf20Sopenharmony_ci			    skb_headroom(skb));
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	tx_info = MWIFIEX_SKB_TXCB(skb);
1938c2ecf20Sopenharmony_ci	memset(tx_info, 0, sizeof(*tx_info));
1948c2ecf20Sopenharmony_ci	tx_info->bss_num = priv->bss_num;
1958c2ecf20Sopenharmony_ci	tx_info->bss_type = priv->bss_type;
1968c2ecf20Sopenharmony_ci	tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	src_node = mwifiex_get_sta_entry(priv, rx_pkt_hdr->eth803_hdr.h_source);
1998c2ecf20Sopenharmony_ci	if (src_node) {
2008c2ecf20Sopenharmony_ci		src_node->stats.last_rx = jiffies;
2018c2ecf20Sopenharmony_ci		src_node->stats.rx_bytes += skb->len;
2028c2ecf20Sopenharmony_ci		src_node->stats.rx_packets++;
2038c2ecf20Sopenharmony_ci		src_node->stats.last_tx_rate = uap_rx_pd->rx_rate;
2048c2ecf20Sopenharmony_ci		src_node->stats.last_tx_htinfo = uap_rx_pd->ht_info;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) {
2088c2ecf20Sopenharmony_ci		/* Update bridge packet statistics as the
2098c2ecf20Sopenharmony_ci		 * packet is not going to kernel/upper layer.
2108c2ecf20Sopenharmony_ci		 */
2118c2ecf20Sopenharmony_ci		priv->stats.rx_bytes += skb->len;
2128c2ecf20Sopenharmony_ci		priv->stats.rx_packets++;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		/* Sending bridge packet to TX queue, so save the packet
2158c2ecf20Sopenharmony_ci		 * length in TXCB to update statistics in TX complete.
2168c2ecf20Sopenharmony_ci		 */
2178c2ecf20Sopenharmony_ci		tx_info->pkt_len = skb->len;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	__net_timestamp(skb);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	index = mwifiex_1d_to_wmm_queue[skb->priority];
2238c2ecf20Sopenharmony_ci	atomic_inc(&priv->wmm_tx_pending[index]);
2248c2ecf20Sopenharmony_ci	mwifiex_wmm_add_buf_txqueue(priv, skb);
2258c2ecf20Sopenharmony_ci	atomic_inc(&adapter->tx_pending);
2268c2ecf20Sopenharmony_ci	atomic_inc(&adapter->pending_bridged_pkts);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	mwifiex_queue_main_work(priv->adapter);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/*
2348c2ecf20Sopenharmony_ci * This function contains logic for AP packet forwarding.
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci * If a packet is multicast/broadcast, it is sent to kernel/upper layer
2378c2ecf20Sopenharmony_ci * as well as queued back to AP TX queue so that it can be sent to other
2388c2ecf20Sopenharmony_ci * associated stations.
2398c2ecf20Sopenharmony_ci * If a packet is unicast and RA is present in associated station list,
2408c2ecf20Sopenharmony_ci * it is again requeued into AP TX queue.
2418c2ecf20Sopenharmony_ci * If a packet is unicast and RA is not in associated station list,
2428c2ecf20Sopenharmony_ci * packet is forwarded to kernel to handle routing logic.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_ciint mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
2458c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
2488c2ecf20Sopenharmony_ci	struct uap_rxpd *uap_rx_pd;
2498c2ecf20Sopenharmony_ci	struct rx_packet_hdr *rx_pkt_hdr;
2508c2ecf20Sopenharmony_ci	u8 ra[ETH_ALEN];
2518c2ecf20Sopenharmony_ci	struct sk_buff *skb_uap;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	uap_rx_pd = (struct uap_rxpd *)(skb->data);
2548c2ecf20Sopenharmony_ci	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* don't do packet forwarding in disconnected state */
2578c2ecf20Sopenharmony_ci	if (!priv->media_connected) {
2588c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
2598c2ecf20Sopenharmony_ci			    "drop packet in disconnected state.\n");
2608c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2618c2ecf20Sopenharmony_ci		return 0;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(ra)) {
2678c2ecf20Sopenharmony_ci		skb_uap = skb_copy(skb, GFP_ATOMIC);
2688c2ecf20Sopenharmony_ci		if (likely(skb_uap)) {
2698c2ecf20Sopenharmony_ci			mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
2708c2ecf20Sopenharmony_ci		} else {
2718c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
2728c2ecf20Sopenharmony_ci				    "failed to copy skb for uAP\n");
2738c2ecf20Sopenharmony_ci			priv->stats.rx_dropped++;
2748c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
2758c2ecf20Sopenharmony_ci			return -1;
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci	} else {
2788c2ecf20Sopenharmony_ci		if (mwifiex_get_sta_entry(priv, ra)) {
2798c2ecf20Sopenharmony_ci			/* Requeue Intra-BSS packet */
2808c2ecf20Sopenharmony_ci			mwifiex_uap_queue_bridged_pkt(priv, skb);
2818c2ecf20Sopenharmony_ci			return 0;
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Forward unicat/Inter-BSS packets to kernel. */
2868c2ecf20Sopenharmony_ci	return mwifiex_process_rx_packet(priv, skb);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ciint mwifiex_uap_recv_packet(struct mwifiex_private *priv,
2908c2ecf20Sopenharmony_ci			    struct sk_buff *skb)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
2938c2ecf20Sopenharmony_ci	struct mwifiex_sta_node *src_node;
2948c2ecf20Sopenharmony_ci	struct ethhdr *p_ethhdr;
2958c2ecf20Sopenharmony_ci	struct sk_buff *skb_uap;
2968c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!skb)
2998c2ecf20Sopenharmony_ci		return -1;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	p_ethhdr = (void *)skb->data;
3028c2ecf20Sopenharmony_ci	src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
3038c2ecf20Sopenharmony_ci	if (src_node) {
3048c2ecf20Sopenharmony_ci		src_node->stats.last_rx = jiffies;
3058c2ecf20Sopenharmony_ci		src_node->stats.rx_bytes += skb->len;
3068c2ecf20Sopenharmony_ci		src_node->stats.rx_packets++;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(p_ethhdr->h_dest) ||
3108c2ecf20Sopenharmony_ci	    mwifiex_get_sta_entry(priv, p_ethhdr->h_dest)) {
3118c2ecf20Sopenharmony_ci		if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN)
3128c2ecf20Sopenharmony_ci			skb_uap =
3138c2ecf20Sopenharmony_ci			skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
3148c2ecf20Sopenharmony_ci		else
3158c2ecf20Sopenharmony_ci			skb_uap = skb_copy(skb, GFP_ATOMIC);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		if (likely(skb_uap)) {
3188c2ecf20Sopenharmony_ci			tx_info = MWIFIEX_SKB_TXCB(skb_uap);
3198c2ecf20Sopenharmony_ci			memset(tx_info, 0, sizeof(*tx_info));
3208c2ecf20Sopenharmony_ci			tx_info->bss_num = priv->bss_num;
3218c2ecf20Sopenharmony_ci			tx_info->bss_type = priv->bss_type;
3228c2ecf20Sopenharmony_ci			tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
3238c2ecf20Sopenharmony_ci			__net_timestamp(skb_uap);
3248c2ecf20Sopenharmony_ci			mwifiex_wmm_add_buf_txqueue(priv, skb_uap);
3258c2ecf20Sopenharmony_ci			atomic_inc(&adapter->tx_pending);
3268c2ecf20Sopenharmony_ci			atomic_inc(&adapter->pending_bridged_pkts);
3278c2ecf20Sopenharmony_ci			if ((atomic_read(&adapter->pending_bridged_pkts) >=
3288c2ecf20Sopenharmony_ci					MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
3298c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
3308c2ecf20Sopenharmony_ci					    "Tx: Bridge packet limit reached. Drop packet!\n");
3318c2ecf20Sopenharmony_ci				mwifiex_uap_cleanup_tx_queues(priv);
3328c2ecf20Sopenharmony_ci			}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		} else {
3358c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "failed to allocate skb_uap");
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		mwifiex_queue_main_work(adapter);
3398c2ecf20Sopenharmony_ci		/* Don't forward Intra-BSS unicast packet to upper layer*/
3408c2ecf20Sopenharmony_ci		if (mwifiex_get_sta_entry(priv, p_ethhdr->h_dest))
3418c2ecf20Sopenharmony_ci			return 0;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	skb->dev = priv->netdev;
3458c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, priv->netdev);
3468c2ecf20Sopenharmony_ci	skb->ip_summed = CHECKSUM_NONE;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* This is required only in case of 11n and USB/PCIE as we alloc
3498c2ecf20Sopenharmony_ci	 * a buffer of 4K only if its 11N (to be able to receive 4K
3508c2ecf20Sopenharmony_ci	 * AMSDU packets). In case of SD we allocate buffers based
3518c2ecf20Sopenharmony_ci	 * on the size of packet and hence this is not needed.
3528c2ecf20Sopenharmony_ci	 *
3538c2ecf20Sopenharmony_ci	 * Modifying the truesize here as our allocation for each
3548c2ecf20Sopenharmony_ci	 * skb is 4K but we only receive 2K packets and this cause
3558c2ecf20Sopenharmony_ci	 * the kernel to start dropping packets in case where
3568c2ecf20Sopenharmony_ci	 * application has allocated buffer based on 2K size i.e.
3578c2ecf20Sopenharmony_ci	 * if there a 64K packet received (in IP fragments and
3588c2ecf20Sopenharmony_ci	 * application allocates 64K to receive this packet but
3598c2ecf20Sopenharmony_ci	 * this packet would almost double up because we allocate
3608c2ecf20Sopenharmony_ci	 * each 1.5K fragment in 4K and pass it up. As soon as the
3618c2ecf20Sopenharmony_ci	 * 64K limit hits kernel will start to drop rest of the
3628c2ecf20Sopenharmony_ci	 * fragments. Currently we fail the Filesndl-ht.scr script
3638c2ecf20Sopenharmony_ci	 * for UDP, hence this fix
3648c2ecf20Sopenharmony_ci	 */
3658c2ecf20Sopenharmony_ci	if ((adapter->iface_type == MWIFIEX_USB ||
3668c2ecf20Sopenharmony_ci	     adapter->iface_type == MWIFIEX_PCIE) &&
3678c2ecf20Sopenharmony_ci	    skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)
3688c2ecf20Sopenharmony_ci		skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Forward multicast/broadcast packet to upper layer*/
3718c2ecf20Sopenharmony_ci	netif_rx_any_context(skb);
3728c2ecf20Sopenharmony_ci	return 0;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/*
3768c2ecf20Sopenharmony_ci * This function processes the packet received on AP interface.
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * The function looks into the RxPD and performs sanity tests on the
3798c2ecf20Sopenharmony_ci * received buffer to ensure its a valid packet before processing it
3808c2ecf20Sopenharmony_ci * further. If the packet is determined to be aggregated, it is
3818c2ecf20Sopenharmony_ci * de-aggregated accordingly. Then skb is passed to AP packet forwarding logic.
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci * The completion callback is called after processing is complete.
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_ciint mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
3868c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
3898c2ecf20Sopenharmony_ci	int ret;
3908c2ecf20Sopenharmony_ci	struct uap_rxpd *uap_rx_pd;
3918c2ecf20Sopenharmony_ci	struct rx_packet_hdr *rx_pkt_hdr;
3928c2ecf20Sopenharmony_ci	u16 rx_pkt_type;
3938c2ecf20Sopenharmony_ci	u8 ta[ETH_ALEN], pkt_type;
3948c2ecf20Sopenharmony_ci	struct mwifiex_sta_node *node;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	uap_rx_pd = (struct uap_rxpd *)(skb->data);
3978c2ecf20Sopenharmony_ci	rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
3988c2ecf20Sopenharmony_ci	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
4018c2ecf20Sopenharmony_ci	    sizeof(rx_pkt_hdr->eth803_hdr) > skb->len) {
4028c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
4038c2ecf20Sopenharmony_ci			    "wrong rx packet for struct ethhdr: len=%d, offset=%d\n",
4048c2ecf20Sopenharmony_ci			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
4058c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
4068c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
4078c2ecf20Sopenharmony_ci		return 0;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
4138c2ecf20Sopenharmony_ci	     le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
4148c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
4158c2ecf20Sopenharmony_ci			    "wrong rx packet: len=%d, offset=%d, length=%d\n",
4168c2ecf20Sopenharmony_ci			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
4178c2ecf20Sopenharmony_ci			    le16_to_cpu(uap_rx_pd->rx_pkt_length));
4188c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci		node = mwifiex_get_sta_entry(priv, ta);
4218c2ecf20Sopenharmony_ci		if (node)
4228c2ecf20Sopenharmony_ci			node->stats.tx_failed++;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
4258c2ecf20Sopenharmony_ci		return 0;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (rx_pkt_type == PKT_TYPE_MGMT) {
4298c2ecf20Sopenharmony_ci		ret = mwifiex_process_mgmt_packet(priv, skb);
4308c2ecf20Sopenharmony_ci		if (ret)
4318c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed");
4328c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
4338c2ecf20Sopenharmony_ci		return ret;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
4388c2ecf20Sopenharmony_ci		spin_lock_bh(&priv->sta_list_spinlock);
4398c2ecf20Sopenharmony_ci		node = mwifiex_get_sta_entry(priv, ta);
4408c2ecf20Sopenharmony_ci		if (node)
4418c2ecf20Sopenharmony_ci			node->rx_seq[uap_rx_pd->priority] =
4428c2ecf20Sopenharmony_ci						le16_to_cpu(uap_rx_pd->seq_num);
4438c2ecf20Sopenharmony_ci		spin_unlock_bh(&priv->sta_list_spinlock);
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!priv->ap_11n_enabled ||
4478c2ecf20Sopenharmony_ci	    (!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
4488c2ecf20Sopenharmony_ci	    (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
4498c2ecf20Sopenharmony_ci		ret = mwifiex_handle_uap_rx_forward(priv, skb);
4508c2ecf20Sopenharmony_ci		return ret;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Reorder and send to kernel */
4548c2ecf20Sopenharmony_ci	pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
4558c2ecf20Sopenharmony_ci	ret = mwifiex_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
4568c2ecf20Sopenharmony_ci					 uap_rx_pd->priority, ta, pkt_type,
4578c2ecf20Sopenharmony_ci					 skb);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (ret || (rx_pkt_type == PKT_TYPE_BAR))
4608c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (ret)
4638c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return ret;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/*
4698c2ecf20Sopenharmony_ci * This function fills the TxPD for AP tx packets.
4708c2ecf20Sopenharmony_ci *
4718c2ecf20Sopenharmony_ci * The Tx buffer received by this function should already have the
4728c2ecf20Sopenharmony_ci * header space allocated for TxPD.
4738c2ecf20Sopenharmony_ci *
4748c2ecf20Sopenharmony_ci * This function inserts the TxPD in between interface header and actual
4758c2ecf20Sopenharmony_ci * data and adjusts the buffer pointers accordingly.
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * The following TxPD fields are set by this function, as required -
4788c2ecf20Sopenharmony_ci *      - BSS number
4798c2ecf20Sopenharmony_ci *      - Tx packet length and offset
4808c2ecf20Sopenharmony_ci *      - Priority
4818c2ecf20Sopenharmony_ci *      - Packet delay
4828c2ecf20Sopenharmony_ci *      - Priority specific Tx control
4838c2ecf20Sopenharmony_ci *      - Flags
4848c2ecf20Sopenharmony_ci */
4858c2ecf20Sopenharmony_civoid *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
4868c2ecf20Sopenharmony_ci			       struct sk_buff *skb)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
4898c2ecf20Sopenharmony_ci	struct uap_txpd *txpd;
4908c2ecf20Sopenharmony_ci	struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
4918c2ecf20Sopenharmony_ci	int pad;
4928c2ecf20Sopenharmony_ci	u16 pkt_type, pkt_offset;
4938c2ecf20Sopenharmony_ci	int hroom = adapter->intf_hdr_len;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (!skb->len) {
4968c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
4978c2ecf20Sopenharmony_ci			    "Tx: bad packet length: %d\n", skb->len);
4988c2ecf20Sopenharmony_ci		tx_info->status_code = -1;
4998c2ecf20Sopenharmony_ci		return skb->data;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	pad = ((void *)skb->data - (sizeof(*txpd) + hroom) - NULL) &
5078c2ecf20Sopenharmony_ci			(MWIFIEX_DMA_ALIGN_SZ - 1);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	skb_push(skb, sizeof(*txpd) + pad);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	txpd = (struct uap_txpd *)skb->data;
5128c2ecf20Sopenharmony_ci	memset(txpd, 0, sizeof(*txpd));
5138c2ecf20Sopenharmony_ci	txpd->bss_num = priv->bss_num;
5148c2ecf20Sopenharmony_ci	txpd->bss_type = priv->bss_type;
5158c2ecf20Sopenharmony_ci	txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - (sizeof(*txpd) +
5168c2ecf20Sopenharmony_ci						pad)));
5178c2ecf20Sopenharmony_ci	txpd->priority = (u8)skb->priority;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS ||
5228c2ecf20Sopenharmony_ci	    tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) {
5238c2ecf20Sopenharmony_ci		txpd->tx_token_id = tx_info->ack_frame_id;
5248c2ecf20Sopenharmony_ci		txpd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
5288c2ecf20Sopenharmony_ci		/*
5298c2ecf20Sopenharmony_ci		 * Set the priority specific tx_control field, setting of 0 will
5308c2ecf20Sopenharmony_ci		 * cause the default value to be used later in this function.
5318c2ecf20Sopenharmony_ci		 */
5328c2ecf20Sopenharmony_ci		txpd->tx_control =
5338c2ecf20Sopenharmony_ci		    cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Offset of actual data */
5368c2ecf20Sopenharmony_ci	pkt_offset = sizeof(*txpd) + pad;
5378c2ecf20Sopenharmony_ci	if (pkt_type == PKT_TYPE_MGMT) {
5388c2ecf20Sopenharmony_ci		/* Set the packet type and add header for management frame */
5398c2ecf20Sopenharmony_ci		txpd->tx_pkt_type = cpu_to_le16(pkt_type);
5408c2ecf20Sopenharmony_ci		pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	txpd->tx_pkt_offset = cpu_to_le16(pkt_offset);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	/* make space for adapter->intf_hdr_len */
5468c2ecf20Sopenharmony_ci	skb_push(skb, hroom);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (!txpd->tx_control)
5498c2ecf20Sopenharmony_ci		/* TxCtrl set by user or default */
5508c2ecf20Sopenharmony_ci		txpd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return skb->data;
5538c2ecf20Sopenharmony_ci}
554