common: Add support for element defragmentation

Add support for element defragmentation as defined in IEEE
P802.11-REVmd/D3.0, 10.28.12 (Element defragmentation).

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
Ilan Peer 2020-02-24 11:14:33 +02:00 committed by Jouni Malinen
parent e636bc855f
commit 101da59aa2
2 changed files with 136 additions and 1 deletions

View file

@ -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,10 +297,39 @@ 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;
}
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
@ -516,7 +547,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
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,
@ -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,78 @@ 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 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);
}

View file

@ -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,10 @@ 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 */