18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * P2P - IE parser
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps_i.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p_i.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct p2p_message *msg)
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i, nlen;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char devtype[WPS_DEV_TYPE_BUFSIZE];
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (id) {
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_CAPABILITY:
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Capability "
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->capability = data;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x "
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Group Capability %02x",
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data[0], data[1]);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_DEVICE_ID:
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < ETH_ALEN) {
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Device ID "
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->device_id = data;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR,
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(msg->device_id));
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_GROUP_OWNER_INTENT:
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 1) {
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent "
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->go_intent = data;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u "
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Tie breaker %u", data[0] >> 1, data[0] & 0x01);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_STATUS:
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 1) {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Status "
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->status = data;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_LISTEN_CHANNEL:
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len == 0) {
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore "
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "null channel");
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 5) {
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel "
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->listen_channel = data;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: "
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Country %c%c(0x%02x) Regulatory "
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Class %d Channel Number %d", data[0], data[1],
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data[2], data[3], data[4]);
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_OPERATING_CHANNEL:
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len == 0) {
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Ignore null channel");
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 5) {
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Operating "
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Channel attribute (length %d)", len);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->operating_channel = data;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Country %c%c(0x%02x) Regulatory "
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Class %d Channel Number %d", data[0], data[1],
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data[2], data[3], data[4]);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_CHANNEL_LIST:
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 3) {
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Channel List "
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->channel_list = data;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->channel_list_len = len;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String "
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "'%c%c(0x%02x)'", data[0], data[1], data[2]);
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List",
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    msg->channel_list, msg->channel_list_len);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_GROUP_INFO:
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->group_info = data;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->group_info_len = len;
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Group Info");
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_DEVICE_INFO:
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < ETH_ALEN + 2 + 8 + 1) {
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Device Info "
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->p2p_device_info = data;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->p2p_device_info_len = len;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = data;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->p2p_device_addr = pos;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ETH_ALEN;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->config_methods = WPA_GET_BE16(pos);
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->pri_dev_type = pos;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 8;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->num_sec_dev_types = *pos++;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (msg->num_sec_dev_types * 8 > data + len - pos) {
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Device Info underflow");
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += msg->num_sec_dev_types * 8;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data + len - pos < 4) {
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length %d", (int) (data + len - pos));
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) {
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name "
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "header", pos, 4);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlen = WPA_GET_BE16(pos);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data + len - pos < (int) nlen || nlen > 32) {
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length %d (buf len %d)", (int) nlen,
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (int) (data + len - pos));
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(msg->device_name, pos, nlen);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->device_name[nlen] = '\0';
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < nlen; i++) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (msg->device_name[i] == '\0')
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (msg->device_name[i] > 0 &&
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    msg->device_name[i] < 32)
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				msg->device_name[i] = '_';
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " primary device type %s device name '%s' "
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "config methods 0x%x",
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(msg->p2p_device_addr),
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps_dev_type_bin2str(msg->pri_dev_type, devtype,
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						sizeof(devtype)),
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   msg->device_name, msg->config_methods);
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_CONFIGURATION_TIMEOUT:
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Configuration "
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Timeout attribute (length %d)", len);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->config_timeout = data;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout");
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_INTENDED_INTERFACE_ADDR:
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < ETH_ALEN) {
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P "
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Interface Address attribute (length %d)",
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   len);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->intended_addr = data;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: "
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR, MAC2STR(msg->intended_addr));
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_GROUP_BSSID:
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < ETH_ALEN) {
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID "
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->group_bssid = data;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR,
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(msg->group_bssid));
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_GROUP_ID:
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < ETH_ALEN || len > ETH_ALEN + 32) {
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID "
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute length %d", len);
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->group_id = data;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->group_id_len = len;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address "
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR, MAC2STR(msg->group_id));
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID",
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  msg->group_id + ETH_ALEN,
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  msg->group_id_len - ETH_ALEN);
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_INVITATION_FLAGS:
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 1) {
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Invitation "
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Flag attribute (length %d)", len);
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->invitation_flags = data;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x",
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data[0]);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_MANAGEABILITY:
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 1) {
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Manageability "
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "attribute (length %d)", len);
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->manageability = data;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x",
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data[0]);
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_NOTICE_OF_ABSENCE:
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 2) {
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Notice of "
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Absence attribute (length %d)", len);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->noa = data;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->noa_len = len;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_EXT_LISTEN_TIMING:
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 4) {
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen "
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Timing attribute (length %d)", len);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->ext_listen_timing = data;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing "
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(period %u msec  interval %u msec)",
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   WPA_GET_LE16(msg->ext_listen_timing),
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   WPA_GET_LE16(msg->ext_listen_timing + 2));
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case P2P_ATTR_MINOR_REASON_CODE:
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len < 1) {
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason "
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Code attribute (length %d)", len);
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->minor_reason_code = data;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   *msg->minor_reason_code);
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(length %d)", id, len);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse_p2p_ie - Parse P2P IE
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Concatenated P2P IE(s) payload
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: Buffer for returning parsed attributes
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: Caller is responsible for clearing the msg data structure before
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * calling this function.
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos = wpabuf_head_u8(buf);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end = pos + wpabuf_len(buf);
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE");
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos < end) {
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 attr_len;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 >= end) {
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr_len = WPA_GET_LE16(pos + 1);
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   pos[0], attr_len);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 3 + attr_len > end) {
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "(len=%u left=%d)",
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   attr_len, (int) (end - pos - 3));
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 3 + attr_len;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE");
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(buf, &attr))
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) &&
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !msg->device_name[0])
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len);
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.config_methods) {
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_config_methods =
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPA_GET_BE16(attr.config_methods);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x",
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   msg->wps_config_methods);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.dev_password_id) {
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   msg->dev_password_id);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.primary_dev_type) {
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char devtype[WPS_DEV_TYPE_BUFSIZE];
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_pri_dev_type = attr.primary_dev_type;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s",
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype,
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						sizeof(devtype)));
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.sec_dev_type_list) {
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_sec_dev_type_list = attr.sec_dev_type_list;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_vendor_ext[i] = attr.vendor_ext[i];
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i];
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->manufacturer = attr.manufacturer;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->manufacturer_len = attr.manufacturer_len;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->model_name = attr.model_name;
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->model_name_len = attr.model_name_len;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->model_number = attr.model_number;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->model_number_len = attr.model_number_len;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->serial_number = attr.serial_number;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->serial_number_len = attr.serial_number_len;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE)
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: IEs from the message
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: Buffer for returning parsed attributes
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: Caller is responsible for clearing the msg data structure before
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * calling this function.
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: Caller must free temporary memory allocations by calling
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse_free() when the parsed data is not needed anymore.
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee802_11_elems elems;
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ieee802_11_parse_elems(data, len, &elems, 0);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (elems.ds_params && elems.ds_params_len >= 1)
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->ds_params = elems.ds_params;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (elems.ssid)
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg->ssid = elems.ssid - 2;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len,
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  WPS_DEV_OUI_WFA);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg->wps_attributes &&
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    p2p_parse_wps_ie(msg->wps_attributes, msg)) {
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(msg);
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len,
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  P2P_IE_VENDOR_TYPE);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg->p2p_attributes &&
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (msg->p2p_attributes)
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					msg->p2p_attributes);
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(msg);
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse - Parse a P2P Action frame contents
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Action frame payload after Category and Code fields
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: Buffer for returning parsed attributes
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: Caller must free temporary memory allocations by calling
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse_free() when the parsed data is not needed anymore.
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(msg, 0, sizeof(*msg));
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "P2P: Parsing the received message");
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 1) {
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message");
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->dialog_token = data[0];
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return p2p_parse_ies(data + 1, len - 1, msg);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_parse_free - Free temporary data from P2P parsing
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: Parsed attributes
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_parse_free(struct p2p_message *msg)
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(msg->p2p_attributes);
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->p2p_attributes = NULL;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(msg->wps_attributes);
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg->wps_attributes = NULL;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_group_info_parse(const u8 *gi, size_t gi_len,
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct p2p_group_info *info)
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *g, *gend;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(info, 0, sizeof(*info));
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (gi == NULL)
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	g = gi;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gend = gi + gi_len;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (g < gend) {
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct p2p_client_info *cli;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *t, *cend;
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int count;
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli = &info->client[info->num_clients];
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cend = g + 1 + g[0];
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (cend > gend)
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid data */
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* g at start of P2P Client Info Descriptor */
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* t at Device Capability Bitmap */
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		t = g + 1 + 2 * ETH_ALEN;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (t > cend)
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid data */
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->p2p_device_addr = g + 1;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->p2p_interface_addr = g + 1 + ETH_ALEN;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->dev_capab = t[0];
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (t + 1 + 2 + 8 + 1 > cend)
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid data */
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->config_methods = WPA_GET_BE16(&t[1]);
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->pri_dev_type = &t[3];
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		t += 1 + 2 + 8;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* t at Number of Secondary Device Types */
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->num_sec_dev_types = *t++;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (t + 8 * cli->num_sec_dev_types > cend)
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid data */
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->sec_dev_types = t;
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		t += 8 * cli->num_sec_dev_types;
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* t at Device Name in WPS TLV format */
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (t + 2 + 2 > cend)
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid data */
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (WPA_GET_BE16(t) != ATTR_DEV_NAME)
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid Device Name TLV */
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		t += 2;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_BE16(t);
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		t += 2;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count > cend - t)
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1; /* invalid Device Name TLV */
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count >= 32)
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			count = 32;
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->dev_name = (const char *) t;
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli->dev_name_len = count;
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		g = cend;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->num_clients++;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (info->num_clients == P2P_MAX_GROUP_ENTRIES)
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       char *end)
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos = buf;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_group_info info;
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int i;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_group_info_parse(gi, gi_len, &info) < 0)
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < info.num_clients; i++) {
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct p2p_client_info *cli;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char name[33];
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char devtype[WPS_DEV_TYPE_BUFSIZE];
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 s;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int count;
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cli = &info.client[i];
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "p2p_group_client: "
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "dev=" MACSTR " iface=" MACSTR,
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  MAC2STR(cli->p2p_device_addr),
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  MAC2STR(cli->p2p_interface_addr));
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos,
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  " dev_capab=0x%x config_methods=0x%x "
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "dev_type=%s",
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  cli->dev_capab, cli->config_methods,
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  wps_dev_type_bin2str(cli->pri_dev_type,
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						       devtype,
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						       sizeof(devtype)));
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (s = 0; s < cli->num_sec_dev_types; s++) {
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = os_snprintf(pos, end - pos, " dev_type=%s",
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  wps_dev_type_bin2str(
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  &cli->sec_dev_types[s * 8],
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  devtype, sizeof(devtype)));
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0 || ret >= end - pos)
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return pos - buf;
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += ret;
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(name, cli->dev_name, cli->dev_name_len);
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		name[cli->dev_name_len] = '\0';
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = (int) cli->dev_name_len - 1;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (count >= 0) {
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (name[count] > 0 && name[count] < 32)
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				name[count] = '_';
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			count--;
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pos - buf;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_attr_text - Build text format description of P2P IE attributes
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: P2P IE contents
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for returning text
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @end: Pointer to the end of the buf area
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Number of octets written to the buffer or -1 on faikure
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used to parse P2P IE contents into text format
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * field=value lines.
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_attr_text(struct wpabuf *data, char *buf, char *end)
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos = buf;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&msg, 0, sizeof(msg));
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse_p2p_ie(data, &msg))
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.capability) {
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos,
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "p2p_dev_capab=0x%x\n"
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "p2p_group_capab=0x%x\n",
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  msg.capability[0], msg.capability[1]);
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.pri_dev_type) {
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char devtype[WPS_DEV_TYPE_BUFSIZE];
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos,
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "p2p_primary_device_type=%s\n",
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  wps_dev_type_bin2str(msg.pri_dev_type,
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						       devtype,
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						       sizeof(devtype)));
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  msg.device_name);
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || ret >= end - pos)
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return pos - buf;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ret;
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.p2p_device_addr) {
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "\n",
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  MAC2STR(msg.p2p_device_addr));
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos - buf;
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  msg.config_methods);
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || ret >= end - pos)
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return pos - buf;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ret;
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = p2p_group_info_text(msg.group_info, msg.group_info_len,
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  pos, end);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return pos - buf;
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ret;
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pos - buf;
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie)
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&msg, 0, sizeof(msg));
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse_p2p_ie(p2p_ie, &msg))
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg.manageability)
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 p2p_get_group_capab(const struct wpabuf *p2p_ie)
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&msg, 0, sizeof(msg));
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse_p2p_ie(p2p_ie, &msg))
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg.capability)
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg.capability[1];
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie)
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&msg, 0, sizeof(msg));
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse_p2p_ie(p2p_ie, &msg))
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.p2p_device_addr)
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return msg.p2p_device_addr;
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.device_id)
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return msg.device_id;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
719