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:
parent
e636bc855f
commit
101da59aa2
2 changed files with 136 additions and 1 deletions
|
@ -206,6 +206,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||||
ext_id = *pos++;
|
ext_id = *pos++;
|
||||||
elen--;
|
elen--;
|
||||||
|
|
||||||
|
elems->frag_ies.last_eid_ext = 0;
|
||||||
|
|
||||||
switch (ext_id) {
|
switch (ext_id) {
|
||||||
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
|
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
|
||||||
if (elen != 1)
|
if (elen != 1)
|
||||||
|
@ -295,10 +297,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elen == 254)
|
||||||
|
elems->frag_ies.last_eid_ext = ext_id;
|
||||||
|
|
||||||
return 0;
|
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
|
* ieee802_11_parse_elems - Parse information elements in management frames
|
||||||
* @start: Pointer to the start of IEs
|
* @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;
|
elems->dils_len = elen;
|
||||||
break;
|
break;
|
||||||
case WLAN_EID_FRAGMENT:
|
case WLAN_EID_FRAGMENT:
|
||||||
/* TODO */
|
ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
|
||||||
break;
|
break;
|
||||||
case WLAN_EID_EXTENSION:
|
case WLAN_EID_EXTENSION:
|
||||||
if (ieee802_11_parse_extension(pos, elen, elems,
|
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);
|
id, elen);
|
||||||
break;
|
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)) {
|
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;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct element {
|
||||||
struct hostapd_hw_modes;
|
struct hostapd_hw_modes;
|
||||||
|
|
||||||
#define MAX_NOF_MB_IES_SUPPORTED 5
|
#define MAX_NOF_MB_IES_SUPPORTED 5
|
||||||
|
#define MAX_NUM_FRAG_IES_SUPPORTED 3
|
||||||
|
|
||||||
struct mb_ies_info {
|
struct mb_ies_info {
|
||||||
struct {
|
struct {
|
||||||
|
@ -30,6 +31,21 @@ struct mb_ies_info {
|
||||||
u8 nof_ies;
|
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 */
|
/* Parsed Information Elements */
|
||||||
struct ieee802_11_elems {
|
struct ieee802_11_elems {
|
||||||
const u8 *ssid;
|
const u8 *ssid;
|
||||||
|
@ -151,6 +167,7 @@ struct ieee802_11_elems {
|
||||||
u8 short_ssid_list_len;
|
u8 short_ssid_list_len;
|
||||||
|
|
||||||
struct mb_ies_info mb_ies;
|
struct mb_ies_info mb_ies;
|
||||||
|
struct frag_ies_info frag_ies;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
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,
|
int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
|
||||||
struct ieee80211_edmg_config requested);
|
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 */
|
#endif /* IEEE802_11_COMMON_H */
|
||||||
|
|
Loading…
Reference in a new issue