monitor: Parse and print P2P IE payloads
This commit is contained in:
parent
90dc88bfa0
commit
7d7c79fbf0
692
monitor/nlmon.c
692
monitor/nlmon.c
|
@ -53,6 +53,7 @@
|
||||||
#include "src/eapol.h"
|
#include "src/eapol.h"
|
||||||
#include "src/util.h"
|
#include "src/util.h"
|
||||||
#include "src/wscutil.h"
|
#include "src/wscutil.h"
|
||||||
|
#include "src/p2putil.h"
|
||||||
#include "monitor/pcap.h"
|
#include "monitor/pcap.h"
|
||||||
#include "monitor/display.h"
|
#include "monitor/display.h"
|
||||||
#include "monitor/nlmon.h"
|
#include "monitor/nlmon.h"
|
||||||
|
@ -2719,22 +2720,701 @@ 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,
|
static void print_management_ies(unsigned int level, const char *label,
|
||||||
const void *data, uint16_t size)
|
const void *data, uint16_t size)
|
||||||
{
|
{
|
||||||
void *wsc_data;
|
void *wsc_data, *p2p_data;
|
||||||
ssize_t wsc_len;
|
ssize_t wsc_len, p2p_len;
|
||||||
|
|
||||||
print_ie(level, label, data, size);
|
print_ie(level, label, data, size);
|
||||||
|
|
||||||
wsc_data = ie_tlv_extract_wsc_payload(data, size, &wsc_len);
|
wsc_data = ie_tlv_extract_wsc_payload(data, size, &wsc_len);
|
||||||
if (!wsc_data)
|
if (wsc_data) {
|
||||||
return;
|
print_wsc_attributes(level + 1, "WSC Payload",
|
||||||
|
wsc_data, wsc_len);
|
||||||
print_wsc_attributes(level + 1, "WSC Payload", wsc_data, wsc_len);
|
|
||||||
l_free(wsc_data);
|
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,
|
static void print_address(unsigned int level, const char *label,
|
||||||
const unsigned char address[6])
|
const unsigned char address[6])
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue