mirror of
				https://git.kernel.org/pub/scm/network/wireless/iwd.git
				synced 2025-11-04 08:57:29 +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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user