1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * P2P - IE parser
3e5b75505Sopenharmony_ci * Copyright (c) 2009-2010, Atheros Communications
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
13e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h"
14e5b75505Sopenharmony_ci#include "wps/wps_i.h"
15e5b75505Sopenharmony_ci#include "p2p_i.h"
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci
18e5b75505Sopenharmony_civoid p2p_copy_filter_devname(char *dst, size_t dst_len,
19e5b75505Sopenharmony_ci			     const void *src, size_t src_len)
20e5b75505Sopenharmony_ci{
21e5b75505Sopenharmony_ci	size_t i;
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci	if (src_len >= dst_len)
24e5b75505Sopenharmony_ci		src_len = dst_len - 1;
25e5b75505Sopenharmony_ci	os_memcpy(dst, src, src_len);
26e5b75505Sopenharmony_ci	dst[src_len] = '\0';
27e5b75505Sopenharmony_ci	for (i = 0; i < src_len; i++) {
28e5b75505Sopenharmony_ci		if (dst[i] == '\0')
29e5b75505Sopenharmony_ci			break;
30e5b75505Sopenharmony_ci		if (is_ctrl_char(dst[i]))
31e5b75505Sopenharmony_ci			dst[i] = '_';
32e5b75505Sopenharmony_ci	}
33e5b75505Sopenharmony_ci}
34e5b75505Sopenharmony_ci
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_cistatic int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
37e5b75505Sopenharmony_ci			       struct p2p_message *msg)
38e5b75505Sopenharmony_ci{
39e5b75505Sopenharmony_ci	const u8 *pos;
40e5b75505Sopenharmony_ci	u16 nlen;
41e5b75505Sopenharmony_ci	char devtype[WPS_DEV_TYPE_BUFSIZE];
42e5b75505Sopenharmony_ci
43e5b75505Sopenharmony_ci	switch (id) {
44e5b75505Sopenharmony_ci	case P2P_ATTR_CAPABILITY:
45e5b75505Sopenharmony_ci		if (len < 2) {
46e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Capability "
47e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
48e5b75505Sopenharmony_ci			return -1;
49e5b75505Sopenharmony_ci		}
50e5b75505Sopenharmony_ci		msg->capability = data;
51e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x "
52e5b75505Sopenharmony_ci			   "Group Capability %02x",
53e5b75505Sopenharmony_ci			   data[0], data[1]);
54e5b75505Sopenharmony_ci		break;
55e5b75505Sopenharmony_ci	case P2P_ATTR_DEVICE_ID:
56e5b75505Sopenharmony_ci		if (len < ETH_ALEN) {
57e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Device ID "
58e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
59e5b75505Sopenharmony_ci			return -1;
60e5b75505Sopenharmony_ci		}
61e5b75505Sopenharmony_ci		msg->device_id = data;
62e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR,
63e5b75505Sopenharmony_ci			   MAC2STR(msg->device_id));
64e5b75505Sopenharmony_ci		break;
65e5b75505Sopenharmony_ci	case P2P_ATTR_GROUP_OWNER_INTENT:
66e5b75505Sopenharmony_ci		if (len < 1) {
67e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent "
68e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
69e5b75505Sopenharmony_ci			return -1;
70e5b75505Sopenharmony_ci		}
71e5b75505Sopenharmony_ci		msg->go_intent = data;
72e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u "
73e5b75505Sopenharmony_ci			   "Tie breaker %u", data[0] >> 1, data[0] & 0x01);
74e5b75505Sopenharmony_ci		break;
75e5b75505Sopenharmony_ci	case P2P_ATTR_STATUS:
76e5b75505Sopenharmony_ci		if (len < 1) {
77e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Status "
78e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
79e5b75505Sopenharmony_ci			return -1;
80e5b75505Sopenharmony_ci		}
81e5b75505Sopenharmony_ci		msg->status = data;
82e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]);
83e5b75505Sopenharmony_ci		break;
84e5b75505Sopenharmony_ci	case P2P_ATTR_LISTEN_CHANNEL:
85e5b75505Sopenharmony_ci		if (len == 0) {
86e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore "
87e5b75505Sopenharmony_ci				   "null channel");
88e5b75505Sopenharmony_ci			break;
89e5b75505Sopenharmony_ci		}
90e5b75505Sopenharmony_ci		if (len < 5) {
91e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel "
92e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
93e5b75505Sopenharmony_ci			return -1;
94e5b75505Sopenharmony_ci		}
95e5b75505Sopenharmony_ci		msg->listen_channel = data;
96e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: "
97e5b75505Sopenharmony_ci			   "Country %c%c(0x%02x) Regulatory "
98e5b75505Sopenharmony_ci			   "Class %d Channel Number %d", data[0], data[1],
99e5b75505Sopenharmony_ci			   data[2], data[3], data[4]);
100e5b75505Sopenharmony_ci		break;
101e5b75505Sopenharmony_ci	case P2P_ATTR_OPERATING_CHANNEL:
102e5b75505Sopenharmony_ci		if (len == 0) {
103e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
104e5b75505Sopenharmony_ci				   "Ignore null channel");
105e5b75505Sopenharmony_ci			break;
106e5b75505Sopenharmony_ci		}
107e5b75505Sopenharmony_ci		if (len < 5) {
108e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Operating "
109e5b75505Sopenharmony_ci				   "Channel attribute (length %d)", len);
110e5b75505Sopenharmony_ci			return -1;
111e5b75505Sopenharmony_ci		}
112e5b75505Sopenharmony_ci		msg->operating_channel = data;
113e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: "
114e5b75505Sopenharmony_ci			   "Country %c%c(0x%02x) Regulatory "
115e5b75505Sopenharmony_ci			   "Class %d Channel Number %d", data[0], data[1],
116e5b75505Sopenharmony_ci			   data[2], data[3], data[4]);
117e5b75505Sopenharmony_ci		break;
118e5b75505Sopenharmony_ci	case P2P_ATTR_CHANNEL_LIST:
119e5b75505Sopenharmony_ci		if (len < 3) {
120e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Channel List "
121e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
122e5b75505Sopenharmony_ci			return -1;
123e5b75505Sopenharmony_ci		}
124e5b75505Sopenharmony_ci		msg->channel_list = data;
125e5b75505Sopenharmony_ci		msg->channel_list_len = len;
126e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String "
127e5b75505Sopenharmony_ci			   "'%c%c(0x%02x)'", data[0], data[1], data[2]);
128e5b75505Sopenharmony_ci		wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List",
129e5b75505Sopenharmony_ci			    msg->channel_list, msg->channel_list_len);
130e5b75505Sopenharmony_ci		break;
131e5b75505Sopenharmony_ci	case P2P_ATTR_GROUP_INFO:
132e5b75505Sopenharmony_ci		msg->group_info = data;
133e5b75505Sopenharmony_ci		msg->group_info_len = len;
134e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Group Info");
135e5b75505Sopenharmony_ci		break;
136e5b75505Sopenharmony_ci	case P2P_ATTR_DEVICE_INFO:
137e5b75505Sopenharmony_ci		if (len < ETH_ALEN + 2 + 8 + 1) {
138e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Device Info "
139e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
140e5b75505Sopenharmony_ci			return -1;
141e5b75505Sopenharmony_ci		}
142e5b75505Sopenharmony_ci		msg->p2p_device_info = data;
143e5b75505Sopenharmony_ci		msg->p2p_device_info_len = len;
144e5b75505Sopenharmony_ci		pos = data;
145e5b75505Sopenharmony_ci		msg->p2p_device_addr = pos;
146e5b75505Sopenharmony_ci		pos += ETH_ALEN;
147e5b75505Sopenharmony_ci		msg->config_methods = WPA_GET_BE16(pos);
148e5b75505Sopenharmony_ci		pos += 2;
149e5b75505Sopenharmony_ci		msg->pri_dev_type = pos;
150e5b75505Sopenharmony_ci		pos += 8;
151e5b75505Sopenharmony_ci		msg->num_sec_dev_types = *pos++;
152e5b75505Sopenharmony_ci		if (msg->num_sec_dev_types * 8 > data + len - pos) {
153e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Device Info underflow");
154e5b75505Sopenharmony_ci			return -1;
155e5b75505Sopenharmony_ci		}
156e5b75505Sopenharmony_ci		pos += msg->num_sec_dev_types * 8;
157e5b75505Sopenharmony_ci		if (data + len - pos < 4) {
158e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
159e5b75505Sopenharmony_ci				   "length %d", (int) (data + len - pos));
160e5b75505Sopenharmony_ci			return -1;
161e5b75505Sopenharmony_ci		}
162e5b75505Sopenharmony_ci		if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) {
163e5b75505Sopenharmony_ci			wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name "
164e5b75505Sopenharmony_ci				    "header", pos, 4);
165e5b75505Sopenharmony_ci			return -1;
166e5b75505Sopenharmony_ci		}
167e5b75505Sopenharmony_ci		pos += 2;
168e5b75505Sopenharmony_ci		nlen = WPA_GET_BE16(pos);
169e5b75505Sopenharmony_ci		pos += 2;
170e5b75505Sopenharmony_ci		if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
171e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
172e5b75505Sopenharmony_ci				   "length %u (buf len %d)", nlen,
173e5b75505Sopenharmony_ci				   (int) (data + len - pos));
174e5b75505Sopenharmony_ci			return -1;
175e5b75505Sopenharmony_ci		}
176e5b75505Sopenharmony_ci		p2p_copy_filter_devname(msg->device_name,
177e5b75505Sopenharmony_ci					sizeof(msg->device_name), pos, nlen);
178e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "P2P: * Device Info: addr " MACSTR
179e5b75505Sopenharmony_ci			   " primary device type %s device name '%s' "
180e5b75505Sopenharmony_ci			   "config methods 0x%x",
181e5b75505Sopenharmony_ci			   MAC2STR(msg->p2p_device_addr),
182e5b75505Sopenharmony_ci			   wps_dev_type_bin2str(msg->pri_dev_type, devtype,
183e5b75505Sopenharmony_ci						sizeof(devtype)),
184e5b75505Sopenharmony_ci			   msg->device_name, msg->config_methods);
185e5b75505Sopenharmony_ci		break;
186e5b75505Sopenharmony_ci	case P2P_ATTR_CONFIGURATION_TIMEOUT:
187e5b75505Sopenharmony_ci		if (len < 2) {
188e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Configuration "
189e5b75505Sopenharmony_ci				   "Timeout attribute (length %d)", len);
190e5b75505Sopenharmony_ci			return -1;
191e5b75505Sopenharmony_ci		}
192e5b75505Sopenharmony_ci		msg->config_timeout = data;
193e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout");
194e5b75505Sopenharmony_ci		break;
195e5b75505Sopenharmony_ci	case P2P_ATTR_INTENDED_INTERFACE_ADDR:
196e5b75505Sopenharmony_ci		if (len < ETH_ALEN) {
197e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P "
198e5b75505Sopenharmony_ci				   "Interface Address attribute (length %d)",
199e5b75505Sopenharmony_ci				   len);
200e5b75505Sopenharmony_ci			return -1;
201e5b75505Sopenharmony_ci		}
202e5b75505Sopenharmony_ci		msg->intended_addr = data;
203e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: "
204e5b75505Sopenharmony_ci			   MACSTR, MAC2STR(msg->intended_addr));
205e5b75505Sopenharmony_ci		break;
206e5b75505Sopenharmony_ci	case P2P_ATTR_GROUP_BSSID:
207e5b75505Sopenharmony_ci		if (len < ETH_ALEN) {
208e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID "
209e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
210e5b75505Sopenharmony_ci			return -1;
211e5b75505Sopenharmony_ci		}
212e5b75505Sopenharmony_ci		msg->group_bssid = data;
213e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR,
214e5b75505Sopenharmony_ci			   MAC2STR(msg->group_bssid));
215e5b75505Sopenharmony_ci		break;
216e5b75505Sopenharmony_ci	case P2P_ATTR_GROUP_ID:
217e5b75505Sopenharmony_ci		if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
218e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID "
219e5b75505Sopenharmony_ci				   "attribute length %d", len);
220e5b75505Sopenharmony_ci			return -1;
221e5b75505Sopenharmony_ci		}
222e5b75505Sopenharmony_ci		msg->group_id = data;
223e5b75505Sopenharmony_ci		msg->group_id_len = len;
224e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address "
225e5b75505Sopenharmony_ci			   MACSTR, MAC2STR(msg->group_id));
226e5b75505Sopenharmony_ci		wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID",
227e5b75505Sopenharmony_ci				  msg->group_id + ETH_ALEN,
228e5b75505Sopenharmony_ci				  msg->group_id_len - ETH_ALEN);
229e5b75505Sopenharmony_ci		break;
230e5b75505Sopenharmony_ci	case P2P_ATTR_INVITATION_FLAGS:
231e5b75505Sopenharmony_ci		if (len < 1) {
232e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Invitation "
233e5b75505Sopenharmony_ci				   "Flag attribute (length %d)", len);
234e5b75505Sopenharmony_ci			return -1;
235e5b75505Sopenharmony_ci		}
236e5b75505Sopenharmony_ci		msg->invitation_flags = data;
237e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x",
238e5b75505Sopenharmony_ci			   data[0]);
239e5b75505Sopenharmony_ci		break;
240e5b75505Sopenharmony_ci	case P2P_ATTR_MANAGEABILITY:
241e5b75505Sopenharmony_ci		if (len < 1) {
242e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Manageability "
243e5b75505Sopenharmony_ci				   "attribute (length %d)", len);
244e5b75505Sopenharmony_ci			return -1;
245e5b75505Sopenharmony_ci		}
246e5b75505Sopenharmony_ci		msg->manageability = data;
247e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x",
248e5b75505Sopenharmony_ci			   data[0]);
249e5b75505Sopenharmony_ci		break;
250e5b75505Sopenharmony_ci	case P2P_ATTR_NOTICE_OF_ABSENCE:
251e5b75505Sopenharmony_ci		if (len < 2) {
252e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Notice of "
253e5b75505Sopenharmony_ci				   "Absence attribute (length %d)", len);
254e5b75505Sopenharmony_ci			return -1;
255e5b75505Sopenharmony_ci		}
256e5b75505Sopenharmony_ci		msg->noa = data;
257e5b75505Sopenharmony_ci		msg->noa_len = len;
258e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
259e5b75505Sopenharmony_ci		break;
260e5b75505Sopenharmony_ci	case P2P_ATTR_EXT_LISTEN_TIMING:
261e5b75505Sopenharmony_ci		if (len < 4) {
262e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen "
263e5b75505Sopenharmony_ci				   "Timing attribute (length %d)", len);
264e5b75505Sopenharmony_ci			return -1;
265e5b75505Sopenharmony_ci		}
266e5b75505Sopenharmony_ci		msg->ext_listen_timing = data;
267e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing "
268e5b75505Sopenharmony_ci			   "(period %u msec  interval %u msec)",
269e5b75505Sopenharmony_ci			   WPA_GET_LE16(msg->ext_listen_timing),
270e5b75505Sopenharmony_ci			   WPA_GET_LE16(msg->ext_listen_timing + 2));
271e5b75505Sopenharmony_ci		break;
272e5b75505Sopenharmony_ci	case P2P_ATTR_MINOR_REASON_CODE:
273e5b75505Sopenharmony_ci		if (len < 1) {
274e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason "
275e5b75505Sopenharmony_ci				   "Code attribute (length %d)", len);
276e5b75505Sopenharmony_ci			return -1;
277e5b75505Sopenharmony_ci		}
278e5b75505Sopenharmony_ci		msg->minor_reason_code = data;
279e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
280e5b75505Sopenharmony_ci			   *msg->minor_reason_code);
281e5b75505Sopenharmony_ci		break;
282e5b75505Sopenharmony_ci	case P2P_ATTR_OOB_GO_NEG_CHANNEL:
283e5b75505Sopenharmony_ci		if (len < 6) {
284e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg "
285e5b75505Sopenharmony_ci				   "Channel attribute (length %d)", len);
286e5b75505Sopenharmony_ci			return -1;
287e5b75505Sopenharmony_ci		}
288e5b75505Sopenharmony_ci		msg->oob_go_neg_channel = data;
289e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: "
290e5b75505Sopenharmony_ci			   "Country %c%c(0x%02x) Operating Class %d "
291e5b75505Sopenharmony_ci			   "Channel Number %d Role %d",
292e5b75505Sopenharmony_ci			   data[0], data[1], data[2], data[3], data[4],
293e5b75505Sopenharmony_ci			   data[5]);
294e5b75505Sopenharmony_ci		break;
295e5b75505Sopenharmony_ci	case P2P_ATTR_SERVICE_HASH:
296e5b75505Sopenharmony_ci		if (len < P2PS_HASH_LEN) {
297e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
298e5b75505Sopenharmony_ci				   "P2P: Too short Service Hash (length %u)",
299e5b75505Sopenharmony_ci				   len);
300e5b75505Sopenharmony_ci			return -1;
301e5b75505Sopenharmony_ci		}
302e5b75505Sopenharmony_ci		msg->service_hash_count = len / P2PS_HASH_LEN;
303e5b75505Sopenharmony_ci		msg->service_hash = data;
304e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len);
305e5b75505Sopenharmony_ci		break;
306e5b75505Sopenharmony_ci	case P2P_ATTR_SESSION_INFORMATION_DATA:
307e5b75505Sopenharmony_ci		msg->session_info = data;
308e5b75505Sopenharmony_ci		msg->session_info_len = len;
309e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p",
310e5b75505Sopenharmony_ci			   len, data);
311e5b75505Sopenharmony_ci		break;
312e5b75505Sopenharmony_ci	case P2P_ATTR_CONNECTION_CAPABILITY:
313e5b75505Sopenharmony_ci		if (len < 1) {
314e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
315e5b75505Sopenharmony_ci				   "P2P: Too short Connection Capability (length %u)",
316e5b75505Sopenharmony_ci				   len);
317e5b75505Sopenharmony_ci			return -1;
318e5b75505Sopenharmony_ci		}
319e5b75505Sopenharmony_ci		msg->conn_cap = data;
320e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
321e5b75505Sopenharmony_ci			   *msg->conn_cap);
322e5b75505Sopenharmony_ci		break;
323e5b75505Sopenharmony_ci	case P2P_ATTR_ADVERTISEMENT_ID:
324e5b75505Sopenharmony_ci		if (len < 10) {
325e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
326e5b75505Sopenharmony_ci				   "P2P: Too short Advertisement ID (length %u)",
327e5b75505Sopenharmony_ci				   len);
328e5b75505Sopenharmony_ci			return -1;
329e5b75505Sopenharmony_ci		}
330e5b75505Sopenharmony_ci		msg->adv_id = data;
331e5b75505Sopenharmony_ci		msg->adv_mac = &data[sizeof(u32)];
332e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x",
333e5b75505Sopenharmony_ci			   WPA_GET_LE32(data));
334e5b75505Sopenharmony_ci		break;
335e5b75505Sopenharmony_ci	case P2P_ATTR_ADVERTISED_SERVICE:
336e5b75505Sopenharmony_ci		if (len < 8) {
337e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
338e5b75505Sopenharmony_ci				   "P2P: Too short Service Instance (length %u)",
339e5b75505Sopenharmony_ci				   len);
340e5b75505Sopenharmony_ci			return -1;
341e5b75505Sopenharmony_ci		}
342e5b75505Sopenharmony_ci		msg->adv_service_instance = data;
343e5b75505Sopenharmony_ci		msg->adv_service_instance_len = len;
344e5b75505Sopenharmony_ci		if (len <= 255 + 8) {
345e5b75505Sopenharmony_ci			char str[256];
346e5b75505Sopenharmony_ci			u8 namelen;
347e5b75505Sopenharmony_ci
348e5b75505Sopenharmony_ci			namelen = data[6];
349e5b75505Sopenharmony_ci			if (namelen > len - 7)
350e5b75505Sopenharmony_ci				break;
351e5b75505Sopenharmony_ci			os_memcpy(str, &data[7], namelen);
352e5b75505Sopenharmony_ci			str[namelen] = '\0';
353e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s",
354e5b75505Sopenharmony_ci				   WPA_GET_LE32(data), str);
355e5b75505Sopenharmony_ci		} else {
356e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p",
357e5b75505Sopenharmony_ci				   data);
358e5b75505Sopenharmony_ci		}
359e5b75505Sopenharmony_ci		break;
360e5b75505Sopenharmony_ci	case P2P_ATTR_SESSION_ID:
361e5b75505Sopenharmony_ci		if (len < sizeof(u32) + ETH_ALEN) {
362e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
363e5b75505Sopenharmony_ci				   "P2P: Too short Session ID Info (length %u)",
364e5b75505Sopenharmony_ci				   len);
365e5b75505Sopenharmony_ci			return -1;
366e5b75505Sopenharmony_ci		}
367e5b75505Sopenharmony_ci		msg->session_id = data;
368e5b75505Sopenharmony_ci		msg->session_mac = &data[sizeof(u32)];
369e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR,
370e5b75505Sopenharmony_ci			   WPA_GET_LE32(data), MAC2STR(msg->session_mac));
371e5b75505Sopenharmony_ci		break;
372e5b75505Sopenharmony_ci	case P2P_ATTR_FEATURE_CAPABILITY:
373e5b75505Sopenharmony_ci		if (!len) {
374e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
375e5b75505Sopenharmony_ci				   "P2P: Too short Feature Capability (length %u)",
376e5b75505Sopenharmony_ci				   len);
377e5b75505Sopenharmony_ci			return -1;
378e5b75505Sopenharmony_ci		}
379e5b75505Sopenharmony_ci		msg->feature_cap = data;
380e5b75505Sopenharmony_ci		msg->feature_cap_len = len;
381e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len);
382e5b75505Sopenharmony_ci		break;
383e5b75505Sopenharmony_ci	case P2P_ATTR_PERSISTENT_GROUP:
384e5b75505Sopenharmony_ci	{
385e5b75505Sopenharmony_ci		if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
386e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
387e5b75505Sopenharmony_ci				   "P2P: Invalid Persistent Group Info (length %u)",
388e5b75505Sopenharmony_ci				   len);
389e5b75505Sopenharmony_ci			return -1;
390e5b75505Sopenharmony_ci		}
391e5b75505Sopenharmony_ci
392e5b75505Sopenharmony_ci		msg->persistent_dev = data;
393e5b75505Sopenharmony_ci		msg->persistent_ssid_len = len - ETH_ALEN;
394e5b75505Sopenharmony_ci		msg->persistent_ssid = &data[ETH_ALEN];
395e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s",
396e5b75505Sopenharmony_ci			   MAC2STR(msg->persistent_dev),
397e5b75505Sopenharmony_ci			   wpa_ssid_txt(msg->persistent_ssid,
398e5b75505Sopenharmony_ci					msg->persistent_ssid_len));
399e5b75505Sopenharmony_ci		break;
400e5b75505Sopenharmony_ci	}
401e5b75505Sopenharmony_ci	default:
402e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
403e5b75505Sopenharmony_ci			   "(length %d)", id, len);
404e5b75505Sopenharmony_ci		break;
405e5b75505Sopenharmony_ci	}
406e5b75505Sopenharmony_ci
407e5b75505Sopenharmony_ci	return 0;
408e5b75505Sopenharmony_ci}
409e5b75505Sopenharmony_ci
410e5b75505Sopenharmony_ci
411e5b75505Sopenharmony_ci/**
412e5b75505Sopenharmony_ci * p2p_parse_p2p_ie - Parse P2P IE
413e5b75505Sopenharmony_ci * @buf: Concatenated P2P IE(s) payload
414e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes
415e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure
416e5b75505Sopenharmony_ci *
417e5b75505Sopenharmony_ci * Note: Caller is responsible for clearing the msg data structure before
418e5b75505Sopenharmony_ci * calling this function.
419e5b75505Sopenharmony_ci */
420e5b75505Sopenharmony_ciint p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
421e5b75505Sopenharmony_ci{
422e5b75505Sopenharmony_ci	const u8 *pos = wpabuf_head_u8(buf);
423e5b75505Sopenharmony_ci	const u8 *end = pos + wpabuf_len(buf);
424e5b75505Sopenharmony_ci
425e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE");
426e5b75505Sopenharmony_ci
427e5b75505Sopenharmony_ci	while (pos < end) {
428e5b75505Sopenharmony_ci		u16 attr_len;
429e5b75505Sopenharmony_ci		u8 id;
430e5b75505Sopenharmony_ci
431e5b75505Sopenharmony_ci		if (end - pos < 3) {
432e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
433e5b75505Sopenharmony_ci			return -1;
434e5b75505Sopenharmony_ci		}
435e5b75505Sopenharmony_ci		id = *pos++;
436e5b75505Sopenharmony_ci		attr_len = WPA_GET_LE16(pos);
437e5b75505Sopenharmony_ci		pos += 2;
438e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
439e5b75505Sopenharmony_ci			   id, attr_len);
440e5b75505Sopenharmony_ci		if (attr_len > end - pos) {
441e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
442e5b75505Sopenharmony_ci				   "(len=%u left=%d)",
443e5b75505Sopenharmony_ci				   attr_len, (int) (end - pos));
444e5b75505Sopenharmony_ci			wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
445e5b75505Sopenharmony_ci			return -1;
446e5b75505Sopenharmony_ci		}
447e5b75505Sopenharmony_ci		if (p2p_parse_attribute(id, pos, attr_len, msg))
448e5b75505Sopenharmony_ci			return -1;
449e5b75505Sopenharmony_ci		pos += attr_len;
450e5b75505Sopenharmony_ci	}
451e5b75505Sopenharmony_ci
452e5b75505Sopenharmony_ci	return 0;
453e5b75505Sopenharmony_ci}
454e5b75505Sopenharmony_ci
455e5b75505Sopenharmony_ci
456e5b75505Sopenharmony_cistatic int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
457e5b75505Sopenharmony_ci{
458e5b75505Sopenharmony_ci	struct wps_parse_attr attr;
459e5b75505Sopenharmony_ci	int i;
460e5b75505Sopenharmony_ci
461e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE");
462e5b75505Sopenharmony_ci	if (wps_parse_msg(buf, &attr))
463e5b75505Sopenharmony_ci		return -1;
464e5b75505Sopenharmony_ci	if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) &&
465e5b75505Sopenharmony_ci	    !msg->device_name[0])
466e5b75505Sopenharmony_ci		os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len);
467e5b75505Sopenharmony_ci	if (attr.config_methods) {
468e5b75505Sopenharmony_ci		msg->wps_config_methods =
469e5b75505Sopenharmony_ci			WPA_GET_BE16(attr.config_methods);
470e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x",
471e5b75505Sopenharmony_ci			   msg->wps_config_methods);
472e5b75505Sopenharmony_ci	}
473e5b75505Sopenharmony_ci	if (attr.dev_password_id) {
474e5b75505Sopenharmony_ci		msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
475e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
476e5b75505Sopenharmony_ci			   msg->dev_password_id);
477e5b75505Sopenharmony_ci		msg->dev_password_id_present = 1;
478e5b75505Sopenharmony_ci	}
479e5b75505Sopenharmony_ci	if (attr.primary_dev_type) {
480e5b75505Sopenharmony_ci		char devtype[WPS_DEV_TYPE_BUFSIZE];
481e5b75505Sopenharmony_ci		msg->wps_pri_dev_type = attr.primary_dev_type;
482e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s",
483e5b75505Sopenharmony_ci			   wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype,
484e5b75505Sopenharmony_ci						sizeof(devtype)));
485e5b75505Sopenharmony_ci	}
486e5b75505Sopenharmony_ci	if (attr.sec_dev_type_list) {
487e5b75505Sopenharmony_ci		msg->wps_sec_dev_type_list = attr.sec_dev_type_list;
488e5b75505Sopenharmony_ci		msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len;
489e5b75505Sopenharmony_ci	}
490e5b75505Sopenharmony_ci
491e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
492e5b75505Sopenharmony_ci		msg->wps_vendor_ext[i] = attr.vendor_ext[i];
493e5b75505Sopenharmony_ci		msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i];
494e5b75505Sopenharmony_ci	}
495e5b75505Sopenharmony_ci
496e5b75505Sopenharmony_ci	msg->manufacturer = attr.manufacturer;
497e5b75505Sopenharmony_ci	msg->manufacturer_len = attr.manufacturer_len;
498e5b75505Sopenharmony_ci	msg->model_name = attr.model_name;
499e5b75505Sopenharmony_ci	msg->model_name_len = attr.model_name_len;
500e5b75505Sopenharmony_ci	msg->model_number = attr.model_number;
501e5b75505Sopenharmony_ci	msg->model_number_len = attr.model_number_len;
502e5b75505Sopenharmony_ci	msg->serial_number = attr.serial_number;
503e5b75505Sopenharmony_ci	msg->serial_number_len = attr.serial_number_len;
504e5b75505Sopenharmony_ci
505e5b75505Sopenharmony_ci	msg->oob_dev_password = attr.oob_dev_password;
506e5b75505Sopenharmony_ci	msg->oob_dev_password_len = attr.oob_dev_password_len;
507e5b75505Sopenharmony_ci
508e5b75505Sopenharmony_ci	return 0;
509e5b75505Sopenharmony_ci}
510e5b75505Sopenharmony_ci
511e5b75505Sopenharmony_ci
512e5b75505Sopenharmony_ci/**
513e5b75505Sopenharmony_ci * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE)
514e5b75505Sopenharmony_ci * @data: IEs from the message
515e5b75505Sopenharmony_ci * @len: Length of data buffer in octets
516e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes
517e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure
518e5b75505Sopenharmony_ci *
519e5b75505Sopenharmony_ci * Note: Caller is responsible for clearing the msg data structure before
520e5b75505Sopenharmony_ci * calling this function.
521e5b75505Sopenharmony_ci *
522e5b75505Sopenharmony_ci * Note: Caller must free temporary memory allocations by calling
523e5b75505Sopenharmony_ci * p2p_parse_free() when the parsed data is not needed anymore.
524e5b75505Sopenharmony_ci */
525e5b75505Sopenharmony_ciint p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
526e5b75505Sopenharmony_ci{
527e5b75505Sopenharmony_ci	struct ieee802_11_elems elems;
528e5b75505Sopenharmony_ci
529e5b75505Sopenharmony_ci	ieee802_11_parse_elems(data, len, &elems, 0);
530e5b75505Sopenharmony_ci	if (elems.ds_params)
531e5b75505Sopenharmony_ci		msg->ds_params = elems.ds_params;
532e5b75505Sopenharmony_ci	if (elems.ssid)
533e5b75505Sopenharmony_ci		msg->ssid = elems.ssid - 2;
534e5b75505Sopenharmony_ci
535e5b75505Sopenharmony_ci	msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len,
536e5b75505Sopenharmony_ci							  WPS_DEV_OUI_WFA);
537e5b75505Sopenharmony_ci	if (msg->wps_attributes &&
538e5b75505Sopenharmony_ci	    p2p_parse_wps_ie(msg->wps_attributes, msg)) {
539e5b75505Sopenharmony_ci		p2p_parse_free(msg);
540e5b75505Sopenharmony_ci		return -1;
541e5b75505Sopenharmony_ci	}
542e5b75505Sopenharmony_ci
543e5b75505Sopenharmony_ci	msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len,
544e5b75505Sopenharmony_ci							  P2P_IE_VENDOR_TYPE);
545e5b75505Sopenharmony_ci	if (msg->p2p_attributes &&
546e5b75505Sopenharmony_ci	    p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
547e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
548e5b75505Sopenharmony_ci		if (msg->p2p_attributes)
549e5b75505Sopenharmony_ci			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
550e5b75505Sopenharmony_ci					msg->p2p_attributes);
551e5b75505Sopenharmony_ci		p2p_parse_free(msg);
552e5b75505Sopenharmony_ci		return -1;
553e5b75505Sopenharmony_ci	}
554e5b75505Sopenharmony_ci
555e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
556e5b75505Sopenharmony_ci	if (elems.wfd) {
557e5b75505Sopenharmony_ci		msg->wfd_subelems = ieee802_11_vendor_ie_concat(
558e5b75505Sopenharmony_ci			data, len, WFD_IE_VENDOR_TYPE);
559e5b75505Sopenharmony_ci	}
560e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
561e5b75505Sopenharmony_ci
562e5b75505Sopenharmony_ci	msg->pref_freq_list = elems.pref_freq_list;
563e5b75505Sopenharmony_ci	msg->pref_freq_list_len = elems.pref_freq_list_len;
564e5b75505Sopenharmony_ci
565e5b75505Sopenharmony_ci	return 0;
566e5b75505Sopenharmony_ci}
567e5b75505Sopenharmony_ci
568e5b75505Sopenharmony_ci
569e5b75505Sopenharmony_ci/**
570e5b75505Sopenharmony_ci * p2p_parse - Parse a P2P Action frame contents
571e5b75505Sopenharmony_ci * @data: Action frame payload after Category and Code fields
572e5b75505Sopenharmony_ci * @len: Length of data buffer in octets
573e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes
574e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure
575e5b75505Sopenharmony_ci *
576e5b75505Sopenharmony_ci * Note: Caller must free temporary memory allocations by calling
577e5b75505Sopenharmony_ci * p2p_parse_free() when the parsed data is not needed anymore.
578e5b75505Sopenharmony_ci */
579e5b75505Sopenharmony_ciint p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
580e5b75505Sopenharmony_ci{
581e5b75505Sopenharmony_ci	os_memset(msg, 0, sizeof(*msg));
582e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: Parsing the received message");
583e5b75505Sopenharmony_ci	if (len < 1) {
584e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message");
585e5b75505Sopenharmony_ci		return -1;
586e5b75505Sopenharmony_ci	}
587e5b75505Sopenharmony_ci	msg->dialog_token = data[0];
588e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token);
589e5b75505Sopenharmony_ci
590e5b75505Sopenharmony_ci	return p2p_parse_ies(data + 1, len - 1, msg);
591e5b75505Sopenharmony_ci}
592e5b75505Sopenharmony_ci
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_ciint p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
595e5b75505Sopenharmony_ci			   size_t p2p_len, struct p2p_message *msg)
596e5b75505Sopenharmony_ci{
597e5b75505Sopenharmony_ci	os_memset(msg, 0, sizeof(*msg));
598e5b75505Sopenharmony_ci
599e5b75505Sopenharmony_ci	msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
600e5b75505Sopenharmony_ci	if (msg->wps_attributes &&
601e5b75505Sopenharmony_ci	    p2p_parse_wps_ie(msg->wps_attributes, msg)) {
602e5b75505Sopenharmony_ci		p2p_parse_free(msg);
603e5b75505Sopenharmony_ci		return -1;
604e5b75505Sopenharmony_ci	}
605e5b75505Sopenharmony_ci
606e5b75505Sopenharmony_ci	msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
607e5b75505Sopenharmony_ci	if (msg->p2p_attributes &&
608e5b75505Sopenharmony_ci	    p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
609e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
610e5b75505Sopenharmony_ci		if (msg->p2p_attributes)
611e5b75505Sopenharmony_ci			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
612e5b75505Sopenharmony_ci					msg->p2p_attributes);
613e5b75505Sopenharmony_ci		p2p_parse_free(msg);
614e5b75505Sopenharmony_ci		return -1;
615e5b75505Sopenharmony_ci	}
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci	return 0;
618e5b75505Sopenharmony_ci}
619e5b75505Sopenharmony_ci
620e5b75505Sopenharmony_ci
621e5b75505Sopenharmony_ci/**
622e5b75505Sopenharmony_ci * p2p_parse_free - Free temporary data from P2P parsing
623e5b75505Sopenharmony_ci * @msg: Parsed attributes
624e5b75505Sopenharmony_ci */
625e5b75505Sopenharmony_civoid p2p_parse_free(struct p2p_message *msg)
626e5b75505Sopenharmony_ci{
627e5b75505Sopenharmony_ci	wpabuf_free(msg->p2p_attributes);
628e5b75505Sopenharmony_ci	msg->p2p_attributes = NULL;
629e5b75505Sopenharmony_ci	wpabuf_free(msg->wps_attributes);
630e5b75505Sopenharmony_ci	msg->wps_attributes = NULL;
631e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
632e5b75505Sopenharmony_ci	wpabuf_free(msg->wfd_subelems);
633e5b75505Sopenharmony_ci	msg->wfd_subelems = NULL;
634e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
635e5b75505Sopenharmony_ci}
636e5b75505Sopenharmony_ci
637e5b75505Sopenharmony_ci
638e5b75505Sopenharmony_ciint p2p_group_info_parse(const u8 *gi, size_t gi_len,
639e5b75505Sopenharmony_ci			 struct p2p_group_info *info)
640e5b75505Sopenharmony_ci{
641e5b75505Sopenharmony_ci	const u8 *g, *gend;
642e5b75505Sopenharmony_ci
643e5b75505Sopenharmony_ci	os_memset(info, 0, sizeof(*info));
644e5b75505Sopenharmony_ci	if (gi == NULL)
645e5b75505Sopenharmony_ci		return 0;
646e5b75505Sopenharmony_ci
647e5b75505Sopenharmony_ci	g = gi;
648e5b75505Sopenharmony_ci	gend = gi + gi_len;
649e5b75505Sopenharmony_ci	while (g < gend) {
650e5b75505Sopenharmony_ci		struct p2p_client_info *cli;
651e5b75505Sopenharmony_ci		const u8 *cend;
652e5b75505Sopenharmony_ci		u16 count;
653e5b75505Sopenharmony_ci		u8 len;
654e5b75505Sopenharmony_ci
655e5b75505Sopenharmony_ci		cli = &info->client[info->num_clients];
656e5b75505Sopenharmony_ci		len = *g++;
657e5b75505Sopenharmony_ci		if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
658e5b75505Sopenharmony_ci			return -1; /* invalid data */
659e5b75505Sopenharmony_ci		cend = g + len;
660e5b75505Sopenharmony_ci		/* g at start of P2P Client Info Descriptor */
661e5b75505Sopenharmony_ci		cli->p2p_device_addr = g;
662e5b75505Sopenharmony_ci		g += ETH_ALEN;
663e5b75505Sopenharmony_ci		cli->p2p_interface_addr = g;
664e5b75505Sopenharmony_ci		g += ETH_ALEN;
665e5b75505Sopenharmony_ci		cli->dev_capab = *g++;
666e5b75505Sopenharmony_ci
667e5b75505Sopenharmony_ci		cli->config_methods = WPA_GET_BE16(g);
668e5b75505Sopenharmony_ci		g += 2;
669e5b75505Sopenharmony_ci		cli->pri_dev_type = g;
670e5b75505Sopenharmony_ci		g += 8;
671e5b75505Sopenharmony_ci
672e5b75505Sopenharmony_ci		/* g at Number of Secondary Device Types */
673e5b75505Sopenharmony_ci		len = *g++;
674e5b75505Sopenharmony_ci		if (8 * len > cend - g)
675e5b75505Sopenharmony_ci			return -1; /* invalid data */
676e5b75505Sopenharmony_ci		cli->num_sec_dev_types = len;
677e5b75505Sopenharmony_ci		cli->sec_dev_types = g;
678e5b75505Sopenharmony_ci		g += 8 * len;
679e5b75505Sopenharmony_ci
680e5b75505Sopenharmony_ci		/* g at Device Name in WPS TLV format */
681e5b75505Sopenharmony_ci		if (cend - g < 2 + 2)
682e5b75505Sopenharmony_ci			return -1; /* invalid data */
683e5b75505Sopenharmony_ci		if (WPA_GET_BE16(g) != ATTR_DEV_NAME)
684e5b75505Sopenharmony_ci			return -1; /* invalid Device Name TLV */
685e5b75505Sopenharmony_ci		g += 2;
686e5b75505Sopenharmony_ci		count = WPA_GET_BE16(g);
687e5b75505Sopenharmony_ci		g += 2;
688e5b75505Sopenharmony_ci		if (count > cend - g)
689e5b75505Sopenharmony_ci			return -1; /* invalid Device Name TLV */
690e5b75505Sopenharmony_ci		if (count >= WPS_DEV_NAME_MAX_LEN)
691e5b75505Sopenharmony_ci			count = WPS_DEV_NAME_MAX_LEN;
692e5b75505Sopenharmony_ci		cli->dev_name = (const char *) g;
693e5b75505Sopenharmony_ci		cli->dev_name_len = count;
694e5b75505Sopenharmony_ci
695e5b75505Sopenharmony_ci		g = cend;
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci		info->num_clients++;
698e5b75505Sopenharmony_ci		if (info->num_clients == P2P_MAX_GROUP_ENTRIES)
699e5b75505Sopenharmony_ci			return -1;
700e5b75505Sopenharmony_ci	}
701e5b75505Sopenharmony_ci
702e5b75505Sopenharmony_ci	return 0;
703e5b75505Sopenharmony_ci}
704e5b75505Sopenharmony_ci
705e5b75505Sopenharmony_ci
706e5b75505Sopenharmony_cistatic int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
707e5b75505Sopenharmony_ci			       char *end)
708e5b75505Sopenharmony_ci{
709e5b75505Sopenharmony_ci	char *pos = buf;
710e5b75505Sopenharmony_ci	int ret;
711e5b75505Sopenharmony_ci	struct p2p_group_info info;
712e5b75505Sopenharmony_ci	unsigned int i;
713e5b75505Sopenharmony_ci
714e5b75505Sopenharmony_ci	if (p2p_group_info_parse(gi, gi_len, &info) < 0)
715e5b75505Sopenharmony_ci		return 0;
716e5b75505Sopenharmony_ci
717e5b75505Sopenharmony_ci	for (i = 0; i < info.num_clients; i++) {
718e5b75505Sopenharmony_ci		struct p2p_client_info *cli;
719e5b75505Sopenharmony_ci		char name[WPS_DEV_NAME_MAX_LEN + 1];
720e5b75505Sopenharmony_ci		char devtype[WPS_DEV_TYPE_BUFSIZE];
721e5b75505Sopenharmony_ci		u8 s;
722e5b75505Sopenharmony_ci		int count;
723e5b75505Sopenharmony_ci
724e5b75505Sopenharmony_ci		cli = &info.client[i];
725e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos, "p2p_group_client: "
726e5b75505Sopenharmony_ci				  "dev=" MACSTR " iface=" MACSTR,
727e5b75505Sopenharmony_ci				  MAC2STR(cli->p2p_device_addr),
728e5b75505Sopenharmony_ci				  MAC2STR(cli->p2p_interface_addr));
729e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
730e5b75505Sopenharmony_ci			return pos - buf;
731e5b75505Sopenharmony_ci		pos += ret;
732e5b75505Sopenharmony_ci
733e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos,
734e5b75505Sopenharmony_ci				  " dev_capab=0x%x config_methods=0x%x "
735e5b75505Sopenharmony_ci				  "dev_type=%s",
736e5b75505Sopenharmony_ci				  cli->dev_capab, cli->config_methods,
737e5b75505Sopenharmony_ci				  wps_dev_type_bin2str(cli->pri_dev_type,
738e5b75505Sopenharmony_ci						       devtype,
739e5b75505Sopenharmony_ci						       sizeof(devtype)));
740e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
741e5b75505Sopenharmony_ci			return pos - buf;
742e5b75505Sopenharmony_ci		pos += ret;
743e5b75505Sopenharmony_ci
744e5b75505Sopenharmony_ci		for (s = 0; s < cli->num_sec_dev_types; s++) {
745e5b75505Sopenharmony_ci			ret = os_snprintf(pos, end - pos, " dev_type=%s",
746e5b75505Sopenharmony_ci					  wps_dev_type_bin2str(
747e5b75505Sopenharmony_ci						  &cli->sec_dev_types[s * 8],
748e5b75505Sopenharmony_ci						  devtype, sizeof(devtype)));
749e5b75505Sopenharmony_ci			if (os_snprintf_error(end - pos, ret))
750e5b75505Sopenharmony_ci				return pos - buf;
751e5b75505Sopenharmony_ci			pos += ret;
752e5b75505Sopenharmony_ci		}
753e5b75505Sopenharmony_ci
754e5b75505Sopenharmony_ci		os_memcpy(name, cli->dev_name, cli->dev_name_len);
755e5b75505Sopenharmony_ci		name[cli->dev_name_len] = '\0';
756e5b75505Sopenharmony_ci		count = (int) cli->dev_name_len - 1;
757e5b75505Sopenharmony_ci		while (count >= 0) {
758e5b75505Sopenharmony_ci			if (is_ctrl_char(name[count]))
759e5b75505Sopenharmony_ci				name[count] = '_';
760e5b75505Sopenharmony_ci			count--;
761e5b75505Sopenharmony_ci		}
762e5b75505Sopenharmony_ci
763e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
764e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
765e5b75505Sopenharmony_ci			return pos - buf;
766e5b75505Sopenharmony_ci		pos += ret;
767e5b75505Sopenharmony_ci	}
768e5b75505Sopenharmony_ci
769e5b75505Sopenharmony_ci	return pos - buf;
770e5b75505Sopenharmony_ci}
771e5b75505Sopenharmony_ci
772e5b75505Sopenharmony_ci
773e5b75505Sopenharmony_ci/**
774e5b75505Sopenharmony_ci * p2p_attr_text - Build text format description of P2P IE attributes
775e5b75505Sopenharmony_ci * @data: P2P IE contents
776e5b75505Sopenharmony_ci * @buf: Buffer for returning text
777e5b75505Sopenharmony_ci * @end: Pointer to the end of the buf area
778e5b75505Sopenharmony_ci * Returns: Number of octets written to the buffer or -1 on faikure
779e5b75505Sopenharmony_ci *
780e5b75505Sopenharmony_ci * This function can be used to parse P2P IE contents into text format
781e5b75505Sopenharmony_ci * field=value lines.
782e5b75505Sopenharmony_ci */
783e5b75505Sopenharmony_ciint p2p_attr_text(struct wpabuf *data, char *buf, char *end)
784e5b75505Sopenharmony_ci{
785e5b75505Sopenharmony_ci	struct p2p_message msg;
786e5b75505Sopenharmony_ci	char *pos = buf;
787e5b75505Sopenharmony_ci	int ret;
788e5b75505Sopenharmony_ci
789e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
790e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(data, &msg))
791e5b75505Sopenharmony_ci		return -1;
792e5b75505Sopenharmony_ci
793e5b75505Sopenharmony_ci	if (msg.capability) {
794e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos,
795e5b75505Sopenharmony_ci				  "p2p_dev_capab=0x%x\n"
796e5b75505Sopenharmony_ci				  "p2p_group_capab=0x%x\n",
797e5b75505Sopenharmony_ci				  msg.capability[0], msg.capability[1]);
798e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
799e5b75505Sopenharmony_ci			return pos - buf;
800e5b75505Sopenharmony_ci		pos += ret;
801e5b75505Sopenharmony_ci	}
802e5b75505Sopenharmony_ci
803e5b75505Sopenharmony_ci	if (msg.pri_dev_type) {
804e5b75505Sopenharmony_ci		char devtype[WPS_DEV_TYPE_BUFSIZE];
805e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos,
806e5b75505Sopenharmony_ci				  "p2p_primary_device_type=%s\n",
807e5b75505Sopenharmony_ci				  wps_dev_type_bin2str(msg.pri_dev_type,
808e5b75505Sopenharmony_ci						       devtype,
809e5b75505Sopenharmony_ci						       sizeof(devtype)));
810e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
811e5b75505Sopenharmony_ci			return pos - buf;
812e5b75505Sopenharmony_ci		pos += ret;
813e5b75505Sopenharmony_ci	}
814e5b75505Sopenharmony_ci
815e5b75505Sopenharmony_ci	ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
816e5b75505Sopenharmony_ci			  msg.device_name);
817e5b75505Sopenharmony_ci	if (os_snprintf_error(end - pos, ret))
818e5b75505Sopenharmony_ci		return pos - buf;
819e5b75505Sopenharmony_ci	pos += ret;
820e5b75505Sopenharmony_ci
821e5b75505Sopenharmony_ci	if (msg.p2p_device_addr) {
822e5b75505Sopenharmony_ci		ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
823e5b75505Sopenharmony_ci				  "\n",
824e5b75505Sopenharmony_ci				  MAC2STR(msg.p2p_device_addr));
825e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, ret))
826e5b75505Sopenharmony_ci			return pos - buf;
827e5b75505Sopenharmony_ci		pos += ret;
828e5b75505Sopenharmony_ci	}
829e5b75505Sopenharmony_ci
830e5b75505Sopenharmony_ci	ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
831e5b75505Sopenharmony_ci			  msg.config_methods);
832e5b75505Sopenharmony_ci	if (os_snprintf_error(end - pos, ret))
833e5b75505Sopenharmony_ci		return pos - buf;
834e5b75505Sopenharmony_ci	pos += ret;
835e5b75505Sopenharmony_ci
836e5b75505Sopenharmony_ci	ret = p2p_group_info_text(msg.group_info, msg.group_info_len,
837e5b75505Sopenharmony_ci				  pos, end);
838e5b75505Sopenharmony_ci	if (ret < 0)
839e5b75505Sopenharmony_ci		return pos - buf;
840e5b75505Sopenharmony_ci	pos += ret;
841e5b75505Sopenharmony_ci
842e5b75505Sopenharmony_ci	return pos - buf;
843e5b75505Sopenharmony_ci}
844e5b75505Sopenharmony_ci
845e5b75505Sopenharmony_ci
846e5b75505Sopenharmony_ciint p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie)
847e5b75505Sopenharmony_ci{
848e5b75505Sopenharmony_ci	struct p2p_message msg;
849e5b75505Sopenharmony_ci
850e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
851e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(p2p_ie, &msg))
852e5b75505Sopenharmony_ci		return 0;
853e5b75505Sopenharmony_ci
854e5b75505Sopenharmony_ci	if (!msg.manageability)
855e5b75505Sopenharmony_ci		return 0;
856e5b75505Sopenharmony_ci
857e5b75505Sopenharmony_ci	return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED);
858e5b75505Sopenharmony_ci}
859e5b75505Sopenharmony_ci
860e5b75505Sopenharmony_ci
861e5b75505Sopenharmony_ciu8 p2p_get_group_capab(const struct wpabuf *p2p_ie)
862e5b75505Sopenharmony_ci{
863e5b75505Sopenharmony_ci	struct p2p_message msg;
864e5b75505Sopenharmony_ci
865e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
866e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(p2p_ie, &msg))
867e5b75505Sopenharmony_ci		return 0;
868e5b75505Sopenharmony_ci
869e5b75505Sopenharmony_ci	if (!msg.capability)
870e5b75505Sopenharmony_ci		return 0;
871e5b75505Sopenharmony_ci
872e5b75505Sopenharmony_ci	return msg.capability[1];
873e5b75505Sopenharmony_ci}
874e5b75505Sopenharmony_ci
875e5b75505Sopenharmony_ci
876e5b75505Sopenharmony_ciconst u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie)
877e5b75505Sopenharmony_ci{
878e5b75505Sopenharmony_ci	struct p2p_message msg;
879e5b75505Sopenharmony_ci
880e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
881e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(p2p_ie, &msg))
882e5b75505Sopenharmony_ci		return NULL;
883e5b75505Sopenharmony_ci
884e5b75505Sopenharmony_ci	if (msg.p2p_device_addr)
885e5b75505Sopenharmony_ci		return msg.p2p_device_addr;
886e5b75505Sopenharmony_ci	if (msg.device_id)
887e5b75505Sopenharmony_ci		return msg.device_id;
888e5b75505Sopenharmony_ci
889e5b75505Sopenharmony_ci	return NULL;
890e5b75505Sopenharmony_ci}
891