162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc.
462306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc.
562306a36Sopenharmony_ci * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
662306a36Sopenharmony_ci * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
762306a36Sopenharmony_ci * Copyright 2013-2014  Intel Mobile Communications GmbH
862306a36Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
962306a36Sopenharmony_ci * Copyright (C) 2018-2023 Intel Corporation
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/skbuff.h>
1662306a36Sopenharmony_ci#include <linux/netdevice.h>
1762306a36Sopenharmony_ci#include <linux/etherdevice.h>
1862306a36Sopenharmony_ci#include <linux/rcupdate.h>
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci#include <linux/kcov.h>
2162306a36Sopenharmony_ci#include <linux/bitops.h>
2262306a36Sopenharmony_ci#include <net/mac80211.h>
2362306a36Sopenharmony_ci#include <net/ieee80211_radiotap.h>
2462306a36Sopenharmony_ci#include <asm/unaligned.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "ieee80211_i.h"
2762306a36Sopenharmony_ci#include "driver-ops.h"
2862306a36Sopenharmony_ci#include "led.h"
2962306a36Sopenharmony_ci#include "mesh.h"
3062306a36Sopenharmony_ci#include "wep.h"
3162306a36Sopenharmony_ci#include "wpa.h"
3262306a36Sopenharmony_ci#include "tkip.h"
3362306a36Sopenharmony_ci#include "wme.h"
3462306a36Sopenharmony_ci#include "rate.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * monitor mode reception
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * This function cleans up the SKB, i.e. it removes all the stuff
4062306a36Sopenharmony_ci * only useful for monitoring.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistatic struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
4362306a36Sopenharmony_ci					   unsigned int present_fcs_len,
4462306a36Sopenharmony_ci					   unsigned int rtap_space)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
4862306a36Sopenharmony_ci	unsigned int hdrlen;
4962306a36Sopenharmony_ci	__le16 fc;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (present_fcs_len)
5262306a36Sopenharmony_ci		__pskb_trim(skb, skb->len - present_fcs_len);
5362306a36Sopenharmony_ci	pskb_pull(skb, rtap_space);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* After pulling radiotap header, clear all flags that indicate
5662306a36Sopenharmony_ci	 * info in skb->data.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	status->flag &= ~(RX_FLAG_RADIOTAP_TLV_AT_END |
5962306a36Sopenharmony_ci			  RX_FLAG_RADIOTAP_LSIG |
6062306a36Sopenharmony_ci			  RX_FLAG_RADIOTAP_HE_MU |
6162306a36Sopenharmony_ci			  RX_FLAG_RADIOTAP_HE);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	hdr = (void *)skb->data;
6462306a36Sopenharmony_ci	fc = hdr->frame_control;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/*
6762306a36Sopenharmony_ci	 * Remove the HT-Control field (if present) on management
6862306a36Sopenharmony_ci	 * frames after we've sent the frame to monitoring. We
6962306a36Sopenharmony_ci	 * (currently) don't need it, and don't properly parse
7062306a36Sopenharmony_ci	 * frames with it present, due to the assumption of a
7162306a36Sopenharmony_ci	 * fixed management header length.
7262306a36Sopenharmony_ci	 */
7362306a36Sopenharmony_ci	if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc)))
7462306a36Sopenharmony_ci		return skb;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	hdrlen = ieee80211_hdrlen(fc);
7762306a36Sopenharmony_ci	hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (!pskb_may_pull(skb, hdrlen)) {
8062306a36Sopenharmony_ci		dev_kfree_skb(skb);
8162306a36Sopenharmony_ci		return NULL;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data,
8562306a36Sopenharmony_ci		hdrlen - IEEE80211_HT_CTL_LEN);
8662306a36Sopenharmony_ci	pskb_pull(skb, IEEE80211_HT_CTL_LEN);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return skb;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
9262306a36Sopenharmony_ci				     unsigned int rtap_space)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
9562306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	hdr = (void *)(skb->data + rtap_space);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
10062306a36Sopenharmony_ci			    RX_FLAG_FAILED_PLCP_CRC |
10162306a36Sopenharmony_ci			    RX_FLAG_ONLY_MONITOR |
10262306a36Sopenharmony_ci			    RX_FLAG_NO_PSDU))
10362306a36Sopenharmony_ci		return true;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (unlikely(skb->len < 16 + present_fcs_len + rtap_space))
10662306a36Sopenharmony_ci		return true;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (ieee80211_is_ctl(hdr->frame_control) &&
10962306a36Sopenharmony_ci	    !ieee80211_is_pspoll(hdr->frame_control) &&
11062306a36Sopenharmony_ci	    !ieee80211_is_back_req(hdr->frame_control))
11162306a36Sopenharmony_ci		return true;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return false;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int
11762306a36Sopenharmony_ciieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
11862306a36Sopenharmony_ci			     struct ieee80211_rx_status *status,
11962306a36Sopenharmony_ci			     struct sk_buff *skb)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	int len;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* always present fields */
12462306a36Sopenharmony_ci	len = sizeof(struct ieee80211_radiotap_header) + 8;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* allocate extra bitmaps */
12762306a36Sopenharmony_ci	if (status->chains)
12862306a36Sopenharmony_ci		len += 4 * hweight8(status->chains);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (ieee80211_have_rx_timestamp(status)) {
13162306a36Sopenharmony_ci		len = ALIGN(len, 8);
13262306a36Sopenharmony_ci		len += 8;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci	if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
13562306a36Sopenharmony_ci		len += 1;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* antenna field, if we don't have per-chain info */
13862306a36Sopenharmony_ci	if (!status->chains)
13962306a36Sopenharmony_ci		len += 1;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* padding for RX_FLAGS if necessary */
14262306a36Sopenharmony_ci	len = ALIGN(len, 2);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HT) /* HT info */
14562306a36Sopenharmony_ci		len += 3;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
14862306a36Sopenharmony_ci		len = ALIGN(len, 4);
14962306a36Sopenharmony_ci		len += 8;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (status->encoding == RX_ENC_VHT) {
15362306a36Sopenharmony_ci		len = ALIGN(len, 2);
15462306a36Sopenharmony_ci		len += 12;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (local->hw.radiotap_timestamp.units_pos >= 0) {
15862306a36Sopenharmony_ci		len = ALIGN(len, 8);
15962306a36Sopenharmony_ci		len += 12;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HE &&
16362306a36Sopenharmony_ci	    status->flag & RX_FLAG_RADIOTAP_HE) {
16462306a36Sopenharmony_ci		len = ALIGN(len, 2);
16562306a36Sopenharmony_ci		len += 12;
16662306a36Sopenharmony_ci		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HE &&
17062306a36Sopenharmony_ci	    status->flag & RX_FLAG_RADIOTAP_HE_MU) {
17162306a36Sopenharmony_ci		len = ALIGN(len, 2);
17262306a36Sopenharmony_ci		len += 12;
17362306a36Sopenharmony_ci		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (status->flag & RX_FLAG_NO_PSDU)
17762306a36Sopenharmony_ci		len += 1;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
18062306a36Sopenharmony_ci		len = ALIGN(len, 2);
18162306a36Sopenharmony_ci		len += 4;
18262306a36Sopenharmony_ci		BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (status->chains) {
18662306a36Sopenharmony_ci		/* antenna and antenna signal fields */
18762306a36Sopenharmony_ci		len += 2 * hweight8(status->chains);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
19162306a36Sopenharmony_ci		int tlv_offset = 0;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		/*
19462306a36Sopenharmony_ci		 * The position to look at depends on the existence (or non-
19562306a36Sopenharmony_ci		 * existence) of other elements, so take that into account...
19662306a36Sopenharmony_ci		 */
19762306a36Sopenharmony_ci		if (status->flag & RX_FLAG_RADIOTAP_HE)
19862306a36Sopenharmony_ci			tlv_offset +=
19962306a36Sopenharmony_ci				sizeof(struct ieee80211_radiotap_he);
20062306a36Sopenharmony_ci		if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
20162306a36Sopenharmony_ci			tlv_offset +=
20262306a36Sopenharmony_ci				sizeof(struct ieee80211_radiotap_he_mu);
20362306a36Sopenharmony_ci		if (status->flag & RX_FLAG_RADIOTAP_LSIG)
20462306a36Sopenharmony_ci			tlv_offset +=
20562306a36Sopenharmony_ci				sizeof(struct ieee80211_radiotap_lsig);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		/* ensure 4 byte alignment for TLV */
20862306a36Sopenharmony_ci		len = ALIGN(len, 4);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		/* TLVs until the mac header */
21162306a36Sopenharmony_ci		len += skb_mac_header(skb) - &skb->data[tlv_offset];
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return len;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
21862306a36Sopenharmony_ci					   int link_id,
21962306a36Sopenharmony_ci					   struct sta_info *sta,
22062306a36Sopenharmony_ci					   struct sk_buff *skb)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (link_id >= 0) {
22562306a36Sopenharmony_ci		status->link_valid = 1;
22662306a36Sopenharmony_ci		status->link_id = link_id;
22762306a36Sopenharmony_ci	} else {
22862306a36Sopenharmony_ci		status->link_valid = 0;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	skb_queue_tail(&sdata->skb_queue, skb);
23262306a36Sopenharmony_ci	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
23362306a36Sopenharmony_ci	if (sta)
23462306a36Sopenharmony_ci		sta->deflink.rx_stats.packets++;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
23862306a36Sopenharmony_ci					 int link_id,
23962306a36Sopenharmony_ci					 struct sta_info *sta,
24062306a36Sopenharmony_ci					 struct sk_buff *skb)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	skb->protocol = 0;
24362306a36Sopenharmony_ci	__ieee80211_queue_skb_to_iface(sdata, link_id, sta, skb);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
24762306a36Sopenharmony_ci					 struct sk_buff *skb,
24862306a36Sopenharmony_ci					 int rtap_space)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct {
25162306a36Sopenharmony_ci		struct ieee80211_hdr_3addr hdr;
25262306a36Sopenharmony_ci		u8 category;
25362306a36Sopenharmony_ci		u8 action_code;
25462306a36Sopenharmony_ci	} __packed __aligned(2) action;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (!sdata)
25762306a36Sopenharmony_ci		return;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (skb->len < rtap_space + sizeof(action) +
26262306a36Sopenharmony_ci		       VHT_MUMIMO_GROUPS_DATA_LEN)
26362306a36Sopenharmony_ci		return;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr))
26662306a36Sopenharmony_ci		return;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	skb_copy_bits(skb, rtap_space, &action, sizeof(action));
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!ieee80211_is_action(action.hdr.frame_control))
27162306a36Sopenharmony_ci		return;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (action.category != WLAN_CATEGORY_VHT)
27462306a36Sopenharmony_ci		return;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT)
27762306a36Sopenharmony_ci		return;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr))
28062306a36Sopenharmony_ci		return;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	skb = skb_copy(skb, GFP_ATOMIC);
28362306a36Sopenharmony_ci	if (!skb)
28462306a36Sopenharmony_ci		return;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	ieee80211_queue_skb_to_iface(sdata, -1, NULL, skb);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/*
29062306a36Sopenharmony_ci * ieee80211_add_rx_radiotap_header - add radiotap header
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * add a radiotap header containing all the fields which the hardware provided.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_cistatic void
29562306a36Sopenharmony_ciieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
29662306a36Sopenharmony_ci				 struct sk_buff *skb,
29762306a36Sopenharmony_ci				 struct ieee80211_rate *rate,
29862306a36Sopenharmony_ci				 int rtap_len, bool has_fcs)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
30162306a36Sopenharmony_ci	struct ieee80211_radiotap_header *rthdr;
30262306a36Sopenharmony_ci	unsigned char *pos;
30362306a36Sopenharmony_ci	__le32 *it_present;
30462306a36Sopenharmony_ci	u32 it_present_val;
30562306a36Sopenharmony_ci	u16 rx_flags = 0;
30662306a36Sopenharmony_ci	u16 channel_flags = 0;
30762306a36Sopenharmony_ci	u32 tlvs_len = 0;
30862306a36Sopenharmony_ci	int mpdulen, chain;
30962306a36Sopenharmony_ci	unsigned long chains = status->chains;
31062306a36Sopenharmony_ci	struct ieee80211_radiotap_he he = {};
31162306a36Sopenharmony_ci	struct ieee80211_radiotap_he_mu he_mu = {};
31262306a36Sopenharmony_ci	struct ieee80211_radiotap_lsig lsig = {};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_HE) {
31562306a36Sopenharmony_ci		he = *(struct ieee80211_radiotap_he *)skb->data;
31662306a36Sopenharmony_ci		skb_pull(skb, sizeof(he));
31762306a36Sopenharmony_ci		WARN_ON_ONCE(status->encoding != RX_ENC_HE);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
32162306a36Sopenharmony_ci		he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
32262306a36Sopenharmony_ci		skb_pull(skb, sizeof(he_mu));
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
32662306a36Sopenharmony_ci		lsig = *(struct ieee80211_radiotap_lsig *)skb->data;
32762306a36Sopenharmony_ci		skb_pull(skb, sizeof(lsig));
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
33162306a36Sopenharmony_ci		/* data is pointer at tlv all other info was pulled off */
33262306a36Sopenharmony_ci		tlvs_len = skb_mac_header(skb) - skb->data;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	mpdulen = skb->len;
33662306a36Sopenharmony_ci	if (!(has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)))
33762306a36Sopenharmony_ci		mpdulen += FCS_LEN;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	rthdr = skb_push(skb, rtap_len - tlvs_len);
34062306a36Sopenharmony_ci	memset(rthdr, 0, rtap_len - tlvs_len);
34162306a36Sopenharmony_ci	it_present = &rthdr->it_present;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* radiotap header, set always present flags */
34462306a36Sopenharmony_ci	rthdr->it_len = cpu_to_le16(rtap_len);
34562306a36Sopenharmony_ci	it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
34662306a36Sopenharmony_ci			 BIT(IEEE80211_RADIOTAP_CHANNEL) |
34762306a36Sopenharmony_ci			 BIT(IEEE80211_RADIOTAP_RX_FLAGS);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!status->chains)
35062306a36Sopenharmony_ci		it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
35362306a36Sopenharmony_ci		it_present_val |=
35462306a36Sopenharmony_ci			BIT(IEEE80211_RADIOTAP_EXT) |
35562306a36Sopenharmony_ci			BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
35662306a36Sopenharmony_ci		put_unaligned_le32(it_present_val, it_present);
35762306a36Sopenharmony_ci		it_present++;
35862306a36Sopenharmony_ci		it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
35962306a36Sopenharmony_ci				 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
36362306a36Sopenharmony_ci		it_present_val |= BIT(IEEE80211_RADIOTAP_TLV);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	put_unaligned_le32(it_present_val, it_present);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* This references through an offset into it_optional[] rather
36862306a36Sopenharmony_ci	 * than via it_present otherwise later uses of pos will cause
36962306a36Sopenharmony_ci	 * the compiler to think we have walked past the end of the
37062306a36Sopenharmony_ci	 * struct member.
37162306a36Sopenharmony_ci	 */
37262306a36Sopenharmony_ci	pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* the order of the following fields is important */
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_TSFT */
37762306a36Sopenharmony_ci	if (ieee80211_have_rx_timestamp(status)) {
37862306a36Sopenharmony_ci		/* padding */
37962306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 7)
38062306a36Sopenharmony_ci			*pos++ = 0;
38162306a36Sopenharmony_ci		put_unaligned_le64(
38262306a36Sopenharmony_ci			ieee80211_calculate_rx_timestamp(local, status,
38362306a36Sopenharmony_ci							 mpdulen, 0),
38462306a36Sopenharmony_ci			pos);
38562306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_TSFT));
38662306a36Sopenharmony_ci		pos += 8;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_FLAGS */
39062306a36Sopenharmony_ci	if (has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS))
39162306a36Sopenharmony_ci		*pos |= IEEE80211_RADIOTAP_F_FCS;
39262306a36Sopenharmony_ci	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
39362306a36Sopenharmony_ci		*pos |= IEEE80211_RADIOTAP_F_BADFCS;
39462306a36Sopenharmony_ci	if (status->enc_flags & RX_ENC_FLAG_SHORTPRE)
39562306a36Sopenharmony_ci		*pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
39662306a36Sopenharmony_ci	pos++;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_RATE */
39962306a36Sopenharmony_ci	if (!rate || status->encoding != RX_ENC_LEGACY) {
40062306a36Sopenharmony_ci		/*
40162306a36Sopenharmony_ci		 * Without rate information don't add it. If we have,
40262306a36Sopenharmony_ci		 * MCS information is a separate field in radiotap,
40362306a36Sopenharmony_ci		 * added below. The byte here is needed as padding
40462306a36Sopenharmony_ci		 * for the channel though, so initialise it to 0.
40562306a36Sopenharmony_ci		 */
40662306a36Sopenharmony_ci		*pos = 0;
40762306a36Sopenharmony_ci	} else {
40862306a36Sopenharmony_ci		int shift = 0;
40962306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_RATE));
41062306a36Sopenharmony_ci		if (status->bw == RATE_INFO_BW_10)
41162306a36Sopenharmony_ci			shift = 1;
41262306a36Sopenharmony_ci		else if (status->bw == RATE_INFO_BW_5)
41362306a36Sopenharmony_ci			shift = 2;
41462306a36Sopenharmony_ci		*pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift));
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci	pos++;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_CHANNEL */
41962306a36Sopenharmony_ci	/* TODO: frequency offset in KHz */
42062306a36Sopenharmony_ci	put_unaligned_le16(status->freq, pos);
42162306a36Sopenharmony_ci	pos += 2;
42262306a36Sopenharmony_ci	if (status->bw == RATE_INFO_BW_10)
42362306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_HALF;
42462306a36Sopenharmony_ci	else if (status->bw == RATE_INFO_BW_5)
42562306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_QUARTER;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (status->band == NL80211_BAND_5GHZ ||
42862306a36Sopenharmony_ci	    status->band == NL80211_BAND_6GHZ)
42962306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
43062306a36Sopenharmony_ci	else if (status->encoding != RX_ENC_LEGACY)
43162306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
43262306a36Sopenharmony_ci	else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
43362306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
43462306a36Sopenharmony_ci	else if (rate)
43562306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ;
43662306a36Sopenharmony_ci	else
43762306a36Sopenharmony_ci		channel_flags |= IEEE80211_CHAN_2GHZ;
43862306a36Sopenharmony_ci	put_unaligned_le16(channel_flags, pos);
43962306a36Sopenharmony_ci	pos += 2;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
44262306a36Sopenharmony_ci	if (ieee80211_hw_check(&local->hw, SIGNAL_DBM) &&
44362306a36Sopenharmony_ci	    !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
44462306a36Sopenharmony_ci		*pos = status->signal;
44562306a36Sopenharmony_ci		rthdr->it_present |=
44662306a36Sopenharmony_ci			cpu_to_le32(BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL));
44762306a36Sopenharmony_ci		pos++;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!status->chains) {
45362306a36Sopenharmony_ci		/* IEEE80211_RADIOTAP_ANTENNA */
45462306a36Sopenharmony_ci		*pos = status->antenna;
45562306a36Sopenharmony_ci		pos++;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* IEEE80211_RADIOTAP_RX_FLAGS */
46162306a36Sopenharmony_ci	/* ensure 2 byte alignment for the 2 byte field as required */
46262306a36Sopenharmony_ci	if ((pos - (u8 *)rthdr) & 1)
46362306a36Sopenharmony_ci		*pos++ = 0;
46462306a36Sopenharmony_ci	if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
46562306a36Sopenharmony_ci		rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
46662306a36Sopenharmony_ci	put_unaligned_le16(rx_flags, pos);
46762306a36Sopenharmony_ci	pos += 2;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HT) {
47062306a36Sopenharmony_ci		unsigned int stbc;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS));
47362306a36Sopenharmony_ci		*pos = local->hw.radiotap_mcs_details;
47462306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_HT_GF)
47562306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
47662306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_LDPC)
47762306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FEC;
47862306a36Sopenharmony_ci		pos++;
47962306a36Sopenharmony_ci		*pos = 0;
48062306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
48162306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_SGI;
48262306a36Sopenharmony_ci		if (status->bw == RATE_INFO_BW_40)
48362306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_BW_40;
48462306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_HT_GF)
48562306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_FMT_GF;
48662306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_LDPC)
48762306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
48862306a36Sopenharmony_ci		stbc = (status->enc_flags & RX_ENC_FLAG_STBC_MASK) >> RX_ENC_FLAG_STBC_SHIFT;
48962306a36Sopenharmony_ci		*pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT;
49062306a36Sopenharmony_ci		pos++;
49162306a36Sopenharmony_ci		*pos++ = status->rate_idx;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
49562306a36Sopenharmony_ci		u16 flags = 0;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		/* ensure 4 byte alignment */
49862306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 3)
49962306a36Sopenharmony_ci			pos++;
50062306a36Sopenharmony_ci		rthdr->it_present |=
50162306a36Sopenharmony_ci			cpu_to_le32(BIT(IEEE80211_RADIOTAP_AMPDU_STATUS));
50262306a36Sopenharmony_ci		put_unaligned_le32(status->ampdu_reference, pos);
50362306a36Sopenharmony_ci		pos += 4;
50462306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN)
50562306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
50662306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_IS_LAST)
50762306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
50862306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
50962306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
51062306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
51162306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
51262306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
51362306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
51462306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
51562306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
51662306a36Sopenharmony_ci		put_unaligned_le16(flags, pos);
51762306a36Sopenharmony_ci		pos += 2;
51862306a36Sopenharmony_ci		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
51962306a36Sopenharmony_ci			*pos++ = status->ampdu_delimiter_crc;
52062306a36Sopenharmony_ci		else
52162306a36Sopenharmony_ci			*pos++ = 0;
52262306a36Sopenharmony_ci		*pos++ = 0;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (status->encoding == RX_ENC_VHT) {
52662306a36Sopenharmony_ci		u16 known = local->hw.radiotap_vht_details;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT));
52962306a36Sopenharmony_ci		put_unaligned_le16(known, pos);
53062306a36Sopenharmony_ci		pos += 2;
53162306a36Sopenharmony_ci		/* flags */
53262306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
53362306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
53462306a36Sopenharmony_ci		/* in VHT, STBC is binary */
53562306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_STBC_MASK)
53662306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
53762306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_BF)
53862306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
53962306a36Sopenharmony_ci		pos++;
54062306a36Sopenharmony_ci		/* bandwidth */
54162306a36Sopenharmony_ci		switch (status->bw) {
54262306a36Sopenharmony_ci		case RATE_INFO_BW_80:
54362306a36Sopenharmony_ci			*pos++ = 4;
54462306a36Sopenharmony_ci			break;
54562306a36Sopenharmony_ci		case RATE_INFO_BW_160:
54662306a36Sopenharmony_ci			*pos++ = 11;
54762306a36Sopenharmony_ci			break;
54862306a36Sopenharmony_ci		case RATE_INFO_BW_40:
54962306a36Sopenharmony_ci			*pos++ = 1;
55062306a36Sopenharmony_ci			break;
55162306a36Sopenharmony_ci		default:
55262306a36Sopenharmony_ci			*pos++ = 0;
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci		/* MCS/NSS */
55562306a36Sopenharmony_ci		*pos = (status->rate_idx << 4) | status->nss;
55662306a36Sopenharmony_ci		pos += 4;
55762306a36Sopenharmony_ci		/* coding field */
55862306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_LDPC)
55962306a36Sopenharmony_ci			*pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
56062306a36Sopenharmony_ci		pos++;
56162306a36Sopenharmony_ci		/* group ID */
56262306a36Sopenharmony_ci		pos++;
56362306a36Sopenharmony_ci		/* partial_aid */
56462306a36Sopenharmony_ci		pos += 2;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (local->hw.radiotap_timestamp.units_pos >= 0) {
56862306a36Sopenharmony_ci		u16 accuracy = 0;
56962306a36Sopenharmony_ci		u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		rthdr->it_present |=
57262306a36Sopenharmony_ci			cpu_to_le32(BIT(IEEE80211_RADIOTAP_TIMESTAMP));
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		/* ensure 8 byte alignment */
57562306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 7)
57662306a36Sopenharmony_ci			pos++;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		put_unaligned_le64(status->device_timestamp, pos);
57962306a36Sopenharmony_ci		pos += sizeof(u64);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		if (local->hw.radiotap_timestamp.accuracy >= 0) {
58262306a36Sopenharmony_ci			accuracy = local->hw.radiotap_timestamp.accuracy;
58362306a36Sopenharmony_ci			flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY;
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci		put_unaligned_le16(accuracy, pos);
58662306a36Sopenharmony_ci		pos += sizeof(u16);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		*pos++ = local->hw.radiotap_timestamp.units_pos;
58962306a36Sopenharmony_ci		*pos++ = flags;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HE &&
59362306a36Sopenharmony_ci	    status->flag & RX_FLAG_RADIOTAP_HE) {
59462306a36Sopenharmony_ci#define HE_PREP(f, val)	le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f)
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
59762306a36Sopenharmony_ci			he.data6 |= HE_PREP(DATA6_NSTS,
59862306a36Sopenharmony_ci					    FIELD_GET(RX_ENC_FLAG_STBC_MASK,
59962306a36Sopenharmony_ci						      status->enc_flags));
60062306a36Sopenharmony_ci			he.data3 |= HE_PREP(DATA3_STBC, 1);
60162306a36Sopenharmony_ci		} else {
60262306a36Sopenharmony_ci			he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci#define CHECK_GI(s) \
60662306a36Sopenharmony_ci	BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
60762306a36Sopenharmony_ci		     (int)NL80211_RATE_INFO_HE_GI_##s)
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		CHECK_GI(0_8);
61062306a36Sopenharmony_ci		CHECK_GI(1_6);
61162306a36Sopenharmony_ci		CHECK_GI(3_2);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
61462306a36Sopenharmony_ci		he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
61562306a36Sopenharmony_ci		he.data3 |= HE_PREP(DATA3_CODING,
61662306a36Sopenharmony_ci				    !!(status->enc_flags & RX_ENC_FLAG_LDPC));
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		switch (status->bw) {
62162306a36Sopenharmony_ci		case RATE_INFO_BW_20:
62262306a36Sopenharmony_ci			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62362306a36Sopenharmony_ci					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
62462306a36Sopenharmony_ci			break;
62562306a36Sopenharmony_ci		case RATE_INFO_BW_40:
62662306a36Sopenharmony_ci			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62762306a36Sopenharmony_ci					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
62862306a36Sopenharmony_ci			break;
62962306a36Sopenharmony_ci		case RATE_INFO_BW_80:
63062306a36Sopenharmony_ci			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63162306a36Sopenharmony_ci					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		case RATE_INFO_BW_160:
63462306a36Sopenharmony_ci			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63562306a36Sopenharmony_ci					    IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
63662306a36Sopenharmony_ci			break;
63762306a36Sopenharmony_ci		case RATE_INFO_BW_HE_RU:
63862306a36Sopenharmony_ci#define CHECK_RU_ALLOC(s) \
63962306a36Sopenharmony_ci	BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
64062306a36Sopenharmony_ci		     NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci			CHECK_RU_ALLOC(26);
64362306a36Sopenharmony_ci			CHECK_RU_ALLOC(52);
64462306a36Sopenharmony_ci			CHECK_RU_ALLOC(106);
64562306a36Sopenharmony_ci			CHECK_RU_ALLOC(242);
64662306a36Sopenharmony_ci			CHECK_RU_ALLOC(484);
64762306a36Sopenharmony_ci			CHECK_RU_ALLOC(996);
64862306a36Sopenharmony_ci			CHECK_RU_ALLOC(2x996);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci			he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
65162306a36Sopenharmony_ci					    status->he_ru + 4);
65262306a36Sopenharmony_ci			break;
65362306a36Sopenharmony_ci		default:
65462306a36Sopenharmony_ci			WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		/* ensure 2 byte alignment */
65862306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 1)
65962306a36Sopenharmony_ci			pos++;
66062306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE));
66162306a36Sopenharmony_ci		memcpy(pos, &he, sizeof(he));
66262306a36Sopenharmony_ci		pos += sizeof(he);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (status->encoding == RX_ENC_HE &&
66662306a36Sopenharmony_ci	    status->flag & RX_FLAG_RADIOTAP_HE_MU) {
66762306a36Sopenharmony_ci		/* ensure 2 byte alignment */
66862306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 1)
66962306a36Sopenharmony_ci			pos++;
67062306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE_MU));
67162306a36Sopenharmony_ci		memcpy(pos, &he_mu, sizeof(he_mu));
67262306a36Sopenharmony_ci		pos += sizeof(he_mu);
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (status->flag & RX_FLAG_NO_PSDU) {
67662306a36Sopenharmony_ci		rthdr->it_present |=
67762306a36Sopenharmony_ci			cpu_to_le32(BIT(IEEE80211_RADIOTAP_ZERO_LEN_PSDU));
67862306a36Sopenharmony_ci		*pos++ = status->zero_length_psdu_type;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
68262306a36Sopenharmony_ci		/* ensure 2 byte alignment */
68362306a36Sopenharmony_ci		while ((pos - (u8 *)rthdr) & 1)
68462306a36Sopenharmony_ci			pos++;
68562306a36Sopenharmony_ci		rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_LSIG));
68662306a36Sopenharmony_ci		memcpy(pos, &lsig, sizeof(lsig));
68762306a36Sopenharmony_ci		pos += sizeof(lsig);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
69162306a36Sopenharmony_ci		*pos++ = status->chain_signal[chain];
69262306a36Sopenharmony_ci		*pos++ = chain;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic struct sk_buff *
69762306a36Sopenharmony_ciieee80211_make_monitor_skb(struct ieee80211_local *local,
69862306a36Sopenharmony_ci			   struct sk_buff **origskb,
69962306a36Sopenharmony_ci			   struct ieee80211_rate *rate,
70062306a36Sopenharmony_ci			   int rtap_space, bool use_origskb)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(*origskb);
70362306a36Sopenharmony_ci	int rt_hdrlen, needed_headroom;
70462306a36Sopenharmony_ci	struct sk_buff *skb;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* room for the radiotap header based on driver features */
70762306a36Sopenharmony_ci	rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, *origskb);
70862306a36Sopenharmony_ci	needed_headroom = rt_hdrlen - rtap_space;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (use_origskb) {
71162306a36Sopenharmony_ci		/* only need to expand headroom if necessary */
71262306a36Sopenharmony_ci		skb = *origskb;
71362306a36Sopenharmony_ci		*origskb = NULL;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		/*
71662306a36Sopenharmony_ci		 * This shouldn't trigger often because most devices have an
71762306a36Sopenharmony_ci		 * RX header they pull before we get here, and that should
71862306a36Sopenharmony_ci		 * be big enough for our radiotap information. We should
71962306a36Sopenharmony_ci		 * probably export the length to drivers so that we can have
72062306a36Sopenharmony_ci		 * them allocate enough headroom to start with.
72162306a36Sopenharmony_ci		 */
72262306a36Sopenharmony_ci		if (skb_headroom(skb) < needed_headroom &&
72362306a36Sopenharmony_ci		    pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
72462306a36Sopenharmony_ci			dev_kfree_skb(skb);
72562306a36Sopenharmony_ci			return NULL;
72662306a36Sopenharmony_ci		}
72762306a36Sopenharmony_ci	} else {
72862306a36Sopenharmony_ci		/*
72962306a36Sopenharmony_ci		 * Need to make a copy and possibly remove radiotap header
73062306a36Sopenharmony_ci		 * and FCS from the original.
73162306a36Sopenharmony_ci		 */
73262306a36Sopenharmony_ci		skb = skb_copy_expand(*origskb, needed_headroom + NET_SKB_PAD,
73362306a36Sopenharmony_ci				      0, GFP_ATOMIC);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		if (!skb)
73662306a36Sopenharmony_ci			return NULL;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* prepend radiotap information */
74062306a36Sopenharmony_ci	ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	skb_reset_mac_header(skb);
74362306a36Sopenharmony_ci	skb->ip_summed = CHECKSUM_UNNECESSARY;
74462306a36Sopenharmony_ci	skb->pkt_type = PACKET_OTHERHOST;
74562306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_802_2);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return skb;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/*
75162306a36Sopenharmony_ci * This function copies a received frame to all monitor interfaces and
75262306a36Sopenharmony_ci * returns a cleaned-up SKB that no longer includes the FCS nor the
75362306a36Sopenharmony_ci * radiotap header the driver might have added.
75462306a36Sopenharmony_ci */
75562306a36Sopenharmony_cistatic struct sk_buff *
75662306a36Sopenharmony_ciieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
75762306a36Sopenharmony_ci		     struct ieee80211_rate *rate)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
76062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
76162306a36Sopenharmony_ci	struct sk_buff *monskb = NULL;
76262306a36Sopenharmony_ci	int present_fcs_len = 0;
76362306a36Sopenharmony_ci	unsigned int rtap_space = 0;
76462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *monitor_sdata =
76562306a36Sopenharmony_ci		rcu_dereference(local->monitor_sdata);
76662306a36Sopenharmony_ci	bool only_monitor = false;
76762306a36Sopenharmony_ci	unsigned int min_head_len;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (WARN_ON_ONCE(status->flag & RX_FLAG_RADIOTAP_TLV_AT_END &&
77062306a36Sopenharmony_ci			 !skb_mac_header_was_set(origskb))) {
77162306a36Sopenharmony_ci		/* with this skb no way to know where frame payload starts */
77262306a36Sopenharmony_ci		dev_kfree_skb(origskb);
77362306a36Sopenharmony_ci		return NULL;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_HE)
77762306a36Sopenharmony_ci		rtap_space += sizeof(struct ieee80211_radiotap_he);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
78062306a36Sopenharmony_ci		rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_LSIG)
78362306a36Sopenharmony_ci		rtap_space += sizeof(struct ieee80211_radiotap_lsig);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
78662306a36Sopenharmony_ci		rtap_space += skb_mac_header(origskb) - &origskb->data[rtap_space];
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	min_head_len = rtap_space;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	/*
79162306a36Sopenharmony_ci	 * First, we may need to make a copy of the skb because
79262306a36Sopenharmony_ci	 *  (1) we need to modify it for radiotap (if not present), and
79362306a36Sopenharmony_ci	 *  (2) the other RX handlers will modify the skb we got.
79462306a36Sopenharmony_ci	 *
79562306a36Sopenharmony_ci	 * We don't need to, of course, if we aren't going to return
79662306a36Sopenharmony_ci	 * the SKB because it has a bad FCS/PLCP checksum.
79762306a36Sopenharmony_ci	 */
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_NO_PSDU)) {
80062306a36Sopenharmony_ci		if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
80162306a36Sopenharmony_ci			if (unlikely(origskb->len <= FCS_LEN + rtap_space)) {
80262306a36Sopenharmony_ci				/* driver bug */
80362306a36Sopenharmony_ci				WARN_ON(1);
80462306a36Sopenharmony_ci				dev_kfree_skb(origskb);
80562306a36Sopenharmony_ci				return NULL;
80662306a36Sopenharmony_ci			}
80762306a36Sopenharmony_ci			present_fcs_len = FCS_LEN;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		/* also consider the hdr->frame_control */
81162306a36Sopenharmony_ci		min_head_len += 2;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* ensure that the expected data elements are in skb head */
81562306a36Sopenharmony_ci	if (!pskb_may_pull(origskb, min_head_len)) {
81662306a36Sopenharmony_ci		dev_kfree_skb(origskb);
81762306a36Sopenharmony_ci		return NULL;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	only_monitor = should_drop_frame(origskb, present_fcs_len, rtap_space);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
82362306a36Sopenharmony_ci		if (only_monitor) {
82462306a36Sopenharmony_ci			dev_kfree_skb(origskb);
82562306a36Sopenharmony_ci			return NULL;
82662306a36Sopenharmony_ci		}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		return ieee80211_clean_skb(origskb, present_fcs_len,
82962306a36Sopenharmony_ci					   rtap_space);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
83562306a36Sopenharmony_ci		bool last_monitor = list_is_last(&sdata->u.mntr.list,
83662306a36Sopenharmony_ci						 &local->mon_list);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		if (!monskb)
83962306a36Sopenharmony_ci			monskb = ieee80211_make_monitor_skb(local, &origskb,
84062306a36Sopenharmony_ci							    rate, rtap_space,
84162306a36Sopenharmony_ci							    only_monitor &&
84262306a36Sopenharmony_ci							    last_monitor);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci		if (monskb) {
84562306a36Sopenharmony_ci			struct sk_buff *skb;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci			if (last_monitor) {
84862306a36Sopenharmony_ci				skb = monskb;
84962306a36Sopenharmony_ci				monskb = NULL;
85062306a36Sopenharmony_ci			} else {
85162306a36Sopenharmony_ci				skb = skb_clone(monskb, GFP_ATOMIC);
85262306a36Sopenharmony_ci			}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci			if (skb) {
85562306a36Sopenharmony_ci				skb->dev = sdata->dev;
85662306a36Sopenharmony_ci				dev_sw_netstats_rx_add(skb->dev, skb->len);
85762306a36Sopenharmony_ci				netif_receive_skb(skb);
85862306a36Sopenharmony_ci			}
85962306a36Sopenharmony_ci		}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		if (last_monitor)
86262306a36Sopenharmony_ci			break;
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* this happens if last_monitor was erroneously false */
86662306a36Sopenharmony_ci	dev_kfree_skb(monskb);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* ditto */
86962306a36Sopenharmony_ci	if (!origskb)
87062306a36Sopenharmony_ci		return NULL;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space);
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
87862306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
87962306a36Sopenharmony_ci	int tid, seqno_idx, security_idx;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* does the frame have a qos control field? */
88262306a36Sopenharmony_ci	if (ieee80211_is_data_qos(hdr->frame_control)) {
88362306a36Sopenharmony_ci		u8 *qc = ieee80211_get_qos_ctl(hdr);
88462306a36Sopenharmony_ci		/* frame has qos control */
88562306a36Sopenharmony_ci		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
88662306a36Sopenharmony_ci		if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
88762306a36Sopenharmony_ci			status->rx_flags |= IEEE80211_RX_AMSDU;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		seqno_idx = tid;
89062306a36Sopenharmony_ci		security_idx = tid;
89162306a36Sopenharmony_ci	} else {
89262306a36Sopenharmony_ci		/*
89362306a36Sopenharmony_ci		 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
89462306a36Sopenharmony_ci		 *
89562306a36Sopenharmony_ci		 *	Sequence numbers for management frames, QoS data
89662306a36Sopenharmony_ci		 *	frames with a broadcast/multicast address in the
89762306a36Sopenharmony_ci		 *	Address 1 field, and all non-QoS data frames sent
89862306a36Sopenharmony_ci		 *	by QoS STAs are assigned using an additional single
89962306a36Sopenharmony_ci		 *	modulo-4096 counter, [...]
90062306a36Sopenharmony_ci		 *
90162306a36Sopenharmony_ci		 * We also use that counter for non-QoS STAs.
90262306a36Sopenharmony_ci		 */
90362306a36Sopenharmony_ci		seqno_idx = IEEE80211_NUM_TIDS;
90462306a36Sopenharmony_ci		security_idx = 0;
90562306a36Sopenharmony_ci		if (ieee80211_is_mgmt(hdr->frame_control))
90662306a36Sopenharmony_ci			security_idx = IEEE80211_NUM_TIDS;
90762306a36Sopenharmony_ci		tid = 0;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	rx->seqno_idx = seqno_idx;
91162306a36Sopenharmony_ci	rx->security_idx = security_idx;
91262306a36Sopenharmony_ci	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
91362306a36Sopenharmony_ci	 * For now, set skb->priority to 0 for other cases. */
91462306a36Sopenharmony_ci	rx->skb->priority = (tid > 7) ? 0 : tid;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/**
91862306a36Sopenharmony_ci * DOC: Packet alignment
91962306a36Sopenharmony_ci *
92062306a36Sopenharmony_ci * Drivers always need to pass packets that are aligned to two-byte boundaries
92162306a36Sopenharmony_ci * to the stack.
92262306a36Sopenharmony_ci *
92362306a36Sopenharmony_ci * Additionally, should, if possible, align the payload data in a way that
92462306a36Sopenharmony_ci * guarantees that the contained IP header is aligned to a four-byte
92562306a36Sopenharmony_ci * boundary. In the case of regular frames, this simply means aligning the
92662306a36Sopenharmony_ci * payload to a four-byte boundary (because either the IP header is directly
92762306a36Sopenharmony_ci * contained, or IV/RFC1042 headers that have a length divisible by four are
92862306a36Sopenharmony_ci * in front of it).  If the payload data is not properly aligned and the
92962306a36Sopenharmony_ci * architecture doesn't support efficient unaligned operations, mac80211
93062306a36Sopenharmony_ci * will align the data.
93162306a36Sopenharmony_ci *
93262306a36Sopenharmony_ci * With A-MSDU frames, however, the payload data address must yield two modulo
93362306a36Sopenharmony_ci * four because there are 14-byte 802.3 headers within the A-MSDU frames that
93462306a36Sopenharmony_ci * push the IP header further back to a multiple of four again. Thankfully, the
93562306a36Sopenharmony_ci * specs were sane enough this time around to require padding each A-MSDU
93662306a36Sopenharmony_ci * subframe to a length that is a multiple of four.
93762306a36Sopenharmony_ci *
93862306a36Sopenharmony_ci * Padding like Atheros hardware adds which is between the 802.11 header and
93962306a36Sopenharmony_ci * the payload is not supported, the driver is required to move the 802.11
94062306a36Sopenharmony_ci * header to be directly in front of the payload in that case.
94162306a36Sopenharmony_ci */
94262306a36Sopenharmony_cistatic void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
94562306a36Sopenharmony_ci	WARN_ON_ONCE((unsigned long)rx->skb->data & 1);
94662306a36Sopenharmony_ci#endif
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci/* rx handlers */
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (is_multicast_ether_addr(hdr->addr1))
95762306a36Sopenharmony_ci		return 0;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return ieee80211_is_robust_mgmt_frame(skb);
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	if (!is_multicast_ether_addr(hdr->addr1))
96862306a36Sopenharmony_ci		return 0;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	return ieee80211_is_robust_mgmt_frame(skb);
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */
97562306a36Sopenharmony_cistatic int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
97862306a36Sopenharmony_ci	struct ieee80211_mmie *mmie;
97962306a36Sopenharmony_ci	struct ieee80211_mmie_16 *mmie16;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
98262306a36Sopenharmony_ci		return -1;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (!ieee80211_is_robust_mgmt_frame(skb) &&
98562306a36Sopenharmony_ci	    !ieee80211_is_beacon(hdr->frame_control))
98662306a36Sopenharmony_ci		return -1; /* not a robust management frame */
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	mmie = (struct ieee80211_mmie *)
98962306a36Sopenharmony_ci		(skb->data + skb->len - sizeof(*mmie));
99062306a36Sopenharmony_ci	if (mmie->element_id == WLAN_EID_MMIE &&
99162306a36Sopenharmony_ci	    mmie->length == sizeof(*mmie) - 2)
99262306a36Sopenharmony_ci		return le16_to_cpu(mmie->key_id);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	mmie16 = (struct ieee80211_mmie_16 *)
99562306a36Sopenharmony_ci		(skb->data + skb->len - sizeof(*mmie16));
99662306a36Sopenharmony_ci	if (skb->len >= 24 + sizeof(*mmie16) &&
99762306a36Sopenharmony_ci	    mmie16->element_id == WLAN_EID_MMIE &&
99862306a36Sopenharmony_ci	    mmie16->length == sizeof(*mmie16) - 2)
99962306a36Sopenharmony_ci		return le16_to_cpu(mmie16->key_id);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	return -1;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int ieee80211_get_keyid(struct sk_buff *skb)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
100762306a36Sopenharmony_ci	__le16 fc = hdr->frame_control;
100862306a36Sopenharmony_ci	int hdrlen = ieee80211_hdrlen(fc);
100962306a36Sopenharmony_ci	u8 keyid;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* WEP, TKIP, CCMP and GCMP */
101262306a36Sopenharmony_ci	if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN))
101362306a36Sopenharmony_ci		return -EINVAL;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	skb_copy_bits(skb, hdrlen + 3, &keyid, 1);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	keyid >>= 6;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return keyid;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
102562306a36Sopenharmony_ci	char *dev_addr = rx->sdata->vif.addr;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (ieee80211_is_data(hdr->frame_control)) {
102862306a36Sopenharmony_ci		if (is_multicast_ether_addr(hdr->addr1)) {
102962306a36Sopenharmony_ci			if (ieee80211_has_tods(hdr->frame_control) ||
103062306a36Sopenharmony_ci			    !ieee80211_has_fromds(hdr->frame_control))
103162306a36Sopenharmony_ci				return RX_DROP_MONITOR;
103262306a36Sopenharmony_ci			if (ether_addr_equal(hdr->addr3, dev_addr))
103362306a36Sopenharmony_ci				return RX_DROP_MONITOR;
103462306a36Sopenharmony_ci		} else {
103562306a36Sopenharmony_ci			if (!ieee80211_has_a4(hdr->frame_control))
103662306a36Sopenharmony_ci				return RX_DROP_MONITOR;
103762306a36Sopenharmony_ci			if (ether_addr_equal(hdr->addr4, dev_addr))
103862306a36Sopenharmony_ci				return RX_DROP_MONITOR;
103962306a36Sopenharmony_ci		}
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* If there is not an established peer link and this is not a peer link
104362306a36Sopenharmony_ci	 * establisment frame, beacon or probe, drop the frame.
104462306a36Sopenharmony_ci	 */
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) {
104762306a36Sopenharmony_ci		struct ieee80211_mgmt *mgmt;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		if (!ieee80211_is_mgmt(hdr->frame_control))
105062306a36Sopenharmony_ci			return RX_DROP_MONITOR;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		if (ieee80211_is_action(hdr->frame_control)) {
105362306a36Sopenharmony_ci			u8 category;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci			/* make sure category field is present */
105662306a36Sopenharmony_ci			if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
105762306a36Sopenharmony_ci				return RX_DROP_MONITOR;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci			mgmt = (struct ieee80211_mgmt *)hdr;
106062306a36Sopenharmony_ci			category = mgmt->u.action.category;
106162306a36Sopenharmony_ci			if (category != WLAN_CATEGORY_MESH_ACTION &&
106262306a36Sopenharmony_ci			    category != WLAN_CATEGORY_SELF_PROTECTED)
106362306a36Sopenharmony_ci				return RX_DROP_MONITOR;
106462306a36Sopenharmony_ci			return RX_CONTINUE;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		if (ieee80211_is_probe_req(hdr->frame_control) ||
106862306a36Sopenharmony_ci		    ieee80211_is_probe_resp(hdr->frame_control) ||
106962306a36Sopenharmony_ci		    ieee80211_is_beacon(hdr->frame_control) ||
107062306a36Sopenharmony_ci		    ieee80211_is_auth(hdr->frame_control))
107162306a36Sopenharmony_ci			return RX_CONTINUE;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		return RX_DROP_MONITOR;
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return RX_CONTINUE;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
108062306a36Sopenharmony_ci					      int index)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
108362306a36Sopenharmony_ci	struct sk_buff *tail = skb_peek_tail(frames);
108462306a36Sopenharmony_ci	struct ieee80211_rx_status *status;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (tid_agg_rx->reorder_buf_filtered &&
108762306a36Sopenharmony_ci	    tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
108862306a36Sopenharmony_ci		return true;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (!tail)
109162306a36Sopenharmony_ci		return false;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	status = IEEE80211_SKB_RXCB(tail);
109462306a36Sopenharmony_ci	if (status->flag & RX_FLAG_AMSDU_MORE)
109562306a36Sopenharmony_ci		return false;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return true;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
110162306a36Sopenharmony_ci					    struct tid_ampdu_rx *tid_agg_rx,
110262306a36Sopenharmony_ci					    int index,
110362306a36Sopenharmony_ci					    struct sk_buff_head *frames)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index];
110662306a36Sopenharmony_ci	struct sk_buff *skb;
110762306a36Sopenharmony_ci	struct ieee80211_rx_status *status;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	lockdep_assert_held(&tid_agg_rx->reorder_lock);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (skb_queue_empty(skb_list))
111262306a36Sopenharmony_ci		goto no_frame;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
111562306a36Sopenharmony_ci		__skb_queue_purge(skb_list);
111662306a36Sopenharmony_ci		goto no_frame;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/* release frames from the reorder ring buffer */
112062306a36Sopenharmony_ci	tid_agg_rx->stored_mpdu_num--;
112162306a36Sopenharmony_ci	while ((skb = __skb_dequeue(skb_list))) {
112262306a36Sopenharmony_ci		status = IEEE80211_SKB_RXCB(skb);
112362306a36Sopenharmony_ci		status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
112462306a36Sopenharmony_ci		__skb_queue_tail(frames, skb);
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_cino_frame:
112862306a36Sopenharmony_ci	if (tid_agg_rx->reorder_buf_filtered)
112962306a36Sopenharmony_ci		tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
113062306a36Sopenharmony_ci	tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
113462306a36Sopenharmony_ci					     struct tid_ampdu_rx *tid_agg_rx,
113562306a36Sopenharmony_ci					     u16 head_seq_num,
113662306a36Sopenharmony_ci					     struct sk_buff_head *frames)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	int index;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	lockdep_assert_held(&tid_agg_rx->reorder_lock);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
114362306a36Sopenharmony_ci		index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
114462306a36Sopenharmony_ci		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
114562306a36Sopenharmony_ci						frames);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/*
115062306a36Sopenharmony_ci * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
115162306a36Sopenharmony_ci * the skb was added to the buffer longer than this time ago, the earlier
115262306a36Sopenharmony_ci * frames that have not yet been received are assumed to be lost and the skb
115362306a36Sopenharmony_ci * can be released for processing. This may also release other skb's from the
115462306a36Sopenharmony_ci * reorder buffer if there are no additional gaps between the frames.
115562306a36Sopenharmony_ci *
115662306a36Sopenharmony_ci * Callers must hold tid_agg_rx->reorder_lock.
115762306a36Sopenharmony_ci */
115862306a36Sopenharmony_ci#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_cistatic void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
116162306a36Sopenharmony_ci					  struct tid_ampdu_rx *tid_agg_rx,
116262306a36Sopenharmony_ci					  struct sk_buff_head *frames)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	int index, i, j;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	lockdep_assert_held(&tid_agg_rx->reorder_lock);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* release the buffer until next missing frame */
116962306a36Sopenharmony_ci	index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
117062306a36Sopenharmony_ci	if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
117162306a36Sopenharmony_ci	    tid_agg_rx->stored_mpdu_num) {
117262306a36Sopenharmony_ci		/*
117362306a36Sopenharmony_ci		 * No buffers ready to be released, but check whether any
117462306a36Sopenharmony_ci		 * frames in the reorder buffer have timed out.
117562306a36Sopenharmony_ci		 */
117662306a36Sopenharmony_ci		int skipped = 1;
117762306a36Sopenharmony_ci		for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
117862306a36Sopenharmony_ci		     j = (j + 1) % tid_agg_rx->buf_size) {
117962306a36Sopenharmony_ci			if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
118062306a36Sopenharmony_ci				skipped++;
118162306a36Sopenharmony_ci				continue;
118262306a36Sopenharmony_ci			}
118362306a36Sopenharmony_ci			if (skipped &&
118462306a36Sopenharmony_ci			    !time_after(jiffies, tid_agg_rx->reorder_time[j] +
118562306a36Sopenharmony_ci					HT_RX_REORDER_BUF_TIMEOUT))
118662306a36Sopenharmony_ci				goto set_release_timer;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci			/* don't leave incomplete A-MSDUs around */
118962306a36Sopenharmony_ci			for (i = (index + 1) % tid_agg_rx->buf_size; i != j;
119062306a36Sopenharmony_ci			     i = (i + 1) % tid_agg_rx->buf_size)
119162306a36Sopenharmony_ci				__skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci			ht_dbg_ratelimited(sdata,
119462306a36Sopenharmony_ci					   "release an RX reorder frame due to timeout on earlier frames\n");
119562306a36Sopenharmony_ci			ieee80211_release_reorder_frame(sdata, tid_agg_rx, j,
119662306a36Sopenharmony_ci							frames);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci			/*
119962306a36Sopenharmony_ci			 * Increment the head seq# also for the skipped slots.
120062306a36Sopenharmony_ci			 */
120162306a36Sopenharmony_ci			tid_agg_rx->head_seq_num =
120262306a36Sopenharmony_ci				(tid_agg_rx->head_seq_num +
120362306a36Sopenharmony_ci				 skipped) & IEEE80211_SN_MASK;
120462306a36Sopenharmony_ci			skipped = 0;
120562306a36Sopenharmony_ci		}
120662306a36Sopenharmony_ci	} else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
120762306a36Sopenharmony_ci		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
120862306a36Sopenharmony_ci						frames);
120962306a36Sopenharmony_ci		index =	tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (tid_agg_rx->stored_mpdu_num) {
121362306a36Sopenharmony_ci		j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci		for (; j != (index - 1) % tid_agg_rx->buf_size;
121662306a36Sopenharmony_ci		     j = (j + 1) % tid_agg_rx->buf_size) {
121762306a36Sopenharmony_ci			if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
121862306a36Sopenharmony_ci				break;
121962306a36Sopenharmony_ci		}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci set_release_timer:
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		if (!tid_agg_rx->removed)
122462306a36Sopenharmony_ci			mod_timer(&tid_agg_rx->reorder_timer,
122562306a36Sopenharmony_ci				  tid_agg_rx->reorder_time[j] + 1 +
122662306a36Sopenharmony_ci				  HT_RX_REORDER_BUF_TIMEOUT);
122762306a36Sopenharmony_ci	} else {
122862306a36Sopenharmony_ci		del_timer(&tid_agg_rx->reorder_timer);
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci/*
123362306a36Sopenharmony_ci * As this function belongs to the RX path it must be under
123462306a36Sopenharmony_ci * rcu_read_lock protection. It returns false if the frame
123562306a36Sopenharmony_ci * can be processed immediately, true if it was consumed.
123662306a36Sopenharmony_ci */
123762306a36Sopenharmony_cistatic bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
123862306a36Sopenharmony_ci					     struct tid_ampdu_rx *tid_agg_rx,
123962306a36Sopenharmony_ci					     struct sk_buff *skb,
124062306a36Sopenharmony_ci					     struct sk_buff_head *frames)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
124362306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
124462306a36Sopenharmony_ci	u16 sc = le16_to_cpu(hdr->seq_ctrl);
124562306a36Sopenharmony_ci	u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
124662306a36Sopenharmony_ci	u16 head_seq_num, buf_size;
124762306a36Sopenharmony_ci	int index;
124862306a36Sopenharmony_ci	bool ret = true;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	spin_lock(&tid_agg_rx->reorder_lock);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/*
125362306a36Sopenharmony_ci	 * Offloaded BA sessions have no known starting sequence number so pick
125462306a36Sopenharmony_ci	 * one from first Rxed frame for this tid after BA was started.
125562306a36Sopenharmony_ci	 */
125662306a36Sopenharmony_ci	if (unlikely(tid_agg_rx->auto_seq)) {
125762306a36Sopenharmony_ci		tid_agg_rx->auto_seq = false;
125862306a36Sopenharmony_ci		tid_agg_rx->ssn = mpdu_seq_num;
125962306a36Sopenharmony_ci		tid_agg_rx->head_seq_num = mpdu_seq_num;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	buf_size = tid_agg_rx->buf_size;
126362306a36Sopenharmony_ci	head_seq_num = tid_agg_rx->head_seq_num;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/*
126662306a36Sopenharmony_ci	 * If the current MPDU's SN is smaller than the SSN, it shouldn't
126762306a36Sopenharmony_ci	 * be reordered.
126862306a36Sopenharmony_ci	 */
126962306a36Sopenharmony_ci	if (unlikely(!tid_agg_rx->started)) {
127062306a36Sopenharmony_ci		if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
127162306a36Sopenharmony_ci			ret = false;
127262306a36Sopenharmony_ci			goto out;
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci		tid_agg_rx->started = true;
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	/* frame with out of date sequence number */
127862306a36Sopenharmony_ci	if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
127962306a36Sopenharmony_ci		dev_kfree_skb(skb);
128062306a36Sopenharmony_ci		goto out;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/*
128462306a36Sopenharmony_ci	 * If frame the sequence number exceeds our buffering window
128562306a36Sopenharmony_ci	 * size release some previous frames to make room for this one.
128662306a36Sopenharmony_ci	 */
128762306a36Sopenharmony_ci	if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
128862306a36Sopenharmony_ci		head_seq_num = ieee80211_sn_inc(
128962306a36Sopenharmony_ci				ieee80211_sn_sub(mpdu_seq_num, buf_size));
129062306a36Sopenharmony_ci		/* release stored frames up to new head to stack */
129162306a36Sopenharmony_ci		ieee80211_release_reorder_frames(sdata, tid_agg_rx,
129262306a36Sopenharmony_ci						 head_seq_num, frames);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* Now the new frame is always in the range of the reordering buffer */
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	index = mpdu_seq_num % tid_agg_rx->buf_size;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	/* check if we already stored this frame */
130062306a36Sopenharmony_ci	if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
130162306a36Sopenharmony_ci		dev_kfree_skb(skb);
130262306a36Sopenharmony_ci		goto out;
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/*
130662306a36Sopenharmony_ci	 * If the current MPDU is in the right order and nothing else
130762306a36Sopenharmony_ci	 * is stored we can process it directly, no need to buffer it.
130862306a36Sopenharmony_ci	 * If it is first but there's something stored, we may be able
130962306a36Sopenharmony_ci	 * to release frames after this one.
131062306a36Sopenharmony_ci	 */
131162306a36Sopenharmony_ci	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
131262306a36Sopenharmony_ci	    tid_agg_rx->stored_mpdu_num == 0) {
131362306a36Sopenharmony_ci		if (!(status->flag & RX_FLAG_AMSDU_MORE))
131462306a36Sopenharmony_ci			tid_agg_rx->head_seq_num =
131562306a36Sopenharmony_ci				ieee80211_sn_inc(tid_agg_rx->head_seq_num);
131662306a36Sopenharmony_ci		ret = false;
131762306a36Sopenharmony_ci		goto out;
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	/* put the frame in the reordering buffer */
132162306a36Sopenharmony_ci	__skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb);
132262306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
132362306a36Sopenharmony_ci		tid_agg_rx->reorder_time[index] = jiffies;
132462306a36Sopenharmony_ci		tid_agg_rx->stored_mpdu_num++;
132562306a36Sopenharmony_ci		ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames);
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci out:
132962306a36Sopenharmony_ci	spin_unlock(&tid_agg_rx->reorder_lock);
133062306a36Sopenharmony_ci	return ret;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci/*
133462306a36Sopenharmony_ci * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
133562306a36Sopenharmony_ci * true if the MPDU was buffered, false if it should be processed.
133662306a36Sopenharmony_ci */
133762306a36Sopenharmony_cistatic void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
133862306a36Sopenharmony_ci				       struct sk_buff_head *frames)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
134162306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
134262306a36Sopenharmony_ci	struct sta_info *sta = rx->sta;
134362306a36Sopenharmony_ci	struct tid_ampdu_rx *tid_agg_rx;
134462306a36Sopenharmony_ci	u16 sc;
134562306a36Sopenharmony_ci	u8 tid, ack_policy;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (!ieee80211_is_data_qos(hdr->frame_control) ||
134862306a36Sopenharmony_ci	    is_multicast_ether_addr(hdr->addr1))
134962306a36Sopenharmony_ci		goto dont_reorder;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/*
135262306a36Sopenharmony_ci	 * filter the QoS data rx stream according to
135362306a36Sopenharmony_ci	 * STA/TID and check if this STA/TID is on aggregation
135462306a36Sopenharmony_ci	 */
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	if (!sta)
135762306a36Sopenharmony_ci		goto dont_reorder;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	ack_policy = *ieee80211_get_qos_ctl(hdr) &
136062306a36Sopenharmony_ci		     IEEE80211_QOS_CTL_ACK_POLICY_MASK;
136162306a36Sopenharmony_ci	tid = ieee80211_get_tid(hdr);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
136462306a36Sopenharmony_ci	if (!tid_agg_rx) {
136562306a36Sopenharmony_ci		if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
136662306a36Sopenharmony_ci		    !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
136762306a36Sopenharmony_ci		    !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
136862306a36Sopenharmony_ci			ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
136962306a36Sopenharmony_ci					     WLAN_BACK_RECIPIENT,
137062306a36Sopenharmony_ci					     WLAN_REASON_QSTA_REQUIRE_SETUP);
137162306a36Sopenharmony_ci		goto dont_reorder;
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/* qos null data frames are excluded */
137562306a36Sopenharmony_ci	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
137662306a36Sopenharmony_ci		goto dont_reorder;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* not part of a BA session */
137962306a36Sopenharmony_ci	if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
138062306a36Sopenharmony_ci		goto dont_reorder;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* new, potentially un-ordered, ampdu frame - process it */
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/* reset session timer */
138562306a36Sopenharmony_ci	if (tid_agg_rx->timeout)
138662306a36Sopenharmony_ci		tid_agg_rx->last_rx = jiffies;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	/* if this mpdu is fragmented - terminate rx aggregation session */
138962306a36Sopenharmony_ci	sc = le16_to_cpu(hdr->seq_ctrl);
139062306a36Sopenharmony_ci	if (sc & IEEE80211_SCTL_FRAG) {
139162306a36Sopenharmony_ci		ieee80211_queue_skb_to_iface(rx->sdata, rx->link_id, NULL, skb);
139262306a36Sopenharmony_ci		return;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/*
139662306a36Sopenharmony_ci	 * No locking needed -- we will only ever process one
139762306a36Sopenharmony_ci	 * RX packet at a time, and thus own tid_agg_rx. All
139862306a36Sopenharmony_ci	 * other code manipulating it needs to (and does) make
139962306a36Sopenharmony_ci	 * sure that we cannot get to it any more before doing
140062306a36Sopenharmony_ci	 * anything with it.
140162306a36Sopenharmony_ci	 */
140262306a36Sopenharmony_ci	if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb,
140362306a36Sopenharmony_ci					     frames))
140462306a36Sopenharmony_ci		return;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci dont_reorder:
140762306a36Sopenharmony_ci	__skb_queue_tail(frames, skb);
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
141162306a36Sopenharmony_ciieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
141462306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (status->flag & RX_FLAG_DUP_VALIDATED)
141762306a36Sopenharmony_ci		return RX_CONTINUE;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	/*
142062306a36Sopenharmony_ci	 * Drop duplicate 802.11 retransmissions
142162306a36Sopenharmony_ci	 * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
142262306a36Sopenharmony_ci	 */
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (rx->skb->len < 24)
142562306a36Sopenharmony_ci		return RX_CONTINUE;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (ieee80211_is_ctl(hdr->frame_control) ||
142862306a36Sopenharmony_ci	    ieee80211_is_any_nullfunc(hdr->frame_control) ||
142962306a36Sopenharmony_ci	    is_multicast_ether_addr(hdr->addr1))
143062306a36Sopenharmony_ci		return RX_CONTINUE;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if (!rx->sta)
143362306a36Sopenharmony_ci		return RX_CONTINUE;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
143662306a36Sopenharmony_ci		     rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
143762306a36Sopenharmony_ci		I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
143862306a36Sopenharmony_ci		rx->link_sta->rx_stats.num_duplicates++;
143962306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
144062306a36Sopenharmony_ci	} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
144162306a36Sopenharmony_ci		rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	return RX_CONTINUE;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
144862306a36Sopenharmony_ciieee80211_rx_h_check(struct ieee80211_rx_data *rx)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* Drop disallowed frame classes based on STA auth/assoc state;
145362306a36Sopenharmony_ci	 * IEEE 802.11, Chap 5.5.
145462306a36Sopenharmony_ci	 *
145562306a36Sopenharmony_ci	 * mac80211 filters only based on association state, i.e. it drops
145662306a36Sopenharmony_ci	 * Class 3 frames from not associated stations. hostapd sends
145762306a36Sopenharmony_ci	 * deauth/disassoc frames when needed. In addition, hostapd is
145862306a36Sopenharmony_ci	 * responsible for filtering on both auth and assoc states.
145962306a36Sopenharmony_ci	 */
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
146262306a36Sopenharmony_ci		return ieee80211_rx_mesh_check(rx);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	if (unlikely((ieee80211_is_data(hdr->frame_control) ||
146562306a36Sopenharmony_ci		      ieee80211_is_pspoll(hdr->frame_control)) &&
146662306a36Sopenharmony_ci		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
146762306a36Sopenharmony_ci		     rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
146862306a36Sopenharmony_ci		     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
146962306a36Sopenharmony_ci		/*
147062306a36Sopenharmony_ci		 * accept port control frames from the AP even when it's not
147162306a36Sopenharmony_ci		 * yet marked ASSOC to prevent a race where we don't set the
147262306a36Sopenharmony_ci		 * assoc bit quickly enough before it sends the first frame
147362306a36Sopenharmony_ci		 */
147462306a36Sopenharmony_ci		if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
147562306a36Sopenharmony_ci		    ieee80211_is_data_present(hdr->frame_control)) {
147662306a36Sopenharmony_ci			unsigned int hdrlen;
147762306a36Sopenharmony_ci			__be16 ethertype;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci			hdrlen = ieee80211_hdrlen(hdr->frame_control);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci			if (rx->skb->len < hdrlen + 8)
148262306a36Sopenharmony_ci				return RX_DROP_MONITOR;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci			skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
148562306a36Sopenharmony_ci			if (ethertype == rx->sdata->control_port_protocol)
148662306a36Sopenharmony_ci				return RX_CONTINUE;
148762306a36Sopenharmony_ci		}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
149062306a36Sopenharmony_ci		    cfg80211_rx_spurious_frame(rx->sdata->dev,
149162306a36Sopenharmony_ci					       hdr->addr2,
149262306a36Sopenharmony_ci					       GFP_ATOMIC))
149362306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		return RX_DROP_MONITOR;
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	return RX_CONTINUE;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
150362306a36Sopenharmony_ciieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct ieee80211_local *local;
150662306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
150762306a36Sopenharmony_ci	struct sk_buff *skb;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	local = rx->local;
151062306a36Sopenharmony_ci	skb = rx->skb;
151162306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *) skb->data;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!local->pspolling)
151462306a36Sopenharmony_ci		return RX_CONTINUE;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	if (!ieee80211_has_fromds(hdr->frame_control))
151762306a36Sopenharmony_ci		/* this is not from AP */
151862306a36Sopenharmony_ci		return RX_CONTINUE;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	if (!ieee80211_is_data(hdr->frame_control))
152162306a36Sopenharmony_ci		return RX_CONTINUE;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (!ieee80211_has_moredata(hdr->frame_control)) {
152462306a36Sopenharmony_ci		/* AP has no more frames buffered for us */
152562306a36Sopenharmony_ci		local->pspolling = false;
152662306a36Sopenharmony_ci		return RX_CONTINUE;
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/* more data bit is set, let's request a new frame from the AP */
153062306a36Sopenharmony_ci	ieee80211_send_pspoll(local, rx->sdata);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	return RX_CONTINUE;
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_cistatic void sta_ps_start(struct sta_info *sta)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
153862306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
153962306a36Sopenharmony_ci	struct ps_data *ps;
154062306a36Sopenharmony_ci	int tid;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
154362306a36Sopenharmony_ci	    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
154462306a36Sopenharmony_ci		ps = &sdata->bss->ps;
154562306a36Sopenharmony_ci	else
154662306a36Sopenharmony_ci		return;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	atomic_inc(&ps->num_sta_ps);
154962306a36Sopenharmony_ci	set_sta_flag(sta, WLAN_STA_PS_STA);
155062306a36Sopenharmony_ci	if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
155162306a36Sopenharmony_ci		drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
155262306a36Sopenharmony_ci	ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
155362306a36Sopenharmony_ci	       sta->sta.addr, sta->sta.aid);
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	ieee80211_clear_fast_xmit(sta);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
155862306a36Sopenharmony_ci		struct ieee80211_txq *txq = sta->sta.txq[tid];
155962306a36Sopenharmony_ci		struct txq_info *txqi = to_txq_info(txq);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		spin_lock(&local->active_txq_lock[txq->ac]);
156262306a36Sopenharmony_ci		if (!list_empty(&txqi->schedule_order))
156362306a36Sopenharmony_ci			list_del_init(&txqi->schedule_order);
156462306a36Sopenharmony_ci		spin_unlock(&local->active_txq_lock[txq->ac]);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci		if (txq_has_queue(txq))
156762306a36Sopenharmony_ci			set_bit(tid, &sta->txq_buffered_tids);
156862306a36Sopenharmony_ci		else
156962306a36Sopenharmony_ci			clear_bit(tid, &sta->txq_buffered_tids);
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_cistatic void sta_ps_end(struct sta_info *sta)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
157662306a36Sopenharmony_ci	       sta->sta.addr, sta->sta.aid);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
157962306a36Sopenharmony_ci		/*
158062306a36Sopenharmony_ci		 * Clear the flag only if the other one is still set
158162306a36Sopenharmony_ci		 * so that the TX path won't start TX'ing new frames
158262306a36Sopenharmony_ci		 * directly ... In the case that the driver flag isn't
158362306a36Sopenharmony_ci		 * set ieee80211_sta_ps_deliver_wakeup() will clear it.
158462306a36Sopenharmony_ci		 */
158562306a36Sopenharmony_ci		clear_sta_flag(sta, WLAN_STA_PS_STA);
158662306a36Sopenharmony_ci		ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
158762306a36Sopenharmony_ci		       sta->sta.addr, sta->sta.aid);
158862306a36Sopenharmony_ci		return;
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	set_sta_flag(sta, WLAN_STA_PS_DELIVER);
159262306a36Sopenharmony_ci	clear_sta_flag(sta, WLAN_STA_PS_STA);
159362306a36Sopenharmony_ci	ieee80211_sta_ps_deliver_wakeup(sta);
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ciint ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
159962306a36Sopenharmony_ci	bool in_ps;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS));
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/* Don't let the same PS state be set twice */
160462306a36Sopenharmony_ci	in_ps = test_sta_flag(sta, WLAN_STA_PS_STA);
160562306a36Sopenharmony_ci	if ((start && in_ps) || (!start && !in_ps))
160662306a36Sopenharmony_ci		return -EINVAL;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	if (start)
160962306a36Sopenharmony_ci		sta_ps_start(sta);
161062306a36Sopenharmony_ci	else
161162306a36Sopenharmony_ci		sta_ps_end(sta);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	return 0;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_ps_transition);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_civoid ieee80211_sta_pspoll(struct ieee80211_sta *pubsta)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (test_sta_flag(sta, WLAN_STA_SP))
162262306a36Sopenharmony_ci		return;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
162562306a36Sopenharmony_ci		ieee80211_sta_ps_deliver_poll_response(sta);
162662306a36Sopenharmony_ci	else
162762306a36Sopenharmony_ci		set_sta_flag(sta, WLAN_STA_PSPOLL);
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_pspoll);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_civoid ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
163462306a36Sopenharmony_ci	int ac = ieee80211_ac_from_tid(tid);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	/*
163762306a36Sopenharmony_ci	 * If this AC is not trigger-enabled do nothing unless the
163862306a36Sopenharmony_ci	 * driver is calling us after it already checked.
163962306a36Sopenharmony_ci	 *
164062306a36Sopenharmony_ci	 * NB: This could/should check a separate bitmap of trigger-
164162306a36Sopenharmony_ci	 * enabled queues, but for now we only implement uAPSD w/o
164262306a36Sopenharmony_ci	 * TSPEC changes to the ACs, so they're always the same.
164362306a36Sopenharmony_ci	 */
164462306a36Sopenharmony_ci	if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
164562306a36Sopenharmony_ci	    tid != IEEE80211_NUM_TIDS)
164662306a36Sopenharmony_ci		return;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/* if we are in a service period, do nothing */
164962306a36Sopenharmony_ci	if (test_sta_flag(sta, WLAN_STA_SP))
165062306a36Sopenharmony_ci		return;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
165362306a36Sopenharmony_ci		ieee80211_sta_ps_deliver_uapsd(sta);
165462306a36Sopenharmony_ci	else
165562306a36Sopenharmony_ci		set_sta_flag(sta, WLAN_STA_UAPSD);
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
166062306a36Sopenharmony_ciieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
166362306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)rx->skb->data;
166462306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if (!rx->sta)
166762306a36Sopenharmony_ci		return RX_CONTINUE;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_AP &&
167062306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
167162306a36Sopenharmony_ci		return RX_CONTINUE;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/*
167462306a36Sopenharmony_ci	 * The device handles station powersave, so don't do anything about
167562306a36Sopenharmony_ci	 * uAPSD and PS-Poll frames (the latter shouldn't even come up from
167662306a36Sopenharmony_ci	 * it to mac80211 since they're handled.)
167762306a36Sopenharmony_ci	 */
167862306a36Sopenharmony_ci	if (ieee80211_hw_check(&sdata->local->hw, AP_LINK_PS))
167962306a36Sopenharmony_ci		return RX_CONTINUE;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/*
168262306a36Sopenharmony_ci	 * Don't do anything if the station isn't already asleep. In
168362306a36Sopenharmony_ci	 * the uAPSD case, the station will probably be marked asleep,
168462306a36Sopenharmony_ci	 * in the PS-Poll case the station must be confused ...
168562306a36Sopenharmony_ci	 */
168662306a36Sopenharmony_ci	if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
168762306a36Sopenharmony_ci		return RX_CONTINUE;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
169062306a36Sopenharmony_ci		ieee80211_sta_pspoll(&rx->sta->sta);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci		/* Free PS Poll skb here instead of returning RX_DROP that would
169362306a36Sopenharmony_ci		 * count as an dropped frame. */
169462306a36Sopenharmony_ci		dev_kfree_skb(rx->skb);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci		return RX_QUEUED;
169762306a36Sopenharmony_ci	} else if (!ieee80211_has_morefrags(hdr->frame_control) &&
169862306a36Sopenharmony_ci		   !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
169962306a36Sopenharmony_ci		   ieee80211_has_pm(hdr->frame_control) &&
170062306a36Sopenharmony_ci		   (ieee80211_is_data_qos(hdr->frame_control) ||
170162306a36Sopenharmony_ci		    ieee80211_is_qos_nullfunc(hdr->frame_control))) {
170262306a36Sopenharmony_ci		u8 tid = ieee80211_get_tid(hdr);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci		ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	return RX_CONTINUE;
170862306a36Sopenharmony_ci}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
171162306a36Sopenharmony_ciieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct sta_info *sta = rx->sta;
171462306a36Sopenharmony_ci	struct link_sta_info *link_sta = rx->link_sta;
171562306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
171662306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
171762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
171862306a36Sopenharmony_ci	int i;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (!sta || !link_sta)
172162306a36Sopenharmony_ci		return RX_CONTINUE;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	/*
172462306a36Sopenharmony_ci	 * Update last_rx only for IBSS packets which are for the current
172562306a36Sopenharmony_ci	 * BSSID and for station already AUTHORIZED to avoid keeping the
172662306a36Sopenharmony_ci	 * current IBSS network alive in cases where other STAs start
172762306a36Sopenharmony_ci	 * using different BSSID. This will also give the station another
172862306a36Sopenharmony_ci	 * chance to restart the authentication/authorization in case
172962306a36Sopenharmony_ci	 * something went wrong the first time.
173062306a36Sopenharmony_ci	 */
173162306a36Sopenharmony_ci	if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
173262306a36Sopenharmony_ci		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
173362306a36Sopenharmony_ci						NL80211_IFTYPE_ADHOC);
173462306a36Sopenharmony_ci		if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
173562306a36Sopenharmony_ci		    test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
173662306a36Sopenharmony_ci			link_sta->rx_stats.last_rx = jiffies;
173762306a36Sopenharmony_ci			if (ieee80211_is_data_present(hdr->frame_control) &&
173862306a36Sopenharmony_ci			    !is_multicast_ether_addr(hdr->addr1))
173962306a36Sopenharmony_ci				link_sta->rx_stats.last_rate =
174062306a36Sopenharmony_ci					sta_stats_encode_rate(status);
174162306a36Sopenharmony_ci		}
174262306a36Sopenharmony_ci	} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
174362306a36Sopenharmony_ci		link_sta->rx_stats.last_rx = jiffies;
174462306a36Sopenharmony_ci	} else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
174562306a36Sopenharmony_ci		   !is_multicast_ether_addr(hdr->addr1)) {
174662306a36Sopenharmony_ci		/*
174762306a36Sopenharmony_ci		 * Mesh beacons will update last_rx when if they are found to
174862306a36Sopenharmony_ci		 * match the current local configuration when processed.
174962306a36Sopenharmony_ci		 */
175062306a36Sopenharmony_ci		link_sta->rx_stats.last_rx = jiffies;
175162306a36Sopenharmony_ci		if (ieee80211_is_data_present(hdr->frame_control))
175262306a36Sopenharmony_ci			link_sta->rx_stats.last_rate = sta_stats_encode_rate(status);
175362306a36Sopenharmony_ci	}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	link_sta->rx_stats.fragments++;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	u64_stats_update_begin(&link_sta->rx_stats.syncp);
175862306a36Sopenharmony_ci	link_sta->rx_stats.bytes += rx->skb->len;
175962306a36Sopenharmony_ci	u64_stats_update_end(&link_sta->rx_stats.syncp);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
176262306a36Sopenharmony_ci		link_sta->rx_stats.last_signal = status->signal;
176362306a36Sopenharmony_ci		ewma_signal_add(&link_sta->rx_stats_avg.signal,
176462306a36Sopenharmony_ci				-status->signal);
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (status->chains) {
176862306a36Sopenharmony_ci		link_sta->rx_stats.chains = status->chains;
176962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
177062306a36Sopenharmony_ci			int signal = status->chain_signal[i];
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci			if (!(status->chains & BIT(i)))
177362306a36Sopenharmony_ci				continue;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci			link_sta->rx_stats.chain_signal_last[i] = signal;
177662306a36Sopenharmony_ci			ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
177762306a36Sopenharmony_ci					-signal);
177862306a36Sopenharmony_ci		}
177962306a36Sopenharmony_ci	}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	if (ieee80211_is_s1g_beacon(hdr->frame_control))
178262306a36Sopenharmony_ci		return RX_CONTINUE;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	/*
178562306a36Sopenharmony_ci	 * Change STA power saving mode only at the end of a frame
178662306a36Sopenharmony_ci	 * exchange sequence, and only for a data or management
178762306a36Sopenharmony_ci	 * frame as specified in IEEE 802.11-2016 11.2.3.2
178862306a36Sopenharmony_ci	 */
178962306a36Sopenharmony_ci	if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) &&
179062306a36Sopenharmony_ci	    !ieee80211_has_morefrags(hdr->frame_control) &&
179162306a36Sopenharmony_ci	    !is_multicast_ether_addr(hdr->addr1) &&
179262306a36Sopenharmony_ci	    (ieee80211_is_mgmt(hdr->frame_control) ||
179362306a36Sopenharmony_ci	     ieee80211_is_data(hdr->frame_control)) &&
179462306a36Sopenharmony_ci	    !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
179562306a36Sopenharmony_ci	    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
179662306a36Sopenharmony_ci	     rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
179762306a36Sopenharmony_ci		if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
179862306a36Sopenharmony_ci			if (!ieee80211_has_pm(hdr->frame_control))
179962306a36Sopenharmony_ci				sta_ps_end(sta);
180062306a36Sopenharmony_ci		} else {
180162306a36Sopenharmony_ci			if (ieee80211_has_pm(hdr->frame_control))
180262306a36Sopenharmony_ci				sta_ps_start(sta);
180362306a36Sopenharmony_ci		}
180462306a36Sopenharmony_ci	}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* mesh power save support */
180762306a36Sopenharmony_ci	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
180862306a36Sopenharmony_ci		ieee80211_mps_rx_h_sta_process(sta, hdr);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	/*
181162306a36Sopenharmony_ci	 * Drop (qos-)data::nullfunc frames silently, since they
181262306a36Sopenharmony_ci	 * are used only to control station power saving mode.
181362306a36Sopenharmony_ci	 */
181462306a36Sopenharmony_ci	if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
181562306a36Sopenharmony_ci		I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci		/*
181862306a36Sopenharmony_ci		 * If we receive a 4-addr nullfunc frame from a STA
181962306a36Sopenharmony_ci		 * that was not moved to a 4-addr STA vlan yet send
182062306a36Sopenharmony_ci		 * the event to userspace and for older hostapd drop
182162306a36Sopenharmony_ci		 * the frame to the monitor interface.
182262306a36Sopenharmony_ci		 */
182362306a36Sopenharmony_ci		if (ieee80211_has_a4(hdr->frame_control) &&
182462306a36Sopenharmony_ci		    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
182562306a36Sopenharmony_ci		     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
182662306a36Sopenharmony_ci		      !rx->sdata->u.vlan.sta))) {
182762306a36Sopenharmony_ci			if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
182862306a36Sopenharmony_ci				cfg80211_rx_unexpected_4addr_frame(
182962306a36Sopenharmony_ci					rx->sdata->dev, sta->sta.addr,
183062306a36Sopenharmony_ci					GFP_ATOMIC);
183162306a36Sopenharmony_ci			return RX_DROP_M_UNEXPECTED_4ADDR_FRAME;
183262306a36Sopenharmony_ci		}
183362306a36Sopenharmony_ci		/*
183462306a36Sopenharmony_ci		 * Update counter and free packet here to avoid
183562306a36Sopenharmony_ci		 * counting this as a dropped packed.
183662306a36Sopenharmony_ci		 */
183762306a36Sopenharmony_ci		link_sta->rx_stats.packets++;
183862306a36Sopenharmony_ci		dev_kfree_skb(rx->skb);
183962306a36Sopenharmony_ci		return RX_QUEUED;
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	return RX_CONTINUE;
184362306a36Sopenharmony_ci} /* ieee80211_rx_h_sta_process */
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic struct ieee80211_key *
184662306a36Sopenharmony_ciieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	struct ieee80211_key *key = NULL;
184962306a36Sopenharmony_ci	int idx2;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* Make sure key gets set if either BIGTK key index is set so that
185262306a36Sopenharmony_ci	 * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected
185362306a36Sopenharmony_ci	 * Beacon frames and Beacon frames that claim to use another BIGTK key
185462306a36Sopenharmony_ci	 * index (i.e., a key that we do not have).
185562306a36Sopenharmony_ci	 */
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	if (idx < 0) {
185862306a36Sopenharmony_ci		idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
185962306a36Sopenharmony_ci		idx2 = idx + 1;
186062306a36Sopenharmony_ci	} else {
186162306a36Sopenharmony_ci		if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
186262306a36Sopenharmony_ci			idx2 = idx + 1;
186362306a36Sopenharmony_ci		else
186462306a36Sopenharmony_ci			idx2 = idx - 1;
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (rx->link_sta)
186862306a36Sopenharmony_ci		key = rcu_dereference(rx->link_sta->gtk[idx]);
186962306a36Sopenharmony_ci	if (!key)
187062306a36Sopenharmony_ci		key = rcu_dereference(rx->link->gtk[idx]);
187162306a36Sopenharmony_ci	if (!key && rx->link_sta)
187262306a36Sopenharmony_ci		key = rcu_dereference(rx->link_sta->gtk[idx2]);
187362306a36Sopenharmony_ci	if (!key)
187462306a36Sopenharmony_ci		key = rcu_dereference(rx->link->gtk[idx2]);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	return key;
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
188062306a36Sopenharmony_ciieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
188362306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
188462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
188562306a36Sopenharmony_ci	int keyidx;
188662306a36Sopenharmony_ci	ieee80211_rx_result result = RX_DROP_UNUSABLE;
188762306a36Sopenharmony_ci	struct ieee80211_key *sta_ptk = NULL;
188862306a36Sopenharmony_ci	struct ieee80211_key *ptk_idx = NULL;
188962306a36Sopenharmony_ci	int mmie_keyidx = -1;
189062306a36Sopenharmony_ci	__le16 fc;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	if (ieee80211_is_ext(hdr->frame_control))
189362306a36Sopenharmony_ci		return RX_CONTINUE;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	/*
189662306a36Sopenharmony_ci	 * Key selection 101
189762306a36Sopenharmony_ci	 *
189862306a36Sopenharmony_ci	 * There are five types of keys:
189962306a36Sopenharmony_ci	 *  - GTK (group keys)
190062306a36Sopenharmony_ci	 *  - IGTK (group keys for management frames)
190162306a36Sopenharmony_ci	 *  - BIGTK (group keys for Beacon frames)
190262306a36Sopenharmony_ci	 *  - PTK (pairwise keys)
190362306a36Sopenharmony_ci	 *  - STK (station-to-station pairwise keys)
190462306a36Sopenharmony_ci	 *
190562306a36Sopenharmony_ci	 * When selecting a key, we have to distinguish between multicast
190662306a36Sopenharmony_ci	 * (including broadcast) and unicast frames, the latter can only
190762306a36Sopenharmony_ci	 * use PTKs and STKs while the former always use GTKs, IGTKs, and
190862306a36Sopenharmony_ci	 * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used,
190962306a36Sopenharmony_ci	 * then unicast frames can also use key indices like GTKs. Hence, if we
191062306a36Sopenharmony_ci	 * don't have a PTK/STK we check the key index for a WEP key.
191162306a36Sopenharmony_ci	 *
191262306a36Sopenharmony_ci	 * Note that in a regular BSS, multicast frames are sent by the
191362306a36Sopenharmony_ci	 * AP only, associated stations unicast the frame to the AP first
191462306a36Sopenharmony_ci	 * which then multicasts it on their behalf.
191562306a36Sopenharmony_ci	 *
191662306a36Sopenharmony_ci	 * There is also a slight problem in IBSS mode: GTKs are negotiated
191762306a36Sopenharmony_ci	 * with each station, that is something we don't currently handle.
191862306a36Sopenharmony_ci	 * The spec seems to expect that one negotiates the same key with
191962306a36Sopenharmony_ci	 * every station but there's no such requirement; VLANs could be
192062306a36Sopenharmony_ci	 * possible.
192162306a36Sopenharmony_ci	 */
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	/* start without a key */
192462306a36Sopenharmony_ci	rx->key = NULL;
192562306a36Sopenharmony_ci	fc = hdr->frame_control;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (rx->sta) {
192862306a36Sopenharmony_ci		int keyid = rx->sta->ptk_idx;
192962306a36Sopenharmony_ci		sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci		if (ieee80211_has_protected(fc) &&
193262306a36Sopenharmony_ci		    !(status->flag & RX_FLAG_IV_STRIPPED)) {
193362306a36Sopenharmony_ci			keyid = ieee80211_get_keyid(rx->skb);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci			if (unlikely(keyid < 0))
193662306a36Sopenharmony_ci				return RX_DROP_UNUSABLE;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci			ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
193962306a36Sopenharmony_ci		}
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if (!ieee80211_has_protected(fc))
194362306a36Sopenharmony_ci		mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
194662306a36Sopenharmony_ci		rx->key = ptk_idx ? ptk_idx : sta_ptk;
194762306a36Sopenharmony_ci		if ((status->flag & RX_FLAG_DECRYPTED) &&
194862306a36Sopenharmony_ci		    (status->flag & RX_FLAG_IV_STRIPPED))
194962306a36Sopenharmony_ci			return RX_CONTINUE;
195062306a36Sopenharmony_ci		/* Skip decryption if the frame is not protected. */
195162306a36Sopenharmony_ci		if (!ieee80211_has_protected(fc))
195262306a36Sopenharmony_ci			return RX_CONTINUE;
195362306a36Sopenharmony_ci	} else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) {
195462306a36Sopenharmony_ci		/* Broadcast/multicast robust management frame / BIP */
195562306a36Sopenharmony_ci		if ((status->flag & RX_FLAG_DECRYPTED) &&
195662306a36Sopenharmony_ci		    (status->flag & RX_FLAG_IV_STRIPPED))
195762306a36Sopenharmony_ci			return RX_CONTINUE;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci		if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
196062306a36Sopenharmony_ci		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
196162306a36Sopenharmony_ci				   NUM_DEFAULT_BEACON_KEYS) {
196262306a36Sopenharmony_ci			if (rx->sdata->dev)
196362306a36Sopenharmony_ci				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
196462306a36Sopenharmony_ci							     skb->data,
196562306a36Sopenharmony_ci							     skb->len);
196662306a36Sopenharmony_ci			return RX_DROP_M_BAD_BCN_KEYIDX;
196762306a36Sopenharmony_ci		}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci		rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
197062306a36Sopenharmony_ci		if (!rx->key)
197162306a36Sopenharmony_ci			return RX_CONTINUE; /* Beacon protection not in use */
197262306a36Sopenharmony_ci	} else if (mmie_keyidx >= 0) {
197362306a36Sopenharmony_ci		/* Broadcast/multicast robust management frame / BIP */
197462306a36Sopenharmony_ci		if ((status->flag & RX_FLAG_DECRYPTED) &&
197562306a36Sopenharmony_ci		    (status->flag & RX_FLAG_IV_STRIPPED))
197662306a36Sopenharmony_ci			return RX_CONTINUE;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci		if (mmie_keyidx < NUM_DEFAULT_KEYS ||
197962306a36Sopenharmony_ci		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
198062306a36Sopenharmony_ci			return RX_DROP_M_BAD_MGMT_KEYIDX; /* unexpected BIP keyidx */
198162306a36Sopenharmony_ci		if (rx->link_sta) {
198262306a36Sopenharmony_ci			if (ieee80211_is_group_privacy_action(skb) &&
198362306a36Sopenharmony_ci			    test_sta_flag(rx->sta, WLAN_STA_MFP))
198462306a36Sopenharmony_ci				return RX_DROP_MONITOR;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci			rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]);
198762306a36Sopenharmony_ci		}
198862306a36Sopenharmony_ci		if (!rx->key)
198962306a36Sopenharmony_ci			rx->key = rcu_dereference(rx->link->gtk[mmie_keyidx]);
199062306a36Sopenharmony_ci	} else if (!ieee80211_has_protected(fc)) {
199162306a36Sopenharmony_ci		/*
199262306a36Sopenharmony_ci		 * The frame was not protected, so skip decryption. However, we
199362306a36Sopenharmony_ci		 * need to set rx->key if there is a key that could have been
199462306a36Sopenharmony_ci		 * used so that the frame may be dropped if encryption would
199562306a36Sopenharmony_ci		 * have been expected.
199662306a36Sopenharmony_ci		 */
199762306a36Sopenharmony_ci		struct ieee80211_key *key = NULL;
199862306a36Sopenharmony_ci		int i;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci		if (ieee80211_is_beacon(fc)) {
200162306a36Sopenharmony_ci			key = ieee80211_rx_get_bigtk(rx, -1);
200262306a36Sopenharmony_ci		} else if (ieee80211_is_mgmt(fc) &&
200362306a36Sopenharmony_ci			   is_multicast_ether_addr(hdr->addr1)) {
200462306a36Sopenharmony_ci			key = rcu_dereference(rx->link->default_mgmt_key);
200562306a36Sopenharmony_ci		} else {
200662306a36Sopenharmony_ci			if (rx->link_sta) {
200762306a36Sopenharmony_ci				for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
200862306a36Sopenharmony_ci					key = rcu_dereference(rx->link_sta->gtk[i]);
200962306a36Sopenharmony_ci					if (key)
201062306a36Sopenharmony_ci						break;
201162306a36Sopenharmony_ci				}
201262306a36Sopenharmony_ci			}
201362306a36Sopenharmony_ci			if (!key) {
201462306a36Sopenharmony_ci				for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
201562306a36Sopenharmony_ci					key = rcu_dereference(rx->link->gtk[i]);
201662306a36Sopenharmony_ci					if (key)
201762306a36Sopenharmony_ci						break;
201862306a36Sopenharmony_ci				}
201962306a36Sopenharmony_ci			}
202062306a36Sopenharmony_ci		}
202162306a36Sopenharmony_ci		if (key)
202262306a36Sopenharmony_ci			rx->key = key;
202362306a36Sopenharmony_ci		return RX_CONTINUE;
202462306a36Sopenharmony_ci	} else {
202562306a36Sopenharmony_ci		/*
202662306a36Sopenharmony_ci		 * The device doesn't give us the IV so we won't be
202762306a36Sopenharmony_ci		 * able to look up the key. That's ok though, we
202862306a36Sopenharmony_ci		 * don't need to decrypt the frame, we just won't
202962306a36Sopenharmony_ci		 * be able to keep statistics accurate.
203062306a36Sopenharmony_ci		 * Except for key threshold notifications, should
203162306a36Sopenharmony_ci		 * we somehow allow the driver to tell us which key
203262306a36Sopenharmony_ci		 * the hardware used if this flag is set?
203362306a36Sopenharmony_ci		 */
203462306a36Sopenharmony_ci		if ((status->flag & RX_FLAG_DECRYPTED) &&
203562306a36Sopenharmony_ci		    (status->flag & RX_FLAG_IV_STRIPPED))
203662306a36Sopenharmony_ci			return RX_CONTINUE;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci		keyidx = ieee80211_get_keyid(rx->skb);
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci		if (unlikely(keyidx < 0))
204162306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci		/* check per-station GTK first, if multicast packet */
204462306a36Sopenharmony_ci		if (is_multicast_ether_addr(hdr->addr1) && rx->link_sta)
204562306a36Sopenharmony_ci			rx->key = rcu_dereference(rx->link_sta->gtk[keyidx]);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci		/* if not found, try default key */
204862306a36Sopenharmony_ci		if (!rx->key) {
204962306a36Sopenharmony_ci			if (is_multicast_ether_addr(hdr->addr1))
205062306a36Sopenharmony_ci				rx->key = rcu_dereference(rx->link->gtk[keyidx]);
205162306a36Sopenharmony_ci			if (!rx->key)
205262306a36Sopenharmony_ci				rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci			/*
205562306a36Sopenharmony_ci			 * RSNA-protected unicast frames should always be
205662306a36Sopenharmony_ci			 * sent with pairwise or station-to-station keys,
205762306a36Sopenharmony_ci			 * but for WEP we allow using a key index as well.
205862306a36Sopenharmony_ci			 */
205962306a36Sopenharmony_ci			if (rx->key &&
206062306a36Sopenharmony_ci			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
206162306a36Sopenharmony_ci			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
206262306a36Sopenharmony_ci			    !is_multicast_ether_addr(hdr->addr1))
206362306a36Sopenharmony_ci				rx->key = NULL;
206462306a36Sopenharmony_ci		}
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	if (rx->key) {
206862306a36Sopenharmony_ci		if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
206962306a36Sopenharmony_ci			return RX_DROP_MONITOR;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci		/* TODO: add threshold stuff again */
207262306a36Sopenharmony_ci	} else {
207362306a36Sopenharmony_ci		return RX_DROP_MONITOR;
207462306a36Sopenharmony_ci	}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	switch (rx->key->conf.cipher) {
207762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
207862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
207962306a36Sopenharmony_ci		result = ieee80211_crypto_wep_decrypt(rx);
208062306a36Sopenharmony_ci		break;
208162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
208262306a36Sopenharmony_ci		result = ieee80211_crypto_tkip_decrypt(rx);
208362306a36Sopenharmony_ci		break;
208462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
208562306a36Sopenharmony_ci		result = ieee80211_crypto_ccmp_decrypt(
208662306a36Sopenharmony_ci			rx, IEEE80211_CCMP_MIC_LEN);
208762306a36Sopenharmony_ci		break;
208862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
208962306a36Sopenharmony_ci		result = ieee80211_crypto_ccmp_decrypt(
209062306a36Sopenharmony_ci			rx, IEEE80211_CCMP_256_MIC_LEN);
209162306a36Sopenharmony_ci		break;
209262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
209362306a36Sopenharmony_ci		result = ieee80211_crypto_aes_cmac_decrypt(rx);
209462306a36Sopenharmony_ci		break;
209562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
209662306a36Sopenharmony_ci		result = ieee80211_crypto_aes_cmac_256_decrypt(rx);
209762306a36Sopenharmony_ci		break;
209862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
209962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
210062306a36Sopenharmony_ci		result = ieee80211_crypto_aes_gmac_decrypt(rx);
210162306a36Sopenharmony_ci		break;
210262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
210362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
210462306a36Sopenharmony_ci		result = ieee80211_crypto_gcmp_decrypt(rx);
210562306a36Sopenharmony_ci		break;
210662306a36Sopenharmony_ci	default:
210762306a36Sopenharmony_ci		result = RX_DROP_UNUSABLE;
210862306a36Sopenharmony_ci	}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	/* the hdr variable is invalid after the decrypt handlers */
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/* either the frame has been decrypted or will be dropped */
211362306a36Sopenharmony_ci	status->flag |= RX_FLAG_DECRYPTED;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	if (unlikely(ieee80211_is_beacon(fc) && RX_RES_IS_UNUSABLE(result) &&
211662306a36Sopenharmony_ci		     rx->sdata->dev))
211762306a36Sopenharmony_ci		cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
211862306a36Sopenharmony_ci					     skb->data, skb->len);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	return result;
212162306a36Sopenharmony_ci}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_civoid ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache)
212462306a36Sopenharmony_ci{
212562306a36Sopenharmony_ci	int i;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
212862306a36Sopenharmony_ci		skb_queue_head_init(&cache->entries[i].skb_list);
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_civoid ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache)
213262306a36Sopenharmony_ci{
213362306a36Sopenharmony_ci	int i;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
213662306a36Sopenharmony_ci		__skb_queue_purge(&cache->entries[i].skb_list);
213762306a36Sopenharmony_ci}
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_cistatic inline struct ieee80211_fragment_entry *
214062306a36Sopenharmony_ciieee80211_reassemble_add(struct ieee80211_fragment_cache *cache,
214162306a36Sopenharmony_ci			 unsigned int frag, unsigned int seq, int rx_queue,
214262306a36Sopenharmony_ci			 struct sk_buff **skb)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	struct ieee80211_fragment_entry *entry;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	entry = &cache->entries[cache->next++];
214762306a36Sopenharmony_ci	if (cache->next >= IEEE80211_FRAGMENT_MAX)
214862306a36Sopenharmony_ci		cache->next = 0;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	__skb_queue_purge(&entry->skb_list);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
215362306a36Sopenharmony_ci	*skb = NULL;
215462306a36Sopenharmony_ci	entry->first_frag_time = jiffies;
215562306a36Sopenharmony_ci	entry->seq = seq;
215662306a36Sopenharmony_ci	entry->rx_queue = rx_queue;
215762306a36Sopenharmony_ci	entry->last_frag = frag;
215862306a36Sopenharmony_ci	entry->check_sequential_pn = false;
215962306a36Sopenharmony_ci	entry->extra_len = 0;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	return entry;
216262306a36Sopenharmony_ci}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_cistatic inline struct ieee80211_fragment_entry *
216562306a36Sopenharmony_ciieee80211_reassemble_find(struct ieee80211_fragment_cache *cache,
216662306a36Sopenharmony_ci			  unsigned int frag, unsigned int seq,
216762306a36Sopenharmony_ci			  int rx_queue, struct ieee80211_hdr *hdr)
216862306a36Sopenharmony_ci{
216962306a36Sopenharmony_ci	struct ieee80211_fragment_entry *entry;
217062306a36Sopenharmony_ci	int i, idx;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	idx = cache->next;
217362306a36Sopenharmony_ci	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
217462306a36Sopenharmony_ci		struct ieee80211_hdr *f_hdr;
217562306a36Sopenharmony_ci		struct sk_buff *f_skb;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci		idx--;
217862306a36Sopenharmony_ci		if (idx < 0)
217962306a36Sopenharmony_ci			idx = IEEE80211_FRAGMENT_MAX - 1;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci		entry = &cache->entries[idx];
218262306a36Sopenharmony_ci		if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
218362306a36Sopenharmony_ci		    entry->rx_queue != rx_queue ||
218462306a36Sopenharmony_ci		    entry->last_frag + 1 != frag)
218562306a36Sopenharmony_ci			continue;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci		f_skb = __skb_peek(&entry->skb_list);
218862306a36Sopenharmony_ci		f_hdr = (struct ieee80211_hdr *) f_skb->data;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci		/*
219162306a36Sopenharmony_ci		 * Check ftype and addresses are equal, else check next fragment
219262306a36Sopenharmony_ci		 */
219362306a36Sopenharmony_ci		if (((hdr->frame_control ^ f_hdr->frame_control) &
219462306a36Sopenharmony_ci		     cpu_to_le16(IEEE80211_FCTL_FTYPE)) ||
219562306a36Sopenharmony_ci		    !ether_addr_equal(hdr->addr1, f_hdr->addr1) ||
219662306a36Sopenharmony_ci		    !ether_addr_equal(hdr->addr2, f_hdr->addr2))
219762306a36Sopenharmony_ci			continue;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci		if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
220062306a36Sopenharmony_ci			__skb_queue_purge(&entry->skb_list);
220162306a36Sopenharmony_ci			continue;
220262306a36Sopenharmony_ci		}
220362306a36Sopenharmony_ci		return entry;
220462306a36Sopenharmony_ci	}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	return NULL;
220762306a36Sopenharmony_ci}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_cistatic bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	return rx->key &&
221262306a36Sopenharmony_ci		(rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
221362306a36Sopenharmony_ci		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
221462306a36Sopenharmony_ci		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
221562306a36Sopenharmony_ci		 rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
221662306a36Sopenharmony_ci		ieee80211_has_protected(fc);
221762306a36Sopenharmony_ci}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
222062306a36Sopenharmony_ciieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
222162306a36Sopenharmony_ci{
222262306a36Sopenharmony_ci	struct ieee80211_fragment_cache *cache = &rx->sdata->frags;
222362306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
222462306a36Sopenharmony_ci	u16 sc;
222562306a36Sopenharmony_ci	__le16 fc;
222662306a36Sopenharmony_ci	unsigned int frag, seq;
222762306a36Sopenharmony_ci	struct ieee80211_fragment_entry *entry;
222862306a36Sopenharmony_ci	struct sk_buff *skb;
222962306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *)rx->skb->data;
223262306a36Sopenharmony_ci	fc = hdr->frame_control;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc))
223562306a36Sopenharmony_ci		return RX_CONTINUE;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	sc = le16_to_cpu(hdr->seq_ctrl);
223862306a36Sopenharmony_ci	frag = sc & IEEE80211_SCTL_FRAG;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	if (rx->sta)
224162306a36Sopenharmony_ci		cache = &rx->sta->frags;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
224462306a36Sopenharmony_ci		goto out;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	if (is_multicast_ether_addr(hdr->addr1))
224762306a36Sopenharmony_ci		return RX_DROP_MONITOR;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	I802_DEBUG_INC(rx->local->rx_handlers_fragments);
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (skb_linearize(rx->skb))
225262306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/*
225562306a36Sopenharmony_ci	 *  skb_linearize() might change the skb->data and
225662306a36Sopenharmony_ci	 *  previously cached variables (in this case, hdr) need to
225762306a36Sopenharmony_ci	 *  be refreshed with the new data.
225862306a36Sopenharmony_ci	 */
225962306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *)rx->skb->data;
226062306a36Sopenharmony_ci	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (frag == 0) {
226362306a36Sopenharmony_ci		/* This is the first fragment of a new frame. */
226462306a36Sopenharmony_ci		entry = ieee80211_reassemble_add(cache, frag, seq,
226562306a36Sopenharmony_ci						 rx->seqno_idx, &(rx->skb));
226662306a36Sopenharmony_ci		if (requires_sequential_pn(rx, fc)) {
226762306a36Sopenharmony_ci			int queue = rx->security_idx;
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci			/* Store CCMP/GCMP PN so that we can verify that the
227062306a36Sopenharmony_ci			 * next fragment has a sequential PN value.
227162306a36Sopenharmony_ci			 */
227262306a36Sopenharmony_ci			entry->check_sequential_pn = true;
227362306a36Sopenharmony_ci			entry->is_protected = true;
227462306a36Sopenharmony_ci			entry->key_color = rx->key->color;
227562306a36Sopenharmony_ci			memcpy(entry->last_pn,
227662306a36Sopenharmony_ci			       rx->key->u.ccmp.rx_pn[queue],
227762306a36Sopenharmony_ci			       IEEE80211_CCMP_PN_LEN);
227862306a36Sopenharmony_ci			BUILD_BUG_ON(offsetof(struct ieee80211_key,
227962306a36Sopenharmony_ci					      u.ccmp.rx_pn) !=
228062306a36Sopenharmony_ci				     offsetof(struct ieee80211_key,
228162306a36Sopenharmony_ci					      u.gcmp.rx_pn));
228262306a36Sopenharmony_ci			BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
228362306a36Sopenharmony_ci				     sizeof(rx->key->u.gcmp.rx_pn[queue]));
228462306a36Sopenharmony_ci			BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
228562306a36Sopenharmony_ci				     IEEE80211_GCMP_PN_LEN);
228662306a36Sopenharmony_ci		} else if (rx->key &&
228762306a36Sopenharmony_ci			   (ieee80211_has_protected(fc) ||
228862306a36Sopenharmony_ci			    (status->flag & RX_FLAG_DECRYPTED))) {
228962306a36Sopenharmony_ci			entry->is_protected = true;
229062306a36Sopenharmony_ci			entry->key_color = rx->key->color;
229162306a36Sopenharmony_ci		}
229262306a36Sopenharmony_ci		return RX_QUEUED;
229362306a36Sopenharmony_ci	}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	/* This is a fragment for a frame that should already be pending in
229662306a36Sopenharmony_ci	 * fragment cache. Add this fragment to the end of the pending entry.
229762306a36Sopenharmony_ci	 */
229862306a36Sopenharmony_ci	entry = ieee80211_reassemble_find(cache, frag, seq,
229962306a36Sopenharmony_ci					  rx->seqno_idx, hdr);
230062306a36Sopenharmony_ci	if (!entry) {
230162306a36Sopenharmony_ci		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
230262306a36Sopenharmony_ci		return RX_DROP_MONITOR;
230362306a36Sopenharmony_ci	}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	/* "The receiver shall discard MSDUs and MMPDUs whose constituent
230662306a36Sopenharmony_ci	 *  MPDU PN values are not incrementing in steps of 1."
230762306a36Sopenharmony_ci	 * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
230862306a36Sopenharmony_ci	 * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
230962306a36Sopenharmony_ci	 */
231062306a36Sopenharmony_ci	if (entry->check_sequential_pn) {
231162306a36Sopenharmony_ci		int i;
231262306a36Sopenharmony_ci		u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci		if (!requires_sequential_pn(rx, fc))
231562306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci		/* Prevent mixed key and fragment cache attacks */
231862306a36Sopenharmony_ci		if (entry->key_color != rx->key->color)
231962306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci		memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
232262306a36Sopenharmony_ci		for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
232362306a36Sopenharmony_ci			pn[i]++;
232462306a36Sopenharmony_ci			if (pn[i])
232562306a36Sopenharmony_ci				break;
232662306a36Sopenharmony_ci		}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci		rpn = rx->ccm_gcm.pn;
232962306a36Sopenharmony_ci		if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN))
233062306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
233162306a36Sopenharmony_ci		memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
233262306a36Sopenharmony_ci	} else if (entry->is_protected &&
233362306a36Sopenharmony_ci		   (!rx->key ||
233462306a36Sopenharmony_ci		    (!ieee80211_has_protected(fc) &&
233562306a36Sopenharmony_ci		     !(status->flag & RX_FLAG_DECRYPTED)) ||
233662306a36Sopenharmony_ci		    rx->key->color != entry->key_color)) {
233762306a36Sopenharmony_ci		/* Drop this as a mixed key or fragment cache attack, even
233862306a36Sopenharmony_ci		 * if for TKIP Michael MIC should protect us, and WEP is a
233962306a36Sopenharmony_ci		 * lost cause anyway.
234062306a36Sopenharmony_ci		 */
234162306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
234262306a36Sopenharmony_ci	} else if (entry->is_protected && rx->key &&
234362306a36Sopenharmony_ci		   entry->key_color != rx->key->color &&
234462306a36Sopenharmony_ci		   (status->flag & RX_FLAG_DECRYPTED)) {
234562306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	skb_pull(rx->skb, ieee80211_hdrlen(fc));
234962306a36Sopenharmony_ci	__skb_queue_tail(&entry->skb_list, rx->skb);
235062306a36Sopenharmony_ci	entry->last_frag = frag;
235162306a36Sopenharmony_ci	entry->extra_len += rx->skb->len;
235262306a36Sopenharmony_ci	if (ieee80211_has_morefrags(fc)) {
235362306a36Sopenharmony_ci		rx->skb = NULL;
235462306a36Sopenharmony_ci		return RX_QUEUED;
235562306a36Sopenharmony_ci	}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	rx->skb = __skb_dequeue(&entry->skb_list);
235862306a36Sopenharmony_ci	if (skb_tailroom(rx->skb) < entry->extra_len) {
235962306a36Sopenharmony_ci		I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag);
236062306a36Sopenharmony_ci		if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
236162306a36Sopenharmony_ci					      GFP_ATOMIC))) {
236262306a36Sopenharmony_ci			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
236362306a36Sopenharmony_ci			__skb_queue_purge(&entry->skb_list);
236462306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&entry->skb_list))) {
236862306a36Sopenharmony_ci		skb_put_data(rx->skb, skb->data, skb->len);
236962306a36Sopenharmony_ci		dev_kfree_skb(skb);
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci out:
237362306a36Sopenharmony_ci	ieee80211_led_rx(rx->local);
237462306a36Sopenharmony_ci	if (rx->sta)
237562306a36Sopenharmony_ci		rx->link_sta->rx_stats.packets++;
237662306a36Sopenharmony_ci	return RX_CONTINUE;
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_cistatic int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
238062306a36Sopenharmony_ci{
238162306a36Sopenharmony_ci	if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
238262306a36Sopenharmony_ci		return -EACCES;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	return 0;
238562306a36Sopenharmony_ci}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_cistatic int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
238862306a36Sopenharmony_ci{
238962306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
239062306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	/*
239362306a36Sopenharmony_ci	 * Pass through unencrypted frames if the hardware has
239462306a36Sopenharmony_ci	 * decrypted them already.
239562306a36Sopenharmony_ci	 */
239662306a36Sopenharmony_ci	if (status->flag & RX_FLAG_DECRYPTED)
239762306a36Sopenharmony_ci		return 0;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	/* Drop unencrypted frames if key is set. */
240062306a36Sopenharmony_ci	if (unlikely(!ieee80211_has_protected(fc) &&
240162306a36Sopenharmony_ci		     !ieee80211_is_any_nullfunc(fc) &&
240262306a36Sopenharmony_ci		     ieee80211_is_data(fc) && rx->key))
240362306a36Sopenharmony_ci		return -EACCES;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	return 0;
240662306a36Sopenharmony_ci}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_cistatic int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
240962306a36Sopenharmony_ci{
241062306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
241162306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
241262306a36Sopenharmony_ci	__le16 fc = mgmt->frame_control;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	/*
241562306a36Sopenharmony_ci	 * Pass through unencrypted frames if the hardware has
241662306a36Sopenharmony_ci	 * decrypted them already.
241762306a36Sopenharmony_ci	 */
241862306a36Sopenharmony_ci	if (status->flag & RX_FLAG_DECRYPTED)
241962306a36Sopenharmony_ci		return 0;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	/* drop unicast protected dual (that wasn't protected) */
242262306a36Sopenharmony_ci	if (ieee80211_is_action(fc) &&
242362306a36Sopenharmony_ci	    mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
242462306a36Sopenharmony_ci		return -EACCES;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
242762306a36Sopenharmony_ci		if (unlikely(!ieee80211_has_protected(fc) &&
242862306a36Sopenharmony_ci			     ieee80211_is_unicast_robust_mgmt_frame(rx->skb))) {
242962306a36Sopenharmony_ci			if (ieee80211_is_deauth(fc) ||
243062306a36Sopenharmony_ci			    ieee80211_is_disassoc(fc)) {
243162306a36Sopenharmony_ci				/*
243262306a36Sopenharmony_ci				 * Permit unprotected deauth/disassoc frames
243362306a36Sopenharmony_ci				 * during 4-way-HS (key is installed after HS).
243462306a36Sopenharmony_ci				 */
243562306a36Sopenharmony_ci				if (!rx->key)
243662306a36Sopenharmony_ci					return 0;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
243962306a36Sopenharmony_ci							     rx->skb->data,
244062306a36Sopenharmony_ci							     rx->skb->len);
244162306a36Sopenharmony_ci			}
244262306a36Sopenharmony_ci			return -EACCES;
244362306a36Sopenharmony_ci		}
244462306a36Sopenharmony_ci		/* BIP does not use Protected field, so need to check MMIE */
244562306a36Sopenharmony_ci		if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
244662306a36Sopenharmony_ci			     ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
244762306a36Sopenharmony_ci			if (ieee80211_is_deauth(fc) ||
244862306a36Sopenharmony_ci			    ieee80211_is_disassoc(fc))
244962306a36Sopenharmony_ci				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
245062306a36Sopenharmony_ci							     rx->skb->data,
245162306a36Sopenharmony_ci							     rx->skb->len);
245262306a36Sopenharmony_ci			return -EACCES;
245362306a36Sopenharmony_ci		}
245462306a36Sopenharmony_ci		if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
245562306a36Sopenharmony_ci			     ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
245662306a36Sopenharmony_ci			cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
245762306a36Sopenharmony_ci						     rx->skb->data,
245862306a36Sopenharmony_ci						     rx->skb->len);
245962306a36Sopenharmony_ci			return -EACCES;
246062306a36Sopenharmony_ci		}
246162306a36Sopenharmony_ci		/*
246262306a36Sopenharmony_ci		 * When using MFP, Action frames are not allowed prior to
246362306a36Sopenharmony_ci		 * having configured keys.
246462306a36Sopenharmony_ci		 */
246562306a36Sopenharmony_ci		if (unlikely(ieee80211_is_action(fc) && !rx->key &&
246662306a36Sopenharmony_ci			     ieee80211_is_robust_mgmt_frame(rx->skb)))
246762306a36Sopenharmony_ci			return -EACCES;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci		/* drop unicast public action frames when using MPF */
247062306a36Sopenharmony_ci		if (is_unicast_ether_addr(mgmt->da) &&
247162306a36Sopenharmony_ci		    ieee80211_is_protected_dual_of_public_action(rx->skb))
247262306a36Sopenharmony_ci			return -EACCES;
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	return 0;
247662306a36Sopenharmony_ci}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_cistatic int
247962306a36Sopenharmony_ci__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
248262306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
248362306a36Sopenharmony_ci	bool check_port_control = false;
248462306a36Sopenharmony_ci	struct ethhdr *ehdr;
248562306a36Sopenharmony_ci	int ret;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	*port_control = false;
248862306a36Sopenharmony_ci	if (ieee80211_has_a4(hdr->frame_control) &&
248962306a36Sopenharmony_ci	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
249062306a36Sopenharmony_ci		return -1;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
249362306a36Sopenharmony_ci	    !!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) {
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci		if (!sdata->u.mgd.use_4addr)
249662306a36Sopenharmony_ci			return -1;
249762306a36Sopenharmony_ci		else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr))
249862306a36Sopenharmony_ci			check_port_control = true;
249962306a36Sopenharmony_ci	}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	if (is_multicast_ether_addr(hdr->addr1) &&
250262306a36Sopenharmony_ci	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta)
250362306a36Sopenharmony_ci		return -1;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
250662306a36Sopenharmony_ci	if (ret < 0)
250762306a36Sopenharmony_ci		return ret;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	ehdr = (struct ethhdr *) rx->skb->data;
251062306a36Sopenharmony_ci	if (ehdr->h_proto == rx->sdata->control_port_protocol)
251162306a36Sopenharmony_ci		*port_control = true;
251262306a36Sopenharmony_ci	else if (check_port_control)
251362306a36Sopenharmony_ci		return -1;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	return 0;
251662306a36Sopenharmony_ci}
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_cibool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
251962306a36Sopenharmony_ci			   const u8 *addr, int *out_link_id)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	unsigned int link_id;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	/* non-MLO, or MLD address replaced by hardware */
252462306a36Sopenharmony_ci	if (ether_addr_equal(sdata->vif.addr, addr))
252562306a36Sopenharmony_ci		return true;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (!ieee80211_vif_is_mld(&sdata->vif))
252862306a36Sopenharmony_ci		return false;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
253162306a36Sopenharmony_ci		struct ieee80211_bss_conf *conf;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci		conf = rcu_dereference(sdata->vif.link_conf[link_id]);
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci		if (!conf)
253662306a36Sopenharmony_ci			continue;
253762306a36Sopenharmony_ci		if (ether_addr_equal(conf->addr, addr)) {
253862306a36Sopenharmony_ci			if (out_link_id)
253962306a36Sopenharmony_ci				*out_link_id = link_id;
254062306a36Sopenharmony_ci			return true;
254162306a36Sopenharmony_ci		}
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	return false;
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci/*
254862306a36Sopenharmony_ci * requires that rx->skb is a frame with ethernet header
254962306a36Sopenharmony_ci */
255062306a36Sopenharmony_cistatic bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
255162306a36Sopenharmony_ci{
255262306a36Sopenharmony_ci	static const u8 pae_group_addr[ETH_ALEN] __aligned(2)
255362306a36Sopenharmony_ci		= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
255462306a36Sopenharmony_ci	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	/*
255762306a36Sopenharmony_ci	 * Allow EAPOL frames to us/the PAE group address regardless of
255862306a36Sopenharmony_ci	 * whether the frame was encrypted or not, and always disallow
255962306a36Sopenharmony_ci	 * all other destination addresses for them.
256062306a36Sopenharmony_ci	 */
256162306a36Sopenharmony_ci	if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
256262306a36Sopenharmony_ci		return ieee80211_is_our_addr(rx->sdata, ehdr->h_dest, NULL) ||
256362306a36Sopenharmony_ci		       ether_addr_equal(ehdr->h_dest, pae_group_addr);
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	if (ieee80211_802_1x_port_control(rx) ||
256662306a36Sopenharmony_ci	    ieee80211_drop_unencrypted(rx, fc))
256762306a36Sopenharmony_ci		return false;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	return true;
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_cistatic void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
257362306a36Sopenharmony_ci						 struct ieee80211_rx_data *rx)
257462306a36Sopenharmony_ci{
257562306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
257662306a36Sopenharmony_ci	struct net_device *dev = sdata->dev;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	if (unlikely((skb->protocol == sdata->control_port_protocol ||
257962306a36Sopenharmony_ci		     (skb->protocol == cpu_to_be16(ETH_P_PREAUTH) &&
258062306a36Sopenharmony_ci		      !sdata->control_port_no_preauth)) &&
258162306a36Sopenharmony_ci		     sdata->control_port_over_nl80211)) {
258262306a36Sopenharmony_ci		struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
258362306a36Sopenharmony_ci		bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED);
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci		cfg80211_rx_control_port(dev, skb, noencrypt, rx->link_id);
258662306a36Sopenharmony_ci		dev_kfree_skb(skb);
258762306a36Sopenharmony_ci	} else {
258862306a36Sopenharmony_ci		struct ethhdr *ehdr = (void *)skb_mac_header(skb);
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci		memset(skb->cb, 0, sizeof(skb->cb));
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci		/*
259362306a36Sopenharmony_ci		 * 802.1X over 802.11 requires that the authenticator address
259462306a36Sopenharmony_ci		 * be used for EAPOL frames. However, 802.1X allows the use of
259562306a36Sopenharmony_ci		 * the PAE group address instead. If the interface is part of
259662306a36Sopenharmony_ci		 * a bridge and we pass the frame with the PAE group address,
259762306a36Sopenharmony_ci		 * then the bridge will forward it to the network (even if the
259862306a36Sopenharmony_ci		 * client was not associated yet), which isn't supposed to
259962306a36Sopenharmony_ci		 * happen.
260062306a36Sopenharmony_ci		 * To avoid that, rewrite the destination address to our own
260162306a36Sopenharmony_ci		 * address, so that the authenticator (e.g. hostapd) will see
260262306a36Sopenharmony_ci		 * the frame, but bridge won't forward it anywhere else. Note
260362306a36Sopenharmony_ci		 * that due to earlier filtering, the only other address can
260462306a36Sopenharmony_ci		 * be the PAE group address, unless the hardware allowed them
260562306a36Sopenharmony_ci		 * through in 802.3 offloaded mode.
260662306a36Sopenharmony_ci		 */
260762306a36Sopenharmony_ci		if (unlikely(skb->protocol == sdata->control_port_protocol &&
260862306a36Sopenharmony_ci			     !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
260962306a36Sopenharmony_ci			ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci		/* deliver to local stack */
261262306a36Sopenharmony_ci		if (rx->list)
261362306a36Sopenharmony_ci			list_add_tail(&skb->list, rx->list);
261462306a36Sopenharmony_ci		else
261562306a36Sopenharmony_ci			netif_receive_skb(skb);
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci/*
262062306a36Sopenharmony_ci * requires that rx->skb is a frame with ethernet header
262162306a36Sopenharmony_ci */
262262306a36Sopenharmony_cistatic void
262362306a36Sopenharmony_ciieee80211_deliver_skb(struct ieee80211_rx_data *rx)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
262662306a36Sopenharmony_ci	struct net_device *dev = sdata->dev;
262762306a36Sopenharmony_ci	struct sk_buff *skb, *xmit_skb;
262862306a36Sopenharmony_ci	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
262962306a36Sopenharmony_ci	struct sta_info *dsta;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	skb = rx->skb;
263262306a36Sopenharmony_ci	xmit_skb = NULL;
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	dev_sw_netstats_rx_add(dev, skb->len);
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	if (rx->sta) {
263762306a36Sopenharmony_ci		/* The seqno index has the same property as needed
263862306a36Sopenharmony_ci		 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
263962306a36Sopenharmony_ci		 * for non-QoS-data frames. Here we know it's a data
264062306a36Sopenharmony_ci		 * frame, so count MSDUs.
264162306a36Sopenharmony_ci		 */
264262306a36Sopenharmony_ci		u64_stats_update_begin(&rx->link_sta->rx_stats.syncp);
264362306a36Sopenharmony_ci		rx->link_sta->rx_stats.msdu[rx->seqno_idx]++;
264462306a36Sopenharmony_ci		u64_stats_update_end(&rx->link_sta->rx_stats.syncp);
264562306a36Sopenharmony_ci	}
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
264862306a36Sopenharmony_ci	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
264962306a36Sopenharmony_ci	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
265062306a36Sopenharmony_ci	    ehdr->h_proto != rx->sdata->control_port_protocol &&
265162306a36Sopenharmony_ci	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
265262306a36Sopenharmony_ci		if (is_multicast_ether_addr(ehdr->h_dest) &&
265362306a36Sopenharmony_ci		    ieee80211_vif_get_num_mcast_if(sdata) != 0) {
265462306a36Sopenharmony_ci			/*
265562306a36Sopenharmony_ci			 * send multicast frames both to higher layers in
265662306a36Sopenharmony_ci			 * local net stack and back to the wireless medium
265762306a36Sopenharmony_ci			 */
265862306a36Sopenharmony_ci			xmit_skb = skb_copy(skb, GFP_ATOMIC);
265962306a36Sopenharmony_ci			if (!xmit_skb)
266062306a36Sopenharmony_ci				net_info_ratelimited("%s: failed to clone multicast frame\n",
266162306a36Sopenharmony_ci						    dev->name);
266262306a36Sopenharmony_ci		} else if (!is_multicast_ether_addr(ehdr->h_dest) &&
266362306a36Sopenharmony_ci			   !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) {
266462306a36Sopenharmony_ci			dsta = sta_info_get(sdata, ehdr->h_dest);
266562306a36Sopenharmony_ci			if (dsta) {
266662306a36Sopenharmony_ci				/*
266762306a36Sopenharmony_ci				 * The destination station is associated to
266862306a36Sopenharmony_ci				 * this AP (in this VLAN), so send the frame
266962306a36Sopenharmony_ci				 * directly to it and do not pass it to local
267062306a36Sopenharmony_ci				 * net stack.
267162306a36Sopenharmony_ci				 */
267262306a36Sopenharmony_ci				xmit_skb = skb;
267362306a36Sopenharmony_ci				skb = NULL;
267462306a36Sopenharmony_ci			}
267562306a36Sopenharmony_ci		}
267662306a36Sopenharmony_ci	}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
267962306a36Sopenharmony_ci	if (skb) {
268062306a36Sopenharmony_ci		/* 'align' will only take the values 0 or 2 here since all
268162306a36Sopenharmony_ci		 * frames are required to be aligned to 2-byte boundaries
268262306a36Sopenharmony_ci		 * when being passed to mac80211; the code here works just
268362306a36Sopenharmony_ci		 * as well if that isn't true, but mac80211 assumes it can
268462306a36Sopenharmony_ci		 * access fields as 2-byte aligned (e.g. for ether_addr_equal)
268562306a36Sopenharmony_ci		 */
268662306a36Sopenharmony_ci		int align;
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci		align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3;
268962306a36Sopenharmony_ci		if (align) {
269062306a36Sopenharmony_ci			if (WARN_ON(skb_headroom(skb) < 3)) {
269162306a36Sopenharmony_ci				dev_kfree_skb(skb);
269262306a36Sopenharmony_ci				skb = NULL;
269362306a36Sopenharmony_ci			} else {
269462306a36Sopenharmony_ci				u8 *data = skb->data;
269562306a36Sopenharmony_ci				size_t len = skb_headlen(skb);
269662306a36Sopenharmony_ci				skb->data -= align;
269762306a36Sopenharmony_ci				memmove(skb->data, data, len);
269862306a36Sopenharmony_ci				skb_set_tail_pointer(skb, len);
269962306a36Sopenharmony_ci			}
270062306a36Sopenharmony_ci		}
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci#endif
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	if (skb) {
270562306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, dev);
270662306a36Sopenharmony_ci		ieee80211_deliver_skb_to_local_stack(skb, rx);
270762306a36Sopenharmony_ci	}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	if (xmit_skb) {
271062306a36Sopenharmony_ci		/*
271162306a36Sopenharmony_ci		 * Send to wireless media and increase priority by 256 to
271262306a36Sopenharmony_ci		 * keep the received priority instead of reclassifying
271362306a36Sopenharmony_ci		 * the frame (see cfg80211_classify8021d).
271462306a36Sopenharmony_ci		 */
271562306a36Sopenharmony_ci		xmit_skb->priority += 256;
271662306a36Sopenharmony_ci		xmit_skb->protocol = htons(ETH_P_802_3);
271762306a36Sopenharmony_ci		skb_reset_network_header(xmit_skb);
271862306a36Sopenharmony_ci		skb_reset_mac_header(xmit_skb);
271962306a36Sopenharmony_ci		dev_queue_xmit(xmit_skb);
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
272462306a36Sopenharmony_cistatic bool
272562306a36Sopenharmony_ciieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
272662306a36Sopenharmony_ci			       struct sk_buff *skb, int hdrlen)
272762306a36Sopenharmony_ci{
272862306a36Sopenharmony_ci	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
272962306a36Sopenharmony_ci	struct ieee80211_mesh_fast_tx *entry = NULL;
273062306a36Sopenharmony_ci	struct ieee80211s_hdr *mesh_hdr;
273162306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
273262306a36Sopenharmony_ci	struct sta_info *sta;
273362306a36Sopenharmony_ci	struct ethhdr eth;
273462306a36Sopenharmony_ci	u8 tid;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
273762306a36Sopenharmony_ci	if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
273862306a36Sopenharmony_ci		entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
273962306a36Sopenharmony_ci	else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
274062306a36Sopenharmony_ci		entry = mesh_fast_tx_get(sdata, skb->data);
274162306a36Sopenharmony_ci	if (!entry)
274262306a36Sopenharmony_ci		return false;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	sta = rcu_dereference(entry->mpath->next_hop);
274562306a36Sopenharmony_ci	if (!sta)
274662306a36Sopenharmony_ci		return false;
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	if (skb_linearize(skb))
274962306a36Sopenharmony_ci		return false;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
275262306a36Sopenharmony_ci	tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
275362306a36Sopenharmony_ci	if (tid_tx) {
275462306a36Sopenharmony_ci		if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
275562306a36Sopenharmony_ci			return false;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci		if (tid_tx->timeout)
275862306a36Sopenharmony_ci			tid_tx->last_tx = jiffies;
275962306a36Sopenharmony_ci	}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	ieee80211_aggr_check(sdata, sta, skb);
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	if (ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
276462306a36Sopenharmony_ci					    &skb->protocol))
276562306a36Sopenharmony_ci		hdrlen += ETH_ALEN;
276662306a36Sopenharmony_ci	else
276762306a36Sopenharmony_ci		skb->protocol = htons(skb->len - hdrlen);
276862306a36Sopenharmony_ci	skb_set_network_header(skb, hdrlen + 2);
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	skb->dev = sdata->dev;
277162306a36Sopenharmony_ci	memcpy(&eth, skb->data, ETH_HLEN - 2);
277262306a36Sopenharmony_ci	skb_pull(skb, 2);
277362306a36Sopenharmony_ci	__ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
277462306a36Sopenharmony_ci			      eth.h_dest, eth.h_source);
277562306a36Sopenharmony_ci	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
277662306a36Sopenharmony_ci	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	return true;
277962306a36Sopenharmony_ci}
278062306a36Sopenharmony_ci#endif
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_cistatic ieee80211_rx_result
278362306a36Sopenharmony_ciieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
278462306a36Sopenharmony_ci		       struct sk_buff *skb)
278562306a36Sopenharmony_ci{
278662306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
278762306a36Sopenharmony_ci	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
278862306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
278962306a36Sopenharmony_ci	uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
279062306a36Sopenharmony_ci	struct ieee80211_hdr hdr = {
279162306a36Sopenharmony_ci		.frame_control = cpu_to_le16(fc)
279262306a36Sopenharmony_ci	};
279362306a36Sopenharmony_ci	struct ieee80211_hdr *fwd_hdr;
279462306a36Sopenharmony_ci	struct ieee80211s_hdr *mesh_hdr;
279562306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
279662306a36Sopenharmony_ci	struct sk_buff *fwd_skb;
279762306a36Sopenharmony_ci	struct ethhdr *eth;
279862306a36Sopenharmony_ci	bool multicast;
279962306a36Sopenharmony_ci	int tailroom = 0;
280062306a36Sopenharmony_ci	int hdrlen, mesh_hdrlen;
280162306a36Sopenharmony_ci	u8 *qos;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (!ieee80211_vif_is_mesh(&sdata->vif))
280462306a36Sopenharmony_ci		return RX_CONTINUE;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(*eth) + 6))
280762306a36Sopenharmony_ci		return RX_DROP_MONITOR;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
281062306a36Sopenharmony_ci	mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
281362306a36Sopenharmony_ci		return RX_DROP_MONITOR;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	eth = (struct ethhdr *)skb->data;
281662306a36Sopenharmony_ci	multicast = is_multicast_ether_addr(eth->h_dest);
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
281962306a36Sopenharmony_ci	if (!mesh_hdr->ttl)
282062306a36Sopenharmony_ci		return RX_DROP_MONITOR;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	/* frame is in RMC, don't forward */
282362306a36Sopenharmony_ci	if (is_multicast_ether_addr(eth->h_dest) &&
282462306a36Sopenharmony_ci	    mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
282562306a36Sopenharmony_ci		return RX_DROP_MONITOR;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	/* forward packet */
282862306a36Sopenharmony_ci	if (sdata->crypto_tx_tailroom_needed_cnt)
282962306a36Sopenharmony_ci		tailroom = IEEE80211_ENCRYPT_TAILROOM;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (mesh_hdr->flags & MESH_FLAGS_AE) {
283262306a36Sopenharmony_ci		struct mesh_path *mppath;
283362306a36Sopenharmony_ci		char *proxied_addr;
283462306a36Sopenharmony_ci		bool update = false;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci		if (multicast)
283762306a36Sopenharmony_ci			proxied_addr = mesh_hdr->eaddr1;
283862306a36Sopenharmony_ci		else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
283962306a36Sopenharmony_ci			/* has_a4 already checked in ieee80211_rx_mesh_check */
284062306a36Sopenharmony_ci			proxied_addr = mesh_hdr->eaddr2;
284162306a36Sopenharmony_ci		else
284262306a36Sopenharmony_ci			return RX_DROP_MONITOR;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		rcu_read_lock();
284562306a36Sopenharmony_ci		mppath = mpp_path_lookup(sdata, proxied_addr);
284662306a36Sopenharmony_ci		if (!mppath) {
284762306a36Sopenharmony_ci			mpp_path_add(sdata, proxied_addr, eth->h_source);
284862306a36Sopenharmony_ci		} else {
284962306a36Sopenharmony_ci			spin_lock_bh(&mppath->state_lock);
285062306a36Sopenharmony_ci			if (!ether_addr_equal(mppath->mpp, eth->h_source)) {
285162306a36Sopenharmony_ci				memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
285262306a36Sopenharmony_ci				update = true;
285362306a36Sopenharmony_ci			}
285462306a36Sopenharmony_ci			mppath->exp_time = jiffies;
285562306a36Sopenharmony_ci			spin_unlock_bh(&mppath->state_lock);
285662306a36Sopenharmony_ci		}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci		/* flush fast xmit cache if the address path changed */
285962306a36Sopenharmony_ci		if (update)
286062306a36Sopenharmony_ci			mesh_fast_tx_flush_addr(sdata, proxied_addr);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci		rcu_read_unlock();
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	/* Frame has reached destination.  Don't forward */
286662306a36Sopenharmony_ci	if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
286762306a36Sopenharmony_ci		goto rx_accept;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	if (!--mesh_hdr->ttl) {
287062306a36Sopenharmony_ci		if (multicast)
287162306a36Sopenharmony_ci			goto rx_accept;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
287462306a36Sopenharmony_ci		return RX_DROP_MONITOR;
287562306a36Sopenharmony_ci	}
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	if (!ifmsh->mshcfg.dot11MeshForwarding) {
287862306a36Sopenharmony_ci		if (is_multicast_ether_addr(eth->h_dest))
287962306a36Sopenharmony_ci			goto rx_accept;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci		return RX_DROP_MONITOR;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	if (!multicast &&
288762306a36Sopenharmony_ci	    ieee80211_rx_mesh_fast_forward(sdata, skb, mesh_hdrlen))
288862306a36Sopenharmony_ci		return RX_QUEUED;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
289162306a36Sopenharmony_ci				      eth->h_dest, eth->h_source);
289262306a36Sopenharmony_ci	hdrlen = ieee80211_hdrlen(hdr.frame_control);
289362306a36Sopenharmony_ci	if (multicast) {
289462306a36Sopenharmony_ci		int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci		fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
289762306a36Sopenharmony_ci					       IEEE80211_ENCRYPT_HEADROOM,
289862306a36Sopenharmony_ci					  tailroom, GFP_ATOMIC);
289962306a36Sopenharmony_ci		if (!fwd_skb)
290062306a36Sopenharmony_ci			goto rx_accept;
290162306a36Sopenharmony_ci	} else {
290262306a36Sopenharmony_ci		fwd_skb = skb;
290362306a36Sopenharmony_ci		skb = NULL;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci		if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
290662306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci		if (skb_linearize(fwd_skb))
290962306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
291062306a36Sopenharmony_ci	}
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
291362306a36Sopenharmony_ci	memcpy(fwd_hdr, &hdr, hdrlen - 2);
291462306a36Sopenharmony_ci	qos = ieee80211_get_qos_ctl(fwd_hdr);
291562306a36Sopenharmony_ci	qos[0] = qos[1] = 0;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	skb_reset_mac_header(fwd_skb);
291862306a36Sopenharmony_ci	hdrlen += mesh_hdrlen;
291962306a36Sopenharmony_ci	if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
292062306a36Sopenharmony_ci					    &fwd_skb->protocol))
292162306a36Sopenharmony_ci		hdrlen += ETH_ALEN;
292262306a36Sopenharmony_ci	else
292362306a36Sopenharmony_ci		fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
292462306a36Sopenharmony_ci	skb_set_network_header(fwd_skb, hdrlen + 2);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(fwd_skb);
292762306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
292862306a36Sopenharmony_ci	info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
292962306a36Sopenharmony_ci	info->control.vif = &sdata->vif;
293062306a36Sopenharmony_ci	info->control.jiffies = jiffies;
293162306a36Sopenharmony_ci	fwd_skb->dev = sdata->dev;
293262306a36Sopenharmony_ci	if (multicast) {
293362306a36Sopenharmony_ci		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
293462306a36Sopenharmony_ci		memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
293562306a36Sopenharmony_ci		/* update power mode indication when forwarding */
293662306a36Sopenharmony_ci		ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
293762306a36Sopenharmony_ci	} else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
293862306a36Sopenharmony_ci		/* mesh power mode flags updated in mesh_nexthop_lookup */
293962306a36Sopenharmony_ci		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
294062306a36Sopenharmony_ci	} else {
294162306a36Sopenharmony_ci		/* unable to resolve next hop */
294262306a36Sopenharmony_ci		if (sta)
294362306a36Sopenharmony_ci			mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
294462306a36Sopenharmony_ci					   hdr.addr3, 0,
294562306a36Sopenharmony_ci					   WLAN_REASON_MESH_PATH_NOFORWARD,
294662306a36Sopenharmony_ci					   sta->sta.addr);
294762306a36Sopenharmony_ci		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
294862306a36Sopenharmony_ci		kfree_skb(fwd_skb);
294962306a36Sopenharmony_ci		goto rx_accept;
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
295362306a36Sopenharmony_ci	ieee80211_add_pending_skb(local, fwd_skb);
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_cirx_accept:
295662306a36Sopenharmony_ci	if (!skb)
295762306a36Sopenharmony_ci		return RX_QUEUED;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	ieee80211_strip_8023_mesh_hdr(skb);
296062306a36Sopenharmony_ci#endif
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	return RX_CONTINUE;
296362306a36Sopenharmony_ci}
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
296662306a36Sopenharmony_ci__ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
296762306a36Sopenharmony_ci{
296862306a36Sopenharmony_ci	struct net_device *dev = rx->sdata->dev;
296962306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
297062306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
297162306a36Sopenharmony_ci	__le16 fc = hdr->frame_control;
297262306a36Sopenharmony_ci	struct sk_buff_head frame_list;
297362306a36Sopenharmony_ci	ieee80211_rx_result res;
297462306a36Sopenharmony_ci	struct ethhdr ethhdr;
297562306a36Sopenharmony_ci	const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
297862306a36Sopenharmony_ci		check_da = NULL;
297962306a36Sopenharmony_ci		check_sa = NULL;
298062306a36Sopenharmony_ci	} else switch (rx->sdata->vif.type) {
298162306a36Sopenharmony_ci		case NL80211_IFTYPE_AP:
298262306a36Sopenharmony_ci		case NL80211_IFTYPE_AP_VLAN:
298362306a36Sopenharmony_ci			check_da = NULL;
298462306a36Sopenharmony_ci			break;
298562306a36Sopenharmony_ci		case NL80211_IFTYPE_STATION:
298662306a36Sopenharmony_ci			if (!rx->sta ||
298762306a36Sopenharmony_ci			    !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
298862306a36Sopenharmony_ci				check_sa = NULL;
298962306a36Sopenharmony_ci			break;
299062306a36Sopenharmony_ci		case NL80211_IFTYPE_MESH_POINT:
299162306a36Sopenharmony_ci			check_sa = NULL;
299262306a36Sopenharmony_ci			check_da = NULL;
299362306a36Sopenharmony_ci			break;
299462306a36Sopenharmony_ci		default:
299562306a36Sopenharmony_ci			break;
299662306a36Sopenharmony_ci	}
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	skb->dev = dev;
299962306a36Sopenharmony_ci	__skb_queue_head_init(&frame_list);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
300262306a36Sopenharmony_ci					  rx->sdata->vif.addr,
300362306a36Sopenharmony_ci					  rx->sdata->vif.type,
300462306a36Sopenharmony_ci					  data_offset, true))
300562306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	if (rx->sta->amsdu_mesh_control < 0) {
300862306a36Sopenharmony_ci		s8 valid = -1;
300962306a36Sopenharmony_ci		int i;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		for (i = 0; i <= 2; i++) {
301262306a36Sopenharmony_ci			if (!ieee80211_is_valid_amsdu(skb, i))
301362306a36Sopenharmony_ci				continue;
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci			if (valid >= 0) {
301662306a36Sopenharmony_ci				/* ambiguous */
301762306a36Sopenharmony_ci				valid = -1;
301862306a36Sopenharmony_ci				break;
301962306a36Sopenharmony_ci			}
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci			valid = i;
302262306a36Sopenharmony_ci		}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci		rx->sta->amsdu_mesh_control = valid;
302562306a36Sopenharmony_ci	}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
302862306a36Sopenharmony_ci				 rx->sdata->vif.type,
302962306a36Sopenharmony_ci				 rx->local->hw.extra_tx_headroom,
303062306a36Sopenharmony_ci				 check_da, check_sa,
303162306a36Sopenharmony_ci				 rx->sta->amsdu_mesh_control);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	while (!skb_queue_empty(&frame_list)) {
303462306a36Sopenharmony_ci		rx->skb = __skb_dequeue(&frame_list);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci		res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
303762306a36Sopenharmony_ci		switch (res) {
303862306a36Sopenharmony_ci		case RX_QUEUED:
303962306a36Sopenharmony_ci			continue;
304062306a36Sopenharmony_ci		case RX_CONTINUE:
304162306a36Sopenharmony_ci			break;
304262306a36Sopenharmony_ci		default:
304362306a36Sopenharmony_ci			goto free;
304462306a36Sopenharmony_ci		}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci		if (!ieee80211_frame_allowed(rx, fc))
304762306a36Sopenharmony_ci			goto free;
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci		ieee80211_deliver_skb(rx);
305062306a36Sopenharmony_ci		continue;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_cifree:
305362306a36Sopenharmony_ci		dev_kfree_skb(rx->skb);
305462306a36Sopenharmony_ci	}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	return RX_QUEUED;
305762306a36Sopenharmony_ci}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
306062306a36Sopenharmony_ciieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
306162306a36Sopenharmony_ci{
306262306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
306362306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
306462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
306562306a36Sopenharmony_ci	__le16 fc = hdr->frame_control;
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	if (!(status->rx_flags & IEEE80211_RX_AMSDU))
306862306a36Sopenharmony_ci		return RX_CONTINUE;
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	if (unlikely(!ieee80211_is_data(fc)))
307162306a36Sopenharmony_ci		return RX_CONTINUE;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	if (unlikely(!ieee80211_is_data_present(fc)))
307462306a36Sopenharmony_ci		return RX_DROP_MONITOR;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
307762306a36Sopenharmony_ci		switch (rx->sdata->vif.type) {
307862306a36Sopenharmony_ci		case NL80211_IFTYPE_AP_VLAN:
307962306a36Sopenharmony_ci			if (!rx->sdata->u.vlan.sta)
308062306a36Sopenharmony_ci				return RX_DROP_UNUSABLE;
308162306a36Sopenharmony_ci			break;
308262306a36Sopenharmony_ci		case NL80211_IFTYPE_STATION:
308362306a36Sopenharmony_ci			if (!rx->sdata->u.mgd.use_4addr)
308462306a36Sopenharmony_ci				return RX_DROP_UNUSABLE;
308562306a36Sopenharmony_ci			break;
308662306a36Sopenharmony_ci		case NL80211_IFTYPE_MESH_POINT:
308762306a36Sopenharmony_ci			break;
308862306a36Sopenharmony_ci		default:
308962306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
309062306a36Sopenharmony_ci		}
309162306a36Sopenharmony_ci	}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	if (is_multicast_ether_addr(hdr->addr1) || !rx->sta)
309462306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	if (rx->key) {
309762306a36Sopenharmony_ci		/*
309862306a36Sopenharmony_ci		 * We should not receive A-MSDUs on pre-HT connections,
309962306a36Sopenharmony_ci		 * and HT connections cannot use old ciphers. Thus drop
310062306a36Sopenharmony_ci		 * them, as in those cases we couldn't even have SPP
310162306a36Sopenharmony_ci		 * A-MSDUs or such.
310262306a36Sopenharmony_ci		 */
310362306a36Sopenharmony_ci		switch (rx->key->conf.cipher) {
310462306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_WEP40:
310562306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_WEP104:
310662306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_TKIP:
310762306a36Sopenharmony_ci			return RX_DROP_UNUSABLE;
310862306a36Sopenharmony_ci		default:
310962306a36Sopenharmony_ci			break;
311062306a36Sopenharmony_ci		}
311162306a36Sopenharmony_ci	}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	return __ieee80211_rx_h_amsdu(rx, 0);
311462306a36Sopenharmony_ci}
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
311762306a36Sopenharmony_ciieee80211_rx_h_data(struct ieee80211_rx_data *rx)
311862306a36Sopenharmony_ci{
311962306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
312062306a36Sopenharmony_ci	struct ieee80211_local *local = rx->local;
312162306a36Sopenharmony_ci	struct net_device *dev = sdata->dev;
312262306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
312362306a36Sopenharmony_ci	__le16 fc = hdr->frame_control;
312462306a36Sopenharmony_ci	ieee80211_rx_result res;
312562306a36Sopenharmony_ci	bool port_control;
312662306a36Sopenharmony_ci	int err;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	if (unlikely(!ieee80211_is_data(hdr->frame_control)))
312962306a36Sopenharmony_ci		return RX_CONTINUE;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
313262306a36Sopenharmony_ci		return RX_DROP_MONITOR;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	/*
313562306a36Sopenharmony_ci	 * Send unexpected-4addr-frame event to hostapd. For older versions,
313662306a36Sopenharmony_ci	 * also drop the frame to cooked monitor interfaces.
313762306a36Sopenharmony_ci	 */
313862306a36Sopenharmony_ci	if (ieee80211_has_a4(hdr->frame_control) &&
313962306a36Sopenharmony_ci	    sdata->vif.type == NL80211_IFTYPE_AP) {
314062306a36Sopenharmony_ci		if (rx->sta &&
314162306a36Sopenharmony_ci		    !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
314262306a36Sopenharmony_ci			cfg80211_rx_unexpected_4addr_frame(
314362306a36Sopenharmony_ci				rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
314462306a36Sopenharmony_ci		return RX_DROP_MONITOR;
314562306a36Sopenharmony_ci	}
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	err = __ieee80211_data_to_8023(rx, &port_control);
314862306a36Sopenharmony_ci	if (unlikely(err))
314962306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
315262306a36Sopenharmony_ci	if (res != RX_CONTINUE)
315362306a36Sopenharmony_ci		return res;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	if (!ieee80211_frame_allowed(rx, fc))
315662306a36Sopenharmony_ci		return RX_DROP_MONITOR;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	/* directly handle TDLS channel switch requests/responses */
315962306a36Sopenharmony_ci	if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto ==
316062306a36Sopenharmony_ci						cpu_to_be16(ETH_P_TDLS))) {
316162306a36Sopenharmony_ci		struct ieee80211_tdls_data *tf = (void *)rx->skb->data;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci		if (pskb_may_pull(rx->skb,
316462306a36Sopenharmony_ci				  offsetof(struct ieee80211_tdls_data, u)) &&
316562306a36Sopenharmony_ci		    tf->payload_type == WLAN_TDLS_SNAP_RFTYPE &&
316662306a36Sopenharmony_ci		    tf->category == WLAN_CATEGORY_TDLS &&
316762306a36Sopenharmony_ci		    (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
316862306a36Sopenharmony_ci		     tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
316962306a36Sopenharmony_ci			rx->skb->protocol = cpu_to_be16(ETH_P_TDLS);
317062306a36Sopenharmony_ci			__ieee80211_queue_skb_to_iface(sdata, rx->link_id,
317162306a36Sopenharmony_ci						       rx->sta, rx->skb);
317262306a36Sopenharmony_ci			return RX_QUEUED;
317362306a36Sopenharmony_ci		}
317462306a36Sopenharmony_ci	}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
317762306a36Sopenharmony_ci	    unlikely(port_control) && sdata->bss) {
317862306a36Sopenharmony_ci		sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
317962306a36Sopenharmony_ci				     u.ap);
318062306a36Sopenharmony_ci		dev = sdata->dev;
318162306a36Sopenharmony_ci		rx->sdata = sdata;
318262306a36Sopenharmony_ci	}
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	rx->skb->dev = dev;
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ci	if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
318762306a36Sopenharmony_ci	    local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
318862306a36Sopenharmony_ci	    !is_multicast_ether_addr(
318962306a36Sopenharmony_ci		    ((struct ethhdr *)rx->skb->data)->h_dest) &&
319062306a36Sopenharmony_ci	    (!local->scanning &&
319162306a36Sopenharmony_ci	     !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)))
319262306a36Sopenharmony_ci		mod_timer(&local->dynamic_ps_timer, jiffies +
319362306a36Sopenharmony_ci			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	ieee80211_deliver_skb(rx);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	return RX_QUEUED;
319862306a36Sopenharmony_ci}
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
320162306a36Sopenharmony_ciieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
320262306a36Sopenharmony_ci{
320362306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
320462306a36Sopenharmony_ci	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
320562306a36Sopenharmony_ci	struct tid_ampdu_rx *tid_agg_rx;
320662306a36Sopenharmony_ci	u16 start_seq_num;
320762306a36Sopenharmony_ci	u16 tid;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	if (likely(!ieee80211_is_ctl(bar->frame_control)))
321062306a36Sopenharmony_ci		return RX_CONTINUE;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	if (ieee80211_is_back_req(bar->frame_control)) {
321362306a36Sopenharmony_ci		struct {
321462306a36Sopenharmony_ci			__le16 control, start_seq_num;
321562306a36Sopenharmony_ci		} __packed bar_data;
321662306a36Sopenharmony_ci		struct ieee80211_event event = {
321762306a36Sopenharmony_ci			.type = BAR_RX_EVENT,
321862306a36Sopenharmony_ci		};
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci		if (!rx->sta)
322162306a36Sopenharmony_ci			return RX_DROP_MONITOR;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci		if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control),
322462306a36Sopenharmony_ci				  &bar_data, sizeof(bar_data)))
322562306a36Sopenharmony_ci			return RX_DROP_MONITOR;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci		tid = le16_to_cpu(bar_data.control) >> 12;
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci		if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
323062306a36Sopenharmony_ci		    !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
323162306a36Sopenharmony_ci			ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
323262306a36Sopenharmony_ci					     WLAN_BACK_RECIPIENT,
323362306a36Sopenharmony_ci					     WLAN_REASON_QSTA_REQUIRE_SETUP);
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci		tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
323662306a36Sopenharmony_ci		if (!tid_agg_rx)
323762306a36Sopenharmony_ci			return RX_DROP_MONITOR;
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci		start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
324062306a36Sopenharmony_ci		event.u.ba.tid = tid;
324162306a36Sopenharmony_ci		event.u.ba.ssn = start_seq_num;
324262306a36Sopenharmony_ci		event.u.ba.sta = &rx->sta->sta;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci		/* reset session timer */
324562306a36Sopenharmony_ci		if (tid_agg_rx->timeout)
324662306a36Sopenharmony_ci			mod_timer(&tid_agg_rx->session_timer,
324762306a36Sopenharmony_ci				  TU_TO_EXP_TIME(tid_agg_rx->timeout));
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci		spin_lock(&tid_agg_rx->reorder_lock);
325062306a36Sopenharmony_ci		/* release stored frames up to start of BAR */
325162306a36Sopenharmony_ci		ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
325262306a36Sopenharmony_ci						 start_seq_num, frames);
325362306a36Sopenharmony_ci		spin_unlock(&tid_agg_rx->reorder_lock);
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci		drv_event_callback(rx->local, rx->sdata, &event);
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci		kfree_skb(skb);
325862306a36Sopenharmony_ci		return RX_QUEUED;
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	/*
326262306a36Sopenharmony_ci	 * After this point, we only want management frames,
326362306a36Sopenharmony_ci	 * so we can drop all remaining control frames to
326462306a36Sopenharmony_ci	 * cooked monitor interfaces.
326562306a36Sopenharmony_ci	 */
326662306a36Sopenharmony_ci	return RX_DROP_MONITOR;
326762306a36Sopenharmony_ci}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_cistatic void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
327062306a36Sopenharmony_ci					   struct ieee80211_mgmt *mgmt,
327162306a36Sopenharmony_ci					   size_t len)
327262306a36Sopenharmony_ci{
327362306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
327462306a36Sopenharmony_ci	struct sk_buff *skb;
327562306a36Sopenharmony_ci	struct ieee80211_mgmt *resp;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) {
327862306a36Sopenharmony_ci		/* Not to own unicast address */
327962306a36Sopenharmony_ci		return;
328062306a36Sopenharmony_ci	}
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	if (!ether_addr_equal(mgmt->sa, sdata->deflink.u.mgd.bssid) ||
328362306a36Sopenharmony_ci	    !ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) {
328462306a36Sopenharmony_ci		/* Not from the current AP or not associated yet. */
328562306a36Sopenharmony_ci		return;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
328962306a36Sopenharmony_ci		/* Too short SA Query request frame */
329062306a36Sopenharmony_ci		return;
329162306a36Sopenharmony_ci	}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom);
329462306a36Sopenharmony_ci	if (skb == NULL)
329562306a36Sopenharmony_ci		return;
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	skb_reserve(skb, local->hw.extra_tx_headroom);
329862306a36Sopenharmony_ci	resp = skb_put_zero(skb, 24);
329962306a36Sopenharmony_ci	memcpy(resp->da, mgmt->sa, ETH_ALEN);
330062306a36Sopenharmony_ci	memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
330162306a36Sopenharmony_ci	memcpy(resp->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN);
330262306a36Sopenharmony_ci	resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
330362306a36Sopenharmony_ci					  IEEE80211_STYPE_ACTION);
330462306a36Sopenharmony_ci	skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
330562306a36Sopenharmony_ci	resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
330662306a36Sopenharmony_ci	resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
330762306a36Sopenharmony_ci	memcpy(resp->u.action.u.sa_query.trans_id,
330862306a36Sopenharmony_ci	       mgmt->u.action.u.sa_query.trans_id,
330962306a36Sopenharmony_ci	       WLAN_SA_QUERY_TR_ID_LEN);
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	ieee80211_tx_skb(sdata, skb);
331262306a36Sopenharmony_ci}
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_cistatic void
331562306a36Sopenharmony_ciieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
331662306a36Sopenharmony_ci{
331762306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
331862306a36Sopenharmony_ci	const struct element *ie;
331962306a36Sopenharmony_ci	size_t baselen;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
332262306a36Sopenharmony_ci				     NL80211_EXT_FEATURE_BSS_COLOR))
332362306a36Sopenharmony_ci		return;
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
332662306a36Sopenharmony_ci		return;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	if (rx->sdata->vif.bss_conf.csa_active)
332962306a36Sopenharmony_ci		return;
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	baselen = mgmt->u.beacon.variable - rx->skb->data;
333262306a36Sopenharmony_ci	if (baselen > rx->skb->len)
333362306a36Sopenharmony_ci		return;
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION,
333662306a36Sopenharmony_ci				    mgmt->u.beacon.variable,
333762306a36Sopenharmony_ci				    rx->skb->len - baselen);
333862306a36Sopenharmony_ci	if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
333962306a36Sopenharmony_ci	    ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
334062306a36Sopenharmony_ci		struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
334162306a36Sopenharmony_ci		const struct ieee80211_he_operation *he_oper;
334262306a36Sopenharmony_ci		u8 color;
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci		he_oper = (void *)(ie->data + 1);
334562306a36Sopenharmony_ci		if (le32_get_bits(he_oper->he_oper_params,
334662306a36Sopenharmony_ci				  IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED))
334762306a36Sopenharmony_ci			return;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci		color = le32_get_bits(he_oper->he_oper_params,
335062306a36Sopenharmony_ci				      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
335162306a36Sopenharmony_ci		if (color == bss_conf->he_bss_color.color)
335262306a36Sopenharmony_ci			ieee80211_obss_color_collision_notify(&rx->sdata->vif,
335362306a36Sopenharmony_ci							      BIT_ULL(color),
335462306a36Sopenharmony_ci							      GFP_ATOMIC);
335562306a36Sopenharmony_ci	}
335662306a36Sopenharmony_ci}
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
335962306a36Sopenharmony_ciieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
336062306a36Sopenharmony_ci{
336162306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
336262306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	if (ieee80211_is_s1g_beacon(mgmt->frame_control))
336562306a36Sopenharmony_ci		return RX_CONTINUE;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	/*
336862306a36Sopenharmony_ci	 * From here on, look only at management frames.
336962306a36Sopenharmony_ci	 * Data and control frames are already handled,
337062306a36Sopenharmony_ci	 * and unknown (reserved) frames are useless.
337162306a36Sopenharmony_ci	 */
337262306a36Sopenharmony_ci	if (rx->skb->len < 24)
337362306a36Sopenharmony_ci		return RX_DROP_MONITOR;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	if (!ieee80211_is_mgmt(mgmt->frame_control))
337662306a36Sopenharmony_ci		return RX_DROP_MONITOR;
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	/* drop too small action frames */
337962306a36Sopenharmony_ci	if (ieee80211_is_action(mgmt->frame_control) &&
338062306a36Sopenharmony_ci	    rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
338162306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
338462306a36Sopenharmony_ci	    ieee80211_is_beacon(mgmt->frame_control) &&
338562306a36Sopenharmony_ci	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
338662306a36Sopenharmony_ci		int sig = 0;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci		/* sw bss color collision detection */
338962306a36Sopenharmony_ci		ieee80211_rx_check_bss_color_collision(rx);
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
339262306a36Sopenharmony_ci		    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
339362306a36Sopenharmony_ci			sig = status->signal;
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci		cfg80211_report_obss_beacon_khz(rx->local->hw.wiphy,
339662306a36Sopenharmony_ci						rx->skb->data, rx->skb->len,
339762306a36Sopenharmony_ci						ieee80211_rx_status_to_khz(status),
339862306a36Sopenharmony_ci						sig);
339962306a36Sopenharmony_ci		rx->flags |= IEEE80211_RX_BEACON_REPORTED;
340062306a36Sopenharmony_ci	}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	if (ieee80211_drop_unencrypted_mgmt(rx))
340362306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	return RX_CONTINUE;
340662306a36Sopenharmony_ci}
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_cistatic bool
340962306a36Sopenharmony_ciieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
341062306a36Sopenharmony_ci{
341162306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
341262306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	/* TWT actions are only supported in AP for the moment */
341562306a36Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_AP)
341662306a36Sopenharmony_ci		return false;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	if (!rx->local->ops->add_twt_setup)
341962306a36Sopenharmony_ci		return false;
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci	if (!sdata->vif.bss_conf.twt_responder)
342262306a36Sopenharmony_ci		return false;
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	if (!rx->sta)
342562306a36Sopenharmony_ci		return false;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	switch (mgmt->u.action.u.s1g.action_code) {
342862306a36Sopenharmony_ci	case WLAN_S1G_TWT_SETUP: {
342962306a36Sopenharmony_ci		struct ieee80211_twt_setup *twt;
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
343262306a36Sopenharmony_ci				   1 + /* action code */
343362306a36Sopenharmony_ci				   sizeof(struct ieee80211_twt_setup) +
343462306a36Sopenharmony_ci				   2 /* TWT req_type agrt */)
343562306a36Sopenharmony_ci			break;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci		twt = (void *)mgmt->u.action.u.s1g.variable;
343862306a36Sopenharmony_ci		if (twt->element_id != WLAN_EID_S1G_TWT)
343962306a36Sopenharmony_ci			break;
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
344262306a36Sopenharmony_ci				   4 + /* action code + token + tlv */
344362306a36Sopenharmony_ci				   twt->length)
344462306a36Sopenharmony_ci			break;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		return true; /* queue the frame */
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci	case WLAN_S1G_TWT_TEARDOWN:
344962306a36Sopenharmony_ci		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
345062306a36Sopenharmony_ci			break;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci		return true; /* queue the frame */
345362306a36Sopenharmony_ci	default:
345462306a36Sopenharmony_ci		break;
345562306a36Sopenharmony_ci	}
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	return false;
345862306a36Sopenharmony_ci}
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
346162306a36Sopenharmony_ciieee80211_rx_h_action(struct ieee80211_rx_data *rx)
346262306a36Sopenharmony_ci{
346362306a36Sopenharmony_ci	struct ieee80211_local *local = rx->local;
346462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
346562306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
346662306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
346762306a36Sopenharmony_ci	int len = rx->skb->len;
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	if (!ieee80211_is_action(mgmt->frame_control))
347062306a36Sopenharmony_ci		return RX_CONTINUE;
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
347362306a36Sopenharmony_ci	    mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
347462306a36Sopenharmony_ci	    mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
347562306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	switch (mgmt->u.action.category) {
347862306a36Sopenharmony_ci	case WLAN_CATEGORY_HT:
347962306a36Sopenharmony_ci		/* reject HT action frames from stations not supporting HT */
348062306a36Sopenharmony_ci		if (!rx->link_sta->pub->ht_cap.ht_supported)
348162306a36Sopenharmony_ci			goto invalid;
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
348462306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
348562306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
348662306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP &&
348762306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
348862306a36Sopenharmony_ci			break;
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci		/* verify action & smps_control/chanwidth are present */
349162306a36Sopenharmony_ci		if (len < IEEE80211_MIN_ACTION_SIZE + 2)
349262306a36Sopenharmony_ci			goto invalid;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci		switch (mgmt->u.action.u.ht_smps.action) {
349562306a36Sopenharmony_ci		case WLAN_HT_ACTION_SMPS: {
349662306a36Sopenharmony_ci			struct ieee80211_supported_band *sband;
349762306a36Sopenharmony_ci			enum ieee80211_smps_mode smps_mode;
349862306a36Sopenharmony_ci			struct sta_opmode_info sta_opmode = {};
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci			if (sdata->vif.type != NL80211_IFTYPE_AP &&
350162306a36Sopenharmony_ci			    sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
350262306a36Sopenharmony_ci				goto handled;
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci			/* convert to HT capability */
350562306a36Sopenharmony_ci			switch (mgmt->u.action.u.ht_smps.smps_control) {
350662306a36Sopenharmony_ci			case WLAN_HT_SMPS_CONTROL_DISABLED:
350762306a36Sopenharmony_ci				smps_mode = IEEE80211_SMPS_OFF;
350862306a36Sopenharmony_ci				break;
350962306a36Sopenharmony_ci			case WLAN_HT_SMPS_CONTROL_STATIC:
351062306a36Sopenharmony_ci				smps_mode = IEEE80211_SMPS_STATIC;
351162306a36Sopenharmony_ci				break;
351262306a36Sopenharmony_ci			case WLAN_HT_SMPS_CONTROL_DYNAMIC:
351362306a36Sopenharmony_ci				smps_mode = IEEE80211_SMPS_DYNAMIC;
351462306a36Sopenharmony_ci				break;
351562306a36Sopenharmony_ci			default:
351662306a36Sopenharmony_ci				goto invalid;
351762306a36Sopenharmony_ci			}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci			/* if no change do nothing */
352062306a36Sopenharmony_ci			if (rx->link_sta->pub->smps_mode == smps_mode)
352162306a36Sopenharmony_ci				goto handled;
352262306a36Sopenharmony_ci			rx->link_sta->pub->smps_mode = smps_mode;
352362306a36Sopenharmony_ci			sta_opmode.smps_mode =
352462306a36Sopenharmony_ci				ieee80211_smps_mode_to_smps_mode(smps_mode);
352562306a36Sopenharmony_ci			sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED;
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci			sband = rx->local->hw.wiphy->bands[status->band];
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci			rate_control_rate_update(local, sband, rx->sta, 0,
353062306a36Sopenharmony_ci						 IEEE80211_RC_SMPS_CHANGED);
353162306a36Sopenharmony_ci			cfg80211_sta_opmode_change_notify(sdata->dev,
353262306a36Sopenharmony_ci							  rx->sta->addr,
353362306a36Sopenharmony_ci							  &sta_opmode,
353462306a36Sopenharmony_ci							  GFP_ATOMIC);
353562306a36Sopenharmony_ci			goto handled;
353662306a36Sopenharmony_ci		}
353762306a36Sopenharmony_ci		case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
353862306a36Sopenharmony_ci			struct ieee80211_supported_band *sband;
353962306a36Sopenharmony_ci			u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
354062306a36Sopenharmony_ci			enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
354162306a36Sopenharmony_ci			struct sta_opmode_info sta_opmode = {};
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci			/* If it doesn't support 40 MHz it can't change ... */
354462306a36Sopenharmony_ci			if (!(rx->link_sta->pub->ht_cap.cap &
354562306a36Sopenharmony_ci					IEEE80211_HT_CAP_SUP_WIDTH_20_40))
354662306a36Sopenharmony_ci				goto handled;
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci			if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
354962306a36Sopenharmony_ci				max_bw = IEEE80211_STA_RX_BW_20;
355062306a36Sopenharmony_ci			else
355162306a36Sopenharmony_ci				max_bw = ieee80211_sta_cap_rx_bw(rx->link_sta);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci			/* set cur_max_bandwidth and recalc sta bw */
355462306a36Sopenharmony_ci			rx->link_sta->cur_max_bandwidth = max_bw;
355562306a36Sopenharmony_ci			new_bw = ieee80211_sta_cur_vht_bw(rx->link_sta);
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci			if (rx->link_sta->pub->bandwidth == new_bw)
355862306a36Sopenharmony_ci				goto handled;
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci			rx->link_sta->pub->bandwidth = new_bw;
356162306a36Sopenharmony_ci			sband = rx->local->hw.wiphy->bands[status->band];
356262306a36Sopenharmony_ci			sta_opmode.bw =
356362306a36Sopenharmony_ci				ieee80211_sta_rx_bw_to_chan_width(rx->link_sta);
356462306a36Sopenharmony_ci			sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci			rate_control_rate_update(local, sband, rx->sta, 0,
356762306a36Sopenharmony_ci						 IEEE80211_RC_BW_CHANGED);
356862306a36Sopenharmony_ci			cfg80211_sta_opmode_change_notify(sdata->dev,
356962306a36Sopenharmony_ci							  rx->sta->addr,
357062306a36Sopenharmony_ci							  &sta_opmode,
357162306a36Sopenharmony_ci							  GFP_ATOMIC);
357262306a36Sopenharmony_ci			goto handled;
357362306a36Sopenharmony_ci		}
357462306a36Sopenharmony_ci		default:
357562306a36Sopenharmony_ci			goto invalid;
357662306a36Sopenharmony_ci		}
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci		break;
357962306a36Sopenharmony_ci	case WLAN_CATEGORY_PUBLIC:
358062306a36Sopenharmony_ci		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
358162306a36Sopenharmony_ci			goto invalid;
358262306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION)
358362306a36Sopenharmony_ci			break;
358462306a36Sopenharmony_ci		if (!rx->sta)
358562306a36Sopenharmony_ci			break;
358662306a36Sopenharmony_ci		if (!ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid))
358762306a36Sopenharmony_ci			break;
358862306a36Sopenharmony_ci		if (mgmt->u.action.u.ext_chan_switch.action_code !=
358962306a36Sopenharmony_ci				WLAN_PUB_ACTION_EXT_CHANSW_ANN)
359062306a36Sopenharmony_ci			break;
359162306a36Sopenharmony_ci		if (len < offsetof(struct ieee80211_mgmt,
359262306a36Sopenharmony_ci				   u.action.u.ext_chan_switch.variable))
359362306a36Sopenharmony_ci			goto invalid;
359462306a36Sopenharmony_ci		goto queue;
359562306a36Sopenharmony_ci	case WLAN_CATEGORY_VHT:
359662306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
359762306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
359862306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
359962306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP &&
360062306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
360162306a36Sopenharmony_ci			break;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci		/* verify action code is present */
360462306a36Sopenharmony_ci		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
360562306a36Sopenharmony_ci			goto invalid;
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci		switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
360862306a36Sopenharmony_ci		case WLAN_VHT_ACTION_OPMODE_NOTIF: {
360962306a36Sopenharmony_ci			/* verify opmode is present */
361062306a36Sopenharmony_ci			if (len < IEEE80211_MIN_ACTION_SIZE + 2)
361162306a36Sopenharmony_ci				goto invalid;
361262306a36Sopenharmony_ci			goto queue;
361362306a36Sopenharmony_ci		}
361462306a36Sopenharmony_ci		case WLAN_VHT_ACTION_GROUPID_MGMT: {
361562306a36Sopenharmony_ci			if (len < IEEE80211_MIN_ACTION_SIZE + 25)
361662306a36Sopenharmony_ci				goto invalid;
361762306a36Sopenharmony_ci			goto queue;
361862306a36Sopenharmony_ci		}
361962306a36Sopenharmony_ci		default:
362062306a36Sopenharmony_ci			break;
362162306a36Sopenharmony_ci		}
362262306a36Sopenharmony_ci		break;
362362306a36Sopenharmony_ci	case WLAN_CATEGORY_BACK:
362462306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
362562306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
362662306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
362762306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_AP &&
362862306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
362962306a36Sopenharmony_ci			break;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci		/* verify action_code is present */
363262306a36Sopenharmony_ci		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
363362306a36Sopenharmony_ci			break;
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci		switch (mgmt->u.action.u.addba_req.action_code) {
363662306a36Sopenharmony_ci		case WLAN_ACTION_ADDBA_REQ:
363762306a36Sopenharmony_ci			if (len < (IEEE80211_MIN_ACTION_SIZE +
363862306a36Sopenharmony_ci				   sizeof(mgmt->u.action.u.addba_req)))
363962306a36Sopenharmony_ci				goto invalid;
364062306a36Sopenharmony_ci			break;
364162306a36Sopenharmony_ci		case WLAN_ACTION_ADDBA_RESP:
364262306a36Sopenharmony_ci			if (len < (IEEE80211_MIN_ACTION_SIZE +
364362306a36Sopenharmony_ci				   sizeof(mgmt->u.action.u.addba_resp)))
364462306a36Sopenharmony_ci				goto invalid;
364562306a36Sopenharmony_ci			break;
364662306a36Sopenharmony_ci		case WLAN_ACTION_DELBA:
364762306a36Sopenharmony_ci			if (len < (IEEE80211_MIN_ACTION_SIZE +
364862306a36Sopenharmony_ci				   sizeof(mgmt->u.action.u.delba)))
364962306a36Sopenharmony_ci				goto invalid;
365062306a36Sopenharmony_ci			break;
365162306a36Sopenharmony_ci		default:
365262306a36Sopenharmony_ci			goto invalid;
365362306a36Sopenharmony_ci		}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci		goto queue;
365662306a36Sopenharmony_ci	case WLAN_CATEGORY_SPECTRUM_MGMT:
365762306a36Sopenharmony_ci		/* verify action_code is present */
365862306a36Sopenharmony_ci		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
365962306a36Sopenharmony_ci			break;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci		switch (mgmt->u.action.u.measurement.action_code) {
366262306a36Sopenharmony_ci		case WLAN_ACTION_SPCT_MSR_REQ:
366362306a36Sopenharmony_ci			if (status->band != NL80211_BAND_5GHZ)
366462306a36Sopenharmony_ci				break;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci			if (len < (IEEE80211_MIN_ACTION_SIZE +
366762306a36Sopenharmony_ci				   sizeof(mgmt->u.action.u.measurement)))
366862306a36Sopenharmony_ci				break;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci			if (sdata->vif.type != NL80211_IFTYPE_STATION)
367162306a36Sopenharmony_ci				break;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci			ieee80211_process_measurement_req(sdata, mgmt, len);
367462306a36Sopenharmony_ci			goto handled;
367562306a36Sopenharmony_ci		case WLAN_ACTION_SPCT_CHL_SWITCH: {
367662306a36Sopenharmony_ci			u8 *bssid;
367762306a36Sopenharmony_ci			if (len < (IEEE80211_MIN_ACTION_SIZE +
367862306a36Sopenharmony_ci				   sizeof(mgmt->u.action.u.chan_switch)))
367962306a36Sopenharmony_ci				break;
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci			if (sdata->vif.type != NL80211_IFTYPE_STATION &&
368262306a36Sopenharmony_ci			    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
368362306a36Sopenharmony_ci			    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
368462306a36Sopenharmony_ci				break;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci			if (sdata->vif.type == NL80211_IFTYPE_STATION)
368762306a36Sopenharmony_ci				bssid = sdata->deflink.u.mgd.bssid;
368862306a36Sopenharmony_ci			else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
368962306a36Sopenharmony_ci				bssid = sdata->u.ibss.bssid;
369062306a36Sopenharmony_ci			else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
369162306a36Sopenharmony_ci				bssid = mgmt->sa;
369262306a36Sopenharmony_ci			else
369362306a36Sopenharmony_ci				break;
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci			if (!ether_addr_equal(mgmt->bssid, bssid))
369662306a36Sopenharmony_ci				break;
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci			goto queue;
369962306a36Sopenharmony_ci			}
370062306a36Sopenharmony_ci		}
370162306a36Sopenharmony_ci		break;
370262306a36Sopenharmony_ci	case WLAN_CATEGORY_SELF_PROTECTED:
370362306a36Sopenharmony_ci		if (len < (IEEE80211_MIN_ACTION_SIZE +
370462306a36Sopenharmony_ci			   sizeof(mgmt->u.action.u.self_prot.action_code)))
370562306a36Sopenharmony_ci			break;
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci		switch (mgmt->u.action.u.self_prot.action_code) {
370862306a36Sopenharmony_ci		case WLAN_SP_MESH_PEERING_OPEN:
370962306a36Sopenharmony_ci		case WLAN_SP_MESH_PEERING_CLOSE:
371062306a36Sopenharmony_ci		case WLAN_SP_MESH_PEERING_CONFIRM:
371162306a36Sopenharmony_ci			if (!ieee80211_vif_is_mesh(&sdata->vif))
371262306a36Sopenharmony_ci				goto invalid;
371362306a36Sopenharmony_ci			if (sdata->u.mesh.user_mpm)
371462306a36Sopenharmony_ci				/* userspace handles this frame */
371562306a36Sopenharmony_ci				break;
371662306a36Sopenharmony_ci			goto queue;
371762306a36Sopenharmony_ci		case WLAN_SP_MGK_INFORM:
371862306a36Sopenharmony_ci		case WLAN_SP_MGK_ACK:
371962306a36Sopenharmony_ci			if (!ieee80211_vif_is_mesh(&sdata->vif))
372062306a36Sopenharmony_ci				goto invalid;
372162306a36Sopenharmony_ci			break;
372262306a36Sopenharmony_ci		}
372362306a36Sopenharmony_ci		break;
372462306a36Sopenharmony_ci	case WLAN_CATEGORY_MESH_ACTION:
372562306a36Sopenharmony_ci		if (len < (IEEE80211_MIN_ACTION_SIZE +
372662306a36Sopenharmony_ci			   sizeof(mgmt->u.action.u.mesh_action.action_code)))
372762306a36Sopenharmony_ci			break;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci		if (!ieee80211_vif_is_mesh(&sdata->vif))
373062306a36Sopenharmony_ci			break;
373162306a36Sopenharmony_ci		if (mesh_action_is_path_sel(mgmt) &&
373262306a36Sopenharmony_ci		    !mesh_path_sel_is_hwmp(sdata))
373362306a36Sopenharmony_ci			break;
373462306a36Sopenharmony_ci		goto queue;
373562306a36Sopenharmony_ci	case WLAN_CATEGORY_S1G:
373662306a36Sopenharmony_ci		if (len < offsetofend(typeof(*mgmt),
373762306a36Sopenharmony_ci				      u.action.u.s1g.action_code))
373862306a36Sopenharmony_ci			break;
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci		switch (mgmt->u.action.u.s1g.action_code) {
374162306a36Sopenharmony_ci		case WLAN_S1G_TWT_SETUP:
374262306a36Sopenharmony_ci		case WLAN_S1G_TWT_TEARDOWN:
374362306a36Sopenharmony_ci			if (ieee80211_process_rx_twt_action(rx))
374462306a36Sopenharmony_ci				goto queue;
374562306a36Sopenharmony_ci			break;
374662306a36Sopenharmony_ci		default:
374762306a36Sopenharmony_ci			break;
374862306a36Sopenharmony_ci		}
374962306a36Sopenharmony_ci		break;
375062306a36Sopenharmony_ci	}
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	return RX_CONTINUE;
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci invalid:
375562306a36Sopenharmony_ci	status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
375662306a36Sopenharmony_ci	/* will return in the next handlers */
375762306a36Sopenharmony_ci	return RX_CONTINUE;
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci handled:
376062306a36Sopenharmony_ci	if (rx->sta)
376162306a36Sopenharmony_ci		rx->link_sta->rx_stats.packets++;
376262306a36Sopenharmony_ci	dev_kfree_skb(rx->skb);
376362306a36Sopenharmony_ci	return RX_QUEUED;
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci queue:
376662306a36Sopenharmony_ci	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
376762306a36Sopenharmony_ci	return RX_QUEUED;
376862306a36Sopenharmony_ci}
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
377162306a36Sopenharmony_ciieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
377262306a36Sopenharmony_ci{
377362306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
377462306a36Sopenharmony_ci	struct cfg80211_rx_info info = {
377562306a36Sopenharmony_ci		.freq = ieee80211_rx_status_to_khz(status),
377662306a36Sopenharmony_ci		.buf = rx->skb->data,
377762306a36Sopenharmony_ci		.len = rx->skb->len,
377862306a36Sopenharmony_ci		.link_id = rx->link_id,
377962306a36Sopenharmony_ci		.have_link_id = rx->link_id >= 0,
378062306a36Sopenharmony_ci	};
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	/* skip known-bad action frames and return them in the next handler */
378362306a36Sopenharmony_ci	if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
378462306a36Sopenharmony_ci		return RX_CONTINUE;
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	/*
378762306a36Sopenharmony_ci	 * Getting here means the kernel doesn't know how to handle
378862306a36Sopenharmony_ci	 * it, but maybe userspace does ... include returned frames
378962306a36Sopenharmony_ci	 * so userspace can register for those to know whether ones
379062306a36Sopenharmony_ci	 * it transmitted were processed or returned.
379162306a36Sopenharmony_ci	 */
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
379462306a36Sopenharmony_ci	    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
379562306a36Sopenharmony_ci		info.sig_dbm = status->signal;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	if (ieee80211_is_timing_measurement(rx->skb) ||
379862306a36Sopenharmony_ci	    ieee80211_is_ftm(rx->skb)) {
379962306a36Sopenharmony_ci		info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp);
380062306a36Sopenharmony_ci		info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp);
380162306a36Sopenharmony_ci	}
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) {
380462306a36Sopenharmony_ci		if (rx->sta)
380562306a36Sopenharmony_ci			rx->link_sta->rx_stats.packets++;
380662306a36Sopenharmony_ci		dev_kfree_skb(rx->skb);
380762306a36Sopenharmony_ci		return RX_QUEUED;
380862306a36Sopenharmony_ci	}
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_ci	return RX_CONTINUE;
381162306a36Sopenharmony_ci}
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
381462306a36Sopenharmony_ciieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx)
381562306a36Sopenharmony_ci{
381662306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
381762306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
381862306a36Sopenharmony_ci	int len = rx->skb->len;
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	if (!ieee80211_is_action(mgmt->frame_control))
382162306a36Sopenharmony_ci		return RX_CONTINUE;
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ci	switch (mgmt->u.action.category) {
382462306a36Sopenharmony_ci	case WLAN_CATEGORY_SA_QUERY:
382562306a36Sopenharmony_ci		if (len < (IEEE80211_MIN_ACTION_SIZE +
382662306a36Sopenharmony_ci			   sizeof(mgmt->u.action.u.sa_query)))
382762306a36Sopenharmony_ci			break;
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci		switch (mgmt->u.action.u.sa_query.action) {
383062306a36Sopenharmony_ci		case WLAN_ACTION_SA_QUERY_REQUEST:
383162306a36Sopenharmony_ci			if (sdata->vif.type != NL80211_IFTYPE_STATION)
383262306a36Sopenharmony_ci				break;
383362306a36Sopenharmony_ci			ieee80211_process_sa_query_req(sdata, mgmt, len);
383462306a36Sopenharmony_ci			goto handled;
383562306a36Sopenharmony_ci		}
383662306a36Sopenharmony_ci		break;
383762306a36Sopenharmony_ci	}
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	return RX_CONTINUE;
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci handled:
384262306a36Sopenharmony_ci	if (rx->sta)
384362306a36Sopenharmony_ci		rx->link_sta->rx_stats.packets++;
384462306a36Sopenharmony_ci	dev_kfree_skb(rx->skb);
384562306a36Sopenharmony_ci	return RX_QUEUED;
384662306a36Sopenharmony_ci}
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
384962306a36Sopenharmony_ciieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
385062306a36Sopenharmony_ci{
385162306a36Sopenharmony_ci	struct ieee80211_local *local = rx->local;
385262306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
385362306a36Sopenharmony_ci	struct sk_buff *nskb;
385462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
385562306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci	if (!ieee80211_is_action(mgmt->frame_control))
385862306a36Sopenharmony_ci		return RX_CONTINUE;
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	/*
386162306a36Sopenharmony_ci	 * For AP mode, hostapd is responsible for handling any action
386262306a36Sopenharmony_ci	 * frames that we didn't handle, including returning unknown
386362306a36Sopenharmony_ci	 * ones. For all other modes we will return them to the sender,
386462306a36Sopenharmony_ci	 * setting the 0x80 bit in the action category, as required by
386562306a36Sopenharmony_ci	 * 802.11-2012 9.24.4.
386662306a36Sopenharmony_ci	 * Newer versions of hostapd shall also use the management frame
386762306a36Sopenharmony_ci	 * registration mechanisms, but older ones still use cooked
386862306a36Sopenharmony_ci	 * monitor interfaces so push all frames there.
386962306a36Sopenharmony_ci	 */
387062306a36Sopenharmony_ci	if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
387162306a36Sopenharmony_ci	    (sdata->vif.type == NL80211_IFTYPE_AP ||
387262306a36Sopenharmony_ci	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
387362306a36Sopenharmony_ci		return RX_DROP_MONITOR;
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci	if (is_multicast_ether_addr(mgmt->da))
387662306a36Sopenharmony_ci		return RX_DROP_MONITOR;
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	/* do not return rejected action frames */
387962306a36Sopenharmony_ci	if (mgmt->u.action.category & 0x80)
388062306a36Sopenharmony_ci		return RX_DROP_UNUSABLE;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci	nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
388362306a36Sopenharmony_ci			       GFP_ATOMIC);
388462306a36Sopenharmony_ci	if (nskb) {
388562306a36Sopenharmony_ci		struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci		nmgmt->u.action.category |= 0x80;
388862306a36Sopenharmony_ci		memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
388962306a36Sopenharmony_ci		memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci		memset(nskb->cb, 0, sizeof(nskb->cb));
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci		if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
389462306a36Sopenharmony_ci			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci			info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
389762306a36Sopenharmony_ci				      IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
389862306a36Sopenharmony_ci				      IEEE80211_TX_CTL_NO_CCK_RATE;
389962306a36Sopenharmony_ci			if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
390062306a36Sopenharmony_ci				info->hw_queue =
390162306a36Sopenharmony_ci					local->hw.offchannel_tx_hw_queue;
390262306a36Sopenharmony_ci		}
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_ci		__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1,
390562306a36Sopenharmony_ci					    status->band);
390662306a36Sopenharmony_ci	}
390762306a36Sopenharmony_ci	dev_kfree_skb(rx->skb);
390862306a36Sopenharmony_ci	return RX_QUEUED;
390962306a36Sopenharmony_ci}
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
391262306a36Sopenharmony_ciieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
391362306a36Sopenharmony_ci{
391462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
391562306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)rx->skb->data;
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci	if (!ieee80211_is_ext(hdr->frame_control))
391862306a36Sopenharmony_ci		return RX_CONTINUE;
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_STATION)
392162306a36Sopenharmony_ci		return RX_DROP_MONITOR;
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci	/* for now only beacons are ext, so queue them */
392462306a36Sopenharmony_ci	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	return RX_QUEUED;
392762306a36Sopenharmony_ci}
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_cistatic ieee80211_rx_result debug_noinline
393062306a36Sopenharmony_ciieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
393162306a36Sopenharmony_ci{
393262306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
393362306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
393462306a36Sopenharmony_ci	__le16 stype;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
393962306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
394062306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_OCB &&
394162306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_STATION)
394262306a36Sopenharmony_ci		return RX_DROP_MONITOR;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	switch (stype) {
394562306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_AUTH):
394662306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_BEACON):
394762306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
394862306a36Sopenharmony_ci		/* process for all: mesh, mlme, ibss */
394962306a36Sopenharmony_ci		break;
395062306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
395162306a36Sopenharmony_ci		if (is_multicast_ether_addr(mgmt->da) &&
395262306a36Sopenharmony_ci		    !is_broadcast_ether_addr(mgmt->da))
395362306a36Sopenharmony_ci			return RX_DROP_MONITOR;
395462306a36Sopenharmony_ci
395562306a36Sopenharmony_ci		/* process only for station/IBSS */
395662306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
395762306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
395862306a36Sopenharmony_ci			return RX_DROP_MONITOR;
395962306a36Sopenharmony_ci		break;
396062306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
396162306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
396262306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
396362306a36Sopenharmony_ci		if (is_multicast_ether_addr(mgmt->da) &&
396462306a36Sopenharmony_ci		    !is_broadcast_ether_addr(mgmt->da))
396562306a36Sopenharmony_ci			return RX_DROP_MONITOR;
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci		/* process only for station */
396862306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_STATION)
396962306a36Sopenharmony_ci			return RX_DROP_MONITOR;
397062306a36Sopenharmony_ci		break;
397162306a36Sopenharmony_ci	case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
397262306a36Sopenharmony_ci		/* process only for ibss and mesh */
397362306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
397462306a36Sopenharmony_ci		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
397562306a36Sopenharmony_ci			return RX_DROP_MONITOR;
397662306a36Sopenharmony_ci		break;
397762306a36Sopenharmony_ci	default:
397862306a36Sopenharmony_ci		return RX_DROP_MONITOR;
397962306a36Sopenharmony_ci	}
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	return RX_QUEUED;
398462306a36Sopenharmony_ci}
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_cistatic void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
398762306a36Sopenharmony_ci					struct ieee80211_rate *rate,
398862306a36Sopenharmony_ci					ieee80211_rx_result reason)
398962306a36Sopenharmony_ci{
399062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
399162306a36Sopenharmony_ci	struct ieee80211_local *local = rx->local;
399262306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb, *skb2;
399362306a36Sopenharmony_ci	struct net_device *prev_dev = NULL;
399462306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
399562306a36Sopenharmony_ci	int needed_headroom;
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	/*
399862306a36Sopenharmony_ci	 * If cooked monitor has been processed already, then
399962306a36Sopenharmony_ci	 * don't do it again. If not, set the flag.
400062306a36Sopenharmony_ci	 */
400162306a36Sopenharmony_ci	if (rx->flags & IEEE80211_RX_CMNTR)
400262306a36Sopenharmony_ci		goto out_free_skb;
400362306a36Sopenharmony_ci	rx->flags |= IEEE80211_RX_CMNTR;
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	/* If there are no cooked monitor interfaces, just free the SKB */
400662306a36Sopenharmony_ci	if (!local->cooked_mntrs)
400762306a36Sopenharmony_ci		goto out_free_skb;
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_ci	/* room for the radiotap header based on driver features */
401062306a36Sopenharmony_ci	needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci	if (skb_headroom(skb) < needed_headroom &&
401362306a36Sopenharmony_ci	    pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
401462306a36Sopenharmony_ci		goto out_free_skb;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	/* prepend radiotap information */
401762306a36Sopenharmony_ci	ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
401862306a36Sopenharmony_ci					 false);
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci	skb_reset_mac_header(skb);
402162306a36Sopenharmony_ci	skb->ip_summed = CHECKSUM_UNNECESSARY;
402262306a36Sopenharmony_ci	skb->pkt_type = PACKET_OTHERHOST;
402362306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_802_2);
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
402662306a36Sopenharmony_ci		if (!ieee80211_sdata_running(sdata))
402762306a36Sopenharmony_ci			continue;
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
403062306a36Sopenharmony_ci		    !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))
403162306a36Sopenharmony_ci			continue;
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci		if (prev_dev) {
403462306a36Sopenharmony_ci			skb2 = skb_clone(skb, GFP_ATOMIC);
403562306a36Sopenharmony_ci			if (skb2) {
403662306a36Sopenharmony_ci				skb2->dev = prev_dev;
403762306a36Sopenharmony_ci				netif_receive_skb(skb2);
403862306a36Sopenharmony_ci			}
403962306a36Sopenharmony_ci		}
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci		prev_dev = sdata->dev;
404262306a36Sopenharmony_ci		dev_sw_netstats_rx_add(sdata->dev, skb->len);
404362306a36Sopenharmony_ci	}
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci	if (prev_dev) {
404662306a36Sopenharmony_ci		skb->dev = prev_dev;
404762306a36Sopenharmony_ci		netif_receive_skb(skb);
404862306a36Sopenharmony_ci		return;
404962306a36Sopenharmony_ci	}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci out_free_skb:
405262306a36Sopenharmony_ci	kfree_skb_reason(skb, (__force u32)reason);
405362306a36Sopenharmony_ci}
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_cistatic void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
405662306a36Sopenharmony_ci					 ieee80211_rx_result res)
405762306a36Sopenharmony_ci{
405862306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
405962306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
406062306a36Sopenharmony_ci	struct ieee80211_rate *rate = NULL;
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	if (res == RX_QUEUED) {
406362306a36Sopenharmony_ci		I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
406462306a36Sopenharmony_ci		return;
406562306a36Sopenharmony_ci	}
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	if (res != RX_CONTINUE) {
406862306a36Sopenharmony_ci		I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
406962306a36Sopenharmony_ci		if (rx->sta)
407062306a36Sopenharmony_ci			rx->link_sta->rx_stats.dropped++;
407162306a36Sopenharmony_ci	}
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci	if (u32_get_bits((__force u32)res, SKB_DROP_REASON_SUBSYS_MASK) ==
407462306a36Sopenharmony_ci			SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE) {
407562306a36Sopenharmony_ci		kfree_skb_reason(rx->skb, (__force u32)res);
407662306a36Sopenharmony_ci		return;
407762306a36Sopenharmony_ci	}
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	sband = rx->local->hw.wiphy->bands[status->band];
408062306a36Sopenharmony_ci	if (status->encoding == RX_ENC_LEGACY)
408162306a36Sopenharmony_ci		rate = &sband->bitrates[status->rate_idx];
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	ieee80211_rx_cooked_monitor(rx, rate, res);
408462306a36Sopenharmony_ci}
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_cistatic void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
408762306a36Sopenharmony_ci				  struct sk_buff_head *frames)
408862306a36Sopenharmony_ci{
408962306a36Sopenharmony_ci	ieee80211_rx_result res = RX_DROP_MONITOR;
409062306a36Sopenharmony_ci	struct sk_buff *skb;
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci#define CALL_RXH(rxh)			\
409362306a36Sopenharmony_ci	do {				\
409462306a36Sopenharmony_ci		res = rxh(rx);		\
409562306a36Sopenharmony_ci		if (res != RX_CONTINUE)	\
409662306a36Sopenharmony_ci			goto rxh_next;  \
409762306a36Sopenharmony_ci	} while (0)
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	/* Lock here to avoid hitting all of the data used in the RX
410062306a36Sopenharmony_ci	 * path (e.g. key data, station data, ...) concurrently when
410162306a36Sopenharmony_ci	 * a frame is released from the reorder buffer due to timeout
410262306a36Sopenharmony_ci	 * from the timer, potentially concurrently with RX from the
410362306a36Sopenharmony_ci	 * driver.
410462306a36Sopenharmony_ci	 */
410562306a36Sopenharmony_ci	spin_lock_bh(&rx->local->rx_path_lock);
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci	while ((skb = __skb_dequeue(frames))) {
410862306a36Sopenharmony_ci		/*
410962306a36Sopenharmony_ci		 * all the other fields are valid across frames
411062306a36Sopenharmony_ci		 * that belong to an aMPDU since they are on the
411162306a36Sopenharmony_ci		 * same TID from the same station
411262306a36Sopenharmony_ci		 */
411362306a36Sopenharmony_ci		rx->skb = skb;
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci		if (WARN_ON_ONCE(!rx->link))
411662306a36Sopenharmony_ci			goto rxh_next;
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_check_more_data);
411962306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll);
412062306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_sta_process);
412162306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_decrypt);
412262306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_defragment);
412362306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_michael_mic_verify);
412462306a36Sopenharmony_ci		/* must be after MMIC verify so header is counted in MPDU mic */
412562306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_amsdu);
412662306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_data);
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci		/* special treatment -- needs the queue */
412962306a36Sopenharmony_ci		res = ieee80211_rx_h_ctrl(rx, frames);
413062306a36Sopenharmony_ci		if (res != RX_CONTINUE)
413162306a36Sopenharmony_ci			goto rxh_next;
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_mgmt_check);
413462306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_action);
413562306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_userspace_mgmt);
413662306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_action_post_userspace);
413762306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_action_return);
413862306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_ext);
413962306a36Sopenharmony_ci		CALL_RXH(ieee80211_rx_h_mgmt);
414062306a36Sopenharmony_ci
414162306a36Sopenharmony_ci rxh_next:
414262306a36Sopenharmony_ci		ieee80211_rx_handlers_result(rx, res);
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci#undef CALL_RXH
414562306a36Sopenharmony_ci	}
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci	spin_unlock_bh(&rx->local->rx_path_lock);
414862306a36Sopenharmony_ci}
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_cistatic void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
415162306a36Sopenharmony_ci{
415262306a36Sopenharmony_ci	struct sk_buff_head reorder_release;
415362306a36Sopenharmony_ci	ieee80211_rx_result res = RX_DROP_MONITOR;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	__skb_queue_head_init(&reorder_release);
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci#define CALL_RXH(rxh)			\
415862306a36Sopenharmony_ci	do {				\
415962306a36Sopenharmony_ci		res = rxh(rx);		\
416062306a36Sopenharmony_ci		if (res != RX_CONTINUE)	\
416162306a36Sopenharmony_ci			goto rxh_next;  \
416262306a36Sopenharmony_ci	} while (0)
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci	CALL_RXH(ieee80211_rx_h_check_dup);
416562306a36Sopenharmony_ci	CALL_RXH(ieee80211_rx_h_check);
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci	ieee80211_rx_reorder_ampdu(rx, &reorder_release);
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	ieee80211_rx_handlers(rx, &reorder_release);
417062306a36Sopenharmony_ci	return;
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci rxh_next:
417362306a36Sopenharmony_ci	ieee80211_rx_handlers_result(rx, res);
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci#undef CALL_RXH
417662306a36Sopenharmony_ci}
417762306a36Sopenharmony_ci
417862306a36Sopenharmony_cistatic bool
417962306a36Sopenharmony_ciieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
418062306a36Sopenharmony_ci{
418162306a36Sopenharmony_ci	return !!(sta->valid_links & BIT(link_id));
418262306a36Sopenharmony_ci}
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_cistatic bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
418562306a36Sopenharmony_ci				       u8 link_id)
418662306a36Sopenharmony_ci{
418762306a36Sopenharmony_ci	rx->link_id = link_id;
418862306a36Sopenharmony_ci	rx->link = rcu_dereference(rx->sdata->link[link_id]);
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	if (!rx->sta)
419162306a36Sopenharmony_ci		return rx->link;
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
419462306a36Sopenharmony_ci		return false;
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci	rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	return rx->link && rx->link_sta;
419962306a36Sopenharmony_ci}
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_cistatic bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
420262306a36Sopenharmony_ci				      struct sta_info *sta, int link_id)
420362306a36Sopenharmony_ci{
420462306a36Sopenharmony_ci	rx->link_id = link_id;
420562306a36Sopenharmony_ci	rx->sta = sta;
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_ci	if (sta) {
420862306a36Sopenharmony_ci		rx->local = sta->sdata->local;
420962306a36Sopenharmony_ci		if (!rx->sdata)
421062306a36Sopenharmony_ci			rx->sdata = sta->sdata;
421162306a36Sopenharmony_ci		rx->link_sta = &sta->deflink;
421262306a36Sopenharmony_ci	} else {
421362306a36Sopenharmony_ci		rx->link_sta = NULL;
421462306a36Sopenharmony_ci	}
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci	if (link_id < 0)
421762306a36Sopenharmony_ci		rx->link = &rx->sdata->deflink;
421862306a36Sopenharmony_ci	else if (!ieee80211_rx_data_set_link(rx, link_id))
421962306a36Sopenharmony_ci		return false;
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	return true;
422262306a36Sopenharmony_ci}
422362306a36Sopenharmony_ci
422462306a36Sopenharmony_ci/*
422562306a36Sopenharmony_ci * This function makes calls into the RX path, therefore
422662306a36Sopenharmony_ci * it has to be invoked under RCU read lock.
422762306a36Sopenharmony_ci */
422862306a36Sopenharmony_civoid ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
422962306a36Sopenharmony_ci{
423062306a36Sopenharmony_ci	struct sk_buff_head frames;
423162306a36Sopenharmony_ci	struct ieee80211_rx_data rx = {
423262306a36Sopenharmony_ci		/* This is OK -- must be QoS data frame */
423362306a36Sopenharmony_ci		.security_idx = tid,
423462306a36Sopenharmony_ci		.seqno_idx = tid,
423562306a36Sopenharmony_ci	};
423662306a36Sopenharmony_ci	struct tid_ampdu_rx *tid_agg_rx;
423762306a36Sopenharmony_ci	int link_id = -1;
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci	/* FIXME: statistics won't be right with this */
424062306a36Sopenharmony_ci	if (sta->sta.valid_links)
424162306a36Sopenharmony_ci		link_id = ffs(sta->sta.valid_links) - 1;
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci	if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
424462306a36Sopenharmony_ci		return;
424562306a36Sopenharmony_ci
424662306a36Sopenharmony_ci	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
424762306a36Sopenharmony_ci	if (!tid_agg_rx)
424862306a36Sopenharmony_ci		return;
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci	__skb_queue_head_init(&frames);
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	spin_lock(&tid_agg_rx->reorder_lock);
425362306a36Sopenharmony_ci	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
425462306a36Sopenharmony_ci	spin_unlock(&tid_agg_rx->reorder_lock);
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	if (!skb_queue_empty(&frames)) {
425762306a36Sopenharmony_ci		struct ieee80211_event event = {
425862306a36Sopenharmony_ci			.type = BA_FRAME_TIMEOUT,
425962306a36Sopenharmony_ci			.u.ba.tid = tid,
426062306a36Sopenharmony_ci			.u.ba.sta = &sta->sta,
426162306a36Sopenharmony_ci		};
426262306a36Sopenharmony_ci		drv_event_callback(rx.local, rx.sdata, &event);
426362306a36Sopenharmony_ci	}
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	ieee80211_rx_handlers(&rx, &frames);
426662306a36Sopenharmony_ci}
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_civoid ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
426962306a36Sopenharmony_ci					  u16 ssn, u64 filtered,
427062306a36Sopenharmony_ci					  u16 received_mpdus)
427162306a36Sopenharmony_ci{
427262306a36Sopenharmony_ci	struct ieee80211_local *local;
427362306a36Sopenharmony_ci	struct sta_info *sta;
427462306a36Sopenharmony_ci	struct tid_ampdu_rx *tid_agg_rx;
427562306a36Sopenharmony_ci	struct sk_buff_head frames;
427662306a36Sopenharmony_ci	struct ieee80211_rx_data rx = {
427762306a36Sopenharmony_ci		/* This is OK -- must be QoS data frame */
427862306a36Sopenharmony_ci		.security_idx = tid,
427962306a36Sopenharmony_ci		.seqno_idx = tid,
428062306a36Sopenharmony_ci	};
428162306a36Sopenharmony_ci	int i, diff;
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
428462306a36Sopenharmony_ci		return;
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	__skb_queue_head_init(&frames);
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	sta = container_of(pubsta, struct sta_info, sta);
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	local = sta->sdata->local;
429162306a36Sopenharmony_ci	WARN_ONCE(local->hw.max_rx_aggregation_subframes > 64,
429262306a36Sopenharmony_ci		  "RX BA marker can't support max_rx_aggregation_subframes %u > 64\n",
429362306a36Sopenharmony_ci		  local->hw.max_rx_aggregation_subframes);
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	if (!ieee80211_rx_data_set_sta(&rx, sta, -1))
429662306a36Sopenharmony_ci		return;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci	rcu_read_lock();
429962306a36Sopenharmony_ci	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
430062306a36Sopenharmony_ci	if (!tid_agg_rx)
430162306a36Sopenharmony_ci		goto out;
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	spin_lock_bh(&tid_agg_rx->reorder_lock);
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
430662306a36Sopenharmony_ci		int release;
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci		/* release all frames in the reorder buffer */
430962306a36Sopenharmony_ci		release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
431062306a36Sopenharmony_ci			   IEEE80211_SN_MODULO;
431162306a36Sopenharmony_ci		ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
431262306a36Sopenharmony_ci						 release, &frames);
431362306a36Sopenharmony_ci		/* update ssn to match received ssn */
431462306a36Sopenharmony_ci		tid_agg_rx->head_seq_num = ssn;
431562306a36Sopenharmony_ci	} else {
431662306a36Sopenharmony_ci		ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
431762306a36Sopenharmony_ci						 &frames);
431862306a36Sopenharmony_ci	}
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	/* handle the case that received ssn is behind the mac ssn.
432162306a36Sopenharmony_ci	 * it can be tid_agg_rx->buf_size behind and still be valid */
432262306a36Sopenharmony_ci	diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
432362306a36Sopenharmony_ci	if (diff >= tid_agg_rx->buf_size) {
432462306a36Sopenharmony_ci		tid_agg_rx->reorder_buf_filtered = 0;
432562306a36Sopenharmony_ci		goto release;
432662306a36Sopenharmony_ci	}
432762306a36Sopenharmony_ci	filtered = filtered >> diff;
432862306a36Sopenharmony_ci	ssn += diff;
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	/* update bitmap */
433162306a36Sopenharmony_ci	for (i = 0; i < tid_agg_rx->buf_size; i++) {
433262306a36Sopenharmony_ci		int index = (ssn + i) % tid_agg_rx->buf_size;
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci		tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
433562306a36Sopenharmony_ci		if (filtered & BIT_ULL(i))
433662306a36Sopenharmony_ci			tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
433762306a36Sopenharmony_ci	}
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	/* now process also frames that the filter marking released */
434062306a36Sopenharmony_ci	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
434162306a36Sopenharmony_ci
434262306a36Sopenharmony_cirelease:
434362306a36Sopenharmony_ci	spin_unlock_bh(&tid_agg_rx->reorder_lock);
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci	ieee80211_rx_handlers(&rx, &frames);
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci out:
434862306a36Sopenharmony_ci	rcu_read_unlock();
434962306a36Sopenharmony_ci}
435062306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci/* main receive path */
435362306a36Sopenharmony_ci
435462306a36Sopenharmony_cistatic inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
435562306a36Sopenharmony_ci{
435662306a36Sopenharmony_ci	return ether_addr_equal(raddr, addr) ||
435762306a36Sopenharmony_ci	       is_broadcast_ether_addr(raddr);
435862306a36Sopenharmony_ci}
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_cistatic bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
436162306a36Sopenharmony_ci{
436262306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
436362306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
436462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
436562306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
436662306a36Sopenharmony_ci	u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
436762306a36Sopenharmony_ci	bool multicast = is_multicast_ether_addr(hdr->addr1) ||
436862306a36Sopenharmony_ci			 ieee80211_is_s1g_beacon(hdr->frame_control);
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	switch (sdata->vif.type) {
437162306a36Sopenharmony_ci	case NL80211_IFTYPE_STATION:
437262306a36Sopenharmony_ci		if (!bssid && !sdata->u.mgd.use_4addr)
437362306a36Sopenharmony_ci			return false;
437462306a36Sopenharmony_ci		if (ieee80211_is_first_frag(hdr->seq_ctrl) &&
437562306a36Sopenharmony_ci		    ieee80211_is_robust_mgmt_frame(skb) && !rx->sta)
437662306a36Sopenharmony_ci			return false;
437762306a36Sopenharmony_ci		if (multicast)
437862306a36Sopenharmony_ci			return true;
437962306a36Sopenharmony_ci		return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id);
438062306a36Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
438162306a36Sopenharmony_ci		if (!bssid)
438262306a36Sopenharmony_ci			return false;
438362306a36Sopenharmony_ci		if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
438462306a36Sopenharmony_ci		    ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2) ||
438562306a36Sopenharmony_ci		    !is_valid_ether_addr(hdr->addr2))
438662306a36Sopenharmony_ci			return false;
438762306a36Sopenharmony_ci		if (ieee80211_is_beacon(hdr->frame_control))
438862306a36Sopenharmony_ci			return true;
438962306a36Sopenharmony_ci		if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
439062306a36Sopenharmony_ci			return false;
439162306a36Sopenharmony_ci		if (!multicast &&
439262306a36Sopenharmony_ci		    !ether_addr_equal(sdata->vif.addr, hdr->addr1))
439362306a36Sopenharmony_ci			return false;
439462306a36Sopenharmony_ci		if (!rx->sta) {
439562306a36Sopenharmony_ci			int rate_idx;
439662306a36Sopenharmony_ci			if (status->encoding != RX_ENC_LEGACY)
439762306a36Sopenharmony_ci				rate_idx = 0; /* TODO: HT/VHT rates */
439862306a36Sopenharmony_ci			else
439962306a36Sopenharmony_ci				rate_idx = status->rate_idx;
440062306a36Sopenharmony_ci			ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
440162306a36Sopenharmony_ci						 BIT(rate_idx));
440262306a36Sopenharmony_ci		}
440362306a36Sopenharmony_ci		return true;
440462306a36Sopenharmony_ci	case NL80211_IFTYPE_OCB:
440562306a36Sopenharmony_ci		if (!bssid)
440662306a36Sopenharmony_ci			return false;
440762306a36Sopenharmony_ci		if (!ieee80211_is_data_present(hdr->frame_control))
440862306a36Sopenharmony_ci			return false;
440962306a36Sopenharmony_ci		if (!is_broadcast_ether_addr(bssid))
441062306a36Sopenharmony_ci			return false;
441162306a36Sopenharmony_ci		if (!multicast &&
441262306a36Sopenharmony_ci		    !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
441362306a36Sopenharmony_ci			return false;
441462306a36Sopenharmony_ci		if (!rx->sta) {
441562306a36Sopenharmony_ci			int rate_idx;
441662306a36Sopenharmony_ci			if (status->encoding != RX_ENC_LEGACY)
441762306a36Sopenharmony_ci				rate_idx = 0; /* TODO: HT rates */
441862306a36Sopenharmony_ci			else
441962306a36Sopenharmony_ci				rate_idx = status->rate_idx;
442062306a36Sopenharmony_ci			ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
442162306a36Sopenharmony_ci						BIT(rate_idx));
442262306a36Sopenharmony_ci		}
442362306a36Sopenharmony_ci		return true;
442462306a36Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
442562306a36Sopenharmony_ci		if (ether_addr_equal(sdata->vif.addr, hdr->addr2))
442662306a36Sopenharmony_ci			return false;
442762306a36Sopenharmony_ci		if (multicast)
442862306a36Sopenharmony_ci			return true;
442962306a36Sopenharmony_ci		return ether_addr_equal(sdata->vif.addr, hdr->addr1);
443062306a36Sopenharmony_ci	case NL80211_IFTYPE_AP_VLAN:
443162306a36Sopenharmony_ci	case NL80211_IFTYPE_AP:
443262306a36Sopenharmony_ci		if (!bssid)
443362306a36Sopenharmony_ci			return ieee80211_is_our_addr(sdata, hdr->addr1,
443462306a36Sopenharmony_ci						     &rx->link_id);
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci		if (!is_broadcast_ether_addr(bssid) &&
443762306a36Sopenharmony_ci		    !ieee80211_is_our_addr(sdata, bssid, NULL)) {
443862306a36Sopenharmony_ci			/*
443962306a36Sopenharmony_ci			 * Accept public action frames even when the
444062306a36Sopenharmony_ci			 * BSSID doesn't match, this is used for P2P
444162306a36Sopenharmony_ci			 * and location updates. Note that mac80211
444262306a36Sopenharmony_ci			 * itself never looks at these frames.
444362306a36Sopenharmony_ci			 */
444462306a36Sopenharmony_ci			if (!multicast &&
444562306a36Sopenharmony_ci			    !ieee80211_is_our_addr(sdata, hdr->addr1,
444662306a36Sopenharmony_ci						   &rx->link_id))
444762306a36Sopenharmony_ci				return false;
444862306a36Sopenharmony_ci			if (ieee80211_is_public_action(hdr, skb->len))
444962306a36Sopenharmony_ci				return true;
445062306a36Sopenharmony_ci			return ieee80211_is_beacon(hdr->frame_control);
445162306a36Sopenharmony_ci		}
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci		if (!ieee80211_has_tods(hdr->frame_control)) {
445462306a36Sopenharmony_ci			/* ignore data frames to TDLS-peers */
445562306a36Sopenharmony_ci			if (ieee80211_is_data(hdr->frame_control))
445662306a36Sopenharmony_ci				return false;
445762306a36Sopenharmony_ci			/* ignore action frames to TDLS-peers */
445862306a36Sopenharmony_ci			if (ieee80211_is_action(hdr->frame_control) &&
445962306a36Sopenharmony_ci			    !is_broadcast_ether_addr(bssid) &&
446062306a36Sopenharmony_ci			    !ether_addr_equal(bssid, hdr->addr1))
446162306a36Sopenharmony_ci				return false;
446262306a36Sopenharmony_ci		}
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci		/*
446562306a36Sopenharmony_ci		 * 802.11-2016 Table 9-26 says that for data frames, A1 must be
446662306a36Sopenharmony_ci		 * the BSSID - we've checked that already but may have accepted
446762306a36Sopenharmony_ci		 * the wildcard (ff:ff:ff:ff:ff:ff).
446862306a36Sopenharmony_ci		 *
446962306a36Sopenharmony_ci		 * It also says:
447062306a36Sopenharmony_ci		 *	The BSSID of the Data frame is determined as follows:
447162306a36Sopenharmony_ci		 *	a) If the STA is contained within an AP or is associated
447262306a36Sopenharmony_ci		 *	   with an AP, the BSSID is the address currently in use
447362306a36Sopenharmony_ci		 *	   by the STA contained in the AP.
447462306a36Sopenharmony_ci		 *
447562306a36Sopenharmony_ci		 * So we should not accept data frames with an address that's
447662306a36Sopenharmony_ci		 * multicast.
447762306a36Sopenharmony_ci		 *
447862306a36Sopenharmony_ci		 * Accepting it also opens a security problem because stations
447962306a36Sopenharmony_ci		 * could encrypt it with the GTK and inject traffic that way.
448062306a36Sopenharmony_ci		 */
448162306a36Sopenharmony_ci		if (ieee80211_is_data(hdr->frame_control) && multicast)
448262306a36Sopenharmony_ci			return false;
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci		return true;
448562306a36Sopenharmony_ci	case NL80211_IFTYPE_P2P_DEVICE:
448662306a36Sopenharmony_ci		return ieee80211_is_public_action(hdr, skb->len) ||
448762306a36Sopenharmony_ci		       ieee80211_is_probe_req(hdr->frame_control) ||
448862306a36Sopenharmony_ci		       ieee80211_is_probe_resp(hdr->frame_control) ||
448962306a36Sopenharmony_ci		       ieee80211_is_beacon(hdr->frame_control);
449062306a36Sopenharmony_ci	case NL80211_IFTYPE_NAN:
449162306a36Sopenharmony_ci		/* Currently no frames on NAN interface are allowed */
449262306a36Sopenharmony_ci		return false;
449362306a36Sopenharmony_ci	default:
449462306a36Sopenharmony_ci		break;
449562306a36Sopenharmony_ci	}
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	WARN_ON_ONCE(1);
449862306a36Sopenharmony_ci	return false;
449962306a36Sopenharmony_ci}
450062306a36Sopenharmony_ci
450162306a36Sopenharmony_civoid ieee80211_check_fast_rx(struct sta_info *sta)
450262306a36Sopenharmony_ci{
450362306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
450462306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
450562306a36Sopenharmony_ci	struct ieee80211_key *key;
450662306a36Sopenharmony_ci	struct ieee80211_fast_rx fastrx = {
450762306a36Sopenharmony_ci		.dev = sdata->dev,
450862306a36Sopenharmony_ci		.vif_type = sdata->vif.type,
450962306a36Sopenharmony_ci		.control_port_protocol = sdata->control_port_protocol,
451062306a36Sopenharmony_ci	}, *old, *new = NULL;
451162306a36Sopenharmony_ci	u32 offload_flags;
451262306a36Sopenharmony_ci	bool set_offload = false;
451362306a36Sopenharmony_ci	bool assign = false;
451462306a36Sopenharmony_ci	bool offload;
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci	/* use sparse to check that we don't return without updating */
451762306a36Sopenharmony_ci	__acquire(check_fast_rx);
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header));
452062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN);
452162306a36Sopenharmony_ci	ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
452262306a36Sopenharmony_ci	ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_ci	fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS);
452562306a36Sopenharmony_ci
452662306a36Sopenharmony_ci	/* fast-rx doesn't do reordering */
452762306a36Sopenharmony_ci	if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
452862306a36Sopenharmony_ci	    !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
452962306a36Sopenharmony_ci		goto clear;
453062306a36Sopenharmony_ci
453162306a36Sopenharmony_ci	switch (sdata->vif.type) {
453262306a36Sopenharmony_ci	case NL80211_IFTYPE_STATION:
453362306a36Sopenharmony_ci		if (sta->sta.tdls) {
453462306a36Sopenharmony_ci			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
453562306a36Sopenharmony_ci			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
453662306a36Sopenharmony_ci			fastrx.expected_ds_bits = 0;
453762306a36Sopenharmony_ci		} else {
453862306a36Sopenharmony_ci			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
453962306a36Sopenharmony_ci			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
454062306a36Sopenharmony_ci			fastrx.expected_ds_bits =
454162306a36Sopenharmony_ci				cpu_to_le16(IEEE80211_FCTL_FROMDS);
454262306a36Sopenharmony_ci		}
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_ci		if (sdata->u.mgd.use_4addr && !sta->sta.tdls) {
454562306a36Sopenharmony_ci			fastrx.expected_ds_bits |=
454662306a36Sopenharmony_ci				cpu_to_le16(IEEE80211_FCTL_TODS);
454762306a36Sopenharmony_ci			fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
454862306a36Sopenharmony_ci			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
454962306a36Sopenharmony_ci		}
455062306a36Sopenharmony_ci
455162306a36Sopenharmony_ci		if (!sdata->u.mgd.powersave)
455262306a36Sopenharmony_ci			break;
455362306a36Sopenharmony_ci
455462306a36Sopenharmony_ci		/* software powersave is a huge mess, avoid all of it */
455562306a36Sopenharmony_ci		if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
455662306a36Sopenharmony_ci			goto clear;
455762306a36Sopenharmony_ci		if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
455862306a36Sopenharmony_ci		    !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
455962306a36Sopenharmony_ci			goto clear;
456062306a36Sopenharmony_ci		break;
456162306a36Sopenharmony_ci	case NL80211_IFTYPE_AP_VLAN:
456262306a36Sopenharmony_ci	case NL80211_IFTYPE_AP:
456362306a36Sopenharmony_ci		/* parallel-rx requires this, at least with calls to
456462306a36Sopenharmony_ci		 * ieee80211_sta_ps_transition()
456562306a36Sopenharmony_ci		 */
456662306a36Sopenharmony_ci		if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
456762306a36Sopenharmony_ci			goto clear;
456862306a36Sopenharmony_ci		fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
456962306a36Sopenharmony_ci		fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
457062306a36Sopenharmony_ci		fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS);
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci		fastrx.internal_forward =
457362306a36Sopenharmony_ci			!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
457462306a36Sopenharmony_ci			(sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
457562306a36Sopenharmony_ci			 !sdata->u.vlan.sta);
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
457862306a36Sopenharmony_ci		    sdata->u.vlan.sta) {
457962306a36Sopenharmony_ci			fastrx.expected_ds_bits |=
458062306a36Sopenharmony_ci				cpu_to_le16(IEEE80211_FCTL_FROMDS);
458162306a36Sopenharmony_ci			fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
458262306a36Sopenharmony_ci			fastrx.internal_forward = 0;
458362306a36Sopenharmony_ci		}
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci		break;
458662306a36Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
458762306a36Sopenharmony_ci		fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
458862306a36Sopenharmony_ci						      IEEE80211_FCTL_TODS);
458962306a36Sopenharmony_ci		fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
459062306a36Sopenharmony_ci		fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
459162306a36Sopenharmony_ci		break;
459262306a36Sopenharmony_ci	default:
459362306a36Sopenharmony_ci		goto clear;
459462306a36Sopenharmony_ci	}
459562306a36Sopenharmony_ci
459662306a36Sopenharmony_ci	if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
459762306a36Sopenharmony_ci		goto clear;
459862306a36Sopenharmony_ci
459962306a36Sopenharmony_ci	rcu_read_lock();
460062306a36Sopenharmony_ci	key = rcu_dereference(sta->ptk[sta->ptk_idx]);
460162306a36Sopenharmony_ci	if (!key)
460262306a36Sopenharmony_ci		key = rcu_dereference(sdata->default_unicast_key);
460362306a36Sopenharmony_ci	if (key) {
460462306a36Sopenharmony_ci		switch (key->conf.cipher) {
460562306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_TKIP:
460662306a36Sopenharmony_ci			/* we don't want to deal with MMIC in fast-rx */
460762306a36Sopenharmony_ci			goto clear_rcu;
460862306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_CCMP:
460962306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_CCMP_256:
461062306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_GCMP:
461162306a36Sopenharmony_ci		case WLAN_CIPHER_SUITE_GCMP_256:
461262306a36Sopenharmony_ci			break;
461362306a36Sopenharmony_ci		default:
461462306a36Sopenharmony_ci			/* We also don't want to deal with
461562306a36Sopenharmony_ci			 * WEP or cipher scheme.
461662306a36Sopenharmony_ci			 */
461762306a36Sopenharmony_ci			goto clear_rcu;
461862306a36Sopenharmony_ci		}
461962306a36Sopenharmony_ci
462062306a36Sopenharmony_ci		fastrx.key = true;
462162306a36Sopenharmony_ci		fastrx.icv_len = key->conf.icv_len;
462262306a36Sopenharmony_ci	}
462362306a36Sopenharmony_ci
462462306a36Sopenharmony_ci	assign = true;
462562306a36Sopenharmony_ci clear_rcu:
462662306a36Sopenharmony_ci	rcu_read_unlock();
462762306a36Sopenharmony_ci clear:
462862306a36Sopenharmony_ci	__release(check_fast_rx);
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	if (assign)
463162306a36Sopenharmony_ci		new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_ci	offload_flags = get_bss_sdata(sdata)->vif.offload_flags;
463462306a36Sopenharmony_ci	offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED;
463562306a36Sopenharmony_ci
463662306a36Sopenharmony_ci	if (assign && offload)
463762306a36Sopenharmony_ci		set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
463862306a36Sopenharmony_ci	else
463962306a36Sopenharmony_ci		set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	if (set_offload)
464262306a36Sopenharmony_ci		drv_sta_set_decap_offload(local, sdata, &sta->sta, assign);
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
464562306a36Sopenharmony_ci	old = rcu_dereference_protected(sta->fast_rx, true);
464662306a36Sopenharmony_ci	rcu_assign_pointer(sta->fast_rx, new);
464762306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci	if (old)
465062306a36Sopenharmony_ci		kfree_rcu(old, rcu_head);
465162306a36Sopenharmony_ci}
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_civoid ieee80211_clear_fast_rx(struct sta_info *sta)
465462306a36Sopenharmony_ci{
465562306a36Sopenharmony_ci	struct ieee80211_fast_rx *old;
465662306a36Sopenharmony_ci
465762306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
465862306a36Sopenharmony_ci	old = rcu_dereference_protected(sta->fast_rx, true);
465962306a36Sopenharmony_ci	RCU_INIT_POINTER(sta->fast_rx, NULL);
466062306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	if (old)
466362306a36Sopenharmony_ci		kfree_rcu(old, rcu_head);
466462306a36Sopenharmony_ci}
466562306a36Sopenharmony_ci
466662306a36Sopenharmony_civoid __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
466762306a36Sopenharmony_ci{
466862306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
466962306a36Sopenharmony_ci	struct sta_info *sta;
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	lockdep_assert_held(&local->sta_mtx);
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	list_for_each_entry(sta, &local->sta_list, list) {
467462306a36Sopenharmony_ci		if (sdata != sta->sdata &&
467562306a36Sopenharmony_ci		    (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
467662306a36Sopenharmony_ci			continue;
467762306a36Sopenharmony_ci		ieee80211_check_fast_rx(sta);
467862306a36Sopenharmony_ci	}
467962306a36Sopenharmony_ci}
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_civoid ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
468262306a36Sopenharmony_ci{
468362306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci	mutex_lock(&local->sta_mtx);
468662306a36Sopenharmony_ci	__ieee80211_check_fast_rx_iface(sdata);
468762306a36Sopenharmony_ci	mutex_unlock(&local->sta_mtx);
468862306a36Sopenharmony_ci}
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_cistatic void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
469162306a36Sopenharmony_ci			      struct ieee80211_fast_rx *fast_rx,
469262306a36Sopenharmony_ci			      int orig_len)
469362306a36Sopenharmony_ci{
469462306a36Sopenharmony_ci	struct ieee80211_sta_rx_stats *stats;
469562306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
469662306a36Sopenharmony_ci	struct sta_info *sta = rx->sta;
469762306a36Sopenharmony_ci	struct link_sta_info *link_sta;
469862306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
469962306a36Sopenharmony_ci	void *sa = skb->data + ETH_ALEN;
470062306a36Sopenharmony_ci	void *da = skb->data;
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	if (rx->link_id >= 0) {
470362306a36Sopenharmony_ci		link_sta = rcu_dereference(sta->link[rx->link_id]);
470462306a36Sopenharmony_ci		if (WARN_ON_ONCE(!link_sta)) {
470562306a36Sopenharmony_ci			dev_kfree_skb(rx->skb);
470662306a36Sopenharmony_ci			return;
470762306a36Sopenharmony_ci		}
470862306a36Sopenharmony_ci	} else {
470962306a36Sopenharmony_ci		link_sta = &sta->deflink;
471062306a36Sopenharmony_ci	}
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci	stats = &link_sta->rx_stats;
471362306a36Sopenharmony_ci	if (fast_rx->uses_rss)
471462306a36Sopenharmony_ci		stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	/* statistics part of ieee80211_rx_h_sta_process() */
471762306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
471862306a36Sopenharmony_ci		stats->last_signal = status->signal;
471962306a36Sopenharmony_ci		if (!fast_rx->uses_rss)
472062306a36Sopenharmony_ci			ewma_signal_add(&link_sta->rx_stats_avg.signal,
472162306a36Sopenharmony_ci					-status->signal);
472262306a36Sopenharmony_ci	}
472362306a36Sopenharmony_ci
472462306a36Sopenharmony_ci	if (status->chains) {
472562306a36Sopenharmony_ci		int i;
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_ci		stats->chains = status->chains;
472862306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
472962306a36Sopenharmony_ci			int signal = status->chain_signal[i];
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci			if (!(status->chains & BIT(i)))
473262306a36Sopenharmony_ci				continue;
473362306a36Sopenharmony_ci
473462306a36Sopenharmony_ci			stats->chain_signal_last[i] = signal;
473562306a36Sopenharmony_ci			if (!fast_rx->uses_rss)
473662306a36Sopenharmony_ci				ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
473762306a36Sopenharmony_ci						-signal);
473862306a36Sopenharmony_ci		}
473962306a36Sopenharmony_ci	}
474062306a36Sopenharmony_ci	/* end of statistics */
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_ci	stats->last_rx = jiffies;
474362306a36Sopenharmony_ci	stats->last_rate = sta_stats_encode_rate(status);
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	stats->fragments++;
474662306a36Sopenharmony_ci	stats->packets++;
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci	skb->dev = fast_rx->dev;
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	/* The seqno index has the same property as needed
475362306a36Sopenharmony_ci	 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
475462306a36Sopenharmony_ci	 * for non-QoS-data frames. Here we know it's a data
475562306a36Sopenharmony_ci	 * frame, so count MSDUs.
475662306a36Sopenharmony_ci	 */
475762306a36Sopenharmony_ci	u64_stats_update_begin(&stats->syncp);
475862306a36Sopenharmony_ci	stats->msdu[rx->seqno_idx]++;
475962306a36Sopenharmony_ci	stats->bytes += orig_len;
476062306a36Sopenharmony_ci	u64_stats_update_end(&stats->syncp);
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	if (fast_rx->internal_forward) {
476362306a36Sopenharmony_ci		struct sk_buff *xmit_skb = NULL;
476462306a36Sopenharmony_ci		if (is_multicast_ether_addr(da)) {
476562306a36Sopenharmony_ci			xmit_skb = skb_copy(skb, GFP_ATOMIC);
476662306a36Sopenharmony_ci		} else if (!ether_addr_equal(da, sa) &&
476762306a36Sopenharmony_ci			   sta_info_get(rx->sdata, da)) {
476862306a36Sopenharmony_ci			xmit_skb = skb;
476962306a36Sopenharmony_ci			skb = NULL;
477062306a36Sopenharmony_ci		}
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci		if (xmit_skb) {
477362306a36Sopenharmony_ci			/*
477462306a36Sopenharmony_ci			 * Send to wireless media and increase priority by 256
477562306a36Sopenharmony_ci			 * to keep the received priority instead of
477662306a36Sopenharmony_ci			 * reclassifying the frame (see cfg80211_classify8021d).
477762306a36Sopenharmony_ci			 */
477862306a36Sopenharmony_ci			xmit_skb->priority += 256;
477962306a36Sopenharmony_ci			xmit_skb->protocol = htons(ETH_P_802_3);
478062306a36Sopenharmony_ci			skb_reset_network_header(xmit_skb);
478162306a36Sopenharmony_ci			skb_reset_mac_header(xmit_skb);
478262306a36Sopenharmony_ci			dev_queue_xmit(xmit_skb);
478362306a36Sopenharmony_ci		}
478462306a36Sopenharmony_ci
478562306a36Sopenharmony_ci		if (!skb)
478662306a36Sopenharmony_ci			return;
478762306a36Sopenharmony_ci	}
478862306a36Sopenharmony_ci
478962306a36Sopenharmony_ci	/* deliver to local stack */
479062306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, fast_rx->dev);
479162306a36Sopenharmony_ci	ieee80211_deliver_skb_to_local_stack(skb, rx);
479262306a36Sopenharmony_ci}
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_cistatic bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
479562306a36Sopenharmony_ci				     struct ieee80211_fast_rx *fast_rx)
479662306a36Sopenharmony_ci{
479762306a36Sopenharmony_ci	struct sk_buff *skb = rx->skb;
479862306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
479962306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
480062306a36Sopenharmony_ci	static ieee80211_rx_result res;
480162306a36Sopenharmony_ci	int orig_len = skb->len;
480262306a36Sopenharmony_ci	int hdrlen = ieee80211_hdrlen(hdr->frame_control);
480362306a36Sopenharmony_ci	int snap_offs = hdrlen;
480462306a36Sopenharmony_ci	struct {
480562306a36Sopenharmony_ci		u8 snap[sizeof(rfc1042_header)];
480662306a36Sopenharmony_ci		__be16 proto;
480762306a36Sopenharmony_ci	} *payload __aligned(2);
480862306a36Sopenharmony_ci	struct {
480962306a36Sopenharmony_ci		u8 da[ETH_ALEN];
481062306a36Sopenharmony_ci		u8 sa[ETH_ALEN];
481162306a36Sopenharmony_ci	} addrs __aligned(2);
481262306a36Sopenharmony_ci	struct ieee80211_sta_rx_stats *stats;
481362306a36Sopenharmony_ci
481462306a36Sopenharmony_ci	/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
481562306a36Sopenharmony_ci	 * to a common data structure; drivers can implement that per queue
481662306a36Sopenharmony_ci	 * but we don't have that information in mac80211
481762306a36Sopenharmony_ci	 */
481862306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_DUP_VALIDATED))
481962306a36Sopenharmony_ci		return false;
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci#define FAST_RX_CRYPT_FLAGS	(RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED)
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	/* If using encryption, we also need to have:
482462306a36Sopenharmony_ci	 *  - PN_VALIDATED: similar, but the implementation is tricky
482562306a36Sopenharmony_ci	 *  - DECRYPTED: necessary for PN_VALIDATED
482662306a36Sopenharmony_ci	 */
482762306a36Sopenharmony_ci	if (fast_rx->key &&
482862306a36Sopenharmony_ci	    (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS)
482962306a36Sopenharmony_ci		return false;
483062306a36Sopenharmony_ci
483162306a36Sopenharmony_ci	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
483262306a36Sopenharmony_ci		return false;
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_ci	if (unlikely(ieee80211_is_frag(hdr)))
483562306a36Sopenharmony_ci		return false;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	/* Since our interface address cannot be multicast, this
483862306a36Sopenharmony_ci	 * implicitly also rejects multicast frames without the
483962306a36Sopenharmony_ci	 * explicit check.
484062306a36Sopenharmony_ci	 *
484162306a36Sopenharmony_ci	 * We shouldn't get any *data* frames not addressed to us
484262306a36Sopenharmony_ci	 * (AP mode will accept multicast *management* frames), but
484362306a36Sopenharmony_ci	 * punting here will make it go through the full checks in
484462306a36Sopenharmony_ci	 * ieee80211_accept_frame().
484562306a36Sopenharmony_ci	 */
484662306a36Sopenharmony_ci	if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1))
484762306a36Sopenharmony_ci		return false;
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci	if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
485062306a36Sopenharmony_ci					      IEEE80211_FCTL_TODS)) !=
485162306a36Sopenharmony_ci	    fast_rx->expected_ds_bits)
485262306a36Sopenharmony_ci		return false;
485362306a36Sopenharmony_ci
485462306a36Sopenharmony_ci	/* assign the key to drop unencrypted frames (later)
485562306a36Sopenharmony_ci	 * and strip the IV/MIC if necessary
485662306a36Sopenharmony_ci	 */
485762306a36Sopenharmony_ci	if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) {
485862306a36Sopenharmony_ci		/* GCMP header length is the same */
485962306a36Sopenharmony_ci		snap_offs += IEEE80211_CCMP_HDR_LEN;
486062306a36Sopenharmony_ci	}
486162306a36Sopenharmony_ci
486262306a36Sopenharmony_ci	if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
486362306a36Sopenharmony_ci	    !(status->rx_flags & IEEE80211_RX_AMSDU)) {
486462306a36Sopenharmony_ci		if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
486562306a36Sopenharmony_ci			return false;
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci		payload = (void *)(skb->data + snap_offs);
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci		if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr))
487062306a36Sopenharmony_ci			return false;
487162306a36Sopenharmony_ci
487262306a36Sopenharmony_ci		/* Don't handle these here since they require special code.
487362306a36Sopenharmony_ci		 * Accept AARP and IPX even though they should come with a
487462306a36Sopenharmony_ci		 * bridge-tunnel header - but if we get them this way then
487562306a36Sopenharmony_ci		 * there's little point in discarding them.
487662306a36Sopenharmony_ci		 */
487762306a36Sopenharmony_ci		if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) ||
487862306a36Sopenharmony_ci			     payload->proto == fast_rx->control_port_protocol))
487962306a36Sopenharmony_ci			return false;
488062306a36Sopenharmony_ci	}
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci	/* after this point, don't punt to the slowpath! */
488362306a36Sopenharmony_ci
488462306a36Sopenharmony_ci	if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
488562306a36Sopenharmony_ci	    pskb_trim(skb, skb->len - fast_rx->icv_len))
488662306a36Sopenharmony_ci		goto drop;
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci	if (rx->key && !ieee80211_has_protected(hdr->frame_control))
488962306a36Sopenharmony_ci		goto drop;
489062306a36Sopenharmony_ci
489162306a36Sopenharmony_ci	if (status->rx_flags & IEEE80211_RX_AMSDU) {
489262306a36Sopenharmony_ci		if (__ieee80211_rx_h_amsdu(rx, snap_offs - hdrlen) !=
489362306a36Sopenharmony_ci		    RX_QUEUED)
489462306a36Sopenharmony_ci			goto drop;
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci		return true;
489762306a36Sopenharmony_ci	}
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_ci	/* do the header conversion - first grab the addresses */
490062306a36Sopenharmony_ci	ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
490162306a36Sopenharmony_ci	ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
490262306a36Sopenharmony_ci	if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
490362306a36Sopenharmony_ci	    skb_pull(skb, snap_offs - 2);
490462306a36Sopenharmony_ci	    put_unaligned_be16(skb->len - 2, skb->data);
490562306a36Sopenharmony_ci	} else {
490662306a36Sopenharmony_ci	    skb_postpull_rcsum(skb, skb->data + snap_offs,
490762306a36Sopenharmony_ci			       sizeof(rfc1042_header) + 2);
490862306a36Sopenharmony_ci
490962306a36Sopenharmony_ci	    /* remove the SNAP but leave the ethertype */
491062306a36Sopenharmony_ci	    skb_pull(skb, snap_offs + sizeof(rfc1042_header));
491162306a36Sopenharmony_ci	}
491262306a36Sopenharmony_ci	/* push the addresses in front */
491362306a36Sopenharmony_ci	memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
491462306a36Sopenharmony_ci
491562306a36Sopenharmony_ci	res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
491662306a36Sopenharmony_ci	switch (res) {
491762306a36Sopenharmony_ci	case RX_QUEUED:
491862306a36Sopenharmony_ci		return true;
491962306a36Sopenharmony_ci	case RX_CONTINUE:
492062306a36Sopenharmony_ci		break;
492162306a36Sopenharmony_ci	default:
492262306a36Sopenharmony_ci		goto drop;
492362306a36Sopenharmony_ci	}
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci	ieee80211_rx_8023(rx, fast_rx, orig_len);
492662306a36Sopenharmony_ci
492762306a36Sopenharmony_ci	return true;
492862306a36Sopenharmony_ci drop:
492962306a36Sopenharmony_ci	dev_kfree_skb(skb);
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	if (fast_rx->uses_rss)
493262306a36Sopenharmony_ci		stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
493362306a36Sopenharmony_ci	else
493462306a36Sopenharmony_ci		stats = &rx->link_sta->rx_stats;
493562306a36Sopenharmony_ci
493662306a36Sopenharmony_ci	stats->dropped++;
493762306a36Sopenharmony_ci	return true;
493862306a36Sopenharmony_ci}
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci/*
494162306a36Sopenharmony_ci * This function returns whether or not the SKB
494262306a36Sopenharmony_ci * was destined for RX processing or not, which,
494362306a36Sopenharmony_ci * if consume is true, is equivalent to whether
494462306a36Sopenharmony_ci * or not the skb was consumed.
494562306a36Sopenharmony_ci */
494662306a36Sopenharmony_cistatic bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
494762306a36Sopenharmony_ci					    struct sk_buff *skb, bool consume)
494862306a36Sopenharmony_ci{
494962306a36Sopenharmony_ci	struct ieee80211_local *local = rx->local;
495062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = rx->sdata;
495162306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
495262306a36Sopenharmony_ci	struct link_sta_info *link_sta = rx->link_sta;
495362306a36Sopenharmony_ci	struct ieee80211_link_data *link = rx->link;
495462306a36Sopenharmony_ci
495562306a36Sopenharmony_ci	rx->skb = skb;
495662306a36Sopenharmony_ci
495762306a36Sopenharmony_ci	/* See if we can do fast-rx; if we have to copy we already lost,
495862306a36Sopenharmony_ci	 * so punt in that case. We should never have to deliver a data
495962306a36Sopenharmony_ci	 * frame to multiple interfaces anyway.
496062306a36Sopenharmony_ci	 *
496162306a36Sopenharmony_ci	 * We skip the ieee80211_accept_frame() call and do the necessary
496262306a36Sopenharmony_ci	 * checking inside ieee80211_invoke_fast_rx().
496362306a36Sopenharmony_ci	 */
496462306a36Sopenharmony_ci	if (consume && rx->sta) {
496562306a36Sopenharmony_ci		struct ieee80211_fast_rx *fast_rx;
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci		fast_rx = rcu_dereference(rx->sta->fast_rx);
496862306a36Sopenharmony_ci		if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx))
496962306a36Sopenharmony_ci			return true;
497062306a36Sopenharmony_ci	}
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	if (!ieee80211_accept_frame(rx))
497362306a36Sopenharmony_ci		return false;
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	if (!consume) {
497662306a36Sopenharmony_ci		struct skb_shared_hwtstamps *shwt;
497762306a36Sopenharmony_ci
497862306a36Sopenharmony_ci		rx->skb = skb_copy(skb, GFP_ATOMIC);
497962306a36Sopenharmony_ci		if (!rx->skb) {
498062306a36Sopenharmony_ci			if (net_ratelimit())
498162306a36Sopenharmony_ci				wiphy_debug(local->hw.wiphy,
498262306a36Sopenharmony_ci					"failed to copy skb for %s\n",
498362306a36Sopenharmony_ci					sdata->name);
498462306a36Sopenharmony_ci			return true;
498562306a36Sopenharmony_ci		}
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci		/* skb_copy() does not copy the hw timestamps, so copy it
498862306a36Sopenharmony_ci		 * explicitly
498962306a36Sopenharmony_ci		 */
499062306a36Sopenharmony_ci		shwt = skb_hwtstamps(rx->skb);
499162306a36Sopenharmony_ci		shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
499262306a36Sopenharmony_ci
499362306a36Sopenharmony_ci		/* Update the hdr pointer to the new skb for translation below */
499462306a36Sopenharmony_ci		hdr = (struct ieee80211_hdr *)rx->skb->data;
499562306a36Sopenharmony_ci	}
499662306a36Sopenharmony_ci
499762306a36Sopenharmony_ci	if (unlikely(rx->sta && rx->sta->sta.mlo) &&
499862306a36Sopenharmony_ci	    is_unicast_ether_addr(hdr->addr1) &&
499962306a36Sopenharmony_ci	    !ieee80211_is_probe_resp(hdr->frame_control) &&
500062306a36Sopenharmony_ci	    !ieee80211_is_beacon(hdr->frame_control)) {
500162306a36Sopenharmony_ci		/* translate to MLD addresses */
500262306a36Sopenharmony_ci		if (ether_addr_equal(link->conf->addr, hdr->addr1))
500362306a36Sopenharmony_ci			ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
500462306a36Sopenharmony_ci		if (ether_addr_equal(link_sta->addr, hdr->addr2))
500562306a36Sopenharmony_ci			ether_addr_copy(hdr->addr2, rx->sta->addr);
500662306a36Sopenharmony_ci		/* translate A3 only if it's the BSSID */
500762306a36Sopenharmony_ci		if (!ieee80211_has_tods(hdr->frame_control) &&
500862306a36Sopenharmony_ci		    !ieee80211_has_fromds(hdr->frame_control)) {
500962306a36Sopenharmony_ci			if (ether_addr_equal(link_sta->addr, hdr->addr3))
501062306a36Sopenharmony_ci				ether_addr_copy(hdr->addr3, rx->sta->addr);
501162306a36Sopenharmony_ci			else if (ether_addr_equal(link->conf->addr, hdr->addr3))
501262306a36Sopenharmony_ci				ether_addr_copy(hdr->addr3, rx->sdata->vif.addr);
501362306a36Sopenharmony_ci		}
501462306a36Sopenharmony_ci		/* not needed for A4 since it can only carry the SA */
501562306a36Sopenharmony_ci	}
501662306a36Sopenharmony_ci
501762306a36Sopenharmony_ci	ieee80211_invoke_rx_handlers(rx);
501862306a36Sopenharmony_ci	return true;
501962306a36Sopenharmony_ci}
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_cistatic void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
502262306a36Sopenharmony_ci				       struct ieee80211_sta *pubsta,
502362306a36Sopenharmony_ci				       struct sk_buff *skb,
502462306a36Sopenharmony_ci				       struct list_head *list)
502562306a36Sopenharmony_ci{
502662306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
502762306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
502862306a36Sopenharmony_ci	struct ieee80211_fast_rx *fast_rx;
502962306a36Sopenharmony_ci	struct ieee80211_rx_data rx;
503062306a36Sopenharmony_ci	struct sta_info *sta;
503162306a36Sopenharmony_ci	int link_id = -1;
503262306a36Sopenharmony_ci
503362306a36Sopenharmony_ci	memset(&rx, 0, sizeof(rx));
503462306a36Sopenharmony_ci	rx.skb = skb;
503562306a36Sopenharmony_ci	rx.local = local;
503662306a36Sopenharmony_ci	rx.list = list;
503762306a36Sopenharmony_ci	rx.link_id = -1;
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_ci	I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
504062306a36Sopenharmony_ci
504162306a36Sopenharmony_ci	/* drop frame if too short for header */
504262306a36Sopenharmony_ci	if (skb->len < sizeof(struct ethhdr))
504362306a36Sopenharmony_ci		goto drop;
504462306a36Sopenharmony_ci
504562306a36Sopenharmony_ci	if (!pubsta)
504662306a36Sopenharmony_ci		goto drop;
504762306a36Sopenharmony_ci
504862306a36Sopenharmony_ci	if (status->link_valid)
504962306a36Sopenharmony_ci		link_id = status->link_id;
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci	/*
505262306a36Sopenharmony_ci	 * TODO: Should the frame be dropped if the right link_id is not
505362306a36Sopenharmony_ci	 * available? Or may be it is fine in the current form to proceed with
505462306a36Sopenharmony_ci	 * the frame processing because with frame being in 802.3 format,
505562306a36Sopenharmony_ci	 * link_id is used only for stats purpose and updating the stats on
505662306a36Sopenharmony_ci	 * the deflink is fine?
505762306a36Sopenharmony_ci	 */
505862306a36Sopenharmony_ci	sta = container_of(pubsta, struct sta_info, sta);
505962306a36Sopenharmony_ci	if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
506062306a36Sopenharmony_ci		goto drop;
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci	fast_rx = rcu_dereference(rx.sta->fast_rx);
506362306a36Sopenharmony_ci	if (!fast_rx)
506462306a36Sopenharmony_ci		goto drop;
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	ieee80211_rx_8023(&rx, fast_rx, skb->len);
506762306a36Sopenharmony_ci	return;
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_cidrop:
507062306a36Sopenharmony_ci	dev_kfree_skb(skb);
507162306a36Sopenharmony_ci}
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_cistatic bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
507462306a36Sopenharmony_ci				       struct sk_buff *skb, bool consume)
507562306a36Sopenharmony_ci{
507662306a36Sopenharmony_ci	struct link_sta_info *link_sta;
507762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
507862306a36Sopenharmony_ci	struct sta_info *sta;
507962306a36Sopenharmony_ci	int link_id = -1;
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	/*
508262306a36Sopenharmony_ci	 * Look up link station first, in case there's a
508362306a36Sopenharmony_ci	 * chance that they might have a link address that
508462306a36Sopenharmony_ci	 * is identical to the MLD address, that way we'll
508562306a36Sopenharmony_ci	 * have the link information if needed.
508662306a36Sopenharmony_ci	 */
508762306a36Sopenharmony_ci	link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
508862306a36Sopenharmony_ci	if (link_sta) {
508962306a36Sopenharmony_ci		sta = link_sta->sta;
509062306a36Sopenharmony_ci		link_id = link_sta->link_id;
509162306a36Sopenharmony_ci	} else {
509262306a36Sopenharmony_ci		struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_ci		sta = sta_info_get_bss(rx->sdata, hdr->addr2);
509562306a36Sopenharmony_ci		if (status->link_valid)
509662306a36Sopenharmony_ci			link_id = status->link_id;
509762306a36Sopenharmony_ci	}
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	if (!ieee80211_rx_data_set_sta(rx, sta, link_id))
510062306a36Sopenharmony_ci		return false;
510162306a36Sopenharmony_ci
510262306a36Sopenharmony_ci	return ieee80211_prepare_and_rx_handle(rx, skb, consume);
510362306a36Sopenharmony_ci}
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci/*
510662306a36Sopenharmony_ci * This is the actual Rx frames handler. as it belongs to Rx path it must
510762306a36Sopenharmony_ci * be called with rcu_read_lock protection.
510862306a36Sopenharmony_ci */
510962306a36Sopenharmony_cistatic void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
511062306a36Sopenharmony_ci					 struct ieee80211_sta *pubsta,
511162306a36Sopenharmony_ci					 struct sk_buff *skb,
511262306a36Sopenharmony_ci					 struct list_head *list)
511362306a36Sopenharmony_ci{
511462306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
511562306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
511662306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
511762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
511862306a36Sopenharmony_ci	__le16 fc;
511962306a36Sopenharmony_ci	struct ieee80211_rx_data rx;
512062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *prev;
512162306a36Sopenharmony_ci	struct rhlist_head *tmp;
512262306a36Sopenharmony_ci	int err = 0;
512362306a36Sopenharmony_ci
512462306a36Sopenharmony_ci	fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
512562306a36Sopenharmony_ci	memset(&rx, 0, sizeof(rx));
512662306a36Sopenharmony_ci	rx.skb = skb;
512762306a36Sopenharmony_ci	rx.local = local;
512862306a36Sopenharmony_ci	rx.list = list;
512962306a36Sopenharmony_ci	rx.link_id = -1;
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
513262306a36Sopenharmony_ci		I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
513362306a36Sopenharmony_ci
513462306a36Sopenharmony_ci	if (ieee80211_is_mgmt(fc)) {
513562306a36Sopenharmony_ci		/* drop frame if too short for header */
513662306a36Sopenharmony_ci		if (skb->len < ieee80211_hdrlen(fc))
513762306a36Sopenharmony_ci			err = -ENOBUFS;
513862306a36Sopenharmony_ci		else
513962306a36Sopenharmony_ci			err = skb_linearize(skb);
514062306a36Sopenharmony_ci	} else {
514162306a36Sopenharmony_ci		err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
514262306a36Sopenharmony_ci	}
514362306a36Sopenharmony_ci
514462306a36Sopenharmony_ci	if (err) {
514562306a36Sopenharmony_ci		dev_kfree_skb(skb);
514662306a36Sopenharmony_ci		return;
514762306a36Sopenharmony_ci	}
514862306a36Sopenharmony_ci
514962306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
515062306a36Sopenharmony_ci	ieee80211_parse_qos(&rx);
515162306a36Sopenharmony_ci	ieee80211_verify_alignment(&rx);
515262306a36Sopenharmony_ci
515362306a36Sopenharmony_ci	if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
515462306a36Sopenharmony_ci		     ieee80211_is_beacon(hdr->frame_control) ||
515562306a36Sopenharmony_ci		     ieee80211_is_s1g_beacon(hdr->frame_control)))
515662306a36Sopenharmony_ci		ieee80211_scan_rx(local, skb);
515762306a36Sopenharmony_ci
515862306a36Sopenharmony_ci	if (ieee80211_is_data(fc)) {
515962306a36Sopenharmony_ci		struct sta_info *sta, *prev_sta;
516062306a36Sopenharmony_ci		int link_id = -1;
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci		if (status->link_valid)
516362306a36Sopenharmony_ci			link_id = status->link_id;
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci		if (pubsta) {
516662306a36Sopenharmony_ci			sta = container_of(pubsta, struct sta_info, sta);
516762306a36Sopenharmony_ci			if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
516862306a36Sopenharmony_ci				goto out;
516962306a36Sopenharmony_ci
517062306a36Sopenharmony_ci			/*
517162306a36Sopenharmony_ci			 * In MLO connection, fetch the link_id using addr2
517262306a36Sopenharmony_ci			 * when the driver does not pass link_id in status.
517362306a36Sopenharmony_ci			 * When the address translation is already performed by
517462306a36Sopenharmony_ci			 * driver/hw, the valid link_id must be passed in
517562306a36Sopenharmony_ci			 * status.
517662306a36Sopenharmony_ci			 */
517762306a36Sopenharmony_ci
517862306a36Sopenharmony_ci			if (!status->link_valid && pubsta->mlo) {
517962306a36Sopenharmony_ci				struct ieee80211_hdr *hdr = (void *)skb->data;
518062306a36Sopenharmony_ci				struct link_sta_info *link_sta;
518162306a36Sopenharmony_ci
518262306a36Sopenharmony_ci				link_sta = link_sta_info_get_bss(rx.sdata,
518362306a36Sopenharmony_ci								 hdr->addr2);
518462306a36Sopenharmony_ci				if (!link_sta)
518562306a36Sopenharmony_ci					goto out;
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci				ieee80211_rx_data_set_link(&rx, link_sta->link_id);
518862306a36Sopenharmony_ci			}
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci			if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
519162306a36Sopenharmony_ci				return;
519262306a36Sopenharmony_ci			goto out;
519362306a36Sopenharmony_ci		}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci		prev_sta = NULL;
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_ci		for_each_sta_info(local, hdr->addr2, sta, tmp) {
519862306a36Sopenharmony_ci			if (!prev_sta) {
519962306a36Sopenharmony_ci				prev_sta = sta;
520062306a36Sopenharmony_ci				continue;
520162306a36Sopenharmony_ci			}
520262306a36Sopenharmony_ci
520362306a36Sopenharmony_ci			rx.sdata = prev_sta->sdata;
520462306a36Sopenharmony_ci			if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
520562306a36Sopenharmony_ci				goto out;
520662306a36Sopenharmony_ci
520762306a36Sopenharmony_ci			if (!status->link_valid && prev_sta->sta.mlo)
520862306a36Sopenharmony_ci				continue;
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci			ieee80211_prepare_and_rx_handle(&rx, skb, false);
521162306a36Sopenharmony_ci
521262306a36Sopenharmony_ci			prev_sta = sta;
521362306a36Sopenharmony_ci		}
521462306a36Sopenharmony_ci
521562306a36Sopenharmony_ci		if (prev_sta) {
521662306a36Sopenharmony_ci			rx.sdata = prev_sta->sdata;
521762306a36Sopenharmony_ci			if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
521862306a36Sopenharmony_ci				goto out;
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci			if (!status->link_valid && prev_sta->sta.mlo)
522162306a36Sopenharmony_ci				goto out;
522262306a36Sopenharmony_ci
522362306a36Sopenharmony_ci			if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
522462306a36Sopenharmony_ci				return;
522562306a36Sopenharmony_ci			goto out;
522662306a36Sopenharmony_ci		}
522762306a36Sopenharmony_ci	}
522862306a36Sopenharmony_ci
522962306a36Sopenharmony_ci	prev = NULL;
523062306a36Sopenharmony_ci
523162306a36Sopenharmony_ci	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
523262306a36Sopenharmony_ci		if (!ieee80211_sdata_running(sdata))
523362306a36Sopenharmony_ci			continue;
523462306a36Sopenharmony_ci
523562306a36Sopenharmony_ci		if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
523662306a36Sopenharmony_ci		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
523762306a36Sopenharmony_ci			continue;
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_ci		/*
524062306a36Sopenharmony_ci		 * frame is destined for this interface, but if it's
524162306a36Sopenharmony_ci		 * not also for the previous one we handle that after
524262306a36Sopenharmony_ci		 * the loop to avoid copying the SKB once too much
524362306a36Sopenharmony_ci		 */
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_ci		if (!prev) {
524662306a36Sopenharmony_ci			prev = sdata;
524762306a36Sopenharmony_ci			continue;
524862306a36Sopenharmony_ci		}
524962306a36Sopenharmony_ci
525062306a36Sopenharmony_ci		rx.sdata = prev;
525162306a36Sopenharmony_ci		ieee80211_rx_for_interface(&rx, skb, false);
525262306a36Sopenharmony_ci
525362306a36Sopenharmony_ci		prev = sdata;
525462306a36Sopenharmony_ci	}
525562306a36Sopenharmony_ci
525662306a36Sopenharmony_ci	if (prev) {
525762306a36Sopenharmony_ci		rx.sdata = prev;
525862306a36Sopenharmony_ci
525962306a36Sopenharmony_ci		if (ieee80211_rx_for_interface(&rx, skb, true))
526062306a36Sopenharmony_ci			return;
526162306a36Sopenharmony_ci	}
526262306a36Sopenharmony_ci
526362306a36Sopenharmony_ci out:
526462306a36Sopenharmony_ci	dev_kfree_skb(skb);
526562306a36Sopenharmony_ci}
526662306a36Sopenharmony_ci
526762306a36Sopenharmony_ci/*
526862306a36Sopenharmony_ci * This is the receive path handler. It is called by a low level driver when an
526962306a36Sopenharmony_ci * 802.11 MPDU is received from the hardware.
527062306a36Sopenharmony_ci */
527162306a36Sopenharmony_civoid ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
527262306a36Sopenharmony_ci		       struct sk_buff *skb, struct list_head *list)
527362306a36Sopenharmony_ci{
527462306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
527562306a36Sopenharmony_ci	struct ieee80211_rate *rate = NULL;
527662306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
527762306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
527862306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
527962306a36Sopenharmony_ci
528062306a36Sopenharmony_ci	WARN_ON_ONCE(softirq_count() == 0);
528162306a36Sopenharmony_ci
528262306a36Sopenharmony_ci	if (WARN_ON(status->band >= NUM_NL80211_BANDS))
528362306a36Sopenharmony_ci		goto drop;
528462306a36Sopenharmony_ci
528562306a36Sopenharmony_ci	sband = local->hw.wiphy->bands[status->band];
528662306a36Sopenharmony_ci	if (WARN_ON(!sband))
528762306a36Sopenharmony_ci		goto drop;
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci	/*
529062306a36Sopenharmony_ci	 * If we're suspending, it is possible although not too likely
529162306a36Sopenharmony_ci	 * that we'd be receiving frames after having already partially
529262306a36Sopenharmony_ci	 * quiesced the stack. We can't process such frames then since
529362306a36Sopenharmony_ci	 * that might, for example, cause stations to be added or other
529462306a36Sopenharmony_ci	 * driver callbacks be invoked.
529562306a36Sopenharmony_ci	 */
529662306a36Sopenharmony_ci	if (unlikely(local->quiescing || local->suspended))
529762306a36Sopenharmony_ci		goto drop;
529862306a36Sopenharmony_ci
529962306a36Sopenharmony_ci	/* We might be during a HW reconfig, prevent Rx for the same reason */
530062306a36Sopenharmony_ci	if (unlikely(local->in_reconfig))
530162306a36Sopenharmony_ci		goto drop;
530262306a36Sopenharmony_ci
530362306a36Sopenharmony_ci	/*
530462306a36Sopenharmony_ci	 * The same happens when we're not even started,
530562306a36Sopenharmony_ci	 * but that's worth a warning.
530662306a36Sopenharmony_ci	 */
530762306a36Sopenharmony_ci	if (WARN_ON(!local->started))
530862306a36Sopenharmony_ci		goto drop;
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci	if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
531162306a36Sopenharmony_ci		/*
531262306a36Sopenharmony_ci		 * Validate the rate, unless a PLCP error means that
531362306a36Sopenharmony_ci		 * we probably can't have a valid rate here anyway.
531462306a36Sopenharmony_ci		 */
531562306a36Sopenharmony_ci
531662306a36Sopenharmony_ci		switch (status->encoding) {
531762306a36Sopenharmony_ci		case RX_ENC_HT:
531862306a36Sopenharmony_ci			/*
531962306a36Sopenharmony_ci			 * rate_idx is MCS index, which can be [0-76]
532062306a36Sopenharmony_ci			 * as documented on:
532162306a36Sopenharmony_ci			 *
532262306a36Sopenharmony_ci			 * https://wireless.wiki.kernel.org/en/developers/Documentation/ieee80211/802.11n
532362306a36Sopenharmony_ci			 *
532462306a36Sopenharmony_ci			 * Anything else would be some sort of driver or
532562306a36Sopenharmony_ci			 * hardware error. The driver should catch hardware
532662306a36Sopenharmony_ci			 * errors.
532762306a36Sopenharmony_ci			 */
532862306a36Sopenharmony_ci			if (WARN(status->rate_idx > 76,
532962306a36Sopenharmony_ci				 "Rate marked as an HT rate but passed "
533062306a36Sopenharmony_ci				 "status->rate_idx is not "
533162306a36Sopenharmony_ci				 "an MCS index [0-76]: %d (0x%02x)\n",
533262306a36Sopenharmony_ci				 status->rate_idx,
533362306a36Sopenharmony_ci				 status->rate_idx))
533462306a36Sopenharmony_ci				goto drop;
533562306a36Sopenharmony_ci			break;
533662306a36Sopenharmony_ci		case RX_ENC_VHT:
533762306a36Sopenharmony_ci			if (WARN_ONCE(status->rate_idx > 11 ||
533862306a36Sopenharmony_ci				      !status->nss ||
533962306a36Sopenharmony_ci				      status->nss > 8,
534062306a36Sopenharmony_ci				      "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
534162306a36Sopenharmony_ci				      status->rate_idx, status->nss))
534262306a36Sopenharmony_ci				goto drop;
534362306a36Sopenharmony_ci			break;
534462306a36Sopenharmony_ci		case RX_ENC_HE:
534562306a36Sopenharmony_ci			if (WARN_ONCE(status->rate_idx > 11 ||
534662306a36Sopenharmony_ci				      !status->nss ||
534762306a36Sopenharmony_ci				      status->nss > 8,
534862306a36Sopenharmony_ci				      "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
534962306a36Sopenharmony_ci				      status->rate_idx, status->nss))
535062306a36Sopenharmony_ci				goto drop;
535162306a36Sopenharmony_ci			break;
535262306a36Sopenharmony_ci		case RX_ENC_EHT:
535362306a36Sopenharmony_ci			if (WARN_ONCE(status->rate_idx > 15 ||
535462306a36Sopenharmony_ci				      !status->nss ||
535562306a36Sopenharmony_ci				      status->nss > 8 ||
535662306a36Sopenharmony_ci				      status->eht.gi > NL80211_RATE_INFO_EHT_GI_3_2,
535762306a36Sopenharmony_ci				      "Rate marked as an EHT rate but data is invalid: MCS:%d, NSS:%d, GI:%d\n",
535862306a36Sopenharmony_ci				      status->rate_idx, status->nss, status->eht.gi))
535962306a36Sopenharmony_ci				goto drop;
536062306a36Sopenharmony_ci			break;
536162306a36Sopenharmony_ci		default:
536262306a36Sopenharmony_ci			WARN_ON_ONCE(1);
536362306a36Sopenharmony_ci			fallthrough;
536462306a36Sopenharmony_ci		case RX_ENC_LEGACY:
536562306a36Sopenharmony_ci			if (WARN_ON(status->rate_idx >= sband->n_bitrates))
536662306a36Sopenharmony_ci				goto drop;
536762306a36Sopenharmony_ci			rate = &sband->bitrates[status->rate_idx];
536862306a36Sopenharmony_ci		}
536962306a36Sopenharmony_ci	}
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci	if (WARN_ON_ONCE(status->link_id >= IEEE80211_LINK_UNSPECIFIED))
537262306a36Sopenharmony_ci		goto drop;
537362306a36Sopenharmony_ci
537462306a36Sopenharmony_ci	status->rx_flags = 0;
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_ci	kcov_remote_start_common(skb_get_kcov_handle(skb));
537762306a36Sopenharmony_ci
537862306a36Sopenharmony_ci	/*
537962306a36Sopenharmony_ci	 * Frames with failed FCS/PLCP checksum are not returned,
538062306a36Sopenharmony_ci	 * all other frames are returned without radiotap header
538162306a36Sopenharmony_ci	 * if it was previously present.
538262306a36Sopenharmony_ci	 * Also, frames with less than 16 bytes are dropped.
538362306a36Sopenharmony_ci	 */
538462306a36Sopenharmony_ci	if (!(status->flag & RX_FLAG_8023))
538562306a36Sopenharmony_ci		skb = ieee80211_rx_monitor(local, skb, rate);
538662306a36Sopenharmony_ci	if (skb) {
538762306a36Sopenharmony_ci		if ((status->flag & RX_FLAG_8023) ||
538862306a36Sopenharmony_ci			ieee80211_is_data_present(hdr->frame_control))
538962306a36Sopenharmony_ci			ieee80211_tpt_led_trig_rx(local, skb->len);
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci		if (status->flag & RX_FLAG_8023)
539262306a36Sopenharmony_ci			__ieee80211_rx_handle_8023(hw, pubsta, skb, list);
539362306a36Sopenharmony_ci		else
539462306a36Sopenharmony_ci			__ieee80211_rx_handle_packet(hw, pubsta, skb, list);
539562306a36Sopenharmony_ci	}
539662306a36Sopenharmony_ci
539762306a36Sopenharmony_ci	kcov_remote_stop();
539862306a36Sopenharmony_ci	return;
539962306a36Sopenharmony_ci drop:
540062306a36Sopenharmony_ci	kfree_skb(skb);
540162306a36Sopenharmony_ci}
540262306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_list);
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_civoid ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
540562306a36Sopenharmony_ci		       struct sk_buff *skb, struct napi_struct *napi)
540662306a36Sopenharmony_ci{
540762306a36Sopenharmony_ci	struct sk_buff *tmp;
540862306a36Sopenharmony_ci	LIST_HEAD(list);
540962306a36Sopenharmony_ci
541062306a36Sopenharmony_ci
541162306a36Sopenharmony_ci	/*
541262306a36Sopenharmony_ci	 * key references and virtual interfaces are protected using RCU
541362306a36Sopenharmony_ci	 * and this requires that we are in a read-side RCU section during
541462306a36Sopenharmony_ci	 * receive processing
541562306a36Sopenharmony_ci	 */
541662306a36Sopenharmony_ci	rcu_read_lock();
541762306a36Sopenharmony_ci	ieee80211_rx_list(hw, pubsta, skb, &list);
541862306a36Sopenharmony_ci	rcu_read_unlock();
541962306a36Sopenharmony_ci
542062306a36Sopenharmony_ci	if (!napi) {
542162306a36Sopenharmony_ci		netif_receive_skb_list(&list);
542262306a36Sopenharmony_ci		return;
542362306a36Sopenharmony_ci	}
542462306a36Sopenharmony_ci
542562306a36Sopenharmony_ci	list_for_each_entry_safe(skb, tmp, &list, list) {
542662306a36Sopenharmony_ci		skb_list_del_init(skb);
542762306a36Sopenharmony_ci		napi_gro_receive(napi, skb);
542862306a36Sopenharmony_ci	}
542962306a36Sopenharmony_ci}
543062306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_napi);
543162306a36Sopenharmony_ci
543262306a36Sopenharmony_ci/* This is a version of the rx handler that can be called from hard irq
543362306a36Sopenharmony_ci * context. Post the skb on the queue and schedule the tasklet */
543462306a36Sopenharmony_civoid ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
543562306a36Sopenharmony_ci{
543662306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
543762306a36Sopenharmony_ci
543862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
543962306a36Sopenharmony_ci
544062306a36Sopenharmony_ci	skb->pkt_type = IEEE80211_RX_MSG;
544162306a36Sopenharmony_ci	skb_queue_tail(&local->skb_queue, skb);
544262306a36Sopenharmony_ci	tasklet_schedule(&local->tasklet);
544362306a36Sopenharmony_ci}
544462306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_irqsafe);
5445