[rdk-b][common][bsp][Refactor and sync kernel/wifi from Openwrt]

[Description]
Refactor and sync kernel/wifi from Openwrt
1.kernel: filogic880 initial version

[Release-log]
N/A

diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
new file mode 100644
index 0000000..3fa70b0
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
new file mode 100644
index 0000000..e44aac5
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
new file mode 100644
index 0000000..3432c25
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
new file mode 100644
index 0000000..7565527
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
new file mode 100644
index 0000000..f4906e8
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
new file mode 100644
index 0000000..9e1f781
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
new file mode 100644
index 0000000..4c8e05e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
new file mode 100644
index 0000000..6e97150
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
new file mode 100644
index 0000000..da94840
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
new file mode 100644
index 0000000..4680e1e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
new file mode 100644
index 0000000..db0e51e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
new file mode 100644
index 0000000..ed834ff
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
new file mode 100644
index 0000000..44b8729
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
new file mode 100644
index 0000000..c689fac
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/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/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
index 0e58b61..50b6b94 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
@@ -29,7 +29,7 @@
 
 --- a/net/mac80211/scan.c
 +++ b/net/mac80211/scan.c
-@@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(s
+@@ -465,16 +465,19 @@ static void __ieee80211_scan_completed(s
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
  
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
similarity index 96%
rename from recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
rename to recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
index 1e3486a..edee4b3 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
@@ -56,7 +56,7 @@
  
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -3180,6 +3180,49 @@ static void ieee80211_process_sa_query_r
+@@ -3182,6 +3182,49 @@ static void ieee80211_process_sa_query_r
  	ieee80211_tx_skb(sdata, skb);
  }
  
@@ -106,7 +106,7 @@
  static ieee80211_rx_result debug_noinline
  ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
  {
-@@ -3205,6 +3248,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
+@@ -3207,6 +3250,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
  	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
  		int sig = 0;
  
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch
new file mode 100644
index 0000000..d133ed9
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch
@@ -0,0 +1,513 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 9 Oct 2022 20:15:46 +0200
+Subject: [PATCH] mac80211: add support for restricting netdev features per vif
+
+This can be used to selectively disable feature flags for checksum offload,
+scatter/gather or GSO by changing vif->netdev_features.
+Removing features from vif->netdev_features does not affect the netdev
+features themselves, but instead fixes up skbs in the tx path so that the
+offloads are not needed in the driver.
+
+Aside from making it easier to deal with vif type based hardware limitations,
+this also makes it possible to optimize performance on hardware without native
+GSO support by declaring GSO support in hw->netdev_features and removing it
+from vif->netdev_features. This allows mac80211 to handle GSO segmentation
+after the sta lookup, but before itxq enqueue, thus reducing the number of
+unnecessary sta lookups, as well as some other per-packet processing.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/fq_impl.h
++++ b/include/net/fq_impl.h
+@@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq
+ 			   fq_skb_free_t free_func)
+ {
+ 	struct fq_flow *flow;
++	struct sk_buff *next;
+ 	bool oom;
+ 
+ 	lockdep_assert_held(&fq->lock);
+@@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq
+ 	}
+ 
+ 	flow->tin = tin;
+-	flow->backlog += skb->len;
+-	tin->backlog_bytes += skb->len;
+-	tin->backlog_packets++;
+-	fq->memory_usage += skb->truesize;
+-	fq->backlog++;
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		flow->backlog += skb->len;
++		tin->backlog_bytes += skb->len;
++		tin->backlog_packets++;
++		fq->memory_usage += skb->truesize;
++		fq->backlog++;
++		__skb_queue_tail(&flow->queue, skb);
++	}
+ 
+ 	if (list_empty(&flow->flowchain)) {
+ 		flow->deficit = fq->quantum;
+@@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq
+ 			      &tin->new_flows);
+ 	}
+ 
+-	__skb_queue_tail(&flow->queue, skb);
+ 	oom = (fq->memory_usage > fq->memory_limit);
+ 	while (fq->backlog > fq->limit || oom) {
+ 		flow = fq_find_fattest_flow(fq);
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1685,6 +1685,10 @@ enum ieee80211_offload_flags {
+  *	write-protected by sdata_lock and local->mtx so holding either is fine
+  *	for read access.
+  * @mu_mimo_owner: indicates interface owns MU-MIMO capability
++ * @netdev_features: tx netdev features supported by the hardware for this
++ *	vif. mac80211 initializes this to hw->netdev_features, and the driver
++ *	can mask out specific tx features. mac80211 will handle software fixup
++ *	for masked offloads (GSO, CSUM)
+  * @driver_flags: flags/capabilities the driver has for this interface,
+  *	these need to be set (or cleared) when the interface is added
+  *	or, if supported by the driver, the interface type is changed
+@@ -1736,6 +1740,7 @@ struct ieee80211_vif {
+ 
+ 	struct ieee80211_chanctx_conf __rcu *chanctx_conf;
+ 
++	netdev_features_t netdev_features;
+ 	u32 driver_flags;
+ 	u32 offload_flags;
+ 
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -2209,6 +2209,7 @@ int ieee80211_if_add(struct ieee80211_lo
+ 		ndev->features |= local->hw.netdev_features;
+ 		ndev->hw_features |= ndev->features &
+ 					MAC80211_SUPPORTED_FEATURES_TX;
++		sdata->vif.netdev_features = local->hw.netdev_features;
+ 
+ 		netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
+ 
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1310,7 +1310,11 @@ static struct txq_info *ieee80211_get_tx
+ 
+ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
+ {
+-	IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
++	struct sk_buff *next;
++	codel_time_t now = codel_get_time();
++
++	skb_list_walk_safe(skb, skb, next)
++		IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
+ }
+ 
+ static u32 codel_skb_len_func(const struct sk_buff *skb)
+@@ -3499,47 +3503,71 @@ ieee80211_xmit_fast_finish(struct ieee80
+ 	return TX_CONTINUE;
+ }
+ 
+-static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
+-				struct sta_info *sta,
+-				struct ieee80211_fast_tx *fast_tx,
+-				struct sk_buff *skb)
++static netdev_features_t
++ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
+ {
+-	struct ieee80211_local *local = sdata->local;
+-	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+-	int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
+-	int hw_headroom = sdata->local->hw.extra_tx_headroom;
+-	struct ethhdr eth;
+-	struct ieee80211_tx_info *info;
+-	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
+-	struct ieee80211_tx_data tx;
+-	ieee80211_tx_result r;
+-	struct tid_ampdu_tx *tid_tx = NULL;
+-	u8 tid = IEEE80211_NUM_TIDS;
++	if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
++		return sdata->vif.netdev_features;
+ 
+-	/* control port protocol needs a lot of special handling */
+-	if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
+-		return false;
++	if (!sdata->bss)
++		return 0;
+ 
+-	/* only RFC 1042 SNAP */
+-	if (ethertype < ETH_P_802_3_MIN)
+-		return false;
++	sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
++	return sdata->vif.netdev_features;
++}
+ 
+-	/* don't handle TX status request here either */
+-	if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
+-		return false;
++static struct sk_buff *
++ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
++{
++	if (skb_is_gso(skb)) {
++		struct sk_buff *segs;
+ 
+-	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+-		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+-		tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+-		if (tid_tx) {
+-			if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
+-				return false;
+-			if (tid_tx->timeout)
+-				tid_tx->last_tx = jiffies;
+-		}
++		segs = skb_gso_segment(skb, features);
++		if (!segs)
++			return skb;
++		if (IS_ERR(segs))
++			goto free;
++
++		consume_skb(skb);
++		return segs;
++	}
++
++	if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
++		goto free;
++
++	if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		int ofs = skb_checksum_start_offset(skb);
++
++		if (skb->encapsulation)
++			skb_set_inner_transport_header(skb, ofs);
++		else
++			skb_set_transport_header(skb, ofs);
++
++		if (skb_csum_hwoffload_help(skb, features))
++			goto free;
+ 	}
+ 
+-	/* after this point (skb is modified) we cannot return false */
++	skb_mark_not_on_list(skb);
++	return skb;
++
++free:
++	kfree_skb(skb);
++	return NULL;
++}
++
++static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++				  struct sta_info *sta,
++				  struct ieee80211_fast_tx *fast_tx,
++				  struct sk_buff *skb, u8 tid, bool ampdu)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++	struct ieee80211_tx_info *info;
++	struct ieee80211_tx_data tx;
++	ieee80211_tx_result r;
++	int hw_headroom = sdata->local->hw.extra_tx_headroom;
++	int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
++	struct ethhdr eth;
+ 
+ 	if (skb_shared(skb)) {
+ 		struct sk_buff *tmp_skb = skb;
+@@ -3548,12 +3576,12 @@ static bool ieee80211_xmit_fast(struct i
+ 		kfree_skb(tmp_skb);
+ 
+ 		if (!skb)
+-			return true;
++			return;
+ 	}
+ 
+ 	if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
+ 	    ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
+-		return true;
++		return;
+ 
+ 	/* will not be crypto-handled beyond what we do here, so use false
+ 	 * as the may-encrypt argument for the resize to not account for
+@@ -3562,10 +3590,8 @@ static bool ieee80211_xmit_fast(struct i
+ 	if (unlikely(ieee80211_skb_resize(sdata, skb,
+ 					  max_t(int, extra_head + hw_headroom -
+ 						     skb_headroom(skb), 0),
+-					  ENCRYPT_NO))) {
+-		kfree_skb(skb);
+-		return true;
+-	}
++					  ENCRYPT_NO)))
++		goto free;
+ 
+ 	memcpy(&eth, skb->data, ETH_HLEN - 2);
+ 	hdr = skb_push(skb, extra_head);
+@@ -3579,7 +3605,7 @@ static bool ieee80211_xmit_fast(struct i
+ 	info->control.vif = &sdata->vif;
+ 	info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
+ 		      IEEE80211_TX_CTL_DONTFRAG |
+-		      (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
++		      (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
+ 	info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
+ 
+ #ifdef CPTCFG_MAC80211_DEBUGFS
+@@ -3601,16 +3627,14 @@ static bool ieee80211_xmit_fast(struct i
+ 	tx.key = fast_tx->key;
+ 
+ 	if (ieee80211_queue_skb(local, sdata, sta, skb))
+-		return true;
++		return;
+ 
+ 	tx.skb = skb;
+ 	r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
+ 				       fast_tx->key, &tx);
+ 	tx.skb = NULL;
+-	if (r == TX_DROP) {
+-		kfree_skb(skb);
+-		return true;
+-	}
++	if (r == TX_DROP)
++		goto free;
+ 
+ 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ 		sdata = container_of(sdata->bss,
+@@ -3618,6 +3642,55 @@ static bool ieee80211_xmit_fast(struct i
+ 
+ 	__skb_queue_tail(&tx.skbs, skb);
+ 	ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
++	return;
++
++free:
++	kfree_skb(skb);
++}
++
++static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++				struct sta_info *sta,
++				struct ieee80211_fast_tx *fast_tx,
++				struct sk_buff *skb)
++{
++	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
++	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++	struct tid_ampdu_tx *tid_tx = NULL;
++	struct sk_buff *next;
++	u8 tid = IEEE80211_NUM_TIDS;
++
++	/* control port protocol needs a lot of special handling */
++	if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
++		return false;
++
++	/* only RFC 1042 SNAP */
++	if (ethertype < ETH_P_802_3_MIN)
++		return false;
++
++	/* don't handle TX status request here either */
++	if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
++		return false;
++
++	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
++		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
++		tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++		if (tid_tx) {
++			if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
++				return false;
++			if (tid_tx->timeout)
++				tid_tx->last_tx = jiffies;
++		}
++	}
++
++	skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++	if (!skb)
++		return true;
++
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		__ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx);
++	}
++
+ 	return true;
+ }
+ 
+@@ -4123,31 +4196,14 @@ void __ieee80211_subif_start_xmit(struct
+ 			goto out;
+ 	}
+ 
+-	if (skb_is_gso(skb)) {
+-		struct sk_buff *segs;
+-
+-		segs = skb_gso_segment(skb, 0);
+-		if (IS_ERR(segs)) {
+-			goto out_free;
+-		} else if (segs) {
+-			consume_skb(skb);
+-			skb = segs;
+-		}
+-	} else {
+-		/* we cannot process non-linear frames on this path */
+-		if (skb_linearize(skb))
+-			goto out_free;
+-
+-		/* the frame could be fragmented, software-encrypted, and other
+-		 * things so we cannot really handle checksum offload with it -
+-		 * fix it up in software before we handle anything else.
+-		 */
+-		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			skb_set_transport_header(skb,
+-						 skb_checksum_start_offset(skb));
+-			if (skb_checksum_help(skb))
+-				goto out_free;
+-		}
++	/* the frame could be fragmented, software-encrypted, and other
++	 * things so we cannot really handle checksum or GSO offload.
++	 * fix it up in software before we handle anything else.
++	 */
++	skb = ieee80211_tx_skb_fixup(skb, 0);
++	if (!skb) {
++		len = 0;
++		goto out;
+ 	}
+ 
+ 	skb_list_walk_safe(skb, skb, next) {
+@@ -4310,9 +4366,11 @@ netdev_tx_t ieee80211_subif_start_xmit(s
+ 	return NETDEV_TX_OK;
+ }
+ 
+-static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
+-			      struct sk_buff *skb, struct sta_info *sta,
+-			      bool txpending)
++
++
++static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++				struct sk_buff *skb, struct sta_info *sta,
++				bool txpending)
+ {
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_tx_control control = {};
+@@ -4321,14 +4379,6 @@ static bool ieee80211_tx_8023(struct iee
+ 	unsigned long flags;
+ 	int q = info->hw_queue;
+ 
+-	if (sta)
+-		sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
+-
+-	ieee80211_tpt_led_trig_tx(local, skb->len);
+-
+-	if (ieee80211_queue_skb(local, sdata, sta, skb))
+-		return true;
+-
+ 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ 
+ 	if (local->queue_stop_reasons[q] ||
+@@ -4355,27 +4405,50 @@ static bool ieee80211_tx_8023(struct iee
+ 	return true;
+ }
+ 
++static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++			      struct sk_buff *skb, struct sta_info *sta,
++			      bool txpending)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct sk_buff *next;
++	bool ret = true;
++
++	if (ieee80211_queue_skb(local, sdata, sta, skb))
++		return true;
++
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
++			ret = false;
++	}
++
++	return ret;
++}
++
+ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
+ 				struct net_device *dev, struct sta_info *sta,
+ 				struct ieee80211_key *key, struct sk_buff *skb)
+ {
+-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++	struct ieee80211_tx_info *info;
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct tid_ampdu_tx *tid_tx;
++	struct sk_buff *seg, *next;
++	unsigned int skbs = 0, len = 0;
++	u16 queue;
+ 	u8 tid;
+ 
+ 	if (local->ops->wake_tx_queue) {
+-		u16 queue = __ieee80211_select_queue(sdata, sta, skb);
++		queue = __ieee80211_select_queue(sdata, sta, skb);
+ 		skb_set_queue_mapping(skb, queue);
+ 		skb_get_hash(skb);
++	} else {
++		queue = skb_get_queue_mapping(skb);
+ 	}
+ 
+ 	if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
+ 	    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ 		goto out_free;
+ 
+-	memset(info, 0, sizeof(*info));
+-
+ 	ieee80211_aggr_check(sdata, sta, skb);
+ 
+ 	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+@@ -4387,22 +4460,20 @@ static void ieee80211_8023_xmit(struct i
+ 			return;
+ 		}
+ 
+-		info->flags |= IEEE80211_TX_CTL_AMPDU;
+ 		if (tid_tx->timeout)
+ 			tid_tx->last_tx = jiffies;
+ 	}
+ 
+-	if (unlikely(skb->sk &&
+-		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
+-		info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
+-							     &info->flags, NULL);
++	skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++	if (!skb)
++		return;
+ 
+-	info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
++	info = IEEE80211_SKB_CB(skb);
++	memset(info, 0, sizeof(*info));
++	if (tid_tx)
++		info->flags |= IEEE80211_TX_CTL_AMPDU;
+ 
+-	dev_sw_netstats_tx_add(dev, 1, skb->len);
+-
+-	sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
+-	sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
++	info->hw_queue = sdata->vif.hw_queue[queue];
+ 
+ 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ 		sdata = container_of(sdata->bss,
+@@ -4414,6 +4485,24 @@ static void ieee80211_8023_xmit(struct i
+ 	if (key)
+ 		info->control.hw_key = &key->conf;
+ 
++	skb_list_walk_safe(skb, seg, next) {
++		skbs++;
++		len += seg->len;
++		if (seg != skb)
++			memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
++	}
++
++	if (unlikely(skb->sk &&
++		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
++		info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
++							     &info->flags, NULL);
++
++	dev_sw_netstats_tx_add(dev, skbs, len);
++	sta->tx_stats.packets[queue] += skbs;
++	sta->tx_stats.bytes[queue] += len;
++
++	ieee80211_tpt_led_trig_tx(local, len);
++
+ 	ieee80211_tx_8023(sdata, skb, sta, false);
+ 
+ 	return;
+@@ -4455,6 +4544,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
+ 		    key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
+ 		goto skip_offload;
+ 
++	sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
+ 	ieee80211_8023_xmit(sdata, dev, sta, key, skb);
+ 	goto out;
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch
new file mode 100644
index 0000000..f5fc0f9
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch
@@ -0,0 +1,262 @@
+From a58aa02645052470e6bacb9e6c1eb7adfb9fc0d8 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 5 Oct 2022 19:13:43 +0800
+Subject: [PATCH] mac80211: fix the issue of AP and STA starting on DFS channel
+ concurrently
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ include/net/cfg80211.h       | 21 ++++++++++++++++
+ include/uapi/linux/nl80211.h |  2 +-
+ net/mac80211/cfg.c           | 48 ++++++++++++++++++++++++++++++++++++
+ net/mac80211/chan.c          |  2 +-
+ net/wireless/chan.c          |  6 ++---
+ net/wireless/nl80211.c       |  8 ++++++
+ net/wireless/rdev-ops.h      | 16 ++++++++++++
+ net/wireless/trace.h         | 15 +++++++++++
+ 8 files changed, 113 insertions(+), 5 deletions(-)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index f594914..0af069d 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -800,6 +800,24 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
+ 		chandef1->center_freq2 == chandef2->center_freq2);
+ }
+ 
++/**
++ * cfg80211_chan_fully_overlap - check if two channel are fully overlapped
++ * @chandef1: first channel definition
++ * @chandef2: second channel definition
++ *
++ * Return: %true if the channels are valid and fully overlapped, %false otherwise.
++ */
++static inline bool
++cfg80211_chan_fully_overlap(const struct cfg80211_chan_def *chandef1,
++			    const struct cfg80211_chan_def *chandef2)
++{
++	return (chandef1->center_freq1 != 0 &&
++		chandef1->center_freq1 == chandef2->center_freq1 &&
++		chandef1->width == chandef2->width &&
++		chandef1->freq1_offset == chandef2->freq1_offset &&
++		chandef1->center_freq2 == chandef2->center_freq2);
++}
++
+ /**
+  * cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel
+  *
+@@ -4401,6 +4419,8 @@ struct cfg80211_ops {
+ 				struct cfg80211_color_change_settings *params);
+ 	int	(*set_radar_background)(struct wiphy *wiphy,
+ 					struct cfg80211_chan_def *chandef);
++	void	(*check_cac_skip)(struct wiphy *wiphy,
++				  struct cfg80211_chan_def *chandef);
+ };
+ 
+ /*
+@@ -5554,6 +5574,7 @@ struct wireless_dev {
+ 	struct work_struct pmsr_free_wk;
+ 
+ 	unsigned long unprot_beacon_reported;
++	bool start_disabled;
+ };
+ 
+ static inline u8 *wdev_address(struct wireless_dev *wdev)
+diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
+index e674aa7..ada8288 100644
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -3129,7 +3129,7 @@ enum nl80211_attrs {
+ 	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+ 
+ 	/* add attributes here, update the policy in nl80211.c */
+-
++	NL80211_ATTR_START_DISABLED = 999,
+ 	__NL80211_ATTR_AFTER_LAST,
+ 	NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
+ 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index bf71594..73fb432 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4504,6 +4504,53 @@ ieee80211_set_radar_background(struct wiphy *wiphy,
+ 	return local->ops->set_radar_background(&local->hw, chandef);
+ }
+ 
++static void
++ieee80211_check_cac_skip(struct wiphy *wiphy,
++			 struct cfg80211_chan_def *chandef)
++{
++	struct ieee80211_local *local = wiphy_priv(wiphy);
++	struct ieee80211_sub_if_data *s1;
++	struct ieee80211_sub_if_data *s2;
++	struct ieee80211_sub_if_data *sdata_sta;
++	struct ieee80211_if_managed *ifmgd;
++	struct ieee80211_channel *chan;
++	struct wireless_dev *wdev;
++	unsigned int cac_time_ms;
++
++	mutex_lock(&local->mtx);
++	/* Bypass AP's cac if there is a STA associated to the same DFS channel */
++	list_for_each_entry(s1, &local->interfaces, list) {
++		ifmgd = &s1->u.mgd;
++
++		if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated)
++			sdata_sta = s1;
++		else
++			continue;
++
++		list_for_each_entry(s2, &local->interfaces, list) {
++			wdev = &s2->wdev;
++			chan = wdev->chandef.chan;
++			if (chan) {
++				if (!(chan->flags & IEEE80211_CHAN_RADAR))
++					continue;
++
++				if (wdev->identifier != sdata_sta->wdev.identifier &&
++				    chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started &&
++				    cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef,
++								&s2->vif.bss_conf.chandef)) {
++					cac_time_ms = wdev->cac_time_ms;
++					wdev->cac_start_time = jiffies -
++							       msecs_to_jiffies(cac_time_ms + 1);
++					cfg80211_cac_event(wdev->netdev, &wdev->chandef,
++							   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
++					sdata_info(s2, "Skip CAC on the associated STA's chan\n");
++				}
++			}
++		}
++	}
++	mutex_unlock(&local->mtx);
++}
++
+ const struct cfg80211_ops mac80211_config_ops = {
+ 	.add_virtual_intf = ieee80211_add_iface,
+ 	.del_virtual_intf = ieee80211_del_iface,
+@@ -4610,4 +4657,5 @@ const struct cfg80211_ops mac80211_config_ops = {
+ 	.set_sar_specs = ieee80211_set_sar_specs,
+ 	.color_change = ieee80211_color_change,
+ 	.set_radar_background = ieee80211_set_radar_background,
++	.check_cac_skip = ieee80211_check_cac_skip,
+ };
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index 63e15f5..5e57e4a 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -505,7 +505,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
+ 
+ 	rcu_read_lock();
+ 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+-		if (sdata->radar_required) {
++		if (sdata->radar_required && sdata->wdev.cac_started) {
+ 			rcu_read_unlock();
+ 			return true;
+ 		}
+diff --git a/net/wireless/chan.c b/net/wireless/chan.c
+index 5f50ac4..067ed79 100644
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -664,13 +664,13 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
+ 	switch (wdev->iftype) {
+ 	case NL80211_IFTYPE_AP:
+ 	case NL80211_IFTYPE_P2P_GO:
+-		active = wdev->beacon_interval != 0;
++		active = wdev->beacon_interval != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_ADHOC:
+-		active = wdev->ssid_len != 0;
++		active = wdev->ssid_len != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_MESH_POINT:
+-		active = wdev->mesh_id_len != 0;
++		active = wdev->mesh_id_len != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_STATION:
+ 	case NL80211_IFTYPE_OCB:
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index a20aba5..8dc928d 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -803,6 +803,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
+ 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
+ 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
+ 	[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
++	[NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG },
+ 	[NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+ 
+@@ -5547,6 +5548,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	memset(&params, 0, sizeof(params));
+ 
++	if (info->attrs[NL80211_ATTR_START_DISABLED]) {
++		wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
++		err = 0;
++		goto out;
++	}
++
+ 	/* these are required for START_AP */
+ 	if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ 	    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+@@ -9393,6 +9400,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+ 		wdev->cac_started = true;
+ 		wdev->cac_start_time = jiffies;
+ 		wdev->cac_time_ms = cac_time_ms;
++		err = rdev_check_cac_skip(rdev, &wdev->chandef);
+ 	}
+ unlock:
+ 	wiphy_unlock(wiphy);
+diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
+index 8555468..e7d0064 100644
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -1398,4 +1398,20 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev,
+ 	return ret;
+ }
+ 
++static inline int
++rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
++		    struct cfg80211_chan_def *chandef)
++{
++	struct wiphy *wiphy = &rdev->wiphy;
++
++	if (!rdev->ops->check_cac_skip)
++		return -EOPNOTSUPP;
++
++	trace_rdev_check_cac_skip(wiphy, chandef);
++	rdev->ops->check_cac_skip(wiphy, chandef);
++	trace_rdev_return_void(wiphy);
++
++	return 0;
++}
++
+ #endif /* __CFG80211_RDEV_OPS */
+diff --git a/net/wireless/trace.h b/net/wireless/trace.h
+index 97a2937..e3f1c79 100644
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -3665,6 +3665,21 @@ TRACE_EVENT(rdev_set_radar_background,
+ 		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+ );
+ 
++TRACE_EVENT(rdev_check_cac_skip,
++	    TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
++
++	    TP_ARGS(wiphy, chandef),
++
++	    TP_STRUCT__entry(WIPHY_ENTRY
++			     CHAN_DEF_ENTRY),
++
++	    TP_fast_assign(WIPHY_ASSIGN;
++			   CHAN_DEF_ASSIGN(chandef)),
++
++	    TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
++		      WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
++);
++
+ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
+ 
+ #undef TRACE_INCLUDE_PATH
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
index 8ca4824..10725d1 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
@@ -41,10 +41,25 @@
     file://343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch \
     file://344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch \
     file://345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch \
-    file://350-bss-color-collision.patch \
+    file://346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch \
+    file://347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch \
+    file://348-mac80211-mlme-find-auth-challenge-directly.patch \
+    file://349-mac80211-always-allocate-struct-ieee802_11_elems.patch \
+    file://350-mac80211-fix-memory-leaks-with-element-parsing.patch \
+    file://351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch \
+    file://352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch \
+    file://353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch \
+    file://354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch \
+    file://355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch \
+    file://356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch \
+    file://357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch \
+    file://358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch \
+    file://359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch \
     file://360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch \
     file://361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch \
     file://362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch \
+    file://363-bss-color-collision.patch \
+    file://364-mac80211-add-support-for-restricting-netdev-features.patch \
     file://400-allow-ibss-mixed.patch \
     file://500-mac80211_configure_antenna_gain.patch \
     file://782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch \
@@ -64,4 +79,5 @@
     file://913-mac80211-mtk-remove-timerout-handle-for-ax210-iot-issue.patch \
     file://914-cfg80211-mtk-implement-DFS-status-show-cac-and-nop-skip-command.patch \
     file://915-mac80211-mtk-Set-TWT-Information-Frame-Disabled-bit-as-1.-This-mo.patch \
+    file://916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch \
     "