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