diff mbox series

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

Message ID 20200224091437.15212-9-ilan.peer@intel.com
State Accepted
Headers show
Series Preparations for Pre association Security Negotiation(PASN) Support | expand

Commit Message

Peer, Ilan Feb. 24, 2020, 9:14 a.m. UTC
Add support for element defragmentation as defined in Draft
P802.11REVmd_2.2 section 10.29.11.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
---
 src/common/ieee802_11_common.c | 115 ++++++++++++++++++++++++++++++++-
 src/common/ieee802_11_common.h |  24 +++++++
 2 files changed, 138 insertions(+), 1 deletion(-)
diff mbox series

Patch

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 */