18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: station 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 <uapi/linux/ipv6.h>
218c2ecf20Sopenharmony_ci#include <net/ndisc.h>
228c2ecf20Sopenharmony_ci#include "decl.h"
238c2ecf20Sopenharmony_ci#include "ioctl.h"
248c2ecf20Sopenharmony_ci#include "util.h"
258c2ecf20Sopenharmony_ci#include "fw.h"
268c2ecf20Sopenharmony_ci#include "main.h"
278c2ecf20Sopenharmony_ci#include "11n_aggr.h"
288c2ecf20Sopenharmony_ci#include "11n_rxreorder.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* This function checks if a frame is IPv4 ARP or IPv6 Neighbour advertisement
318c2ecf20Sopenharmony_ci * frame. If frame has both source and destination mac address as same, this
328c2ecf20Sopenharmony_ci * function drops such gratuitous frames.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cistatic bool
358c2ecf20Sopenharmony_cimwifiex_discard_gratuitous_arp(struct mwifiex_private *priv,
368c2ecf20Sopenharmony_ci			       struct sk_buff *skb)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	const struct mwifiex_arp_eth_header *arp;
398c2ecf20Sopenharmony_ci	struct ethhdr *eth;
408c2ecf20Sopenharmony_ci	struct ipv6hdr *ipv6;
418c2ecf20Sopenharmony_ci	struct icmp6hdr *icmpv6;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	eth = (struct ethhdr *)skb->data;
448c2ecf20Sopenharmony_ci	switch (ntohs(eth->h_proto)) {
458c2ecf20Sopenharmony_ci	case ETH_P_ARP:
468c2ecf20Sopenharmony_ci		arp = (void *)(skb->data + sizeof(struct ethhdr));
478c2ecf20Sopenharmony_ci		if (arp->hdr.ar_op == htons(ARPOP_REPLY) ||
488c2ecf20Sopenharmony_ci		    arp->hdr.ar_op == htons(ARPOP_REQUEST)) {
498c2ecf20Sopenharmony_ci			if (!memcmp(arp->ar_sip, arp->ar_tip, 4))
508c2ecf20Sopenharmony_ci				return true;
518c2ecf20Sopenharmony_ci		}
528c2ecf20Sopenharmony_ci		break;
538c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
548c2ecf20Sopenharmony_ci		ipv6 = (void *)(skb->data + sizeof(struct ethhdr));
558c2ecf20Sopenharmony_ci		icmpv6 = (void *)(skb->data + sizeof(struct ethhdr) +
568c2ecf20Sopenharmony_ci				  sizeof(struct ipv6hdr));
578c2ecf20Sopenharmony_ci		if (NDISC_NEIGHBOUR_ADVERTISEMENT == icmpv6->icmp6_type) {
588c2ecf20Sopenharmony_ci			if (!memcmp(&ipv6->saddr, &ipv6->daddr,
598c2ecf20Sopenharmony_ci				    sizeof(struct in6_addr)))
608c2ecf20Sopenharmony_ci				return true;
618c2ecf20Sopenharmony_ci		}
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	default:
648c2ecf20Sopenharmony_ci		break;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return false;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*
718c2ecf20Sopenharmony_ci * This function processes the received packet and forwards it
728c2ecf20Sopenharmony_ci * to kernel/upper layer.
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * This function parses through the received packet and determines
758c2ecf20Sopenharmony_ci * if it is a debug packet or normal packet.
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci * For non-debug packets, the function chops off unnecessary leading
788c2ecf20Sopenharmony_ci * header bytes, reconstructs the packet as an ethernet frame or
798c2ecf20Sopenharmony_ci * 802.2/llc/snap frame as required, and sends it to kernel/upper layer.
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci * The completion callback is called after processing in complete.
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_ciint mwifiex_process_rx_packet(struct mwifiex_private *priv,
848c2ecf20Sopenharmony_ci			      struct sk_buff *skb)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	int ret;
878c2ecf20Sopenharmony_ci	struct rx_packet_hdr *rx_pkt_hdr;
888c2ecf20Sopenharmony_ci	struct rxpd *local_rx_pd;
898c2ecf20Sopenharmony_ci	int hdr_chop;
908c2ecf20Sopenharmony_ci	struct ethhdr *eth;
918c2ecf20Sopenharmony_ci	u16 rx_pkt_off, rx_pkt_len;
928c2ecf20Sopenharmony_ci	u8 *offset;
938c2ecf20Sopenharmony_ci	u8 adj_rx_rate = 0;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	local_rx_pd = (struct rxpd *) (skb->data);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset);
988c2ecf20Sopenharmony_ci	rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length);
998c2ecf20Sopenharmony_ci	rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rfc1042_header) +
1028c2ecf20Sopenharmony_ci	    rx_pkt_off > skb->len) {
1038c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
1048c2ecf20Sopenharmony_ci			    "wrong rx packet offset: len=%d, rx_pkt_off=%d\n",
1058c2ecf20Sopenharmony_ci			    skb->len, rx_pkt_off);
1068c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
1078c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
1088c2ecf20Sopenharmony_ci		return -1;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (sizeof(*rx_pkt_hdr) + rx_pkt_off <= skb->len &&
1128c2ecf20Sopenharmony_ci	    ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
1138c2ecf20Sopenharmony_ci		      sizeof(bridge_tunnel_header))) ||
1148c2ecf20Sopenharmony_ci	     (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
1158c2ecf20Sopenharmony_ci		      sizeof(rfc1042_header)) &&
1168c2ecf20Sopenharmony_ci	      ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP &&
1178c2ecf20Sopenharmony_ci	      ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX))) {
1188c2ecf20Sopenharmony_ci		/*
1198c2ecf20Sopenharmony_ci		 *  Replace the 803 header and rfc1042 header (llc/snap) with an
1208c2ecf20Sopenharmony_ci		 *    EthernetII header, keep the src/dst and snap_type
1218c2ecf20Sopenharmony_ci		 *    (ethertype).
1228c2ecf20Sopenharmony_ci		 *  The firmware only passes up SNAP frames converting
1238c2ecf20Sopenharmony_ci		 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
1248c2ecf20Sopenharmony_ci		 *  To create the Ethernet II, just move the src, dst address
1258c2ecf20Sopenharmony_ci		 *    right before the snap_type.
1268c2ecf20Sopenharmony_ci		 */
1278c2ecf20Sopenharmony_ci		eth = (struct ethhdr *)
1288c2ecf20Sopenharmony_ci			((u8 *) &rx_pkt_hdr->eth803_hdr
1298c2ecf20Sopenharmony_ci			 + sizeof(rx_pkt_hdr->eth803_hdr) +
1308c2ecf20Sopenharmony_ci			 sizeof(rx_pkt_hdr->rfc1042_hdr)
1318c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
1328c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
1338c2ecf20Sopenharmony_ci			 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		memcpy(eth->h_source, rx_pkt_hdr->eth803_hdr.h_source,
1368c2ecf20Sopenharmony_ci		       sizeof(eth->h_source));
1378c2ecf20Sopenharmony_ci		memcpy(eth->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
1388c2ecf20Sopenharmony_ci		       sizeof(eth->h_dest));
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		/* Chop off the rxpd + the excess memory from the 802.2/llc/snap
1418c2ecf20Sopenharmony_ci		   header that was removed. */
1428c2ecf20Sopenharmony_ci		hdr_chop = (u8 *) eth - (u8 *) local_rx_pd;
1438c2ecf20Sopenharmony_ci	} else {
1448c2ecf20Sopenharmony_ci		/* Chop off the rxpd */
1458c2ecf20Sopenharmony_ci		hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr -
1468c2ecf20Sopenharmony_ci			(u8 *) local_rx_pd;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* Chop off the leading header bytes so the it points to the start of
1508c2ecf20Sopenharmony_ci	   either the reconstructed EthII frame or the 802.2/llc/snap frame */
1518c2ecf20Sopenharmony_ci	skb_pull(skb, hdr_chop);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (priv->hs2_enabled &&
1548c2ecf20Sopenharmony_ci	    mwifiex_discard_gratuitous_arp(priv, skb)) {
1558c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n");
1568c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
1578c2ecf20Sopenharmony_ci		return 0;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
1618c2ecf20Sopenharmony_ci	    ntohs(rx_pkt_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
1628c2ecf20Sopenharmony_ci		offset = (u8 *)local_rx_pd + rx_pkt_off;
1638c2ecf20Sopenharmony_ci		mwifiex_process_tdls_action_frame(priv, offset, rx_pkt_len);
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Only stash RX bitrate for unicast packets. */
1678c2ecf20Sopenharmony_ci	if (likely(!is_multicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest))) {
1688c2ecf20Sopenharmony_ci		priv->rxpd_rate = local_rx_pd->rx_rate;
1698c2ecf20Sopenharmony_ci		priv->rxpd_htinfo = local_rx_pd->ht_info;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
1738c2ecf20Sopenharmony_ci	    GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
1748c2ecf20Sopenharmony_ci		adj_rx_rate = mwifiex_adjust_data_rate(priv,
1758c2ecf20Sopenharmony_ci						       local_rx_pd->rx_rate,
1768c2ecf20Sopenharmony_ci						       local_rx_pd->ht_info);
1778c2ecf20Sopenharmony_ci		mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr,
1788c2ecf20Sopenharmony_ci				      local_rx_pd->nf);
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	ret = mwifiex_recv_packet(priv, skb);
1828c2ecf20Sopenharmony_ci	if (ret == -1)
1838c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
1848c2ecf20Sopenharmony_ci			    "recv packet failed\n");
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return ret;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/*
1908c2ecf20Sopenharmony_ci * This function processes the received buffer.
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci * The function looks into the RxPD and performs sanity tests on the
1938c2ecf20Sopenharmony_ci * received buffer to ensure its a valid packet, before processing it
1948c2ecf20Sopenharmony_ci * further. If the packet is determined to be aggregated, it is
1958c2ecf20Sopenharmony_ci * de-aggregated accordingly. Non-unicast packets are sent directly to
1968c2ecf20Sopenharmony_ci * the kernel/upper layers. Unicast packets are handed over to the
1978c2ecf20Sopenharmony_ci * Rx reordering routine if 11n is enabled.
1988c2ecf20Sopenharmony_ci *
1998c2ecf20Sopenharmony_ci * The completion callback is called after processing in complete.
2008c2ecf20Sopenharmony_ci */
2018c2ecf20Sopenharmony_ciint mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
2028c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
2058c2ecf20Sopenharmony_ci	int ret = 0;
2068c2ecf20Sopenharmony_ci	struct rxpd *local_rx_pd;
2078c2ecf20Sopenharmony_ci	struct rx_packet_hdr *rx_pkt_hdr;
2088c2ecf20Sopenharmony_ci	u8 ta[ETH_ALEN];
2098c2ecf20Sopenharmony_ci	u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
2108c2ecf20Sopenharmony_ci	struct mwifiex_sta_node *sta_ptr;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	local_rx_pd = (struct rxpd *) (skb->data);
2138c2ecf20Sopenharmony_ci	rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
2148c2ecf20Sopenharmony_ci	rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset);
2158c2ecf20Sopenharmony_ci	rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length);
2168c2ecf20Sopenharmony_ci	seq_num = le16_to_cpu(local_rx_pd->seq_num);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if ((rx_pkt_offset + rx_pkt_length) > skb->len ||
2218c2ecf20Sopenharmony_ci	    sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) {
2228c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
2238c2ecf20Sopenharmony_ci			    "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
2248c2ecf20Sopenharmony_ci			    skb->len, rx_pkt_offset, rx_pkt_length);
2258c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
2268c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2278c2ecf20Sopenharmony_ci		return ret;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (rx_pkt_type == PKT_TYPE_MGMT) {
2318c2ecf20Sopenharmony_ci		ret = mwifiex_process_mgmt_packet(priv, skb);
2328c2ecf20Sopenharmony_ci		if (ret)
2338c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed");
2348c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2358c2ecf20Sopenharmony_ci		return ret;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/*
2398c2ecf20Sopenharmony_ci	 * If the packet is not an unicast packet then send the packet
2408c2ecf20Sopenharmony_ci	 * directly to os. Don't pass thru rx reordering
2418c2ecf20Sopenharmony_ci	 */
2428c2ecf20Sopenharmony_ci	if ((!IS_11N_ENABLED(priv) &&
2438c2ecf20Sopenharmony_ci	     !(ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
2448c2ecf20Sopenharmony_ci	       !(local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET))) ||
2458c2ecf20Sopenharmony_ci	    !ether_addr_equal_unaligned(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest)) {
2468c2ecf20Sopenharmony_ci		mwifiex_process_rx_packet(priv, skb);
2478c2ecf20Sopenharmony_ci		return ret;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (mwifiex_queuing_ra_based(priv) ||
2518c2ecf20Sopenharmony_ci	    (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
2528c2ecf20Sopenharmony_ci	     local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET)) {
2538c2ecf20Sopenharmony_ci		memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
2548c2ecf20Sopenharmony_ci		if (local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET &&
2558c2ecf20Sopenharmony_ci		    local_rx_pd->priority < MAX_NUM_TID) {
2568c2ecf20Sopenharmony_ci			sta_ptr = mwifiex_get_sta_entry(priv, ta);
2578c2ecf20Sopenharmony_ci			if (sta_ptr)
2588c2ecf20Sopenharmony_ci				sta_ptr->rx_seq[local_rx_pd->priority] =
2598c2ecf20Sopenharmony_ci					      le16_to_cpu(local_rx_pd->seq_num);
2608c2ecf20Sopenharmony_ci			mwifiex_auto_tdls_update_peer_signal(priv, ta,
2618c2ecf20Sopenharmony_ci							     local_rx_pd->snr,
2628c2ecf20Sopenharmony_ci							     local_rx_pd->nf);
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci	} else {
2658c2ecf20Sopenharmony_ci		if (rx_pkt_type != PKT_TYPE_BAR &&
2668c2ecf20Sopenharmony_ci		    local_rx_pd->priority < MAX_NUM_TID)
2678c2ecf20Sopenharmony_ci			priv->rx_seq[local_rx_pd->priority] = seq_num;
2688c2ecf20Sopenharmony_ci		memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
2698c2ecf20Sopenharmony_ci		       ETH_ALEN);
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* Reorder and send to OS */
2738c2ecf20Sopenharmony_ci	ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
2748c2ecf20Sopenharmony_ci					 ta, (u8) rx_pkt_type, skb);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (ret || (rx_pkt_type == PKT_TYPE_BAR))
2778c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (ret)
2808c2ecf20Sopenharmony_ci		priv->stats.rx_dropped++;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return ret;
2838c2ecf20Sopenharmony_ci}
284