From 685634ce903ea8892b3e40767d7a300d5d293cc6 Mon Sep 17 00:00:00 2001
From: Josef Schlehofer <josef.schlehofer@nic.cz>
Date: Wed, 9 Nov 2022 09:22:45 +0100
Subject: [PATCH] patches/openwrt: 5.15: mac80211: downgrade

Unfortunately, the latest Linux backports does not work for us as there
are some issues in ath10k and mt76, thus Wi-Fi is not working as we
would like.
---
 .../0005-Backport-mac80211.patch              | 2835 +++++++++++++++--
 1 file changed, 2603 insertions(+), 232 deletions(-)

diff --git a/patches/openwrt/a-new-kernel-5.15/0005-Backport-mac80211.patch b/patches/openwrt/a-new-kernel-5.15/0005-Backport-mac80211.patch
index 18809e6a6..c6007fdae 100644
--- a/patches/openwrt/a-new-kernel-5.15/0005-Backport-mac80211.patch
+++ b/patches/openwrt/a-new-kernel-5.15/0005-Backport-mac80211.patch
@@ -1,7 +1,7 @@
-From 6cef91a3ac8a1e3eb3b4da472dd6ec00fac869ca Mon Sep 17 00:00:00 2001
+From 50473f5b24b0df9dc8ae8a3229d93f50e069d580 Mon Sep 17 00:00:00 2001
 From: Josef Schlehofer <pepe.schlehofer@gmail.com>
-Date: Mon, 24 Oct 2022 15:13:48 +0200
-Subject: [PATCH] mac80211: update to version 5.15.74-1
+Date: Wed, 9 Nov 2022 09:21:26 +0100
+Subject: [PATCH] mac80211: downgrade to version 5.15.81
 
 ---
  package/kernel/mac80211/Makefile              |   36 +-
@@ -163,13 +163,30 @@ Subject: [PATCH] mac80211: update to version 5.15.74-1
  ...l_ht-fix-max-probability-rate-select.patch |  124 --
  ...el_ht-increase-stats-update-interval.patch |   20 -
  ...l_ht-fix-rounding-error-in-throughpu.patch |   34 -
+ ...80211-mesh-clean-up-rx_bcn_presp-API.patch |  110 ++
  ...l_ht-use-bitfields-to-encode-rate-in.patch |  412 -----
  ...l_ht-update-total-packets-counter-in.patch |   54 -
+ ...ove-CRC-into-struct-ieee802_11_elems.patch |   82 +
  ...l_ht-reduce-the-need-to-sample-slowe.patch |  102 --
+ ...11-mlme-find-auth-challenge-directly.patch |   80 +
+ ...ays-allocate-struct-ieee802_11_elems.patch | 1143 ++++++++++++++
  ...l_ht-significantly-redesign-the-rate.patch |  767 ----------
+ ...ix-memory-leaks-with-element-parsing.patch |  115 ++
  ...el_ht-show-sampling-rates-in-debugfs.patch |   58 -
  ...l_ht-remove-sample-rate-switching-co.patch |  279 ----
+ ...x-u8-overflow-in-cfg80211_update_not.patch |   41 +
  ...l_ht-fix-regression-in-the-max_prob_.patch |   23 -
+ ...-mac80211-reject-bad-MBSSID-elements.patch |   47 +
+ ...11-fix-MBSSID-parsing-use-after-free.patch |   94 ++
+ ...sure-length-byte-is-present-before-a.patch |   41 +
+ ...fi-cfg80211-fix-BSS-refcounting-bugs.patch |   87 ++
+ ...oid-nontransmitted-BSS-list-corrupti.patch |   48 +
+ ...sim-avoid-mac80211-warning-on-bad-ra.patch |   31 +
+ ...x-crash-in-beacon-protection-for-P2P.patch |   52 +
+ ...update-hidden-BSSes-to-avoid-WARN_ON.patch |   85 ++
+ ...emory-leak-where-sta_info-is-not-fre.patch |   77 +
+ ...n-t-finalize-CSA-in-IBSS-mode-if-sta.patch |   47 +
+ ...ac80211-Fix-UAF-in-ieee80211_scan_rx.patch |   55 +
  ...pply-flow-control-on-management-fram.patch |   60 -
  ...set-sk_pacing_shift-for-802.3-txpath.patch |   21 -
  ...-Rx-timestamp-calculation-for-all-pr.patch |  134 --
@@ -197,7 +214,7 @@ Subject: [PATCH] mac80211: update to version 5.15.74-1
  .../500-mac80211_configure_antenna_gain.patch |   66 +-
  ...the-dst-buffer-to-of_get_mac_address.patch |   29 +
  package/kernel/mac80211/realtek.mk            |   18 +
- 193 files changed, 7460 insertions(+), 13476 deletions(-)
+ 210 files changed, 9695 insertions(+), 13476 deletions(-)
  delete mode 100644 package/kernel/mac80211/files/lib/netifd/mac80211.sh
  delete mode 100644 package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch
  delete mode 100644 package/kernel/mac80211/patches/ath/550-ath9k-disable-bands-via-dt.patch
@@ -329,13 +346,30 @@ Subject: [PATCH] mac80211: update to version 5.15.74-1
  delete mode 100644 package/kernel/mac80211/patches/subsys/343-mac80211-minstrel_ht-fix-max-probability-rate-select.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/372-mac80211-set-sk_pacing_shift-for-802.3-txpath.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/373-mac80211-support-Rx-timestamp-calculation-for-all-pr.patch
@@ -362,7 +396,7 @@ Subject: [PATCH] mac80211: update to version 5.15.74-1
  create mode 100644 package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch
 
 diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
-index 014512c67b..5d70874bad 100644
+index 014512c67b..c5b190dfa0 100644
 --- a/package/kernel/mac80211/Makefile
 +++ b/package/kernel/mac80211/Makefile
 @@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
@@ -370,12 +404,12 @@ index 014512c67b..5d70874bad 100644
  PKG_NAME:=mac80211
  
 -PKG_VERSION:=5.10.149-1
-+PKG_VERSION:=5.15.74-1
++PKG_VERSION:=5.15.58-1
  PKG_RELEASE:=1
 -PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.10.149/
 -PKG_HASH:=80a68a78c9b18513bad0bbd0cb70907eadbfd9bba44c075a94f0795fd7f7be2a
-+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.74/
-+PKG_HASH:=98098d0cab24cc76a04db738dc746a0c8d38d180398805481224f141cca06423
++PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.58/
++PKG_HASH:=a3c2a2b7bbaf8943c65fd72f4e7d7ad5e205aeae28b26c835f9d8afa0f9810bf
  
  PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
  PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
@@ -7968,7 +8002,7 @@ diff --git a/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_
 similarity index 97%
 rename from package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 rename to package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
-index 9370a5846d..159aad564b 100644
+index 9370a5846d..1ceb2be25c 100644
 --- a/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 +++ b/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 @@ -52,7 +52,7 @@ Signed-off-by: Xing Song <xing.song@mediatek.com>
@@ -7976,7 +8010,7 @@ index 9370a5846d..159aad564b 100644
  --- a/net/mac80211/rx.c
  +++ b/net/mac80211/rx.c
 -@@ -2942,6 +2942,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
-+@@ -2950,6 +2950,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
++@@ -2948,6 +2948,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
   	if (!fwd_skb)
   		goto out;
   
@@ -8034,7 +8068,7 @@ index 1c940d3db2..c43cd3acb9 100644
   
 diff --git a/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch
 new file mode 100644
-index 0000000000..80c86e3d92
+index 0000000000..fba0912e80
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch
 @@ -0,0 +1,74 @@
@@ -8051,7 +8085,7 @@ index 0000000000..80c86e3d92
 +
 +--- a/drivers/net/wireless/mac80211_hwsim.c
 ++++ b/drivers/net/wireless/mac80211_hwsim.c
-+@@ -3003,15 +3003,19 @@ static void mac80211_hwsim_he_capab(stru
++@@ -3004,15 +3004,19 @@ static void mac80211_hwsim_he_capab(stru
 + {
 + 	u16 n_iftype_data;
 + 
@@ -8074,7 +8108,7 @@ index 0000000000..80c86e3d92
 + 		return;
 + 	}
 + 
-+@@ -3301,6 +3305,12 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3302,6 +3306,12 @@ static int mac80211_hwsim_new_radio(stru
 + 			sband->vht_cap.vht_mcs.tx_mcs_map =
 + 				sband->vht_cap.vht_mcs.rx_mcs_map;
 + 			break;
@@ -8087,7 +8121,7 @@ index 0000000000..80c86e3d92
 + 		case NL80211_BAND_S1GHZ:
 + 			memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
 + 			       sizeof(sband->s1g_cap));
-+@@ -3311,6 +3321,13 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3312,6 +3322,13 @@ static int mac80211_hwsim_new_radio(stru
 + 			continue;
 + 		}
 + 
@@ -8101,7 +8135,7 @@ index 0000000000..80c86e3d92
 + 		sband->ht_cap.ht_supported = true;
 + 		sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 + 				    IEEE80211_HT_CAP_GRN_FLD |
-+@@ -3324,10 +3341,6 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3325,10 +3342,6 @@ static int mac80211_hwsim_new_radio(stru
 + 		sband->ht_cap.mcs.rx_mask[0] = 0xff;
 + 		sband->ht_cap.mcs.rx_mask[1] = 0xff;
 + 		sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
@@ -8114,7 +8148,7 @@ index 0000000000..80c86e3d92
 + 	/* By default all radios belong to the first group */
 diff --git a/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch
 new file mode 100644
-index 0000000000..a9a6182ab2
+index 0000000000..4b9d874cfe
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch
 @@ -0,0 +1,178 @@
@@ -8189,7 +8223,7 @@ index 0000000000..a9a6182ab2
 + #endif /* __MAC80211_DRIVER_OPS */
 +--- a/net/mac80211/ieee80211_i.h
 ++++ b/net/mac80211/ieee80211_i.h
-+@@ -1489,7 +1489,7 @@ struct ieee80211_local {
++@@ -1490,7 +1490,7 @@ struct ieee80211_local {
 + };
 + 
 + static inline struct ieee80211_sub_if_data *
@@ -12243,7 +12277,7 @@ index 0000000000..a135e3d1b5
 + 	wiphy_lock(sdata->local->hw.wiphy);
 diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
 new file mode 100644
-index 0000000000..e2b05719db
+index 0000000000..fdbcce9450
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
 @@ -0,0 +1,326 @@
@@ -12495,7 +12529,7 @@ index 0000000000..e2b05719db
 + 	struct rcu_head rcu_head;
 + };
 + 
-+@@ -1082,6 +1083,20 @@ ieee80211_vif_get_shift(struct ieee80211
++@@ -1083,6 +1084,20 @@ ieee80211_vif_get_shift(struct ieee80211
 + 	return shift;
 + }
 + 
@@ -12708,7 +12742,7 @@ index 0000000000..f0150ddef0
 + 
 diff --git a/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch
 new file mode 100644
-index 0000000000..e59036f5a2
+index 0000000000..11889d1e89
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch
 @@ -0,0 +1,1249 @@
@@ -13041,7 +13075,7 @@ index 0000000000..e59036f5a2
 + 
 +--- a/net/mac80211/ieee80211_i.h
 ++++ b/net/mac80211/ieee80211_i.h
-+@@ -862,16 +862,20 @@ enum txq_info_flags {
++@@ -863,16 +863,20 @@ enum txq_info_flags {
 +  * @def_flow: used as a fallback flow when a packet destined to @tin hashes to
 +  *	a fq_flow which is already owned by a different tin
 +  * @def_cvars: codel vars for @def_flow
@@ -13064,7 +13098,7 @@ index 0000000000..e59036f5a2
 + 	unsigned long flags;
 + 
 + 	/* keep last! */
-+@@ -948,8 +952,6 @@ struct ieee80211_sub_if_data {
++@@ -949,8 +953,6 @@ struct ieee80211_sub_if_data {
 + 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
 + 	struct mac80211_qos_map __rcu *qos_map;
 + 
@@ -13073,7 +13107,7 @@ index 0000000000..e59036f5a2
 + 	struct work_struct csa_finalize_work;
 + 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 + 	struct cfg80211_chan_def csa_chandef;
-+@@ -1184,44 +1186,6 @@ enum mac80211_scan_state {
++@@ -1185,44 +1187,6 @@ enum mac80211_scan_state {
 + 	SCAN_ABORT,
 + };
 + 
@@ -13118,7 +13152,7 @@ index 0000000000..e59036f5a2
 + DECLARE_STATIC_KEY_FALSE(aql_disable);
 + 
 + struct ieee80211_local {
-+@@ -1235,8 +1199,13 @@ struct ieee80211_local {
++@@ -1236,8 +1200,13 @@ struct ieee80211_local {
 + 	struct codel_params cparams;
 + 
 + 	/* protects active_txqs and txqi->schedule_order */
@@ -13133,7 +13167,7 @@ index 0000000000..e59036f5a2
 + 	u32 aql_threshold;
 + 	atomic_t aql_total_pending_airtime;
 + 
-+@@ -1660,125 +1629,6 @@ static inline bool txq_has_queue(struct
++@@ -1654,125 +1623,6 @@ static inline bool txq_has_queue(struct
 + 	return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
 + }
 + 
@@ -13259,7 +13293,7 @@ index 0000000000..e59036f5a2
 + static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 + {
 + 	return ether_addr_equal(raddr, addr) ||
-+@@ -2024,14 +1874,6 @@ int ieee80211_tx_control_port(struct wip
++@@ -2018,14 +1868,6 @@ int ieee80211_tx_control_port(struct wip
 + 			      u64 *cookie);
 + int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
 + 			      const u8 *buf, size_t len);
@@ -13276,7 +13310,7 @@ index 0000000000..e59036f5a2
 + void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 +--- a/net/mac80211/iface.c
 ++++ b/net/mac80211/iface.c
-+@@ -2192,9 +2192,6 @@ int ieee80211_if_add(struct ieee80211_lo
++@@ -2190,9 +2190,6 @@ int ieee80211_if_add(struct ieee80211_lo
 + 		}
 + 	}
 + 
@@ -14199,7 +14233,7 @@ index 0000000000..317e4f0653
 + 	spin_unlock_bh(&local->active_txq_lock[txq->ac]);
 diff --git a/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch
 new file mode 100644
-index 0000000000..fb6fd6eac6
+index 0000000000..42e1671ed6
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch
 @@ -0,0 +1,131 @@
@@ -14220,7 +14254,7 @@ index 0000000000..fb6fd6eac6
 +
 +--- a/net/mac80211/ieee80211_i.h
 ++++ b/net/mac80211/ieee80211_i.h
-+@@ -1215,6 +1215,7 @@ struct ieee80211_local {
++@@ -1216,6 +1216,7 @@ struct ieee80211_local {
 + 	u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
 + 	u32 aql_threshold;
 + 	atomic_t aql_total_pending_airtime;
@@ -17368,6 +17402,122 @@ index 1df5dec039..0000000000
 - }
 - 
 - /*
+diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
+new file mode 100644
+index 0000000000..3fa70b05fd
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
+@@ -0,0 +1,110 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Mon, 20 Sep 2021 15:40:07 +0200
++Subject: [PATCH] mac80211: mesh: clean up rx_bcn_presp API
++
++commit a5b983c6073140b624f64e79fea6d33c3e4315a0 upstream.
++
++We currently pass the entire elements to the rx_bcn_presp()
++method, but only need mesh_config. Additionally, we use the
++length of the elements to calculate back the entire frame's
++length, but that's confusing - just pass the length of the
++frame instead.
++
++Link: https://lore.kernel.org/r/20210920154009.a18ed3d2da6c.I1824b773a0fbae4453e1433c184678ca14e8df45@changeid
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -645,10 +645,9 @@ struct ieee80211_if_ocb {
++  */
++ struct ieee802_11_elems;
++ struct ieee80211_mesh_sync_ops {
++-	void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata,
++-			     u16 stype,
++-			     struct ieee80211_mgmt *mgmt,
++-			     struct ieee802_11_elems *elems,
+++	void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype,
+++			     struct ieee80211_mgmt *mgmt, unsigned int len,
+++			     const struct ieee80211_meshconf_ie *mesh_cfg,
++ 			     struct ieee80211_rx_status *rx_status);
++ 
++ 	/* should be called with beacon_data under RCU read lock */
++--- a/net/mac80211/mesh.c
+++++ b/net/mac80211/mesh.c
++@@ -1354,8 +1354,8 @@ static void ieee80211_mesh_rx_bcn_presp(
++ 	}
++ 
++ 	if (ifmsh->sync_ops)
++-		ifmsh->sync_ops->rx_bcn_presp(sdata,
++-			stype, mgmt, &elems, rx_status);
+++		ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
+++					      elems.mesh_config, rx_status);
++ }
++ 
++ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
++--- a/net/mac80211/mesh_sync.c
+++++ b/net/mac80211/mesh_sync.c
++@@ -3,6 +3,7 @@
++  * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
++  * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
++  * Copyright 2011-2012, cozybit Inc.
+++ * Copyright (C) 2021 Intel Corporation
++  */
++ 
++ #include "ieee80211_i.h"
++@@ -35,12 +36,12 @@ struct sync_method {
++ /**
++  * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
++  *
++- * @ie: information elements of a management frame from the mesh peer
+++ * @cfg: mesh config element from the mesh peer (or %NULL)
++  */
++-static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
+++static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg)
++ {
++-	return (ie->mesh_config->meshconf_cap &
++-			IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
+++	return cfg &&
+++	       (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING);
++ }
++ 
++ void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
++@@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee802
++ 	}
++ }
++ 
++-static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
++-				   u16 stype,
++-				   struct ieee80211_mgmt *mgmt,
++-				   struct ieee802_11_elems *elems,
++-				   struct ieee80211_rx_status *rx_status)
+++static void
+++mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
+++			      struct ieee80211_mgmt *mgmt, unsigned int len,
+++			      const struct ieee80211_meshconf_ie *mesh_cfg,
+++			      struct ieee80211_rx_status *rx_status)
++ {
++ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
++ 	struct ieee80211_local *local = sdata->local;
++@@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_pres
++ 	 */
++ 	if (ieee80211_have_rx_timestamp(rx_status))
++ 		t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
++-						       24 + 12 +
++-						       elems->total_len +
++-						       FCS_LEN,
++-						       24);
+++						       len + FCS_LEN, 24);
++ 	else
++ 		t_r = drv_get_tsf(local, sdata);
++ 
++@@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_pres
++ 	 * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
++ 	 */
++ 
++-	if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
+++	if (mesh_peer_tbtt_adjusting(mesh_cfg)) {
++ 		msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
++ 			  sta->sta.addr);
++ 		goto no_sync;
 diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch
 deleted file mode 100644
 index 6aa6f0ed93..0000000000
@@ -17846,6 +17996,94 @@ index dce8104934..0000000000
 - 	if (sample_idx < 0)
 - 		return;
 - 
+diff --git a/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch b/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
+new file mode 100644
+index 0000000000..e44aac5cba
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
+@@ -0,0 +1,82 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Mon, 20 Sep 2021 15:40:08 +0200
++Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems
++
++commit c6e37ed498f958254b5459253199e816b6bfc52f upstream.
++
++We're currently returning this value, but to prepare for
++returning the allocated structure, move it into there.
++
++Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -1530,6 +1530,7 @@ struct ieee80211_csa_ie {
++ struct ieee802_11_elems {
++ 	const u8 *ie_start;
++ 	size_t total_len;
+++	u32 crc;
++ 
++ 	/* pointers to IEs */
++ 	const struct ieee80211_tdls_lnkie *lnk_id;
++@@ -2089,10 +2090,10 @@ static inline void ieee80211_tx_skb(stru
++ 	ieee80211_tx_skb_tid(sdata, skb, 7);
++ }
++ 
++-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++-			       struct ieee802_11_elems *elems,
++-			       u64 filter, u32 crc, u8 *transmitter_bssid,
++-			       u8 *bss_bssid);
+++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+++				struct ieee802_11_elems *elems,
+++				u64 filter, u32 crc, u8 *transmitter_bssid,
+++				u8 *bss_bssid);
++ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
++ 					  bool action,
++ 					  struct ieee802_11_elems *elems,
++--- a/net/mac80211/mlme.c
+++++ b/net/mac80211/mlme.c
++@@ -4102,10 +4102,11 @@ static void ieee80211_rx_mgmt_beacon(str
++ 	 */
++ 	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
++ 		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
++-	ncrc = ieee802_11_parse_elems_crc(variable,
++-					  len - baselen, false, &elems,
++-					  care_about_ies, ncrc,
++-					  mgmt->bssid, bssid);
+++	ieee802_11_parse_elems_crc(variable,
+++				   len - baselen, false, &elems,
+++				   care_about_ies, ncrc,
+++				   mgmt->bssid, bssid);
+++	ncrc = elems.crc;
++ 
++ 	if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
++ 	    ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -1469,10 +1469,10 @@ static size_t ieee802_11_find_bssid_prof
++ 	return found ? profile_len : 0;
++ }
++ 
++-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++-			       struct ieee802_11_elems *elems,
++-			       u64 filter, u32 crc, u8 *transmitter_bssid,
++-			       u8 *bss_bssid)
+++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+++				struct ieee802_11_elems *elems,
+++				u64 filter, u32 crc, u8 *transmitter_bssid,
+++				u8 *bss_bssid)
++ {
++ 	const struct element *non_inherit = NULL;
++ 	u8 *nontransmitted_profile;
++@@ -1524,7 +1524,7 @@ u32 ieee802_11_parse_elems_crc(const u8
++ 
++ 	kfree(nontransmitted_profile);
++ 
++-	return crc;
+++	elems->crc = crc;
++ }
++ 
++ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
 diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch
 deleted file mode 100644
 index dc6f11e4b9..0000000000
@@ -17954,207 +18192,1442 @@ index dc6f11e4b9..0000000000
 - 
 - 	enum minstrel_sample_mode sample_mode;
 - 	u16 sample_rate;
-diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
-deleted file mode 100644
-index 09f6fd2214..0000000000
---- a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
-+++ /dev/null
-@@ -1,767 +0,0 @@
--From: Felix Fietkau <nbd@nbd.name>
--Date: Fri, 22 Jan 2021 23:57:50 +0100
--Subject: [PATCH] mac80211: minstrel_ht: significantly redesign the rate
-- probing strategy
--
--The biggest flaw in current minstrel_ht is the fact that it needs way too
--many probing packets to be able to quickly find the best rate.
--Depending on the wifi hardware and operating mode, this can significantly
--reduce throughput when not operating at the highest available data rate.
--
--In order to be able to significantly reduce the amount of rate sampling,
--we need a much smarter selection of probing rates.
--
--The new approach introduced by this patch maintains a limited set of
--available rates to be tested during a statistics window.
--
--They are split into distinct categories:
--- MINSTREL_SAMPLE_TYPE_INC - incremental rate upgrade:
--  Pick the next rate group and find the first rate that is faster than
--  the current max. throughput rate
--- MINSTREL_SAMPLE_TYPE_JUMP - random testing of higher rates:
--  Pick a random rate from the next group that is faster than the current
--  max throughput rate. This allows faster adaptation when the link changes
--  significantly
--- MINSTREL_SAMPLE_TYPE_SLOW - test a rate between max_prob, max_tp2 and
--  max_tp in order to reduce the gap between them
--
--In order to prioritize sampling, every 6 attempts are split into 3x INC,
--2x JUMP, 1x SLOW.
--
--Available rates are checked and refilled on every stats window update.
--
--With this approach, we finally get a very small delta in throughput when
--comparing setting the optimal data rate as a fixed rate vs normal rate
--control operation.
--
--Signed-off-by: Felix Fietkau <nbd@nbd.name>
-----
--
----- a/net/mac80211/rc80211_minstrel_ht.c
--+++ b/net/mac80211/rc80211_minstrel_ht.c
--@@ -266,6 +266,14 @@ const struct mcs_group minstrel_mcs_grou
-- const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 };
-- const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 };
-- static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
--+static const u8 minstrel_sample_seq[] = {
--+	MINSTREL_SAMPLE_TYPE_INC,
--+	MINSTREL_SAMPLE_TYPE_JUMP,
--+	MINSTREL_SAMPLE_TYPE_INC,
--+	MINSTREL_SAMPLE_TYPE_JUMP,
--+	MINSTREL_SAMPLE_TYPE_INC,
--+	MINSTREL_SAMPLE_TYPE_SLOW,
--+};
-- 
-- static void
-- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
--@@ -620,77 +628,31 @@ minstrel_ht_prob_rate_reduce_streams(str
-- 	}
-- }
-- 
---static bool
---minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group,
---						int tp_idx, const struct mcs_group *group)
---{
---	if (group->bw < tp_group->bw)
---		return false;
---
---	if (group->streams == tp_group->streams)
---		return true;
---
---	if (tp_idx < 4 && group->streams == tp_group->streams - 1)
---		return true;
---
---	return group->streams == tp_group->streams + 1;
---}
---
---static void
---minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates,
---			     bool faster_rate)
--+static u16
--+__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
--+			      enum minstrel_sample_type type)
-- {
---	const struct mcs_group *group, *tp_group;
---	int i, g, max_dur;
---	int tp_idx;
---
---	tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])];
---	tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]);
---
---	max_dur = minstrel_get_duration(mi->max_tp_rate[0]);
---	if (faster_rate)
---		max_dur -= max_dur / 16;
---
---	for (g = 0; g < MINSTREL_GROUPS_NB; g++) {
---		u16 supported = mi->supported[g];
---
---		if (!supported)
---			continue;
--+	u16 *rates = mi->sample[type].sample_rates;
--+	u16 cur;
--+	int i;
-- 
---		group = &minstrel_mcs_groups[g];
---		if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group))
--+	for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) {
--+		if (!rates[i])
-- 			continue;
-- 
---		for (i = 0; supported; supported >>= 1, i++) {
---			int idx;
---
---			if (!(supported & 1))
---				continue;
---
---			if ((group->duration[i] << group->shift) > max_dur)
---				continue;
---
---			idx = MI_RATE(g, i);
---			if (idx == mi->max_tp_rate[0])
---				continue;
---
---			rates[(*n_rates)++] = idx;
---			break;
---		}
--+		cur = rates[i];
--+		rates[i] = 0;
--+		return cur;
-- 	}
--+
--+	return 0;
-- }
-- 
-- static void
-- minstrel_ht_rate_sample_switch(struct minstrel_priv *mp,
-- 			       struct minstrel_ht_sta *mi)
-- {
---	struct minstrel_rate_stats *mrs;
---	u16 rates[MINSTREL_GROUPS_NB];
---	int n_rates = 0;
---	int probe_rate = 0;
---	bool faster_rate;
---	int i;
---	u8 random;
--+	u16 rate;
-- 
-- 	/*
-- 	 * Use rate switching instead of probing packets for devices with
--@@ -699,43 +661,11 @@ minstrel_ht_rate_sample_switch(struct mi
-- 	if (mp->hw->max_rates > 1)
-- 		return;
-- 
---	/*
---	 * If the current EWMA prob is >75%, look for a rate that's 6.25%
---	 * faster than the max tp rate.
---	 * If that fails, look again for a rate that is at least as fast
---	 */
---	mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
---	faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100);
---	minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate);
---	if (!n_rates && faster_rate)
---		minstrel_ht_find_probe_rates(mi, rates, &n_rates, false);
---
---	/* If no suitable rate was found, try to pick the next one in the group */
---	if (!n_rates) {
---		int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]);
---		u16 supported = mi->supported[g_idx];
---
---		supported >>= MI_RATE_IDX(mi->max_tp_rate[0]);
---		for (i = 0; supported; supported >>= 1, i++) {
---			if (!(supported & 1))
---				continue;
---
---			probe_rate = mi->max_tp_rate[0] + i;
---			goto out;
---		}
---
--+	rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC);
--+	if (!rate)
-- 		return;
---	}
---
---	i = 0;
---	if (n_rates > 1) {
---		random = prandom_u32();
---		i = random % n_rates;
---	}
---	probe_rate = rates[i];
-- 
---out:
---	mi->sample_rate = probe_rate;
--+	mi->sample_rate = rate;
-- 	mi->sample_mode = MINSTREL_SAMPLE_ACTIVE;
-- }
-- 
+diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
+new file mode 100644
+index 0000000000..3432c25a91
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
+@@ -0,0 +1,80 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Mon, 20 Sep 2021 15:40:09 +0200
++Subject: [PATCH] mac80211: mlme: find auth challenge directly
++
++commit 49a765d6785e99157ff5091cc37485732496864e upstream.
++
++There's no need to parse all elements etc. just to find the
++authentication challenge - use cfg80211_find_elem() instead.
++This also allows us to remove WLAN_EID_CHALLENGE handling
++from the element parsing entirely.
++
++Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -1540,7 +1540,6 @@ struct ieee802_11_elems {
++ 	const u8 *supp_rates;
++ 	const u8 *ds_params;
++ 	const struct ieee80211_tim_ie *tim;
++-	const u8 *challenge;
++ 	const u8 *rsn;
++ 	const u8 *rsnx;
++ 	const u8 *erp_info;
++@@ -1594,7 +1593,6 @@ struct ieee802_11_elems {
++ 	u8 ssid_len;
++ 	u8 supp_rates_len;
++ 	u8 tim_len;
++-	u8 challenge_len;
++ 	u8 rsn_len;
++ 	u8 rsnx_len;
++ 	u8 ext_supp_rates_len;
++--- a/net/mac80211/mlme.c
+++++ b/net/mac80211/mlme.c
++@@ -2889,17 +2889,17 @@ static void ieee80211_auth_challenge(str
++ {
++ 	struct ieee80211_local *local = sdata->local;
++ 	struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
+++	const struct element *challenge;
++ 	u8 *pos;
++-	struct ieee802_11_elems elems;
++ 	u32 tx_flags = 0;
++ 	struct ieee80211_prep_tx_info info = {
++ 		.subtype = IEEE80211_STYPE_AUTH,
++ 	};
++ 
++ 	pos = mgmt->u.auth.variable;
++-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
++-			       mgmt->bssid, auth_data->bss->bssid);
++-	if (!elems.challenge)
+++	challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos,
+++				       len - (pos - (u8 *)mgmt));
+++	if (!challenge)
++ 		return;
++ 	auth_data->expected_transaction = 4;
++ 	drv_mgd_prepare_tx(sdata->local, sdata, &info);
++@@ -2907,7 +2907,8 @@ static void ieee80211_auth_challenge(str
++ 		tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
++ 			   IEEE80211_TX_INTFL_MLME_CONN_TX;
++ 	ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
++-			    elems.challenge - 2, elems.challenge_len + 2,
+++			    (void *)challenge,
+++			    challenge->datalen + sizeof(*challenge),
++ 			    auth_data->bss->bssid, auth_data->bss->bssid,
++ 			    auth_data->key, auth_data->key_len,
++ 			    auth_data->key_idx, tx_flags);
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -1120,10 +1120,6 @@ _ieee802_11_parse_elems_crc(const u8 *st
++ 			} else
++ 				elem_parse_failed = true;
++ 			break;
++-		case WLAN_EID_CHALLENGE:
++-			elems->challenge = pos;
++-			elems->challenge_len = elen;
++-			break;
++ 		case WLAN_EID_VENDOR_SPECIFIC:
++ 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
++ 			    pos[2] == 0xf2) {
+diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
+new file mode 100644
+index 0000000000..75655279a9
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
+@@ -0,0 +1,1143 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Mon, 20 Sep 2021 15:40:10 +0200
++Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems
++
++As the 802.11 spec evolves, we need to parse more and more
++elements. This is causing the struct to grow, and we can no
++longer get away with putting it on the stack.
++
++Change the API to always dynamically allocate and return an
++allocated pointer that must be kfree()d later.
++
++As an alternative, I contemplated a scheme whereby we'd say
++in the code which elements we needed, e.g.
++
++    DECLARE_ELEMENT_PARSER(elems,
++                           SUPPORTED_CHANNELS,
++                           CHANNEL_SWITCH,
++                           EXT(KEY_DELIVERY));
++
++    ieee802_11_parse_elems(..., &elems, ...);
++
++and while I think this is possible and will save us a lot
++since most individual places only care about a small subset
++of the elements, it ended up being a bit more work since a
++lot of places do the parsing and then pass the struct to
++other functions, sometimes with multiple levels.
++
++Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/agg-rx.c
+++++ b/net/mac80211/agg-rx.c
++@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str
++ 				     size_t len)
++ {
++ 	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
++-	struct ieee802_11_elems elems = { };
+++	struct ieee802_11_elems *elems = NULL;
++ 	u8 dialog_token;
++ 	int ies_len;
++ 
++@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str
++ 	ies_len = len - offsetof(struct ieee80211_mgmt,
++ 				 u.action.u.addba_req.variable);
++ 	if (ies_len) {
++-		ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
++-                                ies_len, true, &elems, mgmt->bssid, NULL);
++-		if (elems.parse_error)
+++		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
+++					       ies_len, true, mgmt->bssid, NULL);
+++		if (!elems || elems->parse_error)
++ 			return;
++ 	}
++ 
++ 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
++ 					start_seq_num, ba_policy, tid,
++ 					buf_size, true, false,
++-					elems.addba_ext_ie);
+++					elems ? elems->addba_ext_ie : NULL);
+++	kfree(elems);
++ }
++ 
++ void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
++--- a/net/mac80211/ibss.c
+++++ b/net/mac80211/ibss.c
++@@ -9,7 +9,7 @@
++  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
++  * Copyright 2013-2014  Intel Mobile Communications GmbH
++  * Copyright(c) 2016 Intel Deutschland GmbH
++- * Copyright(c) 2018-2020 Intel Corporation
+++ * Copyright(c) 2018-2021 Intel Corporation
++  */
++ 
++ #include <linux/delay.h>
++@@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru
++ 				    struct ieee80211_rx_status *rx_status)
++ {
++ 	size_t baselen;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 
++ 	BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
++ 		     offsetof(typeof(mgmt->u.beacon), variable));
++@@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru
++ 	if (baselen > len)
++ 		return;
++ 
++-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
++-			       false, &elems, mgmt->bssid, NULL);
++-
++-	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
+++	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
+++				       len - baselen, false,
+++				       mgmt->bssid, NULL);
+++
+++	if (elems) {
+++		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
+++		kfree(elems);
+++	}
++ }
++ 
++ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
++@@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc
++ 	struct ieee80211_rx_status *rx_status;
++ 	struct ieee80211_mgmt *mgmt;
++ 	u16 fc;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	int ies_len;
++ 
++ 	rx_status = IEEE80211_SKB_RXCB(skb);
++@@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc
++ 			if (ies_len < 0)
++ 				break;
++ 
++-			ieee802_11_parse_elems(
+++			elems = ieee802_11_parse_elems(
++ 				mgmt->u.action.u.chan_switch.variable,
++-				ies_len, true, &elems, mgmt->bssid, NULL);
+++				ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (elems.parse_error)
+++			if (!elems || elems->parse_error)
++ 				break;
++ 
++ 			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
++-							rx_status, &elems);
+++							rx_status, elems);
+++			kfree(elems);
++ 			break;
++ 		}
++ 	}
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -2088,18 +2088,18 @@ static inline void ieee80211_tx_skb(stru
++ 	ieee80211_tx_skb_tid(sdata, skb, 7);
++ }
++ 
++-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++-				struct ieee802_11_elems *elems,
++-				u64 filter, u32 crc, u8 *transmitter_bssid,
++-				u8 *bss_bssid);
++-static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
++-					  bool action,
++-					  struct ieee802_11_elems *elems,
++-					  u8 *transmitter_bssid,
++-					  u8 *bss_bssid)
+++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
+++						    bool action,
+++						    u64 filter, u32 crc,
+++						    const u8 *transmitter_bssid,
+++						    const u8 *bss_bssid);
+++static inline struct ieee802_11_elems *
+++ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
+++		       const u8 *transmitter_bssid,
+++		       const u8 *bss_bssid)
++ {
++-	ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
++-				   transmitter_bssid, bss_bssid);
+++	return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
+++					  transmitter_bssid, bss_bssid);
++ }
++ 
++ 
++--- a/net/mac80211/mesh.c
+++++ b/net/mac80211/mesh.c
++@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8
++ 	struct sk_buff *presp;
++ 	struct beacon_data *bcn;
++ 	struct ieee80211_mgmt *hdr;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	size_t baselen;
++ 	u8 *pos;
++ 
++@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8
++ 	if (baselen > len)
++ 		return;
++ 
++-	ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
++-			       NULL);
++-
++-	if (!elems.mesh_id)
+++	elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
+++				       NULL);
+++	if (!elems)
++ 		return;
++ 
+++	if (!elems->mesh_id)
+++		goto free;
+++
++ 	/* 802.11-2012 10.1.4.3.2 */
++ 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
++ 	     !is_broadcast_ether_addr(mgmt->da)) ||
++-	    elems.ssid_len != 0)
++-		return;
+++	    elems->ssid_len != 0)
+++		goto free;
++ 
++-	if (elems.mesh_id_len != 0 &&
++-	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
++-	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
++-		return;
+++	if (elems->mesh_id_len != 0 &&
+++	    (elems->mesh_id_len != ifmsh->mesh_id_len ||
+++	     memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
+++		goto free;
++ 
++ 	rcu_read_lock();
++ 	bcn = rcu_dereference(ifmsh->beacon);
++@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8
++ 	ieee80211_tx_skb(sdata, presp);
++ out:
++ 	rcu_read_unlock();
+++free:
+++	kfree(elems);
++ }
++ 
++ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
++@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp(
++ {
++ 	struct ieee80211_local *local = sdata->local;
++ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	struct ieee80211_channel *channel;
++ 	size_t baselen;
++ 	int freq;
++@@ -1320,42 +1324,47 @@ static void ieee80211_mesh_rx_bcn_presp(
++ 	if (baselen > len)
++ 		return;
++ 
++-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
++-			       false, &elems, mgmt->bssid, NULL);
+++	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
+++				       len - baselen,
+++				       false, mgmt->bssid, NULL);
+++	if (!elems)
+++		return;
++ 
++ 	/* ignore non-mesh or secure / unsecure mismatch */
++-	if ((!elems.mesh_id || !elems.mesh_config) ||
++-	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
++-	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
++-		return;
+++	if ((!elems->mesh_id || !elems->mesh_config) ||
+++	    (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
+++	    (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
+++		goto free;
++ 
++-	if (elems.ds_params)
++-		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
+++	if (elems->ds_params)
+++		freq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
++ 	else
++ 		freq = rx_status->freq;
++ 
++ 	channel = ieee80211_get_channel(local->hw.wiphy, freq);
++ 
++ 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
++-		return;
+++		goto free;
++ 
++-	if (mesh_matches_local(sdata, &elems)) {
+++	if (mesh_matches_local(sdata, elems)) {
++ 		mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
++ 			sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
++ 		if (!sdata->u.mesh.user_mpm ||
++ 		    sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
++ 		    sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
++-			mesh_neighbour_update(sdata, mgmt->sa, &elems,
+++			mesh_neighbour_update(sdata, mgmt->sa, elems,
++ 					      rx_status);
++ 
++ 		if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
++ 		    !sdata->vif.csa_active)
++-			ieee80211_mesh_process_chnswitch(sdata, &elems, true);
+++			ieee80211_mesh_process_chnswitch(sdata, elems, true);
++ 	}
++ 
++ 	if (ifmsh->sync_ops)
++ 		ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
++-					      elems.mesh_config, rx_status);
+++					      elems->mesh_config, rx_status);
+++free:
+++	kfree(elems);
++ }
++ 
++ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
++@@ -1447,7 +1456,7 @@ static void mesh_rx_csa_frame(struct iee
++ 			      struct ieee80211_mgmt *mgmt, size_t len)
++ {
++ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	u16 pre_value;
++ 	bool fwd_csa = true;
++ 	size_t baselen;
++@@ -1460,33 +1469,37 @@ static void mesh_rx_csa_frame(struct iee
++ 	pos = mgmt->u.action.u.chan_switch.variable;
++ 	baselen = offsetof(struct ieee80211_mgmt,
++ 			   u.action.u.chan_switch.variable);
++-	ieee802_11_parse_elems(pos, len - baselen, true, &elems,
++-			       mgmt->bssid, NULL);
++-
++-	if (!mesh_matches_local(sdata, &elems))
+++	elems = ieee802_11_parse_elems(pos, len - baselen, true,
+++				       mgmt->bssid, NULL);
+++	if (!elems)
++ 		return;
++ 
++-	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+++	if (!mesh_matches_local(sdata, elems))
+++		goto free;
+++
+++	ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
++ 	if (!--ifmsh->chsw_ttl)
++ 		fwd_csa = false;
++ 
++-	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+++	pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);
++ 	if (ifmsh->pre_value >= pre_value)
++-		return;
+++		goto free;
++ 
++ 	ifmsh->pre_value = pre_value;
++ 
++ 	if (!sdata->vif.csa_active &&
++-	    !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
+++	    !ieee80211_mesh_process_chnswitch(sdata, elems, false)) {
++ 		mcsa_dbg(sdata, "Failed to process CSA action frame");
++-		return;
+++		goto free;
++ 	}
++ 
++ 	/* forward or re-broadcast the CSA frame */
++ 	if (fwd_csa) {
++-		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
+++		if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0)
++ 			mcsa_dbg(sdata, "Failed to forward the CSA frame");
++ 	}
+++free:
+++	kfree(elems);
++ }
++ 
++ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
++--- a/net/mac80211/mesh_hwmp.c
+++++ b/net/mac80211/mesh_hwmp.c
++@@ -1,7 +1,7 @@
++ // SPDX-License-Identifier: GPL-2.0-only
++ /*
++  * Copyright (c) 2008, 2009 open80211s Ltd.
++- * Copyright (C) 2019 Intel Corporation
+++ * Copyright (C) 2019, 2021 Intel Corporation
++  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
++  */
++ 
++@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru
++ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
++ 			    struct ieee80211_mgmt *mgmt, size_t len)
++ {
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	size_t baselen;
++ 	u32 path_metric;
++ 	struct sta_info *sta;
++@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8
++ 	rcu_read_unlock();
++ 
++ 	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
++-	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
++-			       len - baselen, false, &elems, mgmt->bssid, NULL);
+++	elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
+++				       len - baselen, false, mgmt->bssid, NULL);
+++	if (!elems)
+++		return;
++ 
++-	if (elems.preq) {
++-		if (elems.preq_len != 37)
+++	if (elems->preq) {
+++		if (elems->preq_len != 37)
++ 			/* Right now we support just 1 destination and no AE */
++-			return;
++-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
+++			goto free;
+++		path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq,
++ 						  MPATH_PREQ);
++ 		if (path_metric)
++-			hwmp_preq_frame_process(sdata, mgmt, elems.preq,
+++			hwmp_preq_frame_process(sdata, mgmt, elems->preq,
++ 						path_metric);
++ 	}
++-	if (elems.prep) {
++-		if (elems.prep_len != 31)
+++	if (elems->prep) {
+++		if (elems->prep_len != 31)
++ 			/* Right now we support no AE */
++-			return;
++-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
+++			goto free;
+++		path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep,
++ 						  MPATH_PREP);
++ 		if (path_metric)
++-			hwmp_prep_frame_process(sdata, mgmt, elems.prep,
+++			hwmp_prep_frame_process(sdata, mgmt, elems->prep,
++ 						path_metric);
++ 	}
++-	if (elems.perr) {
++-		if (elems.perr_len != 15)
+++	if (elems->perr) {
+++		if (elems->perr_len != 15)
++ 			/* Right now we support only one destination per PERR */
++-			return;
++-		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
+++			goto free;
+++		hwmp_perr_frame_process(sdata, mgmt, elems->perr);
++ 	}
++-	if (elems.rann)
++-		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
+++	if (elems->rann)
+++		hwmp_rann_frame_process(sdata, mgmt, elems->rann);
+++free:
+++	kfree(elems);
++ }
++ 
++ /**
++--- a/net/mac80211/mesh_plink.c
+++++ b/net/mac80211/mesh_plink.c
++@@ -1,7 +1,7 @@
++ // SPDX-License-Identifier: GPL-2.0-only
++ /*
++  * Copyright (c) 2008, 2009 open80211s Ltd.
++- * Copyright (C) 2019 Intel Corporation
+++ * Copyright (C) 2019, 2021 Intel Corporation
++  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
++  */
++ #include <linux/gfp.h>
++@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021
++ 			 struct ieee80211_mgmt *mgmt, size_t len,
++ 			 struct ieee80211_rx_status *rx_status)
++ {
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	size_t baselen;
++ 	u8 *baseaddr;
++ 
++@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021
++ 		if (baselen > len)
++ 			return;
++ 	}
++-	ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
++-			       mgmt->bssid, NULL);
++-	mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
+++	elems = ieee802_11_parse_elems(baseaddr, len - baselen, true,
+++				       mgmt->bssid, NULL);
+++	mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
+++	kfree(elems);
++ }
++--- a/net/mac80211/mlme.c
+++++ b/net/mac80211/mlme.c
++@@ -3317,8 +3317,11 @@ static bool ieee80211_assoc_success(stru
++ 		aid = 0; /* TODO */
++ 	}
++ 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
++-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
++-			       mgmt->bssid, assoc_data->bss->bssid);
+++	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
+++				       mgmt->bssid, assoc_data->bss->bssid);
+++
+++	if (!elems)
+++		return false;
++ 
++ 	if (elems->aid_resp)
++ 		aid = le16_to_cpu(elems->aid_resp->aid);
++@@ -3340,7 +3343,8 @@ static bool ieee80211_assoc_success(stru
++ 
++ 	if (!is_s1g && !elems->supp_rates) {
++ 		sdata_info(sdata, "no SuppRates element in AssocResp\n");
++-		return false;
+++		ret = false;
+++		goto out;
++ 	}
++ 
++ 	sdata->vif.bss_conf.aid = aid;
++@@ -3362,7 +3366,7 @@ static bool ieee80211_assoc_success(stru
++ 	     (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
++ 	      (!elems->vht_cap_elem || !elems->vht_operation)))) {
++ 		const struct cfg80211_bss_ies *ies;
++-		struct ieee802_11_elems bss_elems;
+++		struct ieee802_11_elems *bss_elems;
++ 
++ 		rcu_read_lock();
++ 		ies = rcu_dereference(cbss->ies);
++@@ -3373,13 +3377,17 @@ static bool ieee80211_assoc_success(stru
++ 		if (!bss_ies)
++ 			return false;
++ 
++-		ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
++-				       false, &bss_elems,
++-				       mgmt->bssid,
++-				       assoc_data->bss->bssid);
+++		bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
+++						   false, mgmt->bssid,
+++						   assoc_data->bss->bssid);
+++		if (!bss_elems) {
+++			ret = false;
+++			goto out;
+++		}
+++
++ 		if (assoc_data->wmm &&
++-		    !elems->wmm_param && bss_elems.wmm_param) {
++-			elems->wmm_param = bss_elems.wmm_param;
+++		    !elems->wmm_param && bss_elems->wmm_param) {
+++			elems->wmm_param = bss_elems->wmm_param;
++ 			sdata_info(sdata,
++ 				   "AP bug: WMM param missing from AssocResp\n");
++ 		}
++@@ -3388,30 +3396,32 @@ static bool ieee80211_assoc_success(stru
++ 		 * Also check if we requested HT/VHT, otherwise the AP doesn't
++ 		 * have to include the IEs in the (re)association response.
++ 		 */
++-		if (!elems->ht_cap_elem && bss_elems.ht_cap_elem &&
+++		if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
++ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
++-			elems->ht_cap_elem = bss_elems.ht_cap_elem;
+++			elems->ht_cap_elem = bss_elems->ht_cap_elem;
++ 			sdata_info(sdata,
++ 				   "AP bug: HT capability missing from AssocResp\n");
++ 		}
++-		if (!elems->ht_operation && bss_elems.ht_operation &&
+++		if (!elems->ht_operation && bss_elems->ht_operation &&
++ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
++-			elems->ht_operation = bss_elems.ht_operation;
+++			elems->ht_operation = bss_elems->ht_operation;
++ 			sdata_info(sdata,
++ 				   "AP bug: HT operation missing from AssocResp\n");
++ 		}
++-		if (!elems->vht_cap_elem && bss_elems.vht_cap_elem &&
+++		if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
++ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
++-			elems->vht_cap_elem = bss_elems.vht_cap_elem;
+++			elems->vht_cap_elem = bss_elems->vht_cap_elem;
++ 			sdata_info(sdata,
++ 				   "AP bug: VHT capa missing from AssocResp\n");
++ 		}
++-		if (!elems->vht_operation && bss_elems.vht_operation &&
+++		if (!elems->vht_operation && bss_elems->vht_operation &&
++ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
++-			elems->vht_operation = bss_elems.vht_operation;
+++			elems->vht_operation = bss_elems->vht_operation;
++ 			sdata_info(sdata,
++ 				   "AP bug: VHT operation missing from AssocResp\n");
++ 		}
+++
+++		kfree(bss_elems);
++ 	}
++ 
++ 	/*
++@@ -3662,6 +3672,7 @@ static bool ieee80211_assoc_success(stru
++ 
++ 	ret = true;
++  out:
+++	kfree(elems);
++ 	kfree(bss_ies);
++ 	return ret;
++ }
++@@ -3673,7 +3684,7 @@ static void ieee80211_rx_mgmt_assoc_resp
++ 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
++ 	struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
++ 	u16 capab_info, status_code, aid;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	int ac, uapsd_queues = -1;
++ 	u8 *pos;
++ 	bool reassoc;
++@@ -3730,14 +3741,16 @@ static void ieee80211_rx_mgmt_assoc_resp
++ 	    fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
++ 		return;
++ 
++-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
++-			       mgmt->bssid, assoc_data->bss->bssid);
+++	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
+++				       mgmt->bssid, assoc_data->bss->bssid);
+++	if (!elems)
+++		goto notify_driver;
++ 
++ 	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
++-	    elems.timeout_int &&
++-	    elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
+++	    elems->timeout_int &&
+++	    elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
++ 		u32 tu, ms;
++-		tu = le32_to_cpu(elems.timeout_int->value);
+++		tu = le32_to_cpu(elems->timeout_int->value);
++ 		ms = tu * 1024 / 1000;
++ 		sdata_info(sdata,
++ 			   "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
++@@ -3757,7 +3770,7 @@ static void ieee80211_rx_mgmt_assoc_resp
++ 		event.u.mlme.reason = status_code;
++ 		drv_event_callback(sdata->local, sdata, &event);
++ 	} else {
++-		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) {
+++		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
++ 			/* oops -- internal error -- send timeout for now */
++ 			ieee80211_destroy_assoc_data(sdata, false, false);
++ 			cfg80211_assoc_timeout(sdata->dev, cbss);
++@@ -3787,6 +3800,7 @@ static void ieee80211_rx_mgmt_assoc_resp
++ 			       ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
++ notify_driver:
++ 	drv_mgd_complete_tx(sdata->local, sdata, &info);
+++	kfree(elems);
++ }
++ 
++ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
++@@ -3991,7 +4005,7 @@ static void ieee80211_rx_mgmt_beacon(str
++ 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
++ 	struct ieee80211_mgmt *mgmt = (void *) hdr;
++ 	size_t baselen;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	struct ieee80211_local *local = sdata->local;
++ 	struct ieee80211_chanctx_conf *chanctx_conf;
++ 	struct ieee80211_channel *chan;
++@@ -4037,15 +4051,16 @@ static void ieee80211_rx_mgmt_beacon(str
++ 
++ 	if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
++ 	    ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
++-		ieee802_11_parse_elems(variable,
++-				       len - baselen, false, &elems,
++-				       bssid,
++-				       ifmgd->assoc_data->bss->bssid);
+++		elems = ieee802_11_parse_elems(variable, len - baselen, false,
+++					       bssid,
+++					       ifmgd->assoc_data->bss->bssid);
+++		if (!elems)
+++			return;
++ 
++ 		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
++ 
++-		if (elems.dtim_period)
++-			ifmgd->dtim_period = elems.dtim_period;
+++		if (elems->dtim_period)
+++			ifmgd->dtim_period = elems->dtim_period;
++ 		ifmgd->have_beacon = true;
++ 		ifmgd->assoc_data->need_beacon = false;
++ 		if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
++@@ -4053,17 +4068,17 @@ static void ieee80211_rx_mgmt_beacon(str
++ 				le64_to_cpu(mgmt->u.beacon.timestamp);
++ 			sdata->vif.bss_conf.sync_device_ts =
++ 				rx_status->device_timestamp;
++-			sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
+++			sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
++ 		}
++ 
++-		if (elems.mbssid_config_ie)
+++		if (elems->mbssid_config_ie)
++ 			bss_conf->profile_periodicity =
++-				elems.mbssid_config_ie->profile_periodicity;
+++				elems->mbssid_config_ie->profile_periodicity;
++ 		else
++ 			bss_conf->profile_periodicity = 0;
++ 
++-		if (elems.ext_capab_len >= 11 &&
++-		    (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
+++		if (elems->ext_capab_len >= 11 &&
+++		    (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
++ 			bss_conf->ema_ap = true;
++ 		else
++ 			bss_conf->ema_ap = false;
++@@ -4072,6 +4087,7 @@ static void ieee80211_rx_mgmt_beacon(str
++ 		ifmgd->assoc_data->timeout = jiffies;
++ 		ifmgd->assoc_data->timeout_started = true;
++ 		run_again(sdata, ifmgd->assoc_data->timeout);
+++		kfree(elems);
++ 		return;
++ 	}
++ 
++@@ -4103,14 +4119,15 @@ static void ieee80211_rx_mgmt_beacon(str
++ 	 */
++ 	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
++ 		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
++-	ieee802_11_parse_elems_crc(variable,
++-				   len - baselen, false, &elems,
++-				   care_about_ies, ncrc,
++-				   mgmt->bssid, bssid);
++-	ncrc = elems.crc;
+++	elems = ieee802_11_parse_elems_crc(variable, len - baselen,
+++					   false, care_about_ies, ncrc,
+++					   mgmt->bssid, bssid);
+++	if (!elems)
+++		return;
+++	ncrc = elems->crc;
++ 
++ 	if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
++-	    ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
+++	    ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) {
++ 		if (local->hw.conf.dynamic_ps_timeout > 0) {
++ 			if (local->hw.conf.flags & IEEE80211_CONF_PS) {
++ 				local->hw.conf.flags &= ~IEEE80211_CONF_PS;
++@@ -4180,12 +4197,12 @@ static void ieee80211_rx_mgmt_beacon(str
++ 			le64_to_cpu(mgmt->u.beacon.timestamp);
++ 		sdata->vif.bss_conf.sync_device_ts =
++ 			rx_status->device_timestamp;
++-		sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
+++		sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
++ 	}
++ 
++ 	if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) ||
++ 	    ieee80211_is_s1g_short_beacon(mgmt->frame_control))
++-		return;
+++		goto free;
++ 	ifmgd->beacon_crc = ncrc;
++ 	ifmgd->beacon_crc_valid = true;
++ 
++@@ -4193,12 +4210,12 @@ static void ieee80211_rx_mgmt_beacon(str
++ 
++ 	ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
++ 					 rx_status->device_timestamp,
++-					 &elems, true);
+++					 elems, true);
++ 
++ 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
++-	    ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
++-				     elems.wmm_param_len,
++-				     elems.mu_edca_param_set))
+++	    ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
+++				     elems->wmm_param_len,
+++				     elems->mu_edca_param_set))
++ 		changed |= BSS_CHANGED_QOS;
++ 
++ 	/*
++@@ -4207,7 +4224,7 @@ static void ieee80211_rx_mgmt_beacon(str
++ 	 */
++ 	if (!ifmgd->have_beacon) {
++ 		/* a few bogus AP send dtim_period = 0 or no TIM IE */
++-		bss_conf->dtim_period = elems.dtim_period ?: 1;
+++		bss_conf->dtim_period = elems->dtim_period ?: 1;
++ 
++ 		changed |= BSS_CHANGED_BEACON_INFO;
++ 		ifmgd->have_beacon = true;
++@@ -4219,9 +4236,9 @@ static void ieee80211_rx_mgmt_beacon(str
++ 		ieee80211_recalc_ps_vif(sdata);
++ 	}
++ 
++-	if (elems.erp_info) {
+++	if (elems->erp_info) {
++ 		erp_valid = true;
++-		erp_value = elems.erp_info[0];
+++		erp_value = elems->erp_info[0];
++ 	} else {
++ 		erp_valid = false;
++ 	}
++@@ -4234,12 +4251,12 @@ static void ieee80211_rx_mgmt_beacon(str
++ 	mutex_lock(&local->sta_mtx);
++ 	sta = sta_info_get(sdata, bssid);
++ 
++-	changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
+++	changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
++ 
++-	if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
++-				elems.vht_cap_elem, elems.ht_operation,
++-				elems.vht_operation, elems.he_operation,
++-				elems.s1g_oper, bssid, &changed)) {
+++	if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem,
+++				elems->vht_cap_elem, elems->ht_operation,
+++				elems->vht_operation, elems->he_operation,
+++				elems->s1g_oper, bssid, &changed)) {
++ 		mutex_unlock(&local->sta_mtx);
++ 		sdata_info(sdata,
++ 			   "failed to follow AP %pM bandwidth change, disconnect\n",
++@@ -4251,21 +4268,23 @@ static void ieee80211_rx_mgmt_beacon(str
++ 					    sizeof(deauth_buf), true,
++ 					    WLAN_REASON_DEAUTH_LEAVING,
++ 					    false);
++-		return;
+++		goto free;
++ 	}
++ 
++-	if (sta && elems.opmode_notif)
++-		ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
+++	if (sta && elems->opmode_notif)
+++		ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif,
++ 					    rx_status->band);
++ 	mutex_unlock(&local->sta_mtx);
++ 
++ 	changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
++-					       elems.country_elem,
++-					       elems.country_elem_len,
++-					       elems.pwr_constr_elem,
++-					       elems.cisco_dtpc_elem);
+++					       elems->country_elem,
+++					       elems->country_elem_len,
+++					       elems->pwr_constr_elem,
+++					       elems->cisco_dtpc_elem);
++ 
++ 	ieee80211_bss_info_change_notify(sdata, changed);
+++free:
+++	kfree(elems);
++ }
++ 
++ void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
++@@ -4294,7 +4313,6 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 	struct ieee80211_rx_status *rx_status;
++ 	struct ieee80211_mgmt *mgmt;
++ 	u16 fc;
++-	struct ieee802_11_elems elems;
++ 	int ies_len;
++ 
++ 	rx_status = (struct ieee80211_rx_status *) skb->cb;
++@@ -4326,6 +4344,8 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 		break;
++ 	case IEEE80211_STYPE_ACTION:
++ 		if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
+++			struct ieee802_11_elems *elems;
+++
++ 			ies_len = skb->len -
++ 				  offsetof(struct ieee80211_mgmt,
++ 					   u.action.u.chan_switch.variable);
++@@ -4334,18 +4354,21 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 				break;
++ 
++ 			/* CSA IE cannot be overridden, no need for BSSID */
++-			ieee802_11_parse_elems(
++-				mgmt->u.action.u.chan_switch.variable,
++-				ies_len, true, &elems, mgmt->bssid, NULL);
+++			elems = ieee802_11_parse_elems(
+++					mgmt->u.action.u.chan_switch.variable,
+++					ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (elems.parse_error)
+++			if (!elems || elems->parse_error)
++ 				break;
++ 
++ 			ieee80211_sta_process_chanswitch(sdata,
++ 						 rx_status->mactime,
++ 						 rx_status->device_timestamp,
++-						 &elems, false);
+++						 elems, false);
+++			kfree(elems);
++ 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
+++			struct ieee802_11_elems *elems;
+++
++ 			ies_len = skb->len -
++ 				  offsetof(struct ieee80211_mgmt,
++ 					   u.action.u.ext_chan_switch.variable);
++@@ -4357,21 +4380,22 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 			 * extended CSA IE can't be overridden, no need for
++ 			 * BSSID
++ 			 */
++-			ieee802_11_parse_elems(
++-				mgmt->u.action.u.ext_chan_switch.variable,
++-				ies_len, true, &elems, mgmt->bssid, NULL);
+++			elems = ieee802_11_parse_elems(
+++					mgmt->u.action.u.ext_chan_switch.variable,
+++					ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (elems.parse_error)
+++			if (!elems || elems->parse_error)
++ 				break;
++ 
++ 			/* for the handling code pretend this was also an IE */
++-			elems.ext_chansw_ie =
+++			elems->ext_chansw_ie =
++ 				&mgmt->u.action.u.ext_chan_switch.data;
++ 
++ 			ieee80211_sta_process_chanswitch(sdata,
++ 						 rx_status->mactime,
++ 						 rx_status->device_timestamp,
++-						 &elems, false);
+++						 elems, false);
+++			kfree(elems);
++ 		}
++ 		break;
++ 	}
++--- a/net/mac80211/scan.c
+++++ b/net/mac80211/scan.c
++@@ -9,7 +9,7 @@
++  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
++  * Copyright 2013-2015  Intel Mobile Communications GmbH
++  * Copyright 2016-2017  Intel Deutschland GmbH
++- * Copyright (C) 2018-2020 Intel Corporation
+++ * Copyright (C) 2018-2021 Intel Corporation
++  */
++ 
++ #include <linux/if_arp.h>
++@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802
++ 	};
++ 	bool signal_valid;
++ 	struct ieee80211_sub_if_data *scan_sdata;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	size_t baselen;
++ 	u8 *elements;
++ 
++@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802
++ 	if (baselen > len)
++ 		return NULL;
++ 
++-	ieee802_11_parse_elems(elements, len - baselen, false, &elems,
++-			       mgmt->bssid, cbss->bssid);
+++	elems = ieee802_11_parse_elems(elements, len - baselen, false,
+++				       mgmt->bssid, cbss->bssid);
+++	if (!elems)
+++		return NULL;
++ 
++ 	/* In case the signal is invalid update the status */
++ 	signal_valid = channel == cbss->channel;
++@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802
++ 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
++ 
++ 	bss = (void *)cbss->priv;
++-	ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
+++	ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon);
++ 
++ 	list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
++ 		non_tx_bss = (void *)non_tx_cbss->priv;
++ 
++-		ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
+++		ieee80211_update_bss_from_elems(local, non_tx_bss, elems,
++ 						rx_status, beacon);
++ 	}
++ 
+++	kfree(elems);
+++
++ 	return bss;
++ }
++ 
++--- a/net/mac80211/tdls.c
+++++ b/net/mac80211/tdls.c
++@@ -6,7 +6,7 @@
++  * Copyright 2014, Intel Corporation
++  * Copyright 2014  Intel Mobile Communications GmbH
++  * Copyright 2015 - 2016 Intel Deutschland GmbH
++- * Copyright (C) 2019 Intel Corporation
+++ * Copyright (C) 2019, 2021 Intel Corporation
++  */
++ 
++ #include <linux/ieee80211.h>
++@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re
++ 					   struct sk_buff *skb)
++ {
++ 	struct ieee80211_local *local = sdata->local;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems = NULL;
++ 	struct sta_info *sta;
++ 	struct ieee80211_tdls_data *tf = (void *)skb->data;
++ 	bool local_initiator;
++@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re
++ 		goto call_drv;
++ 	}
++ 
++-	ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
++-			       skb->len - baselen, false, &elems,
++-			       NULL, NULL);
++-	if (elems.parse_error) {
+++	elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
+++				       skb->len - baselen, false, NULL, NULL);
+++	if (!elems) {
+++		ret = -ENOMEM;
+++		goto out;
+++	}
+++
+++	if (elems->parse_error) {
++ 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
++ 		ret = -EINVAL;
++ 		goto out;
++ 	}
++ 
++-	if (!elems.ch_sw_timing || !elems.lnk_id) {
+++	if (!elems->ch_sw_timing || !elems->lnk_id) {
++ 		tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n");
++ 		ret = -EINVAL;
++ 		goto out;
++@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re
++ 
++ 	/* validate the initiator is set correctly */
++ 	local_initiator =
++-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
+++		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
++ 	if (local_initiator == sta->sta.tdls_initiator) {
++ 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
++ 		ret = -EINVAL;
++ 		goto out;
++ 	}
++ 
++-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
++-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
+++	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
+++	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
++ 
++ 	params.tmpl_skb =
++ 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta, &params.ch_sw_tm_ie);
++@@ -1763,6 +1767,7 @@ call_drv:
++ out:
++ 	mutex_unlock(&local->sta_mtx);
++ 	dev_kfree_skb_any(params.tmpl_skb);
+++	kfree(elems);
++ 	return ret;
++ }
++ 
++@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re
++ 					  struct sk_buff *skb)
++ {
++ 	struct ieee80211_local *local = sdata->local;
++-	struct ieee802_11_elems elems;
+++	struct ieee802_11_elems *elems;
++ 	struct cfg80211_chan_def chandef;
++ 	struct ieee80211_channel *chan;
++ 	enum nl80211_channel_type chan_type;
++@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re
++ 		return -EINVAL;
++ 	}
++ 
++-	ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
++-			       skb->len - baselen, false, &elems, NULL, NULL);
++-	if (elems.parse_error) {
+++	elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
+++				       skb->len - baselen, false, NULL, NULL);
+++	if (!elems)
+++		return -ENOMEM;
+++
+++	if (elems->parse_error) {
++ 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
++-		return -EINVAL;
+++		ret = -EINVAL;
+++		goto free;
++ 	}
++ 
++-	if (!elems.ch_sw_timing || !elems.lnk_id) {
+++	if (!elems->ch_sw_timing || !elems->lnk_id) {
++ 		tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n");
++-		return -EINVAL;
+++		ret = -EINVAL;
+++		goto free;
++ 	}
++ 
++-	if (!elems.sec_chan_offs) {
+++	if (!elems->sec_chan_offs) {
++ 		chan_type = NL80211_CHAN_HT20;
++ 	} else {
++-		switch (elems.sec_chan_offs->sec_chan_offs) {
+++		switch (elems->sec_chan_offs->sec_chan_offs) {
++ 		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
++ 			chan_type = NL80211_CHAN_HT40PLUS;
++ 			break;
++@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re
++ 	if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef,
++ 					   sdata->wdev.iftype)) {
++ 		tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n");
++-		return -EINVAL;
+++		ret = -EINVAL;
+++		goto free;
++ 	}
++ 
++ 	mutex_lock(&local->sta_mtx);
++@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re
++ 
++ 	/* validate the initiator is set correctly */
++ 	local_initiator =
++-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
+++		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
++ 	if (local_initiator == sta->sta.tdls_initiator) {
++ 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
++ 		ret = -EINVAL;
++@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re
++ 	}
++ 
++ 	/* peer should have known better */
++-	if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs &&
++-	    elems.sec_chan_offs->sec_chan_offs) {
+++	if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs &&
+++	    elems->sec_chan_offs->sec_chan_offs) {
++ 		tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n");
++ 		ret = -ENOTSUPP;
++ 		goto out;
++ 	}
++ 
++ 	params.chandef = &chandef;
++-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
++-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
+++	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
+++	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
++ 
++ 	params.tmpl_skb =
++ 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta,
++@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re
++ out:
++ 	mutex_unlock(&local->sta_mtx);
++ 	dev_kfree_skb_any(params.tmpl_skb);
+++free:
+++	kfree(elems);
++ 	return ret;
++ }
++ 
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -1399,8 +1399,8 @@ _ieee802_11_parse_elems_crc(const u8 *st
++ 
++ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
++ 					    struct ieee802_11_elems *elems,
++-					    u8 *transmitter_bssid,
++-					    u8 *bss_bssid,
+++					    const u8 *transmitter_bssid,
+++					    const u8 *bss_bssid,
++ 					    u8 *nontransmitted_profile)
++ {
++ 	const struct element *elem, *sub;
++@@ -1465,16 +1465,20 @@ static size_t ieee802_11_find_bssid_prof
++ 	return found ? profile_len : 0;
++ }
++ 
++-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++-				struct ieee802_11_elems *elems,
++-				u64 filter, u32 crc, u8 *transmitter_bssid,
++-				u8 *bss_bssid)
+++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
+++						    bool action, u64 filter,
+++						    u32 crc,
+++						    const u8 *transmitter_bssid,
+++						    const u8 *bss_bssid)
++ {
+++	struct ieee802_11_elems *elems;
++ 	const struct element *non_inherit = NULL;
++ 	u8 *nontransmitted_profile;
++ 	int nontransmitted_profile_len = 0;
++ 
++-	memset(elems, 0, sizeof(*elems));
+++	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
+++	if (!elems)
+++		return NULL;
++ 	elems->ie_start = start;
++ 	elems->total_len = len;
++ 
++@@ -1521,6 +1525,8 @@ void ieee802_11_parse_elems_crc(const u8
++ 	kfree(nontransmitted_profile);
++ 
++ 	elems->crc = crc;
+++
+++	return elems;
++ }
++ 
++ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
+diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
+deleted file mode 100644
+index 09f6fd2214..0000000000
+--- a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
++++ /dev/null
+@@ -1,767 +0,0 @@
+-From: Felix Fietkau <nbd@nbd.name>
+-Date: Fri, 22 Jan 2021 23:57:50 +0100
+-Subject: [PATCH] mac80211: minstrel_ht: significantly redesign the rate
+- probing strategy
+-
+-The biggest flaw in current minstrel_ht is the fact that it needs way too
+-many probing packets to be able to quickly find the best rate.
+-Depending on the wifi hardware and operating mode, this can significantly
+-reduce throughput when not operating at the highest available data rate.
+-
+-In order to be able to significantly reduce the amount of rate sampling,
+-we need a much smarter selection of probing rates.
+-
+-The new approach introduced by this patch maintains a limited set of
+-available rates to be tested during a statistics window.
+-
+-They are split into distinct categories:
+-- MINSTREL_SAMPLE_TYPE_INC - incremental rate upgrade:
+-  Pick the next rate group and find the first rate that is faster than
+-  the current max. throughput rate
+-- MINSTREL_SAMPLE_TYPE_JUMP - random testing of higher rates:
+-  Pick a random rate from the next group that is faster than the current
+-  max throughput rate. This allows faster adaptation when the link changes
+-  significantly
+-- MINSTREL_SAMPLE_TYPE_SLOW - test a rate between max_prob, max_tp2 and
+-  max_tp in order to reduce the gap between them
+-
+-In order to prioritize sampling, every 6 attempts are split into 3x INC,
+-2x JUMP, 1x SLOW.
+-
+-Available rates are checked and refilled on every stats window update.
+-
+-With this approach, we finally get a very small delta in throughput when
+-comparing setting the optimal data rate as a fixed rate vs normal rate
+-control operation.
+-
+-Signed-off-by: Felix Fietkau <nbd@nbd.name>
+----
+-
+---- a/net/mac80211/rc80211_minstrel_ht.c
+-+++ b/net/mac80211/rc80211_minstrel_ht.c
+-@@ -266,6 +266,14 @@ const struct mcs_group minstrel_mcs_grou
+- const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 };
+- const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 };
+- static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
+-+static const u8 minstrel_sample_seq[] = {
+-+	MINSTREL_SAMPLE_TYPE_INC,
+-+	MINSTREL_SAMPLE_TYPE_JUMP,
+-+	MINSTREL_SAMPLE_TYPE_INC,
+-+	MINSTREL_SAMPLE_TYPE_JUMP,
+-+	MINSTREL_SAMPLE_TYPE_INC,
+-+	MINSTREL_SAMPLE_TYPE_SLOW,
+-+};
+- 
+- static void
+- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
+-@@ -620,77 +628,31 @@ minstrel_ht_prob_rate_reduce_streams(str
+- 	}
+- }
+- 
+--static bool
+--minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group,
+--						int tp_idx, const struct mcs_group *group)
+--{
+--	if (group->bw < tp_group->bw)
+--		return false;
+--
+--	if (group->streams == tp_group->streams)
+--		return true;
+--
+--	if (tp_idx < 4 && group->streams == tp_group->streams - 1)
+--		return true;
+--
+--	return group->streams == tp_group->streams + 1;
+--}
+--
+--static void
+--minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates,
+--			     bool faster_rate)
+-+static u16
+-+__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
+-+			      enum minstrel_sample_type type)
+- {
+--	const struct mcs_group *group, *tp_group;
+--	int i, g, max_dur;
+--	int tp_idx;
+--
+--	tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])];
+--	tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]);
+--
+--	max_dur = minstrel_get_duration(mi->max_tp_rate[0]);
+--	if (faster_rate)
+--		max_dur -= max_dur / 16;
+--
+--	for (g = 0; g < MINSTREL_GROUPS_NB; g++) {
+--		u16 supported = mi->supported[g];
+--
+--		if (!supported)
+--			continue;
+-+	u16 *rates = mi->sample[type].sample_rates;
+-+	u16 cur;
+-+	int i;
+- 
+--		group = &minstrel_mcs_groups[g];
+--		if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group))
+-+	for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) {
+-+		if (!rates[i])
+- 			continue;
+- 
+--		for (i = 0; supported; supported >>= 1, i++) {
+--			int idx;
+--
+--			if (!(supported & 1))
+--				continue;
+--
+--			if ((group->duration[i] << group->shift) > max_dur)
+--				continue;
+--
+--			idx = MI_RATE(g, i);
+--			if (idx == mi->max_tp_rate[0])
+--				continue;
+--
+--			rates[(*n_rates)++] = idx;
+--			break;
+--		}
+-+		cur = rates[i];
+-+		rates[i] = 0;
+-+		return cur;
+- 	}
+-+
+-+	return 0;
+- }
+- 
+- static void
+- minstrel_ht_rate_sample_switch(struct minstrel_priv *mp,
+- 			       struct minstrel_ht_sta *mi)
+- {
+--	struct minstrel_rate_stats *mrs;
+--	u16 rates[MINSTREL_GROUPS_NB];
+--	int n_rates = 0;
+--	int probe_rate = 0;
+--	bool faster_rate;
+--	int i;
+--	u8 random;
+-+	u16 rate;
+- 
+- 	/*
+- 	 * Use rate switching instead of probing packets for devices with
+-@@ -699,43 +661,11 @@ minstrel_ht_rate_sample_switch(struct mi
+- 	if (mp->hw->max_rates > 1)
+- 		return;
+- 
+--	/*
+--	 * If the current EWMA prob is >75%, look for a rate that's 6.25%
+--	 * faster than the max tp rate.
+--	 * If that fails, look again for a rate that is at least as fast
+--	 */
+--	mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
+--	faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100);
+--	minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate);
+--	if (!n_rates && faster_rate)
+--		minstrel_ht_find_probe_rates(mi, rates, &n_rates, false);
+--
+--	/* If no suitable rate was found, try to pick the next one in the group */
+--	if (!n_rates) {
+--		int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]);
+--		u16 supported = mi->supported[g_idx];
+--
+--		supported >>= MI_RATE_IDX(mi->max_tp_rate[0]);
+--		for (i = 0; supported; supported >>= 1, i++) {
+--			if (!(supported & 1))
+--				continue;
+--
+--			probe_rate = mi->max_tp_rate[0] + i;
+--			goto out;
+--		}
+--
+-+	rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC);
+-+	if (!rate)
+- 		return;
+--	}
+--
+--	i = 0;
+--	if (n_rates > 1) {
+--		random = prandom_u32();
+--		i = random % n_rates;
+--	}
+--	probe_rate = rates[i];
+- 
+--out:
+--	mi->sample_rate = probe_rate;
+-+	mi->sample_rate = rate;
+- 	mi->sample_mode = MINSTREL_SAMPLE_ACTIVE;
+- }
+- 
 -@@ -804,6 +734,274 @@ minstrel_ht_calc_rate_stats(struct minst
 - 	mrs->attempts = 0;
 - }
@@ -18727,6 +20200,127 @@ index 09f6fd2214..0000000000
 - 	u8 band;
 - 
 - 	/* Bitfield of supported MCS rates of all groups */
+diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
+new file mode 100644
+index 0000000000..f4906e8c03
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
+@@ -0,0 +1,115 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Fri, 1 Oct 2021 21:11:08 +0200
++Subject: [PATCH] mac80211: fix memory leaks with element parsing
++
++commit 8223ac199a3849257e86ec27865dc63f034b1cf1 upstream.
++
++My previous commit 5d24828d05f3 ("mac80211: always allocate
++struct ieee802_11_elems") had a few bugs and leaked the new
++allocated struct in a few error cases, fix that.
++
++Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems")
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/agg-rx.c
+++++ b/net/mac80211/agg-rx.c
++@@ -499,13 +499,14 @@ void ieee80211_process_addba_request(str
++ 		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
++ 					       ies_len, true, mgmt->bssid, NULL);
++ 		if (!elems || elems->parse_error)
++-			return;
+++			goto free;
++ 	}
++ 
++ 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
++ 					start_seq_num, ba_policy, tid,
++ 					buf_size, true, false,
++ 					elems ? elems->addba_ext_ie : NULL);
+++free:
++ 	kfree(elems);
++ }
++ 
++--- a/net/mac80211/ibss.c
+++++ b/net/mac80211/ibss.c
++@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struc
++ 				mgmt->u.action.u.chan_switch.variable,
++ 				ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (!elems || elems->parse_error)
++-				break;
++-
++-			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
++-							rx_status, elems);
+++			if (elems && !elems->parse_error)
+++				ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
+++								skb->len,
+++								rx_status,
+++								elems);
++ 			kfree(elems);
++ 			break;
++ 		}
++--- a/net/mac80211/mlme.c
+++++ b/net/mac80211/mlme.c
++@@ -3374,8 +3374,10 @@ static bool ieee80211_assoc_success(stru
++ 			bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
++ 					  GFP_ATOMIC);
++ 		rcu_read_unlock();
++-		if (!bss_ies)
++-			return false;
+++		if (!bss_ies) {
+++			ret = false;
+++			goto out;
+++		}
++ 
++ 		bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
++ 						   false, mgmt->bssid,
++@@ -4358,13 +4360,11 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 					mgmt->u.action.u.chan_switch.variable,
++ 					ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (!elems || elems->parse_error)
++-				break;
++-
++-			ieee80211_sta_process_chanswitch(sdata,
++-						 rx_status->mactime,
++-						 rx_status->device_timestamp,
++-						 elems, false);
+++			if (elems && !elems->parse_error)
+++				ieee80211_sta_process_chanswitch(sdata,
+++								 rx_status->mactime,
+++								 rx_status->device_timestamp,
+++								 elems, false);
++ 			kfree(elems);
++ 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
++ 			struct ieee802_11_elems *elems;
++@@ -4384,17 +4384,17 @@ void ieee80211_sta_rx_queued_mgmt(struct
++ 					mgmt->u.action.u.ext_chan_switch.variable,
++ 					ies_len, true, mgmt->bssid, NULL);
++ 
++-			if (!elems || elems->parse_error)
++-				break;
+++			if (elems && !elems->parse_error) {
+++				/* for the handling code pretend it was an IE */
+++				elems->ext_chansw_ie =
+++					&mgmt->u.action.u.ext_chan_switch.data;
+++
+++				ieee80211_sta_process_chanswitch(sdata,
+++								 rx_status->mactime,
+++								 rx_status->device_timestamp,
+++								 elems, false);
+++			}
++ 
++-			/* for the handling code pretend this was also an IE */
++-			elems->ext_chansw_ie =
++-				&mgmt->u.action.u.ext_chan_switch.data;
++-
++-			ieee80211_sta_process_chanswitch(sdata,
++-						 rx_status->mactime,
++-						 rx_status->device_timestamp,
++-						 elems, false);
++ 			kfree(elems);
++ 		}
++ 		break;
 diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch
 deleted file mode 100644
 index 041ba31a37..0000000000
@@ -19076,6 +20670,53 @@ index 8170ff85f8..0000000000
 - 
 - 	/* Bitfield of supported MCS rates of all groups */
 - 	u16 supported[MINSTREL_GROUPS_NB];
+diff --git a/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch b/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
+new file mode 100644
+index 0000000000..9e1f781367
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
+@@ -0,0 +1,41 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 28 Sep 2022 21:56:15 +0200
++Subject: [PATCH] wifi: cfg80211: fix u8 overflow in
++ cfg80211_update_notlisted_nontrans()
++
++commit aebe9f4639b13a1f4e9a6b42cdd2e38c617b442d upstream.
++
++In the copy code of the elements, we do the following calculation
++to reach the end of the MBSSID element:
++
++	/* copy the IEs after MBSSID */
++	cpy_len = mbssid[1] + 2;
++
++This looks fine, however, cpy_len is a u8, the same as mbssid[1],
++so the addition of two can overflow. In this case the subsequent
++memcpy() will overflow the allocated buffer, since it copies 256
++bytes too much due to the way the allocation and memcpy() sizes
++are calculated.
++
++Fix this by using size_t for the cpy_len variable.
++
++This fixes CVE-2022-41674.
++
++Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
++Tested-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
++Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
++Reviewed-by: Kees Cook <keescook@chromium.org>
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -2238,7 +2238,7 @@ cfg80211_update_notlisted_nontrans(struc
++ 	size_t new_ie_len;
++ 	struct cfg80211_bss_ies *new_ies;
++ 	const struct cfg80211_bss_ies *old;
++-	u8 cpy_len;
+++	size_t cpy_len;
++ 
++ 	lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch b/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch
 deleted file mode 100644
 index a366a921d4..0000000000
@@ -19105,6 +20746,736 @@ index a366a921d4..0000000000
 - 
 - 		max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
 - 							max_gpr_idx,
+diff --git a/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch b/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
+new file mode 100644
+index 0000000000..4c8e05e9ba
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
+@@ -0,0 +1,47 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 28 Sep 2022 22:01:37 +0200
++Subject: [PATCH] wifi: cfg80211/mac80211: reject bad MBSSID elements
++
++commit 8f033d2becc24aa6bfd2a5c104407963560caabc upstream
++
++Per spec, the maximum value for the MaxBSSID ('n') indicator is 8,
++and the minimum is 1 since a multiple BSSID set with just one BSSID
++doesn't make sense (the # of BSSIDs is limited by 2^n).
++
++Limit this in the parsing in both cfg80211 and mac80211, rejecting
++any elements with an invalid value.
++
++This fixes potentially bad shifts in the processing of these inside
++the cfg80211_gen_new_bssid() function later.
++
++I found this during the investigation of CVE-2022-41674 fixed by the
++previous patch.
++
++Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
++Fixes: 78ac51f81532 ("mac80211: support multi-bssid")
++Reviewed-by: Kees Cook <keescook@chromium.org>
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -1413,6 +1413,8 @@ static size_t ieee802_11_find_bssid_prof
++ 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
++ 		if (elem->datalen < 2)
++ 			continue;
+++		if (elem->data[0] < 1 || elem->data[0] > 8)
+++			continue;
++ 
++ 		for_each_element(sub, elem->data + 1, elem->datalen - 1) {
++ 			u8 new_bssid[ETH_ALEN];
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -2103,6 +2103,8 @@ static void cfg80211_parse_mbssid_data(s
++ 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
++ 		if (elem->datalen < 4)
++ 			continue;
+++		if (elem->data[0] < 1 || (int)elem->data[0] > 8)
+++			continue;
++ 		for_each_element(sub, elem->data + 1, elem->datalen - 1) {
++ 			u8 profile_len;
++ 
+diff --git a/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch b/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
+new file mode 100644
+index 0000000000..6e97150e90
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
+@@ -0,0 +1,94 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 28 Sep 2022 22:07:15 +0200
++Subject: [PATCH] wifi: mac80211: fix MBSSID parsing use-after-free
++
++commit ff05d4b45dd89b922578dac497dcabf57cf771c6
++
++When we parse a multi-BSSID element, we might point some
++element pointers into the allocated nontransmitted_profile.
++However, we free this before returning, causing UAF when the
++relevant pointers in the parsed elements are accessed.
++
++Fix this by not allocating the scratch buffer separately but
++as part of the returned structure instead, that way, there
++are no lifetime issues with it.
++
++The scratch buffer introduction as part of the returned data
++here is taken from MLO feature work done by Ilan.
++
++This fixes CVE-2022-42719.
++
++Fixes: 5023b14cf4df ("mac80211: support profile split between elements")
++Co-developed-by: Ilan Peer <ilan.peer@intel.com>
++Signed-off-by: Ilan Peer <ilan.peer@intel.com>
++Reviewed-by: Kees Cook <keescook@chromium.org>
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -1611,6 +1611,14 @@ struct ieee802_11_elems {
++ 
++ 	/* whether a parse error occurred while retrieving these elements */
++ 	bool parse_error;
+++
+++	/*
+++	 * scratch buffer that can be used for various element parsing related
+++	 * tasks, e.g., element de-fragmentation etc.
+++	 */
+++	size_t scratch_len;
+++	u8 *scratch_pos;
+++	u8 scratch[];
++ };
++ 
++ static inline struct ieee80211_local *hw_to_local(
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -1478,24 +1478,25 @@ struct ieee802_11_elems *ieee802_11_pars
++ 	u8 *nontransmitted_profile;
++ 	int nontransmitted_profile_len = 0;
++ 
++-	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
+++	elems = kzalloc(sizeof(*elems) + len, GFP_ATOMIC);
++ 	if (!elems)
++ 		return NULL;
++ 	elems->ie_start = start;
++ 	elems->total_len = len;
++ 
++-	nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
++-	if (nontransmitted_profile) {
++-		nontransmitted_profile_len =
++-			ieee802_11_find_bssid_profile(start, len, elems,
++-						      transmitter_bssid,
++-						      bss_bssid,
++-						      nontransmitted_profile);
++-		non_inherit =
++-			cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
++-					       nontransmitted_profile,
++-					       nontransmitted_profile_len);
++-	}
+++	elems->scratch_len = len;
+++	elems->scratch_pos = elems->scratch;
+++
+++	nontransmitted_profile = elems->scratch_pos;
+++	nontransmitted_profile_len =
+++		ieee802_11_find_bssid_profile(start, len, elems,
+++					      transmitter_bssid,
+++					      bss_bssid,
+++					      nontransmitted_profile);
+++	non_inherit =
+++		cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
+++				       nontransmitted_profile,
+++				       nontransmitted_profile_len);
++ 
++ 	crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
++ 					  crc, non_inherit);
++@@ -1524,8 +1525,6 @@ struct ieee802_11_elems *ieee802_11_pars
++ 	    offsetofend(struct ieee80211_bssid_index, dtim_count))
++ 		elems->dtim_count = elems->bssid_index->dtim_count;
++ 
++-	kfree(nontransmitted_profile);
++-
++ 	elems->crc = crc;
++ 
++ 	return elems;
+diff --git a/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch b/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
+new file mode 100644
+index 0000000000..da94840dac
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
+@@ -0,0 +1,41 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Thu, 29 Sep 2022 21:50:44 +0200
++Subject: [PATCH] wifi: cfg80211: ensure length byte is present before
++ access
++
++commit 567e14e39e8f8c6997a1378bc3be615afca86063 upstream.
++
++When iterating the elements here, ensure the length byte is
++present before checking it to see if the entire element will
++fit into the buffer.
++
++Longer term, we should rewrite this code using the type-safe
++element iteration macros that check all of this.
++
++Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
++Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -304,7 +304,8 @@ static size_t cfg80211_gen_new_ie(const
++ 	tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
++ 	tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
++ 
++-	while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
+++	while (tmp_old + 2 - ie <= ielen &&
+++	       tmp_old + tmp_old[1] + 2 - ie <= ielen) {
++ 		if (tmp_old[0] == 0) {
++ 			tmp_old++;
++ 			continue;
++@@ -364,7 +365,8 @@ static size_t cfg80211_gen_new_ie(const
++ 	 * copied to new ie, skip ssid, capability, bssid-index ie
++ 	 */
++ 	tmp_new = sub_copy;
++-	while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
+++	while (tmp_new + 2 - sub_copy <= subie_len &&
+++	       tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
++ 		if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
++ 		      tmp_new[0] == WLAN_EID_SSID)) {
++ 			memcpy(pos, tmp_new, tmp_new[1] + 2);
+diff --git a/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch b/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
+new file mode 100644
+index 0000000000..4680e1e815
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
+@@ -0,0 +1,87 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Fri, 30 Sep 2022 23:44:23 +0200
++Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream.
++
++There are multiple refcounting bugs related to multi-BSSID:
++ - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then
++   the bss pointer is overwritten before checking for the
++   transmitted BSS, which is clearly wrong. Fix this by using
++   the bss_from_pub() macro.
++
++ - In cfg80211_bss_update() we copy the transmitted_bss pointer
++   from tmp into new, but then if we release new, we'll unref
++   it erroneously. We already set the pointer and ref it, but
++   need to NULL it since it was copied from the tmp data.
++
++ - In cfg80211_inform_single_bss_data(), if adding to the non-
++   transmitted list fails, we unlink the BSS and yet still we
++   return it, but this results in returning an entry without
++   a reference. We shouldn't return it anyway if it was broken
++   enough to not get added there.
++
++This fixes CVE-2022-42720.
++
++Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS")
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf
++ 	lockdep_assert_held(&rdev->bss_lock);
++ 
++ 	bss->refcount++;
++-	if (bss->pub.hidden_beacon_bss) {
++-		bss = container_of(bss->pub.hidden_beacon_bss,
++-				   struct cfg80211_internal_bss,
++-				   pub);
++-		bss->refcount++;
++-	}
++-	if (bss->pub.transmitted_bss) {
++-		bss = container_of(bss->pub.transmitted_bss,
++-				   struct cfg80211_internal_bss,
++-				   pub);
++-		bss->refcount++;
++-	}
+++
+++	if (bss->pub.hidden_beacon_bss)
+++		bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
+++
+++	if (bss->pub.transmitted_bss)
+++		bss_from_pub(bss->pub.transmitted_bss)->refcount++;
++ }
++ 
++ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
++@@ -1743,6 +1737,8 @@ cfg80211_bss_update(struct cfg80211_regi
++ 		new->refcount = 1;
++ 		INIT_LIST_HEAD(&new->hidden_list);
++ 		INIT_LIST_HEAD(&new->pub.nontrans_list);
+++		/* we'll set this later if it was non-NULL */
+++		new->pub.transmitted_bss = NULL;
++ 
++ 		if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
++ 			hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
++@@ -1983,10 +1979,15 @@ cfg80211_inform_single_bss_data(struct w
++ 		spin_lock_bh(&rdev->bss_lock);
++ 		if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
++ 					       &res->pub)) {
++-			if (__cfg80211_unlink_bss(rdev, res))
+++			if (__cfg80211_unlink_bss(rdev, res)) {
++ 				rdev->bss_generation++;
+++				res = NULL;
+++			}
++ 		}
++ 		spin_unlock_bh(&rdev->bss_lock);
+++
+++		if (!res)
+++			return NULL;
++ 	}
++ 
++ 	trace_cfg80211_return_bss(&res->pub);
+diff --git a/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch b/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
+new file mode 100644
+index 0000000000..db0e51edc2
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
+@@ -0,0 +1,48 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Sat, 1 Oct 2022 00:01:44 +0200
++Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list
++ corruption
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++commit bcca852027e5878aec911a347407ecc88d6fff7f upstream.
++
++If a non-transmitted BSS shares enough information (both
++SSID and BSSID!) with another non-transmitted BSS of a
++different AP, then we can find and update it, and then
++try to add it to the non-transmitted BSS list. We do a
++search for it on the transmitted BSS, but if it's not
++there (but belongs to another transmitted BSS), the list
++gets corrupted.
++
++Since this is an erroneous situation, simply fail the
++list insertion in this case and free the non-transmitted
++BSS.
++
++This fixes CVE-2022-42721.
++
++Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -425,6 +425,15 @@ cfg80211_add_nontrans_list(struct cfg802
++ 
++ 	rcu_read_unlock();
++ 
+++	/*
+++	 * This is a bit weird - it's not on the list, but already on another
+++	 * one! The only way that could happen is if there's some BSSID/SSID
+++	 * shared by multiple APs in their multi-BSSID profiles, potentially
+++	 * with hidden SSID mixed in ... ignore it.
+++	 */
+++	if (!list_empty(&nontrans_bss->nontrans_list))
+++		return -EINVAL;
+++
++ 	/* add to the list */
++ 	list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
++ 	return 0;
+diff --git a/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch b/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
+new file mode 100644
+index 0000000000..ed834ff296
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
+@@ -0,0 +1,31 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 5 Oct 2022 15:10:09 +0200
++Subject: [PATCH] wifi: mac80211_hwsim: avoid mac80211 warning on bad
++ rate
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++commit 1833b6f46d7e2830251a063935ab464256defe22 upstream.
++
++If the tool on the other side (e.g. wmediumd) gets confused
++about the rate, we hit a warning in mac80211. Silence that
++by effectively duplicating the check here and dropping the
++frame silently (in mac80211 it's dropped with the warning).
++
++Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/drivers/net/wireless/mac80211_hwsim.c
+++++ b/drivers/net/wireless/mac80211_hwsim.c
++@@ -3760,6 +3760,8 @@ static int hwsim_cloned_frame_received_n
++ 
++ 	rx_status.band = channel->band;
++ 	rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
+++	if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
+++		goto out;
++ 	rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
++ 
++ 	hdr = (void *)skb->data;
+diff --git a/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
+new file mode 100644
+index 0000000000..44b8729977
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
+@@ -0,0 +1,52 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 5 Oct 2022 21:24:10 +0200
++Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for
++ P2P-device
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream.
++
++If beacon protection is active but the beacon cannot be
++decrypted or is otherwise malformed, we call the cfg80211
++API to report this to userspace, but that uses a netdev
++pointer, which isn't present for P2P-Device. Fix this to
++call it only conditionally to ensure cfg80211 won't crash
++in the case of P2P-Device.
++
++This fixes CVE-2022-42722.
++
++Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space")
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/rx.c
+++++ b/net/mac80211/rx.c
++@@ -1986,10 +1986,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_
++ 
++ 		if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
++ 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
++-		    NUM_DEFAULT_BEACON_KEYS) {
++-			cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
++-						     skb->data,
++-						     skb->len);
+++				   NUM_DEFAULT_BEACON_KEYS) {
+++			if (rx->sdata->dev)
+++				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+++							     skb->data,
+++							     skb->len);
++ 			return RX_DROP_MONITOR; /* unexpected BIP keyidx */
++ 		}
++ 
++@@ -2137,7 +2138,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_
++ 	/* either the frame has been decrypted or will be dropped */
++ 	status->flag |= RX_FLAG_DECRYPTED;
++ 
++-	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
+++	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
+++		     rx->sdata->dev))
++ 		cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
++ 					     skb->data, skb->len);
++ 
+diff --git a/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch b/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
+new file mode 100644
+index 0000000000..c689fac854
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
+@@ -0,0 +1,85 @@
++From: Johannes Berg <johannes.berg@intel.com>
++Date: Wed, 5 Oct 2022 23:11:43 +0200
++Subject: [PATCH] wifi: cfg80211: update hidden BSSes to avoid WARN_ON
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream.
++
++When updating beacon elements in a non-transmitted BSS,
++also update the hidden sub-entries to the same beacon
++elements, so that a future update through other paths
++won't trigger a WARN_ON().
++
++The warning is triggered because the beacon elements in
++the hidden BSSes that are children of the BSS should
++always be the same as in the parent.
++
++Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
++Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/scan.c
+++++ b/net/wireless/scan.c
++@@ -1609,6 +1609,23 @@ struct cfg80211_non_tx_bss {
++ 	u8 bssid_index;
++ };
++ 
+++static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
+++					 const struct cfg80211_bss_ies *new_ies,
+++					 const struct cfg80211_bss_ies *old_ies)
+++{
+++	struct cfg80211_internal_bss *bss;
+++
+++	/* Assign beacon IEs to all sub entries */
+++	list_for_each_entry(bss, &known->hidden_list, hidden_list) {
+++		const struct cfg80211_bss_ies *ies;
+++
+++		ies = rcu_access_pointer(bss->pub.beacon_ies);
+++		WARN_ON(ies != old_ies);
+++
+++		rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
+++	}
+++}
+++
++ static bool
++ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
++ 			  struct cfg80211_internal_bss *known,
++@@ -1632,7 +1649,6 @@ cfg80211_update_known_bss(struct cfg8021
++ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
++ 	} else if (rcu_access_pointer(new->pub.beacon_ies)) {
++ 		const struct cfg80211_bss_ies *old;
++-		struct cfg80211_internal_bss *bss;
++ 
++ 		if (known->pub.hidden_beacon_bss &&
++ 		    !list_empty(&known->hidden_list)) {
++@@ -1660,16 +1676,7 @@ cfg80211_update_known_bss(struct cfg8021
++ 		if (old == rcu_access_pointer(known->pub.ies))
++ 			rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
++ 
++-		/* Assign beacon IEs to all sub entries */
++-		list_for_each_entry(bss, &known->hidden_list, hidden_list) {
++-			const struct cfg80211_bss_ies *ies;
++-
++-			ies = rcu_access_pointer(bss->pub.beacon_ies);
++-			WARN_ON(ies != old);
++-
++-			rcu_assign_pointer(bss->pub.beacon_ies,
++-					   new->pub.beacon_ies);
++-		}
+++		cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
++ 
++ 		if (old)
++ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
++@@ -2319,6 +2326,8 @@ cfg80211_update_notlisted_nontrans(struc
++ 	} else {
++ 		old = rcu_access_pointer(nontrans_bss->beacon_ies);
++ 		rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
+++		cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
+++					     new_ies, old);
++ 		rcu_assign_pointer(nontrans_bss->ies, new_ies);
++ 		if (old)
++ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
+diff --git a/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch b/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+new file mode 100644
+index 0000000000..ff3cb7be53
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+@@ -0,0 +1,77 @@
++From 4db561ae4a90c2d0e15996634567559e292dc9e5 Mon Sep 17 00:00:00 2001
++From: Ahmed Zaki <anzaki@gmail.com>
++Date: Sat, 2 Oct 2021 08:53:29 -0600
++Subject: [PATCH] mac80211: fix a memory leak where sta_info is not freed
++
++commit 8f9dcc29566626f683843ccac6113a12208315ca upstream.
++
++The following is from a system that went OOM due to a memory leak:
++
++wlan0: Allocated STA 74:83:c2:64:0b:87
++wlan0: Allocated STA 74:83:c2:64:0b:87
++wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta)
++wlan0: Adding new IBSS station 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 3
++wlan0: Inserted STA 74:83:c2:64:0b:87
++wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work)
++wlan0: Adding new IBSS station 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 3
++.
++.
++wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 1
++wlan0: Removed STA 74:83:c2:64:0b:87
++wlan0: Destroyed STA 74:83:c2:64:0b:87
++
++The ieee80211_ibss_finish_sta() is called twice on the same STA from 2
++different locations. On the second attempt, the allocated STA is not
++destroyed creating a kernel memory leak.
++
++This is happening because sta_info_insert_finish() does not call
++sta_info_free() the second time when the STA already exists (returns
++-EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is
++destroyed upon errors.
++
++Same fix is applied to -ENOMEM.
++
++Signed-off-by: Ahmed Zaki <anzaki@gmail.com>
++Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com
++[change the error path label to use the existing code]
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Viacheslav Sablin <sablin@ispras.ru>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/sta_info.c | 6 +++---
++ 1 file changed, 3 insertions(+), 3 deletions(-)
++
++--- a/net/mac80211/sta_info.c
+++++ b/net/mac80211/sta_info.c
++@@ -646,13 +646,13 @@ static int sta_info_insert_finish(struct
++ 	/* check if STA exists already */
++ 	if (sta_info_get_bss(sdata, sta->sta.addr)) {
++ 		err = -EEXIST;
++-		goto out_err;
+++		goto out_cleanup;
++ 	}
++ 
++ 	sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
++ 	if (!sinfo) {
++ 		err = -ENOMEM;
++-		goto out_err;
+++		goto out_cleanup;
++ 	}
++ 
++ 	local->num_sta++;
++@@ -708,8 +708,8 @@ static int sta_info_insert_finish(struct
++  out_drop_sta:
++ 	local->num_sta--;
++ 	synchronize_net();
+++ out_cleanup:
++ 	cleanup_single_sta(sta);
++- out_err:
++ 	mutex_unlock(&local->sta_mtx);
++ 	kfree(sinfo);
++ 	rcu_read_lock();
+diff --git a/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch b/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+new file mode 100644
+index 0000000000..dd3e934c00
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+@@ -0,0 +1,47 @@
++From 552ba102a6898630a7d16887f29e606d6fabe508 Mon Sep 17 00:00:00 2001
++From: Siddh Raman Pant <code@siddh.me>
++Date: Sun, 14 Aug 2022 20:45:12 +0530
++Subject: [PATCH] wifi: mac80211: Don't finalize CSA in IBSS mode if state is
++ disconnected
++
++commit 15bc8966b6d3a5b9bfe4c9facfa02f2b69b1e5f0 upstream.
++
++When we are not connected to a channel, sending channel "switch"
++announcement doesn't make any sense.
++
++The BSS list is empty in that case. This causes the for loop in
++cfg80211_get_bss() to be bypassed, so the function returns NULL
++(check line 1424 of net/wireless/scan.c), causing the WARN_ON()
++in ieee80211_ibss_csa_beacon() to get triggered (check line 500
++of net/mac80211/ibss.c), which was consequently reported on the
++syzkaller dashboard.
++
++Thus, check if we have an existing connection before generating
++the CSA beacon in ieee80211_ibss_finish_csa().
++
++Cc: stable@vger.kernel.org
++Fixes: cd7760e62c2a ("mac80211: add support for CSA in IBSS mode")
++Link: https://syzkaller.appspot.com/bug?id=05603ef4ae8926761b678d2939a3b2ad28ab9ca6
++Reported-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
++Signed-off-by: Siddh Raman Pant <code@siddh.me>
++Tested-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
++Link: https://lore.kernel.org/r/20220814151512.9985-1-code@siddh.me
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/ibss.c | 4 ++++
++ 1 file changed, 4 insertions(+)
++
++--- a/net/mac80211/ibss.c
+++++ b/net/mac80211/ibss.c
++@@ -534,6 +534,10 @@ int ieee80211_ibss_finish_csa(struct iee
++ 
++ 	sdata_assert_lock(sdata);
++ 
+++	/* When not connected/joined, sending CSA doesn't make sense. */
+++	if (ifibss->state != IEEE80211_IBSS_MLME_JOINED)
+++		return -ENOLINK;
+++
++ 	/* update cfg80211 bss information with the new channel */
++ 	if (!is_zero_ether_addr(ifibss->bssid)) {
++ 		cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
+diff --git a/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch b/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+new file mode 100644
+index 0000000000..50b6b94fbf
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+@@ -0,0 +1,55 @@
++From 5d20c6f932f2758078d0454729129c894fe353e7 Mon Sep 17 00:00:00 2001
++From: Siddh Raman Pant <code@siddh.me>
++Date: Sat, 20 Aug 2022 01:33:40 +0530
++Subject: [PATCH] wifi: mac80211: Fix UAF in ieee80211_scan_rx()
++
++commit 60deb9f10eec5c6a20252ed36238b55d8b614a2c upstream.
++
++ieee80211_scan_rx() tries to access scan_req->flags after a
++null check, but a UAF is observed when the scan is completed
++and __ieee80211_scan_completed() executes, which then calls
++cfg80211_scan_done() leading to the freeing of scan_req.
++
++Since scan_req is rcu_dereference()'d, prevent the racing in
++__ieee80211_scan_completed() by ensuring that from mac80211's
++POV it is no longer accessed from an RCU read critical section
++before we call cfg80211_scan_done().
++
++Cc: stable@vger.kernel.org
++Link: https://syzkaller.appspot.com/bug?extid=f9acff9bf08a845f225d
++Reported-by: syzbot+f9acff9bf08a845f225d@syzkaller.appspotmail.com
++Suggested-by: Johannes Berg <johannes@sipsolutions.net>
++Signed-off-by: Siddh Raman Pant <code@siddh.me>
++Link: https://lore.kernel.org/r/20220819200340.34826-1-code@siddh.me
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/scan.c | 11 +++++++----
++ 1 file changed, 7 insertions(+), 4 deletions(-)
++
++--- a/net/mac80211/scan.c
+++++ b/net/mac80211/scan.c
++@@ -465,16 +465,19 @@ static void __ieee80211_scan_completed(s
++ 	scan_req = rcu_dereference_protected(local->scan_req,
++ 					     lockdep_is_held(&local->mtx));
++ 
++-	if (scan_req != local->int_scan_req) {
++-		local->scan_info.aborted = aborted;
++-		cfg80211_scan_done(scan_req, &local->scan_info);
++-	}
++ 	RCU_INIT_POINTER(local->scan_req, NULL);
++ 	RCU_INIT_POINTER(local->scan_sdata, NULL);
++ 
++ 	local->scanning = 0;
++ 	local->scan_chandef.chan = NULL;
++ 
+++	synchronize_rcu();
+++
+++	if (scan_req != local->int_scan_req) {
+++		local->scan_info.aborted = aborted;
+++		cfg80211_scan_done(scan_req, &local->scan_info);
+++	}
+++
++ 	/* Set power back to normal operating levels. */
++ 	ieee80211_hw_config(local, 0);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch b/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch
 deleted file mode 100644
 index 0d3b42f3b9..0000000000
@@ -24108,7 +26479,7 @@ index 974595e11a..f2ed528d23 100644
   				return -EINVAL;
   
 diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
-index 4a0bb1a933..0e83e9bd8e 100644
+index 4a0bb1a933..50c24a7746 100644
 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
 +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
 @@ -1,24 +1,24 @@
@@ -24209,7 +26580,7 @@ index 4a0bb1a933..0e83e9bd8e 100644
  --- a/net/mac80211/ieee80211_i.h
  +++ b/net/mac80211/ieee80211_i.h
 -@@ -1440,6 +1440,7 @@ struct ieee80211_local {
-+@@ -1447,6 +1447,7 @@ struct ieee80211_local {
++@@ -1448,6 +1448,7 @@ struct ieee80211_local {
   	int dynamic_ps_forced_timeout;
   
   	int user_power_level; /* in dBm, for all interfaces */
-- 
GitLab