mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-11 10:12:42 +01:00
nlmon: Pretty-print RSN IE
Pretty-print RSN cipher suites, bit fields and PMKIDs if any. Reuse existing functionality for printing netlink message ciphers.
This commit is contained in:
parent
8f5ca9dc73
commit
56a0b6de60
287
monitor/nlmon.c
287
monitor/nlmon.c
@ -564,6 +564,259 @@ static void print_ie_erp(unsigned int level, const char *label,
|
||||
print_attr(level + 1, "Barker preamble mode %d", !!(*flags & 0x04));
|
||||
}
|
||||
|
||||
struct cipher_suites {
|
||||
uint32_t cipher;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
static const struct cipher_suites rsn_cipher_selectors[] = {
|
||||
{ 0x000fac00, "Use group cipher suite" },
|
||||
{ 0x000fac01, "WEP-40" },
|
||||
{ 0x000fac02, "TKIP" },
|
||||
{ 0x000fac04, "CCMP" },
|
||||
{ 0x000fac05, "WEP-104" },
|
||||
{ 0x000fac06, "BIP" },
|
||||
{ 0x000fac07, "Group traffic not allowed" },
|
||||
{ 0x00147201, "WPI-SMS4" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct cipher_suites rsn_akm_selectors[] = {
|
||||
{ 0x000fac01, "IEEE 802.1X/PMKSA; RSNA/PMKSA caching" },
|
||||
{ 0x000fac02, "PSK; RSNA PSK" },
|
||||
{ 0x000fac03, "IEEE 802.1X FT; FT" },
|
||||
{ 0x000fac04, "PSK FT; FT" },
|
||||
{ 0x000fac05, "IEEE 802.1X/PMKSA caching SHA256; RSNA/RSNA caching SHA256" },
|
||||
{ 0x000fac06, "PSK SHA256; RSNA PSK SHA256" },
|
||||
{ 0x000fac07, "TDLS; TPK" },
|
||||
{ 0x000fac08, "SAE/PMKSA caching SHA256; RSNA PMKSA caching SHA256/mesh peering exchange" },
|
||||
{ 0x000fac09, "FT SAE SHA256; FT" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void print_ie_cipher_suite(unsigned int level, const char *label,
|
||||
const uint32_t cipher,
|
||||
const struct cipher_suites cipher_table[])
|
||||
{
|
||||
const char *str = NULL;
|
||||
unsigned int i;
|
||||
unsigned char oui[] = {
|
||||
(cipher & 0xff000000) >> 24,
|
||||
(cipher & 0x00ff0000) >> 16,
|
||||
(cipher & 0x0000ff00) >> 8,
|
||||
};
|
||||
char suite_value[32] = "";
|
||||
|
||||
for (i = 0; cipher_table[i].str; i++) {
|
||||
if (cipher_table[i].cipher == cipher) {
|
||||
str = cipher_table[i].str;
|
||||
snprintf(suite_value, sizeof(suite_value), " %02x",
|
||||
cipher & 0x000000ff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
for (i = 0; oui_table[i].str; i++) {
|
||||
if (!memcmp(oui_table[i].oui, oui, 3)) {
|
||||
str = oui_table[i].str;
|
||||
snprintf(suite_value, sizeof(suite_value),
|
||||
" %02x (vendor specific)",
|
||||
cipher & 0x000000ff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
str = "unknown";
|
||||
snprintf(suite_value, sizeof(suite_value), "%02x (unknown)",
|
||||
cipher & 0x000000ff);
|
||||
}
|
||||
|
||||
if (label)
|
||||
print_attr(level, "%s: %s (%02x:%02x:%02x) suite %s",
|
||||
label, str, oui[0], oui[1], oui[2], suite_value);
|
||||
else
|
||||
print_attr(level, "%s (%02x:%02x:%02x) suite %s",
|
||||
str, oui[0], oui[1], oui[2], suite_value);
|
||||
}
|
||||
|
||||
static void print_ie_cipher_suites(unsigned int level, const char *label,
|
||||
const void *data, uint16_t size,
|
||||
const struct cipher_suites cipher_table[])
|
||||
{
|
||||
uint32_t cipher;
|
||||
|
||||
print_attr(level, "%s: len %u", label, size);
|
||||
|
||||
while (size >= 4) {
|
||||
cipher = l_get_be32((uint32_t *) data);
|
||||
|
||||
print_ie_cipher_suite(level + 1, NULL, cipher, cipher_table);
|
||||
|
||||
data += 4;
|
||||
size -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *rsn_capabilities_bitfield[] = {
|
||||
"Preauthentication",
|
||||
"No Pairwise",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Management Frame Protection Required",
|
||||
"Management Frame Protection Capable",
|
||||
"Reserved",
|
||||
"Peerkey Enabled",
|
||||
"SPP A-MSDU Capable",
|
||||
"SPP A-MSDU Required",
|
||||
"PBAC",
|
||||
"Extended Key ID for Individually Addressed Frames",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void print_ie_bitfield(unsigned int level, const char *label,
|
||||
uint64_t bits, const char *bitfield_table[])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; bitfield_table[i]; i++) {
|
||||
if (!(bits & 1 << i))
|
||||
continue;
|
||||
|
||||
print_attr(level, "%s: bit %2d: %s", label, i,
|
||||
bitfield_table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_ie_rsn(unsigned int level, const char *label,
|
||||
const void *data, uint16_t size)
|
||||
{
|
||||
const void *end = data + size;
|
||||
|
||||
uint16_t version, count, rsn_capa;
|
||||
int i;
|
||||
const char *rsn_capabilities_replay_counter[] = {
|
||||
"1 replay counter",
|
||||
"2 replay counters",
|
||||
"4 replay counters",
|
||||
"16 replay counters"
|
||||
};
|
||||
|
||||
print_attr(level, "RSN:");
|
||||
|
||||
if (end - data < 2) {
|
||||
print_ie_error(level, label, size, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
version = l_get_le16(data);
|
||||
if (version != 1) {
|
||||
print_attr(level, "Unknown RSN version %d", version);
|
||||
return;
|
||||
}
|
||||
|
||||
data += 2;
|
||||
|
||||
if (end - data < 4)
|
||||
goto end;
|
||||
|
||||
print_ie_cipher_suites(level + 1, "Group Data Cipher Suite", data, 4,
|
||||
rsn_cipher_selectors);
|
||||
|
||||
data += 4;
|
||||
|
||||
if (end - data < 2)
|
||||
goto end;
|
||||
|
||||
count = l_get_le16((uint16_t *) data) * 4;
|
||||
data += 2;
|
||||
|
||||
if (end - data < count)
|
||||
goto end;
|
||||
|
||||
print_ie_cipher_suites(level + 1, "Pairwise Cipher Suite", data,
|
||||
count, rsn_cipher_selectors);
|
||||
data += count;
|
||||
|
||||
if (end - data < 2)
|
||||
goto end;
|
||||
|
||||
count = l_get_le16((uint16_t *) data) * 4;
|
||||
data += 2;
|
||||
|
||||
if (end - data < count)
|
||||
goto end;
|
||||
|
||||
print_ie_cipher_suites(level + 1, "AKM Suite", data, count,
|
||||
rsn_akm_selectors);
|
||||
data += count;
|
||||
|
||||
if (end - data < 2)
|
||||
goto end;
|
||||
|
||||
rsn_capa = l_get_le16((uint16_t *) data);
|
||||
data += 2;
|
||||
|
||||
print_ie_bitfield(level + 1, "RSN capabilities", rsn_capa & 0x0003,
|
||||
rsn_capabilities_bitfield);
|
||||
|
||||
count = (rsn_capa & 0x000c) >> 2;
|
||||
print_attr(level + 1, "RSN capabilities: bits 3 - 4: %s per PTKSA",
|
||||
rsn_capabilities_replay_counter[count]);
|
||||
|
||||
count = (rsn_capa & 0x0030) >> 4;
|
||||
print_attr(level + 1, "RSN capabilities: bits 5 - 6: %s per GTKSA",
|
||||
rsn_capabilities_replay_counter[count]);
|
||||
|
||||
print_ie_bitfield(level + 1, "RSN capabilities", rsn_capa & 0xffc0,
|
||||
rsn_capabilities_bitfield);
|
||||
|
||||
if (end - data < 2)
|
||||
goto end;
|
||||
|
||||
count = l_get_le16((uint16_t *) data) * 16;
|
||||
data += 2;
|
||||
|
||||
if (end - data < count)
|
||||
goto end;
|
||||
|
||||
for (i = 0; i < count; i += 16) {
|
||||
const char *bytes = data;
|
||||
|
||||
print_attr(level + 1, "PKMKID: %02x:%02x:%02x:%02x:"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
|
||||
"%02x:%02x:%02x:%02x",
|
||||
bytes[i], bytes[i + 1],
|
||||
bytes[i + 2], bytes[i + 3],
|
||||
bytes[i + 4], bytes[i + 5],
|
||||
bytes[i + 6], bytes[i + 7],
|
||||
bytes[i + 8], bytes[i + 9],
|
||||
bytes[i + 10], bytes[i + 11],
|
||||
bytes[i + 12], bytes[i + 13],
|
||||
bytes[i + 14], bytes[i + 15]);
|
||||
}
|
||||
|
||||
data += count;
|
||||
|
||||
if (end - data < 4)
|
||||
goto end;
|
||||
|
||||
print_ie_cipher_suites(level + 1, "Group Management Cipher Suite",
|
||||
data, 4, rsn_cipher_selectors);
|
||||
|
||||
data += 4;
|
||||
|
||||
end:
|
||||
if (end - data)
|
||||
print_ie_error(level, label, size, -EINVAL);
|
||||
}
|
||||
|
||||
static struct attr_entry ie_entry[] = {
|
||||
{IE_TYPE_SSID, "SSID",
|
||||
ATTR_CUSTOM, { .function = print_ie_ssid } },
|
||||
@ -583,6 +836,8 @@ static struct attr_entry ie_entry[] = {
|
||||
ATTR_CUSTOM, { .function = print_ie_tpc } },
|
||||
{IE_TYPE_ERP, "ERP Information",
|
||||
ATTR_CUSTOM, { .function = print_ie_erp } },
|
||||
{IE_TYPE_RSN, "RSN",
|
||||
ATTR_CUSTOM, { .function = print_ie_rsn } },
|
||||
{IE_TYPE_EXTENDED_SUPPORTED_RATES, "Extended supported rates",
|
||||
ATTR_CUSTOM, { .function = print_ie_rate } },
|
||||
{IE_TYPE_VENDOR_SPECIFIC, "Vendor specific",
|
||||
@ -803,46 +1058,20 @@ static void print_frame(unsigned int level, const char *label,
|
||||
print_hexdump(level + 1, data, size);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
uint32_t cipher;
|
||||
const char *str;
|
||||
} cipher_table[] = {
|
||||
{ 0x000fac00, "Use group cipher suite" },
|
||||
{ 0x000fac01, "WEP-40" },
|
||||
{ 0x000fac02, "TKIP" },
|
||||
{ 0x000fac04, "CCMP" },
|
||||
{ 0x000fac05, "WEP-104" },
|
||||
{ 0x000fac06, "BIP" },
|
||||
{ 0x000fac07, "Group traffic not allowed" },
|
||||
{ 0x00147201, "WPI-SMS4" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void print_cipher_suite(unsigned int level, const char *label,
|
||||
const void *data, uint16_t size)
|
||||
{
|
||||
uint32_t cipher = *((uint32_t *) data);
|
||||
const char *str = "Reserved";
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; cipher_table[i].str; i++) {
|
||||
if (cipher_table[i].cipher == cipher) {
|
||||
str = cipher_table[i].str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (size != 4)
|
||||
return;
|
||||
|
||||
if (label)
|
||||
print_attr(level, "%s: %s (0x%08x)", label, str, cipher);
|
||||
else
|
||||
print_attr(level, "%s (0x%08x)", str, cipher);
|
||||
print_ie_cipher_suite(level, label, cipher, rsn_cipher_selectors);
|
||||
}
|
||||
|
||||
static void print_cipher_suites(unsigned int level, const char *label,
|
||||
const void *data, uint16_t size)
|
||||
{
|
||||
print_attr(level, "%s: len %u", label, size);
|
||||
|
||||
while (size >= 4) {
|
||||
print_cipher_suite(level + 1, NULL, data, 4);
|
||||
data += 4;
|
||||
|
Loading…
Reference in New Issue
Block a user