[PATCH v3 04/21] common: Refactor element defragmentation

Veerendranath Jakkam quic_vjakkam at quicinc.com
Wed Oct 19 07:13:52 PDT 2022


Instead of saving the pointers to the fragment elements during parsing
of the frame, append all fragments found right after the element to the
element length. Defragmentation of the lement can be done by parsing
appended fragment elements. This approach removes the limit on maximum
number of fragmented elements supported in a frame.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam at quicinc.com>
---
 src/common/ieee802_11_common.c | 113 ++++++++++++++++-----------------
 src/common/ieee802_11_common.h |  31 +++------
 2 files changed, 65 insertions(+), 79 deletions(-)

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 966861c17..76dba9d7c 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -239,11 +239,31 @@ static int ieee802_11_parse_mle(const u8 *pos, size_t elen,
 }
 
 
+static size_t ieee802_11_fragments_length(struct ieee802_11_elems *elems,
+					  const u8 *start, size_t len)
+{
+	const struct element *elem;
+	size_t frags_len = 0;
+
+	for_each_element(elem, start, len) {
+		if (elem->id != WLAN_EID_FRAGMENT)
+			break;
+
+		frags_len += elem->datalen + 2;
+		elems->num_frag_elems++;
+	}
+
+	return frags_len;
+}
+
+
 static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 				      struct ieee802_11_elems *elems,
+				      const u8 *start, size_t len,
 				      int show_errors)
 {
 	u8 ext_id;
+	size_t *total_len = NULL;
 
 	if (elen < 1) {
 		if (show_errors) {
@@ -256,8 +276,6 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 	ext_id = *pos++;
 	elen--;
 
-	elems->frag_ies.last_eid_ext = 0;
-
 	switch (ext_id) {
 	case WLAN_EID_EXT_ASSOC_DELAY_INFO:
 		if (elen != 1)
@@ -284,6 +302,7 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 			break;
 		elems->fils_hlp = pos;
 		elems->fils_hlp_len = elen;
+		total_len = &elems->fils_hlp_len;
 		break;
 	case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
 		if (elen < 1)
@@ -300,6 +319,7 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 	case WLAN_EID_EXT_WRAPPED_DATA:
 		elems->wrapped_data = pos;
 		elems->wrapped_data_len = elen;
+		total_len = &elems->wrapped_data_len;
 		break;
 	case WLAN_EID_EXT_FILS_PUBLIC_KEY:
 		if (elen < 1)
@@ -370,39 +390,15 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 		return -1;
 	}
 
-	if (elen == 254)
-		elems->frag_ies.last_eid_ext = ext_id;
+	if (elen == 254 && total_len)
+		*total_len += ieee802_11_fragments_length(
+					elems, pos + elen,
+					(start + len) - (pos + elen));
 
 	return 0;
 }
 
 
-static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
-				      const u8 *pos, u8 elen)
-{
-	if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
-		wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
-		return;
-	}
-
-	/*
-	 * Note: while EID == 0 is a valid ID (SSID IE), it should not be
-	 * fragmented.
-	 */
-	if (!frag_ies->last_eid) {
-		wpa_printf(MSG_MSGDUMP,
-			   "Fragment without a valid last element - skip");
-		return;
-	}
-
-	frag_ies->frags[frag_ies->n_frags].ie = pos;
-	frag_ies->frags[frag_ies->n_frags].ie_len = elen;
-	frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
-	frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
-	frag_ies->n_frags++;
-}
-
-
 /**
  * ieee802_11_parse_elems - Parse information elements in management frames
  * @start: Pointer to the start of IEs
@@ -427,6 +423,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 		u8 id = elem->id, elen = elem->datalen;
 		const u8 *pos = elem->data;
 
+		if (id == WLAN_EID_FRAGMENT && elems->num_frag_elems > 0) {
+			elems->num_frag_elems--;
+			continue;
+		} else {
+			elems->num_frag_elems = 0;
+		}
+
 		switch (id) {
 		case WLAN_EID_SSID:
 			if (elen > SSID_MAX_LEN) {
@@ -630,11 +633,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 			elems->s1g_capab = pos;
 			break;
 		case WLAN_EID_FRAGMENT:
-			ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
+			wpa_printf(MSG_MSGDUMP,
+				   "Fragment without a valid last element - skip");
+
 			break;
 		case WLAN_EID_EXTENSION:
-			if (ieee802_11_parse_extension(pos, elen, elems,
-						       show_errors))
+			if (ieee802_11_parse_extension(pos, elen, elems, start,
+						       len, show_errors))
 				unknown++;
 			break;
 		default:
@@ -646,12 +651,6 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 				   id, elen);
 			break;
 		}
-
-		if (id != WLAN_EID_FRAGMENT && elen == 255)
-			elems->frag_ies.last_eid = id;
-
-		if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
-			elems->frag_ies.last_eid = 0;
 	}
 
 	if (!for_each_element_completed(elem, start, len)) {
@@ -2734,37 +2733,37 @@ enum oper_chan_width op_class_to_ch_width(u8 op_class)
 }
 
 
-struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
-				       u8 eid, u8 eid_ext,
-				       const u8 *data, u8 len)
+struct wpabuf * ieee802_11_defrag_data(const u8 *data, size_t len,
+				       bool ext_elem)
 {
-	struct frag_ies_info *frag_ies = &elems->frag_ies;
 	struct wpabuf *buf;
-	unsigned int i;
+	const u8 *pos;
+	size_t min_defrag_len = ext_elem ? 255 : 256;
 
-	if (!elems || !data || !len)
+	if (!data || !len)
 		return NULL;
 
-	buf = wpabuf_alloc_copy(data, len);
+	if (len < min_defrag_len)
+		return wpabuf_alloc_copy(data, len);
+
+	buf = wpabuf_alloc_copy(data, min_defrag_len - 1);
 	if (!buf)
 		return NULL;
 
-	for (i = 0; i < frag_ies->n_frags; i++) {
-		int ret;
-
-		if (frag_ies->frags[i].eid != eid ||
-		    frag_ies->frags[i].eid_ext != eid_ext)
-			continue;
+	pos = &data[min_defrag_len - 1];
+	len -= (min_defrag_len - 1);
+	while (len > 2 && pos[0] == WLAN_EID_FRAGMENT && pos[1]) {
+		int ret = wpabuf_resize(&buf, pos[1]);
 
-		ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
 		if (ret < 0) {
 			wpabuf_free(buf);
 			return NULL;
 		}
 
 		/* Copy only the fragment data (without the EID and length) */
-		wpabuf_put_data(buf, frag_ies->frags[i].ie,
-				frag_ies->frags[i].ie_len);
+		wpabuf_put_data(buf, &pos[2], pos[1]);
+		pos += pos[1] + 2;
+		len -= (pos[1] + 2);
 	}
 
 	return buf;
@@ -2775,7 +2774,7 @@ struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
 				  u8 eid, u8 eid_ext)
 {
 	const u8 *data;
-	u8 len;
+	size_t len;
 
 	/*
 	 * TODO: Defragmentation mechanism can be supported for all IEs. For now
@@ -2805,7 +2804,7 @@ struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
 		return NULL;
 	}
 
-	return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+	return ieee802_11_defrag_data(data, len, true);
 }
 
 
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ff6d2a89f..294e6265c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -21,7 +21,6 @@ struct element {
 struct hostapd_hw_modes;
 
 #define MAX_NOF_MB_IES_SUPPORTED 5
-#define MAX_NUM_FRAG_IES_SUPPORTED 3
 
 struct mb_ies_info {
 	struct {
@@ -31,21 +30,6 @@ struct mb_ies_info {
 	u8 nof_ies;
 };
 
-struct frag_ies_info {
-	struct {
-		u8 eid;
-		u8 eid_ext;
-		const u8 *ie;
-		u8 ie_len;
-	} frags[MAX_NUM_FRAG_IES_SUPPORTED];
-
-	u8 n_frags;
-
-	/* the last parsed element ID and element extension ID */
-	u8 last_eid;
-	u8 last_eid_ext;
-};
-
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	const u8 *ssid;
@@ -162,10 +146,10 @@ struct ieee802_11_elems {
 	u8 dils_len;
 	u8 fils_req_params_len;
 	u8 fils_key_confirm_len;
-	u8 fils_hlp_len;
+	size_t fils_hlp_len;
 	u8 fils_ip_addr_assign_len;
 	u8 key_delivery_len;
-	u8 wrapped_data_len;
+	size_t wrapped_data_len;
 	u8 fils_pk_len;
 	u8 owe_dh_len;
 	u8 power_capab_len;
@@ -187,7 +171,11 @@ struct ieee802_11_elems {
 	u8 prior_access_mle_len;
 
 	struct mb_ies_info mb_ies;
-	struct frag_ies_info frag_ies;
+	/*
+	 * No.of fragment elements to be skipped after a known fragmented
+	 * element.
+	 */
+	int num_frag_elems;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -348,9 +336,8 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
 int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
 			    struct ieee80211_edmg_config requested);
 
-struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
-				       u8 eid, u8 eid_ext,
-				       const u8 *data, u8 len);
+struct wpabuf * ieee802_11_defrag_data(const u8 *data, size_t len,
+				       bool ext_elem);
 struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
 				  u8 eid, u8 eid_ext);
 const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type);
-- 
2.25.1




More information about the Hostap mailing list