mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-20 19:12:33 +01:00
ie: Parse vendor specific IE
Currently it supports Microsoft vendor specific information element with version and type value 1 only. Typically it contains WPA security related information.
This commit is contained in:
parent
7eac75fa69
commit
50c7346d19
240
src/ie.c
240
src/ie.c
@ -31,6 +31,7 @@
|
||||
#include "ie.h"
|
||||
|
||||
static const uint8_t ieee_oui[3] = { 0x00, 0x0f, 0xac };
|
||||
static const uint8_t microsoft_oui[3] = { 0x00, 0x50, 0xf2 };
|
||||
|
||||
void ie_tlv_iter_init(struct ie_tlv_iter *iter, const unsigned char *tlv,
|
||||
unsigned int len)
|
||||
@ -761,3 +762,242 @@ done:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 802.11i-2004, Section 7.3.2.25.1 and WPA_80211_v3_1 Section 2.1 */
|
||||
static bool ie_parse_wpa_cipher_suite(const uint8_t *data,
|
||||
enum ie_rsn_cipher_suite *out)
|
||||
{
|
||||
/*
|
||||
* Compare the OUI to the ones we know. OUI Format is found in
|
||||
* Figure 8-187 of 802.11
|
||||
*/
|
||||
if (!memcmp(data, microsoft_oui, 3)) {
|
||||
/* Suite type from 802.11i-2004, Table 20da */
|
||||
switch (data[3]) {
|
||||
case 0:
|
||||
*out = IE_RSN_CIPHER_SUITE_USE_GROUP_CIPHER;
|
||||
return true;
|
||||
case 1:
|
||||
*out = IE_RSN_CIPHER_SUITE_WEP40;
|
||||
return true;
|
||||
case 2:
|
||||
*out = IE_RSN_CIPHER_SUITE_TKIP;
|
||||
return true;
|
||||
case 4:
|
||||
*out = IE_RSN_CIPHER_SUITE_CCMP;
|
||||
return true;
|
||||
case 5:
|
||||
*out = IE_RSN_CIPHER_SUITE_WEP104;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 802.11i-2004, Section 7.3.2.25.2 and WPA_80211_v3_1 Section 2.1 */
|
||||
static bool ie_parse_wpa_akm_suite(const uint8_t *data,
|
||||
enum ie_rsn_akm_suite *out)
|
||||
{
|
||||
/*
|
||||
* Compare the OUI to the ones we know. OUI Format is found in
|
||||
* Figure 8-187 of 802.11
|
||||
*/
|
||||
if (!memcmp(data, microsoft_oui, 3)) {
|
||||
/* Suite type from 802.11i-2004, Table 20dc */
|
||||
switch (data[3]) {
|
||||
case 1:
|
||||
*out = IE_RSN_AKM_SUITE_8021X;
|
||||
return true;
|
||||
case 2:
|
||||
*out = IE_RSN_AKM_SUITE_PSK;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ie_parse_wpa_group_cipher(const uint8_t *data,
|
||||
enum ie_rsn_cipher_suite *out)
|
||||
{
|
||||
enum ie_rsn_cipher_suite tmp;
|
||||
|
||||
bool r = ie_parse_wpa_cipher_suite(data, &tmp);
|
||||
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
switch (tmp) {
|
||||
case IE_RSN_CIPHER_SUITE_CCMP:
|
||||
case IE_RSN_CIPHER_SUITE_TKIP:
|
||||
case IE_RSN_CIPHER_SUITE_WEP104:
|
||||
case IE_RSN_CIPHER_SUITE_WEP40:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ie_parse_wpa_pairwise_cipher(const uint8_t *data,
|
||||
enum ie_rsn_cipher_suite *out)
|
||||
{
|
||||
enum ie_rsn_cipher_suite tmp;
|
||||
|
||||
bool r = ie_parse_wpa_cipher_suite(data, &tmp);
|
||||
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
switch (tmp) {
|
||||
case IE_RSN_CIPHER_SUITE_CCMP:
|
||||
case IE_RSN_CIPHER_SUITE_TKIP:
|
||||
case IE_RSN_CIPHER_SUITE_WEP104:
|
||||
case IE_RSN_CIPHER_SUITE_WEP40:
|
||||
/* TODO : not sure about GROUP_CIPHER */
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_ie_wpa_ie(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
if (!data || len < 6)
|
||||
return false;
|
||||
|
||||
if ((!memcmp(data, microsoft_oui, 3) && data[3] == 1 &&
|
||||
l_get_le16(data + 4) == 1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ie_parse_wpa(struct ie_tlv_iter *iter, struct ie_rsn_info *out_info)
|
||||
{
|
||||
const uint8_t *data = iter->data;
|
||||
size_t len = iter->len;
|
||||
struct ie_rsn_info info;
|
||||
uint16_t count;
|
||||
uint16_t i;
|
||||
|
||||
if (!is_ie_wpa_ie(iter->data, iter->len))
|
||||
return -EINVAL;
|
||||
|
||||
info.group_cipher = IE_RSN_CIPHER_SUITE_TKIP;
|
||||
info.pairwise_ciphers = IE_RSN_CIPHER_SUITE_TKIP;
|
||||
info.akm_suites = IE_RSN_AKM_SUITE_PSK;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
RSNE_ADVANCE(data, len, 6);
|
||||
|
||||
/* Parse Group Cipher Suite field */
|
||||
if (len < 4)
|
||||
return -EBADMSG;
|
||||
|
||||
if (!ie_parse_wpa_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_wpa_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_wpa_akm_suite(data + i * 4, &suite))
|
||||
return -ERANGE;
|
||||
|
||||
info.akm_suites |= suite;
|
||||
}
|
||||
|
||||
RSNE_ADVANCE(data, len, count * 4);
|
||||
|
||||
return -EBADMSG;
|
||||
|
||||
done:
|
||||
/*
|
||||
* 802.11i, Section 7.3.2.25.1
|
||||
* Use of CCMP as the group cipher suite with TKIP as the
|
||||
* pairwise cipher suite shall not be supported.
|
||||
*/
|
||||
|
||||
if (info.group_cipher & IE_RSN_CIPHER_SUITE_CCMP &&
|
||||
info.pairwise_ciphers & IE_RSN_CIPHER_SUITE_TKIP)
|
||||
return -EBADMSG;
|
||||
|
||||
if (out_info)
|
||||
memcpy(out_info, &info, sizeof(info));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ie_parse_wpa_from_data(const uint8_t *data, size_t len,
|
||||
struct ie_rsn_info *info)
|
||||
{
|
||||
struct ie_tlv_iter iter;
|
||||
|
||||
ie_tlv_iter_init(&iter, data, len);
|
||||
|
||||
if (!ie_tlv_iter_next(&iter))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_VENDOR_SPECIFIC)
|
||||
return -EPROTOTYPE;
|
||||
|
||||
return ie_parse_wpa(&iter, info);
|
||||
}
|
||||
|
5
src/ie.h
5
src/ie.h
@ -264,3 +264,8 @@ int ie_parse_rsne(struct ie_tlv_iter *iter, struct ie_rsn_info *info);
|
||||
int ie_parse_rsne_from_data(const uint8_t *data, size_t len,
|
||||
struct ie_rsn_info *info);
|
||||
bool ie_build_rsne(const struct ie_rsn_info *info, uint8_t *to);
|
||||
|
||||
int ie_parse_wpa(struct ie_tlv_iter *iter, struct ie_rsn_info *out_info);
|
||||
int ie_parse_wpa_from_data(const uint8_t *data, size_t len,
|
||||
struct ie_rsn_info *info);
|
||||
bool is_ie_wpa_ie(const uint8_t *data, uint8_t len);
|
||||
|
Loading…
Reference in New Issue
Block a user