@@ -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);
+}
@@ -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 */
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(-)