xref: /linux/drivers/net/wireless/nxp/nxpwifi/sta_rx.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen  * NXP Wireless LAN device driver: station RX data handling
4*73b01e57SJeff Chen  *
5*73b01e57SJeff Chen  * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen  */
7*73b01e57SJeff Chen 
8*73b01e57SJeff Chen #include <uapi/linux/ipv6.h>
9*73b01e57SJeff Chen #include <net/ndisc.h>
10*73b01e57SJeff Chen #include "cfg.h"
11*73b01e57SJeff Chen #include "util.h"
12*73b01e57SJeff Chen #include "fw.h"
13*73b01e57SJeff Chen #include "main.h"
14*73b01e57SJeff Chen #include "11n_aggr.h"
15*73b01e57SJeff Chen #include "11n_rxreorder.h"
16*73b01e57SJeff Chen 
17*73b01e57SJeff Chen /*
18*73b01e57SJeff Chen  * Drop gratuitous IPv4 ARP and IPv6 neighbour advertisements when
19*73b01e57SJeff Chen  * source and destination addresses are identical.
20*73b01e57SJeff Chen  */
21*73b01e57SJeff Chen static bool
nxpwifi_discard_gratuitous_arp(struct nxpwifi_private * priv,struct sk_buff * skb)22*73b01e57SJeff Chen nxpwifi_discard_gratuitous_arp(struct nxpwifi_private *priv,
23*73b01e57SJeff Chen 			       struct sk_buff *skb)
24*73b01e57SJeff Chen {
25*73b01e57SJeff Chen 	const struct nxpwifi_arp_eth_header *arp;
26*73b01e57SJeff Chen 	struct ethhdr *eth;
27*73b01e57SJeff Chen 	struct ipv6hdr *ipv6;
28*73b01e57SJeff Chen 	struct icmp6hdr *icmpv6;
29*73b01e57SJeff Chen 
30*73b01e57SJeff Chen 	eth = (struct ethhdr *)skb->data;
31*73b01e57SJeff Chen 	switch (ntohs(eth->h_proto)) {
32*73b01e57SJeff Chen 	case ETH_P_ARP:
33*73b01e57SJeff Chen 		arp = (void *)(skb->data + sizeof(struct ethhdr));
34*73b01e57SJeff Chen 		if (arp->hdr.ar_op == htons(ARPOP_REPLY) ||
35*73b01e57SJeff Chen 		    arp->hdr.ar_op == htons(ARPOP_REQUEST)) {
36*73b01e57SJeff Chen 			if (!memcmp(arp->ar_sip, arp->ar_tip, 4))
37*73b01e57SJeff Chen 				return true;
38*73b01e57SJeff Chen 		}
39*73b01e57SJeff Chen 		break;
40*73b01e57SJeff Chen 	case ETH_P_IPV6:
41*73b01e57SJeff Chen 		ipv6 = (void *)(skb->data + sizeof(struct ethhdr));
42*73b01e57SJeff Chen 		icmpv6 = (void *)(skb->data + sizeof(struct ethhdr) +
43*73b01e57SJeff Chen 				  sizeof(struct ipv6hdr));
44*73b01e57SJeff Chen 		if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
45*73b01e57SJeff Chen 			if (!memcmp(&ipv6->saddr, &ipv6->daddr,
46*73b01e57SJeff Chen 				    sizeof(struct in6_addr)))
47*73b01e57SJeff Chen 				return true;
48*73b01e57SJeff Chen 		}
49*73b01e57SJeff Chen 		break;
50*73b01e57SJeff Chen 	default:
51*73b01e57SJeff Chen 		break;
52*73b01e57SJeff Chen 	}
53*73b01e57SJeff Chen 
54*73b01e57SJeff Chen 	return false;
55*73b01e57SJeff Chen }
56*73b01e57SJeff Chen 
57*73b01e57SJeff Chen /*
58*73b01e57SJeff Chen  * Process a received data packet.
59*73b01e57SJeff Chen  * Convert 802.2/LLC/SNAP to Ethernet II when appropriate, trim the
60*73b01e57SJeff Chen  * rxpd and extra headers, optionally drop gratuitous ARP/NA, cache
61*73b01e57SJeff Chen  * RX rate for unicast, then deliver to the stack.
62*73b01e57SJeff Chen  */
nxpwifi_process_rx_packet(struct nxpwifi_private * priv,struct sk_buff * skb)63*73b01e57SJeff Chen int nxpwifi_process_rx_packet(struct nxpwifi_private *priv,
64*73b01e57SJeff Chen 			      struct sk_buff *skb)
65*73b01e57SJeff Chen {
66*73b01e57SJeff Chen 	int ret;
67*73b01e57SJeff Chen 	struct rx_packet_hdr *rx_pkt_hdr;
68*73b01e57SJeff Chen 	struct rxpd *local_rx_pd;
69*73b01e57SJeff Chen 	int hdr_chop;
70*73b01e57SJeff Chen 	struct ethhdr *eth;
71*73b01e57SJeff Chen 	u16 rx_pkt_off;
72*73b01e57SJeff Chen 	u8 adj_rx_rate = 0;
73*73b01e57SJeff Chen 
74*73b01e57SJeff Chen 	local_rx_pd = (struct rxpd *)(skb->data);
75*73b01e57SJeff Chen 
76*73b01e57SJeff Chen 	rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset);
77*73b01e57SJeff Chen 	rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
78*73b01e57SJeff Chen 
79*73b01e57SJeff Chen 	if (sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rfc1042_header) +
80*73b01e57SJeff Chen 	    rx_pkt_off > skb->len) {
81*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
82*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
83*73b01e57SJeff Chen 		return -EINVAL;
84*73b01e57SJeff Chen 	}
85*73b01e57SJeff Chen 
86*73b01e57SJeff Chen 	if (sizeof(*rx_pkt_hdr) + rx_pkt_off <= skb->len &&
87*73b01e57SJeff Chen 	    ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
88*73b01e57SJeff Chen 		      sizeof(bridge_tunnel_header))) ||
89*73b01e57SJeff Chen 	     (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
90*73b01e57SJeff Chen 		      sizeof(rfc1042_header)) &&
91*73b01e57SJeff Chen 	      rx_pkt_hdr->rfc1042_hdr.snap_type != htons(ETH_P_AARP) &&
92*73b01e57SJeff Chen 	      rx_pkt_hdr->rfc1042_hdr.snap_type != htons(ETH_P_IPX)))) {
93*73b01e57SJeff Chen 		/*
94*73b01e57SJeff Chen 		 * Replace the 803 header and rfc1042 header (llc/snap) with an
95*73b01e57SJeff Chen 		 *    EthernetII header, keep the src/dst and snap_type
96*73b01e57SJeff Chen 		 *    (ethertype).
97*73b01e57SJeff Chen 		 *  The firmware only passes up SNAP frames converting
98*73b01e57SJeff Chen 		 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
99*73b01e57SJeff Chen 		 *  To create the Ethernet II, just move the src, dst address
100*73b01e57SJeff Chen 		 *    right before the snap_type.
101*73b01e57SJeff Chen 		 */
102*73b01e57SJeff Chen 		eth = (struct ethhdr *)
103*73b01e57SJeff Chen 			((u8 *)&rx_pkt_hdr->eth803_hdr
104*73b01e57SJeff Chen 			 + sizeof(rx_pkt_hdr->eth803_hdr) +
105*73b01e57SJeff Chen 			 sizeof(rx_pkt_hdr->rfc1042_hdr)
106*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
107*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
108*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
109*73b01e57SJeff Chen 
110*73b01e57SJeff Chen 		memcpy(eth->h_source, rx_pkt_hdr->eth803_hdr.h_source,
111*73b01e57SJeff Chen 		       sizeof(eth->h_source));
112*73b01e57SJeff Chen 		memcpy(eth->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
113*73b01e57SJeff Chen 		       sizeof(eth->h_dest));
114*73b01e57SJeff Chen 
115*73b01e57SJeff Chen 		/*
116*73b01e57SJeff Chen 		 * Chop off the rxpd + the excess memory from the 802.2/llc/snap
117*73b01e57SJeff Chen 		 * header that was removed.
118*73b01e57SJeff Chen 		 */
119*73b01e57SJeff Chen 		hdr_chop = (u8 *)eth - (u8 *)local_rx_pd;
120*73b01e57SJeff Chen 	} else {
121*73b01e57SJeff Chen 		/* Chop off the rxpd */
122*73b01e57SJeff Chen 		hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)local_rx_pd;
123*73b01e57SJeff Chen 	}
124*73b01e57SJeff Chen 
125*73b01e57SJeff Chen 	/*
126*73b01e57SJeff Chen 	 * Chop off the leading header bytes so the it points to the start of
127*73b01e57SJeff Chen 	 * either the reconstructed EthII frame or the 802.2/llc/snap frame
128*73b01e57SJeff Chen 	 */
129*73b01e57SJeff Chen 	skb_pull(skb, hdr_chop);
130*73b01e57SJeff Chen 
131*73b01e57SJeff Chen 	if (priv->hs2_enabled &&
132*73b01e57SJeff Chen 	    nxpwifi_discard_gratuitous_arp(priv, skb)) {
133*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n");
134*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
135*73b01e57SJeff Chen 		return 0;
136*73b01e57SJeff Chen 	}
137*73b01e57SJeff Chen 
138*73b01e57SJeff Chen 	/* Only stash RX bitrate for unicast packets. */
139*73b01e57SJeff Chen 	if (likely(!is_multicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest))) {
140*73b01e57SJeff Chen 		priv->rxpd_rate = local_rx_pd->rx_rate;
141*73b01e57SJeff Chen 		priv->rxpd_htinfo = local_rx_pd->rate_info;
142*73b01e57SJeff Chen 	}
143*73b01e57SJeff Chen 
144*73b01e57SJeff Chen 	if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA ||
145*73b01e57SJeff Chen 	    GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) {
146*73b01e57SJeff Chen 		adj_rx_rate = nxpwifi_adjust_data_rate(priv,
147*73b01e57SJeff Chen 						       local_rx_pd->rx_rate,
148*73b01e57SJeff Chen 						       local_rx_pd->rate_info);
149*73b01e57SJeff Chen 		nxpwifi_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr,
150*73b01e57SJeff Chen 				      local_rx_pd->nf);
151*73b01e57SJeff Chen 	}
152*73b01e57SJeff Chen 
153*73b01e57SJeff Chen 	ret = nxpwifi_recv_packet(priv, skb);
154*73b01e57SJeff Chen 	if (ret)
155*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, ERROR,
156*73b01e57SJeff Chen 			    "recv packet failed\n");
157*73b01e57SJeff Chen 
158*73b01e57SJeff Chen 	return ret;
159*73b01e57SJeff Chen }
160*73b01e57SJeff Chen 
161*73b01e57SJeff Chen /*
162*73b01e57SJeff Chen  * Process a received buffer on the STA path.
163*73b01e57SJeff Chen  * Validate RxPD and lengths, handle monitor/mgmt frames, fast-path
164*73b01e57SJeff Chen  * non-unicast frames, and feed unicast data into 11n reorder/BA logic.
165*73b01e57SJeff Chen  */
nxpwifi_process_sta_rx_packet(struct nxpwifi_private * priv,struct sk_buff * skb)166*73b01e57SJeff Chen int nxpwifi_process_sta_rx_packet(struct nxpwifi_private *priv,
167*73b01e57SJeff Chen 				  struct sk_buff *skb)
168*73b01e57SJeff Chen {
169*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
170*73b01e57SJeff Chen 	int ret = 0;
171*73b01e57SJeff Chen 	struct rxpd *local_rx_pd;
172*73b01e57SJeff Chen 	struct rx_packet_hdr *rx_pkt_hdr;
173*73b01e57SJeff Chen 	u8 ta[ETH_ALEN];
174*73b01e57SJeff Chen 	u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
175*73b01e57SJeff Chen 
176*73b01e57SJeff Chen 	local_rx_pd = (struct rxpd *)(skb->data);
177*73b01e57SJeff Chen 	rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
178*73b01e57SJeff Chen 	rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset);
179*73b01e57SJeff Chen 	rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length);
180*73b01e57SJeff Chen 	seq_num = le16_to_cpu(local_rx_pd->seq_num);
181*73b01e57SJeff Chen 
182*73b01e57SJeff Chen 	rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
183*73b01e57SJeff Chen 
184*73b01e57SJeff Chen 	if ((rx_pkt_offset + rx_pkt_length) > skb->len ||
185*73b01e57SJeff Chen 	    sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) {
186*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
187*73b01e57SJeff Chen 			    "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
188*73b01e57SJeff Chen 			    skb->len, rx_pkt_offset, rx_pkt_length);
189*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
190*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
191*73b01e57SJeff Chen 		return ret;
192*73b01e57SJeff Chen 	}
193*73b01e57SJeff Chen 
194*73b01e57SJeff Chen 	if (priv->adapter->enable_net_mon && rx_pkt_type == PKT_TYPE_802DOT11) {
195*73b01e57SJeff Chen 		ret = nxpwifi_recv_packet_to_monif(priv, skb);
196*73b01e57SJeff Chen 		if (ret)
197*73b01e57SJeff Chen 			dev_kfree_skb_any(skb);
198*73b01e57SJeff Chen 		return ret;
199*73b01e57SJeff Chen 	}
200*73b01e57SJeff Chen 
201*73b01e57SJeff Chen 	if (rx_pkt_type == PKT_TYPE_MGMT) {
202*73b01e57SJeff Chen 		ret = nxpwifi_process_mgmt_packet(priv, skb);
203*73b01e57SJeff Chen 		if (ret && (ret != -EINPROGRESS))
204*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, DATA, "Rx of mgmt packet failed");
205*73b01e57SJeff Chen 		if (ret != -EINPROGRESS)
206*73b01e57SJeff Chen 			dev_kfree_skb_any(skb);
207*73b01e57SJeff Chen 		return ret;
208*73b01e57SJeff Chen 	}
209*73b01e57SJeff Chen 
210*73b01e57SJeff Chen 	/*
211*73b01e57SJeff Chen 	 * If the packet is not an unicast packet then send the packet
212*73b01e57SJeff Chen 	 * directly to os. Don't pass thru rx reordering
213*73b01e57SJeff Chen 	 */
214*73b01e57SJeff Chen 	if (!IS_11N_ENABLED(priv) ||
215*73b01e57SJeff Chen 	    !ether_addr_equal_unaligned(priv->curr_addr,
216*73b01e57SJeff Chen 					rx_pkt_hdr->eth803_hdr.h_dest)) {
217*73b01e57SJeff Chen 		nxpwifi_process_rx_packet(priv, skb);
218*73b01e57SJeff Chen 		return ret;
219*73b01e57SJeff Chen 	}
220*73b01e57SJeff Chen 
221*73b01e57SJeff Chen 	if (nxpwifi_queuing_ra_based(priv)) {
222*73b01e57SJeff Chen 		memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
223*73b01e57SJeff Chen 	} else {
224*73b01e57SJeff Chen 		if (rx_pkt_type != PKT_TYPE_BAR &&
225*73b01e57SJeff Chen 		    local_rx_pd->priority < MAX_NUM_TID)
226*73b01e57SJeff Chen 			priv->rx_seq[local_rx_pd->priority] = seq_num;
227*73b01e57SJeff Chen 		memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
228*73b01e57SJeff Chen 		       ETH_ALEN);
229*73b01e57SJeff Chen 	}
230*73b01e57SJeff Chen 
231*73b01e57SJeff Chen 	/* Reorder and send to OS */
232*73b01e57SJeff Chen 	ret = nxpwifi_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
233*73b01e57SJeff Chen 					 ta, (u8)rx_pkt_type, skb);
234*73b01e57SJeff Chen 
235*73b01e57SJeff Chen 	if (ret || rx_pkt_type == PKT_TYPE_BAR)
236*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
237*73b01e57SJeff Chen 
238*73b01e57SJeff Chen 	if (ret)
239*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
240*73b01e57SJeff Chen 
241*73b01e57SJeff Chen 	return ret;
242*73b01e57SJeff Chen }
243