ie: Add initial parser for RSN Elements

As found in 802.11 Section 8.4.2.27.  Currently the parser does not
handle the Capabilities, Group Management Cipher Suite or PMKID related
fields.
This commit is contained in:
Denis Kenzior 2015-01-15 17:32:22 -06:00
parent 2b7432bddb
commit 2d8f1cca0b
2 changed files with 129 additions and 0 deletions

104
src/ie.c
View File

@ -318,3 +318,107 @@ static bool ie_parse_pairwise_cipher(const uint8_t *data,
*out = tmp;
return true;
}
#define RSNE_ADVANCE(data, len, step) \
data += step; \
len -= step; \
\
if (len == 0) \
goto done \
int ie_parse_rsne(struct ie_tlv_iter *iter, struct ie_rsn_info *out_info)
{
const uint8_t *data = iter->data;
size_t len = iter->len;
uint16_t version;
struct ie_rsn_info info;
uint16_t count;
uint16_t i;
memset(&info, 0, sizeof(info));
info.group_cipher = IE_RSN_CIPHER_SUITE_CCMP;
info.pairwise_ciphers = IE_RSN_CIPHER_SUITE_CCMP;
info.akm_suites = IE_RSN_AKM_SUITE_8021X;
/* Parse Version field */
if (len < 2)
return -EMSGSIZE;
version = l_get_le16(data);
if (version != 0x01)
return -EBADMSG;
RSNE_ADVANCE(data, len, 2);
/* Parse Group Cipher Suite field */
if (len < 4)
return -EBADMSG;
if (!ie_parse_group_cipher(data, &info.group_cipher))
return -ERANGE;
RSNE_ADVANCE(data, len, 4);
/* Parse Pairwise Cipher Suite Count field */
if (len < 2)
return -EBADMSG;
count = l_get_le16(data);
/*
* The spec doesn't seem to explicitly say what to do in this case,
* so we assume this situation is invalid.
*/
if (count == 0)
return -EINVAL;
data += 2;
len -= 2;
if (len < 4 * count)
return -EBADMSG;
/* Parse Pairwise Cipher Suite List field */
for (i = 0, info.pairwise_ciphers = 0; i < count; i++) {
enum ie_rsn_cipher_suite suite;
if (!ie_parse_pairwise_cipher(data + i * 4, &suite))
return -ERANGE;
info.pairwise_ciphers |= suite;
}
RSNE_ADVANCE(data, len, count * 4);
/* Parse AKM Suite Count field */
if (len < 2)
return -EBADMSG;
count = l_get_le16(data);
if (count == 0)
return -EINVAL;
data += 2;
len -= 2;
if (len < 4 * count)
return -EBADMSG;
/* Parse AKM Suite List field */
for (i = 0, info.akm_suites = 0; i < count; i++) {
enum ie_rsn_akm_suite suite;
if (!ie_parse_akm_suite(data + i * 4, &suite))
return -ERANGE;
info.akm_suites |= suite;
}
RSNE_ADVANCE(data, len, count * 4);
done:
if (out_info)
memcpy(out_info, &info, sizeof(info));
return 0;
}

View File

@ -20,6 +20,9 @@
*
*/
#include <stdbool.h>
#include <stddef.h>
/*
* Information elements, IEEE Std 802.11 ch. 8.4.2
*/
@ -199,6 +202,26 @@ struct ie_tlv_builder {
unsigned int len;
};
struct ie_rsn_info {
enum ie_rsn_cipher_suite group_cipher;
uint16_t pairwise_ciphers;
uint16_t akm_suites;
bool preauthentication:1;
bool no_pairwise:1;
uint8_t ptksa_replay_counter:2;
uint8_t gtksa_replay_counter:2;
bool mfpr:1;
bool mfpc:1;
bool peerkey_enabled:1;
bool spp_a_msdu_capable:1;
bool spp_a_msdu_required:1;
bool pbac:1;
bool extended_key_id:1;
uint8_t num_pmkids;
const uint8_t *pmkids;
enum ie_rsn_cipher_suite group_management_cipher;
};
void ie_tlv_iter_init(struct ie_tlv_iter *iter, const unsigned char *tlv,
unsigned int len);
void ie_tlv_iter_recurse(struct ie_tlv_iter *iter,
@ -214,3 +237,5 @@ bool ie_tlv_builder_recurse(struct ie_tlv_builder *builder,
struct ie_tlv_builder *recurse);
void ie_tlv_builder_finalize(struct ie_tlv_builder *builder,
unsigned int *out_len);
int ie_parse_rsne(struct ie_tlv_iter *iter, struct ie_rsn_info *info);