monitor: Parse and print P2P IE payloads

This commit is contained in:
Andrew Zaborowski 2019-07-08 18:59:52 +02:00 committed by Denis Kenzior
parent 90dc88bfa0
commit 7d7c79fbf0
1 changed files with 686 additions and 6 deletions

View File

@ -53,6 +53,7 @@
#include "src/eapol.h"
#include "src/util.h"
#include "src/wscutil.h"
#include "src/p2putil.h"
#include "monitor/pcap.h"
#include "monitor/display.h"
#include "monitor/nlmon.h"
@ -2719,20 +2720,699 @@ static void print_wsc_attributes(unsigned int level, const char *label,
}
}
static void print_p2p_status(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
static const struct p2p_status_desc {
uint8_t code;
const char *desc;
} descs[] = {
{ P2P_STATUS_SUCCESS, "Success" },
{ P2P_STATUS_FAIL_INFO_NOT_AVAIL, "Fail; information is "
"currently unavailable" },
{ P2P_STATUS_FAIL_INCOMPATIBLE_PARAMS, "Fail; incompatible "
"parameters" },
{ P2P_STATUS_FAIL_LIMIT_REACHED, "Fail; limit reached" },
{ P2P_STATUS_FAIL_INVALID_PARAMS, "Fail; invalid parameters" },
{ P2P_STATUS_FAIL_UNABLE_TO_ACCOMMODATE_REQUEST, "Fail; unable "
"to accomodate request" },
{ P2P_STATUS_FAIL_PREV_PROTOCOL_ERROR, "Fail; previous protocol"
" error, or distruptive behavior" },
{ P2P_STATUS_FAIL_NO_COMMON_CHANNELS, "Fail; no common "
"channels" },
{ P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP, "Fail; unknown P2P "
"Group" },
{ P2P_STATUS_FAIL_INTENT_15_IN_GO_NEGOTIATION, "Fail; both P2P "
"Devices indicated an Intent of 15 in Group Owner "
"Negotiation" },
{ P2P_STATUS_FAIL_INCOMPATIBLE_PROVISIONING, "Fail; "
"incompatible provisioning method" },
{ P2P_STATUS_FAIL_REJECTED_BY_USER, "Fail; rejected by user" },
{ P2P_STATUS_SUCCESS_ACCEPTED_BY_USER, "Success; accepted by "
"user" },
{}
};
int i;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
for (i = 0; descs[i].desc; i++)
if (descs[i].code == bytes[0])
break;
if (descs[i].desc)
print_attr(level, "%s: %s", label, descs[i].desc);
else
print_attr(level, "%s: 0x%02x", label, bytes[0]);
}
#define CHECK_CAPS_BIT(v, str) \
if (caps & (v)) { \
print_attr(level + 1, "%s", (str)); \
caps &= ~(v); \
}
static void print_p2p_device_capability(unsigned int level, const char *label,
const void *data, uint16_t size)
{
uint8_t caps;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
caps = *(const uint8_t *) data;
CHECK_CAPS_BIT(P2P_DEVICE_CAP_SVC_DISCOVERY,
"Service Discovery");
CHECK_CAPS_BIT(P2P_DEVICE_CAP_CLIENT_DISCOVERABILITY,
"P2P Client Discoverability");
CHECK_CAPS_BIT(P2P_DEVICE_CAP_CONCURRENT_OP,
"Concurrent Operation");
CHECK_CAPS_BIT(P2P_DEVICE_CAP_INFRASTRUCTURE_MANAGED,
"P2P Infrastructure Managed");
CHECK_CAPS_BIT(P2P_DEVICE_CAP_DEVICE_LIMIT,
"P2P Device Limit");
CHECK_CAPS_BIT(P2P_DEVICE_CAP_INVITATION_PROCEDURE,
"P2P Invitation Procedure");
if (caps)
print_attr(level + 1, "Reserved: 0x%02x", caps);
}
static void print_p2p_capability(unsigned int level, const char *label,
const void *data, uint16_t size)
{
uint8_t caps;
if (size != 2) {
printf("malformed P2P %s\n", label);
return;
}
print_p2p_device_capability(level, "P2P Device Capability", data++, 1);
print_attr(level, "P2P Group Capability:");
caps = *(const uint8_t *) data++;
CHECK_CAPS_BIT(P2P_GROUP_CAP_GO,
"P2P Group Owner");
CHECK_CAPS_BIT(P2P_GROUP_CAP_PERSISTENT_GROUP,
"Persistent P2P Group");
CHECK_CAPS_BIT(P2P_GROUP_CAP_GROUP_LIMIT,
"P2P Group Limit");
CHECK_CAPS_BIT(P2P_GROUP_CAP_INTRA_BSS_DISTRIBUTION,
"Intra-BSS Distribution");
CHECK_CAPS_BIT(P2P_GROUP_CAP_CROSS_CONNECT,
"Cross Connection");
CHECK_CAPS_BIT(P2P_GROUP_CAP_PERSISTENT_RECONNECT,
"Persistent Reconnect");
CHECK_CAPS_BIT(P2P_GROUP_CAP_GROUP_FORMATION,
"Group Formation");
CHECK_CAPS_BIT(P2P_GROUP_CAP_IP_ALLOCATION,
"IP Address Allocation");
}
#undef CHECK_CAPS_BIT
static void print_p2p_go_intent(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s: Intent %u out of 15, tie breaker %u", label,
bytes[0] >> 1, bytes[0] & 1);
}
static void print_p2p_config_timeout(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size != 2) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s: GO Timeout %ums, Client Timeout %ums", label,
bytes[0] * 10, bytes[1] * 10);
}
static void print_p2p_oper_channel(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size != 5) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_attr(level + 1, "Country %c%c table %u", bytes[0], bytes[1],
bytes[2]);
print_attr(level + 1, "Operating Class %u", bytes[3]);
print_attr(level + 1, "Channel Number %u", bytes[4]);
}
static void print_p2p_extended_timing(unsigned int level, const char *label,
const void *data, uint16_t size)
{
if (size != 4) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s: Availability period: %ums, interval: %ums", label,
l_get_le16(data + 0), l_get_le16(data + 2));
}
static void print_p2p_manageability(unsigned int level, const char *label,
const void *data, uint16_t size)
{
uint8_t val;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
#define CHECK_BIT(v, str) \
if (val & (v)) { \
print_attr(level + 1, "%s", (str)); \
val &= ~(v); \
}
val = *(const uint8_t *) data;
CHECK_BIT(P2P_MANAGEABILITY_DEVICE_MGMT, "P2P Device Management");
CHECK_BIT(P2P_MANAGEABILITY_CROSS_CONNECT,
"Cross Connection Permitted");
CHECK_BIT(P2P_MANAGEABILITY_COEXIST_OPTIONAL, "Coexistence Optional");
if (val)
print_attr(level + 1, "Reserved: 0x%02x", val);
#undef CHECK_BIT
}
static void print_p2p_channel_list(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size < 3) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_attr(level + 1, "Country %c%c table %u", bytes[0], bytes[1],
bytes[2]);
bytes += 3;
size -= 3;
while (size) {
uint8_t channels;
char str[128];
int pos = 0;
if (size < 2 || size < 2 + bytes[1]) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level + 1, "Operating Class %u channels:", *bytes++);
channels = *bytes++;
size -= 2 + channels;
while (channels--)
snprintf(str + pos, sizeof(str) - pos, "%s%u",
pos ? ", " : "", (int) *bytes++);
print_attr(level + 2, "%s", str);
}
}
static void print_p2p_notice_of_absence(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size < 2) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s %u:", label, bytes[0]);
print_attr(level + 1, "GO uses Opportunistic Power Save: %s",
(bytes[1] & 0x80) ? "true" : "false");
print_attr(level + 1, "Client Traffic window len: %u TUs",
bytes[1] & 0x7f);
bytes += 2;
size -= 2;
while (size) {
if (size < 13) {
printf("malformed P2P Channel List\n");
return;
}
print_attr(level + 1, "Notice:");
print_attr(level + 2, "Count/Type: %u", bytes[0]);
print_attr(level + 2, "Duration: %uus", l_get_le32(bytes + 1));
print_attr(level + 2, "Interval: %uus", l_get_le32(bytes + 5));
print_attr(level + 2, "Start Time: %u", l_get_le32(bytes + 8));
bytes += 13;
size -= 13;
}
}
static void print_p2p_device_info(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
int secondary_types;
if (size < 17 || size < 17 + bytes[16] * 8 + 4) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_wsc_mac_address(level + 1, "P2P Device address", bytes, 6);
print_wsc_config_methods(level + 1, "Config Methods", bytes + 6, 2);
print_wsc_primary_device_type(level + 1, "Primary Device Type",
bytes + 8, 8);
secondary_types = bytes[16];
bytes += 17;
size -= 17;
while (secondary_types--) {
print_wsc_primary_device_type(level + 1,
"Secondary Device Type",
bytes, 8);
bytes += 8;
size -= 8;
}
if (l_get_be16(bytes) != WSC_ATTR_DEVICE_NAME ||
4 + l_get_be16(bytes + 2) > size) {
printf("malformed P2P %s\n", label);
return;
}
print_wsc_device_name(level + 1, "Device Name", bytes + 4,
l_get_be16(bytes + 2));
}
static void print_p2p_group_info(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
print_attr(level, "%s:", label);
while (size) {
size_t desc_size = bytes[0];
int secondary_types;
if (1 + desc_size > size || desc_size < 24 ||
desc_size < (size_t) 24 + bytes[24] * 8 + 4) {
printf("malformed P2P Client Info Descriptor\n");
return;
}
size -= 1 + desc_size;
print_attr(level + 1, "P2P Client Info Descriptor:");
print_wsc_mac_address(level + 2, "P2P Device address",
bytes + 1, 6);
print_wsc_mac_address(level + 2, "P2P Interface address",
bytes + 7, 6);
print_p2p_device_capability(level + 2, "P2P Device Capability",
bytes + 13, 1);
print_wsc_config_methods(level + 2, "Config Methods",
bytes + 14, 2);
print_wsc_primary_device_type(level + 2, "Primary Device Type",
bytes + 16, 8);
secondary_types = bytes[24];
bytes += 25;
desc_size -= 24;
while (secondary_types--) {
print_wsc_primary_device_type(level + 2,
"Secondary Device Type",
bytes, 8);
bytes += 8;
desc_size -= 8;
}
if (l_get_be16(bytes) != WSC_ATTR_DEVICE_NAME ||
(size_t) 4 + l_get_be16(bytes + 2) >
desc_size) {
printf("malformed P2P Client Info Descriptor\n");
return;
}
print_wsc_device_name(level + 1, "Device Name", bytes + 4,
l_get_be16(bytes + 2));
bytes += 4 + l_get_be16(bytes + 2);
}
}
static void print_p2p_group_id(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size < 6 || size > 38) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_wsc_mac_address(level + 1, "P2P Device address",
bytes, 6);
print_ie_ssid(level + 1, "SSID", bytes + 6, size - 6);
}
static void print_p2p_interface(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
int addr_count;
if (size < 7 || size < 7 + bytes[6] * 6) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_wsc_mac_address(level + 1, "P2P Device Address",
bytes, 6);
addr_count = bytes[6];
print_attr(level + 1, "P2P Interface Address Count: %u", addr_count);
bytes += 7;
size -= 7;
while (addr_count--) {
print_wsc_mac_address(level + 2, "Interface Address", bytes, 6);
bytes += 6;
}
}
static void print_p2p_invite_flags(unsigned int level, const char *label,
const void *data, uint16_t size)
{
uint8_t flags;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
flags = *(const uint8_t *) data;
print_attr(level, "Invitation Type: %s",
(flags & 1) ? "re-invoke a Persistent Group" :
"join active group");
flags &= ~1;
if (flags)
print_attr(level, "Invitation Flags: reserved 0x%02x", flags);
}
static void print_p2p_oob_neg_channel(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
const char *role;
if (size != 6) {
printf("malformed P2P %s\n", label);
return;
}
print_p2p_oper_channel(level, label, bytes + 0, 5);
switch (bytes[5]) {
case 0x00:
role = "not in a group";
break;
case 0x01:
role = "client";
break;
case 0x02:
role = "Group Owner";
break;
default:
role = "reserved";
break;
}
print_attr(level + 1, "Current group role indication: %s", role);
}
static void print_p2p_service_hash(unsigned int level, const char *label,
const void *data, uint16_t size)
{
if (size % 6 != 0) {
printf("malformed P2P %s\n", label);
return;
}
while (size) {
print_wsc_bytes(level, "Service Hash", data, 6);
data += 6;
size -= 6;
}
}
static void print_p2p_connection_caps(unsigned int level, const char *label,
const void *data, uint16_t size)
{
uint8_t caps;
const char *first;
if (size != 1) {
printf("malformed P2P %s\n", label);
return;
}
caps = *(const uint8_t *) data;
if (caps & 1)
first = "New";
else if (caps & 2)
first = "Cli";
else if (caps & ~4)
first = "Unknown";
else
first = "GO";
print_attr(level, "%s: %s%s", label, first,
(caps & ~4) && (caps & 4) ? ", GO" : "");
}
static void print_p2p_advertisement_id(unsigned int level, const char *label,
const void *data, uint16_t size)
{
if (size != 10) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s: 0x%08x", label, l_get_le32(data + 0));
print_wsc_mac_address(level + 1, "Service MAC Address", data + 4, 6);
}
static void print_p2p_advertised_svc_info(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
while (size) {
if (size < 7 || size < 7 + bytes[6]) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
print_attr(level, "Servce advertisement: ID 0x%08x",
l_get_le32(bytes + 0));
print_wsc_utf8_string(level + 1, "Service Name",
bytes + 6, bytes[6], 255);
print_wsc_config_methods(level + 1, "Service Config Methods",
bytes + 4, 2);
size -= 7 + bytes[6];
bytes += 7 + bytes[6];
}
}
static void print_p2p_session_id(unsigned int level, const char *label,
const void *data, uint16_t size)
{
if (size != 10) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s: 0x%08x", label, l_get_le32(data + 0));
print_wsc_mac_address(level + 1, "Session MAC Address", data + 4, 6);
}
static void print_p2p_feature_caps(unsigned int level, const char *label,
const void *data, uint16_t size)
{
const uint8_t *bytes = data;
if (size != 2) {
printf("malformed P2P %s\n", label);
return;
}
print_attr(level, "%s:", label);
if (bytes[0] == 0x01)
print_attr(level + 1, "Coordination Protocol Transport: UDP");
else
print_attr(level + 1, "Coordination Protocol Transport: "
"reserved 0x%02x", bytes[1]);
}
static struct attr_entry p2p_attr_entry[] = {
{ P2P_ATTR_STATUS, "Status",
ATTR_CUSTOM, { .function = print_p2p_status } },
{ P2P_ATTR_MINOR_REASON_CODE, "Minor Reason Code",
ATTR_CUSTOM, { .function = print_wsc_byte } },
{ P2P_ATTR_P2P_CAPABILITY, "P2P Capability",
ATTR_CUSTOM, { .function = print_p2p_capability } },
{ P2P_ATTR_P2P_DEVICE_ID, "P2P Device ID",
ATTR_CUSTOM, { .function = print_wsc_mac_address } },
{ P2P_ATTR_GO_INTENT, "Group Owner Intent",
ATTR_CUSTOM, { .function = print_p2p_go_intent } },
{ P2P_ATTR_CONFIGURATION_TIMEOUT, "Configuration Timeout",
ATTR_CUSTOM, { .function = print_p2p_config_timeout } },
{ P2P_ATTR_LISTEN_CHANNEL, "Listen Channel",
ATTR_CUSTOM, { .function = print_p2p_oper_channel } },
{ P2P_ATTR_P2P_GROUP_BSSID, "P2P Group BSSID",
ATTR_CUSTOM, { .function = print_wsc_mac_address } },
{ P2P_ATTR_EXTENDED_LISTEN_TIMING, "Extended Listen Timing",
ATTR_CUSTOM, { .function = print_p2p_extended_timing } },
{ P2P_ATTR_INTENDED_P2P_INTERFACE_ADDR, "Intended P2P Interface "
"Address",
ATTR_CUSTOM, { .function = print_wsc_mac_address } },
{ P2P_ATTR_P2P_MANAGEABILITY, "P2P Manageability",
ATTR_CUSTOM, { .function = print_p2p_manageability } },
{ P2P_ATTR_CHANNEL_LIST, "Channel List",
ATTR_CUSTOM, { .function = print_p2p_channel_list } },
{ P2P_ATTR_NOTICE_OF_ABSENCE, "Notice of Absence",
ATTR_CUSTOM, { .function = print_p2p_notice_of_absence } },
{ P2P_ATTR_P2P_DEVICE_INFO, "P2P Device Info",
ATTR_CUSTOM, { .function = print_p2p_device_info } },
{ P2P_ATTR_P2P_GROUP_INFO, "P2P Group Info",
ATTR_CUSTOM, { .function = print_p2p_group_info } },
{ P2P_ATTR_P2P_GROUP_ID, "P2P Group ID",
ATTR_CUSTOM, { .function = print_p2p_group_id } },
{ P2P_ATTR_P2P_INTERFACE, "P2P Interface",
ATTR_CUSTOM, { .function = print_p2p_interface } },
{ P2P_ATTR_OPERATING_CHANNEL, "Operating Channel",
ATTR_CUSTOM, { .function = print_p2p_oper_channel } },
{ P2P_ATTR_INVITATION_FLAGS, "Invitation Flags",
ATTR_CUSTOM, { .function = print_p2p_invite_flags } },
{ P2P_ATTR_OOB_GO_NEGOTIATION_CHANNEL, "Out-of-Band Group Owner "
"Negotiation Channel",
ATTR_CUSTOM, { .function = print_p2p_oob_neg_channel } },
{ P2P_ATTR_SVC_HASH, "Service Hash",
ATTR_CUSTOM, { .function = print_p2p_service_hash } },
{ P2P_ATTR_SESSION_INFO_DATA_INFO, "Session Information Data Info",
ATTR_CUSTOM, { .function = print_wsc_bytes } },
{ P2P_ATTR_CONNECTION_CAPABILITY_INFO, "Connection Capability Info",
ATTR_CUSTOM, { .function = print_p2p_connection_caps } },
{ P2P_ATTR_ADVERTISEMENT_ID_INFO, "Advertisement_ID Info",
ATTR_CUSTOM, { .function = print_p2p_advertisement_id } },
{ P2P_ATTR_ADVERTISED_SVC_INFO, "Advertised Service Info",
ATTR_CUSTOM, { .function = print_p2p_advertised_svc_info } },
{ P2P_ATTR_SESSION_ID_INFO, "Session ID Info",
ATTR_CUSTOM, { .function = print_p2p_session_id } },
{ P2P_ATTR_FEATURE_CAPABILITY, "Feature Capability",
ATTR_CUSTOM, { .function = print_p2p_feature_caps } },
{ P2P_ATTR_PERSISTENT_GROUP_INFO, "Persistent Group Info",
ATTR_CUSTOM, { .function = print_p2p_group_id } },
{ P2P_ATTR_VENDOR_SPECIFIC_ATTR, "Vendor specific attribute",
ATTR_CUSTOM, { .function = print_wsc_bytes } },
{ },
};
static void print_p2p_attributes(unsigned int level, const char *label,
const void *data, uint16_t size)
{
struct p2p_attr_iter iter;
int i;
print_attr(level, "%s: len %u", label, size);
p2p_attr_iter_init(&iter, data, size);
while (p2p_attr_iter_next(&iter)) {
uint16_t type = p2p_attr_iter_get_type(&iter);
uint16_t len = p2p_attr_iter_get_length(&iter);
const void *attr = p2p_attr_iter_get_data(&iter);
struct attr_entry *entry = NULL;
for (i = 0; p2p_attr_entry[i].str; i++) {
if (p2p_attr_entry[i].attr == type) {
entry = &p2p_attr_entry[i];
break;
}
}
if (entry && entry->function)
entry->function(level + 1, entry->str, attr, len);
else {
print_attr(level + 1, "Type: 0x%02x: len %u",
type, len);
print_hexdump(level + 2, attr, len);
}
}
}
static void print_management_ies(unsigned int level, const char *label,
const void *data, uint16_t size)
{
void *wsc_data;
ssize_t wsc_len;
void *wsc_data, *p2p_data;
ssize_t wsc_len, p2p_len;
print_ie(level, label, data, size);
wsc_data = ie_tlv_extract_wsc_payload(data, size, &wsc_len);
if (!wsc_data)
return;
if (wsc_data) {
print_wsc_attributes(level + 1, "WSC Payload",
wsc_data, wsc_len);
l_free(wsc_data);
}
print_wsc_attributes(level + 1, "WSC Payload", wsc_data, wsc_len);
l_free(wsc_data);
p2p_data = ie_tlv_extract_p2p_payload(data, size, &p2p_len);
if (p2p_data) {
print_p2p_attributes(level + 1, "P2P Attributes",
p2p_data, p2p_len);
l_free(p2p_data);
}
}
static void print_address(unsigned int level, const char *label,