[PATCH 08/12] common: Add support for element defragmentation

Ilan Peer <[email protected]>
Newsgroups gmane.linux.drivers.hostap
Message-ID <[email protected]>
Add support for element defragmentation as defined in Draft
P802.11REVmd_2.2 section 10.29.11.

Signed-off-by: Ilan Peer <[email protected]>
---
 src/common/ieee802_11_common.c | 115 ++++++++++++++++++++++++++++++++-
 src/common/ieee802_11_common.h |  24 +++++++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 679170d492..213f6a8553 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -206,6 +206,8 @@ 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)
@@ -295,6 +297,8 @@ 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;
 	return 0;
 }
 
@@ -516,7 +520,34 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 			elems->dils_len = elen;
 			break;
 		case WLAN_EID_FRAGMENT:
-			/* TODO */
+			if (elems->frag_ies.n_frags >=
+			    MAX_NUM_FRAG_IES_SUPPORTED) {
+				wpa_printf(MSG_MSGDUMP,
+					   "Too many frags. Skip");
+				break;
+			}
+
+			/*
+			 * Note: while EID == 0 is a valid ID (SSID IE), it
+			 * should not be fragmented.
+			 */
+			if (!elems->frag_ies.last_eid) {
+				wpa_printf(MSG_MSGDUMP,
+					   "Fragment without a valid IE. Skip");
+				break;
+			}
+
+			elems->frag_ies.frags[elems->frag_ies.n_frags].ie = pos;
+			elems->frag_ies.frags[elems->frag_ies.n_frags].ie_len =
+				elen;
+
+			elems->frag_ies.frags[elems->frag_ies.n_frags].eid =
+				elems->frag_ies.last_eid;
+
+			elems->frag_ies.frags[elems->frag_ies.n_frags].eid_ext =
+				elems->frag_ies.last_eid_ext;
+
+			elems->frag_ies.n_frags++;
 			break;
 		case WLAN_EID_EXTENSION:
 			if (ieee802_11_parse_extension(pos, elen, elems,
@@ -532,6 +563,12 @@ 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)) {
@@ -2391,3 +2428,79 @@ int op_class_to_ch_width(u8 op_class)
 	}
 	return CHANWIDTH_USE_HT;
 }
+
+
+struct wpabuf *ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+				      u8 eid, u8 eid_ext,
+				      const u8 *data, u8 len)
+{
+	struct wpabuf *buf;
+	u32 i;
+
+	if (!elems || !data || !len)
+		return NULL;
+
+	buf = wpabuf_alloc(len);
+	if (!buf)
+		return NULL;
+
+	wpabuf_put_data(buf, data, len);
+
+	for (i = 0; i < elems->frag_ies.n_frags; i++) {
+		int ret;
+
+		if (elems->frag_ies.frags[i].eid != eid ||
+		    elems->frag_ies.frags[i].eid_ext != eid_ext)
+			continue;
+
+		ret = wpabuf_resize(&buf, elems->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, elems->frag_ies.frags[i].ie,
+				elems->frag_ies.frags[i].ie_len);
+	}
+
+	return buf;
+}
+
+
+struct wpabuf *ieee802_11_defrag(struct ieee802_11_elems *elems,
+				 u8 eid, u8 eid_ext)
+{
+	const u8 *data;
+	u8 len;
+
+	/*
+	 * TODO: Defragmentation mechanism can be supported for all IEs. For now
+	 * handle only those that are used (or use ieee802_11_defrag_data()).
+	 */
+	switch (eid) {
+	case WLAN_EID_EXTENSION:
+		switch (eid_ext) {
+		case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+			data = elems->fils_hlp;
+			len = elems->fils_hlp_len;
+			break;
+		case WLAN_EID_EXT_WRAPPED_DATA:
+			data = elems->wrapped_data;
+			len = elems->wrapped_data_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG,
+				   "Defragmentation not supported. eid_ext=%u",
+				   eid_ext);
+			return NULL;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "Defragmentation not supported. eid=%u", eid);
+		return NULL;
+	}
+
+	return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index bb2793d084..ed22d53698 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -21,6 +21,7 @@ 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 {
@@ -30,6 +31,21 @@ 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;
@@ -151,6 +167,7 @@ struct ieee802_11_elems {
 	u8 short_ssid_list_len;
 
 	struct mb_ies_info mb_ies;
+	struct frag_ies_info frag_ies;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -293,4 +310,11 @@ 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(struct ieee802_11_elems *elems,
+				 u8 eid, u8 eid_ext);
+
 #endif /* IEEE802_11_COMMON_H */
-- 
2.17.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.