diff mbox series

[1/2] wifi: mac80211: disambiguate element parsing errors

Message ID 20240129200652.1a69f2a31ec7.I55b86561d64e7ef1504c73f6f2813c33030c8136@changeid
State New
Headers show
Series [1/2] wifi: mac80211: disambiguate element parsing errors | expand

Commit Message

Johannes Berg Jan. 29, 2024, 7:06 p.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

Let the element parsing function return what kind of error
was encountered, as a bitmap, even if nothing currently
checks for which specific error it was, we'll use it later.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/ieee80211_i.h |  11 +++-
 net/mac80211/util.c        | 108 ++++++++++++++++++++++++-------------
 2 files changed, 81 insertions(+), 38 deletions(-)
diff mbox series

Patch

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 46b517cf47ea..f5fe659a1efd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1666,6 +1666,13 @@  struct ieee80211_csa_ie {
 	u32 max_switch_time;
 };
 
+enum ieee80211_elems_parse_error {
+	IEEE80211_PARSE_ERR_INVALID_END		= BIT(0),
+	IEEE80211_PARSE_ERR_DUP_ELEM		= BIT(1),
+	IEEE80211_PARSE_ERR_BAD_ELEM_SIZE	= BIT(2),
+	IEEE80211_PARSE_ERR_UNEXPECTED_ELEM	= BIT(3),
+};
+
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	const u8 *ie_start;
@@ -1776,8 +1783,8 @@  struct ieee802_11_elems {
 	struct ieee80211_mle_per_sta_profile *prof;
 	size_t sta_prof_len;
 
-	/* whether a parse error occurred while retrieving these elements */
-	bool parse_error;
+	/* whether/which parse error occurred while retrieving these elements */
+	u8 parse_error;
 
 	/*
 	 * scratch buffer that can be used for various element parsing related
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5108dbaa9360..c1fa762f0cba 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1063,7 +1063,7 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 
 	for_each_element(elem, params->start, params->len) {
 		const struct element *subelem;
-		bool elem_parse_failed;
+		u8 elem_parse_failed;
 		u8 id = elem->id;
 		u8 elen = elem->datalen;
 		const u8 *pos = elem->data;
@@ -1119,7 +1119,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 		 * that if the content gets bigger it might be needed more than once
 		 */
 			if (test_bit(id, seen_elems)) {
-				elems->parse_error = true;
+				elems->parse_error |=
+					IEEE80211_PARSE_ERR_DUP_ELEM;
 				continue;
 			}
 			break;
@@ -1128,19 +1129,21 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 		if (calc_crc && id < 64 && (params->filter & (1ULL << id)))
 			crc = crc32_be(crc, pos - 2, elen + 2);
 
-		elem_parse_failed = false;
+		elem_parse_failed = 0;
 
 		switch (id) {
 		case WLAN_EID_LINK_ID:
 			if (elen + 2 < sizeof(struct ieee80211_tdls_lnkie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->lnk_id = (void *)(pos - 2);
 			break;
 		case WLAN_EID_CHAN_SWITCH_TIMING:
 			if (elen < sizeof(struct ieee80211_ch_switch_timing)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->ch_sw_timing = (void *)pos;
@@ -1161,14 +1164,16 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= 1)
 				elems->ds_params = pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_TIM:
 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
 				elems->tim = (void *)pos;
 				elems->tim_len = elen;
 			} else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_VENDOR_SPECIFIC:
 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
@@ -1198,7 +1203,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= 1)
 				elems->erp_info = pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_EXT_SUPP_RATES:
 			elems->ext_supp_rates = pos;
@@ -1210,7 +1216,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_ht_cap))
 				elems->ht_cap_elem = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_HT_OPERATION:
 			if (params->mode < IEEE80211_CONN_MODE_HT)
@@ -1218,7 +1225,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_ht_operation))
 				elems->ht_operation = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_VHT_CAPABILITY:
 			if (params->mode < IEEE80211_CONN_MODE_VHT)
@@ -1226,7 +1234,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_vht_cap))
 				elems->vht_cap_elem = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_VHT_OPERATION:
 			if (params->mode < IEEE80211_CONN_MODE_VHT)
@@ -1237,7 +1246,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 					crc = crc32_be(crc, pos - 2, elen + 2);
 				break;
 			}
-			elem_parse_failed = true;
+			elem_parse_failed =
+				IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_OPMODE_NOTIF:
 			if (params->mode < IEEE80211_CONN_MODE_VHT)
@@ -1248,7 +1258,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 					crc = crc32_be(crc, pos - 2, elen + 2);
 				break;
 			}
-			elem_parse_failed = true;
+			elem_parse_failed =
+				IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_MESH_ID:
 			elems->mesh_id = pos;
@@ -1258,7 +1269,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
 				elems->mesh_config = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_PEER_MGMT:
 			elems->peering = pos;
@@ -1284,18 +1296,21 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_rann_ie))
 				elems->rann = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_CHANNEL_SWITCH:
 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->ch_switch_ie = (void *)pos;
 			break;
 		case WLAN_EID_EXT_CHANSWITCH_ANN:
 			if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->ext_chansw_ie = (void *)pos;
@@ -1304,7 +1319,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (params->mode < IEEE80211_CONN_MODE_HT)
 				break;
 			if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->sec_chan_offs = (void *)pos;
@@ -1312,7 +1328,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 		case WLAN_EID_CHAN_SWITCH_PARAM:
 			if (elen <
 			    sizeof(*elems->mesh_chansw_params_ie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->mesh_chansw_params_ie = (void *)pos;
@@ -1320,9 +1337,16 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
 			if (params->mode < IEEE80211_CONN_MODE_VHT)
 				break;
-			if (!params->action ||
-			    elen < sizeof(*elems->wide_bw_chansw_ie)) {
-				elem_parse_failed = true;
+
+			if (!params->action) {
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
+				break;
+			}
+
+			if (elen < sizeof(*elems->wide_bw_chansw_ie)) {
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->wide_bw_chansw_ie = (void *)pos;
@@ -1331,7 +1355,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (params->mode < IEEE80211_CONN_MODE_VHT)
 				break;
 			if (params->action) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
 				break;
 			}
 			/*
@@ -1345,7 +1370,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 					elems->wide_bw_chansw_ie =
 						(void *)subelem->data;
 				else
-					elem_parse_failed = true;
+					elem_parse_failed =
+						IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			}
 
 			if (params->mode < IEEE80211_CONN_MODE_EHT)
@@ -1361,7 +1387,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 									   edatalen))
 					elems->bandwidth_indication = edata;
 				else
-					elem_parse_failed = true;
+					elem_parse_failed =
+						IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			}
 			break;
 		case WLAN_EID_COUNTRY:
@@ -1370,7 +1397,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			break;
 		case WLAN_EID_PWR_CONSTRAINT:
 			if (elen != 1) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->pwr_constr_elem = pos;
@@ -1382,7 +1410,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			 * tag (0x00).
 			 */
 			if (elen < 4) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 
@@ -1391,7 +1420,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 				break;
 
 			if (elen != 6) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 
@@ -1402,7 +1432,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			break;
 		case WLAN_EID_ADDBA_EXT:
 			if (elen < sizeof(struct ieee80211_addba_ext_ie)) {
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 				break;
 			}
 			elems->addba_ext_ie = (void *)pos;
@@ -1411,7 +1442,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
 				elems->timeout_int = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
 			if (elen >= sizeof(*elems->max_idle_period_ie))
@@ -1444,7 +1476,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen >= sizeof(*elems->s1g_capab))
 				elems->s1g_capab = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_S1G_OPERATION:
 			if (params->mode != IEEE80211_CONN_MODE_S1G)
@@ -1452,7 +1485,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen == sizeof(*elems->s1g_oper))
 				elems->s1g_oper = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_S1G_BCN_COMPAT:
 			if (params->mode != IEEE80211_CONN_MODE_S1G)
@@ -1460,7 +1494,8 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen == sizeof(*elems->s1g_bcn_compat))
 				elems->s1g_bcn_compat = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		case WLAN_EID_AID_RESPONSE:
 			if (params->mode != IEEE80211_CONN_MODE_S1G)
@@ -1468,20 +1503,21 @@  _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
 			if (elen == sizeof(struct ieee80211_aid_response_ie))
 				elems->aid_resp = (void *)pos;
 			else
-				elem_parse_failed = true;
+				elem_parse_failed =
+					IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
 			break;
 		default:
 			break;
 		}
 
 		if (elem_parse_failed)
-			elems->parse_error = true;
+			elems->parse_error |= elem_parse_failed;
 		else
 			__set_bit(id, seen_elems);
 	}
 
 	if (!for_each_element_completed(elem, params->start, params->len))
-		elems->parse_error = true;
+		elems->parse_error |= IEEE80211_PARSE_ERR_INVALID_END;
 
 	return crc;
 }