ext_id = *pos++;
elen--;
+ elems->frag_ies.last_eid_ext = 0;
+
switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1)
return -1;
}
+ if (elen == 254)
+ elems->frag_ies.last_eid_ext = ext_id;
+
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
elems->dils_len = elen;
break;
case WLAN_EID_FRAGMENT:
- /* TODO */
+ ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems,
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)) {
}
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 frag_ies_info *frag_ies = &elems->frag_ies;
+ struct wpabuf *buf;
+ unsigned int i;
+
+ if (!elems || !data || !len)
+ return NULL;
+
+ buf = wpabuf_alloc_copy(data, len);
+ 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;
+
+ 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);
+ }
+
+ 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);
+}
struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
+#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info {
struct {
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;
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;
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 */