Takashi Iwai 8eb966
From 5d24828d05f37ad770599de00b53d5386e35aa61 Mon Sep 17 00:00:00 2001
Takashi Iwai 8eb966
From: Johannes Berg <johannes.berg@intel.com>
Takashi Iwai 8eb966
Date: Mon, 20 Sep 2021 15:40:10 +0200
Takashi Iwai 8eb966
Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems
Takashi Iwai 8eb966
Git-commit: 5d24828d05f37ad770599de00b53d5386e35aa61
Takashi Iwai 8eb966
Patch-mainline: v5.16-rc1
Takashi Iwai 8eb966
References: CVE-2022-42719 bsc#1204051
Takashi Iwai 8eb966
Takashi Iwai 8eb966
As the 802.11 spec evolves, we need to parse more and more
Takashi Iwai 8eb966
elements. This is causing the struct to grow, and we can no
Takashi Iwai 8eb966
longer get away with putting it on the stack.
Takashi Iwai 8eb966
Takashi Iwai 8eb966
Change the API to always dynamically allocate and return an
Takashi Iwai 8eb966
allocated pointer that must be kfree()d later.
Takashi Iwai 8eb966
Takashi Iwai 8eb966
As an alternative, I contemplated a scheme whereby we'd say
Takashi Iwai 8eb966
in the code which elements we needed, e.g.
Takashi Iwai 8eb966
Takashi Iwai 8eb966
    DECLARE_ELEMENT_PARSER(elems,
Takashi Iwai 8eb966
                           SUPPORTED_CHANNELS,
Takashi Iwai 8eb966
                           CHANNEL_SWITCH,
Takashi Iwai 8eb966
                           EXT(KEY_DELIVERY));
Takashi Iwai 8eb966
Takashi Iwai 8eb966
    ieee802_11_parse_elems(..., &elems, ...);
Takashi Iwai 8eb966
Takashi Iwai 8eb966
and while I think this is possible and will save us a lot
Takashi Iwai 8eb966
since most individual places only care about a small subset
Takashi Iwai 8eb966
of the elements, it ended up being a bit more work since a
Takashi Iwai 8eb966
lot of places do the parsing and then pass the struct to
Takashi Iwai 8eb966
other functions, sometimes with multiple levels.
Takashi Iwai 8eb966
Takashi Iwai 8eb966
Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid
Takashi Iwai 8eb966
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Takashi Iwai 8eb966
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 8eb966
Takashi Iwai 8eb966
---
Takashi Iwai 8eb966
 net/mac80211/agg-rx.c      |   11 +-
Takashi Iwai 8eb966
 net/mac80211/ibss.c        |   27 ++++--
Takashi Iwai 8eb966
 net/mac80211/ieee80211_i.h |   22 ++---
Takashi Iwai 8eb966
 net/mac80211/mesh.c        |   86 ++++++++++++---------
Takashi Iwai 8eb966
 net/mac80211/mesh_hwmp.c   |   44 ++++++-----
Takashi Iwai 8eb966
 net/mac80211/mesh_plink.c  |   11 +-
Takashi Iwai 8eb966
 net/mac80211/mlme.c        |  176 +++++++++++++++++++++++++--------------------
Takashi Iwai 8eb966
 net/mac80211/scan.c        |   16 ++--
Takashi Iwai 8eb966
 net/mac80211/tdls.c        |   63 +++++++++-------
Takashi Iwai 8eb966
 net/mac80211/util.c        |   20 +++--
Takashi Iwai 8eb966
 10 files changed, 274 insertions(+), 202 deletions(-)
Takashi Iwai 8eb966
Takashi Iwai 8eb966
--- a/net/mac80211/agg-rx.c
Takashi Iwai 8eb966
+++ b/net/mac80211/agg-rx.c
Takashi Iwai 8eb966
@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str
Takashi Iwai 8eb966
 				     size_t len)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems = { };
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems = NULL;
Takashi Iwai 8eb966
 	u8 dialog_token;
Takashi Iwai 8eb966
 	int ies_len;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str
Takashi Iwai 8eb966
 	ies_len = len - offsetof(struct ieee80211_mgmt,
Takashi Iwai 8eb966
 				 u.action.u.addba_req.variable);
Takashi Iwai 8eb966
 	if (ies_len) {
Takashi Iwai 8eb966
-		ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
Takashi Iwai 8eb966
-                                ies_len, true, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
-		if (elems.parse_error)
Takashi Iwai 8eb966
+		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
Takashi Iwai 8eb966
+					       ies_len, true, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+		if (!elems || elems->parse_error)
Takashi Iwai 8eb966
 			return;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Takashi Iwai 8eb966
 					start_seq_num, ba_policy, tid,
Takashi Iwai 8eb966
 					buf_size, true, false,
Takashi Iwai 8eb966
-					elems.addba_ext_ie);
Takashi Iwai 8eb966
+					elems ? elems->addba_ext_ie : NULL);
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
Takashi Iwai 8eb966
--- a/net/mac80211/ibss.c
Takashi Iwai 8eb966
+++ b/net/mac80211/ibss.c
Takashi Iwai 8eb966
@@ -9,7 +9,7 @@
Takashi Iwai 8eb966
  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
Takashi Iwai 8eb966
  * Copyright 2013-2014  Intel Mobile Communications GmbH
Takashi Iwai 8eb966
  * Copyright(c) 2016 Intel Deutschland GmbH
Takashi Iwai 8eb966
- * Copyright(c) 2018-2020 Intel Corporation
Takashi Iwai 8eb966
+ * Copyright(c) 2018-2021 Intel Corporation
Takashi Iwai 8eb966
  */
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 #include <linux/delay.h>
Takashi Iwai 8eb966
@@ -1600,7 +1600,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru
Takashi Iwai 8eb966
 				    struct ieee80211_rx_status *rx_status)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
Takashi Iwai 8eb966
 		     offsetof(typeof(mgmt->u.beacon), variable));
Takashi Iwai 8eb966
@@ -1613,10 +1613,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru
Takashi Iwai 8eb966
 	if (baselen > len)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
Takashi Iwai 8eb966
-			       false, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
-
Takashi Iwai 8eb966
-	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
Takashi Iwai 8eb966
+				       len - baselen, false,
Takashi Iwai 8eb966
+				       mgmt->bssid, NULL);
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	if (elems) {
Takashi Iwai 8eb966
+		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
Takashi Iwai 8eb966
+		kfree(elems);
Takashi Iwai 8eb966
+	}
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
@@ -1625,7 +1629,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc
Takashi Iwai 8eb966
 	struct ieee80211_rx_status *rx_status;
Takashi Iwai 8eb966
 	struct ieee80211_mgmt *mgmt;
Takashi Iwai 8eb966
 	u16 fc;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	int ies_len;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	rx_status = IEEE80211_SKB_RXCB(skb);
Takashi Iwai 8eb966
@@ -1662,15 +1666,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc
Takashi Iwai 8eb966
 			if (ies_len < 0)
Takashi Iwai 8eb966
 				break;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-			ieee802_11_parse_elems(
Takashi Iwai 8eb966
+			elems = ieee802_11_parse_elems(
Takashi Iwai 8eb966
 				mgmt->u.action.u.chan_switch.variable,
Takashi Iwai 8eb966
-				ies_len, true, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+				ies_len, true, mgmt->bssid, NULL);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-			if (elems.parse_error)
Takashi Iwai 8eb966
+			if (!elems || elems->parse_error)
Takashi Iwai 8eb966
 				break;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
Takashi Iwai 8eb966
-							rx_status, &elems);
Takashi Iwai 8eb966
+							rx_status, elems);
Takashi Iwai 8eb966
+			kfree(elems);
Takashi Iwai 8eb966
 			break;
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
--- a/net/mac80211/ieee80211_i.h
Takashi Iwai 8eb966
+++ b/net/mac80211/ieee80211_i.h
Takashi Iwai 8eb966
@@ -2197,18 +2197,18 @@ static inline void ieee80211_tx_skb(stru
Takashi Iwai 8eb966
 	ieee80211_tx_skb_tid(sdata, skb, 7);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
Takashi Iwai 8eb966
-				struct ieee802_11_elems *elems,
Takashi Iwai 8eb966
-				u64 filter, u32 crc, u8 *transmitter_bssid,
Takashi Iwai 8eb966
-				u8 *bss_bssid);
Takashi Iwai 8eb966
-static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
Takashi Iwai 8eb966
-					  bool action,
Takashi Iwai 8eb966
-					  struct ieee802_11_elems *elems,
Takashi Iwai 8eb966
-					  u8 *transmitter_bssid,
Takashi Iwai 8eb966
-					  u8 *bss_bssid)
Takashi Iwai 8eb966
+struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
Takashi Iwai 8eb966
+						    bool action,
Takashi Iwai 8eb966
+						    u64 filter, u32 crc,
Takashi Iwai 8eb966
+						    const u8 *transmitter_bssid,
Takashi Iwai 8eb966
+						    const u8 *bss_bssid);
Takashi Iwai 8eb966
+static inline struct ieee802_11_elems *
Takashi Iwai 8eb966
+ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
Takashi Iwai 8eb966
+		       const u8 *transmitter_bssid,
Takashi Iwai 8eb966
+		       const u8 *bss_bssid)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
-	ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
Takashi Iwai 8eb966
-				   transmitter_bssid, bss_bssid);
Takashi Iwai 8eb966
+	return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
Takashi Iwai 8eb966
+					  transmitter_bssid, bss_bssid);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
--- a/net/mac80211/mesh.c
Takashi Iwai 8eb966
+++ b/net/mac80211/mesh.c
Takashi Iwai 8eb966
@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8
Takashi Iwai 8eb966
 	struct sk_buff *presp;
Takashi Iwai 8eb966
 	struct beacon_data *bcn;
Takashi Iwai 8eb966
 	struct ieee80211_mgmt *hdr;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
 	u8 *pos;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8
Takashi Iwai 8eb966
 	if (baselen > len)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
Takashi Iwai 8eb966
-			       NULL);
Takashi Iwai 8eb966
-
Takashi Iwai 8eb966
-	if (!elems.mesh_id)
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
Takashi Iwai 8eb966
+				       NULL);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
+	if (!elems->mesh_id)
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
 	/* 802.11-2012 10.1.4.3.2 */
Takashi Iwai 8eb966
 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
Takashi Iwai 8eb966
 	     !is_broadcast_ether_addr(mgmt->da)) ||
Takashi Iwai 8eb966
-	    elems.ssid_len != 0)
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+	    elems->ssid_len != 0)
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (elems.mesh_id_len != 0 &&
Takashi Iwai 8eb966
-	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
Takashi Iwai 8eb966
-	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+	if (elems->mesh_id_len != 0 &&
Takashi Iwai 8eb966
+	    (elems->mesh_id_len != ifmsh->mesh_id_len ||
Takashi Iwai 8eb966
+	     memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	rcu_read_lock();
Takashi Iwai 8eb966
 	bcn = rcu_dereference(ifmsh->beacon);
Takashi Iwai 8eb966
@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8
Takashi Iwai 8eb966
 	ieee80211_tx_skb(sdata, presp);
Takashi Iwai 8eb966
 out:
Takashi Iwai 8eb966
 	rcu_read_unlock();
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp(
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	struct ieee80211_local *local = sdata->local;
Takashi Iwai 8eb966
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	struct ieee80211_channel *channel;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
 	int freq;
Takashi Iwai 8eb966
@@ -1320,42 +1324,48 @@ static void ieee80211_mesh_rx_bcn_presp(
Takashi Iwai 8eb966
 	if (baselen > len)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
Takashi Iwai 8eb966
-			       false, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
Takashi Iwai 8eb966
+				       len - baselen,
Takashi Iwai 8eb966
+				       false, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* ignore non-mesh or secure / unsecure mismatch */
Takashi Iwai 8eb966
-	if ((!elems.mesh_id || !elems.mesh_config) ||
Takashi Iwai 8eb966
-	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
Takashi Iwai 8eb966
-	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+	if ((!elems->mesh_id || !elems->mesh_config) ||
Takashi Iwai 8eb966
+	    (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
Takashi Iwai 8eb966
+	    (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (elems.ds_params)
Takashi Iwai 8eb966
-		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
Takashi Iwai 8eb966
+	if (elems->ds_params)
Takashi Iwai 8eb966
+		freq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
Takashi Iwai 8eb966
 	else
Takashi Iwai 8eb966
 		freq = rx_status->freq;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	channel = ieee80211_get_channel(local->hw.wiphy, freq);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (mesh_matches_local(sdata, &elems)) {
Takashi Iwai 8eb966
+	if (mesh_matches_local(sdata, elems)) {
Takashi Iwai 8eb966
 		mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
Takashi Iwai 8eb966
 			sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
Takashi Iwai 8eb966
 		if (!sdata->u.mesh.user_mpm ||
Takashi Iwai 8eb966
 		    sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
Takashi Iwai 8eb966
 		    sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
Takashi Iwai 8eb966
-			mesh_neighbour_update(sdata, mgmt->sa, &elems,
Takashi Iwai 8eb966
+			mesh_neighbour_update(sdata, mgmt->sa, elems,
Takashi Iwai 8eb966
 					      rx_status);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 		if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
Takashi Iwai 8eb966
 		    !sdata->vif.csa_active)
Takashi Iwai 8eb966
-			ieee80211_mesh_process_chnswitch(sdata, &elems, true);
Takashi Iwai 8eb966
+			ieee80211_mesh_process_chnswitch(sdata, elems, true);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (ifmsh->sync_ops)
Takashi Iwai 8eb966
 		ifmsh->sync_ops->rx_bcn_presp(sdata,
Takashi Iwai 8eb966
-			stype, mgmt, &elems, rx_status);
Takashi Iwai 8eb966
+			stype, mgmt, elems, rx_status);
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
Takashi Iwai 8eb966
@@ -1447,7 +1457,7 @@ static void mesh_rx_csa_frame(struct iee
Takashi Iwai 8eb966
 			      struct ieee80211_mgmt *mgmt, size_t len)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	u16 pre_value;
Takashi Iwai 8eb966
 	bool fwd_csa = true;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
@@ -1460,33 +1470,37 @@ static void mesh_rx_csa_frame(struct iee
Takashi Iwai 8eb966
 	pos = mgmt->u.action.u.chan_switch.variable;
Takashi Iwai 8eb966
 	baselen = offsetof(struct ieee80211_mgmt,
Takashi Iwai 8eb966
 			   u.action.u.chan_switch.variable);
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(pos, len - baselen, true, &elems,
Takashi Iwai 8eb966
-			       mgmt->bssid, NULL);
Takashi Iwai 8eb966
-
Takashi Iwai 8eb966
-	if (!mesh_matches_local(sdata, &elems))
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(pos, len - baselen, true,
Takashi Iwai 8eb966
+				       mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
Takashi Iwai 8eb966
+	if (!mesh_matches_local(sdata, elems))
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
Takashi Iwai 8eb966
 	if (!--ifmsh->chsw_ttl)
Takashi Iwai 8eb966
 		fwd_csa = false;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
Takashi Iwai 8eb966
+	pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);
Takashi Iwai 8eb966
 	if (ifmsh->pre_value >= pre_value)
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	ifmsh->pre_value = pre_value;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (!sdata->vif.csa_active &&
Takashi Iwai 8eb966
-	    !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
Takashi Iwai 8eb966
+	    !ieee80211_mesh_process_chnswitch(sdata, elems, false)) {
Takashi Iwai 8eb966
 		mcsa_dbg(sdata, "Failed to process CSA action frame");
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* forward or re-broadcast the CSA frame */
Takashi Iwai 8eb966
 	if (fwd_csa) {
Takashi Iwai 8eb966
-		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
Takashi Iwai 8eb966
+		if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0)
Takashi Iwai 8eb966
 			mcsa_dbg(sdata, "Failed to forward the CSA frame");
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
--- a/net/mac80211/mesh_hwmp.c
Takashi Iwai 8eb966
+++ b/net/mac80211/mesh_hwmp.c
Takashi Iwai 8eb966
@@ -1,7 +1,7 @@
Takashi Iwai 8eb966
 // SPDX-License-Identifier: GPL-2.0-only
Takashi Iwai 8eb966
 /*
Takashi Iwai 8eb966
  * Copyright (c) 2008, 2009 open80211s Ltd.
Takashi Iwai 8eb966
- * Copyright (C) 2019 Intel Corporation
Takashi Iwai 8eb966
+ * Copyright (C) 2019, 2021 Intel Corporation
Takashi Iwai 8eb966
  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
Takashi Iwai 8eb966
  */
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru
Takashi Iwai 8eb966
 void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
 			    struct ieee80211_mgmt *mgmt, size_t len)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
 	u32 path_metric;
Takashi Iwai 8eb966
 	struct sta_info *sta;
Takashi Iwai 8eb966
@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8
Takashi Iwai 8eb966
 	rcu_read_unlock();
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
Takashi Iwai 8eb966
-			       len - baselen, false, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
Takashi Iwai 8eb966
+				       len - baselen, false, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (elems.preq) {
Takashi Iwai 8eb966
-		if (elems.preq_len != 37)
Takashi Iwai 8eb966
+	if (elems->preq) {
Takashi Iwai 8eb966
+		if (elems->preq_len != 37)
Takashi Iwai 8eb966
 			/* Right now we support just 1 destination and no AE */
Takashi Iwai 8eb966
-			return;
Takashi Iwai 8eb966
-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
Takashi Iwai 8eb966
+			goto free;
Takashi Iwai 8eb966
+		path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq,
Takashi Iwai 8eb966
 						  MPATH_PREQ);
Takashi Iwai 8eb966
 		if (path_metric)
Takashi Iwai 8eb966
-			hwmp_preq_frame_process(sdata, mgmt, elems.preq,
Takashi Iwai 8eb966
+			hwmp_preq_frame_process(sdata, mgmt, elems->preq,
Takashi Iwai 8eb966
 						path_metric);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
-	if (elems.prep) {
Takashi Iwai 8eb966
-		if (elems.prep_len != 31)
Takashi Iwai 8eb966
+	if (elems->prep) {
Takashi Iwai 8eb966
+		if (elems->prep_len != 31)
Takashi Iwai 8eb966
 			/* Right now we support no AE */
Takashi Iwai 8eb966
-			return;
Takashi Iwai 8eb966
-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
Takashi Iwai 8eb966
+			goto free;
Takashi Iwai 8eb966
+		path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep,
Takashi Iwai 8eb966
 						  MPATH_PREP);
Takashi Iwai 8eb966
 		if (path_metric)
Takashi Iwai 8eb966
-			hwmp_prep_frame_process(sdata, mgmt, elems.prep,
Takashi Iwai 8eb966
+			hwmp_prep_frame_process(sdata, mgmt, elems->prep,
Takashi Iwai 8eb966
 						path_metric);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
-	if (elems.perr) {
Takashi Iwai 8eb966
-		if (elems.perr_len != 15)
Takashi Iwai 8eb966
+	if (elems->perr) {
Takashi Iwai 8eb966
+		if (elems->perr_len != 15)
Takashi Iwai 8eb966
 			/* Right now we support only one destination per PERR */
Takashi Iwai 8eb966
-			return;
Takashi Iwai 8eb966
-		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
Takashi Iwai 8eb966
+			goto free;
Takashi Iwai 8eb966
+		hwmp_perr_frame_process(sdata, mgmt, elems->perr);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
-	if (elems.rann)
Takashi Iwai 8eb966
-		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
Takashi Iwai 8eb966
+	if (elems->rann)
Takashi Iwai 8eb966
+		hwmp_rann_frame_process(sdata, mgmt, elems->rann);
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 /**
Takashi Iwai 8eb966
--- a/net/mac80211/mesh_plink.c
Takashi Iwai 8eb966
+++ b/net/mac80211/mesh_plink.c
Takashi Iwai 8eb966
@@ -1,7 +1,7 @@
Takashi Iwai 8eb966
 // SPDX-License-Identifier: GPL-2.0-only
Takashi Iwai 8eb966
 /*
Takashi Iwai 8eb966
  * Copyright (c) 2008, 2009 open80211s Ltd.
Takashi Iwai 8eb966
- * Copyright (C) 2019 Intel Corporation
Takashi Iwai 8eb966
+ * Copyright (C) 2019, 2021 Intel Corporation
Takashi Iwai 8eb966
  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
Takashi Iwai 8eb966
  */
Takashi Iwai 8eb966
 #include <linux/gfp.h>
Takashi Iwai 8eb966
@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021
Takashi Iwai 8eb966
 			 struct ieee80211_mgmt *mgmt, size_t len,
Takashi Iwai 8eb966
 			 struct ieee80211_rx_status *rx_status)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
 	u8 *baseaddr;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021
Takashi Iwai 8eb966
 		if (baselen > len)
Takashi Iwai 8eb966
 			return;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
Takashi Iwai 8eb966
-			       mgmt->bssid, NULL);
Takashi Iwai 8eb966
-	mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(baseaddr, len - baselen, true,
Takashi Iwai 8eb966
+				       mgmt->bssid, NULL);
Takashi Iwai 8eb966
+	mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
--- a/net/mac80211/mlme.c
Takashi Iwai 8eb966
+++ b/net/mac80211/mlme.c
Takashi Iwai 8eb966
@@ -3312,8 +3312,11 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 		aid = 0; /* TODO */
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
Takashi Iwai 8eb966
-			       mgmt->bssid, assoc_data->bss->bssid);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
Takashi Iwai 8eb966
+				       mgmt->bssid, assoc_data->bss->bssid);
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return false;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (elems->aid_resp)
Takashi Iwai 8eb966
 		aid = le16_to_cpu(elems->aid_resp->aid);
Takashi Iwai 8eb966
@@ -3335,7 +3338,8 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (!is_s1g && !elems->supp_rates) {
Takashi Iwai 8eb966
 		sdata_info(sdata, "no SuppRates element in AssocResp\n");
Takashi Iwai 8eb966
-		return false;
Takashi Iwai 8eb966
+		ret = false;
Takashi Iwai 8eb966
+		goto out;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	sdata->vif.bss_conf.aid = aid;
Takashi Iwai 8eb966
@@ -3357,7 +3361,7 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 	     (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
Takashi Iwai 8eb966
 	      (!elems->vht_cap_elem || !elems->vht_operation)))) {
Takashi Iwai 8eb966
 		const struct cfg80211_bss_ies *ies;
Takashi Iwai 8eb966
-		struct ieee802_11_elems bss_elems;
Takashi Iwai 8eb966
+		struct ieee802_11_elems *bss_elems;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 		rcu_read_lock();
Takashi Iwai 8eb966
 		ies = rcu_dereference(cbss->ies);
Takashi Iwai 8eb966
@@ -3368,13 +3372,17 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 		if (!bss_ies)
Takashi Iwai 8eb966
 			return false;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-		ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
Takashi Iwai 8eb966
-				       false, &bss_elems,
Takashi Iwai 8eb966
-				       mgmt->bssid,
Takashi Iwai 8eb966
-				       assoc_data->bss->bssid);
Takashi Iwai 8eb966
+		bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
Takashi Iwai 8eb966
+						   false, mgmt->bssid,
Takashi Iwai 8eb966
+						   assoc_data->bss->bssid);
Takashi Iwai 8eb966
+		if (!bss_elems) {
Takashi Iwai 8eb966
+			ret = false;
Takashi Iwai 8eb966
+			goto out;
Takashi Iwai 8eb966
+		}
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
 		if (assoc_data->wmm &&
Takashi Iwai 8eb966
-		    !elems->wmm_param && bss_elems.wmm_param) {
Takashi Iwai 8eb966
-			elems->wmm_param = bss_elems.wmm_param;
Takashi Iwai 8eb966
+		    !elems->wmm_param && bss_elems->wmm_param) {
Takashi Iwai 8eb966
+			elems->wmm_param = bss_elems->wmm_param;
Takashi Iwai 8eb966
 			sdata_info(sdata,
Takashi Iwai 8eb966
 				   "AP bug: WMM param missing from AssocResp\n");
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
@@ -3383,30 +3391,32 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 		 * Also check if we requested HT/VHT, otherwise the AP doesn't
Takashi Iwai 8eb966
 		 * have to include the IEs in the (re)association response.
Takashi Iwai 8eb966
 		 */
Takashi Iwai 8eb966
-		if (!elems->ht_cap_elem && bss_elems.ht_cap_elem &&
Takashi Iwai 8eb966
+		if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
Takashi Iwai 8eb966
 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
Takashi Iwai 8eb966
-			elems->ht_cap_elem = bss_elems.ht_cap_elem;
Takashi Iwai 8eb966
+			elems->ht_cap_elem = bss_elems->ht_cap_elem;
Takashi Iwai 8eb966
 			sdata_info(sdata,
Takashi Iwai 8eb966
 				   "AP bug: HT capability missing from AssocResp\n");
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
-		if (!elems->ht_operation && bss_elems.ht_operation &&
Takashi Iwai 8eb966
+		if (!elems->ht_operation && bss_elems->ht_operation &&
Takashi Iwai 8eb966
 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
Takashi Iwai 8eb966
-			elems->ht_operation = bss_elems.ht_operation;
Takashi Iwai 8eb966
+			elems->ht_operation = bss_elems->ht_operation;
Takashi Iwai 8eb966
 			sdata_info(sdata,
Takashi Iwai 8eb966
 				   "AP bug: HT operation missing from AssocResp\n");
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
-		if (!elems->vht_cap_elem && bss_elems.vht_cap_elem &&
Takashi Iwai 8eb966
+		if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
Takashi Iwai 8eb966
 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
Takashi Iwai 8eb966
-			elems->vht_cap_elem = bss_elems.vht_cap_elem;
Takashi Iwai 8eb966
+			elems->vht_cap_elem = bss_elems->vht_cap_elem;
Takashi Iwai 8eb966
 			sdata_info(sdata,
Takashi Iwai 8eb966
 				   "AP bug: VHT capa missing from AssocResp\n");
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
-		if (!elems->vht_operation && bss_elems.vht_operation &&
Takashi Iwai 8eb966
+		if (!elems->vht_operation && bss_elems->vht_operation &&
Takashi Iwai 8eb966
 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
Takashi Iwai 8eb966
-			elems->vht_operation = bss_elems.vht_operation;
Takashi Iwai 8eb966
+			elems->vht_operation = bss_elems->vht_operation;
Takashi Iwai 8eb966
 			sdata_info(sdata,
Takashi Iwai 8eb966
 				   "AP bug: VHT operation missing from AssocResp\n");
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+		kfree(bss_elems);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/*
Takashi Iwai 8eb966
@@ -3660,6 +3670,7 @@ static bool ieee80211_assoc_success(stru
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	ret = true;
Takashi Iwai 8eb966
  out:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 	kfree(bss_ies);
Takashi Iwai 8eb966
 	return ret;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
@@ -3671,7 +3682,7 @@ static void ieee80211_rx_mgmt_assoc_resp
Takashi Iwai 8eb966
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
Takashi Iwai 8eb966
 	struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
Takashi Iwai 8eb966
 	u16 capab_info, status_code, aid;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	int ac, uapsd_queues = -1;
Takashi Iwai 8eb966
 	u8 *pos;
Takashi Iwai 8eb966
 	bool reassoc;
Takashi Iwai 8eb966
@@ -3728,14 +3739,16 @@ static void ieee80211_rx_mgmt_assoc_resp
Takashi Iwai 8eb966
 	    fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
Takashi Iwai 8eb966
-			       mgmt->bssid, assoc_data->bss->bssid);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
Takashi Iwai 8eb966
+				       mgmt->bssid, assoc_data->bss->bssid);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		goto notify_driver;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
Takashi Iwai 8eb966
-	    elems.timeout_int &&
Takashi Iwai 8eb966
-	    elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
Takashi Iwai 8eb966
+	    elems->timeout_int &&
Takashi Iwai 8eb966
+	    elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
Takashi Iwai 8eb966
 		u32 tu, ms;
Takashi Iwai 8eb966
-		tu = le32_to_cpu(elems.timeout_int->value);
Takashi Iwai 8eb966
+		tu = le32_to_cpu(elems->timeout_int->value);
Takashi Iwai 8eb966
 		ms = tu * 1024 / 1000;
Takashi Iwai 8eb966
 		sdata_info(sdata,
Takashi Iwai 8eb966
 			   "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
Takashi Iwai 8eb966
@@ -3755,7 +3768,7 @@ static void ieee80211_rx_mgmt_assoc_resp
Takashi Iwai 8eb966
 		event.u.mlme.reason = status_code;
Takashi Iwai 8eb966
 		drv_event_callback(sdata->local, sdata, &event);
Takashi Iwai 8eb966
 	} else {
Takashi Iwai 8eb966
-		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) {
Takashi Iwai 8eb966
+		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
Takashi Iwai 8eb966
 			/* oops -- internal error -- send timeout for now */
Takashi Iwai 8eb966
 			ieee80211_destroy_assoc_data(sdata, false, false);
Takashi Iwai 8eb966
 			cfg80211_assoc_timeout(sdata->dev, cbss);
Takashi Iwai 8eb966
@@ -3785,6 +3798,7 @@ static void ieee80211_rx_mgmt_assoc_resp
Takashi Iwai 8eb966
 			       ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
Takashi Iwai 8eb966
 notify_driver:
Takashi Iwai 8eb966
 	drv_mgd_complete_tx(sdata->local, sdata, &info;;
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
@@ -3989,7 +4003,7 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
Takashi Iwai 8eb966
 	struct ieee80211_mgmt *mgmt = (void *) hdr;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	struct ieee80211_local *local = sdata->local;
Takashi Iwai 8eb966
 	struct ieee80211_chanctx_conf *chanctx_conf;
Takashi Iwai 8eb966
 	struct ieee80211_channel *chan;
Takashi Iwai 8eb966
@@ -4035,15 +4049,16 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
Takashi Iwai 8eb966
 	    ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
Takashi Iwai 8eb966
-		ieee802_11_parse_elems(variable,
Takashi Iwai 8eb966
-				       len - baselen, false, &elems,
Takashi Iwai 8eb966
-				       bssid,
Takashi Iwai 8eb966
-				       ifmgd->assoc_data->bss->bssid);
Takashi Iwai 8eb966
+		elems = ieee802_11_parse_elems(variable, len - baselen, false,
Takashi Iwai 8eb966
+					       bssid,
Takashi Iwai 8eb966
+					       ifmgd->assoc_data->bss->bssid);
Takashi Iwai 8eb966
+		if (!elems)
Takashi Iwai 8eb966
+			return;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-		if (elems.dtim_period)
Takashi Iwai 8eb966
-			ifmgd->dtim_period = elems.dtim_period;
Takashi Iwai 8eb966
+		if (elems->dtim_period)
Takashi Iwai 8eb966
+			ifmgd->dtim_period = elems->dtim_period;
Takashi Iwai 8eb966
 		ifmgd->have_beacon = true;
Takashi Iwai 8eb966
 		ifmgd->assoc_data->need_beacon = false;
Takashi Iwai 8eb966
 		if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
Takashi Iwai 8eb966
@@ -4051,17 +4066,17 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 				le64_to_cpu(mgmt->u.beacon.timestamp);
Takashi Iwai 8eb966
 			sdata->vif.bss_conf.sync_device_ts =
Takashi Iwai 8eb966
 				rx_status->device_timestamp;
Takashi Iwai 8eb966
-			sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
Takashi Iwai 8eb966
+			sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-		if (elems.mbssid_config_ie)
Takashi Iwai 8eb966
+		if (elems->mbssid_config_ie)
Takashi Iwai 8eb966
 			bss_conf->profile_periodicity =
Takashi Iwai 8eb966
-				elems.mbssid_config_ie->profile_periodicity;
Takashi Iwai 8eb966
+				elems->mbssid_config_ie->profile_periodicity;
Takashi Iwai 8eb966
 		else
Takashi Iwai 8eb966
 			bss_conf->profile_periodicity = 0;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-		if (elems.ext_capab_len >= 11 &&
Takashi Iwai 8eb966
-		    (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
Takashi Iwai 8eb966
+		if (elems->ext_capab_len >= 11 &&
Takashi Iwai 8eb966
+		    (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
Takashi Iwai 8eb966
 			bss_conf->ema_ap = true;
Takashi Iwai 8eb966
 		else
Takashi Iwai 8eb966
 			bss_conf->ema_ap = false;
Takashi Iwai 8eb966
@@ -4070,6 +4085,7 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 		ifmgd->assoc_data->timeout = jiffies;
Takashi Iwai 8eb966
 		ifmgd->assoc_data->timeout_started = true;
Takashi Iwai 8eb966
 		run_again(sdata, ifmgd->assoc_data->timeout);
Takashi Iwai 8eb966
+		kfree(elems);
Takashi Iwai 8eb966
 		return;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -4101,14 +4117,15 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 	 */
Takashi Iwai 8eb966
 	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
Takashi Iwai 8eb966
 		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
Takashi Iwai 8eb966
-	ieee802_11_parse_elems_crc(variable,
Takashi Iwai 8eb966
-				   len - baselen, false, &elems,
Takashi Iwai 8eb966
-				   care_about_ies, ncrc,
Takashi Iwai 8eb966
-				   mgmt->bssid, bssid);
Takashi Iwai 8eb966
-	ncrc = elems.crc;
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems_crc(variable, len - baselen,
Takashi Iwai 8eb966
+					   false, care_about_ies, ncrc,
Takashi Iwai 8eb966
+					   mgmt->bssid, bssid);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return;
Takashi Iwai 8eb966
+	ncrc = elems->crc;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
Takashi Iwai 8eb966
-	    ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
Takashi Iwai 8eb966
+	    ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) {
Takashi Iwai 8eb966
 		if (local->hw.conf.dynamic_ps_timeout > 0) {
Takashi Iwai 8eb966
 			if (local->hw.conf.flags & IEEE80211_CONF_PS) {
Takashi Iwai 8eb966
 				local->hw.conf.flags &= ~IEEE80211_CONF_PS;
Takashi Iwai 8eb966
@@ -4178,12 +4195,12 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 			le64_to_cpu(mgmt->u.beacon.timestamp);
Takashi Iwai 8eb966
 		sdata->vif.bss_conf.sync_device_ts =
Takashi Iwai 8eb966
 			rx_status->device_timestamp;
Takashi Iwai 8eb966
-		sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
Takashi Iwai 8eb966
+		sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) ||
Takashi Iwai 8eb966
 	    ieee80211_is_s1g_short_beacon(mgmt->frame_control))
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	ifmgd->beacon_crc = ncrc;
Takashi Iwai 8eb966
 	ifmgd->beacon_crc_valid = true;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -4191,12 +4208,12 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
Takashi Iwai 8eb966
 					 rx_status->device_timestamp,
Takashi Iwai 8eb966
-					 &elems, true);
Takashi Iwai 8eb966
+					 elems, true);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
Takashi Iwai 8eb966
-	    ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
Takashi Iwai 8eb966
-				     elems.wmm_param_len,
Takashi Iwai 8eb966
-				     elems.mu_edca_param_set))
Takashi Iwai 8eb966
+	    ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
Takashi Iwai 8eb966
+				     elems->wmm_param_len,
Takashi Iwai 8eb966
+				     elems->mu_edca_param_set))
Takashi Iwai 8eb966
 		changed |= BSS_CHANGED_QOS;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/*
Takashi Iwai 8eb966
@@ -4205,7 +4222,7 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 	 */
Takashi Iwai 8eb966
 	if (!ifmgd->have_beacon) {
Takashi Iwai 8eb966
 		/* a few bogus AP send dtim_period = 0 or no TIM IE */
Takashi Iwai 8eb966
-		bss_conf->dtim_period = elems.dtim_period ?: 1;
Takashi Iwai 8eb966
+		bss_conf->dtim_period = elems->dtim_period ?: 1;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 		changed |= BSS_CHANGED_BEACON_INFO;
Takashi Iwai 8eb966
 		ifmgd->have_beacon = true;
Takashi Iwai 8eb966
@@ -4217,9 +4234,9 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 		ieee80211_recalc_ps_vif(sdata);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (elems.erp_info) {
Takashi Iwai 8eb966
+	if (elems->erp_info) {
Takashi Iwai 8eb966
 		erp_valid = true;
Takashi Iwai 8eb966
-		erp_value = elems.erp_info[0];
Takashi Iwai 8eb966
+		erp_value = elems->erp_info[0];
Takashi Iwai 8eb966
 	} else {
Takashi Iwai 8eb966
 		erp_valid = false;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
@@ -4232,12 +4249,12 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 	mutex_lock(&local->sta_mtx);
Takashi Iwai 8eb966
 	sta = sta_info_get(sdata, bssid);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
Takashi Iwai 8eb966
+	changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
Takashi Iwai 8eb966
-				elems.vht_cap_elem, elems.ht_operation,
Takashi Iwai 8eb966
-				elems.vht_operation, elems.he_operation,
Takashi Iwai 8eb966
-				elems.s1g_oper, bssid, &changed)) {
Takashi Iwai 8eb966
+	if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem,
Takashi Iwai 8eb966
+				elems->vht_cap_elem, elems->ht_operation,
Takashi Iwai 8eb966
+				elems->vht_operation, elems->he_operation,
Takashi Iwai 8eb966
+				elems->s1g_oper, bssid, &changed)) {
Takashi Iwai 8eb966
 		mutex_unlock(&local->sta_mtx);
Takashi Iwai 8eb966
 		sdata_info(sdata,
Takashi Iwai 8eb966
 			   "failed to follow AP %pM bandwidth change, disconnect\n",
Takashi Iwai 8eb966
@@ -4249,21 +4266,23 @@ static void ieee80211_rx_mgmt_beacon(str
Takashi Iwai 8eb966
 					    sizeof(deauth_buf), true,
Takashi Iwai 8eb966
 					    WLAN_REASON_DEAUTH_LEAVING,
Takashi Iwai 8eb966
 					    false);
Takashi Iwai 8eb966
-		return;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (sta && elems.opmode_notif)
Takashi Iwai 8eb966
-		ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
Takashi Iwai 8eb966
+	if (sta && elems->opmode_notif)
Takashi Iwai 8eb966
+		ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif,
Takashi Iwai 8eb966
 					    rx_status->band);
Takashi Iwai 8eb966
 	mutex_unlock(&local->sta_mtx);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
Takashi Iwai 8eb966
-					       elems.country_elem,
Takashi Iwai 8eb966
-					       elems.country_elem_len,
Takashi Iwai 8eb966
-					       elems.pwr_constr_elem,
Takashi Iwai 8eb966
-					       elems.cisco_dtpc_elem);
Takashi Iwai 8eb966
+					       elems->country_elem,
Takashi Iwai 8eb966
+					       elems->country_elem_len,
Takashi Iwai 8eb966
+					       elems->pwr_constr_elem,
Takashi Iwai 8eb966
+					       elems->cisco_dtpc_elem);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	ieee80211_bss_info_change_notify(sdata, changed);
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
Takashi Iwai 8eb966
@@ -4292,7 +4311,6 @@ void ieee80211_sta_rx_queued_mgmt(struct
Takashi Iwai 8eb966
 	struct ieee80211_rx_status *rx_status;
Takashi Iwai 8eb966
 	struct ieee80211_mgmt *mgmt;
Takashi Iwai 8eb966
 	u16 fc;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
 	int ies_len;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	rx_status = (struct ieee80211_rx_status *) skb->cb;
Takashi Iwai 8eb966
@@ -4324,6 +4342,8 @@ void ieee80211_sta_rx_queued_mgmt(struct
Takashi Iwai 8eb966
 		break;
Takashi Iwai 8eb966
 	case IEEE80211_STYPE_ACTION:
Takashi Iwai 8eb966
 		if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
Takashi Iwai 8eb966
+			struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
 			ies_len = skb->len -
Takashi Iwai 8eb966
 				  offsetof(struct ieee80211_mgmt,
Takashi Iwai 8eb966
 					   u.action.u.chan_switch.variable);
Takashi Iwai 8eb966
@@ -4332,18 +4352,21 @@ void ieee80211_sta_rx_queued_mgmt(struct
Takashi Iwai 8eb966
 				break;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 			/* CSA IE cannot be overridden, no need for BSSID */
Takashi Iwai 8eb966
-			ieee802_11_parse_elems(
Takashi Iwai 8eb966
-				mgmt->u.action.u.chan_switch.variable,
Takashi Iwai 8eb966
-				ies_len, true, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+			elems = ieee802_11_parse_elems(
Takashi Iwai 8eb966
+					mgmt->u.action.u.chan_switch.variable,
Takashi Iwai 8eb966
+					ies_len, true, mgmt->bssid, NULL);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-			if (elems.parse_error)
Takashi Iwai 8eb966
+			if (!elems || elems->parse_error)
Takashi Iwai 8eb966
 				break;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 			ieee80211_sta_process_chanswitch(sdata,
Takashi Iwai 8eb966
 						 rx_status->mactime,
Takashi Iwai 8eb966
 						 rx_status->device_timestamp,
Takashi Iwai 8eb966
-						 &elems, false);
Takashi Iwai 8eb966
+						 elems, false);
Takashi Iwai 8eb966
+			kfree(elems);
Takashi Iwai 8eb966
 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
Takashi Iwai 8eb966
+			struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
 			ies_len = skb->len -
Takashi Iwai 8eb966
 				  offsetof(struct ieee80211_mgmt,
Takashi Iwai 8eb966
 					   u.action.u.ext_chan_switch.variable);
Takashi Iwai 8eb966
@@ -4355,21 +4378,22 @@ void ieee80211_sta_rx_queued_mgmt(struct
Takashi Iwai 8eb966
 			 * extended CSA IE can't be overridden, no need for
Takashi Iwai 8eb966
 			 * BSSID
Takashi Iwai 8eb966
 			 */
Takashi Iwai 8eb966
-			ieee802_11_parse_elems(
Takashi Iwai 8eb966
-				mgmt->u.action.u.ext_chan_switch.variable,
Takashi Iwai 8eb966
-				ies_len, true, &elems, mgmt->bssid, NULL);
Takashi Iwai 8eb966
+			elems = ieee802_11_parse_elems(
Takashi Iwai 8eb966
+					mgmt->u.action.u.ext_chan_switch.variable,
Takashi Iwai 8eb966
+					ies_len, true, mgmt->bssid, NULL);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-			if (elems.parse_error)
Takashi Iwai 8eb966
+			if (!elems || elems->parse_error)
Takashi Iwai 8eb966
 				break;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 			/* for the handling code pretend this was also an IE */
Takashi Iwai 8eb966
-			elems.ext_chansw_ie =
Takashi Iwai 8eb966
+			elems->ext_chansw_ie =
Takashi Iwai 8eb966
 				&mgmt->u.action.u.ext_chan_switch.data;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 			ieee80211_sta_process_chanswitch(sdata,
Takashi Iwai 8eb966
 						 rx_status->mactime,
Takashi Iwai 8eb966
 						 rx_status->device_timestamp,
Takashi Iwai 8eb966
-						 &elems, false);
Takashi Iwai 8eb966
+						 elems, false);
Takashi Iwai 8eb966
+			kfree(elems);
Takashi Iwai 8eb966
 		}
Takashi Iwai 8eb966
 		break;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
--- a/net/mac80211/scan.c
Takashi Iwai 8eb966
+++ b/net/mac80211/scan.c
Takashi Iwai 8eb966
@@ -9,7 +9,7 @@
Takashi Iwai 8eb966
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
Takashi Iwai 8eb966
  * Copyright 2013-2015  Intel Mobile Communications GmbH
Takashi Iwai 8eb966
  * Copyright 2016-2017  Intel Deutschland GmbH
Takashi Iwai 8eb966
- * Copyright (C) 2018-2020 Intel Corporation
Takashi Iwai 8eb966
+ * Copyright (C) 2018-2021 Intel Corporation
Takashi Iwai 8eb966
  */
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 #include <linux/if_arp.h>
Takashi Iwai 8eb966
@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802
Takashi Iwai 8eb966
 	};
Takashi Iwai 8eb966
 	bool signal_valid;
Takashi Iwai 8eb966
 	struct ieee80211_sub_if_data *scan_sdata;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	size_t baselen;
Takashi Iwai 8eb966
 	u8 *elements;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802
Takashi Iwai 8eb966
 	if (baselen > len)
Takashi Iwai 8eb966
 		return NULL;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(elements, len - baselen, false, &elems,
Takashi Iwai 8eb966
-			       mgmt->bssid, cbss->bssid);
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(elements, len - baselen, false,
Takashi Iwai 8eb966
+				       mgmt->bssid, cbss->bssid);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return NULL;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* In case the signal is invalid update the status */
Takashi Iwai 8eb966
 	signal_valid = channel == cbss->channel;
Takashi Iwai 8eb966
@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802
Takashi Iwai 8eb966
 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	bss = (void *)cbss->priv;
Takashi Iwai 8eb966
-	ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
Takashi Iwai 8eb966
+	ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
Takashi Iwai 8eb966
 		non_tx_bss = (void *)non_tx_cbss->priv;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-		ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
Takashi Iwai 8eb966
+		ieee80211_update_bss_from_elems(local, non_tx_bss, elems,
Takashi Iwai 8eb966
 						rx_status, beacon);
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
 	return bss;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
--- a/net/mac80211/tdls.c
Takashi Iwai 8eb966
+++ b/net/mac80211/tdls.c
Takashi Iwai 8eb966
@@ -6,7 +6,7 @@
Takashi Iwai 8eb966
  * Copyright 2014, Intel Corporation
Takashi Iwai 8eb966
  * Copyright 2014  Intel Mobile Communications GmbH
Takashi Iwai 8eb966
  * Copyright 2015 - 2016 Intel Deutschland GmbH
Takashi Iwai 8eb966
- * Copyright (C) 2019 Intel Corporation
Takashi Iwai 8eb966
+ * Copyright (C) 2019, 2021 Intel Corporation
Takashi Iwai 8eb966
  */
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 #include <linux/ieee80211.h>
Takashi Iwai 8eb966
@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 					   struct sk_buff *skb)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	struct ieee80211_local *local = sdata->local;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems = NULL;
Takashi Iwai 8eb966
 	struct sta_info *sta;
Takashi Iwai 8eb966
 	struct ieee80211_tdls_data *tf = (void *)skb->data;
Takashi Iwai 8eb966
 	bool local_initiator;
Takashi Iwai 8eb966
@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 		goto call_drv;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
Takashi Iwai 8eb966
-			       skb->len - baselen, false, &elems,
Takashi Iwai 8eb966
-			       NULL, NULL);
Takashi Iwai 8eb966
-	if (elems.parse_error) {
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
Takashi Iwai 8eb966
+				       skb->len - baselen, false, NULL, NULL);
Takashi Iwai 8eb966
+	if (!elems) {
Takashi Iwai 8eb966
+		ret = -ENOMEM;
Takashi Iwai 8eb966
+		goto out;
Takashi Iwai 8eb966
+	}
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	if (elems->parse_error) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
Takashi Iwai 8eb966
 		ret = -EINVAL;
Takashi Iwai 8eb966
 		goto out;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (!elems.ch_sw_timing || !elems.lnk_id) {
Takashi Iwai 8eb966
+	if (!elems->ch_sw_timing || !elems->lnk_id) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n");
Takashi Iwai 8eb966
 		ret = -EINVAL;
Takashi Iwai 8eb966
 		goto out;
Takashi Iwai 8eb966
@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* validate the initiator is set correctly */
Takashi Iwai 8eb966
 	local_initiator =
Takashi Iwai 8eb966
-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
Takashi Iwai 8eb966
+		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
Takashi Iwai 8eb966
 	if (local_initiator == sta->sta.tdls_initiator) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
Takashi Iwai 8eb966
 		ret = -EINVAL;
Takashi Iwai 8eb966
 		goto out;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
Takashi Iwai 8eb966
-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
Takashi Iwai 8eb966
+	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
Takashi Iwai 8eb966
+	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	params.tmpl_skb =
Takashi Iwai 8eb966
 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta, &params.ch_sw_tm_ie);
Takashi Iwai 8eb966
@@ -1763,6 +1767,7 @@ call_drv:
Takashi Iwai 8eb966
 out:
Takashi Iwai 8eb966
 	mutex_unlock(&local->sta_mtx);
Takashi Iwai 8eb966
 	dev_kfree_skb_any(params.tmpl_skb);
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 	return ret;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 					  struct sk_buff *skb)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	struct ieee80211_local *local = sdata->local;
Takashi Iwai 8eb966
-	struct ieee802_11_elems elems;
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	struct cfg80211_chan_def chandef;
Takashi Iwai 8eb966
 	struct ieee80211_channel *chan;
Takashi Iwai 8eb966
 	enum nl80211_channel_type chan_type;
Takashi Iwai 8eb966
@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 		return -EINVAL;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
Takashi Iwai 8eb966
-			       skb->len - baselen, false, &elems, NULL, NULL);
Takashi Iwai 8eb966
-	if (elems.parse_error) {
Takashi Iwai 8eb966
+	elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
Takashi Iwai 8eb966
+				       skb->len - baselen, false, NULL, NULL);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return -ENOMEM;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	if (elems->parse_error) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
Takashi Iwai 8eb966
-		return -EINVAL;
Takashi Iwai 8eb966
+		ret = -EINVAL;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (!elems.ch_sw_timing || !elems.lnk_id) {
Takashi Iwai 8eb966
+	if (!elems->ch_sw_timing || !elems->lnk_id) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n");
Takashi Iwai 8eb966
-		return -EINVAL;
Takashi Iwai 8eb966
+		ret = -EINVAL;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	if (!elems.sec_chan_offs) {
Takashi Iwai 8eb966
+	if (!elems->sec_chan_offs) {
Takashi Iwai 8eb966
 		chan_type = NL80211_CHAN_HT20;
Takashi Iwai 8eb966
 	} else {
Takashi Iwai 8eb966
-		switch (elems.sec_chan_offs->sec_chan_offs) {
Takashi Iwai 8eb966
+		switch (elems->sec_chan_offs->sec_chan_offs) {
Takashi Iwai 8eb966
 		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
Takashi Iwai 8eb966
 			chan_type = NL80211_CHAN_HT40PLUS;
Takashi Iwai 8eb966
 			break;
Takashi Iwai 8eb966
@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 	if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef,
Takashi Iwai 8eb966
 					   sdata->wdev.iftype)) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n");
Takashi Iwai 8eb966
-		return -EINVAL;
Takashi Iwai 8eb966
+		ret = -EINVAL;
Takashi Iwai 8eb966
+		goto free;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	mutex_lock(&local->sta_mtx);
Takashi Iwai 8eb966
@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* validate the initiator is set correctly */
Takashi Iwai 8eb966
 	local_initiator =
Takashi Iwai 8eb966
-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
Takashi Iwai 8eb966
+		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
Takashi Iwai 8eb966
 	if (local_initiator == sta->sta.tdls_initiator) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
Takashi Iwai 8eb966
 		ret = -EINVAL;
Takashi Iwai 8eb966
@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	/* peer should have known better */
Takashi Iwai 8eb966
-	if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs &&
Takashi Iwai 8eb966
-	    elems.sec_chan_offs->sec_chan_offs) {
Takashi Iwai 8eb966
+	if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs &&
Takashi Iwai 8eb966
+	    elems->sec_chan_offs->sec_chan_offs) {
Takashi Iwai 8eb966
 		tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n");
Takashi Iwai 8eb966
 		ret = -ENOTSUPP;
Takashi Iwai 8eb966
 		goto out;
Takashi Iwai 8eb966
 	}
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	params.chandef = &chandef;
Takashi Iwai 8eb966
-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
Takashi Iwai 8eb966
-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
Takashi Iwai 8eb966
+	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
Takashi Iwai 8eb966
+	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	params.tmpl_skb =
Takashi Iwai 8eb966
 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta,
Takashi Iwai 8eb966
@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re
Takashi Iwai 8eb966
 out:
Takashi Iwai 8eb966
 	mutex_unlock(&local->sta_mtx);
Takashi Iwai 8eb966
 	dev_kfree_skb_any(params.tmpl_skb);
Takashi Iwai 8eb966
+free:
Takashi Iwai 8eb966
+	kfree(elems);
Takashi Iwai 8eb966
 	return ret;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
--- a/net/mac80211/util.c
Takashi Iwai 8eb966
+++ b/net/mac80211/util.c
Takashi Iwai 8eb966
@@ -1384,8 +1384,8 @@ _ieee802_11_parse_elems_crc(const u8 *st
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
Takashi Iwai 8eb966
 					    struct ieee802_11_elems *elems,
Takashi Iwai 8eb966
-					    u8 *transmitter_bssid,
Takashi Iwai 8eb966
-					    u8 *bss_bssid,
Takashi Iwai 8eb966
+					    const u8 *transmitter_bssid,
Takashi Iwai 8eb966
+					    const u8 *bss_bssid,
Takashi Iwai 8eb966
 					    u8 *nontransmitted_profile)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
 	const struct element *elem, *sub;
Takashi Iwai 8eb966
@@ -1452,16 +1452,20 @@ static size_t ieee802_11_find_bssid_prof
Takashi Iwai 8eb966
 	return found ? profile_len : 0;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
Takashi Iwai 8eb966
-				struct ieee802_11_elems *elems,
Takashi Iwai 8eb966
-				u64 filter, u32 crc, u8 *transmitter_bssid,
Takashi Iwai 8eb966
-				u8 *bss_bssid)
Takashi Iwai 8eb966
+struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
Takashi Iwai 8eb966
+						    bool action, u64 filter,
Takashi Iwai 8eb966
+						    u32 crc,
Takashi Iwai 8eb966
+						    const u8 *transmitter_bssid,
Takashi Iwai 8eb966
+						    const u8 *bss_bssid)
Takashi Iwai 8eb966
 {
Takashi Iwai 8eb966
+	struct ieee802_11_elems *elems;
Takashi Iwai 8eb966
 	const struct element *non_inherit = NULL;
Takashi Iwai 8eb966
 	u8 *nontransmitted_profile;
Takashi Iwai 8eb966
 	int nontransmitted_profile_len = 0;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
-	memset(elems, 0, sizeof(*elems));
Takashi Iwai 8eb966
+	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
Takashi Iwai 8eb966
+	if (!elems)
Takashi Iwai 8eb966
+		return NULL;
Takashi Iwai 8eb966
 	elems->ie_start = start;
Takashi Iwai 8eb966
 	elems->total_len = len;
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
@@ -1508,6 +1512,8 @@ void ieee802_11_parse_elems_crc(const u8
Takashi Iwai 8eb966
 	kfree(nontransmitted_profile);
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 	elems->crc = crc;
Takashi Iwai 8eb966
+
Takashi Iwai 8eb966
+	return elems;
Takashi Iwai 8eb966
 }
Takashi Iwai 8eb966
 
Takashi Iwai 8eb966
 void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,