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