xref: /openbmc/linux/net/mac80211/rx.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2571ecf67SJohannes Berg /*
3571ecf67SJohannes Berg  * Copyright 2002-2005, Instant802 Networks, Inc.
4571ecf67SJohannes Berg  * Copyright 2005-2006, Devicescape Software, Inc.
5571ecf67SJohannes Berg  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
684040805SJohannes Berg  * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
7d98ad83eSJohannes Berg  * Copyright 2013-2014  Intel Mobile Communications GmbH
8b7540d8fSSara Sharon  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
90e966d9aSJohannes Berg  * Copyright (C) 2018-2023 Intel Corporation
10571ecf67SJohannes Berg  */
11571ecf67SJohannes Berg 
12ab46623eSS.Çağlar Onur #include <linux/jiffies.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
14571ecf67SJohannes Berg #include <linux/kernel.h>
15571ecf67SJohannes Berg #include <linux/skbuff.h>
16571ecf67SJohannes Berg #include <linux/netdevice.h>
17571ecf67SJohannes Berg #include <linux/etherdevice.h>
18d4e46a3dSJohannes Berg #include <linux/rcupdate.h>
19bc3b2d7fSPaul Gortmaker #include <linux/export.h>
20183f47fcSSebastian Andrzej Siewior #include <linux/kcov.h>
2106470f74SSara Sharon #include <linux/bitops.h>
22571ecf67SJohannes Berg #include <net/mac80211.h>
23571ecf67SJohannes Berg #include <net/ieee80211_radiotap.h>
24d26ad377SJohannes Berg #include <asm/unaligned.h>
25571ecf67SJohannes Berg 
26571ecf67SJohannes Berg #include "ieee80211_i.h"
2724487981SJohannes Berg #include "driver-ops.h"
282c8dccc7SJohannes Berg #include "led.h"
2933b64eb2SLuis Carlos Cobo #include "mesh.h"
30571ecf67SJohannes Berg #include "wep.h"
31571ecf67SJohannes Berg #include "wpa.h"
32571ecf67SJohannes Berg #include "tkip.h"
33571ecf67SJohannes Berg #include "wme.h"
341d8d3decSJohannes Berg #include "rate.h"
35571ecf67SJohannes Berg 
36b2e7771eSJohannes Berg /*
37b2e7771eSJohannes Berg  * monitor mode reception
38b2e7771eSJohannes Berg  *
39b2e7771eSJohannes Berg  * This function cleans up the SKB, i.e. it removes all the stuff
40b2e7771eSJohannes Berg  * only useful for monitoring.
41b2e7771eSJohannes Berg  */
ieee80211_clean_skb(struct sk_buff * skb,unsigned int present_fcs_len,unsigned int rtap_space)42c1129924SJohannes Berg static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
4330841f5cSJohannes Berg 					   unsigned int present_fcs_len,
44c096b92aSJohannes Berg 					   unsigned int rtap_space)
45b2e7771eSJohannes Berg {
463a867c7eSMordechay Goodstein 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
47c1129924SJohannes Berg 	struct ieee80211_hdr *hdr;
48c1129924SJohannes Berg 	unsigned int hdrlen;
49c1129924SJohannes Berg 	__le16 fc;
50c1129924SJohannes Berg 
5130841f5cSJohannes Berg 	if (present_fcs_len)
5230841f5cSJohannes Berg 		__pskb_trim(skb, skb->len - present_fcs_len);
53d427c899SRichard Gobert 	pskb_pull(skb, rtap_space);
54c1129924SJohannes Berg 
553a867c7eSMordechay Goodstein 	/* After pulling radiotap header, clear all flags that indicate
563a867c7eSMordechay Goodstein 	 * info in skb->data.
573a867c7eSMordechay Goodstein 	 */
589179dff8SMordechay Goodstein 	status->flag &= ~(RX_FLAG_RADIOTAP_TLV_AT_END |
593a867c7eSMordechay Goodstein 			  RX_FLAG_RADIOTAP_LSIG |
603a867c7eSMordechay Goodstein 			  RX_FLAG_RADIOTAP_HE_MU |
613a867c7eSMordechay Goodstein 			  RX_FLAG_RADIOTAP_HE);
623a867c7eSMordechay Goodstein 
63c1129924SJohannes Berg 	hdr = (void *)skb->data;
64c1129924SJohannes Berg 	fc = hdr->frame_control;
65c1129924SJohannes Berg 
66c1129924SJohannes Berg 	/*
67c1129924SJohannes Berg 	 * Remove the HT-Control field (if present) on management
68c1129924SJohannes Berg 	 * frames after we've sent the frame to monitoring. We
69c1129924SJohannes Berg 	 * (currently) don't need it, and don't properly parse
70c1129924SJohannes Berg 	 * frames with it present, due to the assumption of a
71c1129924SJohannes Berg 	 * fixed management header length.
72c1129924SJohannes Berg 	 */
73c1129924SJohannes Berg 	if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc)))
74c1129924SJohannes Berg 		return skb;
75c1129924SJohannes Berg 
76c1129924SJohannes Berg 	hdrlen = ieee80211_hdrlen(fc);
77c1129924SJohannes Berg 	hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER);
78c1129924SJohannes Berg 
79c1129924SJohannes Berg 	if (!pskb_may_pull(skb, hdrlen)) {
80c1129924SJohannes Berg 		dev_kfree_skb(skb);
81c1129924SJohannes Berg 		return NULL;
82c1129924SJohannes Berg 	}
83c1129924SJohannes Berg 
84c1129924SJohannes Berg 	memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data,
85c1129924SJohannes Berg 		hdrlen - IEEE80211_HT_CTL_LEN);
86d427c899SRichard Gobert 	pskb_pull(skb, IEEE80211_HT_CTL_LEN);
87c1129924SJohannes Berg 
88c1129924SJohannes Berg 	return skb;
89b2e7771eSJohannes Berg }
90b2e7771eSJohannes Berg 
should_drop_frame(struct sk_buff * skb,int present_fcs_len,unsigned int rtap_space)911f7bba79SJohannes Berg static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
92c096b92aSJohannes Berg 				     unsigned int rtap_space)
93b2e7771eSJohannes Berg {
94f1d58c25SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
951f7bba79SJohannes Berg 	struct ieee80211_hdr *hdr;
961f7bba79SJohannes Berg 
97c096b92aSJohannes Berg 	hdr = (void *)(skb->data + rtap_space);
98b2e7771eSJohannes Berg 
994c298677SJohannes Berg 	if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
10017883048SGrzegorz Bajorski 			    RX_FLAG_FAILED_PLCP_CRC |
101c3d1f875SShaul Triebitz 			    RX_FLAG_ONLY_MONITOR |
102c3d1f875SShaul Triebitz 			    RX_FLAG_NO_PSDU))
1036b59db7dSZhao, Gang 		return true;
1046b59db7dSZhao, Gang 
105c096b92aSJohannes Berg 	if (unlikely(skb->len < 16 + present_fcs_len + rtap_space))
1066b59db7dSZhao, Gang 		return true;
1076b59db7dSZhao, Gang 
10887228f57SHarvey Harrison 	if (ieee80211_is_ctl(hdr->frame_control) &&
10987228f57SHarvey Harrison 	    !ieee80211_is_pspoll(hdr->frame_control) &&
11087228f57SHarvey Harrison 	    !ieee80211_is_back_req(hdr->frame_control))
1116b59db7dSZhao, Gang 		return true;
1126b59db7dSZhao, Gang 
1136b59db7dSZhao, Gang 	return false;
114b2e7771eSJohannes Berg }
115b2e7771eSJohannes Berg 
116601ae7f2SBruno Randolf static int
ieee80211_rx_radiotap_hdrlen(struct ieee80211_local * local,struct ieee80211_rx_status * status,struct sk_buff * skb)1171f7bba79SJohannes Berg ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
1181f7bba79SJohannes Berg 			     struct ieee80211_rx_status *status,
1191f7bba79SJohannes Berg 			     struct sk_buff *skb)
120601ae7f2SBruno Randolf {
121601ae7f2SBruno Randolf 	int len;
122601ae7f2SBruno Randolf 
123601ae7f2SBruno Randolf 	/* always present fields */
124a144f378SJohannes Berg 	len = sizeof(struct ieee80211_radiotap_header) + 8;
125601ae7f2SBruno Randolf 
126a144f378SJohannes Berg 	/* allocate extra bitmaps */
127a144f378SJohannes Berg 	if (status->chains)
128a144f378SJohannes Berg 		len += 4 * hweight8(status->chains);
12990b9e446SJohannes Berg 
13090b9e446SJohannes Berg 	if (ieee80211_have_rx_timestamp(status)) {
13190b9e446SJohannes Berg 		len = ALIGN(len, 8);
132601ae7f2SBruno Randolf 		len += 8;
13390b9e446SJohannes Berg 	}
13430686bf7SJohannes Berg 	if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
135601ae7f2SBruno Randolf 		len += 1;
136601ae7f2SBruno Randolf 
137a144f378SJohannes Berg 	/* antenna field, if we don't have per-chain info */
138a144f378SJohannes Berg 	if (!status->chains)
139a144f378SJohannes Berg 		len += 1;
140a144f378SJohannes Berg 
14190b9e446SJohannes Berg 	/* padding for RX_FLAGS if necessary */
14290b9e446SJohannes Berg 	len = ALIGN(len, 2);
143601ae7f2SBruno Randolf 
144da6a4352SJohannes Berg 	if (status->encoding == RX_ENC_HT) /* HT info */
1456d744bacSJohannes Berg 		len += 3;
1466d744bacSJohannes Berg 
1474c298677SJohannes Berg 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
14890b9e446SJohannes Berg 		len = ALIGN(len, 4);
1494c298677SJohannes Berg 		len += 8;
1504c298677SJohannes Berg 	}
1514c298677SJohannes Berg 
152da6a4352SJohannes Berg 	if (status->encoding == RX_ENC_VHT) {
15351648921SJohannes Berg 		len = ALIGN(len, 2);
15451648921SJohannes Berg 		len += 12;
15551648921SJohannes Berg 	}
15651648921SJohannes Berg 
15799ee7caeSJohannes Berg 	if (local->hw.radiotap_timestamp.units_pos >= 0) {
15899ee7caeSJohannes Berg 		len = ALIGN(len, 8);
15999ee7caeSJohannes Berg 		len += 12;
16099ee7caeSJohannes Berg 	}
16199ee7caeSJohannes Berg 
16241cbb0f5SLuca Coelho 	if (status->encoding == RX_ENC_HE &&
16341cbb0f5SLuca Coelho 	    status->flag & RX_FLAG_RADIOTAP_HE) {
16441cbb0f5SLuca Coelho 		len = ALIGN(len, 2);
16541cbb0f5SLuca Coelho 		len += 12;
16641cbb0f5SLuca Coelho 		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
16741cbb0f5SLuca Coelho 	}
16841cbb0f5SLuca Coelho 
16941cbb0f5SLuca Coelho 	if (status->encoding == RX_ENC_HE &&
17041cbb0f5SLuca Coelho 	    status->flag & RX_FLAG_RADIOTAP_HE_MU) {
17141cbb0f5SLuca Coelho 		len = ALIGN(len, 2);
17241cbb0f5SLuca Coelho 		len += 12;
17341cbb0f5SLuca Coelho 		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
17441cbb0f5SLuca Coelho 	}
17541cbb0f5SLuca Coelho 
176c3d1f875SShaul Triebitz 	if (status->flag & RX_FLAG_NO_PSDU)
177c3d1f875SShaul Triebitz 		len += 1;
178c3d1f875SShaul Triebitz 
179d1332e7bSShaul Triebitz 	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
180d1332e7bSShaul Triebitz 		len = ALIGN(len, 2);
181d1332e7bSShaul Triebitz 		len += 4;
182d1332e7bSShaul Triebitz 		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4);
183d1332e7bSShaul Triebitz 	}
184d1332e7bSShaul Triebitz 
185a144f378SJohannes Berg 	if (status->chains) {
186a144f378SJohannes Berg 		/* antenna and antenna signal fields */
187a144f378SJohannes Berg 		len += 2 * hweight8(status->chains);
188a144f378SJohannes Berg 	}
189a144f378SJohannes Berg 
1909179dff8SMordechay Goodstein 	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
1919179dff8SMordechay Goodstein 		int tlv_offset = 0;
192c15353beSLiad Kaufman 
193c15353beSLiad Kaufman 		/*
194c15353beSLiad Kaufman 		 * The position to look at depends on the existence (or non-
195c15353beSLiad Kaufman 		 * existence) of other elements, so take that into account...
196c15353beSLiad Kaufman 		 */
197c15353beSLiad Kaufman 		if (status->flag & RX_FLAG_RADIOTAP_HE)
1989179dff8SMordechay Goodstein 			tlv_offset +=
199c15353beSLiad Kaufman 				sizeof(struct ieee80211_radiotap_he);
200c15353beSLiad Kaufman 		if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
2019179dff8SMordechay Goodstein 			tlv_offset +=
202c15353beSLiad Kaufman 				sizeof(struct ieee80211_radiotap_he_mu);
203c15353beSLiad Kaufman 		if (status->flag & RX_FLAG_RADIOTAP_LSIG)
2049179dff8SMordechay Goodstein 			tlv_offset +=
205c15353beSLiad Kaufman 				sizeof(struct ieee80211_radiotap_lsig);
206c15353beSLiad Kaufman 
2079179dff8SMordechay Goodstein 		/* ensure 4 byte alignment for TLV */
2089179dff8SMordechay Goodstein 		len = ALIGN(len, 4);
2091f7bba79SJohannes Berg 
2109179dff8SMordechay Goodstein 		/* TLVs until the mac header */
2119179dff8SMordechay Goodstein 		len += skb_mac_header(skb) - &skb->data[tlv_offset];
2121f7bba79SJohannes Berg 	}
2131f7bba79SJohannes Berg 
214601ae7f2SBruno Randolf 	return len;
215601ae7f2SBruno Randolf }
216601ae7f2SBruno Randolf 
__ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data * sdata,int link_id,struct sta_info * sta,struct sk_buff * skb)217f057d140SJohannes Berg static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
2184f6c78deSJohannes Berg 					   int link_id,
2190044cc17SJohannes Berg 					   struct sta_info *sta,
2200044cc17SJohannes Berg 					   struct sk_buff *skb)
2210044cc17SJohannes Berg {
2224f6c78deSJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2234f6c78deSJohannes Berg 
2244f6c78deSJohannes Berg 	if (link_id >= 0) {
2254f6c78deSJohannes Berg 		status->link_valid = 1;
2264f6c78deSJohannes Berg 		status->link_id = link_id;
2274f6c78deSJohannes Berg 	} else {
2284f6c78deSJohannes Berg 		status->link_valid = 0;
2294f6c78deSJohannes Berg 	}
2304f6c78deSJohannes Berg 
2310044cc17SJohannes Berg 	skb_queue_tail(&sdata->skb_queue, skb);
23216114496SJohannes Berg 	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
2330044cc17SJohannes Berg 	if (sta)
234046d2e7cSSriram R 		sta->deflink.rx_stats.packets++;
2350044cc17SJohannes Berg }
2360044cc17SJohannes Berg 
ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data * sdata,int link_id,struct sta_info * sta,struct sk_buff * skb)237f057d140SJohannes Berg static void ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
2384f6c78deSJohannes Berg 					 int link_id,
239f057d140SJohannes Berg 					 struct sta_info *sta,
240f057d140SJohannes Berg 					 struct sk_buff *skb)
241f057d140SJohannes Berg {
242f057d140SJohannes Berg 	skb->protocol = 0;
2434f6c78deSJohannes Berg 	__ieee80211_queue_skb_to_iface(sdata, link_id, sta, skb);
244f057d140SJohannes Berg }
245f057d140SJohannes Berg 
ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int rtap_space)2469e478066SJohannes Berg static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
2479e478066SJohannes Berg 					 struct sk_buff *skb,
248c096b92aSJohannes Berg 					 int rtap_space)
2499e478066SJohannes Berg {
2509e478066SJohannes Berg 	struct {
2519e478066SJohannes Berg 		struct ieee80211_hdr_3addr hdr;
2529e478066SJohannes Berg 		u8 category;
2539e478066SJohannes Berg 		u8 action_code;
2547c53eb5dSMathieu Malaterre 	} __packed __aligned(2) action;
2559e478066SJohannes Berg 
2569e478066SJohannes Berg 	if (!sdata)
2579e478066SJohannes Berg 		return;
2589e478066SJohannes Berg 
2599e478066SJohannes Berg 	BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
2609e478066SJohannes Berg 
261c096b92aSJohannes Berg 	if (skb->len < rtap_space + sizeof(action) +
2629e478066SJohannes Berg 		       VHT_MUMIMO_GROUPS_DATA_LEN)
2639e478066SJohannes Berg 		return;
2649e478066SJohannes Berg 
2659e478066SJohannes Berg 	if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr))
2669e478066SJohannes Berg 		return;
2679e478066SJohannes Berg 
268c096b92aSJohannes Berg 	skb_copy_bits(skb, rtap_space, &action, sizeof(action));
2699e478066SJohannes Berg 
2709e478066SJohannes Berg 	if (!ieee80211_is_action(action.hdr.frame_control))
2719e478066SJohannes Berg 		return;
2729e478066SJohannes Berg 
2739e478066SJohannes Berg 	if (action.category != WLAN_CATEGORY_VHT)
2749e478066SJohannes Berg 		return;
2759e478066SJohannes Berg 
2769e478066SJohannes Berg 	if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT)
2779e478066SJohannes Berg 		return;
2789e478066SJohannes Berg 
2799e478066SJohannes Berg 	if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr))
2809e478066SJohannes Berg 		return;
2819e478066SJohannes Berg 
2829e478066SJohannes Berg 	skb = skb_copy(skb, GFP_ATOMIC);
2839e478066SJohannes Berg 	if (!skb)
2849e478066SJohannes Berg 		return;
2859e478066SJohannes Berg 
2864f6c78deSJohannes Berg 	ieee80211_queue_skb_to_iface(sdata, -1, NULL, skb);
2879e478066SJohannes Berg }
2889e478066SJohannes Berg 
28900ea6debSJohannes Berg /*
290601ae7f2SBruno Randolf  * ieee80211_add_rx_radiotap_header - add radiotap header
291601ae7f2SBruno Randolf  *
292601ae7f2SBruno Randolf  * add a radiotap header containing all the fields which the hardware provided.
293601ae7f2SBruno Randolf  */
294601ae7f2SBruno Randolf static void
ieee80211_add_rx_radiotap_header(struct ieee80211_local * local,struct sk_buff * skb,struct ieee80211_rate * rate,int rtap_len,bool has_fcs)295601ae7f2SBruno Randolf ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
296601ae7f2SBruno Randolf 				 struct sk_buff *skb,
297601ae7f2SBruno Randolf 				 struct ieee80211_rate *rate,
298973ef21aSFelix Fietkau 				 int rtap_len, bool has_fcs)
299601ae7f2SBruno Randolf {
300f1d58c25SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
301601ae7f2SBruno Randolf 	struct ieee80211_radiotap_header *rthdr;
302601ae7f2SBruno Randolf 	unsigned char *pos;
303a144f378SJohannes Berg 	__le32 *it_present;
304a144f378SJohannes Berg 	u32 it_present_val;
3056a86b9c7SJohannes Berg 	u16 rx_flags = 0;
306a5e70697SSimon Wunderlich 	u16 channel_flags = 0;
3079179dff8SMordechay Goodstein 	u32 tlvs_len = 0;
308a144f378SJohannes Berg 	int mpdulen, chain;
309a144f378SJohannes Berg 	unsigned long chains = status->chains;
31041cbb0f5SLuca Coelho 	struct ieee80211_radiotap_he he = {};
31141cbb0f5SLuca Coelho 	struct ieee80211_radiotap_he_mu he_mu = {};
312d1332e7bSShaul Triebitz 	struct ieee80211_radiotap_lsig lsig = {};
31341cbb0f5SLuca Coelho 
31441cbb0f5SLuca Coelho 	if (status->flag & RX_FLAG_RADIOTAP_HE) {
31541cbb0f5SLuca Coelho 		he = *(struct ieee80211_radiotap_he *)skb->data;
31641cbb0f5SLuca Coelho 		skb_pull(skb, sizeof(he));
31741cbb0f5SLuca Coelho 		WARN_ON_ONCE(status->encoding != RX_ENC_HE);
31841cbb0f5SLuca Coelho 	}
31941cbb0f5SLuca Coelho 
32041cbb0f5SLuca Coelho 	if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
32141cbb0f5SLuca Coelho 		he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
32241cbb0f5SLuca Coelho 		skb_pull(skb, sizeof(he_mu));
32341cbb0f5SLuca Coelho 	}
3241f7bba79SJohannes Berg 
325d1332e7bSShaul Triebitz 	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
326d1332e7bSShaul Triebitz 		lsig = *(struct ieee80211_radiotap_lsig *)skb->data;
327d1332e7bSShaul Triebitz 		skb_pull(skb, sizeof(lsig));
328d1332e7bSShaul Triebitz 	}
329d1332e7bSShaul Triebitz 
3309179dff8SMordechay Goodstein 	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
3319179dff8SMordechay Goodstein 		/* data is pointer at tlv all other info was pulled off */
3329179dff8SMordechay Goodstein 		tlvs_len = skb_mac_header(skb) - skb->data;
3331f7bba79SJohannes Berg 	}
334f4bda337SThomas Pedersen 
335f4bda337SThomas Pedersen 	mpdulen = skb->len;
33630686bf7SJohannes Berg 	if (!(has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)))
337f4bda337SThomas Pedersen 		mpdulen += FCS_LEN;
338601ae7f2SBruno Randolf 
3399179dff8SMordechay Goodstein 	rthdr = skb_push(skb, rtap_len - tlvs_len);
3409179dff8SMordechay Goodstein 	memset(rthdr, 0, rtap_len - tlvs_len);
341a144f378SJohannes Berg 	it_present = &rthdr->it_present;
342601ae7f2SBruno Randolf 
343601ae7f2SBruno Randolf 	/* radiotap header, set always present flags */
3440059b2b1SEmmanuel Grumbach 	rthdr->it_len = cpu_to_le16(rtap_len);
345a144f378SJohannes Berg 	it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
346a144f378SJohannes Berg 			 BIT(IEEE80211_RADIOTAP_CHANNEL) |
347a144f378SJohannes Berg 			 BIT(IEEE80211_RADIOTAP_RX_FLAGS);
348601ae7f2SBruno Randolf 
349a144f378SJohannes Berg 	if (!status->chains)
350a144f378SJohannes Berg 		it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
351a144f378SJohannes Berg 
352a144f378SJohannes Berg 	for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
353a144f378SJohannes Berg 		it_present_val |=
354a144f378SJohannes Berg 			BIT(IEEE80211_RADIOTAP_EXT) |
355a144f378SJohannes Berg 			BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
356a144f378SJohannes Berg 		put_unaligned_le32(it_present_val, it_present);
357a144f378SJohannes Berg 		it_present++;
358a144f378SJohannes Berg 		it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
359a144f378SJohannes Berg 				 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
360a144f378SJohannes Berg 	}
361601ae7f2SBruno Randolf 
3629179dff8SMordechay Goodstein 	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
3639179dff8SMordechay Goodstein 		it_present_val |= BIT(IEEE80211_RADIOTAP_TLV);
3641f7bba79SJohannes Berg 
365a144f378SJohannes Berg 	put_unaligned_le32(it_present_val, it_present);
366a144f378SJohannes Berg 
3678c89f7b3SKees Cook 	/* This references through an offset into it_optional[] rather
3688c89f7b3SKees Cook 	 * than via it_present otherwise later uses of pos will cause
3698c89f7b3SKees Cook 	 * the compiler to think we have walked past the end of the
3708c89f7b3SKees Cook 	 * struct member.
3718c89f7b3SKees Cook 	 */
372c033a38aSJohannes Berg 	pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
373a144f378SJohannes Berg 
374601ae7f2SBruno Randolf 	/* the order of the following fields is important */
375601ae7f2SBruno Randolf 
376601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_TSFT */
377f4bda337SThomas Pedersen 	if (ieee80211_have_rx_timestamp(status)) {
37890b9e446SJohannes Berg 		/* padding */
37990b9e446SJohannes Berg 		while ((pos - (u8 *)rthdr) & 7)
38090b9e446SJohannes Berg 			*pos++ = 0;
381f4bda337SThomas Pedersen 		put_unaligned_le64(
382f4bda337SThomas Pedersen 			ieee80211_calculate_rx_timestamp(local, status,
383f4bda337SThomas Pedersen 							 mpdulen, 0),
384f4bda337SThomas Pedersen 			pos);
3855cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_TSFT));
386601ae7f2SBruno Randolf 		pos += 8;
387601ae7f2SBruno Randolf 	}
388601ae7f2SBruno Randolf 
389601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_FLAGS */
39030686bf7SJohannes Berg 	if (has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS))
391601ae7f2SBruno Randolf 		*pos |= IEEE80211_RADIOTAP_F_FCS;
392aae89831SJohannes Berg 	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
393aae89831SJohannes Berg 		*pos |= IEEE80211_RADIOTAP_F_BADFCS;
3947fdd69c5SJohannes Berg 	if (status->enc_flags & RX_ENC_FLAG_SHORTPRE)
395b4f28bbbSBruno Randolf 		*pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
396601ae7f2SBruno Randolf 	pos++;
397601ae7f2SBruno Randolf 
398601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_RATE */
399da6a4352SJohannes Berg 	if (!rate || status->encoding != RX_ENC_LEGACY) {
4000fb8ca45SJouni Malinen 		/*
401f8d1ccf1SJohannes Berg 		 * Without rate information don't add it. If we have,
40238f37be2SMohammed Shafi Shajakhan 		 * MCS information is a separate field in radiotap,
40373b48099SJohannes Berg 		 * added below. The byte here is needed as padding
40473b48099SJohannes Berg 		 * for the channel though, so initialise it to 0.
4050fb8ca45SJouni Malinen 		 */
4060fb8ca45SJouni Malinen 		*pos = 0;
4078d6f658eSJouni Malinen 	} else {
4082103dec1SSimon Wunderlich 		int shift = 0;
4095cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_RATE));
410da6a4352SJohannes Berg 		if (status->bw == RATE_INFO_BW_10)
4112103dec1SSimon Wunderlich 			shift = 1;
412da6a4352SJohannes Berg 		else if (status->bw == RATE_INFO_BW_5)
4132103dec1SSimon Wunderlich 			shift = 2;
4142103dec1SSimon Wunderlich 		*pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift));
4158d6f658eSJouni Malinen 	}
416601ae7f2SBruno Randolf 	pos++;
417601ae7f2SBruno Randolf 
418601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_CHANNEL */
4193b23c184SThomas Pedersen 	/* TODO: frequency offset in KHz */
4206a86b9c7SJohannes Berg 	put_unaligned_le16(status->freq, pos);
421601ae7f2SBruno Randolf 	pos += 2;
422da6a4352SJohannes Berg 	if (status->bw == RATE_INFO_BW_10)
423a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_HALF;
424da6a4352SJohannes Berg 	else if (status->bw == RATE_INFO_BW_5)
425a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_QUARTER;
426a5e70697SSimon Wunderlich 
427412a84b5SAloka Dixit 	if (status->band == NL80211_BAND_5GHZ ||
428412a84b5SAloka Dixit 	    status->band == NL80211_BAND_6GHZ)
429a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
430da6a4352SJohannes Berg 	else if (status->encoding != RX_ENC_LEGACY)
431a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
432f8d1ccf1SJohannes Berg 	else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
433a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
434f8d1ccf1SJohannes Berg 	else if (rate)
4353a5c5e81SMathy Vanhoef 		channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ;
436f8d1ccf1SJohannes Berg 	else
437a5e70697SSimon Wunderlich 		channel_flags |= IEEE80211_CHAN_2GHZ;
438a5e70697SSimon Wunderlich 	put_unaligned_le16(channel_flags, pos);
439601ae7f2SBruno Randolf 	pos += 2;
440601ae7f2SBruno Randolf 
441601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
44230686bf7SJohannes Berg 	if (ieee80211_hw_check(&local->hw, SIGNAL_DBM) &&
443fe8431f8SFelix Fietkau 	    !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
444601ae7f2SBruno Randolf 		*pos = status->signal;
445601ae7f2SBruno Randolf 		rthdr->it_present |=
4465cafd378SKees Cook 			cpu_to_le32(BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL));
447601ae7f2SBruno Randolf 		pos++;
448601ae7f2SBruno Randolf 	}
449601ae7f2SBruno Randolf 
450601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
451601ae7f2SBruno Randolf 
452a144f378SJohannes Berg 	if (!status->chains) {
453601ae7f2SBruno Randolf 		/* IEEE80211_RADIOTAP_ANTENNA */
454601ae7f2SBruno Randolf 		*pos = status->antenna;
455601ae7f2SBruno Randolf 		pos++;
456a144f378SJohannes Berg 	}
457601ae7f2SBruno Randolf 
458601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
459601ae7f2SBruno Randolf 
460601ae7f2SBruno Randolf 	/* IEEE80211_RADIOTAP_RX_FLAGS */
461601ae7f2SBruno Randolf 	/* ensure 2 byte alignment for the 2 byte field as required */
4626a86b9c7SJohannes Berg 	if ((pos - (u8 *)rthdr) & 1)
46390b9e446SJohannes Berg 		*pos++ = 0;
464aae89831SJohannes Berg 	if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
4656a86b9c7SJohannes Berg 		rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
4666a86b9c7SJohannes Berg 	put_unaligned_le16(rx_flags, pos);
467601ae7f2SBruno Randolf 	pos += 2;
4686d744bacSJohannes Berg 
469da6a4352SJohannes Berg 	if (status->encoding == RX_ENC_HT) {
470786677d1SOleksij Rempel 		unsigned int stbc;
471786677d1SOleksij Rempel 
4725cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS));
47357553c3aSP Praneesh 		*pos = local->hw.radiotap_mcs_details;
47457553c3aSP Praneesh 		if (status->enc_flags & RX_ENC_FLAG_HT_GF)
47557553c3aSP Praneesh 			*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
47657553c3aSP Praneesh 		if (status->enc_flags & RX_ENC_FLAG_LDPC)
47757553c3aSP Praneesh 			*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FEC;
47857553c3aSP Praneesh 		pos++;
4796d744bacSJohannes Berg 		*pos = 0;
4807fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
4816d744bacSJohannes Berg 			*pos |= IEEE80211_RADIOTAP_MCS_SGI;
482da6a4352SJohannes Berg 		if (status->bw == RATE_INFO_BW_40)
4836d744bacSJohannes Berg 			*pos |= IEEE80211_RADIOTAP_MCS_BW_40;
4847fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_HT_GF)
485ac55d2feSJohannes Berg 			*pos |= IEEE80211_RADIOTAP_MCS_FMT_GF;
4867fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_LDPC)
48763c361f5SEmmanuel Grumbach 			*pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
4887fdd69c5SJohannes Berg 		stbc = (status->enc_flags & RX_ENC_FLAG_STBC_MASK) >> RX_ENC_FLAG_STBC_SHIFT;
489786677d1SOleksij Rempel 		*pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT;
4906d744bacSJohannes Berg 		pos++;
4916d744bacSJohannes Berg 		*pos++ = status->rate_idx;
4926d744bacSJohannes Berg 	}
4934c298677SJohannes Berg 
4944c298677SJohannes Berg 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
4954c298677SJohannes Berg 		u16 flags = 0;
4964c298677SJohannes Berg 
4974c298677SJohannes Berg 		/* ensure 4 byte alignment */
4984c298677SJohannes Berg 		while ((pos - (u8 *)rthdr) & 3)
4994c298677SJohannes Berg 			pos++;
5004c298677SJohannes Berg 		rthdr->it_present |=
5015cafd378SKees Cook 			cpu_to_le32(BIT(IEEE80211_RADIOTAP_AMPDU_STATUS));
5024c298677SJohannes Berg 		put_unaligned_le32(status->ampdu_reference, pos);
5034c298677SJohannes Berg 		pos += 4;
5044c298677SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN)
5054c298677SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
5064c298677SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_IS_LAST)
5074c298677SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
5084c298677SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
5094c298677SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
5104c298677SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
5114c298677SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
5127299d6f7SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
5137299d6f7SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
5147299d6f7SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
5157299d6f7SJohannes Berg 			flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
5164c298677SJohannes Berg 		put_unaligned_le16(flags, pos);
5174c298677SJohannes Berg 		pos += 2;
5184c298677SJohannes Berg 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
5194c298677SJohannes Berg 			*pos++ = status->ampdu_delimiter_crc;
5204c298677SJohannes Berg 		else
5214c298677SJohannes Berg 			*pos++ = 0;
5224c298677SJohannes Berg 		*pos++ = 0;
5234c298677SJohannes Berg 	}
52490b9e446SJohannes Berg 
525da6a4352SJohannes Berg 	if (status->encoding == RX_ENC_VHT) {
52651648921SJohannes Berg 		u16 known = local->hw.radiotap_vht_details;
52751648921SJohannes Berg 
5285cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT));
52951648921SJohannes Berg 		put_unaligned_le16(known, pos);
53051648921SJohannes Berg 		pos += 2;
53151648921SJohannes Berg 		/* flags */
5327fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
53351648921SJohannes Berg 			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
53463c361f5SEmmanuel Grumbach 		/* in VHT, STBC is binary */
5357fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_STBC_MASK)
53663c361f5SEmmanuel Grumbach 			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
5377fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_BF)
538fb378c23SEmmanuel Grumbach 			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
53951648921SJohannes Berg 		pos++;
54051648921SJohannes Berg 		/* bandwidth */
541da6a4352SJohannes Berg 		switch (status->bw) {
542da6a4352SJohannes Berg 		case RATE_INFO_BW_80:
54351648921SJohannes Berg 			*pos++ = 4;
544da6a4352SJohannes Berg 			break;
545da6a4352SJohannes Berg 		case RATE_INFO_BW_160:
54651648921SJohannes Berg 			*pos++ = 11;
547da6a4352SJohannes Berg 			break;
548da6a4352SJohannes Berg 		case RATE_INFO_BW_40:
54951648921SJohannes Berg 			*pos++ = 1;
550da6a4352SJohannes Berg 			break;
551da6a4352SJohannes Berg 		default:
55251648921SJohannes Berg 			*pos++ = 0;
553da6a4352SJohannes Berg 		}
55451648921SJohannes Berg 		/* MCS/NSS */
5558613c948SJohannes Berg 		*pos = (status->rate_idx << 4) | status->nss;
55651648921SJohannes Berg 		pos += 4;
55751648921SJohannes Berg 		/* coding field */
5587fdd69c5SJohannes Berg 		if (status->enc_flags & RX_ENC_FLAG_LDPC)
55963c361f5SEmmanuel Grumbach 			*pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
56051648921SJohannes Berg 		pos++;
56151648921SJohannes Berg 		/* group ID */
56251648921SJohannes Berg 		pos++;
56351648921SJohannes Berg 		/* partial_aid */
56451648921SJohannes Berg 		pos += 2;
56551648921SJohannes Berg 	}
56651648921SJohannes Berg 
56799ee7caeSJohannes Berg 	if (local->hw.radiotap_timestamp.units_pos >= 0) {
56899ee7caeSJohannes Berg 		u16 accuracy = 0;
56999ee7caeSJohannes Berg 		u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT;
57099ee7caeSJohannes Berg 
57199ee7caeSJohannes Berg 		rthdr->it_present |=
5725cafd378SKees Cook 			cpu_to_le32(BIT(IEEE80211_RADIOTAP_TIMESTAMP));
57399ee7caeSJohannes Berg 
57499ee7caeSJohannes Berg 		/* ensure 8 byte alignment */
57599ee7caeSJohannes Berg 		while ((pos - (u8 *)rthdr) & 7)
57699ee7caeSJohannes Berg 			pos++;
57799ee7caeSJohannes Berg 
57899ee7caeSJohannes Berg 		put_unaligned_le64(status->device_timestamp, pos);
57999ee7caeSJohannes Berg 		pos += sizeof(u64);
58099ee7caeSJohannes Berg 
58199ee7caeSJohannes Berg 		if (local->hw.radiotap_timestamp.accuracy >= 0) {
58299ee7caeSJohannes Berg 			accuracy = local->hw.radiotap_timestamp.accuracy;
58399ee7caeSJohannes Berg 			flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY;
58499ee7caeSJohannes Berg 		}
58599ee7caeSJohannes Berg 		put_unaligned_le16(accuracy, pos);
58699ee7caeSJohannes Berg 		pos += sizeof(u16);
58799ee7caeSJohannes Berg 
58899ee7caeSJohannes Berg 		*pos++ = local->hw.radiotap_timestamp.units_pos;
58999ee7caeSJohannes Berg 		*pos++ = flags;
59099ee7caeSJohannes Berg 	}
59199ee7caeSJohannes Berg 
59241cbb0f5SLuca Coelho 	if (status->encoding == RX_ENC_HE &&
59341cbb0f5SLuca Coelho 	    status->flag & RX_FLAG_RADIOTAP_HE) {
594331aead5SJohannes Berg #define HE_PREP(f, val)	le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f)
59541cbb0f5SLuca Coelho 
59641cbb0f5SLuca Coelho 		if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
59741cbb0f5SLuca Coelho 			he.data6 |= HE_PREP(DATA6_NSTS,
59841cbb0f5SLuca Coelho 					    FIELD_GET(RX_ENC_FLAG_STBC_MASK,
59941cbb0f5SLuca Coelho 						      status->enc_flags));
60041cbb0f5SLuca Coelho 			he.data3 |= HE_PREP(DATA3_STBC, 1);
60141cbb0f5SLuca Coelho 		} else {
60241cbb0f5SLuca Coelho 			he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
60341cbb0f5SLuca Coelho 		}
60441cbb0f5SLuca Coelho 
60541cbb0f5SLuca Coelho #define CHECK_GI(s) \
60641cbb0f5SLuca Coelho 	BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
60741cbb0f5SLuca Coelho 		     (int)NL80211_RATE_INFO_HE_GI_##s)
60841cbb0f5SLuca Coelho 
60941cbb0f5SLuca Coelho 		CHECK_GI(0_8);
61041cbb0f5SLuca Coelho 		CHECK_GI(1_6);
61141cbb0f5SLuca Coelho 		CHECK_GI(3_2);
61241cbb0f5SLuca Coelho 
61341cbb0f5SLuca Coelho 		he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
61441cbb0f5SLuca Coelho 		he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
61541cbb0f5SLuca Coelho 		he.data3 |= HE_PREP(DATA3_CODING,
61641cbb0f5SLuca Coelho 				    !!(status->enc_flags & RX_ENC_FLAG_LDPC));
61741cbb0f5SLuca Coelho 
61841cbb0f5SLuca Coelho 		he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
61941cbb0f5SLuca Coelho 
62041cbb0f5SLuca Coelho 		switch (status->bw) {
62141cbb0f5SLuca Coelho 		case RATE_INFO_BW_20:
62241cbb0f5SLuca Coelho 			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62341cbb0f5SLuca Coelho 					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
62441cbb0f5SLuca Coelho 			break;
62541cbb0f5SLuca Coelho 		case RATE_INFO_BW_40:
62641cbb0f5SLuca Coelho 			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62741cbb0f5SLuca Coelho 					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
62841cbb0f5SLuca Coelho 			break;
62941cbb0f5SLuca Coelho 		case RATE_INFO_BW_80:
63041cbb0f5SLuca Coelho 			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63141cbb0f5SLuca Coelho 					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
63241cbb0f5SLuca Coelho 			break;
63341cbb0f5SLuca Coelho 		case RATE_INFO_BW_160:
63441cbb0f5SLuca Coelho 			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63541cbb0f5SLuca Coelho 					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
63641cbb0f5SLuca Coelho 			break;
63741cbb0f5SLuca Coelho 		case RATE_INFO_BW_HE_RU:
63841cbb0f5SLuca Coelho #define CHECK_RU_ALLOC(s) \
63941cbb0f5SLuca Coelho 	BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
64041cbb0f5SLuca Coelho 		     NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
64141cbb0f5SLuca Coelho 
64241cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(26);
64341cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(52);
64441cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(106);
64541cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(242);
64641cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(484);
64741cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(996);
64841cbb0f5SLuca Coelho 			CHECK_RU_ALLOC(2x996);
64941cbb0f5SLuca Coelho 
65041cbb0f5SLuca Coelho 			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
65141cbb0f5SLuca Coelho 					    status->he_ru + 4);
65241cbb0f5SLuca Coelho 			break;
65341cbb0f5SLuca Coelho 		default:
65441cbb0f5SLuca Coelho 			WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
65541cbb0f5SLuca Coelho 		}
65641cbb0f5SLuca Coelho 
65741cbb0f5SLuca Coelho 		/* ensure 2 byte alignment */
65841cbb0f5SLuca Coelho 		while ((pos - (u8 *)rthdr) & 1)
65941cbb0f5SLuca Coelho 			pos++;
6605cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE));
66141cbb0f5SLuca Coelho 		memcpy(pos, &he, sizeof(he));
66241cbb0f5SLuca Coelho 		pos += sizeof(he);
66341cbb0f5SLuca Coelho 	}
66441cbb0f5SLuca Coelho 
66541cbb0f5SLuca Coelho 	if (status->encoding == RX_ENC_HE &&
66641cbb0f5SLuca Coelho 	    status->flag & RX_FLAG_RADIOTAP_HE_MU) {
66741cbb0f5SLuca Coelho 		/* ensure 2 byte alignment */
66841cbb0f5SLuca Coelho 		while ((pos - (u8 *)rthdr) & 1)
66941cbb0f5SLuca Coelho 			pos++;
6705cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE_MU));
67141cbb0f5SLuca Coelho 		memcpy(pos, &he_mu, sizeof(he_mu));
67241cbb0f5SLuca Coelho 		pos += sizeof(he_mu);
67341cbb0f5SLuca Coelho 	}
67441cbb0f5SLuca Coelho 
675c3d1f875SShaul Triebitz 	if (status->flag & RX_FLAG_NO_PSDU) {
676c3d1f875SShaul Triebitz 		rthdr->it_present |=
6775cafd378SKees Cook 			cpu_to_le32(BIT(IEEE80211_RADIOTAP_ZERO_LEN_PSDU));
678c3d1f875SShaul Triebitz 		*pos++ = status->zero_length_psdu_type;
679c3d1f875SShaul Triebitz 	}
680c3d1f875SShaul Triebitz 
681d1332e7bSShaul Triebitz 	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
682d1332e7bSShaul Triebitz 		/* ensure 2 byte alignment */
683d1332e7bSShaul Triebitz 		while ((pos - (u8 *)rthdr) & 1)
684d1332e7bSShaul Triebitz 			pos++;
6855cafd378SKees Cook 		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_LSIG));
686d1332e7bSShaul Triebitz 		memcpy(pos, &lsig, sizeof(lsig));
687d1332e7bSShaul Triebitz 		pos += sizeof(lsig);
688d1332e7bSShaul Triebitz 	}
689d1332e7bSShaul Triebitz 
690a144f378SJohannes Berg 	for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
691a144f378SJohannes Berg 		*pos++ = status->chain_signal[chain];
692a144f378SJohannes Berg 		*pos++ = chain;
693a144f378SJohannes Berg 	}
694601ae7f2SBruno Randolf }
695601ae7f2SBruno Randolf 
696127f60bfSJohannes Berg static struct sk_buff *
ieee80211_make_monitor_skb(struct ieee80211_local * local,struct sk_buff ** origskb,struct ieee80211_rate * rate,int rtap_space,bool use_origskb)697127f60bfSJohannes Berg ieee80211_make_monitor_skb(struct ieee80211_local *local,
698127f60bfSJohannes Berg 			   struct sk_buff **origskb,
699127f60bfSJohannes Berg 			   struct ieee80211_rate *rate,
700c096b92aSJohannes Berg 			   int rtap_space, bool use_origskb)
701127f60bfSJohannes Berg {
702127f60bfSJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(*origskb);
703127f60bfSJohannes Berg 	int rt_hdrlen, needed_headroom;
704127f60bfSJohannes Berg 	struct sk_buff *skb;
705127f60bfSJohannes Berg 
706127f60bfSJohannes Berg 	/* room for the radiotap header based on driver features */
707127f60bfSJohannes Berg 	rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, *origskb);
708c096b92aSJohannes Berg 	needed_headroom = rt_hdrlen - rtap_space;
709127f60bfSJohannes Berg 
710127f60bfSJohannes Berg 	if (use_origskb) {
711127f60bfSJohannes Berg 		/* only need to expand headroom if necessary */
712127f60bfSJohannes Berg 		skb = *origskb;
713127f60bfSJohannes Berg 		*origskb = NULL;
714127f60bfSJohannes Berg 
715127f60bfSJohannes Berg 		/*
716127f60bfSJohannes Berg 		 * This shouldn't trigger often because most devices have an
717127f60bfSJohannes Berg 		 * RX header they pull before we get here, and that should
718127f60bfSJohannes Berg 		 * be big enough for our radiotap information. We should
719127f60bfSJohannes Berg 		 * probably export the length to drivers so that we can have
720127f60bfSJohannes Berg 		 * them allocate enough headroom to start with.
721127f60bfSJohannes Berg 		 */
722127f60bfSJohannes Berg 		if (skb_headroom(skb) < needed_headroom &&
723127f60bfSJohannes Berg 		    pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
724127f60bfSJohannes Berg 			dev_kfree_skb(skb);
725127f60bfSJohannes Berg 			return NULL;
726127f60bfSJohannes Berg 		}
727127f60bfSJohannes Berg 	} else {
728127f60bfSJohannes Berg 		/*
729127f60bfSJohannes Berg 		 * Need to make a copy and possibly remove radiotap header
730127f60bfSJohannes Berg 		 * and FCS from the original.
731127f60bfSJohannes Berg 		 */
732ec61cd49SJohan Almbladh 		skb = skb_copy_expand(*origskb, needed_headroom + NET_SKB_PAD,
733ec61cd49SJohan Almbladh 				      0, GFP_ATOMIC);
734127f60bfSJohannes Berg 
735127f60bfSJohannes Berg 		if (!skb)
736127f60bfSJohannes Berg 			return NULL;
737127f60bfSJohannes Berg 	}
738127f60bfSJohannes Berg 
739127f60bfSJohannes Berg 	/* prepend radiotap information */
740127f60bfSJohannes Berg 	ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true);
741127f60bfSJohannes Berg 
742127f60bfSJohannes Berg 	skb_reset_mac_header(skb);
743127f60bfSJohannes Berg 	skb->ip_summed = CHECKSUM_UNNECESSARY;
744127f60bfSJohannes Berg 	skb->pkt_type = PACKET_OTHERHOST;
745127f60bfSJohannes Berg 	skb->protocol = htons(ETH_P_802_2);
746127f60bfSJohannes Berg 
747127f60bfSJohannes Berg 	return skb;
748127f60bfSJohannes Berg }
749127f60bfSJohannes Berg 
750b2e7771eSJohannes Berg /*
751b2e7771eSJohannes Berg  * This function copies a received frame to all monitor interfaces and
752b2e7771eSJohannes Berg  * returns a cleaned-up SKB that no longer includes the FCS nor the
753b2e7771eSJohannes Berg  * radiotap header the driver might have added.
754b2e7771eSJohannes Berg  */
755b2e7771eSJohannes Berg static struct sk_buff *
ieee80211_rx_monitor(struct ieee80211_local * local,struct sk_buff * origskb,struct ieee80211_rate * rate)756b2e7771eSJohannes Berg ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
7578318d78aSJohannes Berg 		     struct ieee80211_rate *rate)
758b2e7771eSJohannes Berg {
759f1d58c25SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
760b2e7771eSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
761127f60bfSJohannes Berg 	struct sk_buff *monskb = NULL;
762b2e7771eSJohannes Berg 	int present_fcs_len = 0;
763c096b92aSJohannes Berg 	unsigned int rtap_space = 0;
76442bd20d9SAviya Erenfeld 	struct ieee80211_sub_if_data *monitor_sdata =
76542bd20d9SAviya Erenfeld 		rcu_dereference(local->monitor_sdata);
766127f60bfSJohannes Berg 	bool only_monitor = false;
7678020919aSIlan Peer 	unsigned int min_head_len;
7681f7bba79SJohannes Berg 
7699179dff8SMordechay Goodstein 	if (WARN_ON_ONCE(status->flag & RX_FLAG_RADIOTAP_TLV_AT_END &&
7709179dff8SMordechay Goodstein 			 !skb_mac_header_was_set(origskb))) {
7719179dff8SMordechay Goodstein 		/* with this skb no way to know where frame payload starts */
7729179dff8SMordechay Goodstein 		dev_kfree_skb(origskb);
7739179dff8SMordechay Goodstein 		return NULL;
7749179dff8SMordechay Goodstein 	}
7759179dff8SMordechay Goodstein 
77641cbb0f5SLuca Coelho 	if (status->flag & RX_FLAG_RADIOTAP_HE)
77741cbb0f5SLuca Coelho 		rtap_space += sizeof(struct ieee80211_radiotap_he);
77841cbb0f5SLuca Coelho 
77941cbb0f5SLuca Coelho 	if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
78041cbb0f5SLuca Coelho 		rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
78141cbb0f5SLuca Coelho 
782d359bbceSIlan Peer 	if (status->flag & RX_FLAG_RADIOTAP_LSIG)
783d359bbceSIlan Peer 		rtap_space += sizeof(struct ieee80211_radiotap_lsig);
784d359bbceSIlan Peer 
7859179dff8SMordechay Goodstein 	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
7869179dff8SMordechay Goodstein 		rtap_space += skb_mac_header(origskb) - &origskb->data[rtap_space];
787b2e7771eSJohannes Berg 
7888020919aSIlan Peer 	min_head_len = rtap_space;
7898020919aSIlan Peer 
790b2e7771eSJohannes Berg 	/*
791b2e7771eSJohannes Berg 	 * First, we may need to make a copy of the skb because
792b2e7771eSJohannes Berg 	 *  (1) we need to modify it for radiotap (if not present), and
793b2e7771eSJohannes Berg 	 *  (2) the other RX handlers will modify the skb we got.
794b2e7771eSJohannes Berg 	 *
795b2e7771eSJohannes Berg 	 * We don't need to, of course, if we aren't going to return
796b2e7771eSJohannes Berg 	 * the SKB because it has a bad FCS/PLCP checksum.
797b2e7771eSJohannes Berg 	 */
7980869aea0SJohannes Berg 
7998020919aSIlan Peer 	if (!(status->flag & RX_FLAG_NO_PSDU)) {
80030841f5cSJohannes Berg 		if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
8018020919aSIlan Peer 			if (unlikely(origskb->len <= FCS_LEN + rtap_space)) {
80230841f5cSJohannes Berg 				/* driver bug */
80330841f5cSJohannes Berg 				WARN_ON(1);
80430841f5cSJohannes Berg 				dev_kfree_skb(origskb);
80530841f5cSJohannes Berg 				return NULL;
80630841f5cSJohannes Berg 			}
807b2e7771eSJohannes Berg 			present_fcs_len = FCS_LEN;
80830841f5cSJohannes Berg 		}
809b2e7771eSJohannes Berg 
8108020919aSIlan Peer 		/* also consider the hdr->frame_control */
8118020919aSIlan Peer 		min_head_len += 2;
8128020919aSIlan Peer 	}
8138020919aSIlan Peer 
8148020919aSIlan Peer 	/* ensure that the expected data elements are in skb head */
8158020919aSIlan Peer 	if (!pskb_may_pull(origskb, min_head_len)) {
816e3cf8b3fSZhu Yi 		dev_kfree_skb(origskb);
817e3cf8b3fSZhu Yi 		return NULL;
818e3cf8b3fSZhu Yi 	}
819e3cf8b3fSZhu Yi 
820c096b92aSJohannes Berg 	only_monitor = should_drop_frame(origskb, present_fcs_len, rtap_space);
821127f60bfSJohannes Berg 
82217883048SGrzegorz Bajorski 	if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
823127f60bfSJohannes Berg 		if (only_monitor) {
824b2e7771eSJohannes Berg 			dev_kfree_skb(origskb);
825b2e7771eSJohannes Berg 			return NULL;
826b2e7771eSJohannes Berg 		}
827b2e7771eSJohannes Berg 
828c1129924SJohannes Berg 		return ieee80211_clean_skb(origskb, present_fcs_len,
829c1129924SJohannes Berg 					   rtap_space);
830b2e7771eSJohannes Berg 	}
831b2e7771eSJohannes Berg 
832c096b92aSJohannes Berg 	ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
8339e478066SJohannes Berg 
834f64331d5SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
835127f60bfSJohannes Berg 		bool last_monitor = list_is_last(&sdata->u.mntr.list,
836127f60bfSJohannes Berg 						 &local->mon_list);
837127f60bfSJohannes Berg 
838127f60bfSJohannes Berg 		if (!monskb)
839127f60bfSJohannes Berg 			monskb = ieee80211_make_monitor_skb(local, &origskb,
840c096b92aSJohannes Berg 							    rate, rtap_space,
841127f60bfSJohannes Berg 							    only_monitor &&
842127f60bfSJohannes Berg 							    last_monitor);
843127f60bfSJohannes Berg 
844127f60bfSJohannes Berg 		if (monskb) {
845127f60bfSJohannes Berg 			struct sk_buff *skb;
846127f60bfSJohannes Berg 
847127f60bfSJohannes Berg 			if (last_monitor) {
848127f60bfSJohannes Berg 				skb = monskb;
849127f60bfSJohannes Berg 				monskb = NULL;
850127f60bfSJohannes Berg 			} else {
851127f60bfSJohannes Berg 				skb = skb_clone(monskb, GFP_ATOMIC);
852b2e7771eSJohannes Berg 			}
853b2e7771eSJohannes Berg 
854127f60bfSJohannes Berg 			if (skb) {
855127f60bfSJohannes Berg 				skb->dev = sdata->dev;
85636ec144fSLev Stipakov 				dev_sw_netstats_rx_add(skb->dev, skb->len);
8575548a8a1SJohn W. Linville 				netif_receive_skb(skb);
858127f60bfSJohannes Berg 			}
859127f60bfSJohannes Berg 		}
860b2e7771eSJohannes Berg 
861127f60bfSJohannes Berg 		if (last_monitor)
862127f60bfSJohannes Berg 			break;
863127f60bfSJohannes Berg 	}
864127f60bfSJohannes Berg 
865127f60bfSJohannes Berg 	/* this happens if last_monitor was erroneously false */
866127f60bfSJohannes Berg 	dev_kfree_skb(monskb);
867127f60bfSJohannes Berg 
868127f60bfSJohannes Berg 	/* ditto */
869127f60bfSJohannes Berg 	if (!origskb)
870127f60bfSJohannes Berg 		return NULL;
871127f60bfSJohannes Berg 
872c1129924SJohannes Berg 	return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space);
873b2e7771eSJohannes Berg }
874b2e7771eSJohannes Berg 
ieee80211_parse_qos(struct ieee80211_rx_data * rx)8755cf121c3SJohannes Berg static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
8766e0d114dSJohannes Berg {
877238f74a2SHarvey Harrison 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
878554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
8799e26297aSJohannes Berg 	int tid, seqno_idx, security_idx;
8806e0d114dSJohannes Berg 
8816e0d114dSJohannes Berg 	/* does the frame have a qos control field? */
882238f74a2SHarvey Harrison 	if (ieee80211_is_data_qos(hdr->frame_control)) {
883238f74a2SHarvey Harrison 		u8 *qc = ieee80211_get_qos_ctl(hdr);
8846e0d114dSJohannes Berg 		/* frame has qos control */
885238f74a2SHarvey Harrison 		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
88604b7dcf9SJohannes Berg 		if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
887554891e6SJohannes Berg 			status->rx_flags |= IEEE80211_RX_AMSDU;
8889e26297aSJohannes Berg 
8899e26297aSJohannes Berg 		seqno_idx = tid;
8909e26297aSJohannes Berg 		security_idx = tid;
8916e0d114dSJohannes Berg 	} else {
8921411f9b5SJohannes Berg 		/*
8931411f9b5SJohannes Berg 		 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
8941411f9b5SJohannes Berg 		 *
8951411f9b5SJohannes Berg 		 *	Sequence numbers for management frames, QoS data
8961411f9b5SJohannes Berg 		 *	frames with a broadcast/multicast address in the
8971411f9b5SJohannes Berg 		 *	Address 1 field, and all non-QoS data frames sent
8981411f9b5SJohannes Berg 		 *	by QoS STAs are assigned using an additional single
8991411f9b5SJohannes Berg 		 *	modulo-4096 counter, [...]
9001411f9b5SJohannes Berg 		 *
9011411f9b5SJohannes Berg 		 * We also use that counter for non-QoS STAs.
9021411f9b5SJohannes Berg 		 */
9035a306f58SJohannes Berg 		seqno_idx = IEEE80211_NUM_TIDS;
9049e26297aSJohannes Berg 		security_idx = 0;
9059e26297aSJohannes Berg 		if (ieee80211_is_mgmt(hdr->frame_control))
9065a306f58SJohannes Berg 			security_idx = IEEE80211_NUM_TIDS;
9079e26297aSJohannes Berg 		tid = 0;
9086e0d114dSJohannes Berg 	}
90952865dfdSJohannes Berg 
9109e26297aSJohannes Berg 	rx->seqno_idx = seqno_idx;
9119e26297aSJohannes Berg 	rx->security_idx = security_idx;
9126e0d114dSJohannes Berg 	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
9136e0d114dSJohannes Berg 	 * For now, set skb->priority to 0 for other cases. */
9146e0d114dSJohannes Berg 	rx->skb->priority = (tid > 7) ? 0 : tid;
91538f3714dSJohannes Berg }
9166e0d114dSJohannes Berg 
917d1c3a37cSJohannes Berg /**
918d1c3a37cSJohannes Berg  * DOC: Packet alignment
919d1c3a37cSJohannes Berg  *
920d1c3a37cSJohannes Berg  * Drivers always need to pass packets that are aligned to two-byte boundaries
921d1c3a37cSJohannes Berg  * to the stack.
922d1c3a37cSJohannes Berg  *
923d1c3a37cSJohannes Berg  * Additionally, should, if possible, align the payload data in a way that
924d1c3a37cSJohannes Berg  * guarantees that the contained IP header is aligned to a four-byte
925d1c3a37cSJohannes Berg  * boundary. In the case of regular frames, this simply means aligning the
926d1c3a37cSJohannes Berg  * payload to a four-byte boundary (because either the IP header is directly
927d1c3a37cSJohannes Berg  * contained, or IV/RFC1042 headers that have a length divisible by four are
92859d9cb07SKalle Valo  * in front of it).  If the payload data is not properly aligned and the
92959d9cb07SKalle Valo  * architecture doesn't support efficient unaligned operations, mac80211
93059d9cb07SKalle Valo  * will align the data.
931d1c3a37cSJohannes Berg  *
932d1c3a37cSJohannes Berg  * With A-MSDU frames, however, the payload data address must yield two modulo
933d1c3a37cSJohannes Berg  * four because there are 14-byte 802.3 headers within the A-MSDU frames that
934d1c3a37cSJohannes Berg  * push the IP header further back to a multiple of four again. Thankfully, the
935d1c3a37cSJohannes Berg  * specs were sane enough this time around to require padding each A-MSDU
936d1c3a37cSJohannes Berg  * subframe to a length that is a multiple of four.
937d1c3a37cSJohannes Berg  *
93825985edcSLucas De Marchi  * Padding like Atheros hardware adds which is between the 802.11 header and
939d1c3a37cSJohannes Berg  * the payload is not supported, the driver is required to move the 802.11
940d1c3a37cSJohannes Berg  * header to be directly in front of the payload in that case.
941d1c3a37cSJohannes Berg  */
ieee80211_verify_alignment(struct ieee80211_rx_data * rx)942d1c3a37cSJohannes Berg static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
94338f3714dSJohannes Berg {
94459d9cb07SKalle Valo #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
945441275e1SJohannes Berg 	WARN_ON_ONCE((unsigned long)rx->skb->data & 1);
946d1c3a37cSJohannes Berg #endif
9476e0d114dSJohannes Berg }
9486e0d114dSJohannes Berg 
9496368e4b1SRon Rindjunsky 
950571ecf67SJohannes Berg /* rx handlers */
951571ecf67SJohannes Berg 
ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff * skb)9523cfcf6acSJouni Malinen static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
9533cfcf6acSJouni Malinen {
9543cfcf6acSJouni Malinen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
9553cfcf6acSJouni Malinen 
956d8ca16dbSJohannes Berg 	if (is_multicast_ether_addr(hdr->addr1))
9573cfcf6acSJouni Malinen 		return 0;
9583cfcf6acSJouni Malinen 
959d8ca16dbSJohannes Berg 	return ieee80211_is_robust_mgmt_frame(skb);
9603cfcf6acSJouni Malinen }
9613cfcf6acSJouni Malinen 
9623cfcf6acSJouni Malinen 
ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff * skb)9633cfcf6acSJouni Malinen static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb)
9643cfcf6acSJouni Malinen {
9653cfcf6acSJouni Malinen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
9663cfcf6acSJouni Malinen 
967d8ca16dbSJohannes Berg 	if (!is_multicast_ether_addr(hdr->addr1))
9683cfcf6acSJouni Malinen 		return 0;
9693cfcf6acSJouni Malinen 
970d8ca16dbSJohannes Berg 	return ieee80211_is_robust_mgmt_frame(skb);
9713cfcf6acSJouni Malinen }
9723cfcf6acSJouni Malinen 
9733cfcf6acSJouni Malinen 
9743cfcf6acSJouni Malinen /* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */
ieee80211_get_mmie_keyidx(struct sk_buff * skb)9753cfcf6acSJouni Malinen static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
9763cfcf6acSJouni Malinen {
9773cfcf6acSJouni Malinen 	struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
9783cfcf6acSJouni Malinen 	struct ieee80211_mmie *mmie;
97956c52da2SJouni Malinen 	struct ieee80211_mmie_16 *mmie16;
9803cfcf6acSJouni Malinen 
9811df332e8SJohannes Berg 	if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
9823cfcf6acSJouni Malinen 		return -1;
9833cfcf6acSJouni Malinen 
984af2d14b0SJouni Malinen 	if (!ieee80211_is_robust_mgmt_frame(skb) &&
985af2d14b0SJouni Malinen 	    !ieee80211_is_beacon(hdr->frame_control))
9863cfcf6acSJouni Malinen 		return -1; /* not a robust management frame */
9873cfcf6acSJouni Malinen 
9883cfcf6acSJouni Malinen 	mmie = (struct ieee80211_mmie *)
9893cfcf6acSJouni Malinen 		(skb->data + skb->len - sizeof(*mmie));
99056c52da2SJouni Malinen 	if (mmie->element_id == WLAN_EID_MMIE &&
99156c52da2SJouni Malinen 	    mmie->length == sizeof(*mmie) - 2)
9923cfcf6acSJouni Malinen 		return le16_to_cpu(mmie->key_id);
99356c52da2SJouni Malinen 
99456c52da2SJouni Malinen 	mmie16 = (struct ieee80211_mmie_16 *)
99556c52da2SJouni Malinen 		(skb->data + skb->len - sizeof(*mmie16));
99656c52da2SJouni Malinen 	if (skb->len >= 24 + sizeof(*mmie16) &&
99756c52da2SJouni Malinen 	    mmie16->element_id == WLAN_EID_MMIE &&
99856c52da2SJouni Malinen 	    mmie16->length == sizeof(*mmie16) - 2)
99956c52da2SJouni Malinen 		return le16_to_cpu(mmie16->key_id);
100056c52da2SJouni Malinen 
100156c52da2SJouni Malinen 	return -1;
10023cfcf6acSJouni Malinen }
10033cfcf6acSJouni Malinen 
ieee80211_get_keyid(struct sk_buff * skb)100423a5f0afSJohannes Berg static int ieee80211_get_keyid(struct sk_buff *skb)
10052475b1ccSMax Stepanov {
10062475b1ccSMax Stepanov 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
100723a5f0afSJohannes Berg 	__le16 fc = hdr->frame_control;
100823a5f0afSJohannes Berg 	int hdrlen = ieee80211_hdrlen(fc);
10092475b1ccSMax Stepanov 	u8 keyid;
10102475b1ccSMax Stepanov 
101196fc6efbSAlexander Wetzel 	/* WEP, TKIP, CCMP and GCMP */
101223a5f0afSJohannes Berg 	if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN))
10132475b1ccSMax Stepanov 		return -EINVAL;
10142475b1ccSMax Stepanov 
101523a5f0afSJohannes Berg 	skb_copy_bits(skb, hdrlen + 3, &keyid, 1);
101696fc6efbSAlexander Wetzel 
101723a5f0afSJohannes Berg 	keyid >>= 6;
10182475b1ccSMax Stepanov 
10192475b1ccSMax Stepanov 	return keyid;
10202475b1ccSMax Stepanov }
10212475b1ccSMax Stepanov 
ieee80211_rx_mesh_check(struct ieee80211_rx_data * rx)10221df332e8SJohannes Berg static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
102333b64eb2SLuis Carlos Cobo {
102433b64eb2SLuis Carlos Cobo 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
102547846c9bSJohannes Berg 	char *dev_addr = rx->sdata->vif.addr;
1026d6d1a5a7SJohannes Berg 
1027a7767f95SHarvey Harrison 	if (ieee80211_is_data(hdr->frame_control)) {
10283c5772a5SJavier Cardona 		if (is_multicast_ether_addr(hdr->addr1)) {
10293c5772a5SJavier Cardona 			if (ieee80211_has_tods(hdr->frame_control) ||
10303c5772a5SJavier Cardona 			    !ieee80211_has_fromds(hdr->frame_control))
10313c5772a5SJavier Cardona 				return RX_DROP_MONITOR;
1032b203ca39SJoe Perches 			if (ether_addr_equal(hdr->addr3, dev_addr))
10333c5772a5SJavier Cardona 				return RX_DROP_MONITOR;
10343c5772a5SJavier Cardona 		} else {
1035a7767f95SHarvey Harrison 			if (!ieee80211_has_a4(hdr->frame_control))
103633b64eb2SLuis Carlos Cobo 				return RX_DROP_MONITOR;
1037b203ca39SJoe Perches 			if (ether_addr_equal(hdr->addr4, dev_addr))
103833b64eb2SLuis Carlos Cobo 				return RX_DROP_MONITOR;
103933b64eb2SLuis Carlos Cobo 		}
10403c5772a5SJavier Cardona 	}
104133b64eb2SLuis Carlos Cobo 
104233b64eb2SLuis Carlos Cobo 	/* If there is not an established peer link and this is not a peer link
104333b64eb2SLuis Carlos Cobo 	 * establisment frame, beacon or probe, drop the frame.
104433b64eb2SLuis Carlos Cobo 	 */
104533b64eb2SLuis Carlos Cobo 
104657cf8043SJavier Cardona 	if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) {
104733b64eb2SLuis Carlos Cobo 		struct ieee80211_mgmt *mgmt;
1048d6d1a5a7SJohannes Berg 
1049a7767f95SHarvey Harrison 		if (!ieee80211_is_mgmt(hdr->frame_control))
105033b64eb2SLuis Carlos Cobo 			return RX_DROP_MONITOR;
105133b64eb2SLuis Carlos Cobo 
1052a7767f95SHarvey Harrison 		if (ieee80211_is_action(hdr->frame_control)) {
1053d3aaec8aSJavier Cardona 			u8 category;
10549b395bc3SJohannes Berg 
10559b395bc3SJohannes Berg 			/* make sure category field is present */
10569b395bc3SJohannes Berg 			if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
10579b395bc3SJohannes Berg 				return RX_DROP_MONITOR;
10589b395bc3SJohannes Berg 
105933b64eb2SLuis Carlos Cobo 			mgmt = (struct ieee80211_mgmt *)hdr;
1060d3aaec8aSJavier Cardona 			category = mgmt->u.action.category;
1061d3aaec8aSJavier Cardona 			if (category != WLAN_CATEGORY_MESH_ACTION &&
1062d3aaec8aSJavier Cardona 			    category != WLAN_CATEGORY_SELF_PROTECTED)
106333b64eb2SLuis Carlos Cobo 				return RX_DROP_MONITOR;
106433b64eb2SLuis Carlos Cobo 			return RX_CONTINUE;
106533b64eb2SLuis Carlos Cobo 		}
106633b64eb2SLuis Carlos Cobo 
1067a7767f95SHarvey Harrison 		if (ieee80211_is_probe_req(hdr->frame_control) ||
1068a7767f95SHarvey Harrison 		    ieee80211_is_probe_resp(hdr->frame_control) ||
106971839121SJavier Cardona 		    ieee80211_is_beacon(hdr->frame_control) ||
107071839121SJavier Cardona 		    ieee80211_is_auth(hdr->frame_control))
1071a7767f95SHarvey Harrison 			return RX_CONTINUE;
1072a7767f95SHarvey Harrison 
1073a7767f95SHarvey Harrison 		return RX_DROP_MONITOR;
1074a7767f95SHarvey Harrison 	}
1075a7767f95SHarvey Harrison 
1076902acc78SJohannes Berg 	return RX_CONTINUE;
1077902acc78SJohannes Berg }
107833b64eb2SLuis Carlos Cobo 
ieee80211_rx_reorder_ready(struct tid_ampdu_rx * tid_agg_rx,int index)1079fb4ea054SJohannes Berg static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
1080fb4ea054SJohannes Berg 					      int index)
1081fb4ea054SJohannes Berg {
1082fb4ea054SJohannes Berg 	struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
1083fb4ea054SJohannes Berg 	struct sk_buff *tail = skb_peek_tail(frames);
1084fb4ea054SJohannes Berg 	struct ieee80211_rx_status *status;
1085fb4ea054SJohannes Berg 
1086b98c1610SPing-Ke Shih 	if (tid_agg_rx->reorder_buf_filtered &&
1087b98c1610SPing-Ke Shih 	    tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
108806470f74SSara Sharon 		return true;
108906470f74SSara Sharon 
1090fb4ea054SJohannes Berg 	if (!tail)
1091fb4ea054SJohannes Berg 		return false;
1092fb4ea054SJohannes Berg 
1093fb4ea054SJohannes Berg 	status = IEEE80211_SKB_RXCB(tail);
1094fb4ea054SJohannes Berg 	if (status->flag & RX_FLAG_AMSDU_MORE)
1095fb4ea054SJohannes Berg 		return false;
1096fb4ea054SJohannes Berg 
1097fb4ea054SJohannes Berg 	return true;
1098fb4ea054SJohannes Berg }
1099fb4ea054SJohannes Berg 
ieee80211_release_reorder_frame(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,int index,struct sk_buff_head * frames)1100d3b2fb53SJohannes Berg static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
11011edfb1afSJohannes Berg 					    struct tid_ampdu_rx *tid_agg_rx,
1102f9e124fbSChristian Lamparter 					    int index,
1103f9e124fbSChristian Lamparter 					    struct sk_buff_head *frames)
11041edfb1afSJohannes Berg {
110583eb935eSMichal Kazior 	struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index];
110683eb935eSMichal Kazior 	struct sk_buff *skb;
11074cfda47bSChristian Lamparter 	struct ieee80211_rx_status *status;
11081edfb1afSJohannes Berg 
1109dd318575SJohannes Berg 	lockdep_assert_held(&tid_agg_rx->reorder_lock);
1110dd318575SJohannes Berg 
111183eb935eSMichal Kazior 	if (skb_queue_empty(skb_list))
11121edfb1afSJohannes Berg 		goto no_frame;
11131edfb1afSJohannes Berg 
1114fb4ea054SJohannes Berg 	if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
111583eb935eSMichal Kazior 		__skb_queue_purge(skb_list);
111683eb935eSMichal Kazior 		goto no_frame;
111783eb935eSMichal Kazior 	}
111883eb935eSMichal Kazior 
111983eb935eSMichal Kazior 	/* release frames from the reorder ring buffer */
11201edfb1afSJohannes Berg 	tid_agg_rx->stored_mpdu_num--;
112183eb935eSMichal Kazior 	while ((skb = __skb_dequeue(skb_list))) {
11224cfda47bSChristian Lamparter 		status = IEEE80211_SKB_RXCB(skb);
11234cfda47bSChristian Lamparter 		status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
1124f9e124fbSChristian Lamparter 		__skb_queue_tail(frames, skb);
112583eb935eSMichal Kazior 	}
11261edfb1afSJohannes Berg 
11271edfb1afSJohannes Berg no_frame:
1128b98c1610SPing-Ke Shih 	if (tid_agg_rx->reorder_buf_filtered)
112906470f74SSara Sharon 		tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
11309a886586SJohannes Berg 	tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
11311edfb1afSJohannes Berg }
11321edfb1afSJohannes Berg 
ieee80211_release_reorder_frames(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,u16 head_seq_num,struct sk_buff_head * frames)1133d3b2fb53SJohannes Berg static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
11341edfb1afSJohannes Berg 					     struct tid_ampdu_rx *tid_agg_rx,
1135f9e124fbSChristian Lamparter 					     u16 head_seq_num,
1136f9e124fbSChristian Lamparter 					     struct sk_buff_head *frames)
11371edfb1afSJohannes Berg {
11381edfb1afSJohannes Berg 	int index;
11391edfb1afSJohannes Berg 
1140dd318575SJohannes Berg 	lockdep_assert_held(&tid_agg_rx->reorder_lock);
1141dd318575SJohannes Berg 
11429a886586SJohannes Berg 	while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
11432e3049b7SKarl Beldan 		index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1144f9e124fbSChristian Lamparter 		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
1145f9e124fbSChristian Lamparter 						frames);
11461edfb1afSJohannes Berg 	}
11471edfb1afSJohannes Berg }
11481edfb1afSJohannes Berg 
11491edfb1afSJohannes Berg /*
11501edfb1afSJohannes Berg  * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
11511edfb1afSJohannes Berg  * the skb was added to the buffer longer than this time ago, the earlier
11521edfb1afSJohannes Berg  * frames that have not yet been received are assumed to be lost and the skb
11531edfb1afSJohannes Berg  * can be released for processing. This may also release other skb's from the
11541edfb1afSJohannes Berg  * reorder buffer if there are no additional gaps between the frames.
11552bff8ebfSChristian Lamparter  *
11562bff8ebfSChristian Lamparter  * Callers must hold tid_agg_rx->reorder_lock.
11571edfb1afSJohannes Berg  */
11581edfb1afSJohannes Berg #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
11591edfb1afSJohannes Berg 
ieee80211_sta_reorder_release(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,struct sk_buff_head * frames)1160d3b2fb53SJohannes Berg static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
1161f9e124fbSChristian Lamparter 					  struct tid_ampdu_rx *tid_agg_rx,
1162f9e124fbSChristian Lamparter 					  struct sk_buff_head *frames)
1163aa0c8636SChristian Lamparter {
116483eb935eSMichal Kazior 	int index, i, j;
1165aa0c8636SChristian Lamparter 
1166dd318575SJohannes Berg 	lockdep_assert_held(&tid_agg_rx->reorder_lock);
1167dd318575SJohannes Berg 
1168aa0c8636SChristian Lamparter 	/* release the buffer until next missing frame */
11692e3049b7SKarl Beldan 	index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1170fb4ea054SJohannes Berg 	if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
117107ae2dfcSEliad Peller 	    tid_agg_rx->stored_mpdu_num) {
1172aa0c8636SChristian Lamparter 		/*
1173aa0c8636SChristian Lamparter 		 * No buffers ready to be released, but check whether any
1174aa0c8636SChristian Lamparter 		 * frames in the reorder buffer have timed out.
1175aa0c8636SChristian Lamparter 		 */
1176aa0c8636SChristian Lamparter 		int skipped = 1;
1177aa0c8636SChristian Lamparter 		for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
1178aa0c8636SChristian Lamparter 		     j = (j + 1) % tid_agg_rx->buf_size) {
1179fb4ea054SJohannes Berg 			if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
1180aa0c8636SChristian Lamparter 				skipped++;
1181aa0c8636SChristian Lamparter 				continue;
1182aa0c8636SChristian Lamparter 			}
1183499fe9a4SDaniel Halperin 			if (skipped &&
1184499fe9a4SDaniel Halperin 			    !time_after(jiffies, tid_agg_rx->reorder_time[j] +
1185aa0c8636SChristian Lamparter 					HT_RX_REORDER_BUF_TIMEOUT))
11862bff8ebfSChristian Lamparter 				goto set_release_timer;
1187aa0c8636SChristian Lamparter 
118883eb935eSMichal Kazior 			/* don't leave incomplete A-MSDUs around */
118983eb935eSMichal Kazior 			for (i = (index + 1) % tid_agg_rx->buf_size; i != j;
119083eb935eSMichal Kazior 			     i = (i + 1) % tid_agg_rx->buf_size)
119183eb935eSMichal Kazior 				__skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
119283eb935eSMichal Kazior 
1193bdcbd8e0SJohannes Berg 			ht_dbg_ratelimited(sdata,
11940fb9a9ecSJoe Perches 					   "release an RX reorder frame due to timeout on earlier frames\n");
1195f9e124fbSChristian Lamparter 			ieee80211_release_reorder_frame(sdata, tid_agg_rx, j,
1196f9e124fbSChristian Lamparter 							frames);
1197aa0c8636SChristian Lamparter 
1198aa0c8636SChristian Lamparter 			/*
1199aa0c8636SChristian Lamparter 			 * Increment the head seq# also for the skipped slots.
1200aa0c8636SChristian Lamparter 			 */
1201aa0c8636SChristian Lamparter 			tid_agg_rx->head_seq_num =
12029a886586SJohannes Berg 				(tid_agg_rx->head_seq_num +
12039a886586SJohannes Berg 				 skipped) & IEEE80211_SN_MASK;
1204aa0c8636SChristian Lamparter 			skipped = 0;
1205aa0c8636SChristian Lamparter 		}
1206fb4ea054SJohannes Berg 	} else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
1207f9e124fbSChristian Lamparter 		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
1208f9e124fbSChristian Lamparter 						frames);
12092e3049b7SKarl Beldan 		index =	tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1210aa0c8636SChristian Lamparter 	}
12112bff8ebfSChristian Lamparter 
12122bff8ebfSChristian Lamparter 	if (tid_agg_rx->stored_mpdu_num) {
12132e3049b7SKarl Beldan 		j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
12142bff8ebfSChristian Lamparter 
12152bff8ebfSChristian Lamparter 		for (; j != (index - 1) % tid_agg_rx->buf_size;
12162bff8ebfSChristian Lamparter 		     j = (j + 1) % tid_agg_rx->buf_size) {
1217fb4ea054SJohannes Berg 			if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
12182bff8ebfSChristian Lamparter 				break;
12192bff8ebfSChristian Lamparter 		}
12202bff8ebfSChristian Lamparter 
12212bff8ebfSChristian Lamparter  set_release_timer:
12222bff8ebfSChristian Lamparter 
1223788211d8SJohannes Berg 		if (!tid_agg_rx->removed)
12242bff8ebfSChristian Lamparter 			mod_timer(&tid_agg_rx->reorder_timer,
1225334df731SChristian Lamparter 				  tid_agg_rx->reorder_time[j] + 1 +
12262bff8ebfSChristian Lamparter 				  HT_RX_REORDER_BUF_TIMEOUT);
12272bff8ebfSChristian Lamparter 	} else {
12282bff8ebfSChristian Lamparter 		del_timer(&tid_agg_rx->reorder_timer);
12292bff8ebfSChristian Lamparter 	}
1230aa0c8636SChristian Lamparter }
1231aa0c8636SChristian Lamparter 
12321edfb1afSJohannes Berg /*
12331edfb1afSJohannes Berg  * As this function belongs to the RX path it must be under
12341edfb1afSJohannes Berg  * rcu_read_lock protection. It returns false if the frame
12351edfb1afSJohannes Berg  * can be processed immediately, true if it was consumed.
12361edfb1afSJohannes Berg  */
ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,struct sk_buff * skb,struct sk_buff_head * frames)1237d3b2fb53SJohannes Berg static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
12381edfb1afSJohannes Berg 					     struct tid_ampdu_rx *tid_agg_rx,
1239f9e124fbSChristian Lamparter 					     struct sk_buff *skb,
1240f9e124fbSChristian Lamparter 					     struct sk_buff_head *frames)
12411edfb1afSJohannes Berg {
12421edfb1afSJohannes Berg 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
124383eb935eSMichal Kazior 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
12441edfb1afSJohannes Berg 	u16 sc = le16_to_cpu(hdr->seq_ctrl);
12451edfb1afSJohannes Berg 	u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
12461edfb1afSJohannes Berg 	u16 head_seq_num, buf_size;
12471edfb1afSJohannes Berg 	int index;
12482bff8ebfSChristian Lamparter 	bool ret = true;
12491edfb1afSJohannes Berg 
1250dd318575SJohannes Berg 	spin_lock(&tid_agg_rx->reorder_lock);
1251dd318575SJohannes Berg 
12524549cf2bSMichal Kazior 	/*
12534549cf2bSMichal Kazior 	 * Offloaded BA sessions have no known starting sequence number so pick
12544549cf2bSMichal Kazior 	 * one from first Rxed frame for this tid after BA was started.
12554549cf2bSMichal Kazior 	 */
12564549cf2bSMichal Kazior 	if (unlikely(tid_agg_rx->auto_seq)) {
12574549cf2bSMichal Kazior 		tid_agg_rx->auto_seq = false;
12584549cf2bSMichal Kazior 		tid_agg_rx->ssn = mpdu_seq_num;
12594549cf2bSMichal Kazior 		tid_agg_rx->head_seq_num = mpdu_seq_num;
12604549cf2bSMichal Kazior 	}
12614549cf2bSMichal Kazior 
12621edfb1afSJohannes Berg 	buf_size = tid_agg_rx->buf_size;
12631edfb1afSJohannes Berg 	head_seq_num = tid_agg_rx->head_seq_num;
12641edfb1afSJohannes Berg 
1265b7540d8fSSara Sharon 	/*
1266b7540d8fSSara Sharon 	 * If the current MPDU's SN is smaller than the SSN, it shouldn't
1267b7540d8fSSara Sharon 	 * be reordered.
1268b7540d8fSSara Sharon 	 */
1269b7540d8fSSara Sharon 	if (unlikely(!tid_agg_rx->started)) {
1270b7540d8fSSara Sharon 		if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
1271b7540d8fSSara Sharon 			ret = false;
1272b7540d8fSSara Sharon 			goto out;
1273b7540d8fSSara Sharon 		}
1274b7540d8fSSara Sharon 		tid_agg_rx->started = true;
1275b7540d8fSSara Sharon 	}
1276b7540d8fSSara Sharon 
12771edfb1afSJohannes Berg 	/* frame with out of date sequence number */
12789a886586SJohannes Berg 	if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
12791edfb1afSJohannes Berg 		dev_kfree_skb(skb);
12802bff8ebfSChristian Lamparter 		goto out;
12811edfb1afSJohannes Berg 	}
12821edfb1afSJohannes Berg 
12831edfb1afSJohannes Berg 	/*
12841edfb1afSJohannes Berg 	 * If frame the sequence number exceeds our buffering window
12851edfb1afSJohannes Berg 	 * size release some previous frames to make room for this one.
12861edfb1afSJohannes Berg 	 */
12879a886586SJohannes Berg 	if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
12889a886586SJohannes Berg 		head_seq_num = ieee80211_sn_inc(
12899a886586SJohannes Berg 				ieee80211_sn_sub(mpdu_seq_num, buf_size));
12901edfb1afSJohannes Berg 		/* release stored frames up to new head to stack */
1291d3b2fb53SJohannes Berg 		ieee80211_release_reorder_frames(sdata, tid_agg_rx,
1292f9e124fbSChristian Lamparter 						 head_seq_num, frames);
12931edfb1afSJohannes Berg 	}
12941edfb1afSJohannes Berg 
12951edfb1afSJohannes Berg 	/* Now the new frame is always in the range of the reordering buffer */
12961edfb1afSJohannes Berg 
12972e3049b7SKarl Beldan 	index = mpdu_seq_num % tid_agg_rx->buf_size;
12981edfb1afSJohannes Berg 
12991edfb1afSJohannes Berg 	/* check if we already stored this frame */
1300fb4ea054SJohannes Berg 	if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
13011edfb1afSJohannes Berg 		dev_kfree_skb(skb);
13022bff8ebfSChristian Lamparter 		goto out;
13031edfb1afSJohannes Berg 	}
13041edfb1afSJohannes Berg 
13051edfb1afSJohannes Berg 	/*
13061edfb1afSJohannes Berg 	 * If the current MPDU is in the right order and nothing else
13071edfb1afSJohannes Berg 	 * is stored we can process it directly, no need to buffer it.
1308c835b214SJohannes Berg 	 * If it is first but there's something stored, we may be able
1309c835b214SJohannes Berg 	 * to release frames after this one.
13101edfb1afSJohannes Berg 	 */
13111edfb1afSJohannes Berg 	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
13121edfb1afSJohannes Berg 	    tid_agg_rx->stored_mpdu_num == 0) {
131383eb935eSMichal Kazior 		if (!(status->flag & RX_FLAG_AMSDU_MORE))
13149a886586SJohannes Berg 			tid_agg_rx->head_seq_num =
13159a886586SJohannes Berg 				ieee80211_sn_inc(tid_agg_rx->head_seq_num);
13162bff8ebfSChristian Lamparter 		ret = false;
13172bff8ebfSChristian Lamparter 		goto out;
13181edfb1afSJohannes Berg 	}
13191edfb1afSJohannes Berg 
13201edfb1afSJohannes Berg 	/* put the frame in the reordering buffer */
132183eb935eSMichal Kazior 	__skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb);
132283eb935eSMichal Kazior 	if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
13231edfb1afSJohannes Berg 		tid_agg_rx->reorder_time[index] = jiffies;
13241edfb1afSJohannes Berg 		tid_agg_rx->stored_mpdu_num++;
1325f9e124fbSChristian Lamparter 		ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames);
132683eb935eSMichal Kazior 	}
13271edfb1afSJohannes Berg 
13282bff8ebfSChristian Lamparter  out:
13292bff8ebfSChristian Lamparter 	spin_unlock(&tid_agg_rx->reorder_lock);
13302bff8ebfSChristian Lamparter 	return ret;
13311edfb1afSJohannes Berg }
13321edfb1afSJohannes Berg 
13331edfb1afSJohannes Berg /*
13341edfb1afSJohannes Berg  * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
13351edfb1afSJohannes Berg  * true if the MPDU was buffered, false if it should be processed.
13361edfb1afSJohannes Berg  */
ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)1337f9e124fbSChristian Lamparter static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
1338f9e124fbSChristian Lamparter 				       struct sk_buff_head *frames)
13391edfb1afSJohannes Berg {
13402569a826SJohannes Berg 	struct sk_buff *skb = rx->skb;
13411edfb1afSJohannes Berg 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
13422569a826SJohannes Berg 	struct sta_info *sta = rx->sta;
13431edfb1afSJohannes Berg 	struct tid_ampdu_rx *tid_agg_rx;
13441edfb1afSJohannes Berg 	u16 sc;
13456cc00d54SThomas Pedersen 	u8 tid, ack_policy;
13461edfb1afSJohannes Berg 
1347051a41faSJohannes Berg 	if (!ieee80211_is_data_qos(hdr->frame_control) ||
1348051a41faSJohannes Berg 	    is_multicast_ether_addr(hdr->addr1))
13492569a826SJohannes Berg 		goto dont_reorder;
13501edfb1afSJohannes Berg 
13511edfb1afSJohannes Berg 	/*
13521edfb1afSJohannes Berg 	 * filter the QoS data rx stream according to
13531edfb1afSJohannes Berg 	 * STA/TID and check if this STA/TID is on aggregation
13541edfb1afSJohannes Berg 	 */
13551edfb1afSJohannes Berg 
13561edfb1afSJohannes Berg 	if (!sta)
13572569a826SJohannes Berg 		goto dont_reorder;
13581edfb1afSJohannes Berg 
13596cc00d54SThomas Pedersen 	ack_policy = *ieee80211_get_qos_ctl(hdr) &
13606cc00d54SThomas Pedersen 		     IEEE80211_QOS_CTL_ACK_POLICY_MASK;
1361a1f2ba04SSara Sharon 	tid = ieee80211_get_tid(hdr);
13621edfb1afSJohannes Berg 
1363a87f736dSJohannes Berg 	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
1364bfe40fa3SJohannes Berg 	if (!tid_agg_rx) {
1365bfe40fa3SJohannes Berg 		if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
1366bfe40fa3SJohannes Berg 		    !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
1367bfe40fa3SJohannes Berg 		    !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
1368bfe40fa3SJohannes Berg 			ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
1369bfe40fa3SJohannes Berg 					     WLAN_BACK_RECIPIENT,
1370bfe40fa3SJohannes Berg 					     WLAN_REASON_QSTA_REQUIRE_SETUP);
1371a87f736dSJohannes Berg 		goto dont_reorder;
1372bfe40fa3SJohannes Berg 	}
13731edfb1afSJohannes Berg 
13741edfb1afSJohannes Berg 	/* qos null data frames are excluded */
13751edfb1afSJohannes Berg 	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
1376a87f736dSJohannes Berg 		goto dont_reorder;
13771edfb1afSJohannes Berg 
13786cc00d54SThomas Pedersen 	/* not part of a BA session */
13795e469ed9SFelix Fietkau 	if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
13806cc00d54SThomas Pedersen 		goto dont_reorder;
13816cc00d54SThomas Pedersen 
13821edfb1afSJohannes Berg 	/* new, potentially un-ordered, ampdu frame - process it */
13831edfb1afSJohannes Berg 
13841edfb1afSJohannes Berg 	/* reset session timer */
13851edfb1afSJohannes Berg 	if (tid_agg_rx->timeout)
138612d3952fSFelix Fietkau 		tid_agg_rx->last_rx = jiffies;
13871edfb1afSJohannes Berg 
13881edfb1afSJohannes Berg 	/* if this mpdu is fragmented - terminate rx aggregation session */
13891edfb1afSJohannes Berg 	sc = le16_to_cpu(hdr->seq_ctrl);
13901edfb1afSJohannes Berg 	if (sc & IEEE80211_SCTL_FRAG) {
13914f6c78deSJohannes Berg 		ieee80211_queue_skb_to_iface(rx->sdata, rx->link_id, NULL, skb);
13922569a826SJohannes Berg 		return;
13931edfb1afSJohannes Berg 	}
13941edfb1afSJohannes Berg 
1395a87f736dSJohannes Berg 	/*
1396a87f736dSJohannes Berg 	 * No locking needed -- we will only ever process one
1397a87f736dSJohannes Berg 	 * RX packet at a time, and thus own tid_agg_rx. All
1398a87f736dSJohannes Berg 	 * other code manipulating it needs to (and does) make
1399a87f736dSJohannes Berg 	 * sure that we cannot get to it any more before doing
1400a87f736dSJohannes Berg 	 * anything with it.
1401a87f736dSJohannes Berg 	 */
1402f9e124fbSChristian Lamparter 	if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb,
1403f9e124fbSChristian Lamparter 					     frames))
14042569a826SJohannes Berg 		return;
14052569a826SJohannes Berg 
14062569a826SJohannes Berg  dont_reorder:
1407f9e124fbSChristian Lamparter 	__skb_queue_tail(frames, skb);
14081edfb1afSJohannes Berg }
140933b64eb2SLuis Carlos Cobo 
141049461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check_dup(struct ieee80211_rx_data * rx)14110395442aSJohannes Berg ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
1412571ecf67SJohannes Berg {
1413a7767f95SHarvey Harrison 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
1414554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
1415571ecf67SJohannes Berg 
1416f9cfa5f3SSara Sharon 	if (status->flag & RX_FLAG_DUP_VALIDATED)
1417f9cfa5f3SSara Sharon 		return RX_CONTINUE;
1418f9cfa5f3SSara Sharon 
14196b0f3274SJohannes Berg 	/*
14206b0f3274SJohannes Berg 	 * Drop duplicate 802.11 retransmissions
14216b0f3274SJohannes Berg 	 * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
14226b0f3274SJohannes Berg 	 */
14230395442aSJohannes Berg 
14240395442aSJohannes Berg 	if (rx->skb->len < 24)
14250395442aSJohannes Berg 		return RX_CONTINUE;
14260395442aSJohannes Berg 
14270395442aSJohannes Berg 	if (ieee80211_is_ctl(hdr->frame_control) ||
142830b2f0beSThomas Pedersen 	    ieee80211_is_any_nullfunc(hdr->frame_control) ||
14290395442aSJohannes Berg 	    is_multicast_ether_addr(hdr->addr1))
14300395442aSJohannes Berg 		return RX_CONTINUE;
14310395442aSJohannes Berg 
1432a732fa70SJohannes Berg 	if (!rx->sta)
1433a732fa70SJohannes Berg 		return RX_CONTINUE;
1434a732fa70SJohannes Berg 
1435a7767f95SHarvey Harrison 	if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
1436a732fa70SJohannes Berg 		     rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
1437c206ca67SJohannes Berg 		I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
1438b320d6c4SBenjamin Berg 		rx->link_sta->rx_stats.num_duplicates++;
1439b1f93314SFelix Fietkau 		return RX_DROP_UNUSABLE;
14400cfcefefSMichal Kazior 	} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
14419e26297aSJohannes Berg 		rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
1442571ecf67SJohannes Berg 	}
1443571ecf67SJohannes Berg 
14440395442aSJohannes Berg 	return RX_CONTINUE;
14450395442aSJohannes Berg }
14460395442aSJohannes Berg 
14470395442aSJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check(struct ieee80211_rx_data * rx)14480395442aSJohannes Berg ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
14490395442aSJohannes Berg {
14500395442aSJohannes Berg 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
14510395442aSJohannes Berg 
1452571ecf67SJohannes Berg 	/* Drop disallowed frame classes based on STA auth/assoc state;
1453571ecf67SJohannes Berg 	 * IEEE 802.11, Chap 5.5.
1454571ecf67SJohannes Berg 	 *
1455ccd7b362SJohannes Berg 	 * mac80211 filters only based on association state, i.e. it drops
1456ccd7b362SJohannes Berg 	 * Class 3 frames from not associated stations. hostapd sends
1457571ecf67SJohannes Berg 	 * deauth/disassoc frames when needed. In addition, hostapd is
1458571ecf67SJohannes Berg 	 * responsible for filtering on both auth and assoc states.
1459571ecf67SJohannes Berg 	 */
146033b64eb2SLuis Carlos Cobo 
1461902acc78SJohannes Berg 	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
146233b64eb2SLuis Carlos Cobo 		return ieee80211_rx_mesh_check(rx);
146333b64eb2SLuis Carlos Cobo 
1464a7767f95SHarvey Harrison 	if (unlikely((ieee80211_is_data(hdr->frame_control) ||
1465a7767f95SHarvey Harrison 		      ieee80211_is_pspoll(hdr->frame_control)) &&
146605c914feSJohannes Berg 		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1467239281f8SRostislav Lisovy 		     rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
1468c2c98fdeSJohannes Berg 		     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
14697852e361SJohannes Berg 		/*
14707852e361SJohannes Berg 		 * accept port control frames from the AP even when it's not
14717852e361SJohannes Berg 		 * yet marked ASSOC to prevent a race where we don't set the
14727852e361SJohannes Berg 		 * assoc bit quickly enough before it sends the first frame
14737852e361SJohannes Berg 		 */
14747852e361SJohannes Berg 		if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
14752a33bee2SGuy Eilam 		    ieee80211_is_data_present(hdr->frame_control)) {
14766dbda2d0SJohannes Berg 			unsigned int hdrlen;
14776dbda2d0SJohannes Berg 			__be16 ethertype;
14782a33bee2SGuy Eilam 
14796dbda2d0SJohannes Berg 			hdrlen = ieee80211_hdrlen(hdr->frame_control);
14806dbda2d0SJohannes Berg 
14816dbda2d0SJohannes Berg 			if (rx->skb->len < hdrlen + 8)
14826dbda2d0SJohannes Berg 				return RX_DROP_MONITOR;
14836dbda2d0SJohannes Berg 
14846dbda2d0SJohannes Berg 			skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
14856dbda2d0SJohannes Berg 			if (ethertype == rx->sdata->control_port_protocol)
14862a33bee2SGuy Eilam 				return RX_CONTINUE;
14872a33bee2SGuy Eilam 		}
148821fc7560SJohannes Berg 
148921fc7560SJohannes Berg 		if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
149021fc7560SJohannes Berg 		    cfg80211_rx_spurious_frame(rx->sdata->dev,
149121fc7560SJohannes Berg 					       hdr->addr2,
149221fc7560SJohannes Berg 					       GFP_ATOMIC))
149321fc7560SJohannes Berg 			return RX_DROP_UNUSABLE;
149421fc7560SJohannes Berg 
1495e4c26addSJohannes Berg 		return RX_DROP_MONITOR;
14962a33bee2SGuy Eilam 	}
1497571ecf67SJohannes Berg 
14989ae54c84SJohannes Berg 	return RX_CONTINUE;
1499570bd537SJohannes Berg }
1500570bd537SJohannes Berg 
1501570bd537SJohannes Berg 
150249461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check_more_data(struct ieee80211_rx_data * rx)1503572e0012SKalle Valo ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
1504572e0012SKalle Valo {
1505572e0012SKalle Valo 	struct ieee80211_local *local;
1506572e0012SKalle Valo 	struct ieee80211_hdr *hdr;
1507572e0012SKalle Valo 	struct sk_buff *skb;
1508572e0012SKalle Valo 
1509572e0012SKalle Valo 	local = rx->local;
1510572e0012SKalle Valo 	skb = rx->skb;
1511572e0012SKalle Valo 	hdr = (struct ieee80211_hdr *) skb->data;
1512572e0012SKalle Valo 
1513572e0012SKalle Valo 	if (!local->pspolling)
1514572e0012SKalle Valo 		return RX_CONTINUE;
1515572e0012SKalle Valo 
1516572e0012SKalle Valo 	if (!ieee80211_has_fromds(hdr->frame_control))
1517572e0012SKalle Valo 		/* this is not from AP */
1518572e0012SKalle Valo 		return RX_CONTINUE;
1519572e0012SKalle Valo 
1520572e0012SKalle Valo 	if (!ieee80211_is_data(hdr->frame_control))
1521572e0012SKalle Valo 		return RX_CONTINUE;
1522572e0012SKalle Valo 
1523572e0012SKalle Valo 	if (!ieee80211_has_moredata(hdr->frame_control)) {
1524572e0012SKalle Valo 		/* AP has no more frames buffered for us */
1525572e0012SKalle Valo 		local->pspolling = false;
1526572e0012SKalle Valo 		return RX_CONTINUE;
1527572e0012SKalle Valo 	}
1528572e0012SKalle Valo 
1529572e0012SKalle Valo 	/* more data bit is set, let's request a new frame from the AP */
1530572e0012SKalle Valo 	ieee80211_send_pspoll(local, rx->sdata);
1531572e0012SKalle Valo 
1532572e0012SKalle Valo 	return RX_CONTINUE;
1533572e0012SKalle Valo }
1534572e0012SKalle Valo 
sta_ps_start(struct sta_info * sta)1535d012a605SMarco Porsch static void sta_ps_start(struct sta_info *sta)
1536571ecf67SJohannes Berg {
1537133b8226SJohannes Berg 	struct ieee80211_sub_if_data *sdata = sta->sdata;
15384571d3bfSChristian Lamparter 	struct ieee80211_local *local = sdata->local;
1539d012a605SMarco Porsch 	struct ps_data *ps;
1540ba8c3d6fSFelix Fietkau 	int tid;
15410795af57SJoe Perches 
1542d012a605SMarco Porsch 	if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
1543d012a605SMarco Porsch 	    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1544d012a605SMarco Porsch 		ps = &sdata->bss->ps;
1545d012a605SMarco Porsch 	else
1546d012a605SMarco Porsch 		return;
1547d012a605SMarco Porsch 
1548d012a605SMarco Porsch 	atomic_inc(&ps->num_sta_ps);
1549c2c98fdeSJohannes Berg 	set_sta_flag(sta, WLAN_STA_PS_STA);
155030686bf7SJohannes Berg 	if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
155112375ef9SJohannes Berg 		drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
1552bdcbd8e0SJohannes Berg 	ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
1553bdcbd8e0SJohannes Berg 	       sta->sta.addr, sta->sta.aid);
1554ba8c3d6fSFelix Fietkau 
155517c18bf8SJohannes Berg 	ieee80211_clear_fast_xmit(sta);
155617c18bf8SJohannes Berg 
1557adf8ed01SJohannes Berg 	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
1558b49c15e1SFelix Fietkau 		struct ieee80211_txq *txq = sta->sta.txq[tid];
1559942741daSFelix Fietkau 		struct txq_info *txqi = to_txq_info(txq);
1560b49c15e1SFelix Fietkau 
1561942741daSFelix Fietkau 		spin_lock(&local->active_txq_lock[txq->ac]);
1562942741daSFelix Fietkau 		if (!list_empty(&txqi->schedule_order))
1563942741daSFelix Fietkau 			list_del_init(&txqi->schedule_order);
1564942741daSFelix Fietkau 		spin_unlock(&local->active_txq_lock[txq->ac]);
1565b49c15e1SFelix Fietkau 
1566b49c15e1SFelix Fietkau 		if (txq_has_queue(txq))
1567ba8c3d6fSFelix Fietkau 			set_bit(tid, &sta->txq_buffered_tids);
1568ba8c3d6fSFelix Fietkau 		else
1569ba8c3d6fSFelix Fietkau 			clear_bit(tid, &sta->txq_buffered_tids);
1570ba8c3d6fSFelix Fietkau 	}
1571571ecf67SJohannes Berg }
1572571ecf67SJohannes Berg 
sta_ps_end(struct sta_info * sta)1573d012a605SMarco Porsch static void sta_ps_end(struct sta_info *sta)
1574571ecf67SJohannes Berg {
1575bdcbd8e0SJohannes Berg 	ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
1576bdcbd8e0SJohannes Berg 	       sta->sta.addr, sta->sta.aid);
1577004c872eSJohannes Berg 
1578c2c98fdeSJohannes Berg 	if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
1579e3685e03SJohannes Berg 		/*
1580e3685e03SJohannes Berg 		 * Clear the flag only if the other one is still set
1581e3685e03SJohannes Berg 		 * so that the TX path won't start TX'ing new frames
1582e3685e03SJohannes Berg 		 * directly ... In the case that the driver flag isn't
1583e3685e03SJohannes Berg 		 * set ieee80211_sta_ps_deliver_wakeup() will clear it.
1584e3685e03SJohannes Berg 		 */
1585e3685e03SJohannes Berg 		clear_sta_flag(sta, WLAN_STA_PS_STA);
1586bdcbd8e0SJohannes Berg 		ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
1587bdcbd8e0SJohannes Berg 		       sta->sta.addr, sta->sta.aid);
1588af818581SJohannes Berg 		return;
1589af818581SJohannes Berg 	}
1590af818581SJohannes Berg 
15915ac2e350SJohannes Berg 	set_sta_flag(sta, WLAN_STA_PS_DELIVER);
15925ac2e350SJohannes Berg 	clear_sta_flag(sta, WLAN_STA_PS_STA);
1593af818581SJohannes Berg 	ieee80211_sta_ps_deliver_wakeup(sta);
1594571ecf67SJohannes Berg }
1595571ecf67SJohannes Berg 
ieee80211_sta_ps_transition(struct ieee80211_sta * pubsta,bool start)1596cf47161aSJohannes Berg int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
1597d057e5a3SArik Nemtsov {
1598cf47161aSJohannes Berg 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1599d057e5a3SArik Nemtsov 	bool in_ps;
1600d057e5a3SArik Nemtsov 
1601cf47161aSJohannes Berg 	WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS));
1602d057e5a3SArik Nemtsov 
1603d057e5a3SArik Nemtsov 	/* Don't let the same PS state be set twice */
1604cf47161aSJohannes Berg 	in_ps = test_sta_flag(sta, WLAN_STA_PS_STA);
1605d057e5a3SArik Nemtsov 	if ((start && in_ps) || (!start && !in_ps))
1606d057e5a3SArik Nemtsov 		return -EINVAL;
1607d057e5a3SArik Nemtsov 
1608d057e5a3SArik Nemtsov 	if (start)
1609cf47161aSJohannes Berg 		sta_ps_start(sta);
1610d057e5a3SArik Nemtsov 	else
1611cf47161aSJohannes Berg 		sta_ps_end(sta);
1612d057e5a3SArik Nemtsov 
1613d057e5a3SArik Nemtsov 	return 0;
1614d057e5a3SArik Nemtsov }
1615d057e5a3SArik Nemtsov EXPORT_SYMBOL(ieee80211_sta_ps_transition);
1616d057e5a3SArik Nemtsov 
ieee80211_sta_pspoll(struct ieee80211_sta * pubsta)161746fa38e8SJohannes Berg void ieee80211_sta_pspoll(struct ieee80211_sta *pubsta)
161846fa38e8SJohannes Berg {
161946fa38e8SJohannes Berg 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
162046fa38e8SJohannes Berg 
162146fa38e8SJohannes Berg 	if (test_sta_flag(sta, WLAN_STA_SP))
162246fa38e8SJohannes Berg 		return;
162346fa38e8SJohannes Berg 
162446fa38e8SJohannes Berg 	if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
162546fa38e8SJohannes Berg 		ieee80211_sta_ps_deliver_poll_response(sta);
162646fa38e8SJohannes Berg 	else
162746fa38e8SJohannes Berg 		set_sta_flag(sta, WLAN_STA_PSPOLL);
162846fa38e8SJohannes Berg }
162946fa38e8SJohannes Berg EXPORT_SYMBOL(ieee80211_sta_pspoll);
163046fa38e8SJohannes Berg 
ieee80211_sta_uapsd_trigger(struct ieee80211_sta * pubsta,u8 tid)163146fa38e8SJohannes Berg void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
163246fa38e8SJohannes Berg {
163346fa38e8SJohannes Berg 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1634731977e9SAmadeusz Sławiński 	int ac = ieee80211_ac_from_tid(tid);
163546fa38e8SJohannes Berg 
163646fa38e8SJohannes Berg 	/*
16370aa419ecSEmmanuel Grumbach 	 * If this AC is not trigger-enabled do nothing unless the
16380aa419ecSEmmanuel Grumbach 	 * driver is calling us after it already checked.
163946fa38e8SJohannes Berg 	 *
164046fa38e8SJohannes Berg 	 * NB: This could/should check a separate bitmap of trigger-
164146fa38e8SJohannes Berg 	 * enabled queues, but for now we only implement uAPSD w/o
164246fa38e8SJohannes Berg 	 * TSPEC changes to the ACs, so they're always the same.
164346fa38e8SJohannes Berg 	 */
1644f438ceb8SEmmanuel Grumbach 	if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
1645f438ceb8SEmmanuel Grumbach 	    tid != IEEE80211_NUM_TIDS)
164646fa38e8SJohannes Berg 		return;
164746fa38e8SJohannes Berg 
164846fa38e8SJohannes Berg 	/* if we are in a service period, do nothing */
164946fa38e8SJohannes Berg 	if (test_sta_flag(sta, WLAN_STA_SP))
165046fa38e8SJohannes Berg 		return;
165146fa38e8SJohannes Berg 
165246fa38e8SJohannes Berg 	if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
165346fa38e8SJohannes Berg 		ieee80211_sta_ps_deliver_uapsd(sta);
165446fa38e8SJohannes Berg 	else
165546fa38e8SJohannes Berg 		set_sta_flag(sta, WLAN_STA_UAPSD);
165646fa38e8SJohannes Berg }
165746fa38e8SJohannes Berg EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
165846fa38e8SJohannes Berg 
165949461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data * rx)166047086fc5SJohannes Berg ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
166147086fc5SJohannes Berg {
166247086fc5SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
166347086fc5SJohannes Berg 	struct ieee80211_hdr *hdr = (void *)rx->skb->data;
166447086fc5SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
166547086fc5SJohannes Berg 
16665c90067cSJohannes Berg 	if (!rx->sta)
166747086fc5SJohannes Berg 		return RX_CONTINUE;
166847086fc5SJohannes Berg 
166947086fc5SJohannes Berg 	if (sdata->vif.type != NL80211_IFTYPE_AP &&
167047086fc5SJohannes Berg 	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
167147086fc5SJohannes Berg 		return RX_CONTINUE;
167247086fc5SJohannes Berg 
167347086fc5SJohannes Berg 	/*
167447086fc5SJohannes Berg 	 * The device handles station powersave, so don't do anything about
167547086fc5SJohannes Berg 	 * uAPSD and PS-Poll frames (the latter shouldn't even come up from
167647086fc5SJohannes Berg 	 * it to mac80211 since they're handled.)
167747086fc5SJohannes Berg 	 */
167830686bf7SJohannes Berg 	if (ieee80211_hw_check(&sdata->local->hw, AP_LINK_PS))
167947086fc5SJohannes Berg 		return RX_CONTINUE;
168047086fc5SJohannes Berg 
168147086fc5SJohannes Berg 	/*
168247086fc5SJohannes Berg 	 * Don't do anything if the station isn't already asleep. In
168347086fc5SJohannes Berg 	 * the uAPSD case, the station will probably be marked asleep,
168447086fc5SJohannes Berg 	 * in the PS-Poll case the station must be confused ...
168547086fc5SJohannes Berg 	 */
1686c2c98fdeSJohannes Berg 	if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
168747086fc5SJohannes Berg 		return RX_CONTINUE;
168847086fc5SJohannes Berg 
168947086fc5SJohannes Berg 	if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
169046fa38e8SJohannes Berg 		ieee80211_sta_pspoll(&rx->sta->sta);
169147086fc5SJohannes Berg 
169247086fc5SJohannes Berg 		/* Free PS Poll skb here instead of returning RX_DROP that would
169347086fc5SJohannes Berg 		 * count as an dropped frame. */
169447086fc5SJohannes Berg 		dev_kfree_skb(rx->skb);
169547086fc5SJohannes Berg 
169647086fc5SJohannes Berg 		return RX_QUEUED;
169747086fc5SJohannes Berg 	} else if (!ieee80211_has_morefrags(hdr->frame_control) &&
169847086fc5SJohannes Berg 		   !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
169947086fc5SJohannes Berg 		   ieee80211_has_pm(hdr->frame_control) &&
170047086fc5SJohannes Berg 		   (ieee80211_is_data_qos(hdr->frame_control) ||
170147086fc5SJohannes Berg 		    ieee80211_is_qos_nullfunc(hdr->frame_control))) {
1702a1f2ba04SSara Sharon 		u8 tid = ieee80211_get_tid(hdr);
170347086fc5SJohannes Berg 
170446fa38e8SJohannes Berg 		ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
170547086fc5SJohannes Berg 	}
170647086fc5SJohannes Berg 
170747086fc5SJohannes Berg 	return RX_CONTINUE;
170847086fc5SJohannes Berg }
170947086fc5SJohannes Berg 
171047086fc5SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data * rx)17115cf121c3SJohannes Berg ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
1712571ecf67SJohannes Berg {
1713571ecf67SJohannes Berg 	struct sta_info *sta = rx->sta;
1714b320d6c4SBenjamin Berg 	struct link_sta_info *link_sta = rx->link_sta;
1715eb9fb5b8SJohannes Berg 	struct sk_buff *skb = rx->skb;
1716eb9fb5b8SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1717eb9fb5b8SJohannes Berg 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1718ef0621e8SFelix Fietkau 	int i;
1719571ecf67SJohannes Berg 
1720b320d6c4SBenjamin Berg 	if (!sta || !link_sta)
17219ae54c84SJohannes Berg 		return RX_CONTINUE;
1722571ecf67SJohannes Berg 
1723b291ba11SJohannes Berg 	/*
1724b291ba11SJohannes Berg 	 * Update last_rx only for IBSS packets which are for the current
1725e584da5eSAntonio Quartulli 	 * BSSID and for station already AUTHORIZED to avoid keeping the
1726e584da5eSAntonio Quartulli 	 * current IBSS network alive in cases where other STAs start
1727e584da5eSAntonio Quartulli 	 * using different BSSID. This will also give the station another
1728e584da5eSAntonio Quartulli 	 * chance to restart the authentication/authorization in case
1729e584da5eSAntonio Quartulli 	 * something went wrong the first time.
1730b291ba11SJohannes Berg 	 */
173105c914feSJohannes Berg 	if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
173271364716SRon Rindjunsky 		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
173305c914feSJohannes Berg 						NL80211_IFTYPE_ADHOC);
1734e584da5eSAntonio Quartulli 		if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
1735e584da5eSAntonio Quartulli 		    test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
1736b320d6c4SBenjamin Berg 			link_sta->rx_stats.last_rx = jiffies;
17370e966d9aSJohannes Berg 			if (ieee80211_is_data_present(hdr->frame_control) &&
17384f6b1b3dSJohannes Berg 			    !is_multicast_ether_addr(hdr->addr1))
1739b320d6c4SBenjamin Berg 				link_sta->rx_stats.last_rate =
17404f6b1b3dSJohannes Berg 					sta_stats_encode_rate(status);
17413af6334cSFelix Fietkau 		}
1742239281f8SRostislav Lisovy 	} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
1743b320d6c4SBenjamin Berg 		link_sta->rx_stats.last_rx = jiffies;
174409a740ceSThomas Pedersen 	} else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
1745f879ac8eSWen Gong 		   !is_multicast_ether_addr(hdr->addr1)) {
1746b291ba11SJohannes Berg 		/*
174733b64eb2SLuis Carlos Cobo 		 * Mesh beacons will update last_rx when if they are found to
174833b64eb2SLuis Carlos Cobo 		 * match the current local configuration when processed.
1749571ecf67SJohannes Berg 		 */
1750b320d6c4SBenjamin Berg 		link_sta->rx_stats.last_rx = jiffies;
17510e966d9aSJohannes Berg 		if (ieee80211_is_data_present(hdr->frame_control))
1752b320d6c4SBenjamin Berg 			link_sta->rx_stats.last_rate = sta_stats_encode_rate(status);
1753571ecf67SJohannes Berg 	}
1754571ecf67SJohannes Berg 
1755b320d6c4SBenjamin Berg 	link_sta->rx_stats.fragments++;
17560f9c5a61SJohannes Berg 
1757b320d6c4SBenjamin Berg 	u64_stats_update_begin(&link_sta->rx_stats.syncp);
1758b320d6c4SBenjamin Berg 	link_sta->rx_stats.bytes += rx->skb->len;
1759b320d6c4SBenjamin Berg 	u64_stats_update_end(&link_sta->rx_stats.syncp);
17600f9c5a61SJohannes Berg 
1761fe8431f8SFelix Fietkau 	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
1762b320d6c4SBenjamin Berg 		link_sta->rx_stats.last_signal = status->signal;
1763b320d6c4SBenjamin Berg 		ewma_signal_add(&link_sta->rx_stats_avg.signal,
1764046d2e7cSSriram R 				-status->signal);
1765fe8431f8SFelix Fietkau 	}
1766571ecf67SJohannes Berg 
1767ef0621e8SFelix Fietkau 	if (status->chains) {
1768b320d6c4SBenjamin Berg 		link_sta->rx_stats.chains = status->chains;
1769ef0621e8SFelix Fietkau 		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
1770ef0621e8SFelix Fietkau 			int signal = status->chain_signal[i];
1771ef0621e8SFelix Fietkau 
1772ef0621e8SFelix Fietkau 			if (!(status->chains & BIT(i)))
1773ef0621e8SFelix Fietkau 				continue;
1774ef0621e8SFelix Fietkau 
1775b320d6c4SBenjamin Berg 			link_sta->rx_stats.chain_signal_last[i] = signal;
1776b320d6c4SBenjamin Berg 			ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
1777e5a9f8d0SJohannes Berg 					-signal);
1778ef0621e8SFelix Fietkau 		}
1779ef0621e8SFelix Fietkau 	}
1780ef0621e8SFelix Fietkau 
178109a740ceSThomas Pedersen 	if (ieee80211_is_s1g_beacon(hdr->frame_control))
178209a740ceSThomas Pedersen 		return RX_CONTINUE;
178309a740ceSThomas Pedersen 
178472eaa43aSJohannes Berg 	/*
178572eaa43aSJohannes Berg 	 * Change STA power saving mode only at the end of a frame
17869fef6544SEmmanuel Grumbach 	 * exchange sequence, and only for a data or management
17879fef6544SEmmanuel Grumbach 	 * frame as specified in IEEE 802.11-2016 11.2.3.2
178872eaa43aSJohannes Berg 	 */
178930686bf7SJohannes Berg 	if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) &&
1790d057e5a3SArik Nemtsov 	    !ieee80211_has_morefrags(hdr->frame_control) &&
179120932750SEmmanuel Grumbach 	    !is_multicast_ether_addr(hdr->addr1) &&
17929fef6544SEmmanuel Grumbach 	    (ieee80211_is_mgmt(hdr->frame_control) ||
17939fef6544SEmmanuel Grumbach 	     ieee80211_is_data(hdr->frame_control)) &&
17944cfda47bSChristian Lamparter 	    !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
179505c914feSJohannes Berg 	    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
17969fef6544SEmmanuel Grumbach 	     rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
1797b4ba544cSJohannes Berg 		if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
1798b4ba544cSJohannes Berg 			if (!ieee80211_has_pm(hdr->frame_control))
1799d012a605SMarco Porsch 				sta_ps_end(sta);
180072eaa43aSJohannes Berg 		} else {
180172eaa43aSJohannes Berg 			if (ieee80211_has_pm(hdr->frame_control))
1802d012a605SMarco Porsch 				sta_ps_start(sta);
1803571ecf67SJohannes Berg 		}
180472eaa43aSJohannes Berg 	}
1805571ecf67SJohannes Berg 
18063f52b7e3SMarco Porsch 	/* mesh power save support */
18073f52b7e3SMarco Porsch 	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
18083f52b7e3SMarco Porsch 		ieee80211_mps_rx_h_sta_process(sta, hdr);
18093f52b7e3SMarco Porsch 
181022403defSJohannes Berg 	/*
181122403defSJohannes Berg 	 * Drop (qos-)data::nullfunc frames silently, since they
181222403defSJohannes Berg 	 * are used only to control station power saving mode.
181322403defSJohannes Berg 	 */
181430b2f0beSThomas Pedersen 	if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
1815571ecf67SJohannes Berg 		I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
1816d524215fSFelix Fietkau 
1817d524215fSFelix Fietkau 		/*
1818d524215fSFelix Fietkau 		 * If we receive a 4-addr nullfunc frame from a STA
1819e7f4a940SJohannes Berg 		 * that was not moved to a 4-addr STA vlan yet send
1820e7f4a940SJohannes Berg 		 * the event to userspace and for older hostapd drop
1821e7f4a940SJohannes Berg 		 * the frame to the monitor interface.
1822d524215fSFelix Fietkau 		 */
1823d524215fSFelix Fietkau 		if (ieee80211_has_a4(hdr->frame_control) &&
1824d524215fSFelix Fietkau 		    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
1825d524215fSFelix Fietkau 		     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
1826e7f4a940SJohannes Berg 		      !rx->sdata->u.vlan.sta))) {
1827e7f4a940SJohannes Berg 			if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
1828e7f4a940SJohannes Berg 				cfg80211_rx_unexpected_4addr_frame(
1829e7f4a940SJohannes Berg 					rx->sdata->dev, sta->sta.addr,
1830e7f4a940SJohannes Berg 					GFP_ATOMIC);
1831baa951a1SJohannes Berg 			return RX_DROP_M_UNEXPECTED_4ADDR_FRAME;
1832e7f4a940SJohannes Berg 		}
183322403defSJohannes Berg 		/*
183422403defSJohannes Berg 		 * Update counter and free packet here to avoid
183522403defSJohannes Berg 		 * counting this as a dropped packed.
183622403defSJohannes Berg 		 */
1837b320d6c4SBenjamin Berg 		link_sta->rx_stats.packets++;
1838571ecf67SJohannes Berg 		dev_kfree_skb(rx->skb);
18399ae54c84SJohannes Berg 		return RX_QUEUED;
1840571ecf67SJohannes Berg 	}
1841571ecf67SJohannes Berg 
18429ae54c84SJohannes Berg 	return RX_CONTINUE;
1843571ecf67SJohannes Berg } /* ieee80211_rx_h_sta_process */
1844571ecf67SJohannes Berg 
1845af2d14b0SJouni Malinen static struct ieee80211_key *
ieee80211_rx_get_bigtk(struct ieee80211_rx_data * rx,int idx)1846af2d14b0SJouni Malinen ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx)
1847af2d14b0SJouni Malinen {
1848af2d14b0SJouni Malinen 	struct ieee80211_key *key = NULL;
1849af2d14b0SJouni Malinen 	int idx2;
1850af2d14b0SJouni Malinen 
1851af2d14b0SJouni Malinen 	/* Make sure key gets set if either BIGTK key index is set so that
1852af2d14b0SJouni Malinen 	 * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected
1853af2d14b0SJouni Malinen 	 * Beacon frames and Beacon frames that claim to use another BIGTK key
1854af2d14b0SJouni Malinen 	 * index (i.e., a key that we do not have).
1855af2d14b0SJouni Malinen 	 */
1856af2d14b0SJouni Malinen 
1857af2d14b0SJouni Malinen 	if (idx < 0) {
1858af2d14b0SJouni Malinen 		idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
1859af2d14b0SJouni Malinen 		idx2 = idx + 1;
1860af2d14b0SJouni Malinen 	} else {
1861af2d14b0SJouni Malinen 		if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
1862af2d14b0SJouni Malinen 			idx2 = idx + 1;
1863af2d14b0SJouni Malinen 		else
1864af2d14b0SJouni Malinen 			idx2 = idx - 1;
1865af2d14b0SJouni Malinen 	}
1866af2d14b0SJouni Malinen 
1867ccdde7c7SJohannes Berg 	if (rx->link_sta)
1868ccdde7c7SJohannes Berg 		key = rcu_dereference(rx->link_sta->gtk[idx]);
1869af2d14b0SJouni Malinen 	if (!key)
1870ccdde7c7SJohannes Berg 		key = rcu_dereference(rx->link->gtk[idx]);
1871ccdde7c7SJohannes Berg 	if (!key && rx->link_sta)
1872ccdde7c7SJohannes Berg 		key = rcu_dereference(rx->link_sta->gtk[idx2]);
1873af2d14b0SJouni Malinen 	if (!key)
1874ccdde7c7SJohannes Berg 		key = rcu_dereference(rx->link->gtk[idx2]);
1875af2d14b0SJouni Malinen 
1876af2d14b0SJouni Malinen 	return key;
1877af2d14b0SJouni Malinen }
1878af2d14b0SJouni Malinen 
187986c228a7SJohan Almbladh static ieee80211_rx_result debug_noinline
ieee80211_rx_h_decrypt(struct ieee80211_rx_data * rx)188086c228a7SJohan Almbladh ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
188186c228a7SJohan Almbladh {
188286c228a7SJohan Almbladh 	struct sk_buff *skb = rx->skb;
188386c228a7SJohan Almbladh 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
188486c228a7SJohan Almbladh 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
188586c228a7SJohan Almbladh 	int keyidx;
188686c228a7SJohan Almbladh 	ieee80211_rx_result result = RX_DROP_UNUSABLE;
188786c228a7SJohan Almbladh 	struct ieee80211_key *sta_ptk = NULL;
188896fc6efbSAlexander Wetzel 	struct ieee80211_key *ptk_idx = NULL;
188986c228a7SJohan Almbladh 	int mmie_keyidx = -1;
189086c228a7SJohan Almbladh 	__le16 fc;
189186c228a7SJohan Almbladh 
189209a740ceSThomas Pedersen 	if (ieee80211_is_ext(hdr->frame_control))
189309a740ceSThomas Pedersen 		return RX_CONTINUE;
189409a740ceSThomas Pedersen 
189586c228a7SJohan Almbladh 	/*
189686c228a7SJohan Almbladh 	 * Key selection 101
189786c228a7SJohan Almbladh 	 *
1898af2d14b0SJouni Malinen 	 * There are five types of keys:
189986c228a7SJohan Almbladh 	 *  - GTK (group keys)
190086c228a7SJohan Almbladh 	 *  - IGTK (group keys for management frames)
1901af2d14b0SJouni Malinen 	 *  - BIGTK (group keys for Beacon frames)
190286c228a7SJohan Almbladh 	 *  - PTK (pairwise keys)
190386c228a7SJohan Almbladh 	 *  - STK (station-to-station pairwise keys)
190486c228a7SJohan Almbladh 	 *
190586c228a7SJohan Almbladh 	 * When selecting a key, we have to distinguish between multicast
190686c228a7SJohan Almbladh 	 * (including broadcast) and unicast frames, the latter can only
1907af2d14b0SJouni Malinen 	 * use PTKs and STKs while the former always use GTKs, IGTKs, and
1908af2d14b0SJouni Malinen 	 * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used,
1909af2d14b0SJouni Malinen 	 * then unicast frames can also use key indices like GTKs. Hence, if we
191086c228a7SJohan Almbladh 	 * don't have a PTK/STK we check the key index for a WEP key.
191186c228a7SJohan Almbladh 	 *
191286c228a7SJohan Almbladh 	 * Note that in a regular BSS, multicast frames are sent by the
191386c228a7SJohan Almbladh 	 * AP only, associated stations unicast the frame to the AP first
191486c228a7SJohan Almbladh 	 * which then multicasts it on their behalf.
191586c228a7SJohan Almbladh 	 *
191686c228a7SJohan Almbladh 	 * There is also a slight problem in IBSS mode: GTKs are negotiated
191786c228a7SJohan Almbladh 	 * with each station, that is something we don't currently handle.
191886c228a7SJohan Almbladh 	 * The spec seems to expect that one negotiates the same key with
191986c228a7SJohan Almbladh 	 * every station but there's no such requirement; VLANs could be
192086c228a7SJohan Almbladh 	 * possible.
192186c228a7SJohan Almbladh 	 */
192286c228a7SJohan Almbladh 
192386c228a7SJohan Almbladh 	/* start without a key */
192486c228a7SJohan Almbladh 	rx->key = NULL;
192586c228a7SJohan Almbladh 	fc = hdr->frame_control;
192686c228a7SJohan Almbladh 
19272475b1ccSMax Stepanov 	if (rx->sta) {
19282475b1ccSMax Stepanov 		int keyid = rx->sta->ptk_idx;
192996fc6efbSAlexander Wetzel 		sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
19302475b1ccSMax Stepanov 
193177dfc2bcSXing Song 		if (ieee80211_has_protected(fc) &&
193277dfc2bcSXing Song 		    !(status->flag & RX_FLAG_IV_STRIPPED)) {
193323a5f0afSJohannes Berg 			keyid = ieee80211_get_keyid(rx->skb);
193496fc6efbSAlexander Wetzel 
19352475b1ccSMax Stepanov 			if (unlikely(keyid < 0))
19362475b1ccSMax Stepanov 				return RX_DROP_UNUSABLE;
193796fc6efbSAlexander Wetzel 
193896fc6efbSAlexander Wetzel 			ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
19392475b1ccSMax Stepanov 		}
19402475b1ccSMax Stepanov 	}
19412475b1ccSMax Stepanov 
194286c228a7SJohan Almbladh 	if (!ieee80211_has_protected(fc))
194386c228a7SJohan Almbladh 		mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
194486c228a7SJohan Almbladh 
194586c228a7SJohan Almbladh 	if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
194696fc6efbSAlexander Wetzel 		rx->key = ptk_idx ? ptk_idx : sta_ptk;
194786c228a7SJohan Almbladh 		if ((status->flag & RX_FLAG_DECRYPTED) &&
194886c228a7SJohan Almbladh 		    (status->flag & RX_FLAG_IV_STRIPPED))
194986c228a7SJohan Almbladh 			return RX_CONTINUE;
195086c228a7SJohan Almbladh 		/* Skip decryption if the frame is not protected. */
195186c228a7SJohan Almbladh 		if (!ieee80211_has_protected(fc))
195286c228a7SJohan Almbladh 			return RX_CONTINUE;
1953af2d14b0SJouni Malinen 	} else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) {
1954af2d14b0SJouni Malinen 		/* Broadcast/multicast robust management frame / BIP */
1955af2d14b0SJouni Malinen 		if ((status->flag & RX_FLAG_DECRYPTED) &&
1956af2d14b0SJouni Malinen 		    (status->flag & RX_FLAG_IV_STRIPPED))
1957af2d14b0SJouni Malinen 			return RX_CONTINUE;
1958af2d14b0SJouni Malinen 
1959af2d14b0SJouni Malinen 		if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
1960af2d14b0SJouni Malinen 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
19619eaf183aSJouni Malinen 				   NUM_DEFAULT_BEACON_KEYS) {
1962b2d03cabSJohannes Berg 			if (rx->sdata->dev)
19639eaf183aSJouni Malinen 				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
19649eaf183aSJouni Malinen 							     skb->data,
19659eaf183aSJouni Malinen 							     skb->len);
1966baa951a1SJohannes Berg 			return RX_DROP_M_BAD_BCN_KEYIDX;
19679eaf183aSJouni Malinen 		}
1968af2d14b0SJouni Malinen 
1969af2d14b0SJouni Malinen 		rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
1970af2d14b0SJouni Malinen 		if (!rx->key)
1971af2d14b0SJouni Malinen 			return RX_CONTINUE; /* Beacon protection not in use */
197286c228a7SJohan Almbladh 	} else if (mmie_keyidx >= 0) {
197386c228a7SJohan Almbladh 		/* Broadcast/multicast robust management frame / BIP */
197486c228a7SJohan Almbladh 		if ((status->flag & RX_FLAG_DECRYPTED) &&
197586c228a7SJohan Almbladh 		    (status->flag & RX_FLAG_IV_STRIPPED))
197686c228a7SJohan Almbladh 			return RX_CONTINUE;
197786c228a7SJohan Almbladh 
197886c228a7SJohan Almbladh 		if (mmie_keyidx < NUM_DEFAULT_KEYS ||
197986c228a7SJohan Almbladh 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
1980baa951a1SJohannes Berg 			return RX_DROP_M_BAD_MGMT_KEYIDX; /* unexpected BIP keyidx */
1981ccdde7c7SJohannes Berg 		if (rx->link_sta) {
198246f6b060SMasashi Honma 			if (ieee80211_is_group_privacy_action(skb) &&
198346f6b060SMasashi Honma 			    test_sta_flag(rx->sta, WLAN_STA_MFP))
198446f6b060SMasashi Honma 				return RX_DROP_MONITOR;
198546f6b060SMasashi Honma 
1986ccdde7c7SJohannes Berg 			rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]);
198746f6b060SMasashi Honma 		}
198886c228a7SJohan Almbladh 		if (!rx->key)
1989ccdde7c7SJohannes Berg 			rx->key = rcu_dereference(rx->link->gtk[mmie_keyidx]);
199086c228a7SJohan Almbladh 	} else if (!ieee80211_has_protected(fc)) {
199186c228a7SJohan Almbladh 		/*
199286c228a7SJohan Almbladh 		 * The frame was not protected, so skip decryption. However, we
199386c228a7SJohan Almbladh 		 * need to set rx->key if there is a key that could have been
199486c228a7SJohan Almbladh 		 * used so that the frame may be dropped if encryption would
199586c228a7SJohan Almbladh 		 * have been expected.
199686c228a7SJohan Almbladh 		 */
199786c228a7SJohan Almbladh 		struct ieee80211_key *key = NULL;
199886c228a7SJohan Almbladh 		int i;
199986c228a7SJohan Almbladh 
2000af2d14b0SJouni Malinen 		if (ieee80211_is_beacon(fc)) {
2001af2d14b0SJouni Malinen 			key = ieee80211_rx_get_bigtk(rx, -1);
2002af2d14b0SJouni Malinen 		} else if (ieee80211_is_mgmt(fc) &&
2003af2d14b0SJouni Malinen 			   is_multicast_ether_addr(hdr->addr1)) {
2004ccdde7c7SJohannes Berg 			key = rcu_dereference(rx->link->default_mgmt_key);
2005af2d14b0SJouni Malinen 		} else {
2006ccdde7c7SJohannes Berg 			if (rx->link_sta) {
200786c228a7SJohan Almbladh 				for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
2008ccdde7c7SJohannes Berg 					key = rcu_dereference(rx->link_sta->gtk[i]);
200986c228a7SJohan Almbladh 					if (key)
201086c228a7SJohan Almbladh 						break;
201186c228a7SJohan Almbladh 				}
201286c228a7SJohan Almbladh 			}
201386c228a7SJohan Almbladh 			if (!key) {
201486c228a7SJohan Almbladh 				for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
2015ccdde7c7SJohannes Berg 					key = rcu_dereference(rx->link->gtk[i]);
201686c228a7SJohan Almbladh 					if (key)
201786c228a7SJohan Almbladh 						break;
201886c228a7SJohan Almbladh 				}
201986c228a7SJohan Almbladh 			}
2020af2d14b0SJouni Malinen 		}
202186c228a7SJohan Almbladh 		if (key)
202286c228a7SJohan Almbladh 			rx->key = key;
202386c228a7SJohan Almbladh 		return RX_CONTINUE;
202486c228a7SJohan Almbladh 	} else {
202586c228a7SJohan Almbladh 		/*
202686c228a7SJohan Almbladh 		 * The device doesn't give us the IV so we won't be
202786c228a7SJohan Almbladh 		 * able to look up the key. That's ok though, we
202886c228a7SJohan Almbladh 		 * don't need to decrypt the frame, we just won't
202986c228a7SJohan Almbladh 		 * be able to keep statistics accurate.
203086c228a7SJohan Almbladh 		 * Except for key threshold notifications, should
203186c228a7SJohan Almbladh 		 * we somehow allow the driver to tell us which key
203286c228a7SJohan Almbladh 		 * the hardware used if this flag is set?
203386c228a7SJohan Almbladh 		 */
203486c228a7SJohan Almbladh 		if ((status->flag & RX_FLAG_DECRYPTED) &&
203586c228a7SJohan Almbladh 		    (status->flag & RX_FLAG_IV_STRIPPED))
203686c228a7SJohan Almbladh 			return RX_CONTINUE;
203786c228a7SJohan Almbladh 
203823a5f0afSJohannes Berg 		keyidx = ieee80211_get_keyid(rx->skb);
20392475b1ccSMax Stepanov 
20402475b1ccSMax Stepanov 		if (unlikely(keyidx < 0))
20412475b1ccSMax Stepanov 			return RX_DROP_UNUSABLE;
204286c228a7SJohan Almbladh 
204386c228a7SJohan Almbladh 		/* check per-station GTK first, if multicast packet */
2044ccdde7c7SJohannes Berg 		if (is_multicast_ether_addr(hdr->addr1) && rx->link_sta)
2045ccdde7c7SJohannes Berg 			rx->key = rcu_dereference(rx->link_sta->gtk[keyidx]);
204686c228a7SJohan Almbladh 
204786c228a7SJohan Almbladh 		/* if not found, try default key */
204886c228a7SJohan Almbladh 		if (!rx->key) {
2049bfd8403aSJohannes Berg 			if (is_multicast_ether_addr(hdr->addr1))
2050ccdde7c7SJohannes Berg 				rx->key = rcu_dereference(rx->link->gtk[keyidx]);
2051bfd8403aSJohannes Berg 			if (!rx->key)
205286c228a7SJohan Almbladh 				rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
205386c228a7SJohan Almbladh 
205486c228a7SJohan Almbladh 			/*
205586c228a7SJohan Almbladh 			 * RSNA-protected unicast frames should always be
205686c228a7SJohan Almbladh 			 * sent with pairwise or station-to-station keys,
205786c228a7SJohan Almbladh 			 * but for WEP we allow using a key index as well.
205886c228a7SJohan Almbladh 			 */
205986c228a7SJohan Almbladh 			if (rx->key &&
206086c228a7SJohan Almbladh 			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
206186c228a7SJohan Almbladh 			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
206286c228a7SJohan Almbladh 			    !is_multicast_ether_addr(hdr->addr1))
206386c228a7SJohan Almbladh 				rx->key = NULL;
206486c228a7SJohan Almbladh 		}
206586c228a7SJohan Almbladh 	}
206686c228a7SJohan Almbladh 
206786c228a7SJohan Almbladh 	if (rx->key) {
206886c228a7SJohan Almbladh 		if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
206986c228a7SJohan Almbladh 			return RX_DROP_MONITOR;
207086c228a7SJohan Almbladh 
207186c228a7SJohan Almbladh 		/* TODO: add threshold stuff again */
207286c228a7SJohan Almbladh 	} else {
207386c228a7SJohan Almbladh 		return RX_DROP_MONITOR;
207486c228a7SJohan Almbladh 	}
207586c228a7SJohan Almbladh 
207686c228a7SJohan Almbladh 	switch (rx->key->conf.cipher) {
207786c228a7SJohan Almbladh 	case WLAN_CIPHER_SUITE_WEP40:
207886c228a7SJohan Almbladh 	case WLAN_CIPHER_SUITE_WEP104:
207986c228a7SJohan Almbladh 		result = ieee80211_crypto_wep_decrypt(rx);
208086c228a7SJohan Almbladh 		break;
208186c228a7SJohan Almbladh 	case WLAN_CIPHER_SUITE_TKIP:
208286c228a7SJohan Almbladh 		result = ieee80211_crypto_tkip_decrypt(rx);
208386c228a7SJohan Almbladh 		break;
208486c228a7SJohan Almbladh 	case WLAN_CIPHER_SUITE_CCMP:
20852b2ba0dbSJouni Malinen 		result = ieee80211_crypto_ccmp_decrypt(
20862b2ba0dbSJouni Malinen 			rx, IEEE80211_CCMP_MIC_LEN);
20872b2ba0dbSJouni Malinen 		break;
20882b2ba0dbSJouni Malinen 	case WLAN_CIPHER_SUITE_CCMP_256:
20892b2ba0dbSJouni Malinen 		result = ieee80211_crypto_ccmp_decrypt(
20902b2ba0dbSJouni Malinen 			rx, IEEE80211_CCMP_256_MIC_LEN);
209186c228a7SJohan Almbladh 		break;
209286c228a7SJohan Almbladh 	case WLAN_CIPHER_SUITE_AES_CMAC:
209386c228a7SJohan Almbladh 		result = ieee80211_crypto_aes_cmac_decrypt(rx);
209486c228a7SJohan Almbladh 		break;
209556c52da2SJouni Malinen 	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
209656c52da2SJouni Malinen 		result = ieee80211_crypto_aes_cmac_256_decrypt(rx);
209756c52da2SJouni Malinen 		break;
20988ade538bSJouni Malinen 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
20998ade538bSJouni Malinen 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
21008ade538bSJouni Malinen 		result = ieee80211_crypto_aes_gmac_decrypt(rx);
21018ade538bSJouni Malinen 		break;
210200b9cfa3SJouni Malinen 	case WLAN_CIPHER_SUITE_GCMP:
210300b9cfa3SJouni Malinen 	case WLAN_CIPHER_SUITE_GCMP_256:
210400b9cfa3SJouni Malinen 		result = ieee80211_crypto_gcmp_decrypt(rx);
210500b9cfa3SJouni Malinen 		break;
210686c228a7SJohan Almbladh 	default:
210723a5f0afSJohannes Berg 		result = RX_DROP_UNUSABLE;
210886c228a7SJohan Almbladh 	}
210986c228a7SJohan Almbladh 
211086c228a7SJohan Almbladh 	/* the hdr variable is invalid after the decrypt handlers */
211186c228a7SJohan Almbladh 
211286c228a7SJohan Almbladh 	/* either the frame has been decrypted or will be dropped */
211386c228a7SJohan Almbladh 	status->flag |= RX_FLAG_DECRYPTED;
211486c228a7SJohan Almbladh 
21152fa71edbSJohannes Berg 	if (unlikely(ieee80211_is_beacon(fc) && RX_RES_IS_UNUSABLE(result) &&
2116b2d03cabSJohannes Berg 		     rx->sdata->dev))
21179eaf183aSJouni Malinen 		cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
21189eaf183aSJouni Malinen 					     skb->data, skb->len);
21199eaf183aSJouni Malinen 
212086c228a7SJohan Almbladh 	return result;
212186c228a7SJohan Almbladh }
212286c228a7SJohan Almbladh 
ieee80211_init_frag_cache(struct ieee80211_fragment_cache * cache)21233a11ce08SJohannes Berg void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache)
21243a11ce08SJohannes Berg {
21253a11ce08SJohannes Berg 	int i;
21263a11ce08SJohannes Berg 
21273a11ce08SJohannes Berg 	for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
21283a11ce08SJohannes Berg 		skb_queue_head_init(&cache->entries[i].skb_list);
21293a11ce08SJohannes Berg }
21303a11ce08SJohannes Berg 
ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache * cache)21313a11ce08SJohannes Berg void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache)
21323a11ce08SJohannes Berg {
21333a11ce08SJohannes Berg 	int i;
21343a11ce08SJohannes Berg 
21353a11ce08SJohannes Berg 	for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
21363a11ce08SJohannes Berg 		__skb_queue_purge(&cache->entries[i].skb_list);
21373a11ce08SJohannes Berg }
21383a11ce08SJohannes Berg 
2139571ecf67SJohannes Berg static inline struct ieee80211_fragment_entry *
ieee80211_reassemble_add(struct ieee80211_fragment_cache * cache,unsigned int frag,unsigned int seq,int rx_queue,struct sk_buff ** skb)21403a11ce08SJohannes Berg ieee80211_reassemble_add(struct ieee80211_fragment_cache *cache,
2141571ecf67SJohannes Berg 			 unsigned int frag, unsigned int seq, int rx_queue,
2142571ecf67SJohannes Berg 			 struct sk_buff **skb)
2143571ecf67SJohannes Berg {
2144571ecf67SJohannes Berg 	struct ieee80211_fragment_entry *entry;
2145571ecf67SJohannes Berg 
21463a11ce08SJohannes Berg 	entry = &cache->entries[cache->next++];
21473a11ce08SJohannes Berg 	if (cache->next >= IEEE80211_FRAGMENT_MAX)
21483a11ce08SJohannes Berg 		cache->next = 0;
2149571ecf67SJohannes Berg 
2150571ecf67SJohannes Berg 	__skb_queue_purge(&entry->skb_list);
2151571ecf67SJohannes Berg 
2152571ecf67SJohannes Berg 	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
2153571ecf67SJohannes Berg 	*skb = NULL;
2154571ecf67SJohannes Berg 	entry->first_frag_time = jiffies;
2155571ecf67SJohannes Berg 	entry->seq = seq;
2156571ecf67SJohannes Berg 	entry->rx_queue = rx_queue;
2157571ecf67SJohannes Berg 	entry->last_frag = frag;
21589acc54beSJohannes Berg 	entry->check_sequential_pn = false;
2159571ecf67SJohannes Berg 	entry->extra_len = 0;
2160571ecf67SJohannes Berg 
2161571ecf67SJohannes Berg 	return entry;
2162571ecf67SJohannes Berg }
2163571ecf67SJohannes Berg 
2164571ecf67SJohannes Berg static inline struct ieee80211_fragment_entry *
ieee80211_reassemble_find(struct ieee80211_fragment_cache * cache,unsigned int frag,unsigned int seq,int rx_queue,struct ieee80211_hdr * hdr)21653a11ce08SJohannes Berg ieee80211_reassemble_find(struct ieee80211_fragment_cache *cache,
2166b73d70adSHarvey Harrison 			  unsigned int frag, unsigned int seq,
2167571ecf67SJohannes Berg 			  int rx_queue, struct ieee80211_hdr *hdr)
2168571ecf67SJohannes Berg {
2169571ecf67SJohannes Berg 	struct ieee80211_fragment_entry *entry;
2170571ecf67SJohannes Berg 	int i, idx;
2171571ecf67SJohannes Berg 
21723a11ce08SJohannes Berg 	idx = cache->next;
2173571ecf67SJohannes Berg 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
2174571ecf67SJohannes Berg 		struct ieee80211_hdr *f_hdr;
21757957a9deSDavid S. Miller 		struct sk_buff *f_skb;
2176571ecf67SJohannes Berg 
2177571ecf67SJohannes Berg 		idx--;
2178571ecf67SJohannes Berg 		if (idx < 0)
2179571ecf67SJohannes Berg 			idx = IEEE80211_FRAGMENT_MAX - 1;
2180571ecf67SJohannes Berg 
21813a11ce08SJohannes Berg 		entry = &cache->entries[idx];
2182571ecf67SJohannes Berg 		if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
2183571ecf67SJohannes Berg 		    entry->rx_queue != rx_queue ||
2184571ecf67SJohannes Berg 		    entry->last_frag + 1 != frag)
2185571ecf67SJohannes Berg 			continue;
2186571ecf67SJohannes Berg 
21877957a9deSDavid S. Miller 		f_skb = __skb_peek(&entry->skb_list);
21887957a9deSDavid S. Miller 		f_hdr = (struct ieee80211_hdr *) f_skb->data;
2189571ecf67SJohannes Berg 
2190b73d70adSHarvey Harrison 		/*
2191b73d70adSHarvey Harrison 		 * Check ftype and addresses are equal, else check next fragment
2192b73d70adSHarvey Harrison 		 */
2193b73d70adSHarvey Harrison 		if (((hdr->frame_control ^ f_hdr->frame_control) &
2194b73d70adSHarvey Harrison 		     cpu_to_le16(IEEE80211_FCTL_FTYPE)) ||
2195b203ca39SJoe Perches 		    !ether_addr_equal(hdr->addr1, f_hdr->addr1) ||
2196b203ca39SJoe Perches 		    !ether_addr_equal(hdr->addr2, f_hdr->addr2))
2197571ecf67SJohannes Berg 			continue;
2198571ecf67SJohannes Berg 
2199ab46623eSS.Çağlar Onur 		if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
2200571ecf67SJohannes Berg 			__skb_queue_purge(&entry->skb_list);
2201571ecf67SJohannes Berg 			continue;
2202571ecf67SJohannes Berg 		}
2203571ecf67SJohannes Berg 		return entry;
2204571ecf67SJohannes Berg 	}
2205571ecf67SJohannes Berg 
2206571ecf67SJohannes Berg 	return NULL;
2207571ecf67SJohannes Berg }
2208571ecf67SJohannes Berg 
requires_sequential_pn(struct ieee80211_rx_data * rx,__le16 fc)2209965a7d72SMathy Vanhoef static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc)
2210965a7d72SMathy Vanhoef {
2211965a7d72SMathy Vanhoef 	return rx->key &&
2212965a7d72SMathy Vanhoef 		(rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
2213965a7d72SMathy Vanhoef 		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
2214965a7d72SMathy Vanhoef 		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
2215965a7d72SMathy Vanhoef 		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
2216965a7d72SMathy Vanhoef 		ieee80211_has_protected(fc);
2217965a7d72SMathy Vanhoef }
2218965a7d72SMathy Vanhoef 
221949461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_defragment(struct ieee80211_rx_data * rx)22205cf121c3SJohannes Berg ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
2221571ecf67SJohannes Berg {
22223a11ce08SJohannes Berg 	struct ieee80211_fragment_cache *cache = &rx->sdata->frags;
2223571ecf67SJohannes Berg 	struct ieee80211_hdr *hdr;
2224571ecf67SJohannes Berg 	u16 sc;
2225358c8d9dSHarvey Harrison 	__le16 fc;
2226571ecf67SJohannes Berg 	unsigned int frag, seq;
2227571ecf67SJohannes Berg 	struct ieee80211_fragment_entry *entry;
2228571ecf67SJohannes Berg 	struct sk_buff *skb;
22293edc6b0dSWen Gong 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
2230571ecf67SJohannes Berg 
2231571ecf67SJohannes Berg 	hdr = (struct ieee80211_hdr *)rx->skb->data;
2232358c8d9dSHarvey Harrison 	fc = hdr->frame_control;
2233f7fbf70eSJavier Cardona 
223409a740ceSThomas Pedersen 	if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc))
2235f7fbf70eSJavier Cardona 		return RX_CONTINUE;
2236f7fbf70eSJavier Cardona 
2237571ecf67SJohannes Berg 	sc = le16_to_cpu(hdr->seq_ctrl);
2238571ecf67SJohannes Berg 	frag = sc & IEEE80211_SCTL_FRAG;
2239571ecf67SJohannes Berg 
22403a11ce08SJohannes Berg 	if (rx->sta)
22413a11ce08SJohannes Berg 		cache = &rx->sta->frags;
22423a11ce08SJohannes Berg 
2243d025933eSAndreas Müller 	if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
2244d025933eSAndreas Müller 		goto out;
2245d025933eSAndreas Müller 
2246a9799541SJohannes Berg 	if (is_multicast_ether_addr(hdr->addr1))
2247a9799541SJohannes Berg 		return RX_DROP_MONITOR;
2248a9799541SJohannes Berg 
2249571ecf67SJohannes Berg 	I802_DEBUG_INC(rx->local->rx_handlers_fragments);
2250571ecf67SJohannes Berg 
2251e3cf8b3fSZhu Yi 	if (skb_linearize(rx->skb))
2252e3cf8b3fSZhu Yi 		return RX_DROP_UNUSABLE;
2253e3cf8b3fSZhu Yi 
2254058897a4SAbhijeet Kolekar 	/*
2255058897a4SAbhijeet Kolekar 	 *  skb_linearize() might change the skb->data and
2256058897a4SAbhijeet Kolekar 	 *  previously cached variables (in this case, hdr) need to
2257058897a4SAbhijeet Kolekar 	 *  be refreshed with the new data.
2258058897a4SAbhijeet Kolekar 	 */
2259058897a4SAbhijeet Kolekar 	hdr = (struct ieee80211_hdr *)rx->skb->data;
2260571ecf67SJohannes Berg 	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
2261571ecf67SJohannes Berg 
2262571ecf67SJohannes Berg 	if (frag == 0) {
2263571ecf67SJohannes Berg 		/* This is the first fragment of a new frame. */
22643a11ce08SJohannes Berg 		entry = ieee80211_reassemble_add(cache, frag, seq,
22659e26297aSJohannes Berg 						 rx->seqno_idx, &(rx->skb));
2266965a7d72SMathy Vanhoef 		if (requires_sequential_pn(rx, fc)) {
22679e26297aSJohannes Berg 			int queue = rx->security_idx;
22689acc54beSJohannes Berg 
22699acc54beSJohannes Berg 			/* Store CCMP/GCMP PN so that we can verify that the
22709acc54beSJohannes Berg 			 * next fragment has a sequential PN value.
22719acc54beSJohannes Berg 			 */
22729acc54beSJohannes Berg 			entry->check_sequential_pn = true;
22737e44a0b5SJohannes Berg 			entry->is_protected = true;
227494034c40SMathy Vanhoef 			entry->key_color = rx->key->color;
2275571ecf67SJohannes Berg 			memcpy(entry->last_pn,
22769190252cSJouni Malinen 			       rx->key->u.ccmp.rx_pn[queue],
22774325f6caSJohannes Berg 			       IEEE80211_CCMP_PN_LEN);
22789acc54beSJohannes Berg 			BUILD_BUG_ON(offsetof(struct ieee80211_key,
22799acc54beSJohannes Berg 					      u.ccmp.rx_pn) !=
22809acc54beSJohannes Berg 				     offsetof(struct ieee80211_key,
22819acc54beSJohannes Berg 					      u.gcmp.rx_pn));
22829acc54beSJohannes Berg 			BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
22839acc54beSJohannes Berg 				     sizeof(rx->key->u.gcmp.rx_pn[queue]));
22849acc54beSJohannes Berg 			BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
22859acc54beSJohannes Berg 				     IEEE80211_GCMP_PN_LEN);
22863edc6b0dSWen Gong 		} else if (rx->key &&
22873edc6b0dSWen Gong 			   (ieee80211_has_protected(fc) ||
22883edc6b0dSWen Gong 			    (status->flag & RX_FLAG_DECRYPTED))) {
22897e44a0b5SJohannes Berg 			entry->is_protected = true;
22907e44a0b5SJohannes Berg 			entry->key_color = rx->key->color;
2291571ecf67SJohannes Berg 		}
22929ae54c84SJohannes Berg 		return RX_QUEUED;
2293571ecf67SJohannes Berg 	}
2294571ecf67SJohannes Berg 
2295571ecf67SJohannes Berg 	/* This is a fragment for a frame that should already be pending in
2296571ecf67SJohannes Berg 	 * fragment cache. Add this fragment to the end of the pending entry.
2297571ecf67SJohannes Berg 	 */
22983a11ce08SJohannes Berg 	entry = ieee80211_reassemble_find(cache, frag, seq,
22999e26297aSJohannes Berg 					  rx->seqno_idx, hdr);
2300571ecf67SJohannes Berg 	if (!entry) {
2301571ecf67SJohannes Berg 		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
2302e4c26addSJohannes Berg 		return RX_DROP_MONITOR;
2303571ecf67SJohannes Berg 	}
2304571ecf67SJohannes Berg 
23059acc54beSJohannes Berg 	/* "The receiver shall discard MSDUs and MMPDUs whose constituent
23069acc54beSJohannes Berg 	 *  MPDU PN values are not incrementing in steps of 1."
23079acc54beSJohannes Berg 	 * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
23089acc54beSJohannes Berg 	 * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
23099acc54beSJohannes Berg 	 */
23109acc54beSJohannes Berg 	if (entry->check_sequential_pn) {
2311571ecf67SJohannes Berg 		int i;
23124325f6caSJohannes Berg 		u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
23139acc54beSJohannes Berg 
2314965a7d72SMathy Vanhoef 		if (!requires_sequential_pn(rx, fc))
2315e4c26addSJohannes Berg 			return RX_DROP_UNUSABLE;
231694034c40SMathy Vanhoef 
231794034c40SMathy Vanhoef 		/* Prevent mixed key and fragment cache attacks */
231894034c40SMathy Vanhoef 		if (entry->key_color != rx->key->color)
231994034c40SMathy Vanhoef 			return RX_DROP_UNUSABLE;
232094034c40SMathy Vanhoef 
23214325f6caSJohannes Berg 		memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
23224325f6caSJohannes Berg 		for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
2323571ecf67SJohannes Berg 			pn[i]++;
2324571ecf67SJohannes Berg 			if (pn[i])
2325571ecf67SJohannes Berg 				break;
2326571ecf67SJohannes Berg 		}
2327bf30ca92SJohannes Berg 
2328bf30ca92SJohannes Berg 		rpn = rx->ccm_gcm.pn;
23294325f6caSJohannes Berg 		if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN))
2330e4c26addSJohannes Berg 			return RX_DROP_UNUSABLE;
23314325f6caSJohannes Berg 		memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
23327e44a0b5SJohannes Berg 	} else if (entry->is_protected &&
23333edc6b0dSWen Gong 		   (!rx->key ||
23343edc6b0dSWen Gong 		    (!ieee80211_has_protected(fc) &&
23353edc6b0dSWen Gong 		     !(status->flag & RX_FLAG_DECRYPTED)) ||
23367e44a0b5SJohannes Berg 		    rx->key->color != entry->key_color)) {
23377e44a0b5SJohannes Berg 		/* Drop this as a mixed key or fragment cache attack, even
23387e44a0b5SJohannes Berg 		 * if for TKIP Michael MIC should protect us, and WEP is a
23397e44a0b5SJohannes Berg 		 * lost cause anyway.
23407e44a0b5SJohannes Berg 		 */
23417e44a0b5SJohannes Berg 		return RX_DROP_UNUSABLE;
23423edc6b0dSWen Gong 	} else if (entry->is_protected && rx->key &&
23433edc6b0dSWen Gong 		   entry->key_color != rx->key->color &&
23443edc6b0dSWen Gong 		   (status->flag & RX_FLAG_DECRYPTED)) {
23453edc6b0dSWen Gong 		return RX_DROP_UNUSABLE;
2346571ecf67SJohannes Berg 	}
2347571ecf67SJohannes Berg 
2348358c8d9dSHarvey Harrison 	skb_pull(rx->skb, ieee80211_hdrlen(fc));
2349571ecf67SJohannes Berg 	__skb_queue_tail(&entry->skb_list, rx->skb);
2350571ecf67SJohannes Berg 	entry->last_frag = frag;
2351571ecf67SJohannes Berg 	entry->extra_len += rx->skb->len;
2352358c8d9dSHarvey Harrison 	if (ieee80211_has_morefrags(fc)) {
2353571ecf67SJohannes Berg 		rx->skb = NULL;
23549ae54c84SJohannes Berg 		return RX_QUEUED;
2355571ecf67SJohannes Berg 	}
2356571ecf67SJohannes Berg 
2357571ecf67SJohannes Berg 	rx->skb = __skb_dequeue(&entry->skb_list);
2358571ecf67SJohannes Berg 	if (skb_tailroom(rx->skb) < entry->extra_len) {
2359f1160434SJohannes Berg 		I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag);
2360571ecf67SJohannes Berg 		if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
2361571ecf67SJohannes Berg 					      GFP_ATOMIC))) {
2362571ecf67SJohannes Berg 			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
2363571ecf67SJohannes Berg 			__skb_queue_purge(&entry->skb_list);
2364e4c26addSJohannes Berg 			return RX_DROP_UNUSABLE;
2365571ecf67SJohannes Berg 		}
2366571ecf67SJohannes Berg 	}
2367571ecf67SJohannes Berg 	while ((skb = __skb_dequeue(&entry->skb_list))) {
236859ae1d12SJohannes Berg 		skb_put_data(rx->skb, skb->data, skb->len);
2369571ecf67SJohannes Berg 		dev_kfree_skb(skb);
2370571ecf67SJohannes Berg 	}
2371571ecf67SJohannes Berg 
2372571ecf67SJohannes Berg  out:
2373d025933eSAndreas Müller 	ieee80211_led_rx(rx->local);
2374571ecf67SJohannes Berg 	if (rx->sta)
2375b320d6c4SBenjamin Berg 		rx->link_sta->rx_stats.packets++;
23769ae54c84SJohannes Berg 	return RX_CONTINUE;
2377571ecf67SJohannes Berg }
2378571ecf67SJohannes Berg 
ieee80211_802_1x_port_control(struct ieee80211_rx_data * rx)23791df332e8SJohannes Berg static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
2380571ecf67SJohannes Berg {
23811df332e8SJohannes Berg 	if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
238276ee65bfSRon Rindjunsky 		return -EACCES;
2383571ecf67SJohannes Berg 
238476ee65bfSRon Rindjunsky 	return 0;
2385571ecf67SJohannes Berg }
2386571ecf67SJohannes Berg 
ieee80211_drop_unencrypted(struct ieee80211_rx_data * rx,__le16 fc)23871df332e8SJohannes Berg static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
2388571ecf67SJohannes Berg {
2389eb9fb5b8SJohannes Berg 	struct sk_buff *skb = rx->skb;
2390eb9fb5b8SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2391eb9fb5b8SJohannes Berg 
23923017b80bSJohannes Berg 	/*
23937848ba7dSJohannes Berg 	 * Pass through unencrypted frames if the hardware has
23947848ba7dSJohannes Berg 	 * decrypted them already.
23953017b80bSJohannes Berg 	 */
2396eb9fb5b8SJohannes Berg 	if (status->flag & RX_FLAG_DECRYPTED)
239776ee65bfSRon Rindjunsky 		return 0;
2398571ecf67SJohannes Berg 
2399571ecf67SJohannes Berg 	/* Drop unencrypted frames if key is set. */
2400358c8d9dSHarvey Harrison 	if (unlikely(!ieee80211_has_protected(fc) &&
240130b2f0beSThomas Pedersen 		     !ieee80211_is_any_nullfunc(fc) &&
2402e8f4fb7cSJohannes Berg 		     ieee80211_is_data(fc) && rx->key))
24033cfcf6acSJouni Malinen 		return -EACCES;
2404bef5d1c7SJohannes Berg 
2405bef5d1c7SJohannes Berg 	return 0;
2406bef5d1c7SJohannes Berg }
2407bef5d1c7SJohannes Berg 
ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data * rx)24081df332e8SJohannes Berg static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
2409bef5d1c7SJohannes Berg {
2410e3efca0aSJouni Malinen 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
241176a3059cSJohannes Berg 	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
241276a3059cSJohannes Berg 	__le16 fc = mgmt->frame_control;
2413bef5d1c7SJohannes Berg 
2414e3efca0aSJouni Malinen 	/*
2415e3efca0aSJouni Malinen 	 * Pass through unencrypted frames if the hardware has
2416e3efca0aSJouni Malinen 	 * decrypted them already.
2417e3efca0aSJouni Malinen 	 */
2418e3efca0aSJouni Malinen 	if (status->flag & RX_FLAG_DECRYPTED)
2419e3efca0aSJouni Malinen 		return 0;
2420bef5d1c7SJohannes Berg 
242176a3059cSJohannes Berg 	/* drop unicast protected dual (that wasn't protected) */
242276a3059cSJohannes Berg 	if (ieee80211_is_action(fc) &&
242376a3059cSJohannes Berg 	    mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
242476a3059cSJohannes Berg 		return -EACCES;
242576a3059cSJohannes Berg 
2426c2c98fdeSJohannes Berg 	if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
2427d211e90eSJouni Malinen 		if (unlikely(!ieee80211_has_protected(fc) &&
24287339e0f2SAlon Giladi 			     ieee80211_is_unicast_robust_mgmt_frame(rx->skb))) {
24296ff57cf8SJohannes Berg 			if (ieee80211_is_deauth(fc) ||
24307339e0f2SAlon Giladi 			    ieee80211_is_disassoc(fc)) {
24317339e0f2SAlon Giladi 				/*
24327339e0f2SAlon Giladi 				 * Permit unprotected deauth/disassoc frames
24337339e0f2SAlon Giladi 				 * during 4-way-HS (key is installed after HS).
24347339e0f2SAlon Giladi 				 */
24357339e0f2SAlon Giladi 				if (!rx->key)
24367339e0f2SAlon Giladi 					return 0;
24377339e0f2SAlon Giladi 
24386ff57cf8SJohannes Berg 				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
2439cf4e594eSJouni Malinen 							     rx->skb->data,
2440cf4e594eSJouni Malinen 							     rx->skb->len);
24417339e0f2SAlon Giladi 			}
2442f2ca3ea4SJouni Malinen 			return -EACCES;
2443cf4e594eSJouni Malinen 		}
24443cfcf6acSJouni Malinen 		/* BIP does not use Protected field, so need to check MMIE */
2445f64f9e71SJoe Perches 		if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
2446cf4e594eSJouni Malinen 			     ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
24476ff57cf8SJohannes Berg 			if (ieee80211_is_deauth(fc) ||
24486ff57cf8SJohannes Berg 			    ieee80211_is_disassoc(fc))
24496ff57cf8SJohannes Berg 				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
2450cf4e594eSJouni Malinen 							     rx->skb->data,
2451cf4e594eSJouni Malinen 							     rx->skb->len);
245276ee65bfSRon Rindjunsky 			return -EACCES;
2453cf4e594eSJouni Malinen 		}
2454af2d14b0SJouni Malinen 		if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
24559eaf183aSJouni Malinen 			     ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
24569eaf183aSJouni Malinen 			cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
24579eaf183aSJouni Malinen 						     rx->skb->data,
24589eaf183aSJouni Malinen 						     rx->skb->len);
2459af2d14b0SJouni Malinen 			return -EACCES;
24609eaf183aSJouni Malinen 		}
2461f2ca3ea4SJouni Malinen 		/*
2462f2ca3ea4SJouni Malinen 		 * When using MFP, Action frames are not allowed prior to
2463f2ca3ea4SJouni Malinen 		 * having configured keys.
2464f2ca3ea4SJouni Malinen 		 */
2465f2ca3ea4SJouni Malinen 		if (unlikely(ieee80211_is_action(fc) && !rx->key &&
2466d8ca16dbSJohannes Berg 			     ieee80211_is_robust_mgmt_frame(rx->skb)))
2467f2ca3ea4SJouni Malinen 			return -EACCES;
246876a3059cSJohannes Berg 
246976a3059cSJohannes Berg 		/* drop unicast public action frames when using MPF */
247076a3059cSJohannes Berg 		if (is_unicast_ether_addr(mgmt->da) &&
247191535613SAvraham Stern 		    ieee80211_is_protected_dual_of_public_action(rx->skb))
247276a3059cSJohannes Berg 			return -EACCES;
2473f2ca3ea4SJouni Malinen 	}
2474b3fc9c6cSJohannes Berg 
247576ee65bfSRon Rindjunsky 	return 0;
2476571ecf67SJohannes Berg }
2477571ecf67SJohannes Berg 
247876ee65bfSRon Rindjunsky static int
__ieee80211_data_to_8023(struct ieee80211_rx_data * rx,bool * port_control)24794114fa21SFelix Fietkau __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
2480571ecf67SJohannes Berg {
2481eb9fb5b8SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
2482f14543eeSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
2483fbb327c5SFelix Fietkau 	bool check_port_control = false;
2484fbb327c5SFelix Fietkau 	struct ethhdr *ehdr;
2485fbb327c5SFelix Fietkau 	int ret;
2486f14543eeSFelix Fietkau 
24874114fa21SFelix Fietkau 	*port_control = false;
24889bc383deSJohannes Berg 	if (ieee80211_has_a4(hdr->frame_control) &&
24899bc383deSJohannes Berg 	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
2490f14543eeSFelix Fietkau 		return -1;
24919bc383deSJohannes Berg 
2492fbb327c5SFelix Fietkau 	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
2493fbb327c5SFelix Fietkau 	    !!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) {
2494fbb327c5SFelix Fietkau 
2495fbb327c5SFelix Fietkau 		if (!sdata->u.mgd.use_4addr)
2496fbb327c5SFelix Fietkau 			return -1;
24971ecef20cSSathishkumar Muruganandam 		else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr))
2498fbb327c5SFelix Fietkau 			check_port_control = true;
2499fbb327c5SFelix Fietkau 	}
2500fbb327c5SFelix Fietkau 
25019bc383deSJohannes Berg 	if (is_multicast_ether_addr(hdr->addr1) &&
2502fbb327c5SFelix Fietkau 	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta)
2503f14543eeSFelix Fietkau 		return -1;
2504571ecf67SJohannes Berg 
2505fbb327c5SFelix Fietkau 	ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
25064114fa21SFelix Fietkau 	if (ret < 0)
2507fbb327c5SFelix Fietkau 		return ret;
2508fbb327c5SFelix Fietkau 
2509fbb327c5SFelix Fietkau 	ehdr = (struct ethhdr *) rx->skb->data;
25104114fa21SFelix Fietkau 	if (ehdr->h_proto == rx->sdata->control_port_protocol)
25114114fa21SFelix Fietkau 		*port_control = true;
25124114fa21SFelix Fietkau 	else if (check_port_control)
2513fbb327c5SFelix Fietkau 		return -1;
2514fbb327c5SFelix Fietkau 
2515fbb327c5SFelix Fietkau 	return 0;
251676ee65bfSRon Rindjunsky }
2517571ecf67SJohannes Berg 
ieee80211_is_our_addr(struct ieee80211_sub_if_data * sdata,const u8 * addr,int * out_link_id)25180d5891e3SAndrei Otcheretianski bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
2519d06faef1SAndrei Otcheretianski 			   const u8 *addr, int *out_link_id)
2520d06faef1SAndrei Otcheretianski {
2521d06faef1SAndrei Otcheretianski 	unsigned int link_id;
2522d06faef1SAndrei Otcheretianski 
2523d06faef1SAndrei Otcheretianski 	/* non-MLO, or MLD address replaced by hardware */
2524d06faef1SAndrei Otcheretianski 	if (ether_addr_equal(sdata->vif.addr, addr))
2525d06faef1SAndrei Otcheretianski 		return true;
2526d06faef1SAndrei Otcheretianski 
2527f1871abdSIlan Peer 	if (!ieee80211_vif_is_mld(&sdata->vif))
2528d06faef1SAndrei Otcheretianski 		return false;
2529d06faef1SAndrei Otcheretianski 
2530d06faef1SAndrei Otcheretianski 	for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
2531d06faef1SAndrei Otcheretianski 		struct ieee80211_bss_conf *conf;
2532d06faef1SAndrei Otcheretianski 
2533d06faef1SAndrei Otcheretianski 		conf = rcu_dereference(sdata->vif.link_conf[link_id]);
2534d06faef1SAndrei Otcheretianski 
2535d06faef1SAndrei Otcheretianski 		if (!conf)
2536d06faef1SAndrei Otcheretianski 			continue;
2537d06faef1SAndrei Otcheretianski 		if (ether_addr_equal(conf->addr, addr)) {
2538d06faef1SAndrei Otcheretianski 			if (out_link_id)
2539d06faef1SAndrei Otcheretianski 				*out_link_id = link_id;
2540d06faef1SAndrei Otcheretianski 			return true;
2541d06faef1SAndrei Otcheretianski 		}
2542d06faef1SAndrei Otcheretianski 	}
2543d06faef1SAndrei Otcheretianski 
2544d06faef1SAndrei Otcheretianski 	return false;
2545d06faef1SAndrei Otcheretianski }
2546d06faef1SAndrei Otcheretianski 
2547ce3edf6dSJohannes Berg /*
2548ce3edf6dSJohannes Berg  * requires that rx->skb is a frame with ethernet header
2549ce3edf6dSJohannes Berg  */
ieee80211_frame_allowed(struct ieee80211_rx_data * rx,__le16 fc)2550358c8d9dSHarvey Harrison static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
2551ce3edf6dSJohannes Berg {
2552c97c23e3SSenthil Balasubramanian 	static const u8 pae_group_addr[ETH_ALEN] __aligned(2)
2553ce3edf6dSJohannes Berg 		= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
2554ce3edf6dSJohannes Berg 	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
2555ce3edf6dSJohannes Berg 
2556ce3edf6dSJohannes Berg 	/*
2557a8c4d76aSJohannes Berg 	 * Allow EAPOL frames to us/the PAE group address regardless of
2558a8c4d76aSJohannes Berg 	 * whether the frame was encrypted or not, and always disallow
2559a8c4d76aSJohannes Berg 	 * all other destination addresses for them.
2560ce3edf6dSJohannes Berg 	 */
2561a8c4d76aSJohannes Berg 	if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
2562d06faef1SAndrei Otcheretianski 		return ieee80211_is_our_addr(rx->sdata, ehdr->h_dest, NULL) ||
2563a8c4d76aSJohannes Berg 		       ether_addr_equal(ehdr->h_dest, pae_group_addr);
2564ce3edf6dSJohannes Berg 
2565ce3edf6dSJohannes Berg 	if (ieee80211_802_1x_port_control(rx) ||
2566358c8d9dSHarvey Harrison 	    ieee80211_drop_unencrypted(rx, fc))
2567ce3edf6dSJohannes Berg 		return false;
2568ce3edf6dSJohannes Berg 
2569ce3edf6dSJohannes Berg 	return true;
2570ce3edf6dSJohannes Berg }
2571ce3edf6dSJohannes Berg 
ieee80211_deliver_skb_to_local_stack(struct sk_buff * skb,struct ieee80211_rx_data * rx)2572018f6fbfSDenis Kenzior static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
2573018f6fbfSDenis Kenzior 						 struct ieee80211_rx_data *rx)
2574018f6fbfSDenis Kenzior {
2575018f6fbfSDenis Kenzior 	struct ieee80211_sub_if_data *sdata = rx->sdata;
2576018f6fbfSDenis Kenzior 	struct net_device *dev = sdata->dev;
2577018f6fbfSDenis Kenzior 
2578018f6fbfSDenis Kenzior 	if (unlikely((skb->protocol == sdata->control_port_protocol ||
25797f3f96ceSMarkus Theil 		     (skb->protocol == cpu_to_be16(ETH_P_PREAUTH) &&
25807f3f96ceSMarkus Theil 		      !sdata->control_port_no_preauth)) &&
2581018f6fbfSDenis Kenzior 		     sdata->control_port_over_nl80211)) {
2582018f6fbfSDenis Kenzior 		struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2583f8b43c5cSDenis Kenzior 		bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED);
2584018f6fbfSDenis Kenzior 
25854c532321SJohannes Berg 		cfg80211_rx_control_port(dev, skb, noencrypt, rx->link_id);
2586018f6fbfSDenis Kenzior 		dev_kfree_skb(skb);
2587018f6fbfSDenis Kenzior 	} else {
2588a8c4d76aSJohannes Berg 		struct ethhdr *ehdr = (void *)skb_mac_header(skb);
2589a8c4d76aSJohannes Berg 
2590c8a41c6aSDenis Kenzior 		memset(skb->cb, 0, sizeof(skb->cb));
2591c8a41c6aSDenis Kenzior 
2592a8c4d76aSJohannes Berg 		/*
2593a8c4d76aSJohannes Berg 		 * 802.1X over 802.11 requires that the authenticator address
2594a8c4d76aSJohannes Berg 		 * be used for EAPOL frames. However, 802.1X allows the use of
2595a8c4d76aSJohannes Berg 		 * the PAE group address instead. If the interface is part of
2596a8c4d76aSJohannes Berg 		 * a bridge and we pass the frame with the PAE group address,
2597a8c4d76aSJohannes Berg 		 * then the bridge will forward it to the network (even if the
2598a8c4d76aSJohannes Berg 		 * client was not associated yet), which isn't supposed to
2599a8c4d76aSJohannes Berg 		 * happen.
2600a8c4d76aSJohannes Berg 		 * To avoid that, rewrite the destination address to our own
2601a8c4d76aSJohannes Berg 		 * address, so that the authenticator (e.g. hostapd) will see
2602a8c4d76aSJohannes Berg 		 * the frame, but bridge won't forward it anywhere else. Note
2603a8c4d76aSJohannes Berg 		 * that due to earlier filtering, the only other address can
2604610d086dSDeren Wu 		 * be the PAE group address, unless the hardware allowed them
2605610d086dSDeren Wu 		 * through in 802.3 offloaded mode.
2606a8c4d76aSJohannes Berg 		 */
2607a8c4d76aSJohannes Berg 		if (unlikely(skb->protocol == sdata->control_port_protocol &&
2608a8c4d76aSJohannes Berg 			     !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
2609a8c4d76aSJohannes Berg 			ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
2610a8c4d76aSJohannes Berg 
2611018f6fbfSDenis Kenzior 		/* deliver to local stack */
2612c5d1686bSFelix Fietkau 		if (rx->list)
2613c5d1686bSFelix Fietkau 			list_add_tail(&skb->list, rx->list);
2614018f6fbfSDenis Kenzior 		else
2615018f6fbfSDenis Kenzior 			netif_receive_skb(skb);
2616018f6fbfSDenis Kenzior 	}
2617018f6fbfSDenis Kenzior }
2618018f6fbfSDenis Kenzior 
2619ce3edf6dSJohannes Berg /*
2620ce3edf6dSJohannes Berg  * requires that rx->skb is a frame with ethernet header
2621ce3edf6dSJohannes Berg  */
262276ee65bfSRon Rindjunsky static void
ieee80211_deliver_skb(struct ieee80211_rx_data * rx)26235cf121c3SJohannes Berg ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
262476ee65bfSRon Rindjunsky {
2625eb9fb5b8SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
2626eb9fb5b8SJohannes Berg 	struct net_device *dev = sdata->dev;
262776ee65bfSRon Rindjunsky 	struct sk_buff *skb, *xmit_skb;
2628ce3edf6dSJohannes Berg 	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
2629ce3edf6dSJohannes Berg 	struct sta_info *dsta;
2630571ecf67SJohannes Berg 
263176ee65bfSRon Rindjunsky 	skb = rx->skb;
263276ee65bfSRon Rindjunsky 	xmit_skb = NULL;
2633571ecf67SJohannes Berg 
263436ec144fSLev Stipakov 	dev_sw_netstats_rx_add(dev, skb->len);
26355a490510SJohannes Berg 
2636de8f18d3SJohannes Berg 	if (rx->sta) {
2637de8f18d3SJohannes Berg 		/* The seqno index has the same property as needed
2638de8f18d3SJohannes Berg 		 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
2639de8f18d3SJohannes Berg 		 * for non-QoS-data frames. Here we know it's a data
2640de8f18d3SJohannes Berg 		 * frame, so count MSDUs.
2641de8f18d3SJohannes Berg 		 */
2642b320d6c4SBenjamin Berg 		u64_stats_update_begin(&rx->link_sta->rx_stats.syncp);
2643b320d6c4SBenjamin Berg 		rx->link_sta->rx_stats.msdu[rx->seqno_idx]++;
2644b320d6c4SBenjamin Berg 		u64_stats_update_end(&rx->link_sta->rx_stats.syncp);
2645de8f18d3SJohannes Berg 	}
2646de8f18d3SJohannes Berg 
264705c914feSJohannes Berg 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
264805c914feSJohannes Berg 	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
2649213cd118SJohannes Berg 	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
2650a8c4d76aSJohannes Berg 	    ehdr->h_proto != rx->sdata->control_port_protocol &&
26519bc383deSJohannes Berg 	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
265272f15d53SMichael Braun 		if (is_multicast_ether_addr(ehdr->h_dest) &&
265372f15d53SMichael Braun 		    ieee80211_vif_get_num_mcast_if(sdata) != 0) {
2654ce3edf6dSJohannes Berg 			/*
2655ce3edf6dSJohannes Berg 			 * send multicast frames both to higher layers in
2656ce3edf6dSJohannes Berg 			 * local net stack and back to the wireless medium
2657ce3edf6dSJohannes Berg 			 */
265876ee65bfSRon Rindjunsky 			xmit_skb = skb_copy(skb, GFP_ATOMIC);
2659e87cc472SJoe Perches 			if (!xmit_skb)
2660bdcbd8e0SJohannes Berg 				net_info_ratelimited("%s: failed to clone multicast frame\n",
2661e87cc472SJoe Perches 						    dev->name);
266242dca5efSJohannes Berg 		} else if (!is_multicast_ether_addr(ehdr->h_dest) &&
266342dca5efSJohannes Berg 			   !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) {
266442dca5efSJohannes Berg 			dsta = sta_info_get(sdata, ehdr->h_dest);
2665abe60632SJohannes Berg 			if (dsta) {
2666ce3edf6dSJohannes Berg 				/*
2667ce3edf6dSJohannes Berg 				 * The destination station is associated to
2668ce3edf6dSJohannes Berg 				 * this AP (in this VLAN), so send the frame
2669ce3edf6dSJohannes Berg 				 * directly to it and do not pass it to local
2670ce3edf6dSJohannes Berg 				 * net stack.
2671571ecf67SJohannes Berg 				 */
267276ee65bfSRon Rindjunsky 				xmit_skb = skb;
2673571ecf67SJohannes Berg 				skb = NULL;
2674571ecf67SJohannes Berg 			}
2675571ecf67SJohannes Berg 		}
2676571ecf67SJohannes Berg 	}
2677571ecf67SJohannes Berg 
267859d9cb07SKalle Valo #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
26799e890a1fSJohannes Berg 	if (skb) {
26809e890a1fSJohannes Berg 		/* 'align' will only take the values 0 or 2 here since all
26819e890a1fSJohannes Berg 		 * frames are required to be aligned to 2-byte boundaries
26829e890a1fSJohannes Berg 		 * when being passed to mac80211; the code here works just
26839e890a1fSJohannes Berg 		 * as well if that isn't true, but mac80211 assumes it can
26849e890a1fSJohannes Berg 		 * access fields as 2-byte aligned (e.g. for ether_addr_equal)
2685d1c3a37cSJohannes Berg 		 */
26869e890a1fSJohannes Berg 		int align;
26879e890a1fSJohannes Berg 
26889e890a1fSJohannes Berg 		align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3;
2689d1c3a37cSJohannes Berg 		if (align) {
2690d1c3a37cSJohannes Berg 			if (WARN_ON(skb_headroom(skb) < 3)) {
2691d1c3a37cSJohannes Berg 				dev_kfree_skb(skb);
2692d1c3a37cSJohannes Berg 				skb = NULL;
2693d1c3a37cSJohannes Berg 			} else {
2694d1c3a37cSJohannes Berg 				u8 *data = skb->data;
26958ce0b589SZhu Yi 				size_t len = skb_headlen(skb);
26968ce0b589SZhu Yi 				skb->data -= align;
26978ce0b589SZhu Yi 				memmove(skb->data, data, len);
26988ce0b589SZhu Yi 				skb_set_tail_pointer(skb, len);
2699d1c3a37cSJohannes Berg 			}
2700d1c3a37cSJohannes Berg 		}
27019e890a1fSJohannes Berg 	}
2702d1c3a37cSJohannes Berg #endif
2703d1c3a37cSJohannes Berg 
2704d1c3a37cSJohannes Berg 	if (skb) {
2705571ecf67SJohannes Berg 		skb->protocol = eth_type_trans(skb, dev);
2706018f6fbfSDenis Kenzior 		ieee80211_deliver_skb_to_local_stack(skb, rx);
2707571ecf67SJohannes Berg 	}
2708571ecf67SJohannes Berg 
270976ee65bfSRon Rindjunsky 	if (xmit_skb) {
2710aef6c928SHelmut Schaa 		/*
2711aef6c928SHelmut Schaa 		 * Send to wireless media and increase priority by 256 to
2712aef6c928SHelmut Schaa 		 * keep the received priority instead of reclassifying
2713aef6c928SHelmut Schaa 		 * the frame (see cfg80211_classify8021d).
2714aef6c928SHelmut Schaa 		 */
2715aef6c928SHelmut Schaa 		xmit_skb->priority += 256;
2716f831e909SYOSHIFUJI Hideaki 		xmit_skb->protocol = htons(ETH_P_802_3);
2717ce3edf6dSJohannes Berg 		skb_reset_network_header(xmit_skb);
2718ce3edf6dSJohannes Berg 		skb_reset_mac_header(xmit_skb);
271976ee65bfSRon Rindjunsky 		dev_queue_xmit(xmit_skb);
2720571ecf67SJohannes Berg 	}
272176ee65bfSRon Rindjunsky }
272276ee65bfSRon Rindjunsky 
27238b0f5cb6SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
27248b0f5cb6SFelix Fietkau static bool
ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int hdrlen)27258b0f5cb6SFelix Fietkau ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
27268b0f5cb6SFelix Fietkau 			       struct sk_buff *skb, int hdrlen)
27278b0f5cb6SFelix Fietkau {
27288b0f5cb6SFelix Fietkau 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2729154be74eSFelix Fietkau 	struct ieee80211_mesh_fast_tx_key key = {
2730154be74eSFelix Fietkau 		.type = MESH_FAST_TX_TYPE_FORWARDED
2731154be74eSFelix Fietkau 	};
2732154be74eSFelix Fietkau 	struct ieee80211_mesh_fast_tx *entry;
27338b0f5cb6SFelix Fietkau 	struct ieee80211s_hdr *mesh_hdr;
27348b0f5cb6SFelix Fietkau 	struct tid_ampdu_tx *tid_tx;
27358b0f5cb6SFelix Fietkau 	struct sta_info *sta;
27368b0f5cb6SFelix Fietkau 	struct ethhdr eth;
27378b0f5cb6SFelix Fietkau 	u8 tid;
27388b0f5cb6SFelix Fietkau 
27398b0f5cb6SFelix Fietkau 	mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
27408b0f5cb6SFelix Fietkau 	if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
2741154be74eSFelix Fietkau 		ether_addr_copy(key.addr, mesh_hdr->eaddr1);
27428b0f5cb6SFelix Fietkau 	else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
2743154be74eSFelix Fietkau 		ether_addr_copy(key.addr, skb->data);
2744154be74eSFelix Fietkau 	else
2745154be74eSFelix Fietkau 		return false;
2746154be74eSFelix Fietkau 
2747154be74eSFelix Fietkau 	entry = mesh_fast_tx_get(sdata, &key);
27488b0f5cb6SFelix Fietkau 	if (!entry)
27498b0f5cb6SFelix Fietkau 		return false;
27508b0f5cb6SFelix Fietkau 
27518b0f5cb6SFelix Fietkau 	sta = rcu_dereference(entry->mpath->next_hop);
27528b0f5cb6SFelix Fietkau 	if (!sta)
27538b0f5cb6SFelix Fietkau 		return false;
27548b0f5cb6SFelix Fietkau 
27558b0f5cb6SFelix Fietkau 	if (skb_linearize(skb))
27568b0f5cb6SFelix Fietkau 		return false;
27578b0f5cb6SFelix Fietkau 
27588b0f5cb6SFelix Fietkau 	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
27598b0f5cb6SFelix Fietkau 	tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
27608b0f5cb6SFelix Fietkau 	if (tid_tx) {
27618b0f5cb6SFelix Fietkau 		if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
27628b0f5cb6SFelix Fietkau 			return false;
27638b0f5cb6SFelix Fietkau 
27648b0f5cb6SFelix Fietkau 		if (tid_tx->timeout)
27658b0f5cb6SFelix Fietkau 			tid_tx->last_tx = jiffies;
27668b0f5cb6SFelix Fietkau 	}
27678b0f5cb6SFelix Fietkau 
27688b0f5cb6SFelix Fietkau 	ieee80211_aggr_check(sdata, sta, skb);
27698b0f5cb6SFelix Fietkau 
27708b0f5cb6SFelix Fietkau 	if (ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
27718b0f5cb6SFelix Fietkau 					    &skb->protocol))
27728b0f5cb6SFelix Fietkau 		hdrlen += ETH_ALEN;
27738b0f5cb6SFelix Fietkau 	else
27748b0f5cb6SFelix Fietkau 		skb->protocol = htons(skb->len - hdrlen);
27758b0f5cb6SFelix Fietkau 	skb_set_network_header(skb, hdrlen + 2);
27768b0f5cb6SFelix Fietkau 
27778b0f5cb6SFelix Fietkau 	skb->dev = sdata->dev;
27788b0f5cb6SFelix Fietkau 	memcpy(&eth, skb->data, ETH_HLEN - 2);
27798b0f5cb6SFelix Fietkau 	skb_pull(skb, 2);
27808b0f5cb6SFelix Fietkau 	__ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
27818b0f5cb6SFelix Fietkau 			      eth.h_dest, eth.h_source);
27828b0f5cb6SFelix Fietkau 	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
27838b0f5cb6SFelix Fietkau 	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
27848b0f5cb6SFelix Fietkau 
27858b0f5cb6SFelix Fietkau 	return true;
27868b0f5cb6SFelix Fietkau }
27878b0f5cb6SFelix Fietkau #endif
27888b0f5cb6SFelix Fietkau 
2789986e43b1SFelix Fietkau static ieee80211_rx_result
ieee80211_rx_mesh_data(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb)2790986e43b1SFelix Fietkau ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
2791986e43b1SFelix Fietkau 		       struct sk_buff *skb)
2792986e43b1SFelix Fietkau {
2793986e43b1SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
2794986e43b1SFelix Fietkau 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2795986e43b1SFelix Fietkau 	struct ieee80211_local *local = sdata->local;
2796986e43b1SFelix Fietkau 	uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
2797986e43b1SFelix Fietkau 	struct ieee80211_hdr hdr = {
2798986e43b1SFelix Fietkau 		.frame_control = cpu_to_le16(fc)
2799986e43b1SFelix Fietkau 	};
2800986e43b1SFelix Fietkau 	struct ieee80211_hdr *fwd_hdr;
2801986e43b1SFelix Fietkau 	struct ieee80211s_hdr *mesh_hdr;
2802986e43b1SFelix Fietkau 	struct ieee80211_tx_info *info;
2803986e43b1SFelix Fietkau 	struct sk_buff *fwd_skb;
2804986e43b1SFelix Fietkau 	struct ethhdr *eth;
2805986e43b1SFelix Fietkau 	bool multicast;
2806986e43b1SFelix Fietkau 	int tailroom = 0;
2807986e43b1SFelix Fietkau 	int hdrlen, mesh_hdrlen;
2808986e43b1SFelix Fietkau 	u8 *qos;
2809986e43b1SFelix Fietkau 
2810986e43b1SFelix Fietkau 	if (!ieee80211_vif_is_mesh(&sdata->vif))
2811986e43b1SFelix Fietkau 		return RX_CONTINUE;
2812986e43b1SFelix Fietkau 
2813986e43b1SFelix Fietkau 	if (!pskb_may_pull(skb, sizeof(*eth) + 6))
2814986e43b1SFelix Fietkau 		return RX_DROP_MONITOR;
2815986e43b1SFelix Fietkau 
2816986e43b1SFelix Fietkau 	mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
2817986e43b1SFelix Fietkau 	mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
2818986e43b1SFelix Fietkau 
2819986e43b1SFelix Fietkau 	if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
2820986e43b1SFelix Fietkau 		return RX_DROP_MONITOR;
2821986e43b1SFelix Fietkau 
2822986e43b1SFelix Fietkau 	eth = (struct ethhdr *)skb->data;
2823986e43b1SFelix Fietkau 	multicast = is_multicast_ether_addr(eth->h_dest);
2824986e43b1SFelix Fietkau 
2825986e43b1SFelix Fietkau 	mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
2826986e43b1SFelix Fietkau 	if (!mesh_hdr->ttl)
2827986e43b1SFelix Fietkau 		return RX_DROP_MONITOR;
2828986e43b1SFelix Fietkau 
2829986e43b1SFelix Fietkau 	/* frame is in RMC, don't forward */
2830986e43b1SFelix Fietkau 	if (is_multicast_ether_addr(eth->h_dest) &&
2831986e43b1SFelix Fietkau 	    mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
2832986e43b1SFelix Fietkau 		return RX_DROP_MONITOR;
2833986e43b1SFelix Fietkau 
2834986e43b1SFelix Fietkau 	/* forward packet */
2835986e43b1SFelix Fietkau 	if (sdata->crypto_tx_tailroom_needed_cnt)
2836986e43b1SFelix Fietkau 		tailroom = IEEE80211_ENCRYPT_TAILROOM;
2837986e43b1SFelix Fietkau 
2838986e43b1SFelix Fietkau 	if (mesh_hdr->flags & MESH_FLAGS_AE) {
2839986e43b1SFelix Fietkau 		struct mesh_path *mppath;
2840986e43b1SFelix Fietkau 		char *proxied_addr;
2841d5edb9aeSFelix Fietkau 		bool update = false;
2842986e43b1SFelix Fietkau 
2843986e43b1SFelix Fietkau 		if (multicast)
2844986e43b1SFelix Fietkau 			proxied_addr = mesh_hdr->eaddr1;
2845986e43b1SFelix Fietkau 		else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
2846986e43b1SFelix Fietkau 			/* has_a4 already checked in ieee80211_rx_mesh_check */
2847986e43b1SFelix Fietkau 			proxied_addr = mesh_hdr->eaddr2;
2848986e43b1SFelix Fietkau 		else
2849986e43b1SFelix Fietkau 			return RX_DROP_MONITOR;
2850986e43b1SFelix Fietkau 
2851986e43b1SFelix Fietkau 		rcu_read_lock();
2852986e43b1SFelix Fietkau 		mppath = mpp_path_lookup(sdata, proxied_addr);
2853986e43b1SFelix Fietkau 		if (!mppath) {
2854986e43b1SFelix Fietkau 			mpp_path_add(sdata, proxied_addr, eth->h_source);
2855986e43b1SFelix Fietkau 		} else {
2856986e43b1SFelix Fietkau 			spin_lock_bh(&mppath->state_lock);
2857d5edb9aeSFelix Fietkau 			if (!ether_addr_equal(mppath->mpp, eth->h_source)) {
2858986e43b1SFelix Fietkau 				memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
2859d5edb9aeSFelix Fietkau 				update = true;
2860d5edb9aeSFelix Fietkau 			}
2861986e43b1SFelix Fietkau 			mppath->exp_time = jiffies;
2862986e43b1SFelix Fietkau 			spin_unlock_bh(&mppath->state_lock);
2863986e43b1SFelix Fietkau 		}
2864d5edb9aeSFelix Fietkau 
2865d5edb9aeSFelix Fietkau 		/* flush fast xmit cache if the address path changed */
2866d5edb9aeSFelix Fietkau 		if (update)
2867d5edb9aeSFelix Fietkau 			mesh_fast_tx_flush_addr(sdata, proxied_addr);
2868d5edb9aeSFelix Fietkau 
2869986e43b1SFelix Fietkau 		rcu_read_unlock();
2870986e43b1SFelix Fietkau 	}
2871986e43b1SFelix Fietkau 
2872f355f701SFelix Fietkau 	/* Frame has reached destination.  Don't forward */
2873f355f701SFelix Fietkau 	if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
2874f355f701SFelix Fietkau 		goto rx_accept;
2875f355f701SFelix Fietkau 
2876e26c0946SFelix Fietkau 	if (!--mesh_hdr->ttl) {
2877e26c0946SFelix Fietkau 		if (multicast)
2878e26c0946SFelix Fietkau 			goto rx_accept;
2879e26c0946SFelix Fietkau 
2880e26c0946SFelix Fietkau 		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
2881e26c0946SFelix Fietkau 		return RX_DROP_MONITOR;
2882e26c0946SFelix Fietkau 	}
2883e26c0946SFelix Fietkau 
2884f355f701SFelix Fietkau 	if (!ifmsh->mshcfg.dot11MeshForwarding) {
2885f355f701SFelix Fietkau 		if (is_multicast_ether_addr(eth->h_dest))
2886f355f701SFelix Fietkau 			goto rx_accept;
2887f355f701SFelix Fietkau 
2888f355f701SFelix Fietkau 		return RX_DROP_MONITOR;
2889f355f701SFelix Fietkau 	}
2890f355f701SFelix Fietkau 
2891986e43b1SFelix Fietkau 	skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
2892986e43b1SFelix Fietkau 
28938b0f5cb6SFelix Fietkau 	if (!multicast &&
28948b0f5cb6SFelix Fietkau 	    ieee80211_rx_mesh_fast_forward(sdata, skb, mesh_hdrlen))
28958b0f5cb6SFelix Fietkau 		return RX_QUEUED;
28968b0f5cb6SFelix Fietkau 
2897986e43b1SFelix Fietkau 	ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
2898986e43b1SFelix Fietkau 				      eth->h_dest, eth->h_source);
2899986e43b1SFelix Fietkau 	hdrlen = ieee80211_hdrlen(hdr.frame_control);
2900986e43b1SFelix Fietkau 	if (multicast) {
2901986e43b1SFelix Fietkau 		int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
2902986e43b1SFelix Fietkau 
2903986e43b1SFelix Fietkau 		fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
2904986e43b1SFelix Fietkau 					       IEEE80211_ENCRYPT_HEADROOM,
2905986e43b1SFelix Fietkau 					  tailroom, GFP_ATOMIC);
2906986e43b1SFelix Fietkau 		if (!fwd_skb)
2907986e43b1SFelix Fietkau 			goto rx_accept;
2908986e43b1SFelix Fietkau 	} else {
2909986e43b1SFelix Fietkau 		fwd_skb = skb;
2910986e43b1SFelix Fietkau 		skb = NULL;
2911986e43b1SFelix Fietkau 
2912986e43b1SFelix Fietkau 		if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
2913986e43b1SFelix Fietkau 			return RX_DROP_UNUSABLE;
29148f0149a8SFelix Fietkau 
29158f0149a8SFelix Fietkau 		if (skb_linearize(fwd_skb))
29168f0149a8SFelix Fietkau 			return RX_DROP_UNUSABLE;
2917986e43b1SFelix Fietkau 	}
2918986e43b1SFelix Fietkau 
2919986e43b1SFelix Fietkau 	fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
2920986e43b1SFelix Fietkau 	memcpy(fwd_hdr, &hdr, hdrlen - 2);
2921986e43b1SFelix Fietkau 	qos = ieee80211_get_qos_ctl(fwd_hdr);
2922986e43b1SFelix Fietkau 	qos[0] = qos[1] = 0;
2923986e43b1SFelix Fietkau 
2924986e43b1SFelix Fietkau 	skb_reset_mac_header(fwd_skb);
2925986e43b1SFelix Fietkau 	hdrlen += mesh_hdrlen;
2926986e43b1SFelix Fietkau 	if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
2927986e43b1SFelix Fietkau 					    &fwd_skb->protocol))
2928986e43b1SFelix Fietkau 		hdrlen += ETH_ALEN;
2929986e43b1SFelix Fietkau 	else
2930986e43b1SFelix Fietkau 		fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
2931899c2c11SFelix Fietkau 	skb_set_network_header(fwd_skb, hdrlen + 2);
2932986e43b1SFelix Fietkau 
2933986e43b1SFelix Fietkau 	info = IEEE80211_SKB_CB(fwd_skb);
2934986e43b1SFelix Fietkau 	memset(info, 0, sizeof(*info));
2935986e43b1SFelix Fietkau 	info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
2936986e43b1SFelix Fietkau 	info->control.vif = &sdata->vif;
2937986e43b1SFelix Fietkau 	info->control.jiffies = jiffies;
29388b0f5cb6SFelix Fietkau 	fwd_skb->dev = sdata->dev;
2939986e43b1SFelix Fietkau 	if (multicast) {
2940986e43b1SFelix Fietkau 		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
2941986e43b1SFelix Fietkau 		memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
2942986e43b1SFelix Fietkau 		/* update power mode indication when forwarding */
2943986e43b1SFelix Fietkau 		ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
2944986e43b1SFelix Fietkau 	} else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
2945986e43b1SFelix Fietkau 		/* mesh power mode flags updated in mesh_nexthop_lookup */
2946986e43b1SFelix Fietkau 		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
2947986e43b1SFelix Fietkau 	} else {
2948986e43b1SFelix Fietkau 		/* unable to resolve next hop */
2949986e43b1SFelix Fietkau 		if (sta)
2950986e43b1SFelix Fietkau 			mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
2951986e43b1SFelix Fietkau 					   hdr.addr3, 0,
2952986e43b1SFelix Fietkau 					   WLAN_REASON_MESH_PATH_NOFORWARD,
2953986e43b1SFelix Fietkau 					   sta->sta.addr);
2954986e43b1SFelix Fietkau 		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
2955986e43b1SFelix Fietkau 		kfree_skb(fwd_skb);
2956986e43b1SFelix Fietkau 		goto rx_accept;
2957986e43b1SFelix Fietkau 	}
2958986e43b1SFelix Fietkau 
2959986e43b1SFelix Fietkau 	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
2960*69226421SAndy Strohman 	ieee80211_set_qos_hdr(sdata, fwd_skb);
2961986e43b1SFelix Fietkau 	ieee80211_add_pending_skb(local, fwd_skb);
2962986e43b1SFelix Fietkau 
2963986e43b1SFelix Fietkau rx_accept:
2964986e43b1SFelix Fietkau 	if (!skb)
2965986e43b1SFelix Fietkau 		return RX_QUEUED;
2966986e43b1SFelix Fietkau 
2967986e43b1SFelix Fietkau 	ieee80211_strip_8023_mesh_hdr(skb);
2968986e43b1SFelix Fietkau #endif
2969986e43b1SFelix Fietkau 
2970986e43b1SFelix Fietkau 	return RX_CONTINUE;
2971986e43b1SFelix Fietkau }
2972986e43b1SFelix Fietkau 
297349461622SJohannes Berg static ieee80211_rx_result debug_noinline
__ieee80211_rx_h_amsdu(struct ieee80211_rx_data * rx,u8 data_offset)297424bba078SFelix Fietkau __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
2975fd4c7f2fSRon Rindjunsky {
2976eb9fb5b8SJohannes Berg 	struct net_device *dev = rx->sdata->dev;
2977eaf85ca7SZhu Yi 	struct sk_buff *skb = rx->skb;
2978358c8d9dSHarvey Harrison 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
2979358c8d9dSHarvey Harrison 	__le16 fc = hdr->frame_control;
2980eaf85ca7SZhu Yi 	struct sk_buff_head frame_list;
29814d78e032SFelix Fietkau 	ieee80211_rx_result res;
29827f6990c8SJohannes Berg 	struct ethhdr ethhdr;
2983e2b5227fSJohannes Berg 	const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
2984fd4c7f2fSRon Rindjunsky 
2985ea720935SJohannes Berg 	if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
2986e2b5227fSJohannes Berg 		check_da = NULL;
2987e2b5227fSJohannes Berg 		check_sa = NULL;
2988e2b5227fSJohannes Berg 	} else switch (rx->sdata->vif.type) {
2989e2b5227fSJohannes Berg 		case NL80211_IFTYPE_AP:
2990e2b5227fSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
2991e2b5227fSJohannes Berg 			check_da = NULL;
2992e2b5227fSJohannes Berg 			break;
2993e2b5227fSJohannes Berg 		case NL80211_IFTYPE_STATION:
2994e2b5227fSJohannes Berg 			if (!rx->sta ||
2995e2b5227fSJohannes Berg 			    !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
2996e2b5227fSJohannes Berg 				check_sa = NULL;
2997e2b5227fSJohannes Berg 			break;
2998e2b5227fSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
2999e2b5227fSJohannes Berg 			check_sa = NULL;
3000986e43b1SFelix Fietkau 			check_da = NULL;
3001e2b5227fSJohannes Berg 			break;
3002e2b5227fSJohannes Berg 		default:
3003e2b5227fSJohannes Berg 			break;
3004ea720935SJohannes Berg 	}
3005eaf85ca7SZhu Yi 
3006fd4c7f2fSRon Rindjunsky 	skb->dev = dev;
3007eaf85ca7SZhu Yi 	__skb_queue_head_init(&frame_list);
3008fd4c7f2fSRon Rindjunsky 
30097f6990c8SJohannes Berg 	if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
30107f6990c8SJohannes Berg 					  rx->sdata->vif.addr,
301124bba078SFelix Fietkau 					  rx->sdata->vif.type,
3012a1d5ff56SMathy Vanhoef 					  data_offset, true))
30137f6990c8SJohannes Berg 		return RX_DROP_UNUSABLE;
30147f6990c8SJohannes Berg 
3015a16fc383SFelix Fietkau 	if (rx->sta->amsdu_mesh_control < 0) {
3016fe4a6d2dSFelix Fietkau 		s8 valid = -1;
3017fe4a6d2dSFelix Fietkau 		int i;
30186e4c0d04SFelix Fietkau 
3019fe4a6d2dSFelix Fietkau 		for (i = 0; i <= 2; i++) {
3020fe4a6d2dSFelix Fietkau 			if (!ieee80211_is_valid_amsdu(skb, i))
3021fe4a6d2dSFelix Fietkau 				continue;
3022fe4a6d2dSFelix Fietkau 
3023fe4a6d2dSFelix Fietkau 			if (valid >= 0) {
3024fe4a6d2dSFelix Fietkau 				/* ambiguous */
3025fe4a6d2dSFelix Fietkau 				valid = -1;
3026fe4a6d2dSFelix Fietkau 				break;
3027fe4a6d2dSFelix Fietkau 			}
3028fe4a6d2dSFelix Fietkau 
3029fe4a6d2dSFelix Fietkau 			valid = i;
3030fe4a6d2dSFelix Fietkau 		}
3031fe4a6d2dSFelix Fietkau 
3032fe4a6d2dSFelix Fietkau 		rx->sta->amsdu_mesh_control = valid;
30336e4c0d04SFelix Fietkau 	}
30346e4c0d04SFelix Fietkau 
3035eaf85ca7SZhu Yi 	ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
3036eaf85ca7SZhu Yi 				 rx->sdata->vif.type,
30378b935ee2SJohannes Berg 				 rx->local->hw.extra_tx_headroom,
30386e4c0d04SFelix Fietkau 				 check_da, check_sa,
30396e4c0d04SFelix Fietkau 				 rx->sta->amsdu_mesh_control);
3040fd4c7f2fSRon Rindjunsky 
3041eaf85ca7SZhu Yi 	while (!skb_queue_empty(&frame_list)) {
3042eaf85ca7SZhu Yi 		rx->skb = __skb_dequeue(&frame_list);
3043fd4c7f2fSRon Rindjunsky 
3044986e43b1SFelix Fietkau 		res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
3045986e43b1SFelix Fietkau 		switch (res) {
3046986e43b1SFelix Fietkau 		case RX_QUEUED:
3047ce3edf6dSJohannes Berg 			continue;
3048986e43b1SFelix Fietkau 		case RX_CONTINUE:
3049986e43b1SFelix Fietkau 			break;
3050986e43b1SFelix Fietkau 		default:
3051986e43b1SFelix Fietkau 			goto free;
3052ce3edf6dSJohannes Berg 		}
3053fd4c7f2fSRon Rindjunsky 
3054986e43b1SFelix Fietkau 		if (!ieee80211_frame_allowed(rx, fc))
3055986e43b1SFelix Fietkau 			goto free;
3056986e43b1SFelix Fietkau 
3057fd4c7f2fSRon Rindjunsky 		ieee80211_deliver_skb(rx);
3058986e43b1SFelix Fietkau 		continue;
3059986e43b1SFelix Fietkau 
3060986e43b1SFelix Fietkau free:
3061986e43b1SFelix Fietkau 		dev_kfree_skb(rx->skb);
3062fd4c7f2fSRon Rindjunsky 	}
3063fd4c7f2fSRon Rindjunsky 
30649ae54c84SJohannes Berg 	return RX_QUEUED;
3065fd4c7f2fSRon Rindjunsky }
3066fd4c7f2fSRon Rindjunsky 
306724bba078SFelix Fietkau static ieee80211_rx_result debug_noinline
ieee80211_rx_h_amsdu(struct ieee80211_rx_data * rx)306824bba078SFelix Fietkau ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
306924bba078SFelix Fietkau {
307024bba078SFelix Fietkau 	struct sk_buff *skb = rx->skb;
307124bba078SFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
307224bba078SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
307324bba078SFelix Fietkau 	__le16 fc = hdr->frame_control;
307424bba078SFelix Fietkau 
307524bba078SFelix Fietkau 	if (!(status->rx_flags & IEEE80211_RX_AMSDU))
307624bba078SFelix Fietkau 		return RX_CONTINUE;
307724bba078SFelix Fietkau 
307824bba078SFelix Fietkau 	if (unlikely(!ieee80211_is_data(fc)))
307924bba078SFelix Fietkau 		return RX_CONTINUE;
308024bba078SFelix Fietkau 
308124bba078SFelix Fietkau 	if (unlikely(!ieee80211_is_data_present(fc)))
308224bba078SFelix Fietkau 		return RX_DROP_MONITOR;
308324bba078SFelix Fietkau 
308424bba078SFelix Fietkau 	if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
308524bba078SFelix Fietkau 		switch (rx->sdata->vif.type) {
308624bba078SFelix Fietkau 		case NL80211_IFTYPE_AP_VLAN:
308724bba078SFelix Fietkau 			if (!rx->sdata->u.vlan.sta)
308824bba078SFelix Fietkau 				return RX_DROP_UNUSABLE;
308924bba078SFelix Fietkau 			break;
309024bba078SFelix Fietkau 		case NL80211_IFTYPE_STATION:
309124bba078SFelix Fietkau 			if (!rx->sdata->u.mgd.use_4addr)
309224bba078SFelix Fietkau 				return RX_DROP_UNUSABLE;
309324bba078SFelix Fietkau 			break;
3094986e43b1SFelix Fietkau 		case NL80211_IFTYPE_MESH_POINT:
3095986e43b1SFelix Fietkau 			break;
309624bba078SFelix Fietkau 		default:
309724bba078SFelix Fietkau 			return RX_DROP_UNUSABLE;
309824bba078SFelix Fietkau 		}
309924bba078SFelix Fietkau 	}
310024bba078SFelix Fietkau 
3101a16fc383SFelix Fietkau 	if (is_multicast_ether_addr(hdr->addr1) || !rx->sta)
310224bba078SFelix Fietkau 		return RX_DROP_UNUSABLE;
310324bba078SFelix Fietkau 
3104270032a2SJohannes Berg 	if (rx->key) {
3105270032a2SJohannes Berg 		/*
3106270032a2SJohannes Berg 		 * We should not receive A-MSDUs on pre-HT connections,
3107270032a2SJohannes Berg 		 * and HT connections cannot use old ciphers. Thus drop
3108270032a2SJohannes Berg 		 * them, as in those cases we couldn't even have SPP
3109270032a2SJohannes Berg 		 * A-MSDUs or such.
3110270032a2SJohannes Berg 		 */
3111270032a2SJohannes Berg 		switch (rx->key->conf.cipher) {
3112270032a2SJohannes Berg 		case WLAN_CIPHER_SUITE_WEP40:
3113270032a2SJohannes Berg 		case WLAN_CIPHER_SUITE_WEP104:
3114270032a2SJohannes Berg 		case WLAN_CIPHER_SUITE_TKIP:
3115270032a2SJohannes Berg 			return RX_DROP_UNUSABLE;
3116270032a2SJohannes Berg 		default:
3117270032a2SJohannes Berg 			break;
3118270032a2SJohannes Berg 		}
3119270032a2SJohannes Berg 	}
3120270032a2SJohannes Berg 
312124bba078SFelix Fietkau 	return __ieee80211_rx_h_amsdu(rx, 0);
312224bba078SFelix Fietkau }
312324bba078SFelix Fietkau 
3124e32f85f7SLuis Carlos Cobo static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data * rx)31255cf121c3SJohannes Berg ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
312676ee65bfSRon Rindjunsky {
3127eb9fb5b8SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
3128e15276a4SVivek Natarajan 	struct ieee80211_local *local = rx->local;
3129eb9fb5b8SJohannes Berg 	struct net_device *dev = sdata->dev;
3130358c8d9dSHarvey Harrison 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
3131358c8d9dSHarvey Harrison 	__le16 fc = hdr->frame_control;
31324d78e032SFelix Fietkau 	ieee80211_rx_result res;
31334114fa21SFelix Fietkau 	bool port_control;
3134ce3edf6dSJohannes Berg 	int err;
313576ee65bfSRon Rindjunsky 
3136358c8d9dSHarvey Harrison 	if (unlikely(!ieee80211_is_data(hdr->frame_control)))
31379ae54c84SJohannes Berg 		return RX_CONTINUE;
313876ee65bfSRon Rindjunsky 
3139358c8d9dSHarvey Harrison 	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
3140e4c26addSJohannes Berg 		return RX_DROP_MONITOR;
314176ee65bfSRon Rindjunsky 
3142f14543eeSFelix Fietkau 	/*
3143e7f4a940SJohannes Berg 	 * Send unexpected-4addr-frame event to hostapd. For older versions,
3144e7f4a940SJohannes Berg 	 * also drop the frame to cooked monitor interfaces.
3145f14543eeSFelix Fietkau 	 */
3146f14543eeSFelix Fietkau 	if (ieee80211_has_a4(hdr->frame_control) &&
3147e7f4a940SJohannes Berg 	    sdata->vif.type == NL80211_IFTYPE_AP) {
3148e7f4a940SJohannes Berg 		if (rx->sta &&
3149e7f4a940SJohannes Berg 		    !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
3150e7f4a940SJohannes Berg 			cfg80211_rx_unexpected_4addr_frame(
3151e7f4a940SJohannes Berg 				rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
3152f14543eeSFelix Fietkau 		return RX_DROP_MONITOR;
3153e7f4a940SJohannes Berg 	}
3154f14543eeSFelix Fietkau 
31554114fa21SFelix Fietkau 	err = __ieee80211_data_to_8023(rx, &port_control);
315676ee65bfSRon Rindjunsky 	if (unlikely(err))
3157e4c26addSJohannes Berg 		return RX_DROP_UNUSABLE;
315876ee65bfSRon Rindjunsky 
3159986e43b1SFelix Fietkau 	res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
3160986e43b1SFelix Fietkau 	if (res != RX_CONTINUE)
3161986e43b1SFelix Fietkau 		return res;
3162986e43b1SFelix Fietkau 
3163358c8d9dSHarvey Harrison 	if (!ieee80211_frame_allowed(rx, fc))
3164e4c26addSJohannes Berg 		return RX_DROP_MONITOR;
3165ce3edf6dSJohannes Berg 
31668a4d32f3SArik Nemtsov 	/* directly handle TDLS channel switch requests/responses */
31678a4d32f3SArik Nemtsov 	if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto ==
31688a4d32f3SArik Nemtsov 						cpu_to_be16(ETH_P_TDLS))) {
31698a4d32f3SArik Nemtsov 		struct ieee80211_tdls_data *tf = (void *)rx->skb->data;
31708a4d32f3SArik Nemtsov 
31718a4d32f3SArik Nemtsov 		if (pskb_may_pull(rx->skb,
31728a4d32f3SArik Nemtsov 				  offsetof(struct ieee80211_tdls_data, u)) &&
31738a4d32f3SArik Nemtsov 		    tf->payload_type == WLAN_TDLS_SNAP_RFTYPE &&
31748a4d32f3SArik Nemtsov 		    tf->category == WLAN_CATEGORY_TDLS &&
31758a4d32f3SArik Nemtsov 		    (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
31768a4d32f3SArik Nemtsov 		     tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
3177f057d140SJohannes Berg 			rx->skb->protocol = cpu_to_be16(ETH_P_TDLS);
31784f6c78deSJohannes Berg 			__ieee80211_queue_skb_to_iface(sdata, rx->link_id,
31794f6c78deSJohannes Berg 						       rx->sta, rx->skb);
31808a4d32f3SArik Nemtsov 			return RX_QUEUED;
31818a4d32f3SArik Nemtsov 		}
31828a4d32f3SArik Nemtsov 	}
31838a4d32f3SArik Nemtsov 
31844114fa21SFelix Fietkau 	if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
31854114fa21SFelix Fietkau 	    unlikely(port_control) && sdata->bss) {
31864114fa21SFelix Fietkau 		sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
31874114fa21SFelix Fietkau 				     u.ap);
31884114fa21SFelix Fietkau 		dev = sdata->dev;
31894114fa21SFelix Fietkau 		rx->sdata = sdata;
31904114fa21SFelix Fietkau 	}
31914114fa21SFelix Fietkau 
319276ee65bfSRon Rindjunsky 	rx->skb->dev = dev;
319376ee65bfSRon Rindjunsky 
3194602fae42SJohannes Berg 	if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
3195602fae42SJohannes Berg 	    local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
31968c99f691SRajkumar Manoharan 	    !is_multicast_ether_addr(
31978c99f691SRajkumar Manoharan 		    ((struct ethhdr *)rx->skb->data)->h_dest) &&
31988c99f691SRajkumar Manoharan 	    (!local->scanning &&
3199602fae42SJohannes Berg 	     !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)))
3200e15276a4SVivek Natarajan 		mod_timer(&local->dynamic_ps_timer, jiffies +
3201e15276a4SVivek Natarajan 			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
3202e15276a4SVivek Natarajan 
320376ee65bfSRon Rindjunsky 	ieee80211_deliver_skb(rx);
3204571ecf67SJohannes Berg 
32059ae54c84SJohannes Berg 	return RX_QUEUED;
3206571ecf67SJohannes Berg }
3207571ecf67SJohannes Berg 
320849461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ctrl(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)3209f9e124fbSChristian Lamparter ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
321071364716SRon Rindjunsky {
321171364716SRon Rindjunsky 	struct sk_buff *skb = rx->skb;
321271364716SRon Rindjunsky 	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
321371364716SRon Rindjunsky 	struct tid_ampdu_rx *tid_agg_rx;
321471364716SRon Rindjunsky 	u16 start_seq_num;
321571364716SRon Rindjunsky 	u16 tid;
321671364716SRon Rindjunsky 
3217a7767f95SHarvey Harrison 	if (likely(!ieee80211_is_ctl(bar->frame_control)))
32189ae54c84SJohannes Berg 		return RX_CONTINUE;
321971364716SRon Rindjunsky 
3220a7767f95SHarvey Harrison 	if (ieee80211_is_back_req(bar->frame_control)) {
32218ae5977fSJohannes Berg 		struct {
32228ae5977fSJohannes Berg 			__le16 control, start_seq_num;
32238ae5977fSJohannes Berg 		} __packed bar_data;
32246382246eSEmmanuel Grumbach 		struct ieee80211_event event = {
32256382246eSEmmanuel Grumbach 			.type = BAR_RX_EVENT,
32266382246eSEmmanuel Grumbach 		};
32278ae5977fSJohannes Berg 
322871364716SRon Rindjunsky 		if (!rx->sta)
3229a02ae758SJohannes Berg 			return RX_DROP_MONITOR;
32308ae5977fSJohannes Berg 
32318ae5977fSJohannes Berg 		if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control),
32328ae5977fSJohannes Berg 				  &bar_data, sizeof(bar_data)))
32338ae5977fSJohannes Berg 			return RX_DROP_MONITOR;
32348ae5977fSJohannes Berg 
32358ae5977fSJohannes Berg 		tid = le16_to_cpu(bar_data.control) >> 12;
3236a87f736dSJohannes Berg 
323753f24974SJohannes Berg 		if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
323853f24974SJohannes Berg 		    !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
323953f24974SJohannes Berg 			ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
324053f24974SJohannes Berg 					     WLAN_BACK_RECIPIENT,
324153f24974SJohannes Berg 					     WLAN_REASON_QSTA_REQUIRE_SETUP);
324253f24974SJohannes Berg 
3243a87f736dSJohannes Berg 		tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
3244a87f736dSJohannes Berg 		if (!tid_agg_rx)
3245a02ae758SJohannes Berg 			return RX_DROP_MONITOR;
324671364716SRon Rindjunsky 
32478ae5977fSJohannes Berg 		start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
32486382246eSEmmanuel Grumbach 		event.u.ba.tid = tid;
32496382246eSEmmanuel Grumbach 		event.u.ba.ssn = start_seq_num;
32506382246eSEmmanuel Grumbach 		event.u.ba.sta = &rx->sta->sta;
325171364716SRon Rindjunsky 
325271364716SRon Rindjunsky 		/* reset session timer */
325320ad19d0SJohannes Berg 		if (tid_agg_rx->timeout)
325420ad19d0SJohannes Berg 			mod_timer(&tid_agg_rx->session_timer,
325520ad19d0SJohannes Berg 				  TU_TO_EXP_TIME(tid_agg_rx->timeout));
325671364716SRon Rindjunsky 
3257dd318575SJohannes Berg 		spin_lock(&tid_agg_rx->reorder_lock);
3258a02ae758SJohannes Berg 		/* release stored frames up to start of BAR */
3259d3b2fb53SJohannes Berg 		ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
3260f9e124fbSChristian Lamparter 						 start_seq_num, frames);
3261dd318575SJohannes Berg 		spin_unlock(&tid_agg_rx->reorder_lock);
3262dd318575SJohannes Berg 
32636382246eSEmmanuel Grumbach 		drv_event_callback(rx->local, rx->sdata, &event);
32646382246eSEmmanuel Grumbach 
3265a02ae758SJohannes Berg 		kfree_skb(skb);
3266a02ae758SJohannes Berg 		return RX_QUEUED;
326771364716SRon Rindjunsky 	}
326871364716SRon Rindjunsky 
326908daecaeSJohannes Berg 	/*
327008daecaeSJohannes Berg 	 * After this point, we only want management frames,
327108daecaeSJohannes Berg 	 * so we can drop all remaining control frames to
327208daecaeSJohannes Berg 	 * cooked monitor interfaces.
327308daecaeSJohannes Berg 	 */
327408daecaeSJohannes Berg 	return RX_DROP_MONITOR;
327571364716SRon Rindjunsky }
327671364716SRon Rindjunsky 
ieee80211_process_sa_query_req(struct ieee80211_sub_if_data * sdata,struct ieee80211_mgmt * mgmt,size_t len)3277f4f727a6SJouni Malinen static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
3278fea14732SJouni Malinen 					   struct ieee80211_mgmt *mgmt,
3279fea14732SJouni Malinen 					   size_t len)
3280fea14732SJouni Malinen {
3281fea14732SJouni Malinen 	struct ieee80211_local *local = sdata->local;
3282fea14732SJouni Malinen 	struct sk_buff *skb;
3283fea14732SJouni Malinen 	struct ieee80211_mgmt *resp;
3284fea14732SJouni Malinen 
3285b203ca39SJoe Perches 	if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) {
3286fea14732SJouni Malinen 		/* Not to own unicast address */
3287fea14732SJouni Malinen 		return;
3288fea14732SJouni Malinen 	}
3289fea14732SJouni Malinen 
3290bfd8403aSJohannes Berg 	if (!ether_addr_equal(mgmt->sa, sdata->deflink.u.mgd.bssid) ||
3291bfd8403aSJohannes Berg 	    !ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) {
329277fdaa12SJohannes Berg 		/* Not from the current AP or not associated yet. */
3293fea14732SJouni Malinen 		return;
3294fea14732SJouni Malinen 	}
3295fea14732SJouni Malinen 
3296fea14732SJouni Malinen 	if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
3297fea14732SJouni Malinen 		/* Too short SA Query request frame */
3298fea14732SJouni Malinen 		return;
3299fea14732SJouni Malinen 	}
3300fea14732SJouni Malinen 
3301fea14732SJouni Malinen 	skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom);
3302fea14732SJouni Malinen 	if (skb == NULL)
3303fea14732SJouni Malinen 		return;
3304fea14732SJouni Malinen 
3305fea14732SJouni Malinen 	skb_reserve(skb, local->hw.extra_tx_headroom);
3306b080db58SJohannes Berg 	resp = skb_put_zero(skb, 24);
3307fea14732SJouni Malinen 	memcpy(resp->da, mgmt->sa, ETH_ALEN);
330847846c9bSJohannes Berg 	memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
3309bfd8403aSJohannes Berg 	memcpy(resp->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN);
3310fea14732SJouni Malinen 	resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3311fea14732SJouni Malinen 					  IEEE80211_STYPE_ACTION);
3312fea14732SJouni Malinen 	skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
3313fea14732SJouni Malinen 	resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
3314fea14732SJouni Malinen 	resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
3315fea14732SJouni Malinen 	memcpy(resp->u.action.u.sa_query.trans_id,
3316fea14732SJouni Malinen 	       mgmt->u.action.u.sa_query.trans_id,
3317fea14732SJouni Malinen 	       WLAN_SA_QUERY_TR_ID_LEN);
3318fea14732SJouni Malinen 
331962ae67beSJohannes Berg 	ieee80211_tx_skb(sdata, skb);
3320fea14732SJouni Malinen }
3321fea14732SJouni Malinen 
33226d945a33SLorenzo Bianconi static void
ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data * rx)33236d945a33SLorenzo Bianconi ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
33246d945a33SLorenzo Bianconi {
33256d945a33SLorenzo Bianconi 	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
33266d945a33SLorenzo Bianconi 	const struct element *ie;
33276d945a33SLorenzo Bianconi 	size_t baselen;
33286d945a33SLorenzo Bianconi 
33296d945a33SLorenzo Bianconi 	if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
33306d945a33SLorenzo Bianconi 				     NL80211_EXT_FEATURE_BSS_COLOR))
33316d945a33SLorenzo Bianconi 		return;
33326d945a33SLorenzo Bianconi 
33336d945a33SLorenzo Bianconi 	if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
33346d945a33SLorenzo Bianconi 		return;
33356d945a33SLorenzo Bianconi 
3336d0a9123eSJohannes Berg 	if (rx->sdata->vif.bss_conf.csa_active)
33376d945a33SLorenzo Bianconi 		return;
33386d945a33SLorenzo Bianconi 
33396d945a33SLorenzo Bianconi 	baselen = mgmt->u.beacon.variable - rx->skb->data;
33406d945a33SLorenzo Bianconi 	if (baselen > rx->skb->len)
33416d945a33SLorenzo Bianconi 		return;
33426d945a33SLorenzo Bianconi 
33436d945a33SLorenzo Bianconi 	ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION,
33446d945a33SLorenzo Bianconi 				    mgmt->u.beacon.variable,
33456d945a33SLorenzo Bianconi 				    rx->skb->len - baselen);
33466d945a33SLorenzo Bianconi 	if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
33476d945a33SLorenzo Bianconi 	    ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
33486d945a33SLorenzo Bianconi 		struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
33496d945a33SLorenzo Bianconi 		const struct ieee80211_he_operation *he_oper;
33506d945a33SLorenzo Bianconi 		u8 color;
33516d945a33SLorenzo Bianconi 
33526d945a33SLorenzo Bianconi 		he_oper = (void *)(ie->data + 1);
33536d945a33SLorenzo Bianconi 		if (le32_get_bits(he_oper->he_oper_params,
33546d945a33SLorenzo Bianconi 				  IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED))
33556d945a33SLorenzo Bianconi 			return;
33566d945a33SLorenzo Bianconi 
33576d945a33SLorenzo Bianconi 		color = le32_get_bits(he_oper->he_oper_params,
33586d945a33SLorenzo Bianconi 				      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
33596d945a33SLorenzo Bianconi 		if (color == bss_conf->he_bss_color.color)
336082253ddaSJohannes Berg 			ieee80211_obss_color_collision_notify(&rx->sdata->vif,
336103895c84SLorenzo Bianconi 							      BIT_ULL(color),
336203895c84SLorenzo Bianconi 							      GFP_ATOMIC);
33636d945a33SLorenzo Bianconi 	}
33646d945a33SLorenzo Bianconi }
33656d945a33SLorenzo Bianconi 
336649461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data * rx)33672e161f78SJohannes Berg ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
33682e161f78SJohannes Berg {
33692e161f78SJohannes Berg 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
3370554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
33712e161f78SJohannes Berg 
337209a740ceSThomas Pedersen 	if (ieee80211_is_s1g_beacon(mgmt->frame_control))
337309a740ceSThomas Pedersen 		return RX_CONTINUE;
337409a740ceSThomas Pedersen 
33752e161f78SJohannes Berg 	/*
33762e161f78SJohannes Berg 	 * From here on, look only at management frames.
33772e161f78SJohannes Berg 	 * Data and control frames are already handled,
33782e161f78SJohannes Berg 	 * and unknown (reserved) frames are useless.
33792e161f78SJohannes Berg 	 */
33802e161f78SJohannes Berg 	if (rx->skb->len < 24)
33812e161f78SJohannes Berg 		return RX_DROP_MONITOR;
33822e161f78SJohannes Berg 
33832e161f78SJohannes Berg 	if (!ieee80211_is_mgmt(mgmt->frame_control))
33842e161f78SJohannes Berg 		return RX_DROP_MONITOR;
33852e161f78SJohannes Berg 
33862cc7add3SJohannes Berg 	/* drop too small action frames */
33872cc7add3SJohannes Berg 	if (ieee80211_is_action(mgmt->frame_control) &&
33882cc7add3SJohannes Berg 	    rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
33892cc7add3SJohannes Berg 		return RX_DROP_UNUSABLE;
33902cc7add3SJohannes Berg 
3391ee971924SJohannes Berg 	if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
3392ee971924SJohannes Berg 	    ieee80211_is_beacon(mgmt->frame_control) &&
3393ee971924SJohannes Berg 	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
3394804483e9SJohannes Berg 		int sig = 0;
3395804483e9SJohannes Berg 
33966d945a33SLorenzo Bianconi 		/* sw bss color collision detection */
33976d945a33SLorenzo Bianconi 		ieee80211_rx_check_bss_color_collision(rx);
33986d945a33SLorenzo Bianconi 
33991ad22fb5STosoni 		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
34001ad22fb5STosoni 		    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
3401804483e9SJohannes Berg 			sig = status->signal;
3402804483e9SJohannes Berg 
3403e76fede8SThomas Pedersen 		cfg80211_report_obss_beacon_khz(rx->local->hw.wiphy,
3404ee971924SJohannes Berg 						rx->skb->data, rx->skb->len,
3405e76fede8SThomas Pedersen 						ieee80211_rx_status_to_khz(status),
3406e76fede8SThomas Pedersen 						sig);
3407ee971924SJohannes Berg 		rx->flags |= IEEE80211_RX_BEACON_REPORTED;
3408ee971924SJohannes Berg 	}
3409ee971924SJohannes Berg 
34102e161f78SJohannes Berg 	if (ieee80211_drop_unencrypted_mgmt(rx))
34112e161f78SJohannes Berg 		return RX_DROP_UNUSABLE;
34122e161f78SJohannes Berg 
34132e161f78SJohannes Berg 	return RX_CONTINUE;
34142e161f78SJohannes Berg }
34152e161f78SJohannes Berg 
3416f5a4c24eSLorenzo Bianconi static bool
ieee80211_process_rx_twt_action(struct ieee80211_rx_data * rx)3417f5a4c24eSLorenzo Bianconi ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
3418f5a4c24eSLorenzo Bianconi {
3419f5a4c24eSLorenzo Bianconi 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
3420f5a4c24eSLorenzo Bianconi 	struct ieee80211_sub_if_data *sdata = rx->sdata;
3421f5a4c24eSLorenzo Bianconi 
3422f5a4c24eSLorenzo Bianconi 	/* TWT actions are only supported in AP for the moment */
3423f5a4c24eSLorenzo Bianconi 	if (sdata->vif.type != NL80211_IFTYPE_AP)
3424f5a4c24eSLorenzo Bianconi 		return false;
3425f5a4c24eSLorenzo Bianconi 
3426f5a4c24eSLorenzo Bianconi 	if (!rx->local->ops->add_twt_setup)
3427f5a4c24eSLorenzo Bianconi 		return false;
3428f5a4c24eSLorenzo Bianconi 
342968ba1131SLorenzo Bianconi 	if (!sdata->vif.bss_conf.twt_responder)
3430f5a4c24eSLorenzo Bianconi 		return false;
3431f5a4c24eSLorenzo Bianconi 
3432f5a4c24eSLorenzo Bianconi 	if (!rx->sta)
3433f5a4c24eSLorenzo Bianconi 		return false;
3434f5a4c24eSLorenzo Bianconi 
3435f5a4c24eSLorenzo Bianconi 	switch (mgmt->u.action.u.s1g.action_code) {
3436f5a4c24eSLorenzo Bianconi 	case WLAN_S1G_TWT_SETUP: {
3437f5a4c24eSLorenzo Bianconi 		struct ieee80211_twt_setup *twt;
3438f5a4c24eSLorenzo Bianconi 
3439f5a4c24eSLorenzo Bianconi 		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3440f5a4c24eSLorenzo Bianconi 				   1 + /* action code */
3441f5a4c24eSLorenzo Bianconi 				   sizeof(struct ieee80211_twt_setup) +
3442f5a4c24eSLorenzo Bianconi 				   2 /* TWT req_type agrt */)
3443f5a4c24eSLorenzo Bianconi 			break;
3444f5a4c24eSLorenzo Bianconi 
3445f5a4c24eSLorenzo Bianconi 		twt = (void *)mgmt->u.action.u.s1g.variable;
3446f5a4c24eSLorenzo Bianconi 		if (twt->element_id != WLAN_EID_S1G_TWT)
3447f5a4c24eSLorenzo Bianconi 			break;
3448f5a4c24eSLorenzo Bianconi 
3449f5a4c24eSLorenzo Bianconi 		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3450f5a4c24eSLorenzo Bianconi 				   4 + /* action code + token + tlv */
3451f5a4c24eSLorenzo Bianconi 				   twt->length)
3452f5a4c24eSLorenzo Bianconi 			break;
3453f5a4c24eSLorenzo Bianconi 
3454f5a4c24eSLorenzo Bianconi 		return true; /* queue the frame */
3455f5a4c24eSLorenzo Bianconi 	}
3456f5a4c24eSLorenzo Bianconi 	case WLAN_S1G_TWT_TEARDOWN:
3457f5a4c24eSLorenzo Bianconi 		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
3458f5a4c24eSLorenzo Bianconi 			break;
3459f5a4c24eSLorenzo Bianconi 
3460f5a4c24eSLorenzo Bianconi 		return true; /* queue the frame */
3461f5a4c24eSLorenzo Bianconi 	default:
3462f5a4c24eSLorenzo Bianconi 		break;
3463f5a4c24eSLorenzo Bianconi 	}
3464f5a4c24eSLorenzo Bianconi 
3465f5a4c24eSLorenzo Bianconi 	return false;
3466f5a4c24eSLorenzo Bianconi }
3467f5a4c24eSLorenzo Bianconi 
34682e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data * rx)3469de1ede7aSJohannes Berg ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
3470de1ede7aSJohannes Berg {
3471de1ede7aSJohannes Berg 	struct ieee80211_local *local = rx->local;
3472eb9fb5b8SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
3473de1ede7aSJohannes Berg 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
3474554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
3475de1ede7aSJohannes Berg 	int len = rx->skb->len;
3476de1ede7aSJohannes Berg 
3477de1ede7aSJohannes Berg 	if (!ieee80211_is_action(mgmt->frame_control))
3478de1ede7aSJohannes Berg 		return RX_CONTINUE;
3479de1ede7aSJohannes Berg 
3480815b8092SMarco Porsch 	if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
3481cd7760e6SSimon Wunderlich 	    mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
3482cd7760e6SSimon Wunderlich 	    mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
348384040805SJohannes Berg 		return RX_DROP_UNUSABLE;
3484de1ede7aSJohannes Berg 
3485de1ede7aSJohannes Berg 	switch (mgmt->u.action.category) {
34861d8d3decSJohannes Berg 	case WLAN_CATEGORY_HT:
34871d8d3decSJohannes Berg 		/* reject HT action frames from stations not supporting HT */
3488b320d6c4SBenjamin Berg 		if (!rx->link_sta->pub->ht_cap.ht_supported)
34891d8d3decSJohannes Berg 			goto invalid;
34901d8d3decSJohannes Berg 
34911d8d3decSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
34921d8d3decSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
34931d8d3decSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
34941d8d3decSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_AP &&
34951d8d3decSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
34961d8d3decSJohannes Berg 			break;
34971d8d3decSJohannes Berg 
3498ec61cd63SJohannes Berg 		/* verify action & smps_control/chanwidth are present */
34991d8d3decSJohannes Berg 		if (len < IEEE80211_MIN_ACTION_SIZE + 2)
35001d8d3decSJohannes Berg 			goto invalid;
35011d8d3decSJohannes Berg 
35021d8d3decSJohannes Berg 		switch (mgmt->u.action.u.ht_smps.action) {
35031d8d3decSJohannes Berg 		case WLAN_HT_ACTION_SMPS: {
35041d8d3decSJohannes Berg 			struct ieee80211_supported_band *sband;
3505af0ed69bSJohannes Berg 			enum ieee80211_smps_mode smps_mode;
3506ff84e7bfStamizhr@codeaurora.org 			struct sta_opmode_info sta_opmode = {};
35071d8d3decSJohannes Berg 
3508c4d800dcSIlan Peer 			if (sdata->vif.type != NL80211_IFTYPE_AP &&
3509c4d800dcSIlan Peer 			    sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
3510c4d800dcSIlan Peer 				goto handled;
3511c4d800dcSIlan Peer 
35121d8d3decSJohannes Berg 			/* convert to HT capability */
35131d8d3decSJohannes Berg 			switch (mgmt->u.action.u.ht_smps.smps_control) {
35141d8d3decSJohannes Berg 			case WLAN_HT_SMPS_CONTROL_DISABLED:
3515af0ed69bSJohannes Berg 				smps_mode = IEEE80211_SMPS_OFF;
35161d8d3decSJohannes Berg 				break;
35171d8d3decSJohannes Berg 			case WLAN_HT_SMPS_CONTROL_STATIC:
3518af0ed69bSJohannes Berg 				smps_mode = IEEE80211_SMPS_STATIC;
35191d8d3decSJohannes Berg 				break;
35201d8d3decSJohannes Berg 			case WLAN_HT_SMPS_CONTROL_DYNAMIC:
3521af0ed69bSJohannes Berg 				smps_mode = IEEE80211_SMPS_DYNAMIC;
35221d8d3decSJohannes Berg 				break;
35231d8d3decSJohannes Berg 			default:
35241d8d3decSJohannes Berg 				goto invalid;
35251d8d3decSJohannes Berg 			}
35261d8d3decSJohannes Berg 
35271d8d3decSJohannes Berg 			/* if no change do nothing */
3528261ce887SBenjamin Berg 			if (rx->link_sta->pub->smps_mode == smps_mode)
35291d8d3decSJohannes Berg 				goto handled;
3530261ce887SBenjamin Berg 			rx->link_sta->pub->smps_mode = smps_mode;
353157566b20Stamizhr@codeaurora.org 			sta_opmode.smps_mode =
353257566b20Stamizhr@codeaurora.org 				ieee80211_smps_mode_to_smps_mode(smps_mode);
3533ff84e7bfStamizhr@codeaurora.org 			sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED;
35341d8d3decSJohannes Berg 
35351d8d3decSJohannes Berg 			sband = rx->local->hw.wiphy->bands[status->band];
35361d8d3decSJohannes Berg 
3537b4f85443SJohannes Berg 			rate_control_rate_update(local, sband, rx->sta, 0,
353864f68e5dSJohannes Berg 						 IEEE80211_RC_SMPS_CHANGED);
3539ff84e7bfStamizhr@codeaurora.org 			cfg80211_sta_opmode_change_notify(sdata->dev,
3540ff84e7bfStamizhr@codeaurora.org 							  rx->sta->addr,
3541ff84e7bfStamizhr@codeaurora.org 							  &sta_opmode,
3542c752cac9SYan-Hsuan Chuang 							  GFP_ATOMIC);
35431d8d3decSJohannes Berg 			goto handled;
35441d8d3decSJohannes Berg 		}
3545ec61cd63SJohannes Berg 		case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
3546ec61cd63SJohannes Berg 			struct ieee80211_supported_band *sband;
3547ec61cd63SJohannes Berg 			u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
35481c45c5ceSEliad Peller 			enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
3549ff84e7bfStamizhr@codeaurora.org 			struct sta_opmode_info sta_opmode = {};
3550ec61cd63SJohannes Berg 
3551ec61cd63SJohannes Berg 			/* If it doesn't support 40 MHz it can't change ... */
3552b320d6c4SBenjamin Berg 			if (!(rx->link_sta->pub->ht_cap.cap &
3553e1a0c6b3SJohannes Berg 					IEEE80211_HT_CAP_SUP_WIDTH_20_40))
3554ec61cd63SJohannes Berg 				goto handled;
3555ec61cd63SJohannes Berg 
3556e1a0c6b3SJohannes Berg 			if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
35571c45c5ceSEliad Peller 				max_bw = IEEE80211_STA_RX_BW_20;
3558ec61cd63SJohannes Berg 			else
3559b320d6c4SBenjamin Berg 				max_bw = ieee80211_sta_cap_rx_bw(rx->link_sta);
35601c45c5ceSEliad Peller 
35611c45c5ceSEliad Peller 			/* set cur_max_bandwidth and recalc sta bw */
3562b320d6c4SBenjamin Berg 			rx->link_sta->cur_max_bandwidth = max_bw;
3563b320d6c4SBenjamin Berg 			new_bw = ieee80211_sta_cur_vht_bw(rx->link_sta);
3564e1a0c6b3SJohannes Berg 
3565b320d6c4SBenjamin Berg 			if (rx->link_sta->pub->bandwidth == new_bw)
3566e1a0c6b3SJohannes Berg 				goto handled;
3567ec61cd63SJohannes Berg 
3568b320d6c4SBenjamin Berg 			rx->link_sta->pub->bandwidth = new_bw;
3569ec61cd63SJohannes Berg 			sband = rx->local->hw.wiphy->bands[status->band];
357097f5f425Stamizhr@codeaurora.org 			sta_opmode.bw =
3571b320d6c4SBenjamin Berg 				ieee80211_sta_rx_bw_to_chan_width(rx->link_sta);
3572ff84e7bfStamizhr@codeaurora.org 			sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
3573ec61cd63SJohannes Berg 
3574b4f85443SJohannes Berg 			rate_control_rate_update(local, sband, rx->sta, 0,
3575ec61cd63SJohannes Berg 						 IEEE80211_RC_BW_CHANGED);
3576ff84e7bfStamizhr@codeaurora.org 			cfg80211_sta_opmode_change_notify(sdata->dev,
3577ff84e7bfStamizhr@codeaurora.org 							  rx->sta->addr,
3578ff84e7bfStamizhr@codeaurora.org 							  &sta_opmode,
3579c752cac9SYan-Hsuan Chuang 							  GFP_ATOMIC);
3580ec61cd63SJohannes Berg 			goto handled;
3581ec61cd63SJohannes Berg 		}
35821d8d3decSJohannes Berg 		default:
35831d8d3decSJohannes Berg 			goto invalid;
35841d8d3decSJohannes Berg 		}
35851d8d3decSJohannes Berg 
35861d8d3decSJohannes Berg 		break;
35871b3a2e49SJohannes Berg 	case WLAN_CATEGORY_PUBLIC:
35881b3a2e49SJohannes Berg 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
35891b3a2e49SJohannes Berg 			goto invalid;
35901b3a2e49SJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
35911b3a2e49SJohannes Berg 			break;
35921b3a2e49SJohannes Berg 		if (!rx->sta)
35931b3a2e49SJohannes Berg 			break;
3594bfd8403aSJohannes Berg 		if (!ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid))
35951b3a2e49SJohannes Berg 			break;
35961b3a2e49SJohannes Berg 		if (mgmt->u.action.u.ext_chan_switch.action_code !=
35971b3a2e49SJohannes Berg 				WLAN_PUB_ACTION_EXT_CHANSW_ANN)
35981b3a2e49SJohannes Berg 			break;
35991b3a2e49SJohannes Berg 		if (len < offsetof(struct ieee80211_mgmt,
36001b3a2e49SJohannes Berg 				   u.action.u.ext_chan_switch.variable))
36011b3a2e49SJohannes Berg 			goto invalid;
36021b3a2e49SJohannes Berg 		goto queue;
36030af83d3dSJohannes Berg 	case WLAN_CATEGORY_VHT:
36040af83d3dSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
36050af83d3dSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
36060af83d3dSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
36070af83d3dSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_AP &&
36080af83d3dSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
36090af83d3dSJohannes Berg 			break;
36100af83d3dSJohannes Berg 
36110af83d3dSJohannes Berg 		/* verify action code is present */
36120af83d3dSJohannes Berg 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
36130af83d3dSJohannes Berg 			goto invalid;
36140af83d3dSJohannes Berg 
36150af83d3dSJohannes Berg 		switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
36160af83d3dSJohannes Berg 		case WLAN_VHT_ACTION_OPMODE_NOTIF: {
36170af83d3dSJohannes Berg 			/* verify opmode is present */
36180af83d3dSJohannes Berg 			if (len < IEEE80211_MIN_ACTION_SIZE + 2)
36190af83d3dSJohannes Berg 				goto invalid;
3620d2941df8SJohannes Berg 			goto queue;
36210af83d3dSJohannes Berg 		}
362223a1f8d4SSara Sharon 		case WLAN_VHT_ACTION_GROUPID_MGMT: {
362323a1f8d4SSara Sharon 			if (len < IEEE80211_MIN_ACTION_SIZE + 25)
362423a1f8d4SSara Sharon 				goto invalid;
362523a1f8d4SSara Sharon 			goto queue;
362623a1f8d4SSara Sharon 		}
36270af83d3dSJohannes Berg 		default:
36280af83d3dSJohannes Berg 			break;
36290af83d3dSJohannes Berg 		}
36300af83d3dSJohannes Berg 		break;
3631de1ede7aSJohannes Berg 	case WLAN_CATEGORY_BACK:
36328abd3f9bSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
3633ae2772b3SThomas Pedersen 		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
36348abd3f9bSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
363513c40c54SAlexander Simon 		    sdata->vif.type != NL80211_IFTYPE_AP &&
363613c40c54SAlexander Simon 		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
363784040805SJohannes Berg 			break;
36388abd3f9bSJohannes Berg 
3639026331c4SJouni Malinen 		/* verify action_code is present */
3640026331c4SJouni Malinen 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
3641026331c4SJouni Malinen 			break;
3642026331c4SJouni Malinen 
3643de1ede7aSJohannes Berg 		switch (mgmt->u.action.u.addba_req.action_code) {
3644de1ede7aSJohannes Berg 		case WLAN_ACTION_ADDBA_REQ:
3645de1ede7aSJohannes Berg 			if (len < (IEEE80211_MIN_ACTION_SIZE +
3646de1ede7aSJohannes Berg 				   sizeof(mgmt->u.action.u.addba_req)))
3647bed7ee6eSJohannes Berg 				goto invalid;
3648bed7ee6eSJohannes Berg 			break;
3649de1ede7aSJohannes Berg 		case WLAN_ACTION_ADDBA_RESP:
3650de1ede7aSJohannes Berg 			if (len < (IEEE80211_MIN_ACTION_SIZE +
3651de1ede7aSJohannes Berg 				   sizeof(mgmt->u.action.u.addba_resp)))
3652bed7ee6eSJohannes Berg 				goto invalid;
3653de1ede7aSJohannes Berg 			break;
3654de1ede7aSJohannes Berg 		case WLAN_ACTION_DELBA:
3655de1ede7aSJohannes Berg 			if (len < (IEEE80211_MIN_ACTION_SIZE +
3656de1ede7aSJohannes Berg 				   sizeof(mgmt->u.action.u.delba)))
3657bed7ee6eSJohannes Berg 				goto invalid;
3658de1ede7aSJohannes Berg 			break;
3659bed7ee6eSJohannes Berg 		default:
3660bed7ee6eSJohannes Berg 			goto invalid;
3661de1ede7aSJohannes Berg 		}
3662bed7ee6eSJohannes Berg 
36638b58ff83SJohannes Berg 		goto queue;
366439192c0bSJohannes Berg 	case WLAN_CATEGORY_SPECTRUM_MGMT:
3665026331c4SJouni Malinen 		/* verify action_code is present */
3666026331c4SJouni Malinen 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
3667026331c4SJouni Malinen 			break;
3668026331c4SJouni Malinen 
366939192c0bSJohannes Berg 		switch (mgmt->u.action.u.measurement.action_code) {
367039192c0bSJohannes Berg 		case WLAN_ACTION_SPCT_MSR_REQ:
367157fbcce3SJohannes Berg 			if (status->band != NL80211_BAND_5GHZ)
3672cd7760e6SSimon Wunderlich 				break;
3673cd7760e6SSimon Wunderlich 
367439192c0bSJohannes Berg 			if (len < (IEEE80211_MIN_ACTION_SIZE +
367539192c0bSJohannes Berg 				   sizeof(mgmt->u.action.u.measurement)))
367639192c0bSJohannes Berg 				break;
3677cd7760e6SSimon Wunderlich 
3678cc32abd4SJohannes Berg 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
367984040805SJohannes Berg 				break;
3680cc32abd4SJohannes Berg 
3681cd7760e6SSimon Wunderlich 			ieee80211_process_measurement_req(sdata, mgmt, len);
3682cd7760e6SSimon Wunderlich 			goto handled;
3683cd7760e6SSimon Wunderlich 		case WLAN_ACTION_SPCT_CHL_SWITCH: {
3684cd7760e6SSimon Wunderlich 			u8 *bssid;
3685cd7760e6SSimon Wunderlich 			if (len < (IEEE80211_MIN_ACTION_SIZE +
3686cd7760e6SSimon Wunderlich 				   sizeof(mgmt->u.action.u.chan_switch)))
3687cd7760e6SSimon Wunderlich 				break;
3688cd7760e6SSimon Wunderlich 
3689cd7760e6SSimon Wunderlich 			if (sdata->vif.type != NL80211_IFTYPE_STATION &&
3690b8456a14SChun-Yeow Yeoh 			    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3691b8456a14SChun-Yeow Yeoh 			    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
3692cd7760e6SSimon Wunderlich 				break;
3693cd7760e6SSimon Wunderlich 
3694cd7760e6SSimon Wunderlich 			if (sdata->vif.type == NL80211_IFTYPE_STATION)
3695bfd8403aSJohannes Berg 				bssid = sdata->deflink.u.mgd.bssid;
3696cd7760e6SSimon Wunderlich 			else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
3697cd7760e6SSimon Wunderlich 				bssid = sdata->u.ibss.bssid;
3698b8456a14SChun-Yeow Yeoh 			else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
3699b8456a14SChun-Yeow Yeoh 				bssid = mgmt->sa;
3700cd7760e6SSimon Wunderlich 			else
3701cd7760e6SSimon Wunderlich 				break;
3702cd7760e6SSimon Wunderlich 
3703cd7760e6SSimon Wunderlich 			if (!ether_addr_equal(mgmt->bssid, bssid))
370484040805SJohannes Berg 				break;
3705c481ec97SSujith 
37068b58ff83SJohannes Berg 			goto queue;
370739192c0bSJohannes Berg 			}
3708cd7760e6SSimon Wunderlich 		}
370939192c0bSJohannes Berg 		break;
37108db09850SThomas Pedersen 	case WLAN_CATEGORY_SELF_PROTECTED:
37119b395bc3SJohannes Berg 		if (len < (IEEE80211_MIN_ACTION_SIZE +
37129b395bc3SJohannes Berg 			   sizeof(mgmt->u.action.u.self_prot.action_code)))
37139b395bc3SJohannes Berg 			break;
37149b395bc3SJohannes Berg 
37158db09850SThomas Pedersen 		switch (mgmt->u.action.u.self_prot.action_code) {
37168db09850SThomas Pedersen 		case WLAN_SP_MESH_PEERING_OPEN:
37178db09850SThomas Pedersen 		case WLAN_SP_MESH_PEERING_CLOSE:
37188db09850SThomas Pedersen 		case WLAN_SP_MESH_PEERING_CONFIRM:
37198db09850SThomas Pedersen 			if (!ieee80211_vif_is_mesh(&sdata->vif))
37208db09850SThomas Pedersen 				goto invalid;
3721a6dad6a2SThomas Pedersen 			if (sdata->u.mesh.user_mpm)
37228db09850SThomas Pedersen 				/* userspace handles this frame */
37238db09850SThomas Pedersen 				break;
37248db09850SThomas Pedersen 			goto queue;
37258db09850SThomas Pedersen 		case WLAN_SP_MGK_INFORM:
37268db09850SThomas Pedersen 		case WLAN_SP_MGK_ACK:
37278db09850SThomas Pedersen 			if (!ieee80211_vif_is_mesh(&sdata->vif))
37288db09850SThomas Pedersen 				goto invalid;
37298db09850SThomas Pedersen 			break;
37308db09850SThomas Pedersen 		}
37318db09850SThomas Pedersen 		break;
3732d3aaec8aSJavier Cardona 	case WLAN_CATEGORY_MESH_ACTION:
37339b395bc3SJohannes Berg 		if (len < (IEEE80211_MIN_ACTION_SIZE +
37349b395bc3SJohannes Berg 			   sizeof(mgmt->u.action.u.mesh_action.action_code)))
37359b395bc3SJohannes Berg 			break;
37369b395bc3SJohannes Berg 
373777a121c3SJohannes Berg 		if (!ieee80211_vif_is_mesh(&sdata->vif))
37381cb561f8SJavier Cardona 			break;
373925d49e4dSThomas Pedersen 		if (mesh_action_is_path_sel(mgmt) &&
37401df332e8SJohannes Berg 		    !mesh_path_sel_is_hwmp(sdata))
3741c7108a71SJavier Cardona 			break;
3742c7108a71SJavier Cardona 		goto queue;
3743f5a4c24eSLorenzo Bianconi 	case WLAN_CATEGORY_S1G:
374419e4a47eSJohannes Berg 		if (len < offsetofend(typeof(*mgmt),
374519e4a47eSJohannes Berg 				      u.action.u.s1g.action_code))
374619e4a47eSJohannes Berg 			break;
374719e4a47eSJohannes Berg 
3748f5a4c24eSLorenzo Bianconi 		switch (mgmt->u.action.u.s1g.action_code) {
3749f5a4c24eSLorenzo Bianconi 		case WLAN_S1G_TWT_SETUP:
3750f5a4c24eSLorenzo Bianconi 		case WLAN_S1G_TWT_TEARDOWN:
3751f5a4c24eSLorenzo Bianconi 			if (ieee80211_process_rx_twt_action(rx))
3752f5a4c24eSLorenzo Bianconi 				goto queue;
3753f5a4c24eSLorenzo Bianconi 			break;
3754f5a4c24eSLorenzo Bianconi 		default:
3755f5a4c24eSLorenzo Bianconi 			break;
3756f5a4c24eSLorenzo Bianconi 		}
3757f5a4c24eSLorenzo Bianconi 		break;
375884040805SJohannes Berg 	}
3759026331c4SJouni Malinen 
37602e161f78SJohannes Berg 	return RX_CONTINUE;
37612e161f78SJohannes Berg 
3762bed7ee6eSJohannes Berg  invalid:
3763554891e6SJohannes Berg 	status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
37642e161f78SJohannes Berg 	/* will return in the next handlers */
37652e161f78SJohannes Berg 	return RX_CONTINUE;
37662e161f78SJohannes Berg 
37672e161f78SJohannes Berg  handled:
37682e161f78SJohannes Berg 	if (rx->sta)
3769b320d6c4SBenjamin Berg 		rx->link_sta->rx_stats.packets++;
37702e161f78SJohannes Berg 	dev_kfree_skb(rx->skb);
37712e161f78SJohannes Berg 	return RX_QUEUED;
37722e161f78SJohannes Berg 
37732e161f78SJohannes Berg  queue:
37744f6c78deSJohannes Berg 	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
37752e161f78SJohannes Berg 	return RX_QUEUED;
37762e161f78SJohannes Berg }
37772e161f78SJohannes Berg 
37782e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data * rx)37792e161f78SJohannes Berg ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
37802e161f78SJohannes Berg {
3781554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
3782f9202638SAvraham Stern 	struct cfg80211_rx_info info = {
3783f9202638SAvraham Stern 		.freq = ieee80211_rx_status_to_khz(status),
3784f9202638SAvraham Stern 		.buf = rx->skb->data,
37852ec833a5SJohannes Berg 		.len = rx->skb->len,
37862ec833a5SJohannes Berg 		.link_id = rx->link_id,
37872ec833a5SJohannes Berg 		.have_link_id = rx->link_id >= 0,
3788f9202638SAvraham Stern 	};
37892e161f78SJohannes Berg 
37902e161f78SJohannes Berg 	/* skip known-bad action frames and return them in the next handler */
3791554891e6SJohannes Berg 	if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
37922e161f78SJohannes Berg 		return RX_CONTINUE;
3793d7907448SFelix Fietkau 
3794026331c4SJouni Malinen 	/*
3795026331c4SJouni Malinen 	 * Getting here means the kernel doesn't know how to handle
3796026331c4SJouni Malinen 	 * it, but maybe userspace does ... include returned frames
3797026331c4SJouni Malinen 	 * so userspace can register for those to know whether ones
3798026331c4SJouni Malinen 	 * it transmitted were processed or returned.
3799026331c4SJouni Malinen 	 */
3800026331c4SJouni Malinen 
38011ad22fb5STosoni 	if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
38021ad22fb5STosoni 	    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
3803f9202638SAvraham Stern 		info.sig_dbm = status->signal;
3804804483e9SJohannes Berg 
3805f9202638SAvraham Stern 	if (ieee80211_is_timing_measurement(rx->skb) ||
3806f9202638SAvraham Stern 	    ieee80211_is_ftm(rx->skb)) {
3807f9202638SAvraham Stern 		info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp);
3808f9202638SAvraham Stern 		info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp);
3809f9202638SAvraham Stern 	}
3810f9202638SAvraham Stern 
3811f9202638SAvraham Stern 	if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) {
38122e161f78SJohannes Berg 		if (rx->sta)
3813b320d6c4SBenjamin Berg 			rx->link_sta->rx_stats.packets++;
38142e161f78SJohannes Berg 		dev_kfree_skb(rx->skb);
38152e161f78SJohannes Berg 		return RX_QUEUED;
38162e161f78SJohannes Berg 	}
38172e161f78SJohannes Berg 
38182e161f78SJohannes Berg 	return RX_CONTINUE;
38192e161f78SJohannes Berg }
38202e161f78SJohannes Berg 
38212e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data * rx)38221ea02224SJohannes Berg ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx)
38231ea02224SJohannes Berg {
38241ea02224SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
38251ea02224SJohannes Berg 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
38261ea02224SJohannes Berg 	int len = rx->skb->len;
38271ea02224SJohannes Berg 
38281ea02224SJohannes Berg 	if (!ieee80211_is_action(mgmt->frame_control))
38291ea02224SJohannes Berg 		return RX_CONTINUE;
38301ea02224SJohannes Berg 
38311ea02224SJohannes Berg 	switch (mgmt->u.action.category) {
38321ea02224SJohannes Berg 	case WLAN_CATEGORY_SA_QUERY:
38331ea02224SJohannes Berg 		if (len < (IEEE80211_MIN_ACTION_SIZE +
38341ea02224SJohannes Berg 			   sizeof(mgmt->u.action.u.sa_query)))
38351ea02224SJohannes Berg 			break;
38361ea02224SJohannes Berg 
38371ea02224SJohannes Berg 		switch (mgmt->u.action.u.sa_query.action) {
38381ea02224SJohannes Berg 		case WLAN_ACTION_SA_QUERY_REQUEST:
38391ea02224SJohannes Berg 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
38401ea02224SJohannes Berg 				break;
38411ea02224SJohannes Berg 			ieee80211_process_sa_query_req(sdata, mgmt, len);
38421ea02224SJohannes Berg 			goto handled;
38431ea02224SJohannes Berg 		}
38441ea02224SJohannes Berg 		break;
38451ea02224SJohannes Berg 	}
38461ea02224SJohannes Berg 
38471ea02224SJohannes Berg 	return RX_CONTINUE;
38481ea02224SJohannes Berg 
38491ea02224SJohannes Berg  handled:
38501ea02224SJohannes Berg 	if (rx->sta)
3851b320d6c4SBenjamin Berg 		rx->link_sta->rx_stats.packets++;
38521ea02224SJohannes Berg 	dev_kfree_skb(rx->skb);
38531ea02224SJohannes Berg 	return RX_QUEUED;
38541ea02224SJohannes Berg }
38551ea02224SJohannes Berg 
38561ea02224SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action_return(struct ieee80211_rx_data * rx)38572e161f78SJohannes Berg ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
38582e161f78SJohannes Berg {
38592e161f78SJohannes Berg 	struct ieee80211_local *local = rx->local;
38602e161f78SJohannes Berg 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
38612e161f78SJohannes Berg 	struct sk_buff *nskb;
38622e161f78SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
3863554891e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
38642e161f78SJohannes Berg 
38652e161f78SJohannes Berg 	if (!ieee80211_is_action(mgmt->frame_control))
38662e161f78SJohannes Berg 		return RX_CONTINUE;
38672e161f78SJohannes Berg 
38682e161f78SJohannes Berg 	/*
38692e161f78SJohannes Berg 	 * For AP mode, hostapd is responsible for handling any action
38702e161f78SJohannes Berg 	 * frames that we didn't handle, including returning unknown
38712e161f78SJohannes Berg 	 * ones. For all other modes we will return them to the sender,
38722e161f78SJohannes Berg 	 * setting the 0x80 bit in the action category, as required by
38734b5ebcccSJohannes Berg 	 * 802.11-2012 9.24.4.
38742e161f78SJohannes Berg 	 * Newer versions of hostapd shall also use the management frame
38752e161f78SJohannes Berg 	 * registration mechanisms, but older ones still use cooked
38762e161f78SJohannes Berg 	 * monitor interfaces so push all frames there.
38772e161f78SJohannes Berg 	 */
3878554891e6SJohannes Berg 	if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
38792e161f78SJohannes Berg 	    (sdata->vif.type == NL80211_IFTYPE_AP ||
38802e161f78SJohannes Berg 	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
38812e161f78SJohannes Berg 		return RX_DROP_MONITOR;
3882026331c4SJouni Malinen 
38834b5ebcccSJohannes Berg 	if (is_multicast_ether_addr(mgmt->da))
38844b5ebcccSJohannes Berg 		return RX_DROP_MONITOR;
38854b5ebcccSJohannes Berg 
388684040805SJohannes Berg 	/* do not return rejected action frames */
388784040805SJohannes Berg 	if (mgmt->u.action.category & 0x80)
388884040805SJohannes Berg 		return RX_DROP_UNUSABLE;
388984040805SJohannes Berg 
389084040805SJohannes Berg 	nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
389184040805SJohannes Berg 			       GFP_ATOMIC);
389284040805SJohannes Berg 	if (nskb) {
3893292b4df6SJohn W. Linville 		struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
389484040805SJohannes Berg 
3895292b4df6SJohn W. Linville 		nmgmt->u.action.category |= 0x80;
3896292b4df6SJohn W. Linville 		memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
3897292b4df6SJohn W. Linville 		memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
389884040805SJohannes Berg 
389984040805SJohannes Berg 		memset(nskb->cb, 0, sizeof(nskb->cb));
390084040805SJohannes Berg 
390107e5a5f5SJohannes Berg 		if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
390207e5a5f5SJohannes Berg 			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
390307e5a5f5SJohannes Berg 
390407e5a5f5SJohannes Berg 			info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
390507e5a5f5SJohannes Berg 				      IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
390607e5a5f5SJohannes Berg 				      IEEE80211_TX_CTL_NO_CCK_RATE;
390730686bf7SJohannes Berg 			if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
390807e5a5f5SJohannes Berg 				info->hw_queue =
390907e5a5f5SJohannes Berg 					local->hw.offchannel_tx_hw_queue;
391007e5a5f5SJohannes Berg 		}
391107e5a5f5SJohannes Berg 
3912e1e68b14SJohannes Berg 		__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1,
391308aca29aSMathy Vanhoef 					    status->band);
391439192c0bSJohannes Berg 	}
3915de1ede7aSJohannes Berg 	dev_kfree_skb(rx->skb);
3916de1ede7aSJohannes Berg 	return RX_QUEUED;
3917de1ede7aSJohannes Berg }
3918de1ede7aSJohannes Berg 
3919de1ede7aSJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ext(struct ieee80211_rx_data * rx)392009a740ceSThomas Pedersen ieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
392109a740ceSThomas Pedersen {
392209a740ceSThomas Pedersen 	struct ieee80211_sub_if_data *sdata = rx->sdata;
392309a740ceSThomas Pedersen 	struct ieee80211_hdr *hdr = (void *)rx->skb->data;
392409a740ceSThomas Pedersen 
392509a740ceSThomas Pedersen 	if (!ieee80211_is_ext(hdr->frame_control))
392609a740ceSThomas Pedersen 		return RX_CONTINUE;
392709a740ceSThomas Pedersen 
392809a740ceSThomas Pedersen 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
392909a740ceSThomas Pedersen 		return RX_DROP_MONITOR;
393009a740ceSThomas Pedersen 
393109a740ceSThomas Pedersen 	/* for now only beacons are ext, so queue them */
39324f6c78deSJohannes Berg 	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
393309a740ceSThomas Pedersen 
393409a740ceSThomas Pedersen 	return RX_QUEUED;
393509a740ceSThomas Pedersen }
393609a740ceSThomas Pedersen 
393709a740ceSThomas Pedersen static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt(struct ieee80211_rx_data * rx)39385cf121c3SJohannes Berg ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
3939571ecf67SJohannes Berg {
3940eb9fb5b8SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
394177a121c3SJohannes Berg 	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
394277a121c3SJohannes Berg 	__le16 stype;
3943571ecf67SJohannes Berg 
394477a121c3SJohannes Berg 	stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
3945472dbc45SJohannes Berg 
394677a121c3SJohannes Berg 	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
394777a121c3SJohannes Berg 	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3948239281f8SRostislav Lisovy 	    sdata->vif.type != NL80211_IFTYPE_OCB &&
394977a121c3SJohannes Berg 	    sdata->vif.type != NL80211_IFTYPE_STATION)
39507986cf95SJohannes Berg 		return RX_DROP_MONITOR;
395177a121c3SJohannes Berg 
395277a121c3SJohannes Berg 	switch (stype) {
395366e67e41SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_AUTH):
395477a121c3SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_BEACON):
395577a121c3SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
395677a121c3SJohannes Berg 		/* process for all: mesh, mlme, ibss */
395777a121c3SJohannes Berg 		break;
395895697f99SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
395995697f99SJohannes Berg 		if (is_multicast_ether_addr(mgmt->da) &&
396095697f99SJohannes Berg 		    !is_broadcast_ether_addr(mgmt->da))
396195697f99SJohannes Berg 			return RX_DROP_MONITOR;
396295697f99SJohannes Berg 
396395697f99SJohannes Berg 		/* process only for station/IBSS */
396495697f99SJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
396595697f99SJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
396695697f99SJohannes Berg 			return RX_DROP_MONITOR;
396795697f99SJohannes Berg 		break;
396866e67e41SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
396966e67e41SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
397077a121c3SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
39712c31333aSChristian Lamparter 		if (is_multicast_ether_addr(mgmt->da) &&
39722c31333aSChristian Lamparter 		    !is_broadcast_ether_addr(mgmt->da))
39732c31333aSChristian Lamparter 			return RX_DROP_MONITOR;
39742c31333aSChristian Lamparter 
397577a121c3SJohannes Berg 		/* process only for station */
397677a121c3SJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
397777a121c3SJohannes Berg 			return RX_DROP_MONITOR;
397877a121c3SJohannes Berg 		break;
397977a121c3SJohannes Berg 	case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
39809fb04b50SThomas Pedersen 		/* process only for ibss and mesh */
39819fb04b50SThomas Pedersen 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
39829fb04b50SThomas Pedersen 		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
398377a121c3SJohannes Berg 			return RX_DROP_MONITOR;
398477a121c3SJohannes Berg 		break;
398577a121c3SJohannes Berg 	default:
398677a121c3SJohannes Berg 		return RX_DROP_MONITOR;
398777a121c3SJohannes Berg 	}
398877a121c3SJohannes Berg 
39894f6c78deSJohannes Berg 	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
399077a121c3SJohannes Berg 
399177a121c3SJohannes Berg 	return RX_QUEUED;
3992571ecf67SJohannes Berg }
3993571ecf67SJohannes Berg 
ieee80211_rx_cooked_monitor(struct ieee80211_rx_data * rx,struct ieee80211_rate * rate,ieee80211_rx_result reason)39945f0b7de5SJohannes Berg static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
3995baa951a1SJohannes Berg 					struct ieee80211_rate *rate,
3996baa951a1SJohannes Berg 					ieee80211_rx_result reason)
39973d30d949SMichael Wu {
39983d30d949SMichael Wu 	struct ieee80211_sub_if_data *sdata;
39993d30d949SMichael Wu 	struct ieee80211_local *local = rx->local;
40003d30d949SMichael Wu 	struct sk_buff *skb = rx->skb, *skb2;
40013d30d949SMichael Wu 	struct net_device *prev_dev = NULL;
4002eb9fb5b8SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4003293702a3SJohannes Berg 	int needed_headroom;
40043d30d949SMichael Wu 
4005554891e6SJohannes Berg 	/*
4006554891e6SJohannes Berg 	 * If cooked monitor has been processed already, then
4007554891e6SJohannes Berg 	 * don't do it again. If not, set the flag.
4008554891e6SJohannes Berg 	 */
4009554891e6SJohannes Berg 	if (rx->flags & IEEE80211_RX_CMNTR)
40107c1e1831SJohn W. Linville 		goto out_free_skb;
4011554891e6SJohannes Berg 	rx->flags |= IEEE80211_RX_CMNTR;
40127c1e1831SJohn W. Linville 
4013152c477aSJohannes Berg 	/* If there are no cooked monitor interfaces, just free the SKB */
4014152c477aSJohannes Berg 	if (!local->cooked_mntrs)
4015152c477aSJohannes Berg 		goto out_free_skb;
4016152c477aSJohannes Berg 
4017293702a3SJohannes Berg 	/* room for the radiotap header based on driver features */
40181f7bba79SJohannes Berg 	needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);
4019293702a3SJohannes Berg 
4020293702a3SJohannes Berg 	if (skb_headroom(skb) < needed_headroom &&
4021293702a3SJohannes Berg 	    pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
40223d30d949SMichael Wu 		goto out_free_skb;
40233d30d949SMichael Wu 
4024293702a3SJohannes Berg 	/* prepend radiotap information */
4025973ef21aSFelix Fietkau 	ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
4026973ef21aSFelix Fietkau 					 false);
40273d30d949SMichael Wu 
4028d57a544dSZhang Shengju 	skb_reset_mac_header(skb);
40293d30d949SMichael Wu 	skb->ip_summed = CHECKSUM_UNNECESSARY;
40303d30d949SMichael Wu 	skb->pkt_type = PACKET_OTHERHOST;
40313d30d949SMichael Wu 	skb->protocol = htons(ETH_P_802_2);
40323d30d949SMichael Wu 
40333d30d949SMichael Wu 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
40349607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
40353d30d949SMichael Wu 			continue;
40363d30d949SMichael Wu 
403705c914feSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
4038d8212184SAviya Erenfeld 		    !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))
40393d30d949SMichael Wu 			continue;
40403d30d949SMichael Wu 
40413d30d949SMichael Wu 		if (prev_dev) {
40423d30d949SMichael Wu 			skb2 = skb_clone(skb, GFP_ATOMIC);
40433d30d949SMichael Wu 			if (skb2) {
40443d30d949SMichael Wu 				skb2->dev = prev_dev;
40455548a8a1SJohn W. Linville 				netif_receive_skb(skb2);
40463d30d949SMichael Wu 			}
40473d30d949SMichael Wu 		}
40483d30d949SMichael Wu 
40493d30d949SMichael Wu 		prev_dev = sdata->dev;
405036ec144fSLev Stipakov 		dev_sw_netstats_rx_add(sdata->dev, skb->len);
40513d30d949SMichael Wu 	}
40523d30d949SMichael Wu 
40533d30d949SMichael Wu 	if (prev_dev) {
40543d30d949SMichael Wu 		skb->dev = prev_dev;
40555548a8a1SJohn W. Linville 		netif_receive_skb(skb);
40563d30d949SMichael Wu 		return;
4057554891e6SJohannes Berg 	}
40583d30d949SMichael Wu 
40593d30d949SMichael Wu  out_free_skb:
4060baa951a1SJohannes Berg 	kfree_skb_reason(skb, (__force u32)reason);
40613d30d949SMichael Wu }
40623d30d949SMichael Wu 
ieee80211_rx_handlers_result(struct ieee80211_rx_data * rx,ieee80211_rx_result res)4063aa0c8636SChristian Lamparter static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
4064aa0c8636SChristian Lamparter 					 ieee80211_rx_result res)
4065aa0c8636SChristian Lamparter {
4066baa951a1SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
4067baa951a1SJohannes Berg 	struct ieee80211_supported_band *sband;
4068baa951a1SJohannes Berg 	struct ieee80211_rate *rate = NULL;
4069baa951a1SJohannes Berg 
4070baa951a1SJohannes Berg 	if (res == RX_QUEUED) {
4071baa951a1SJohannes Berg 		I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
4072baa951a1SJohannes Berg 		return;
4073baa951a1SJohannes Berg 	}
4074baa951a1SJohannes Berg 
4075baa951a1SJohannes Berg 	if (res != RX_CONTINUE) {
4076aa0c8636SChristian Lamparter 		I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
4077aa0c8636SChristian Lamparter 		if (rx->sta)
4078b320d6c4SBenjamin Berg 			rx->link_sta->rx_stats.dropped++;
4079baa951a1SJohannes Berg 	}
4080aa0c8636SChristian Lamparter 
4081baa951a1SJohannes Berg 	if (u32_get_bits((__force u32)res, SKB_DROP_REASON_SUBSYS_MASK) ==
4082baa951a1SJohannes Berg 			SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE) {
4083baa951a1SJohannes Berg 		kfree_skb_reason(rx->skb, (__force u32)res);
4084baa951a1SJohannes Berg 		return;
4085baa951a1SJohannes Berg 	}
4086aa0c8636SChristian Lamparter 
4087aa0c8636SChristian Lamparter 	sband = rx->local->hw.wiphy->bands[status->band];
408841cbb0f5SLuca Coelho 	if (status->encoding == RX_ENC_LEGACY)
4089aa0c8636SChristian Lamparter 		rate = &sband->bitrates[status->rate_idx];
4090aa0c8636SChristian Lamparter 
4091baa951a1SJohannes Berg 	ieee80211_rx_cooked_monitor(rx, rate, res);
4092aa0c8636SChristian Lamparter }
4093aa0c8636SChristian Lamparter 
ieee80211_rx_handlers(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)4094f9e124fbSChristian Lamparter static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
4095f9e124fbSChristian Lamparter 				  struct sk_buff_head *frames)
4096aa0c8636SChristian Lamparter {
4097aa0c8636SChristian Lamparter 	ieee80211_rx_result res = RX_DROP_MONITOR;
4098aa0c8636SChristian Lamparter 	struct sk_buff *skb;
4099aa0c8636SChristian Lamparter 
4100aa0c8636SChristian Lamparter #define CALL_RXH(rxh)			\
4101aa0c8636SChristian Lamparter 	do {				\
4102aa0c8636SChristian Lamparter 		res = rxh(rx);		\
4103aa0c8636SChristian Lamparter 		if (res != RX_CONTINUE)	\
4104aa0c8636SChristian Lamparter 			goto rxh_next;  \
41058ebaa5b0SJohannes Berg 	} while (0)
4106aa0c8636SChristian Lamparter 
410745ceeee8SJohannes Berg 	/* Lock here to avoid hitting all of the data used in the RX
410845ceeee8SJohannes Berg 	 * path (e.g. key data, station data, ...) concurrently when
410945ceeee8SJohannes Berg 	 * a frame is released from the reorder buffer due to timeout
411045ceeee8SJohannes Berg 	 * from the timer, potentially concurrently with RX from the
411145ceeee8SJohannes Berg 	 * driver.
411245ceeee8SJohannes Berg 	 */
4113f9e124fbSChristian Lamparter 	spin_lock_bh(&rx->local->rx_path_lock);
411424a8fdadSChristian Lamparter 
4115f9e124fbSChristian Lamparter 	while ((skb = __skb_dequeue(frames))) {
4116aa0c8636SChristian Lamparter 		/*
4117aa0c8636SChristian Lamparter 		 * all the other fields are valid across frames
4118aa0c8636SChristian Lamparter 		 * that belong to an aMPDU since they are on the
4119aa0c8636SChristian Lamparter 		 * same TID from the same station
4120aa0c8636SChristian Lamparter 		 */
4121aa0c8636SChristian Lamparter 		rx->skb = skb;
4122aa0c8636SChristian Lamparter 
412356057da4SJohannes Berg 		if (WARN_ON_ONCE(!rx->link))
412456057da4SJohannes Berg 			goto rxh_next;
412556057da4SJohannes Berg 
41268ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_check_more_data);
41278ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll);
41288ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_sta_process);
41298ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_decrypt);
41308ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_defragment);
41318ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_michael_mic_verify);
4132aa0c8636SChristian Lamparter 		/* must be after MMIC verify so header is counted in MPDU mic */
41338ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_amsdu);
41348ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_data);
4135f9e124fbSChristian Lamparter 
4136f9e124fbSChristian Lamparter 		/* special treatment -- needs the queue */
4137f9e124fbSChristian Lamparter 		res = ieee80211_rx_h_ctrl(rx, frames);
4138f9e124fbSChristian Lamparter 		if (res != RX_CONTINUE)
4139f9e124fbSChristian Lamparter 			goto rxh_next;
4140f9e124fbSChristian Lamparter 
41418ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_mgmt_check);
41428ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_action);
41438ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_userspace_mgmt);
41441ea02224SJohannes Berg 		CALL_RXH(ieee80211_rx_h_action_post_userspace);
41458ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_action_return);
414609a740ceSThomas Pedersen 		CALL_RXH(ieee80211_rx_h_ext);
41478ebaa5b0SJohannes Berg 		CALL_RXH(ieee80211_rx_h_mgmt);
4148aa0c8636SChristian Lamparter 
4149aa0c8636SChristian Lamparter  rxh_next:
4150aa0c8636SChristian Lamparter 		ieee80211_rx_handlers_result(rx, res);
4151f9e124fbSChristian Lamparter 
4152aa0c8636SChristian Lamparter #undef CALL_RXH
4153aa0c8636SChristian Lamparter 	}
415424a8fdadSChristian Lamparter 
4155f9e124fbSChristian Lamparter 	spin_unlock_bh(&rx->local->rx_path_lock);
4156aa0c8636SChristian Lamparter }
4157571ecf67SJohannes Berg 
ieee80211_invoke_rx_handlers(struct ieee80211_rx_data * rx)41584406c376SJohannes Berg static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
415958905290SJohannes Berg {
4160f9e124fbSChristian Lamparter 	struct sk_buff_head reorder_release;
416158905290SJohannes Berg 	ieee80211_rx_result res = RX_DROP_MONITOR;
416258905290SJohannes Berg 
4163f9e124fbSChristian Lamparter 	__skb_queue_head_init(&reorder_release);
4164f9e124fbSChristian Lamparter 
416549461622SJohannes Berg #define CALL_RXH(rxh)			\
4166e32f85f7SLuis Carlos Cobo 	do {				\
416749461622SJohannes Berg 		res = rxh(rx);		\
416849461622SJohannes Berg 		if (res != RX_CONTINUE)	\
41692569a826SJohannes Berg 			goto rxh_next;  \
41708ebaa5b0SJohannes Berg 	} while (0)
417158905290SJohannes Berg 
41728ebaa5b0SJohannes Berg 	CALL_RXH(ieee80211_rx_h_check_dup);
41738ebaa5b0SJohannes Berg 	CALL_RXH(ieee80211_rx_h_check);
41742569a826SJohannes Berg 
4175f9e124fbSChristian Lamparter 	ieee80211_rx_reorder_ampdu(rx, &reorder_release);
41762569a826SJohannes Berg 
4177f9e124fbSChristian Lamparter 	ieee80211_rx_handlers(rx, &reorder_release);
4178aa0c8636SChristian Lamparter 	return;
417949461622SJohannes Berg 
41802569a826SJohannes Berg  rxh_next:
4181aa0c8636SChristian Lamparter 	ieee80211_rx_handlers_result(rx, res);
4182aa0c8636SChristian Lamparter 
4183aa0c8636SChristian Lamparter #undef CALL_RXH
41842569a826SJohannes Berg }
418558905290SJohannes Berg 
4186e66b7920SFelix Fietkau static bool
ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta * sta,u8 link_id)4187e66b7920SFelix Fietkau ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
4188e66b7920SFelix Fietkau {
4189e66b7920SFelix Fietkau 	return !!(sta->valid_links & BIT(link_id));
4190e66b7920SFelix Fietkau }
4191e66b7920SFelix Fietkau 
ieee80211_rx_data_set_link(struct ieee80211_rx_data * rx,u8 link_id)4192e66b7920SFelix Fietkau static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
4193e66b7920SFelix Fietkau 				       u8 link_id)
4194e66b7920SFelix Fietkau {
4195e66b7920SFelix Fietkau 	rx->link_id = link_id;
4196e66b7920SFelix Fietkau 	rx->link = rcu_dereference(rx->sdata->link[link_id]);
4197e66b7920SFelix Fietkau 
4198e66b7920SFelix Fietkau 	if (!rx->sta)
4199e66b7920SFelix Fietkau 		return rx->link;
4200e66b7920SFelix Fietkau 
4201e66b7920SFelix Fietkau 	if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
4202e66b7920SFelix Fietkau 		return false;
4203e66b7920SFelix Fietkau 
4204e66b7920SFelix Fietkau 	rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
4205e66b7920SFelix Fietkau 
4206e66b7920SFelix Fietkau 	return rx->link && rx->link_sta;
4207e66b7920SFelix Fietkau }
4208e66b7920SFelix Fietkau 
ieee80211_rx_data_set_sta(struct ieee80211_rx_data * rx,struct sta_info * sta,int link_id)4209e66b7920SFelix Fietkau static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
42100d846bdcSJohannes Berg 				      struct sta_info *sta, int link_id)
4211e66b7920SFelix Fietkau {
4212e66b7920SFelix Fietkau 	rx->link_id = link_id;
4213e66b7920SFelix Fietkau 	rx->sta = sta;
4214e66b7920SFelix Fietkau 
4215e66b7920SFelix Fietkau 	if (sta) {
4216e66b7920SFelix Fietkau 		rx->local = sta->sdata->local;
4217e66b7920SFelix Fietkau 		if (!rx->sdata)
4218e66b7920SFelix Fietkau 			rx->sdata = sta->sdata;
4219e66b7920SFelix Fietkau 		rx->link_sta = &sta->deflink;
4220ab5f171eSJohannes Berg 	} else {
4221ab5f171eSJohannes Berg 		rx->link_sta = NULL;
4222e66b7920SFelix Fietkau 	}
4223e66b7920SFelix Fietkau 
4224e66b7920SFelix Fietkau 	if (link_id < 0)
4225e66b7920SFelix Fietkau 		rx->link = &rx->sdata->deflink;
4226e66b7920SFelix Fietkau 	else if (!ieee80211_rx_data_set_link(rx, link_id))
4227e66b7920SFelix Fietkau 		return false;
4228e66b7920SFelix Fietkau 
4229e66b7920SFelix Fietkau 	return true;
4230e66b7920SFelix Fietkau }
4231e66b7920SFelix Fietkau 
42322bff8ebfSChristian Lamparter /*
4233dd318575SJohannes Berg  * This function makes calls into the RX path, therefore
4234dd318575SJohannes Berg  * it has to be invoked under RCU read lock.
42352bff8ebfSChristian Lamparter  */
ieee80211_release_reorder_timeout(struct sta_info * sta,int tid)42362bff8ebfSChristian Lamparter void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
42372bff8ebfSChristian Lamparter {
4238f9e124fbSChristian Lamparter 	struct sk_buff_head frames;
4239554891e6SJohannes Berg 	struct ieee80211_rx_data rx = {
42409e26297aSJohannes Berg 		/* This is OK -- must be QoS data frame */
42419e26297aSJohannes Berg 		.security_idx = tid,
42429e26297aSJohannes Berg 		.seqno_idx = tid,
4243554891e6SJohannes Berg 	};
42442c15a0cfSChristian Lamparter 	struct tid_ampdu_rx *tid_agg_rx;
4245e66b7920SFelix Fietkau 	int link_id = -1;
4246e66b7920SFelix Fietkau 
4247e66b7920SFelix Fietkau 	/* FIXME: statistics won't be right with this */
4248e66b7920SFelix Fietkau 	if (sta->sta.valid_links)
4249e66b7920SFelix Fietkau 		link_id = ffs(sta->sta.valid_links) - 1;
4250e66b7920SFelix Fietkau 
42510d846bdcSJohannes Berg 	if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
4252e66b7920SFelix Fietkau 		return;
42532c15a0cfSChristian Lamparter 
42542c15a0cfSChristian Lamparter 	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
42552c15a0cfSChristian Lamparter 	if (!tid_agg_rx)
42562c15a0cfSChristian Lamparter 		return;
42572bff8ebfSChristian Lamparter 
4258f9e124fbSChristian Lamparter 	__skb_queue_head_init(&frames);
4259f9e124fbSChristian Lamparter 
42602c15a0cfSChristian Lamparter 	spin_lock(&tid_agg_rx->reorder_lock);
4261f9e124fbSChristian Lamparter 	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
42622c15a0cfSChristian Lamparter 	spin_unlock(&tid_agg_rx->reorder_lock);
42632bff8ebfSChristian Lamparter 
4264b497de63SEmmanuel Grumbach 	if (!skb_queue_empty(&frames)) {
4265b497de63SEmmanuel Grumbach 		struct ieee80211_event event = {
4266b497de63SEmmanuel Grumbach 			.type = BA_FRAME_TIMEOUT,
4267b497de63SEmmanuel Grumbach 			.u.ba.tid = tid,
4268b497de63SEmmanuel Grumbach 			.u.ba.sta = &sta->sta,
4269b497de63SEmmanuel Grumbach 		};
4270b497de63SEmmanuel Grumbach 		drv_event_callback(rx.local, rx.sdata, &event);
4271b497de63SEmmanuel Grumbach 	}
4272b497de63SEmmanuel Grumbach 
4273f9e124fbSChristian Lamparter 	ieee80211_rx_handlers(&rx, &frames);
42742bff8ebfSChristian Lamparter }
42752bff8ebfSChristian Lamparter 
ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta * pubsta,u8 tid,u16 ssn,u64 filtered,u16 received_mpdus)427606470f74SSara Sharon void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
427706470f74SSara Sharon 					  u16 ssn, u64 filtered,
427806470f74SSara Sharon 					  u16 received_mpdus)
427906470f74SSara Sharon {
4280b98c1610SPing-Ke Shih 	struct ieee80211_local *local;
428106470f74SSara Sharon 	struct sta_info *sta;
428206470f74SSara Sharon 	struct tid_ampdu_rx *tid_agg_rx;
428306470f74SSara Sharon 	struct sk_buff_head frames;
428406470f74SSara Sharon 	struct ieee80211_rx_data rx = {
428506470f74SSara Sharon 		/* This is OK -- must be QoS data frame */
428606470f74SSara Sharon 		.security_idx = tid,
428706470f74SSara Sharon 		.seqno_idx = tid,
428806470f74SSara Sharon 	};
428906470f74SSara Sharon 	int i, diff;
429006470f74SSara Sharon 
429106470f74SSara Sharon 	if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
429206470f74SSara Sharon 		return;
429306470f74SSara Sharon 
429406470f74SSara Sharon 	__skb_queue_head_init(&frames);
429506470f74SSara Sharon 
429606470f74SSara Sharon 	sta = container_of(pubsta, struct sta_info, sta);
429706470f74SSara Sharon 
4298b98c1610SPing-Ke Shih 	local = sta->sdata->local;
4299b98c1610SPing-Ke Shih 	WARN_ONCE(local->hw.max_rx_aggregation_subframes > 64,
4300b98c1610SPing-Ke Shih 		  "RX BA marker can't support max_rx_aggregation_subframes %u > 64\n",
4301b98c1610SPing-Ke Shih 		  local->hw.max_rx_aggregation_subframes);
4302b98c1610SPing-Ke Shih 
43030d846bdcSJohannes Berg 	if (!ieee80211_rx_data_set_sta(&rx, sta, -1))
4304e66b7920SFelix Fietkau 		return;
430506470f74SSara Sharon 
430606470f74SSara Sharon 	rcu_read_lock();
430706470f74SSara Sharon 	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
430806470f74SSara Sharon 	if (!tid_agg_rx)
430906470f74SSara Sharon 		goto out;
431006470f74SSara Sharon 
431106470f74SSara Sharon 	spin_lock_bh(&tid_agg_rx->reorder_lock);
431206470f74SSara Sharon 
431306470f74SSara Sharon 	if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
431406470f74SSara Sharon 		int release;
431506470f74SSara Sharon 
431606470f74SSara Sharon 		/* release all frames in the reorder buffer */
431706470f74SSara Sharon 		release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
431806470f74SSara Sharon 			   IEEE80211_SN_MODULO;
431906470f74SSara Sharon 		ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
432006470f74SSara Sharon 						 release, &frames);
432106470f74SSara Sharon 		/* update ssn to match received ssn */
432206470f74SSara Sharon 		tid_agg_rx->head_seq_num = ssn;
432306470f74SSara Sharon 	} else {
432406470f74SSara Sharon 		ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
432506470f74SSara Sharon 						 &frames);
432606470f74SSara Sharon 	}
432706470f74SSara Sharon 
432806470f74SSara Sharon 	/* handle the case that received ssn is behind the mac ssn.
432906470f74SSara Sharon 	 * it can be tid_agg_rx->buf_size behind and still be valid */
433006470f74SSara Sharon 	diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
433106470f74SSara Sharon 	if (diff >= tid_agg_rx->buf_size) {
433206470f74SSara Sharon 		tid_agg_rx->reorder_buf_filtered = 0;
433306470f74SSara Sharon 		goto release;
433406470f74SSara Sharon 	}
433506470f74SSara Sharon 	filtered = filtered >> diff;
433606470f74SSara Sharon 	ssn += diff;
433706470f74SSara Sharon 
433806470f74SSara Sharon 	/* update bitmap */
433906470f74SSara Sharon 	for (i = 0; i < tid_agg_rx->buf_size; i++) {
434006470f74SSara Sharon 		int index = (ssn + i) % tid_agg_rx->buf_size;
434106470f74SSara Sharon 
434206470f74SSara Sharon 		tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
434306470f74SSara Sharon 		if (filtered & BIT_ULL(i))
434406470f74SSara Sharon 			tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
434506470f74SSara Sharon 	}
434606470f74SSara Sharon 
434706470f74SSara Sharon 	/* now process also frames that the filter marking released */
434806470f74SSara Sharon 	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
434906470f74SSara Sharon 
435006470f74SSara Sharon release:
435106470f74SSara Sharon 	spin_unlock_bh(&tid_agg_rx->reorder_lock);
435206470f74SSara Sharon 
435306470f74SSara Sharon 	ieee80211_rx_handlers(&rx, &frames);
435406470f74SSara Sharon 
435506470f74SSara Sharon  out:
435606470f74SSara Sharon 	rcu_read_unlock();
435706470f74SSara Sharon }
435806470f74SSara Sharon EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
435906470f74SSara Sharon 
4360571ecf67SJohannes Berg /* main receive path */
4361571ecf67SJohannes Berg 
ieee80211_bssid_match(const u8 * raddr,const u8 * addr)43627e60096fSJohannes Berg static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
43637e60096fSJohannes Berg {
43647e60096fSJohannes Berg 	return ether_addr_equal(raddr, addr) ||
43657e60096fSJohannes Berg 	       is_broadcast_ether_addr(raddr);
43667e60096fSJohannes Berg }
43677e60096fSJohannes Berg 
ieee80211_accept_frame(struct ieee80211_rx_data * rx)4368a58fbe1aSJohannes Berg static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
436923a24defSJohannes Berg {
437020b01f80SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
4371eb9fb5b8SJohannes Berg 	struct sk_buff *skb = rx->skb;
4372a58fbe1aSJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
4373eb9fb5b8SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4374eb9fb5b8SJohannes Berg 	u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
437509a740ceSThomas Pedersen 	bool multicast = is_multicast_ether_addr(hdr->addr1) ||
437609a740ceSThomas Pedersen 			 ieee80211_is_s1g_beacon(hdr->frame_control);
437723a24defSJohannes Berg 
437851fb61e7SJohannes Berg 	switch (sdata->vif.type) {
437905c914feSJohannes Berg 	case NL80211_IFTYPE_STATION:
43809bc383deSJohannes Berg 		if (!bssid && !sdata->u.mgd.use_4addr)
43813c2723f5SJohannes Berg 			return false;
4382e6f5dcb7SGilad Itzkovitch 		if (ieee80211_is_first_frag(hdr->seq_ctrl) &&
4383e6f5dcb7SGilad Itzkovitch 		    ieee80211_is_robust_mgmt_frame(skb) && !rx->sta)
4384588f7d39SJohannes Berg 			return false;
4385a58fbe1aSJohannes Berg 		if (multicast)
4386a58fbe1aSJohannes Berg 			return true;
4387892b3bceSJohannes Berg 		return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id);
438805c914feSJohannes Berg 	case NL80211_IFTYPE_ADHOC:
438923a24defSJohannes Berg 		if (!bssid)
43903c2723f5SJohannes Berg 			return false;
43916329b8d9SFelix Fietkau 		if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
4392a6555f84SYueHaibing 		    ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2) ||
4393a6555f84SYueHaibing 		    !is_valid_ether_addr(hdr->addr2))
43943c2723f5SJohannes Berg 			return false;
4395a58fbe1aSJohannes Berg 		if (ieee80211_is_beacon(hdr->frame_control))
43963c2723f5SJohannes Berg 			return true;
4397a58fbe1aSJohannes Berg 		if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
43983c2723f5SJohannes Berg 			return false;
4399a58fbe1aSJohannes Berg 		if (!multicast &&
4400a58fbe1aSJohannes Berg 		    !ether_addr_equal(sdata->vif.addr, hdr->addr1))
44013c2723f5SJohannes Berg 			return false;
4402a58fbe1aSJohannes Berg 		if (!rx->sta) {
44030fb8ca45SJouni Malinen 			int rate_idx;
4404da6a4352SJohannes Berg 			if (status->encoding != RX_ENC_LEGACY)
44055614618eSJohannes Berg 				rate_idx = 0; /* TODO: HT/VHT rates */
44060fb8ca45SJouni Malinen 			else
4407eb9fb5b8SJohannes Berg 				rate_idx = status->rate_idx;
44088bf11d8dSJohannes Berg 			ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
44098bf11d8dSJohannes Berg 						 BIT(rate_idx));
44100fb8ca45SJouni Malinen 		}
4411a58fbe1aSJohannes Berg 		return true;
4412239281f8SRostislav Lisovy 	case NL80211_IFTYPE_OCB:
4413239281f8SRostislav Lisovy 		if (!bssid)
4414239281f8SRostislav Lisovy 			return false;
4415cc117298SBertold Van den Bergh 		if (!ieee80211_is_data_present(hdr->frame_control))
4416239281f8SRostislav Lisovy 			return false;
4417a58fbe1aSJohannes Berg 		if (!is_broadcast_ether_addr(bssid))
4418239281f8SRostislav Lisovy 			return false;
4419a58fbe1aSJohannes Berg 		if (!multicast &&
4420a58fbe1aSJohannes Berg 		    !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
4421239281f8SRostislav Lisovy 			return false;
4422a58fbe1aSJohannes Berg 		if (!rx->sta) {
4423239281f8SRostislav Lisovy 			int rate_idx;
4424da6a4352SJohannes Berg 			if (status->encoding != RX_ENC_LEGACY)
4425239281f8SRostislav Lisovy 				rate_idx = 0; /* TODO: HT rates */
4426239281f8SRostislav Lisovy 			else
4427239281f8SRostislav Lisovy 				rate_idx = status->rate_idx;
4428239281f8SRostislav Lisovy 			ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
4429239281f8SRostislav Lisovy 						BIT(rate_idx));
4430239281f8SRostislav Lisovy 		}
4431a58fbe1aSJohannes Berg 		return true;
443205c914feSJohannes Berg 	case NL80211_IFTYPE_MESH_POINT:
4433736a80bbSJohannes Berg 		if (ether_addr_equal(sdata->vif.addr, hdr->addr2))
4434736a80bbSJohannes Berg 			return false;
4435a58fbe1aSJohannes Berg 		if (multicast)
4436a58fbe1aSJohannes Berg 			return true;
4437a58fbe1aSJohannes Berg 		return ether_addr_equal(sdata->vif.addr, hdr->addr1);
443805c914feSJohannes Berg 	case NL80211_IFTYPE_AP_VLAN:
443905c914feSJohannes Berg 	case NL80211_IFTYPE_AP:
4440a58fbe1aSJohannes Berg 		if (!bssid)
4441892b3bceSJohannes Berg 			return ieee80211_is_our_addr(sdata, hdr->addr1,
4442892b3bceSJohannes Berg 						     &rx->link_id);
4443a58fbe1aSJohannes Berg 
4444892b3bceSJohannes Berg 		if (!is_broadcast_ether_addr(bssid) &&
4445892b3bceSJohannes Berg 		    !ieee80211_is_our_addr(sdata, bssid, NULL)) {
44463df6eaeaSJohannes Berg 			/*
44473df6eaeaSJohannes Berg 			 * Accept public action frames even when the
44483df6eaeaSJohannes Berg 			 * BSSID doesn't match, this is used for P2P
44493df6eaeaSJohannes Berg 			 * and location updates. Note that mac80211
44503df6eaeaSJohannes Berg 			 * itself never looks at these frames.
44513df6eaeaSJohannes Berg 			 */
44522b9ccd4eSJohannes Berg 			if (!multicast &&
4453892b3bceSJohannes Berg 			    !ieee80211_is_our_addr(sdata, hdr->addr1,
4454892b3bceSJohannes Berg 						   &rx->link_id))
44553c2723f5SJohannes Berg 				return false;
4456d48b2968SJohannes Berg 			if (ieee80211_is_public_action(hdr, skb->len))
44573c2723f5SJohannes Berg 				return true;
44585c90067cSJohannes Berg 			return ieee80211_is_beacon(hdr->frame_control);
4459a58fbe1aSJohannes Berg 		}
4460a58fbe1aSJohannes Berg 
4461a58fbe1aSJohannes Berg 		if (!ieee80211_has_tods(hdr->frame_control)) {
4462db8e1732SArik Nemtsov 			/* ignore data frames to TDLS-peers */
4463db8e1732SArik Nemtsov 			if (ieee80211_is_data(hdr->frame_control))
4464db8e1732SArik Nemtsov 				return false;
4465db8e1732SArik Nemtsov 			/* ignore action frames to TDLS-peers */
4466db8e1732SArik Nemtsov 			if (ieee80211_is_action(hdr->frame_control) &&
44671ec7bae8SJouni Malinen 			    !is_broadcast_ether_addr(bssid) &&
4468db8e1732SArik Nemtsov 			    !ether_addr_equal(bssid, hdr->addr1))
4469db8e1732SArik Nemtsov 				return false;
447023a24defSJohannes Berg 		}
44713018e947SJohannes Berg 
44723018e947SJohannes Berg 		/*
44733018e947SJohannes Berg 		 * 802.11-2016 Table 9-26 says that for data frames, A1 must be
44743018e947SJohannes Berg 		 * the BSSID - we've checked that already but may have accepted
44753018e947SJohannes Berg 		 * the wildcard (ff:ff:ff:ff:ff:ff).
44763018e947SJohannes Berg 		 *
44773018e947SJohannes Berg 		 * It also says:
44783018e947SJohannes Berg 		 *	The BSSID of the Data frame is determined as follows:
44793018e947SJohannes Berg 		 *	a) If the STA is contained within an AP or is associated
44803018e947SJohannes Berg 		 *	   with an AP, the BSSID is the address currently in use
44813018e947SJohannes Berg 		 *	   by the STA contained in the AP.
44823018e947SJohannes Berg 		 *
44833018e947SJohannes Berg 		 * So we should not accept data frames with an address that's
44843018e947SJohannes Berg 		 * multicast.
44853018e947SJohannes Berg 		 *
44863018e947SJohannes Berg 		 * Accepting it also opens a security problem because stations
44873018e947SJohannes Berg 		 * could encrypt it with the GTK and inject traffic that way.
44883018e947SJohannes Berg 		 */
44893018e947SJohannes Berg 		if (ieee80211_is_data(hdr->frame_control) && multicast)
44903018e947SJohannes Berg 			return false;
44913018e947SJohannes Berg 
4492a58fbe1aSJohannes Berg 		return true;
4493f142c6b9SJohannes Berg 	case NL80211_IFTYPE_P2P_DEVICE:
4494a58fbe1aSJohannes Berg 		return ieee80211_is_public_action(hdr, skb->len) ||
4495a58fbe1aSJohannes Berg 		       ieee80211_is_probe_req(hdr->frame_control) ||
4496a58fbe1aSJohannes Berg 		       ieee80211_is_probe_resp(hdr->frame_control) ||
4497a58fbe1aSJohannes Berg 		       ieee80211_is_beacon(hdr->frame_control);
4498cb3b7d87SAyala Beker 	case NL80211_IFTYPE_NAN:
4499cb3b7d87SAyala Beker 		/* Currently no frames on NAN interface are allowed */
4500cb3b7d87SAyala Beker 		return false;
45012ca27bcfSJohannes Berg 	default:
4502fb1c1cd6SJohannes Berg 		break;
450323a24defSJohannes Berg 	}
450423a24defSJohannes Berg 
4505a58fbe1aSJohannes Berg 	WARN_ON_ONCE(1);
4506a58fbe1aSJohannes Berg 	return false;
450723a24defSJohannes Berg }
450823a24defSJohannes Berg 
ieee80211_check_fast_rx(struct sta_info * sta)450949ddf8e6SJohannes Berg void ieee80211_check_fast_rx(struct sta_info *sta)
451049ddf8e6SJohannes Berg {
451149ddf8e6SJohannes Berg 	struct ieee80211_sub_if_data *sdata = sta->sdata;
451249ddf8e6SJohannes Berg 	struct ieee80211_local *local = sdata->local;
451349ddf8e6SJohannes Berg 	struct ieee80211_key *key;
451449ddf8e6SJohannes Berg 	struct ieee80211_fast_rx fastrx = {
451549ddf8e6SJohannes Berg 		.dev = sdata->dev,
451649ddf8e6SJohannes Berg 		.vif_type = sdata->vif.type,
451749ddf8e6SJohannes Berg 		.control_port_protocol = sdata->control_port_protocol,
451849ddf8e6SJohannes Berg 	}, *old, *new = NULL;
45193bf9e30eSFelix Fietkau 	u32 offload_flags;
452080a915ecSFelix Fietkau 	bool set_offload = false;
452149ddf8e6SJohannes Berg 	bool assign = false;
452280a915ecSFelix Fietkau 	bool offload;
452349ddf8e6SJohannes Berg 
452449ddf8e6SJohannes Berg 	/* use sparse to check that we don't return without updating */
452549ddf8e6SJohannes Berg 	__acquire(check_fast_rx);
452649ddf8e6SJohannes Berg 
452749ddf8e6SJohannes Berg 	BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header));
452849ddf8e6SJohannes Berg 	BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN);
452949ddf8e6SJohannes Berg 	ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
453049ddf8e6SJohannes Berg 	ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);
453149ddf8e6SJohannes Berg 
4532c9c5962bSJohannes Berg 	fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS);
4533c9c5962bSJohannes Berg 
453449ddf8e6SJohannes Berg 	/* fast-rx doesn't do reordering */
453549ddf8e6SJohannes Berg 	if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
453649ddf8e6SJohannes Berg 	    !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
453749ddf8e6SJohannes Berg 		goto clear;
453849ddf8e6SJohannes Berg 
453949ddf8e6SJohannes Berg 	switch (sdata->vif.type) {
454049ddf8e6SJohannes Berg 	case NL80211_IFTYPE_STATION:
454149ddf8e6SJohannes Berg 		if (sta->sta.tdls) {
454249ddf8e6SJohannes Berg 			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
454349ddf8e6SJohannes Berg 			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
454449ddf8e6SJohannes Berg 			fastrx.expected_ds_bits = 0;
454549ddf8e6SJohannes Berg 		} else {
454649ddf8e6SJohannes Berg 			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
454749ddf8e6SJohannes Berg 			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
454849ddf8e6SJohannes Berg 			fastrx.expected_ds_bits =
454949ddf8e6SJohannes Berg 				cpu_to_le16(IEEE80211_FCTL_FROMDS);
455049ddf8e6SJohannes Berg 		}
45511d870162SFelix Fietkau 
45529251a473SFelix Fietkau 		if (sdata->u.mgd.use_4addr && !sta->sta.tdls) {
45539251a473SFelix Fietkau 			fastrx.expected_ds_bits |=
45549251a473SFelix Fietkau 				cpu_to_le16(IEEE80211_FCTL_TODS);
45559251a473SFelix Fietkau 			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
45569251a473SFelix Fietkau 			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
45579251a473SFelix Fietkau 		}
45589251a473SFelix Fietkau 
45591d870162SFelix Fietkau 		if (!sdata->u.mgd.powersave)
45601d870162SFelix Fietkau 			break;
45611d870162SFelix Fietkau 
45621d870162SFelix Fietkau 		/* software powersave is a huge mess, avoid all of it */
45631d870162SFelix Fietkau 		if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
45641d870162SFelix Fietkau 			goto clear;
45651d870162SFelix Fietkau 		if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
45661d870162SFelix Fietkau 		    !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
45671d870162SFelix Fietkau 			goto clear;
456849ddf8e6SJohannes Berg 		break;
456949ddf8e6SJohannes Berg 	case NL80211_IFTYPE_AP_VLAN:
457049ddf8e6SJohannes Berg 	case NL80211_IFTYPE_AP:
457149ddf8e6SJohannes Berg 		/* parallel-rx requires this, at least with calls to
457249ddf8e6SJohannes Berg 		 * ieee80211_sta_ps_transition()
457349ddf8e6SJohannes Berg 		 */
457449ddf8e6SJohannes Berg 		if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
457549ddf8e6SJohannes Berg 			goto clear;
457649ddf8e6SJohannes Berg 		fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
457749ddf8e6SJohannes Berg 		fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
457849ddf8e6SJohannes Berg 		fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS);
457949ddf8e6SJohannes Berg 
458049ddf8e6SJohannes Berg 		fastrx.internal_forward =
458149ddf8e6SJohannes Berg 			!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
458249ddf8e6SJohannes Berg 			(sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
458349ddf8e6SJohannes Berg 			 !sdata->u.vlan.sta);
458459cae5b9SFelix Fietkau 
458559cae5b9SFelix Fietkau 		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
458659cae5b9SFelix Fietkau 		    sdata->u.vlan.sta) {
458759cae5b9SFelix Fietkau 			fastrx.expected_ds_bits |=
458859cae5b9SFelix Fietkau 				cpu_to_le16(IEEE80211_FCTL_FROMDS);
458959cae5b9SFelix Fietkau 			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
459059cae5b9SFelix Fietkau 			fastrx.internal_forward = 0;
459159cae5b9SFelix Fietkau 		}
459259cae5b9SFelix Fietkau 
459349ddf8e6SJohannes Berg 		break;
45943468e1e0SFelix Fietkau 	case NL80211_IFTYPE_MESH_POINT:
45953468e1e0SFelix Fietkau 		fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
45963468e1e0SFelix Fietkau 						      IEEE80211_FCTL_TODS);
45973468e1e0SFelix Fietkau 		fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
45983468e1e0SFelix Fietkau 		fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
45993468e1e0SFelix Fietkau 		break;
460049ddf8e6SJohannes Berg 	default:
460149ddf8e6SJohannes Berg 		goto clear;
460249ddf8e6SJohannes Berg 	}
460349ddf8e6SJohannes Berg 
460449ddf8e6SJohannes Berg 	if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
460549ddf8e6SJohannes Berg 		goto clear;
460649ddf8e6SJohannes Berg 
460749ddf8e6SJohannes Berg 	rcu_read_lock();
460849ddf8e6SJohannes Berg 	key = rcu_dereference(sta->ptk[sta->ptk_idx]);
4609622d3b4eSFelix Fietkau 	if (!key)
4610622d3b4eSFelix Fietkau 		key = rcu_dereference(sdata->default_unicast_key);
461149ddf8e6SJohannes Berg 	if (key) {
461249ddf8e6SJohannes Berg 		switch (key->conf.cipher) {
461349ddf8e6SJohannes Berg 		case WLAN_CIPHER_SUITE_TKIP:
461449ddf8e6SJohannes Berg 			/* we don't want to deal with MMIC in fast-rx */
461549ddf8e6SJohannes Berg 			goto clear_rcu;
461649ddf8e6SJohannes Berg 		case WLAN_CIPHER_SUITE_CCMP:
461749ddf8e6SJohannes Berg 		case WLAN_CIPHER_SUITE_CCMP_256:
461849ddf8e6SJohannes Berg 		case WLAN_CIPHER_SUITE_GCMP:
461949ddf8e6SJohannes Berg 		case WLAN_CIPHER_SUITE_GCMP_256:
462049ddf8e6SJohannes Berg 			break;
462149ddf8e6SJohannes Berg 		default:
462296fc6efbSAlexander Wetzel 			/* We also don't want to deal with
462396fc6efbSAlexander Wetzel 			 * WEP or cipher scheme.
462449ddf8e6SJohannes Berg 			 */
462549ddf8e6SJohannes Berg 			goto clear_rcu;
462649ddf8e6SJohannes Berg 		}
462749ddf8e6SJohannes Berg 
462849ddf8e6SJohannes Berg 		fastrx.key = true;
462949ddf8e6SJohannes Berg 		fastrx.icv_len = key->conf.icv_len;
463049ddf8e6SJohannes Berg 	}
463149ddf8e6SJohannes Berg 
463249ddf8e6SJohannes Berg 	assign = true;
463349ddf8e6SJohannes Berg  clear_rcu:
463449ddf8e6SJohannes Berg 	rcu_read_unlock();
463549ddf8e6SJohannes Berg  clear:
463649ddf8e6SJohannes Berg 	__release(check_fast_rx);
463749ddf8e6SJohannes Berg 
463849ddf8e6SJohannes Berg 	if (assign)
463949ddf8e6SJohannes Berg 		new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
464049ddf8e6SJohannes Berg 
46413bf9e30eSFelix Fietkau 	offload_flags = get_bss_sdata(sdata)->vif.offload_flags;
46423bf9e30eSFelix Fietkau 	offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED;
464380a915ecSFelix Fietkau 
46443bf9e30eSFelix Fietkau 	if (assign && offload)
464580a915ecSFelix Fietkau 		set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
464680a915ecSFelix Fietkau 	else
464780a915ecSFelix Fietkau 		set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
464880a915ecSFelix Fietkau 
464980a915ecSFelix Fietkau 	if (set_offload)
465080a915ecSFelix Fietkau 		drv_sta_set_decap_offload(local, sdata, &sta->sta, assign);
465180a915ecSFelix Fietkau 
465249ddf8e6SJohannes Berg 	spin_lock_bh(&sta->lock);
465349ddf8e6SJohannes Berg 	old = rcu_dereference_protected(sta->fast_rx, true);
465449ddf8e6SJohannes Berg 	rcu_assign_pointer(sta->fast_rx, new);
465549ddf8e6SJohannes Berg 	spin_unlock_bh(&sta->lock);
465649ddf8e6SJohannes Berg 
465749ddf8e6SJohannes Berg 	if (old)
465849ddf8e6SJohannes Berg 		kfree_rcu(old, rcu_head);
465949ddf8e6SJohannes Berg }
466049ddf8e6SJohannes Berg 
ieee80211_clear_fast_rx(struct sta_info * sta)466149ddf8e6SJohannes Berg void ieee80211_clear_fast_rx(struct sta_info *sta)
466249ddf8e6SJohannes Berg {
466349ddf8e6SJohannes Berg 	struct ieee80211_fast_rx *old;
466449ddf8e6SJohannes Berg 
466549ddf8e6SJohannes Berg 	spin_lock_bh(&sta->lock);
466649ddf8e6SJohannes Berg 	old = rcu_dereference_protected(sta->fast_rx, true);
466749ddf8e6SJohannes Berg 	RCU_INIT_POINTER(sta->fast_rx, NULL);
466849ddf8e6SJohannes Berg 	spin_unlock_bh(&sta->lock);
466949ddf8e6SJohannes Berg 
467049ddf8e6SJohannes Berg 	if (old)
467149ddf8e6SJohannes Berg 		kfree_rcu(old, rcu_head);
467249ddf8e6SJohannes Berg }
467349ddf8e6SJohannes Berg 
__ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data * sdata)467449ddf8e6SJohannes Berg void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
467549ddf8e6SJohannes Berg {
467649ddf8e6SJohannes Berg 	struct ieee80211_local *local = sdata->local;
467749ddf8e6SJohannes Berg 	struct sta_info *sta;
467849ddf8e6SJohannes Berg 
467949ddf8e6SJohannes Berg 	lockdep_assert_held(&local->sta_mtx);
468049ddf8e6SJohannes Berg 
4681253216ffSMadhuparna Bhowmik 	list_for_each_entry(sta, &local->sta_list, list) {
468249ddf8e6SJohannes Berg 		if (sdata != sta->sdata &&
468349ddf8e6SJohannes Berg 		    (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
468449ddf8e6SJohannes Berg 			continue;
468549ddf8e6SJohannes Berg 		ieee80211_check_fast_rx(sta);
468649ddf8e6SJohannes Berg 	}
468749ddf8e6SJohannes Berg }
468849ddf8e6SJohannes Berg 
ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data * sdata)468949ddf8e6SJohannes Berg void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
469049ddf8e6SJohannes Berg {
469149ddf8e6SJohannes Berg 	struct ieee80211_local *local = sdata->local;
469249ddf8e6SJohannes Berg 
469349ddf8e6SJohannes Berg 	mutex_lock(&local->sta_mtx);
469449ddf8e6SJohannes Berg 	__ieee80211_check_fast_rx_iface(sdata);
469549ddf8e6SJohannes Berg 	mutex_unlock(&local->sta_mtx);
469649ddf8e6SJohannes Berg }
469749ddf8e6SJohannes Berg 
ieee80211_rx_8023(struct ieee80211_rx_data * rx,struct ieee80211_fast_rx * fast_rx,int orig_len)469880a915ecSFelix Fietkau static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
469980a915ecSFelix Fietkau 			      struct ieee80211_fast_rx *fast_rx,
470080a915ecSFelix Fietkau 			      int orig_len)
470180a915ecSFelix Fietkau {
470280a915ecSFelix Fietkau 	struct ieee80211_sta_rx_stats *stats;
470380a915ecSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
470480a915ecSFelix Fietkau 	struct sta_info *sta = rx->sta;
470543635a5aSVasanthakumar Thiagarajan 	struct link_sta_info *link_sta;
470680a915ecSFelix Fietkau 	struct sk_buff *skb = rx->skb;
470780a915ecSFelix Fietkau 	void *sa = skb->data + ETH_ALEN;
470880a915ecSFelix Fietkau 	void *da = skb->data;
470980a915ecSFelix Fietkau 
471043635a5aSVasanthakumar Thiagarajan 	if (rx->link_id >= 0) {
471143635a5aSVasanthakumar Thiagarajan 		link_sta = rcu_dereference(sta->link[rx->link_id]);
471243635a5aSVasanthakumar Thiagarajan 		if (WARN_ON_ONCE(!link_sta)) {
471343635a5aSVasanthakumar Thiagarajan 			dev_kfree_skb(rx->skb);
471443635a5aSVasanthakumar Thiagarajan 			return;
471543635a5aSVasanthakumar Thiagarajan 		}
471643635a5aSVasanthakumar Thiagarajan 	} else {
471743635a5aSVasanthakumar Thiagarajan 		link_sta = &sta->deflink;
471843635a5aSVasanthakumar Thiagarajan 	}
471943635a5aSVasanthakumar Thiagarajan 
472043635a5aSVasanthakumar Thiagarajan 	stats = &link_sta->rx_stats;
472180a915ecSFelix Fietkau 	if (fast_rx->uses_rss)
472243635a5aSVasanthakumar Thiagarajan 		stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
472380a915ecSFelix Fietkau 
472480a915ecSFelix Fietkau 	/* statistics part of ieee80211_rx_h_sta_process() */
472580a915ecSFelix Fietkau 	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
472680a915ecSFelix Fietkau 		stats->last_signal = status->signal;
472780a915ecSFelix Fietkau 		if (!fast_rx->uses_rss)
472843635a5aSVasanthakumar Thiagarajan 			ewma_signal_add(&link_sta->rx_stats_avg.signal,
472980a915ecSFelix Fietkau 					-status->signal);
473080a915ecSFelix Fietkau 	}
473180a915ecSFelix Fietkau 
473280a915ecSFelix Fietkau 	if (status->chains) {
473380a915ecSFelix Fietkau 		int i;
473480a915ecSFelix Fietkau 
473580a915ecSFelix Fietkau 		stats->chains = status->chains;
473680a915ecSFelix Fietkau 		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
473780a915ecSFelix Fietkau 			int signal = status->chain_signal[i];
473880a915ecSFelix Fietkau 
473980a915ecSFelix Fietkau 			if (!(status->chains & BIT(i)))
474080a915ecSFelix Fietkau 				continue;
474180a915ecSFelix Fietkau 
474280a915ecSFelix Fietkau 			stats->chain_signal_last[i] = signal;
474380a915ecSFelix Fietkau 			if (!fast_rx->uses_rss)
474443635a5aSVasanthakumar Thiagarajan 				ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
474580a915ecSFelix Fietkau 						-signal);
474680a915ecSFelix Fietkau 		}
474780a915ecSFelix Fietkau 	}
474880a915ecSFelix Fietkau 	/* end of statistics */
474980a915ecSFelix Fietkau 
475080a915ecSFelix Fietkau 	stats->last_rx = jiffies;
475180a915ecSFelix Fietkau 	stats->last_rate = sta_stats_encode_rate(status);
475280a915ecSFelix Fietkau 
475380a915ecSFelix Fietkau 	stats->fragments++;
475480a915ecSFelix Fietkau 	stats->packets++;
475580a915ecSFelix Fietkau 
475680a915ecSFelix Fietkau 	skb->dev = fast_rx->dev;
475780a915ecSFelix Fietkau 
475880a915ecSFelix Fietkau 	dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
475980a915ecSFelix Fietkau 
476080a915ecSFelix Fietkau 	/* The seqno index has the same property as needed
476180a915ecSFelix Fietkau 	 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
476280a915ecSFelix Fietkau 	 * for non-QoS-data frames. Here we know it's a data
476380a915ecSFelix Fietkau 	 * frame, so count MSDUs.
476480a915ecSFelix Fietkau 	 */
476580a915ecSFelix Fietkau 	u64_stats_update_begin(&stats->syncp);
476680a915ecSFelix Fietkau 	stats->msdu[rx->seqno_idx]++;
476780a915ecSFelix Fietkau 	stats->bytes += orig_len;
476880a915ecSFelix Fietkau 	u64_stats_update_end(&stats->syncp);
476980a915ecSFelix Fietkau 
477080a915ecSFelix Fietkau 	if (fast_rx->internal_forward) {
477180a915ecSFelix Fietkau 		struct sk_buff *xmit_skb = NULL;
477280a915ecSFelix Fietkau 		if (is_multicast_ether_addr(da)) {
477380a915ecSFelix Fietkau 			xmit_skb = skb_copy(skb, GFP_ATOMIC);
477480a915ecSFelix Fietkau 		} else if (!ether_addr_equal(da, sa) &&
477580a915ecSFelix Fietkau 			   sta_info_get(rx->sdata, da)) {
477680a915ecSFelix Fietkau 			xmit_skb = skb;
477780a915ecSFelix Fietkau 			skb = NULL;
477880a915ecSFelix Fietkau 		}
477980a915ecSFelix Fietkau 
478080a915ecSFelix Fietkau 		if (xmit_skb) {
478180a915ecSFelix Fietkau 			/*
478280a915ecSFelix Fietkau 			 * Send to wireless media and increase priority by 256
478380a915ecSFelix Fietkau 			 * to keep the received priority instead of
478480a915ecSFelix Fietkau 			 * reclassifying the frame (see cfg80211_classify8021d).
478580a915ecSFelix Fietkau 			 */
478680a915ecSFelix Fietkau 			xmit_skb->priority += 256;
478780a915ecSFelix Fietkau 			xmit_skb->protocol = htons(ETH_P_802_3);
478880a915ecSFelix Fietkau 			skb_reset_network_header(xmit_skb);
478980a915ecSFelix Fietkau 			skb_reset_mac_header(xmit_skb);
479080a915ecSFelix Fietkau 			dev_queue_xmit(xmit_skb);
479180a915ecSFelix Fietkau 		}
479280a915ecSFelix Fietkau 
479380a915ecSFelix Fietkau 		if (!skb)
479480a915ecSFelix Fietkau 			return;
479580a915ecSFelix Fietkau 	}
479680a915ecSFelix Fietkau 
479780a915ecSFelix Fietkau 	/* deliver to local stack */
479880a915ecSFelix Fietkau 	skb->protocol = eth_type_trans(skb, fast_rx->dev);
4799610d086dSDeren Wu 	ieee80211_deliver_skb_to_local_stack(skb, rx);
480080a915ecSFelix Fietkau }
480180a915ecSFelix Fietkau 
ieee80211_invoke_fast_rx(struct ieee80211_rx_data * rx,struct ieee80211_fast_rx * fast_rx)480249ddf8e6SJohannes Berg static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
480349ddf8e6SJohannes Berg 				     struct ieee80211_fast_rx *fast_rx)
480449ddf8e6SJohannes Berg {
480549ddf8e6SJohannes Berg 	struct sk_buff *skb = rx->skb;
480649ddf8e6SJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
480749ddf8e6SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
48083468e1e0SFelix Fietkau 	static ieee80211_rx_result res;
480949ddf8e6SJohannes Berg 	int orig_len = skb->len;
481024bba078SFelix Fietkau 	int hdrlen = ieee80211_hdrlen(hdr->frame_control);
481124bba078SFelix Fietkau 	int snap_offs = hdrlen;
481249ddf8e6SJohannes Berg 	struct {
481349ddf8e6SJohannes Berg 		u8 snap[sizeof(rfc1042_header)];
481449ddf8e6SJohannes Berg 		__be16 proto;
481549ddf8e6SJohannes Berg 	} *payload __aligned(2);
481649ddf8e6SJohannes Berg 	struct {
481749ddf8e6SJohannes Berg 		u8 da[ETH_ALEN];
481849ddf8e6SJohannes Berg 		u8 sa[ETH_ALEN];
481949ddf8e6SJohannes Berg 	} addrs __aligned(2);
482043635a5aSVasanthakumar Thiagarajan 	struct ieee80211_sta_rx_stats *stats;
4821c9c5962bSJohannes Berg 
482249ddf8e6SJohannes Berg 	/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
482349ddf8e6SJohannes Berg 	 * to a common data structure; drivers can implement that per queue
482449ddf8e6SJohannes Berg 	 * but we don't have that information in mac80211
482549ddf8e6SJohannes Berg 	 */
482649ddf8e6SJohannes Berg 	if (!(status->flag & RX_FLAG_DUP_VALIDATED))
482749ddf8e6SJohannes Berg 		return false;
482849ddf8e6SJohannes Berg 
482949ddf8e6SJohannes Berg #define FAST_RX_CRYPT_FLAGS	(RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED)
483049ddf8e6SJohannes Berg 
483149ddf8e6SJohannes Berg 	/* If using encryption, we also need to have:
483249ddf8e6SJohannes Berg 	 *  - PN_VALIDATED: similar, but the implementation is tricky
483349ddf8e6SJohannes Berg 	 *  - DECRYPTED: necessary for PN_VALIDATED
483449ddf8e6SJohannes Berg 	 */
483549ddf8e6SJohannes Berg 	if (fast_rx->key &&
483649ddf8e6SJohannes Berg 	    (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS)
483749ddf8e6SJohannes Berg 		return false;
483849ddf8e6SJohannes Berg 
483949ddf8e6SJohannes Berg 	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
484049ddf8e6SJohannes Berg 		return false;
484149ddf8e6SJohannes Berg 
484249ddf8e6SJohannes Berg 	if (unlikely(ieee80211_is_frag(hdr)))
484349ddf8e6SJohannes Berg 		return false;
484449ddf8e6SJohannes Berg 
484549ddf8e6SJohannes Berg 	/* Since our interface address cannot be multicast, this
484649ddf8e6SJohannes Berg 	 * implicitly also rejects multicast frames without the
484749ddf8e6SJohannes Berg 	 * explicit check.
484849ddf8e6SJohannes Berg 	 *
484949ddf8e6SJohannes Berg 	 * We shouldn't get any *data* frames not addressed to us
485049ddf8e6SJohannes Berg 	 * (AP mode will accept multicast *management* frames), but
485149ddf8e6SJohannes Berg 	 * punting here will make it go through the full checks in
485249ddf8e6SJohannes Berg 	 * ieee80211_accept_frame().
485349ddf8e6SJohannes Berg 	 */
485449ddf8e6SJohannes Berg 	if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1))
485549ddf8e6SJohannes Berg 		return false;
485649ddf8e6SJohannes Berg 
485749ddf8e6SJohannes Berg 	if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
485849ddf8e6SJohannes Berg 					      IEEE80211_FCTL_TODS)) !=
485949ddf8e6SJohannes Berg 	    fast_rx->expected_ds_bits)
4860b323ac19SFelix Fietkau 		return false;
486149ddf8e6SJohannes Berg 
486249ddf8e6SJohannes Berg 	/* assign the key to drop unencrypted frames (later)
486349ddf8e6SJohannes Berg 	 * and strip the IV/MIC if necessary
486449ddf8e6SJohannes Berg 	 */
486549ddf8e6SJohannes Berg 	if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) {
486649ddf8e6SJohannes Berg 		/* GCMP header length is the same */
486749ddf8e6SJohannes Berg 		snap_offs += IEEE80211_CCMP_HDR_LEN;
486849ddf8e6SJohannes Berg 	}
486949ddf8e6SJohannes Berg 
48703468e1e0SFelix Fietkau 	if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
48713468e1e0SFelix Fietkau 	    !(status->rx_flags & IEEE80211_RX_AMSDU)) {
487249ddf8e6SJohannes Berg 		if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
4873f5369dcfSFelix Fietkau 			return false;
487424bba078SFelix Fietkau 
487549ddf8e6SJohannes Berg 		payload = (void *)(skb->data + snap_offs);
487649ddf8e6SJohannes Berg 
487749ddf8e6SJohannes Berg 		if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr))
487849ddf8e6SJohannes Berg 			return false;
487949ddf8e6SJohannes Berg 
488049ddf8e6SJohannes Berg 		/* Don't handle these here since they require special code.
488149ddf8e6SJohannes Berg 		 * Accept AARP and IPX even though they should come with a
488249ddf8e6SJohannes Berg 		 * bridge-tunnel header - but if we get them this way then
488349ddf8e6SJohannes Berg 		 * there's little point in discarding them.
488449ddf8e6SJohannes Berg 		 */
488549ddf8e6SJohannes Berg 		if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) ||
488649ddf8e6SJohannes Berg 			     payload->proto == fast_rx->control_port_protocol))
488749ddf8e6SJohannes Berg 			return false;
488824bba078SFelix Fietkau 	}
488949ddf8e6SJohannes Berg 
489049ddf8e6SJohannes Berg 	/* after this point, don't punt to the slowpath! */
489149ddf8e6SJohannes Berg 
489249ddf8e6SJohannes Berg 	if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
489349ddf8e6SJohannes Berg 	    pskb_trim(skb, skb->len - fast_rx->icv_len))
489449ddf8e6SJohannes Berg 		goto drop;
489549ddf8e6SJohannes Berg 
489649ddf8e6SJohannes Berg 	if (rx->key && !ieee80211_has_protected(hdr->frame_control))
489749ddf8e6SJohannes Berg 		goto drop;
489849ddf8e6SJohannes Berg 
489924bba078SFelix Fietkau 	if (status->rx_flags & IEEE80211_RX_AMSDU) {
490024bba078SFelix Fietkau 		if (__ieee80211_rx_h_amsdu(rx, snap_offs - hdrlen) !=
490124bba078SFelix Fietkau 		    RX_QUEUED)
490224bba078SFelix Fietkau 			goto drop;
490324bba078SFelix Fietkau 
490424bba078SFelix Fietkau 		return true;
490524bba078SFelix Fietkau 	}
490624bba078SFelix Fietkau 
490749ddf8e6SJohannes Berg 	/* do the header conversion - first grab the addresses */
490849ddf8e6SJohannes Berg 	ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
490949ddf8e6SJohannes Berg 	ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
49103468e1e0SFelix Fietkau 	if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
49113468e1e0SFelix Fietkau 	    skb_pull(skb, snap_offs - 2);
49123468e1e0SFelix Fietkau 	    put_unaligned_be16(skb->len - 2, skb->data);
49133468e1e0SFelix Fietkau 	} else {
4914667aa742SJohannes Berg 	    skb_postpull_rcsum(skb, skb->data + snap_offs,
4915667aa742SJohannes Berg 			       sizeof(rfc1042_header) + 2);
49163468e1e0SFelix Fietkau 
491749ddf8e6SJohannes Berg 	    /* remove the SNAP but leave the ethertype */
491849ddf8e6SJohannes Berg 	    skb_pull(skb, snap_offs + sizeof(rfc1042_header));
49193468e1e0SFelix Fietkau 	}
492049ddf8e6SJohannes Berg 	/* push the addresses in front */
492149ddf8e6SJohannes Berg 	memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
492249ddf8e6SJohannes Berg 
49233468e1e0SFelix Fietkau 	res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
49243468e1e0SFelix Fietkau 	switch (res) {
49253468e1e0SFelix Fietkau 	case RX_QUEUED:
49263468e1e0SFelix Fietkau 		return true;
49273468e1e0SFelix Fietkau 	case RX_CONTINUE:
49283468e1e0SFelix Fietkau 		break;
49293468e1e0SFelix Fietkau 	default:
49303468e1e0SFelix Fietkau 		goto drop;
49313468e1e0SFelix Fietkau 	}
49323468e1e0SFelix Fietkau 
493380a915ecSFelix Fietkau 	ieee80211_rx_8023(rx, fast_rx, orig_len);
493449ddf8e6SJohannes Berg 
493549ddf8e6SJohannes Berg 	return true;
493649ddf8e6SJohannes Berg  drop:
493749ddf8e6SJohannes Berg 	dev_kfree_skb(skb);
493843635a5aSVasanthakumar Thiagarajan 
493980a915ecSFelix Fietkau 	if (fast_rx->uses_rss)
4940e66b7920SFelix Fietkau 		stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
494143635a5aSVasanthakumar Thiagarajan 	else
4942e66b7920SFelix Fietkau 		stats = &rx->link_sta->rx_stats;
494380a915ecSFelix Fietkau 
4944c9c5962bSJohannes Berg 	stats->dropped++;
494549ddf8e6SJohannes Berg 	return true;
494649ddf8e6SJohannes Berg }
494749ddf8e6SJohannes Berg 
4948571ecf67SJohannes Berg /*
49494406c376SJohannes Berg  * This function returns whether or not the SKB
49504406c376SJohannes Berg  * was destined for RX processing or not, which,
49514406c376SJohannes Berg  * if consume is true, is equivalent to whether
49524406c376SJohannes Berg  * or not the skb was consumed.
49534406c376SJohannes Berg  */
ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data * rx,struct sk_buff * skb,bool consume)49544406c376SJohannes Berg static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
49554406c376SJohannes Berg 					    struct sk_buff *skb, bool consume)
49564406c376SJohannes Berg {
49574406c376SJohannes Berg 	struct ieee80211_local *local = rx->local;
49584406c376SJohannes Berg 	struct ieee80211_sub_if_data *sdata = rx->sdata;
495942fb9148SJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
4960e66b7920SFelix Fietkau 	struct link_sta_info *link_sta = rx->link_sta;
4961e66b7920SFelix Fietkau 	struct ieee80211_link_data *link = rx->link;
49624406c376SJohannes Berg 
49634406c376SJohannes Berg 	rx->skb = skb;
49644406c376SJohannes Berg 
496549ddf8e6SJohannes Berg 	/* See if we can do fast-rx; if we have to copy we already lost,
496649ddf8e6SJohannes Berg 	 * so punt in that case. We should never have to deliver a data
496749ddf8e6SJohannes Berg 	 * frame to multiple interfaces anyway.
496849ddf8e6SJohannes Berg 	 *
496949ddf8e6SJohannes Berg 	 * We skip the ieee80211_accept_frame() call and do the necessary
497049ddf8e6SJohannes Berg 	 * checking inside ieee80211_invoke_fast_rx().
497149ddf8e6SJohannes Berg 	 */
497249ddf8e6SJohannes Berg 	if (consume && rx->sta) {
497349ddf8e6SJohannes Berg 		struct ieee80211_fast_rx *fast_rx;
497449ddf8e6SJohannes Berg 
497549ddf8e6SJohannes Berg 		fast_rx = rcu_dereference(rx->sta->fast_rx);
497649ddf8e6SJohannes Berg 		if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx))
497749ddf8e6SJohannes Berg 			return true;
497849ddf8e6SJohannes Berg 	}
497949ddf8e6SJohannes Berg 
4980a58fbe1aSJohannes Berg 	if (!ieee80211_accept_frame(rx))
49814406c376SJohannes Berg 		return false;
49824406c376SJohannes Berg 
49834406c376SJohannes Berg 	if (!consume) {
4984f9202638SAvraham Stern 		struct skb_shared_hwtstamps *shwt;
4985f9202638SAvraham Stern 
4986f9202638SAvraham Stern 		rx->skb = skb_copy(skb, GFP_ATOMIC);
4987f9202638SAvraham Stern 		if (!rx->skb) {
49884406c376SJohannes Berg 			if (net_ratelimit())
49894406c376SJohannes Berg 				wiphy_debug(local->hw.wiphy,
4990b305dae4SBen Greear 					"failed to copy skb for %s\n",
49914406c376SJohannes Berg 					sdata->name);
49924406c376SJohannes Berg 			return true;
49934406c376SJohannes Berg 		}
49944406c376SJohannes Berg 
4995f9202638SAvraham Stern 		/* skb_copy() does not copy the hw timestamps, so copy it
4996f9202638SAvraham Stern 		 * explicitly
4997f9202638SAvraham Stern 		 */
4998f9202638SAvraham Stern 		shwt = skb_hwtstamps(rx->skb);
4999f9202638SAvraham Stern 		shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
5000fa22b51aSSriram R 
5001fa22b51aSSriram R 		/* Update the hdr pointer to the new skb for translation below */
5002fa22b51aSSriram R 		hdr = (struct ieee80211_hdr *)rx->skb->data;
50034406c376SJohannes Berg 	}
50044406c376SJohannes Berg 
5005daf8fb42SAndrei Otcheretianski 	if (unlikely(rx->sta && rx->sta->sta.mlo) &&
500647c171a4SJohannes Berg 	    is_unicast_ether_addr(hdr->addr1) &&
500747c171a4SJohannes Berg 	    !ieee80211_is_probe_resp(hdr->frame_control) &&
500847c171a4SJohannes Berg 	    !ieee80211_is_beacon(hdr->frame_control)) {
500942fb9148SJohannes Berg 		/* translate to MLD addresses */
501042fb9148SJohannes Berg 		if (ether_addr_equal(link->conf->addr, hdr->addr1))
501142fb9148SJohannes Berg 			ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
501242fb9148SJohannes Berg 		if (ether_addr_equal(link_sta->addr, hdr->addr2))
501342fb9148SJohannes Berg 			ether_addr_copy(hdr->addr2, rx->sta->addr);
50141f638944SJohannes Berg 		/* translate A3 only if it's the BSSID */
50151f638944SJohannes Berg 		if (!ieee80211_has_tods(hdr->frame_control) &&
50161f638944SJohannes Berg 		    !ieee80211_has_fromds(hdr->frame_control)) {
501742fb9148SJohannes Berg 			if (ether_addr_equal(link_sta->addr, hdr->addr3))
501842fb9148SJohannes Berg 				ether_addr_copy(hdr->addr3, rx->sta->addr);
501942fb9148SJohannes Berg 			else if (ether_addr_equal(link->conf->addr, hdr->addr3))
502042fb9148SJohannes Berg 				ether_addr_copy(hdr->addr3, rx->sdata->vif.addr);
50211f638944SJohannes Berg 		}
502242fb9148SJohannes Berg 		/* not needed for A4 since it can only carry the SA */
502342fb9148SJohannes Berg 	}
502442fb9148SJohannes Berg 
50254406c376SJohannes Berg 	ieee80211_invoke_rx_handlers(rx);
50264406c376SJohannes Berg 	return true;
50274406c376SJohannes Berg }
50284406c376SJohannes Berg 
__ieee80211_rx_handle_8023(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)502980a915ecSFelix Fietkau static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
503080a915ecSFelix Fietkau 				       struct ieee80211_sta *pubsta,
503180a915ecSFelix Fietkau 				       struct sk_buff *skb,
503280a915ecSFelix Fietkau 				       struct list_head *list)
503380a915ecSFelix Fietkau {
503480a915ecSFelix Fietkau 	struct ieee80211_local *local = hw_to_local(hw);
5035ea9d807bSVasanthakumar Thiagarajan 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
503680a915ecSFelix Fietkau 	struct ieee80211_fast_rx *fast_rx;
503780a915ecSFelix Fietkau 	struct ieee80211_rx_data rx;
50380d846bdcSJohannes Berg 	struct sta_info *sta;
5039e66b7920SFelix Fietkau 	int link_id = -1;
504080a915ecSFelix Fietkau 
504180a915ecSFelix Fietkau 	memset(&rx, 0, sizeof(rx));
504280a915ecSFelix Fietkau 	rx.skb = skb;
504380a915ecSFelix Fietkau 	rx.local = local;
504480a915ecSFelix Fietkau 	rx.list = list;
5045892b3bceSJohannes Berg 	rx.link_id = -1;
504680a915ecSFelix Fietkau 
504780a915ecSFelix Fietkau 	I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
504880a915ecSFelix Fietkau 
504980a915ecSFelix Fietkau 	/* drop frame if too short for header */
505080a915ecSFelix Fietkau 	if (skb->len < sizeof(struct ethhdr))
505180a915ecSFelix Fietkau 		goto drop;
505280a915ecSFelix Fietkau 
505380a915ecSFelix Fietkau 	if (!pubsta)
505480a915ecSFelix Fietkau 		goto drop;
505580a915ecSFelix Fietkau 
5056e66b7920SFelix Fietkau 	if (status->link_valid)
5057e66b7920SFelix Fietkau 		link_id = status->link_id;
5058ea9d807bSVasanthakumar Thiagarajan 
5059ea9d807bSVasanthakumar Thiagarajan 	/*
5060ea9d807bSVasanthakumar Thiagarajan 	 * TODO: Should the frame be dropped if the right link_id is not
5061ea9d807bSVasanthakumar Thiagarajan 	 * available? Or may be it is fine in the current form to proceed with
5062ea9d807bSVasanthakumar Thiagarajan 	 * the frame processing because with frame being in 802.3 format,
5063ea9d807bSVasanthakumar Thiagarajan 	 * link_id is used only for stats purpose and updating the stats on
5064ea9d807bSVasanthakumar Thiagarajan 	 * the deflink is fine?
5065ea9d807bSVasanthakumar Thiagarajan 	 */
50660d846bdcSJohannes Berg 	sta = container_of(pubsta, struct sta_info, sta);
50670d846bdcSJohannes Berg 	if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
5068ea9d807bSVasanthakumar Thiagarajan 		goto drop;
506980a915ecSFelix Fietkau 
507080a915ecSFelix Fietkau 	fast_rx = rcu_dereference(rx.sta->fast_rx);
507180a915ecSFelix Fietkau 	if (!fast_rx)
507280a915ecSFelix Fietkau 		goto drop;
507380a915ecSFelix Fietkau 
507480a915ecSFelix Fietkau 	ieee80211_rx_8023(&rx, fast_rx, skb->len);
507580a915ecSFelix Fietkau 	return;
507680a915ecSFelix Fietkau 
507780a915ecSFelix Fietkau drop:
507880a915ecSFelix Fietkau 	dev_kfree_skb(skb);
507980a915ecSFelix Fietkau }
508080a915ecSFelix Fietkau 
ieee80211_rx_for_interface(struct ieee80211_rx_data * rx,struct sk_buff * skb,bool consume)5081892b3bceSJohannes Berg static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
5082892b3bceSJohannes Berg 				       struct sk_buff *skb, bool consume)
5083892b3bceSJohannes Berg {
5084892b3bceSJohannes Berg 	struct link_sta_info *link_sta;
5085892b3bceSJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
5086e66b7920SFelix Fietkau 	struct sta_info *sta;
5087e66b7920SFelix Fietkau 	int link_id = -1;
5088892b3bceSJohannes Berg 
5089892b3bceSJohannes Berg 	/*
5090892b3bceSJohannes Berg 	 * Look up link station first, in case there's a
5091892b3bceSJohannes Berg 	 * chance that they might have a link address that
5092892b3bceSJohannes Berg 	 * is identical to the MLD address, that way we'll
5093892b3bceSJohannes Berg 	 * have the link information if needed.
5094892b3bceSJohannes Berg 	 */
5095892b3bceSJohannes Berg 	link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
5096892b3bceSJohannes Berg 	if (link_sta) {
5097e66b7920SFelix Fietkau 		sta = link_sta->sta;
5098e66b7920SFelix Fietkau 		link_id = link_sta->link_id;
5099892b3bceSJohannes Berg 	} else {
5100ea9d807bSVasanthakumar Thiagarajan 		struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5101ea9d807bSVasanthakumar Thiagarajan 
5102e66b7920SFelix Fietkau 		sta = sta_info_get_bss(rx->sdata, hdr->addr2);
5103e66b7920SFelix Fietkau 		if (status->link_valid)
5104e66b7920SFelix Fietkau 			link_id = status->link_id;
5105e66b7920SFelix Fietkau 	}
5106ea9d807bSVasanthakumar Thiagarajan 
51070d846bdcSJohannes Berg 	if (!ieee80211_rx_data_set_sta(rx, sta, link_id))
5108e66b7920SFelix Fietkau 		return false;
5109892b3bceSJohannes Berg 
5110892b3bceSJohannes Berg 	return ieee80211_prepare_and_rx_handle(rx, skb, consume);
5111892b3bceSJohannes Berg }
5112892b3bceSJohannes Berg 
51134406c376SJohannes Berg /*
51146b59db7dSZhao, Gang  * This is the actual Rx frames handler. as it belongs to Rx path it must
51156368e4b1SRon Rindjunsky  * be called with rcu_read_lock protection.
5116571ecf67SJohannes Berg  */
__ieee80211_rx_handle_packet(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)511771ebb4aaSRon Rindjunsky static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
5118d63b548fSJohannes Berg 					 struct ieee80211_sta *pubsta,
5119af9f9b22SJohannes Berg 					 struct sk_buff *skb,
5120c5d1686bSFelix Fietkau 					 struct list_head *list)
5121571ecf67SJohannes Berg {
5122571ecf67SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
5123ea9d807bSVasanthakumar Thiagarajan 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5124571ecf67SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
5125571ecf67SJohannes Berg 	struct ieee80211_hdr *hdr;
5126e3cf8b3fSZhu Yi 	__le16 fc;
51275cf121c3SJohannes Berg 	struct ieee80211_rx_data rx;
51284406c376SJohannes Berg 	struct ieee80211_sub_if_data *prev;
512983e7e4ceSHerbert Xu 	struct rhlist_head *tmp;
5130e3cf8b3fSZhu Yi 	int err = 0;
5131571ecf67SJohannes Berg 
5132e3cf8b3fSZhu Yi 	fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
5133571ecf67SJohannes Berg 	memset(&rx, 0, sizeof(rx));
5134571ecf67SJohannes Berg 	rx.skb = skb;
5135571ecf67SJohannes Berg 	rx.local = local;
5136c5d1686bSFelix Fietkau 	rx.list = list;
5137892b3bceSJohannes Berg 	rx.link_id = -1;
513872abd81bSJohannes Berg 
5139e3cf8b3fSZhu Yi 	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
5140c206ca67SJohannes Berg 		I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
5141571ecf67SJohannes Berg 
51424a4f1a58SJohannes Berg 	if (ieee80211_is_mgmt(fc)) {
51434a4f1a58SJohannes Berg 		/* drop frame if too short for header */
51444a4f1a58SJohannes Berg 		if (skb->len < ieee80211_hdrlen(fc))
51454a4f1a58SJohannes Berg 			err = -ENOBUFS;
5146e3cf8b3fSZhu Yi 		else
51474a4f1a58SJohannes Berg 			err = skb_linearize(skb);
51484a4f1a58SJohannes Berg 	} else {
5149e3cf8b3fSZhu Yi 		err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
51504a4f1a58SJohannes Berg 	}
5151e3cf8b3fSZhu Yi 
5152e3cf8b3fSZhu Yi 	if (err) {
5153e3cf8b3fSZhu Yi 		dev_kfree_skb(skb);
5154e3cf8b3fSZhu Yi 		return;
5155e3cf8b3fSZhu Yi 	}
5156e3cf8b3fSZhu Yi 
5157e3cf8b3fSZhu Yi 	hdr = (struct ieee80211_hdr *)skb->data;
515838f3714dSJohannes Berg 	ieee80211_parse_qos(&rx);
5159d1c3a37cSJohannes Berg 	ieee80211_verify_alignment(&rx);
516038f3714dSJohannes Berg 
5161d48b2968SJohannes Berg 	if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
5162cd418ba6SThomas Pedersen 		     ieee80211_is_beacon(hdr->frame_control) ||
5163cd418ba6SThomas Pedersen 		     ieee80211_is_s1g_beacon(hdr->frame_control)))
5164d48b2968SJohannes Berg 		ieee80211_scan_rx(local, skb);
5165d48b2968SJohannes Berg 
516619d19e96SJohannes Berg 	if (ieee80211_is_data(fc)) {
516719d19e96SJohannes Berg 		struct sta_info *sta, *prev_sta;
5168e66b7920SFelix Fietkau 		int link_id = -1;
5169ea9d807bSVasanthakumar Thiagarajan 
5170ea9d807bSVasanthakumar Thiagarajan 		if (status->link_valid)
5171e66b7920SFelix Fietkau 			link_id = status->link_id;
5172e66b7920SFelix Fietkau 
5173e66b7920SFelix Fietkau 		if (pubsta) {
51740d846bdcSJohannes Berg 			sta = container_of(pubsta, struct sta_info, sta);
51750d846bdcSJohannes Berg 			if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
5176e66b7920SFelix Fietkau 				goto out;
5177ea9d807bSVasanthakumar Thiagarajan 
5178ea9d807bSVasanthakumar Thiagarajan 			/*
5179ea9d807bSVasanthakumar Thiagarajan 			 * In MLO connection, fetch the link_id using addr2
5180ea9d807bSVasanthakumar Thiagarajan 			 * when the driver does not pass link_id in status.
5181ea9d807bSVasanthakumar Thiagarajan 			 * When the address translation is already performed by
5182ea9d807bSVasanthakumar Thiagarajan 			 * driver/hw, the valid link_id must be passed in
5183ea9d807bSVasanthakumar Thiagarajan 			 * status.
5184ea9d807bSVasanthakumar Thiagarajan 			 */
5185ea9d807bSVasanthakumar Thiagarajan 
5186ea9d807bSVasanthakumar Thiagarajan 			if (!status->link_valid && pubsta->mlo) {
5187ea9d807bSVasanthakumar Thiagarajan 				struct ieee80211_hdr *hdr = (void *)skb->data;
5188ea9d807bSVasanthakumar Thiagarajan 				struct link_sta_info *link_sta;
5189ea9d807bSVasanthakumar Thiagarajan 
5190ea9d807bSVasanthakumar Thiagarajan 				link_sta = link_sta_info_get_bss(rx.sdata,
5191ea9d807bSVasanthakumar Thiagarajan 								 hdr->addr2);
5192ea9d807bSVasanthakumar Thiagarajan 				if (!link_sta)
5193ea9d807bSVasanthakumar Thiagarajan 					goto out;
5194ea9d807bSVasanthakumar Thiagarajan 
5195e66b7920SFelix Fietkau 				ieee80211_rx_data_set_link(&rx, link_sta->link_id);
5196ea9d807bSVasanthakumar Thiagarajan 			}
5197ea9d807bSVasanthakumar Thiagarajan 
5198d63b548fSJohannes Berg 			if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
5199d63b548fSJohannes Berg 				return;
5200d63b548fSJohannes Berg 			goto out;
520119d19e96SJohannes Berg 		}
52027bedd0cfSJohannes Berg 
520356af3268SBen Greear 		prev_sta = NULL;
52044406c376SJohannes Berg 
520583e7e4ceSHerbert Xu 		for_each_sta_info(local, hdr->addr2, sta, tmp) {
520656af3268SBen Greear 			if (!prev_sta) {
520756af3268SBen Greear 				prev_sta = sta;
520856af3268SBen Greear 				continue;
520956af3268SBen Greear 			}
521056af3268SBen Greear 
5211e66b7920SFelix Fietkau 			rx.sdata = prev_sta->sdata;
52120d846bdcSJohannes Berg 			if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
5213e66b7920SFelix Fietkau 				goto out;
5214e66b7920SFelix Fietkau 
5215e66b7920SFelix Fietkau 			if (!status->link_valid && prev_sta->sta.mlo)
5216ea9d807bSVasanthakumar Thiagarajan 				continue;
5217ea9d807bSVasanthakumar Thiagarajan 
52184406c376SJohannes Berg 			ieee80211_prepare_and_rx_handle(&rx, skb, false);
5219571ecf67SJohannes Berg 
522056af3268SBen Greear 			prev_sta = sta;
52214406c376SJohannes Berg 		}
522256af3268SBen Greear 
522356af3268SBen Greear 		if (prev_sta) {
5224e66b7920SFelix Fietkau 			rx.sdata = prev_sta->sdata;
52250d846bdcSJohannes Berg 			if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
5226ea9d807bSVasanthakumar Thiagarajan 				goto out;
5227ea9d807bSVasanthakumar Thiagarajan 
5228e66b7920SFelix Fietkau 			if (!status->link_valid && prev_sta->sta.mlo)
5229e66b7920SFelix Fietkau 				goto out;
523056af3268SBen Greear 
52314406c376SJohannes Berg 			if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
523256af3268SBen Greear 				return;
52338e26d5adSSenthil Balasubramanian 			goto out;
5234abe60632SJohannes Berg 		}
523556af3268SBen Greear 	}
52364406c376SJohannes Berg 
52374406c376SJohannes Berg 	prev = NULL;
52384406c376SJohannes Berg 
5239abe60632SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
52409607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
52412a8a9a88SJohannes Berg 			continue;
52422a8a9a88SJohannes Berg 
5243fbc44bf7SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
5244fbc44bf7SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
5245b2e7771eSJohannes Berg 			continue;
5246b2e7771eSJohannes Berg 
5247340e11f3SJohannes Berg 		/*
5248abe60632SJohannes Berg 		 * frame is destined for this interface, but if it's
5249abe60632SJohannes Berg 		 * not also for the previous one we handle that after
5250abe60632SJohannes Berg 		 * the loop to avoid copying the SKB once too much
5251340e11f3SJohannes Berg 		 */
5252340e11f3SJohannes Berg 
5253340e11f3SJohannes Berg 		if (!prev) {
5254340e11f3SJohannes Berg 			prev = sdata;
5255340e11f3SJohannes Berg 			continue;
5256340e11f3SJohannes Berg 		}
5257340e11f3SJohannes Berg 
525820b01f80SJohannes Berg 		rx.sdata = prev;
5259892b3bceSJohannes Berg 		ieee80211_rx_for_interface(&rx, skb, false);
52604bb29f8cSFelix Fietkau 
5261571ecf67SJohannes Berg 		prev = sdata;
5262571ecf67SJohannes Berg 	}
52634bb29f8cSFelix Fietkau 
52644bb29f8cSFelix Fietkau 	if (prev) {
526520b01f80SJohannes Berg 		rx.sdata = prev;
52664bb29f8cSFelix Fietkau 
5267892b3bceSJohannes Berg 		if (ieee80211_rx_for_interface(&rx, skb, true))
52684406c376SJohannes Berg 			return;
52694406c376SJohannes Berg 	}
52704bb29f8cSFelix Fietkau 
52718e26d5adSSenthil Balasubramanian  out:
5272571ecf67SJohannes Berg 	dev_kfree_skb(skb);
5273571ecf67SJohannes Berg }
52746368e4b1SRon Rindjunsky 
52756368e4b1SRon Rindjunsky /*
52766368e4b1SRon Rindjunsky  * This is the receive path handler. It is called by a low level driver when an
52776368e4b1SRon Rindjunsky  * 802.11 MPDU is received from the hardware.
52786368e4b1SRon Rindjunsky  */
ieee80211_rx_list(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)5279c5d1686bSFelix Fietkau void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
5280c5d1686bSFelix Fietkau 		       struct sk_buff *skb, struct list_head *list)
52816368e4b1SRon Rindjunsky {
52826368e4b1SRon Rindjunsky 	struct ieee80211_local *local = hw_to_local(hw);
52838318d78aSJohannes Berg 	struct ieee80211_rate *rate = NULL;
52848318d78aSJohannes Berg 	struct ieee80211_supported_band *sband;
5285f1d58c25SJohannes Berg 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
528630f6cf96SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
52878318d78aSJohannes Berg 
5288d20ef63dSJohannes Berg 	WARN_ON_ONCE(softirq_count() == 0);
5289d20ef63dSJohannes Berg 
529057fbcce3SJohannes Berg 	if (WARN_ON(status->band >= NUM_NL80211_BANDS))
529177a980dcSJohannes Berg 		goto drop;
52928318d78aSJohannes Berg 
52938318d78aSJohannes Berg 	sband = local->hw.wiphy->bands[status->band];
529477a980dcSJohannes Berg 	if (WARN_ON(!sband))
529577a980dcSJohannes Berg 		goto drop;
52968318d78aSJohannes Berg 
529789c3a8acSJohannes Berg 	/*
529889c3a8acSJohannes Berg 	 * If we're suspending, it is possible although not too likely
529989c3a8acSJohannes Berg 	 * that we'd be receiving frames after having already partially
530089c3a8acSJohannes Berg 	 * quiesced the stack. We can't process such frames then since
530189c3a8acSJohannes Berg 	 * that might, for example, cause stations to be added or other
530289c3a8acSJohannes Berg 	 * driver callbacks be invoked.
530389c3a8acSJohannes Berg 	 */
530477a980dcSJohannes Berg 	if (unlikely(local->quiescing || local->suspended))
530577a980dcSJohannes Berg 		goto drop;
530689c3a8acSJohannes Berg 
530704800adaSArik Nemtsov 	/* We might be during a HW reconfig, prevent Rx for the same reason */
530804800adaSArik Nemtsov 	if (unlikely(local->in_reconfig))
530904800adaSArik Nemtsov 		goto drop;
531004800adaSArik Nemtsov 
5311ea77f12fSJohannes Berg 	/*
5312ea77f12fSJohannes Berg 	 * The same happens when we're not even started,
5313ea77f12fSJohannes Berg 	 * but that's worth a warning.
5314ea77f12fSJohannes Berg 	 */
531577a980dcSJohannes Berg 	if (WARN_ON(!local->started))
531677a980dcSJohannes Berg 		goto drop;
5317ea77f12fSJohannes Berg 
5318fc885189SJohannes Berg 	if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
5319fc885189SJohannes Berg 		/*
5320fc885189SJohannes Berg 		 * Validate the rate, unless a PLCP error means that
5321fc885189SJohannes Berg 		 * we probably can't have a valid rate here anyway.
5322fc885189SJohannes Berg 		 */
5323fc885189SJohannes Berg 
5324da6a4352SJohannes Berg 		switch (status->encoding) {
5325da6a4352SJohannes Berg 		case RX_ENC_HT:
5326e5d6eb83SLuis R. Rodriguez 			/*
5327fc885189SJohannes Berg 			 * rate_idx is MCS index, which can be [0-76]
5328fc885189SJohannes Berg 			 * as documented on:
5329e5d6eb83SLuis R. Rodriguez 			 *
533059d4bfc1SFlavio Suligoi 			 * https://wireless.wiki.kernel.org/en/developers/Documentation/ieee80211/802.11n
5331e5d6eb83SLuis R. Rodriguez 			 *
5332fc885189SJohannes Berg 			 * Anything else would be some sort of driver or
5333fc885189SJohannes Berg 			 * hardware error. The driver should catch hardware
5334fc885189SJohannes Berg 			 * errors.
5335e5d6eb83SLuis R. Rodriguez 			 */
5336444e3803SJohannes Berg 			if (WARN(status->rate_idx > 76,
5337e5d6eb83SLuis R. Rodriguez 				 "Rate marked as an HT rate but passed "
5338e5d6eb83SLuis R. Rodriguez 				 "status->rate_idx is not "
5339e5d6eb83SLuis R. Rodriguez 				 "an MCS index [0-76]: %d (0x%02x)\n",
5340e5d6eb83SLuis R. Rodriguez 				 status->rate_idx,
5341e5d6eb83SLuis R. Rodriguez 				 status->rate_idx))
534277a980dcSJohannes Berg 				goto drop;
5343da6a4352SJohannes Berg 			break;
5344da6a4352SJohannes Berg 		case RX_ENC_VHT:
534504be6d33SPing-Ke Shih 			if (WARN_ONCE(status->rate_idx > 11 ||
53468613c948SJohannes Berg 				      !status->nss ||
53478613c948SJohannes Berg 				      status->nss > 8,
53485614618eSJohannes Berg 				      "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
53498613c948SJohannes Berg 				      status->rate_idx, status->nss))
53505614618eSJohannes Berg 				goto drop;
5351da6a4352SJohannes Berg 			break;
535241cbb0f5SLuca Coelho 		case RX_ENC_HE:
535341cbb0f5SLuca Coelho 			if (WARN_ONCE(status->rate_idx > 11 ||
535441cbb0f5SLuca Coelho 				      !status->nss ||
535541cbb0f5SLuca Coelho 				      status->nss > 8,
535641cbb0f5SLuca Coelho 				      "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
535741cbb0f5SLuca Coelho 				      status->rate_idx, status->nss))
535841cbb0f5SLuca Coelho 				goto drop;
535941cbb0f5SLuca Coelho 			break;
5360f66c48afSJohannes Berg 		case RX_ENC_EHT:
5361f66c48afSJohannes Berg 			if (WARN_ONCE(status->rate_idx > 15 ||
5362f66c48afSJohannes Berg 				      !status->nss ||
5363f66c48afSJohannes Berg 				      status->nss > 8 ||
5364f66c48afSJohannes Berg 				      status->eht.gi > NL80211_RATE_INFO_EHT_GI_3_2,
5365f66c48afSJohannes Berg 				      "Rate marked as an EHT rate but data is invalid: MCS:%d, NSS:%d, GI:%d\n",
5366f66c48afSJohannes Berg 				      status->rate_idx, status->nss, status->eht.gi))
5367f66c48afSJohannes Berg 				goto drop;
5368f66c48afSJohannes Berg 			break;
5369da6a4352SJohannes Berg 		default:
5370da6a4352SJohannes Berg 			WARN_ON_ONCE(1);
5371fc0561dcSGustavo A. R. Silva 			fallthrough;
5372da6a4352SJohannes Berg 		case RX_ENC_LEGACY:
5373444e3803SJohannes Berg 			if (WARN_ON(status->rate_idx >= sband->n_bitrates))
537477a980dcSJohannes Berg 				goto drop;
53758318d78aSJohannes Berg 			rate = &sband->bitrates[status->rate_idx];
53760fb8ca45SJouni Malinen 		}
5377fc885189SJohannes Berg 	}
53786368e4b1SRon Rindjunsky 
5379ea9d807bSVasanthakumar Thiagarajan 	if (WARN_ON_ONCE(status->link_id >= IEEE80211_LINK_UNSPECIFIED))
5380ea9d807bSVasanthakumar Thiagarajan 		goto drop;
5381ea9d807bSVasanthakumar Thiagarajan 
5382554891e6SJohannes Berg 	status->rx_flags = 0;
5383554891e6SJohannes Berg 
5384261e411bSAleksandr Nogikh 	kcov_remote_start_common(skb_get_kcov_handle(skb));
5385261e411bSAleksandr Nogikh 
53866368e4b1SRon Rindjunsky 	/*
53876368e4b1SRon Rindjunsky 	 * Frames with failed FCS/PLCP checksum are not returned,
53886368e4b1SRon Rindjunsky 	 * all other frames are returned without radiotap header
53896368e4b1SRon Rindjunsky 	 * if it was previously present.
53906368e4b1SRon Rindjunsky 	 * Also, frames with less than 16 bytes are dropped.
53916368e4b1SRon Rindjunsky 	 */
539280a915ecSFelix Fietkau 	if (!(status->flag & RX_FLAG_8023))
5393f1d58c25SJohannes Berg 		skb = ieee80211_rx_monitor(local, skb, rate);
5394261e411bSAleksandr Nogikh 	if (skb) {
539530f6cf96SFelix Fietkau 		if ((status->flag & RX_FLAG_8023) ||
539630f6cf96SFelix Fietkau 			ieee80211_is_data_present(hdr->frame_control))
539730f6cf96SFelix Fietkau 			ieee80211_tpt_led_trig_rx(local, skb->len);
5398d63b548fSJohannes Berg 
539980a915ecSFelix Fietkau 		if (status->flag & RX_FLAG_8023)
540080a915ecSFelix Fietkau 			__ieee80211_rx_handle_8023(hw, pubsta, skb, list);
540180a915ecSFelix Fietkau 		else
5402c5d1686bSFelix Fietkau 			__ieee80211_rx_handle_packet(hw, pubsta, skb, list);
5403261e411bSAleksandr Nogikh 	}
540477a980dcSJohannes Berg 
5405261e411bSAleksandr Nogikh 	kcov_remote_stop();
540677a980dcSJohannes Berg 	return;
540777a980dcSJohannes Berg  drop:
540877a980dcSJohannes Berg 	kfree_skb(skb);
54096368e4b1SRon Rindjunsky }
5410c5d1686bSFelix Fietkau EXPORT_SYMBOL(ieee80211_rx_list);
5411c5d1686bSFelix Fietkau 
ieee80211_rx_napi(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct napi_struct * napi)5412c5d1686bSFelix Fietkau void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
5413c5d1686bSFelix Fietkau 		       struct sk_buff *skb, struct napi_struct *napi)
5414c5d1686bSFelix Fietkau {
5415c5d1686bSFelix Fietkau 	struct sk_buff *tmp;
5416c5d1686bSFelix Fietkau 	LIST_HEAD(list);
5417c5d1686bSFelix Fietkau 
5418c5d1686bSFelix Fietkau 
5419c5d1686bSFelix Fietkau 	/*
5420c5d1686bSFelix Fietkau 	 * key references and virtual interfaces are protected using RCU
5421c5d1686bSFelix Fietkau 	 * and this requires that we are in a read-side RCU section during
5422c5d1686bSFelix Fietkau 	 * receive processing
5423c5d1686bSFelix Fietkau 	 */
5424c5d1686bSFelix Fietkau 	rcu_read_lock();
5425c5d1686bSFelix Fietkau 	ieee80211_rx_list(hw, pubsta, skb, &list);
5426c5d1686bSFelix Fietkau 	rcu_read_unlock();
5427c5d1686bSFelix Fietkau 
5428c5d1686bSFelix Fietkau 	if (!napi) {
5429c5d1686bSFelix Fietkau 		netif_receive_skb_list(&list);
5430c5d1686bSFelix Fietkau 		return;
5431c5d1686bSFelix Fietkau 	}
5432c5d1686bSFelix Fietkau 
5433c5d1686bSFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
5434c5d1686bSFelix Fietkau 		skb_list_del_init(skb);
5435c5d1686bSFelix Fietkau 		napi_gro_receive(napi, skb);
5436c5d1686bSFelix Fietkau 	}
5437c5d1686bSFelix Fietkau }
5438af9f9b22SJohannes Berg EXPORT_SYMBOL(ieee80211_rx_napi);
5439571ecf67SJohannes Berg 
5440571ecf67SJohannes Berg /* This is a version of the rx handler that can be called from hard irq
5441571ecf67SJohannes Berg  * context. Post the skb on the queue and schedule the tasklet */
ieee80211_rx_irqsafe(struct ieee80211_hw * hw,struct sk_buff * skb)5442f1d58c25SJohannes Berg void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
5443571ecf67SJohannes Berg {
5444571ecf67SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
5445571ecf67SJohannes Berg 
5446571ecf67SJohannes Berg 	BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
5447571ecf67SJohannes Berg 
5448571ecf67SJohannes Berg 	skb->pkt_type = IEEE80211_RX_MSG;
5449571ecf67SJohannes Berg 	skb_queue_tail(&local->skb_queue, skb);
5450571ecf67SJohannes Berg 	tasklet_schedule(&local->tasklet);
5451571ecf67SJohannes Berg }
5452571ecf67SJohannes Berg EXPORT_SYMBOL(ieee80211_rx_irqsafe);
5453