xref: /freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c (revision d93a896ef95946b0bf1219866fcb324b78543444)
1 /*
2  * WPA Supplicant / dbus-based control interface (P2P)
3  * Copyright (c) 2011-2012, Intel Corporation
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "utils/includes.h"
12 #include "common.h"
13 #include "../config.h"
14 #include "../wpa_supplicant_i.h"
15 #include "../wps_supplicant.h"
16 #include "../notify.h"
17 #include "dbus_new_helpers.h"
18 #include "dbus_new.h"
19 #include "dbus_new_handlers.h"
20 #include "dbus_new_handlers_p2p.h"
21 #include "dbus_dict_helpers.h"
22 #include "p2p/p2p.h"
23 #include "common/ieee802_11_defs.h"
24 #include "ap/hostapd.h"
25 #include "ap/ap_config.h"
26 #include "ap/wps_hostapd.h"
27 
28 #include "../p2p_supplicant.h"
29 #include "../wifi_display.h"
30 
31 /**
32  * Parses out the mac address from the peer object path.
33  * @peer_path - object path of the form
34  *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
35  * @addr - out param must be of ETH_ALEN size
36  * Returns 0 if valid (including MAC), -1 otherwise
37  */
38 static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
39 {
40 	const char *p;
41 
42 	if (!peer_path)
43 		return -1;
44 	p = os_strrchr(peer_path, '/');
45 	if (!p)
46 		return -1;
47 	p++;
48 	return hwaddr_compact_aton(p, addr);
49 }
50 
51 
52 /**
53  * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
54  * error message
55  * @message: Pointer to incoming dbus message this error refers to
56  * Returns: a dbus error message
57  *
58  * Convenience function to create and return an invalid persistent group error.
59  */
60 static DBusMessage *
61 wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
62 {
63 	return dbus_message_new_error(
64 		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
65 		"There is no such persistent group in this P2P device.");
66 }
67 
68 
69 DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
70 					 struct wpa_supplicant *wpa_s)
71 {
72 	struct wpa_dbus_dict_entry entry;
73 	DBusMessage *reply = NULL;
74 	DBusMessageIter iter;
75 	DBusMessageIter iter_dict;
76 	unsigned int timeout = 0;
77 	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
78 	int num_req_dev_types = 0;
79 	unsigned int i;
80 	u8 *req_dev_types = NULL;
81 
82 	dbus_message_iter_init(message, &iter);
83 	entry.key = NULL;
84 
85 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
86 		goto error;
87 
88 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
89 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
90 			goto error;
91 
92 		if (os_strcmp(entry.key, "Timeout") == 0 &&
93 		    entry.type == DBUS_TYPE_INT32) {
94 			timeout = entry.uint32_value;
95 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
96 			if (entry.type != DBUS_TYPE_ARRAY ||
97 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
98 				goto error_clear;
99 
100 			os_free(req_dev_types);
101 			req_dev_types =
102 				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
103 			if (!req_dev_types)
104 				goto error_clear;
105 
106 			for (i = 0; i < entry.array_len; i++) {
107 				if (wpabuf_len(entry.binarray_value[i]) !=
108 				    WPS_DEV_TYPE_LEN)
109 					goto error_clear;
110 				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
111 					  wpabuf_head(entry.binarray_value[i]),
112 					  WPS_DEV_TYPE_LEN);
113 			}
114 			num_req_dev_types = entry.array_len;
115 		} else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
116 			   entry.type == DBUS_TYPE_STRING) {
117 			if (os_strcmp(entry.str_value, "start_with_full") == 0)
118 				type = P2P_FIND_START_WITH_FULL;
119 			else if (os_strcmp(entry.str_value, "social") == 0)
120 				type = P2P_FIND_ONLY_SOCIAL;
121 			else if (os_strcmp(entry.str_value, "progressive") == 0)
122 				type = P2P_FIND_PROGRESSIVE;
123 			else
124 				goto error_clear;
125 		} else
126 			goto error_clear;
127 		wpa_dbus_dict_entry_clear(&entry);
128 	}
129 
130 	wpa_s = wpa_s->global->p2p_init_wpa_s;
131 
132 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
133 		      NULL, 0, 0, NULL, 0);
134 	os_free(req_dev_types);
135 	return reply;
136 
137 error_clear:
138 	wpa_dbus_dict_entry_clear(&entry);
139 error:
140 	os_free(req_dev_types);
141 	reply = wpas_dbus_error_invalid_args(message, entry.key);
142 	return reply;
143 }
144 
145 
146 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
147 					      struct wpa_supplicant *wpa_s)
148 {
149 	wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
150 	return NULL;
151 }
152 
153 
154 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
155 					       struct wpa_supplicant *wpa_s)
156 {
157 	DBusMessageIter iter;
158 	char *peer_object_path = NULL;
159 	u8 peer_addr[ETH_ALEN];
160 
161 	dbus_message_iter_init(message, &iter);
162 	dbus_message_iter_get_basic(&iter, &peer_object_path);
163 
164 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
165 		return wpas_dbus_error_invalid_args(message, NULL);
166 
167 	wpa_s = wpa_s->global->p2p_init_wpa_s;
168 
169 	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
170 		return wpas_dbus_error_unknown_error(message,
171 				"Failed to call wpas_p2p_reject method.");
172 
173 	return NULL;
174 }
175 
176 
177 DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
178 					   struct wpa_supplicant *wpa_s)
179 {
180 	dbus_int32_t timeout = 0;
181 
182 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
183 				   DBUS_TYPE_INVALID))
184 		return wpas_dbus_error_no_memory(message);
185 
186 	wpa_s = wpa_s->global->p2p_init_wpa_s;
187 
188 	if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
189 		return dbus_message_new_error(message,
190 					      WPAS_DBUS_ERROR_UNKNOWN_ERROR,
191 					      "Could not start P2P listen");
192 	}
193 
194 	return NULL;
195 }
196 
197 
198 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
199 	DBusMessage *message, struct wpa_supplicant *wpa_s)
200 {
201 	unsigned int period = 0, interval = 0;
202 	struct wpa_dbus_dict_entry entry;
203 	DBusMessageIter iter;
204 	DBusMessageIter iter_dict;
205 
206 	dbus_message_iter_init(message, &iter);
207 	entry.key = NULL;
208 
209 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
210 		goto error;
211 
212 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
213 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
214 			goto error;
215 
216 		if (os_strcmp(entry.key, "period") == 0 &&
217 		    entry.type == DBUS_TYPE_INT32)
218 			period = entry.uint32_value;
219 		else if (os_strcmp(entry.key, "interval") == 0 &&
220 			 entry.type == DBUS_TYPE_INT32)
221 			interval = entry.uint32_value;
222 		else
223 			goto error_clear;
224 		wpa_dbus_dict_entry_clear(&entry);
225 	}
226 
227 	wpa_s = wpa_s->global->p2p_init_wpa_s;
228 
229 	if (wpas_p2p_ext_listen(wpa_s, period, interval))
230 		return wpas_dbus_error_unknown_error(
231 			message, "failed to initiate a p2p_ext_listen.");
232 
233 	return NULL;
234 
235 error_clear:
236 	wpa_dbus_dict_entry_clear(&entry);
237 error:
238 	return wpas_dbus_error_invalid_args(message, entry.key);
239 }
240 
241 
242 DBusMessage * wpas_dbus_handler_p2p_presence_request(
243 	DBusMessage *message, struct wpa_supplicant *wpa_s)
244 {
245 	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
246 	struct wpa_dbus_dict_entry entry;
247 	DBusMessageIter iter;
248 	DBusMessageIter iter_dict;
249 
250 	dbus_message_iter_init(message, &iter);
251 	entry.key = NULL;
252 
253 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
254 		goto error;
255 
256 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
257 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
258 			goto error;
259 
260 		if (os_strcmp(entry.key, "duration1") == 0 &&
261 		    entry.type == DBUS_TYPE_INT32)
262 			dur1 = entry.uint32_value;
263 		else if (os_strcmp(entry.key, "interval1") == 0 &&
264 			 entry.type == DBUS_TYPE_INT32)
265 			int1 = entry.uint32_value;
266 		else if (os_strcmp(entry.key, "duration2") == 0 &&
267 			 entry.type == DBUS_TYPE_INT32)
268 			dur2 = entry.uint32_value;
269 		else if (os_strcmp(entry.key, "interval2") == 0 &&
270 			 entry.type == DBUS_TYPE_INT32)
271 			int2 = entry.uint32_value;
272 		else
273 			goto error_clear;
274 
275 		wpa_dbus_dict_entry_clear(&entry);
276 	}
277 
278 	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
279 		return wpas_dbus_error_unknown_error(message,
280 				"Failed to invoke presence request.");
281 
282 	return NULL;
283 
284 error_clear:
285 	wpa_dbus_dict_entry_clear(&entry);
286 error:
287 	return wpas_dbus_error_invalid_args(message, entry.key);
288 }
289 
290 
291 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
292 					      struct wpa_supplicant *wpa_s)
293 {
294 	DBusMessageIter iter_dict;
295 	DBusMessage *reply = NULL;
296 	DBusMessageIter iter;
297 	struct wpa_dbus_dict_entry entry;
298 	char *pg_object_path = NULL;
299 	int persistent_group = 0;
300 	int freq = 0;
301 	char *iface = NULL;
302 	unsigned int group_id = 0;
303 	struct wpa_ssid *ssid;
304 
305 	dbus_message_iter_init(message, &iter);
306 
307 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
308 		goto inv_args;
309 
310 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
311 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
312 			goto inv_args;
313 
314 		if (os_strcmp(entry.key, "persistent") == 0 &&
315 		    entry.type == DBUS_TYPE_BOOLEAN) {
316 			persistent_group = entry.bool_value;
317 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
318 			   entry.type == DBUS_TYPE_INT32) {
319 			freq = entry.int32_value;
320 			if (freq <= 0)
321 				goto inv_args_clear;
322 		} else if (os_strcmp(entry.key, "persistent_group_object") ==
323 			   0 &&
324 			   entry.type == DBUS_TYPE_OBJECT_PATH)
325 			pg_object_path = os_strdup(entry.str_value);
326 		else
327 			goto inv_args_clear;
328 
329 		wpa_dbus_dict_entry_clear(&entry);
330 	}
331 
332 	wpa_s = wpa_s->global->p2p_init_wpa_s;
333 
334 	if (pg_object_path != NULL) {
335 		char *net_id_str;
336 
337 		/*
338 		 * A persistent group Object Path is defined meaning we want
339 		 * to re-invoke a persistent group.
340 		 */
341 
342 		iface = wpas_dbus_new_decompose_object_path(
343 			pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
344 			&net_id_str);
345 		if (iface == NULL || net_id_str == NULL ||
346 		    !wpa_s->parent->dbus_new_path ||
347 		    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
348 			reply =
349 			    wpas_dbus_error_invalid_args(message,
350 							 pg_object_path);
351 			goto out;
352 		}
353 
354 		group_id = strtoul(net_id_str, NULL, 10);
355 		if (errno == EINVAL) {
356 			reply = wpas_dbus_error_invalid_args(
357 						message, pg_object_path);
358 			goto out;
359 		}
360 
361 		/* Get the SSID structure from the persistent group id */
362 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
363 		if (ssid == NULL || ssid->disabled != 2)
364 			goto inv_args;
365 
366 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
367 						  NULL, 0, 0)) {
368 			reply = wpas_dbus_error_unknown_error(
369 				message,
370 				"Failed to reinvoke a persistent group");
371 			goto out;
372 		}
373 	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
374 		goto inv_args;
375 
376 out:
377 	os_free(pg_object_path);
378 	os_free(iface);
379 	return reply;
380 inv_args_clear:
381 	wpa_dbus_dict_entry_clear(&entry);
382 inv_args:
383 	reply = wpas_dbus_error_invalid_args(message, NULL);
384 	goto out;
385 }
386 
387 
388 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
389 					       struct wpa_supplicant *wpa_s)
390 {
391 	if (wpas_p2p_disconnect(wpa_s))
392 		return wpas_dbus_error_unknown_error(message,
393 						"failed to disconnect");
394 
395 	return NULL;
396 }
397 
398 
399 static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
400 					      DBusMessage *message,
401 					      DBusMessage **out_reply,
402 					      DBusError *error)
403 {
404 	/* Return an error message or an error if P2P isn't available */
405 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
406 		if (out_reply) {
407 			*out_reply = dbus_message_new_error(
408 				message, DBUS_ERROR_FAILED,
409 				"P2P is not available for this interface");
410 		}
411 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
412 				     "P2P is not available for this interface");
413 		return FALSE;
414 	}
415 	return TRUE;
416 }
417 
418 
419 DBusMessage * wpas_dbus_handler_p2p_remove_client(DBusMessage *message,
420 						  struct wpa_supplicant *wpa_s)
421 {
422 	DBusMessageIter iter_dict;
423 	DBusMessage *reply = NULL;
424 	DBusMessageIter iter;
425 	struct wpa_dbus_dict_entry entry;
426 	char *peer_object_path = NULL;
427 	char *interface_addr = NULL;
428 	u8 peer_addr[ETH_ALEN];
429 
430 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
431 		return reply;
432 
433 	dbus_message_iter_init(message, &iter);
434 
435 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
436 		goto err;
437 
438 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
439 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
440 			goto err;
441 
442 		if (os_strcmp(entry.key, "peer") == 0 &&
443 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
444 			os_free(peer_object_path);
445 			peer_object_path = os_strdup(entry.str_value);
446 			wpa_dbus_dict_entry_clear(&entry);
447 		} else if (os_strcmp(entry.key, "iface") == 0 &&
448 			   entry.type == DBUS_TYPE_STRING) {
449 			os_free(interface_addr);
450 			interface_addr = os_strdup(entry.str_value);
451 			wpa_dbus_dict_entry_clear(&entry);
452 		} else {
453 			wpa_dbus_dict_entry_clear(&entry);
454 			goto err;
455 		}
456 	}
457 
458 	if ((!peer_object_path && !interface_addr) ||
459 	    (peer_object_path &&
460 	     (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
461 	      !p2p_peer_known(wpa_s->global->p2p, peer_addr))) ||
462 	    (interface_addr && hwaddr_aton(interface_addr, peer_addr) < 0))
463 		goto err;
464 
465 	wpas_p2p_remove_client(wpa_s, peer_addr, interface_addr != NULL);
466 	reply = NULL;
467 out:
468 	os_free(peer_object_path);
469 	os_free(interface_addr);
470 	return reply;
471 err:
472 	reply = wpas_dbus_error_invalid_args(message, "Invalid address format");
473 	goto out;
474 }
475 
476 
477 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
478 					  struct wpa_supplicant *wpa_s)
479 {
480 	DBusMessage *reply = NULL;
481 
482 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
483 		return reply;
484 
485 	wpa_s = wpa_s->global->p2p_init_wpa_s;
486 
487 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
488 	wpa_s->force_long_sd = 0;
489 	p2p_flush(wpa_s->global->p2p);
490 
491 	return NULL;
492 }
493 
494 
495 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
496 					    struct wpa_supplicant *wpa_s)
497 {
498 	DBusMessageIter iter_dict;
499 	DBusMessage *reply = NULL;
500 	DBusMessageIter iter;
501 	struct wpa_dbus_dict_entry entry;
502 	char *peer_object_path = NULL;
503 	int persistent_group = 0;
504 	int join = 0;
505 	int authorize_only = 0;
506 	int go_intent = -1;
507 	int freq = 0;
508 	u8 addr[ETH_ALEN];
509 	char *pin = NULL;
510 	enum p2p_wps_method wps_method = WPS_NOT_READY;
511 	int new_pin;
512 	char *err_msg = NULL;
513 	char *iface = NULL;
514 
515 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
516 		return reply;
517 
518 	dbus_message_iter_init(message, &iter);
519 
520 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
521 		goto inv_args;
522 
523 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
524 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
525 			goto inv_args;
526 
527 		if (os_strcmp(entry.key, "peer") == 0 &&
528 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
529 			peer_object_path = os_strdup(entry.str_value);
530 		} else if (os_strcmp(entry.key, "persistent") == 0 &&
531 			   entry.type == DBUS_TYPE_BOOLEAN) {
532 			persistent_group = entry.bool_value;
533 		} else if (os_strcmp(entry.key, "join") == 0 &&
534 			   entry.type == DBUS_TYPE_BOOLEAN) {
535 			join = entry.bool_value;
536 		} else if (os_strcmp(entry.key, "authorize_only") == 0 &&
537 			   entry.type == DBUS_TYPE_BOOLEAN) {
538 			authorize_only = entry.bool_value;
539 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
540 			   entry.type == DBUS_TYPE_INT32) {
541 			freq = entry.int32_value;
542 			if (freq <= 0)
543 				goto inv_args_clear;
544 		} else if (os_strcmp(entry.key, "go_intent") == 0 &&
545 			   entry.type == DBUS_TYPE_INT32) {
546 			go_intent = entry.int32_value;
547 			if ((go_intent < 0) || (go_intent > 15))
548 				goto inv_args_clear;
549 		} else if (os_strcmp(entry.key, "wps_method") == 0 &&
550 			   entry.type == DBUS_TYPE_STRING) {
551 			if (os_strcmp(entry.str_value, "pbc") == 0)
552 				wps_method = WPS_PBC;
553 			else if (os_strcmp(entry.str_value, "pin") == 0)
554 				wps_method = WPS_PIN_DISPLAY;
555 			else if (os_strcmp(entry.str_value, "display") == 0)
556 				wps_method = WPS_PIN_DISPLAY;
557 			else if (os_strcmp(entry.str_value, "keypad") == 0)
558 				wps_method = WPS_PIN_KEYPAD;
559 			else
560 				goto inv_args_clear;
561 		} else if (os_strcmp(entry.key, "pin") == 0 &&
562 			   entry.type == DBUS_TYPE_STRING) {
563 			pin = os_strdup(entry.str_value);
564 		} else
565 			goto inv_args_clear;
566 
567 		wpa_dbus_dict_entry_clear(&entry);
568 	}
569 
570 	if (wps_method == WPS_NOT_READY ||
571 	    parse_peer_object_path(peer_object_path, addr) < 0 ||
572 	    !p2p_peer_known(wpa_s->global->p2p, addr))
573 		goto inv_args;
574 
575 	/*
576 	 * Validate the wps_method specified and the pin value.
577 	 */
578 	if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
579 		goto inv_args;
580 
581 	wpa_s = wpa_s->global->p2p_init_wpa_s;
582 
583 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
584 				   persistent_group, 0, join, authorize_only,
585 				   go_intent, freq, -1, 0, 0, 0);
586 
587 	if (new_pin >= 0) {
588 		char npin[9];
589 		char *generated_pin;
590 
591 		os_snprintf(npin, sizeof(npin), "%08d", new_pin);
592 		generated_pin = npin;
593 		reply = dbus_message_new_method_return(message);
594 		dbus_message_append_args(reply, DBUS_TYPE_STRING,
595 					 &generated_pin, DBUS_TYPE_INVALID);
596 	} else {
597 		switch (new_pin) {
598 		case -2:
599 			err_msg =
600 				"connect failed due to channel unavailability.";
601 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
602 			break;
603 
604 		case -3:
605 			err_msg = "connect failed due to unsupported channel.";
606 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
607 			break;
608 
609 		default:
610 			err_msg = "connect failed due to unspecified error.";
611 			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
612 			break;
613 		}
614 
615 		/*
616 		 * TODO:
617 		 * Do we need specialized errors corresponding to above
618 		 * error conditions as against just returning a different
619 		 * error message?
620 		 */
621 		reply = dbus_message_new_error(message, iface, err_msg);
622 	}
623 
624 out:
625 	os_free(peer_object_path);
626 	os_free(pin);
627 	return reply;
628 inv_args_clear:
629 	wpa_dbus_dict_entry_clear(&entry);
630 inv_args:
631 	reply = wpas_dbus_error_invalid_args(message, NULL);
632 	goto out;
633 }
634 
635 
636 /**
637  * wpas_dbus_handler_p2p_cancel - Cancel P2P group formation
638  * @message: Pointer to incoming dbus message
639  * @wpa_s: %wpa_supplicant data structure
640  * Returns: NULL on success or DBus error on failure
641  *
642  * Handler for "Cancel" method call. Returns NULL if P2P cancel succeeds or DBus
643  * error on P2P cancel failure
644  */
645 DBusMessage * wpas_dbus_handler_p2p_cancel(DBusMessage *message,
646 					   struct wpa_supplicant *wpa_s)
647 {
648 	if (wpas_p2p_cancel(wpa_s))
649 		return wpas_dbus_error_unknown_error(message,
650 						     "P2P cancel failed");
651 
652 	return NULL;
653 }
654 
655 
656 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
657 					   struct wpa_supplicant *wpa_s)
658 {
659 	DBusMessageIter iter_dict;
660 	DBusMessage *reply = NULL;
661 	DBusMessageIter iter;
662 	struct wpa_dbus_dict_entry entry;
663 	char *peer_object_path = NULL;
664 	char *pg_object_path = NULL;
665 	char *iface = NULL;
666 	u8 peer_addr[ETH_ALEN];
667 	unsigned int group_id = 0;
668 	int persistent = 0;
669 	struct wpa_ssid *ssid;
670 
671 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
672 		return reply;
673 
674 	dbus_message_iter_init(message, &iter);
675 
676 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
677 		goto err;
678 
679 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
680 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
681 			goto err;
682 
683 		if (os_strcmp(entry.key, "peer") == 0 &&
684 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
685 			peer_object_path = os_strdup(entry.str_value);
686 			wpa_dbus_dict_entry_clear(&entry);
687 		} else if (os_strcmp(entry.key, "persistent_group_object") ==
688 			   0 &&
689 			   entry.type == DBUS_TYPE_OBJECT_PATH) {
690 			pg_object_path = os_strdup(entry.str_value);
691 			persistent = 1;
692 			wpa_dbus_dict_entry_clear(&entry);
693 		} else {
694 			wpa_dbus_dict_entry_clear(&entry);
695 			goto err;
696 		}
697 	}
698 
699 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
700 	    !p2p_peer_known(wpa_s->global->p2p, peer_addr))
701 		goto err;
702 
703 	wpa_s = wpa_s->global->p2p_init_wpa_s;
704 
705 	if (persistent) {
706 		char *net_id_str;
707 		/*
708 		 * A group ID is defined meaning we want to re-invoke a
709 		 * persistent group
710 		 */
711 
712 		iface = wpas_dbus_new_decompose_object_path(
713 			pg_object_path,
714 			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
715 			&net_id_str);
716 		if (iface == NULL || net_id_str == NULL ||
717 		    !wpa_s->parent->dbus_new_path ||
718 		    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
719 			reply = wpas_dbus_error_invalid_args(message,
720 							     pg_object_path);
721 			goto out;
722 		}
723 
724 		group_id = strtoul(net_id_str, NULL, 10);
725 		if (errno == EINVAL) {
726 			reply = wpas_dbus_error_invalid_args(
727 				message, pg_object_path);
728 			goto out;
729 		}
730 
731 		/* Get the SSID structure from the persistent group id */
732 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
733 		if (ssid == NULL || ssid->disabled != 2)
734 			goto err;
735 
736 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
737 		    0) {
738 			reply = wpas_dbus_error_unknown_error(
739 				message,
740 				"Failed to reinvoke a persistent group");
741 			goto out;
742 		}
743 	} else {
744 		/*
745 		 * No group ID means propose to a peer to join my active group
746 		 */
747 		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
748 					  peer_addr, NULL)) {
749 			reply = wpas_dbus_error_unknown_error(
750 				message, "Failed to join to an active group");
751 			goto out;
752 		}
753 	}
754 
755 out:
756 	os_free(iface);
757 	os_free(pg_object_path);
758 	os_free(peer_object_path);
759 	return reply;
760 
761 err:
762 	reply = wpas_dbus_error_invalid_args(message, NULL);
763 	goto out;
764 }
765 
766 
767 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
768 						  struct wpa_supplicant *wpa_s)
769 {
770 	DBusMessageIter iter;
771 	char *peer_object_path = NULL;
772 	char *config_method = NULL;
773 	u8 peer_addr[ETH_ALEN];
774 
775 	dbus_message_iter_init(message, &iter);
776 	dbus_message_iter_get_basic(&iter, &peer_object_path);
777 
778 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
779 		return wpas_dbus_error_invalid_args(message, NULL);
780 
781 	dbus_message_iter_next(&iter);
782 	dbus_message_iter_get_basic(&iter, &config_method);
783 
784 	/*
785 	 * Validation checks on config_method are being duplicated here
786 	 * to be able to return invalid args reply since the error code
787 	 * from p2p module are not granular enough (yet).
788 	 */
789 	if (os_strcmp(config_method, "display") &&
790 	    os_strcmp(config_method, "keypad") &&
791 	    os_strcmp(config_method, "pbc") &&
792 	    os_strcmp(config_method, "pushbutton"))
793 		return wpas_dbus_error_invalid_args(message, NULL);
794 
795 	wpa_s = wpa_s->global->p2p_init_wpa_s;
796 
797 	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
798 			       WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
799 		return wpas_dbus_error_unknown_error(message,
800 				"Failed to send provision discovery request");
801 
802 	return NULL;
803 }
804 
805 
806 /*
807  * P2P Device property accessor methods.
808  */
809 
810 dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
811 					       DBusError *error,
812 					       void *user_data)
813 {
814 	struct wpa_supplicant *wpa_s = user_data;
815 	DBusMessageIter variant_iter, dict_iter;
816 	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
817 		iter_secdev_dict_array;
818 	const char *dev_name;
819 	int num_vendor_extensions = 0;
820 	int i;
821 	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
822 
823 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
824 		return FALSE;
825 
826 	wpa_s = wpa_s->global->p2p_init_wpa_s;
827 
828 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
829 					      "a{sv}", &variant_iter) ||
830 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
831 		goto err_no_mem;
832 
833 	/* DeviceName */
834 	dev_name = wpa_s->conf->device_name;
835 	if (dev_name &&
836 	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
837 		goto err_no_mem;
838 
839 	/* Primary device type */
840 	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
841 					     (char *) wpa_s->conf->device_type,
842 					     WPS_DEV_TYPE_LEN))
843 		goto err_no_mem;
844 
845 	/* Secondary device types */
846 	if (wpa_s->conf->num_sec_device_types) {
847 		if (!wpa_dbus_dict_begin_array(&dict_iter,
848 					       "SecondaryDeviceTypes",
849 					       DBUS_TYPE_ARRAY_AS_STRING
850 					       DBUS_TYPE_BYTE_AS_STRING,
851 					       &iter_secdev_dict_entry,
852 					       &iter_secdev_dict_val,
853 					       &iter_secdev_dict_array))
854 			goto err_no_mem;
855 
856 		for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
857 			wpa_dbus_dict_bin_array_add_element(
858 				&iter_secdev_dict_array,
859 				wpa_s->conf->sec_device_type[i],
860 				WPS_DEV_TYPE_LEN);
861 
862 		if (!wpa_dbus_dict_end_array(&dict_iter,
863 					     &iter_secdev_dict_entry,
864 					     &iter_secdev_dict_val,
865 					     &iter_secdev_dict_array))
866 			goto err_no_mem;
867 	}
868 
869 	/* Vendor Extensions */
870 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
871 		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
872 			continue;
873 		vendor_ext[num_vendor_extensions++] =
874 			wpa_s->conf->wps_vendor_ext[i];
875 	}
876 
877 	if ((num_vendor_extensions &&
878 	     !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
879 						"VendorExtension",
880 						vendor_ext,
881 						num_vendor_extensions)) ||
882 	    !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
883 					 wpa_s->conf->p2p_go_intent) ||
884 	    !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
885 				       wpa_s->conf->persistent_reconnect) ||
886 	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
887 					 wpa_s->conf->p2p_listen_reg_class) ||
888 	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
889 					 wpa_s->conf->p2p_listen_channel) ||
890 	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
891 					 wpa_s->conf->p2p_oper_reg_class) ||
892 	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
893 					 wpa_s->conf->p2p_oper_channel) ||
894 	    (wpa_s->conf->p2p_ssid_postfix &&
895 	     !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
896 					  wpa_s->conf->p2p_ssid_postfix)) ||
897 	    !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
898 				       wpa_s->conf->p2p_intra_bss) ||
899 	    !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
900 					 wpa_s->conf->p2p_group_idle) ||
901 	    !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
902 					 wpa_s->conf->disassoc_low_ack) ||
903 	    !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
904 				       wpa_s->conf->p2p_no_group_iface) ||
905 	    !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
906 					 wpa_s->conf->p2p_search_delay) ||
907 	    !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
908 	    !dbus_message_iter_close_container(iter, &variant_iter))
909 		goto err_no_mem;
910 
911 	return TRUE;
912 
913 err_no_mem:
914 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
915 	return FALSE;
916 }
917 
918 
919 dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
920 					       DBusError *error,
921 					       void *user_data)
922 {
923 	struct wpa_supplicant *wpa_s = user_data;
924 	DBusMessageIter variant_iter, iter_dict;
925 	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
926 	unsigned int i;
927 
928 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
929 		return FALSE;
930 
931 	wpa_s = wpa_s->global->p2p_init_wpa_s;
932 
933 	dbus_message_iter_recurse(iter, &variant_iter);
934 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
935 		return FALSE;
936 
937 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
938 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
939 			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
940 					     "invalid message format");
941 			return FALSE;
942 		}
943 
944 		if (os_strcmp(entry.key, "DeviceName") == 0) {
945 			char *devname;
946 
947 			if (entry.type != DBUS_TYPE_STRING)
948 				goto error;
949 
950 			devname = os_strdup(entry.str_value);
951 			if (devname == NULL)
952 				goto err_no_mem_clear;
953 
954 			os_free(wpa_s->conf->device_name);
955 			wpa_s->conf->device_name = devname;
956 
957 			wpa_s->conf->changed_parameters |=
958 				CFG_CHANGED_DEVICE_NAME;
959 		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
960 			if (entry.type != DBUS_TYPE_ARRAY ||
961 			    entry.array_type != DBUS_TYPE_BYTE ||
962 			    entry.array_len != WPS_DEV_TYPE_LEN)
963 				goto error;
964 
965 			os_memcpy(wpa_s->conf->device_type,
966 				  entry.bytearray_value,
967 				  WPS_DEV_TYPE_LEN);
968 			wpa_s->conf->changed_parameters |=
969 				CFG_CHANGED_DEVICE_TYPE;
970 		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
971 			if (entry.type != DBUS_TYPE_ARRAY ||
972 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
973 			    entry.array_len > MAX_SEC_DEVICE_TYPES)
974 				goto error;
975 
976 			for (i = 0; i < entry.array_len; i++)
977 				if (wpabuf_len(entry.binarray_value[i]) !=
978 				    WPS_DEV_TYPE_LEN)
979 					goto err_no_mem_clear;
980 			for (i = 0; i < entry.array_len; i++)
981 				os_memcpy(wpa_s->conf->sec_device_type[i],
982 					  wpabuf_head(entry.binarray_value[i]),
983 					  WPS_DEV_TYPE_LEN);
984 			wpa_s->conf->num_sec_device_types = entry.array_len;
985 			wpa_s->conf->changed_parameters |=
986 					CFG_CHANGED_SEC_DEVICE_TYPE;
987 		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
988 			if (entry.type != DBUS_TYPE_ARRAY ||
989 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
990 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
991 				goto error;
992 
993 			wpa_s->conf->changed_parameters |=
994 				CFG_CHANGED_VENDOR_EXTENSION;
995 
996 			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
997 				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
998 				if (i < entry.array_len) {
999 					wpa_s->conf->wps_vendor_ext[i] =
1000 						entry.binarray_value[i];
1001 					entry.binarray_value[i] = NULL;
1002 				} else
1003 					wpa_s->conf->wps_vendor_ext[i] = NULL;
1004 			}
1005 		} else if (os_strcmp(entry.key, "GOIntent") == 0 &&
1006 			   entry.type == DBUS_TYPE_UINT32 &&
1007 			   (entry.uint32_value <= 15))
1008 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
1009 		else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
1010 			 entry.type == DBUS_TYPE_BOOLEAN)
1011 			wpa_s->conf->persistent_reconnect = entry.bool_value;
1012 		else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
1013 			 entry.type == DBUS_TYPE_UINT32) {
1014 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
1015 			wpa_s->conf->changed_parameters |=
1016 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
1017 		} else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
1018 			   entry.type == DBUS_TYPE_UINT32) {
1019 			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
1020 			wpa_s->conf->changed_parameters |=
1021 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
1022 		} else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
1023 			   entry.type == DBUS_TYPE_UINT32) {
1024 			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
1025 			wpa_s->conf->changed_parameters |=
1026 				CFG_CHANGED_P2P_OPER_CHANNEL;
1027 		} else if (os_strcmp(entry.key, "OperChannel") == 0 &&
1028 			   entry.type == DBUS_TYPE_UINT32) {
1029 			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
1030 			wpa_s->conf->changed_parameters |=
1031 				CFG_CHANGED_P2P_OPER_CHANNEL;
1032 		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
1033 			char *postfix;
1034 
1035 			if (entry.type != DBUS_TYPE_STRING)
1036 				goto error;
1037 
1038 			postfix = os_strdup(entry.str_value);
1039 			if (!postfix)
1040 				goto err_no_mem_clear;
1041 
1042 			os_free(wpa_s->conf->p2p_ssid_postfix);
1043 			wpa_s->conf->p2p_ssid_postfix = postfix;
1044 
1045 			wpa_s->conf->changed_parameters |=
1046 					CFG_CHANGED_P2P_SSID_POSTFIX;
1047 		} else if (os_strcmp(entry.key, "IntraBss") == 0 &&
1048 			   entry.type == DBUS_TYPE_BOOLEAN) {
1049 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
1050 			wpa_s->conf->changed_parameters |=
1051 				CFG_CHANGED_P2P_INTRA_BSS;
1052 		} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
1053 			   entry.type == DBUS_TYPE_UINT32)
1054 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
1055 		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
1056 			 entry.type == DBUS_TYPE_UINT32)
1057 			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
1058 		else if (os_strcmp(entry.key, "NoGroupIface") == 0 &&
1059 			 entry.type == DBUS_TYPE_BOOLEAN)
1060 			wpa_s->conf->p2p_no_group_iface = entry.bool_value;
1061 		else if (os_strcmp(entry.key, "p2p_search_delay") == 0 &&
1062 			 entry.type == DBUS_TYPE_UINT32)
1063 			wpa_s->conf->p2p_search_delay = entry.uint32_value;
1064 		else
1065 			goto error;
1066 
1067 		wpa_dbus_dict_entry_clear(&entry);
1068 	}
1069 
1070 	if (wpa_s->conf->changed_parameters) {
1071 		/* Some changed parameters requires to update config*/
1072 		wpa_supplicant_update_config(wpa_s);
1073 	}
1074 
1075 	return TRUE;
1076 
1077  error:
1078 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1079 			     "invalid message format");
1080 	wpa_dbus_dict_entry_clear(&entry);
1081 	return FALSE;
1082 
1083  err_no_mem_clear:
1084 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1085 	wpa_dbus_dict_entry_clear(&entry);
1086 	return FALSE;
1087 }
1088 
1089 
1090 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
1091 				       void *user_data)
1092 {
1093 	struct wpa_supplicant *wpa_s = user_data;
1094 	struct p2p_data *p2p = wpa_s->global->p2p;
1095 	int next = 0, i = 0;
1096 	int num = 0, out_of_mem = 0;
1097 	const u8 *addr;
1098 	const struct p2p_peer_info *peer_info = NULL;
1099 	dbus_bool_t success = FALSE;
1100 
1101 	struct dl_list peer_objpath_list;
1102 	struct peer_objpath_node {
1103 		struct dl_list list;
1104 		char path[WPAS_DBUS_OBJECT_PATH_MAX];
1105 	} *node, *tmp;
1106 
1107 	char **peer_obj_paths = NULL;
1108 
1109 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error) ||
1110 	    !wpa_s->parent->parent->dbus_new_path)
1111 		return FALSE;
1112 
1113 	dl_list_init(&peer_objpath_list);
1114 
1115 	/* Get the first peer info */
1116 	peer_info = p2p_get_peer_found(p2p, NULL, next);
1117 
1118 	/* Get next and accumulate them */
1119 	next = 1;
1120 	while (peer_info != NULL) {
1121 		node = os_zalloc(sizeof(struct peer_objpath_node));
1122 		if (!node) {
1123 			out_of_mem = 1;
1124 			goto error;
1125 		}
1126 
1127 		addr = peer_info->p2p_device_addr;
1128 		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1129 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1130 			    "/" COMPACT_MACSTR,
1131 			    wpa_s->parent->parent->dbus_new_path,
1132 			    MAC2STR(addr));
1133 		dl_list_add_tail(&peer_objpath_list, &node->list);
1134 		num++;
1135 
1136 		peer_info = p2p_get_peer_found(p2p, addr, next);
1137 	}
1138 
1139 	/*
1140 	 * Now construct the peer object paths in a form suitable for
1141 	 * array_property_getter helper below.
1142 	 */
1143 	peer_obj_paths = os_calloc(num, sizeof(char *));
1144 
1145 	if (!peer_obj_paths) {
1146 		out_of_mem = 1;
1147 		goto error;
1148 	}
1149 
1150 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1151 			      struct peer_objpath_node, list)
1152 		peer_obj_paths[i++] = node->path;
1153 
1154 	success = wpas_dbus_simple_array_property_getter(iter,
1155 							 DBUS_TYPE_OBJECT_PATH,
1156 							 peer_obj_paths, num,
1157 							 error);
1158 
1159 error:
1160 	if (peer_obj_paths)
1161 		os_free(peer_obj_paths);
1162 
1163 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1164 			      struct peer_objpath_node, list) {
1165 		dl_list_del(&node->list);
1166 		os_free(node);
1167 	}
1168 	if (out_of_mem)
1169 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1170 
1171 	return success;
1172 }
1173 
1174 
1175 enum wpas_p2p_role {
1176 	WPAS_P2P_ROLE_DEVICE,
1177 	WPAS_P2P_ROLE_GO,
1178 	WPAS_P2P_ROLE_CLIENT,
1179 };
1180 
1181 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1182 {
1183 	struct wpa_ssid *ssid = wpa_s->current_ssid;
1184 
1185 	if (!ssid)
1186 		return WPAS_P2P_ROLE_DEVICE;
1187 	if (wpa_s->wpa_state != WPA_COMPLETED)
1188 		return WPAS_P2P_ROLE_DEVICE;
1189 
1190 	switch (ssid->mode) {
1191 	case WPAS_MODE_P2P_GO:
1192 	case WPAS_MODE_P2P_GROUP_FORMATION:
1193 		return WPAS_P2P_ROLE_GO;
1194 	case WPAS_MODE_INFRA:
1195 		if (ssid->p2p_group)
1196 			return WPAS_P2P_ROLE_CLIENT;
1197 		return WPAS_P2P_ROLE_DEVICE;
1198 	default:
1199 		return WPAS_P2P_ROLE_DEVICE;
1200 	}
1201 }
1202 
1203 
1204 dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
1205 				      void *user_data)
1206 {
1207 	struct wpa_supplicant *wpa_s = user_data;
1208 	char *str;
1209 
1210 	switch (wpas_get_p2p_role(wpa_s)) {
1211 	case WPAS_P2P_ROLE_GO:
1212 		str = "GO";
1213 		break;
1214 	case WPAS_P2P_ROLE_CLIENT:
1215 		str = "client";
1216 		break;
1217 	default:
1218 		str = "device";
1219 		break;
1220 	}
1221 
1222 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1223 						error);
1224 }
1225 
1226 
1227 dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
1228 				       void *user_data)
1229 {
1230 	struct wpa_supplicant *wpa_s = user_data;
1231 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
1232 	char *dbus_groupobj_path = path_buf;
1233 
1234 	if (wpa_s->dbus_groupobj_path == NULL)
1235 		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1236 			    "/");
1237 	else
1238 		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1239 			    "%s", wpa_s->dbus_groupobj_path);
1240 
1241 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1242 						&dbus_groupobj_path, error);
1243 }
1244 
1245 
1246 dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
1247 					DBusError *error, void *user_data)
1248 {
1249 	struct wpa_supplicant *wpa_s = user_data;
1250 	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1251 
1252 	if (!wpa_s->parent->parent->dbus_new_path)
1253 		return FALSE;
1254 
1255 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1256 		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
1257 	else
1258 		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1259 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1260 			    COMPACT_MACSTR,
1261 			    wpa_s->parent->parent->dbus_new_path,
1262 			    MAC2STR(wpa_s->go_dev_addr));
1263 
1264 	path = go_peer_obj_path;
1265 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1266 						&path, error);
1267 }
1268 
1269 
1270 /*
1271  * Peer object properties accessor methods
1272  */
1273 
1274 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
1275 						  DBusError *error,
1276 						  void *user_data)
1277 {
1278 	struct peer_handler_args *peer_args = user_data;
1279 	const struct p2p_peer_info *info;
1280 	char *tmp;
1281 
1282 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1283 		return FALSE;
1284 
1285 	/* get the peer info */
1286 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1287 				  peer_args->p2p_device_addr, 0);
1288 	if (info == NULL) {
1289 		dbus_set_error(error, DBUS_ERROR_FAILED,
1290 			       "failed to find peer");
1291 		return FALSE;
1292 	}
1293 
1294 	tmp = os_strdup(info->device_name);
1295 	if (!tmp) {
1296 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1297 		return FALSE;
1298 	}
1299 
1300 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1301 					      error)) {
1302 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1303 		os_free(tmp);
1304 		return FALSE;
1305 	}
1306 
1307 	os_free(tmp);
1308 	return TRUE;
1309 }
1310 
1311 
1312 dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
1313 						   DBusError *error,
1314 						   void *user_data)
1315 {
1316 	struct peer_handler_args *peer_args = user_data;
1317 	const struct p2p_peer_info *info;
1318 	char *tmp;
1319 
1320 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1321 		return FALSE;
1322 
1323 	/* get the peer info */
1324 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1325 				  peer_args->p2p_device_addr, 0);
1326 	if (info == NULL) {
1327 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1328 		return FALSE;
1329 	}
1330 
1331 	tmp = os_strdup(info->manufacturer);
1332 	if (!tmp) {
1333 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1334 		return FALSE;
1335 	}
1336 
1337 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1338 					      error)) {
1339 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1340 		os_free(tmp);
1341 		return FALSE;
1342 	}
1343 
1344 	os_free(tmp);
1345 	return TRUE;
1346 }
1347 
1348 
1349 dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
1350 						DBusError *error,
1351 						void *user_data)
1352 {
1353 	struct peer_handler_args *peer_args = user_data;
1354 	const struct p2p_peer_info *info;
1355 	char *tmp;
1356 
1357 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1358 		return FALSE;
1359 
1360 	/* get the peer info */
1361 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1362 				  peer_args->p2p_device_addr, 0);
1363 	if (info == NULL) {
1364 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1365 		return FALSE;
1366 	}
1367 
1368 	tmp = os_strdup(info->model_name);
1369 	if (!tmp) {
1370 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1371 		return FALSE;
1372 	}
1373 
1374 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1375 					      error)) {
1376 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1377 		os_free(tmp);
1378 		return FALSE;
1379 	}
1380 
1381 	os_free(tmp);
1382 	return TRUE;
1383 }
1384 
1385 
1386 dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
1387 						  DBusError *error,
1388 						  void *user_data)
1389 {
1390 	struct peer_handler_args *peer_args = user_data;
1391 	const struct p2p_peer_info *info;
1392 	char *tmp;
1393 
1394 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1395 		return FALSE;
1396 
1397 	/* get the peer info */
1398 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1399 				  peer_args->p2p_device_addr, 0);
1400 	if (info == NULL) {
1401 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1402 		return FALSE;
1403 	}
1404 
1405 	tmp = os_strdup(info->model_number);
1406 	if (!tmp) {
1407 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1408 		return FALSE;
1409 	}
1410 
1411 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1412 					      error)) {
1413 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1414 		os_free(tmp);
1415 		return FALSE;
1416 	}
1417 
1418 	os_free(tmp);
1419 	return TRUE;
1420 }
1421 
1422 
1423 dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
1424 						   DBusError *error,
1425 						   void *user_data)
1426 {
1427 	struct peer_handler_args *peer_args = user_data;
1428 	const struct p2p_peer_info *info;
1429 	char *tmp;
1430 
1431 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1432 		return FALSE;
1433 
1434 	/* get the peer info */
1435 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1436 				  peer_args->p2p_device_addr, 0);
1437 	if (info == NULL) {
1438 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1439 		return FALSE;
1440 	}
1441 
1442 	tmp = os_strdup(info->serial_number);
1443 	if (!tmp) {
1444 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1445 		return FALSE;
1446 	}
1447 
1448 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1449 					      error)) {
1450 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1451 		os_free(tmp);
1452 		return FALSE;
1453 	}
1454 
1455 	os_free(tmp);
1456 	return TRUE;
1457 }
1458 
1459 
1460 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
1461 	DBusMessageIter *iter, DBusError *error, void *user_data)
1462 {
1463 	struct peer_handler_args *peer_args = user_data;
1464 	const struct p2p_peer_info *info;
1465 
1466 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1467 				  peer_args->p2p_device_addr, 0);
1468 	if (info == NULL) {
1469 		dbus_set_error(error, DBUS_ERROR_FAILED,
1470 			       "failed to find peer");
1471 		return FALSE;
1472 	}
1473 
1474 	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
1475 						    (char *)
1476 						    info->pri_dev_type,
1477 						    WPS_DEV_TYPE_LEN, error)) {
1478 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1479 		return FALSE;
1480 	}
1481 
1482 	return TRUE;
1483 }
1484 
1485 
1486 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
1487 						    DBusError *error,
1488 						    void *user_data)
1489 {
1490 	struct peer_handler_args *peer_args = user_data;
1491 	const struct p2p_peer_info *info;
1492 
1493 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1494 				  peer_args->p2p_device_addr, 0);
1495 	if (info == NULL) {
1496 		dbus_set_error(error, DBUS_ERROR_FAILED,
1497 			       "failed to find peer");
1498 		return FALSE;
1499 	}
1500 
1501 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
1502 					      &info->config_methods, error)) {
1503 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1504 		return FALSE;
1505 	}
1506 
1507 	return TRUE;
1508 }
1509 
1510 
1511 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
1512 					    DBusError *error,
1513 					    void *user_data)
1514 {
1515 	struct peer_handler_args *peer_args = user_data;
1516 	const struct p2p_peer_info *info;
1517 
1518 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1519 				  peer_args->p2p_device_addr, 0);
1520 	if (info == NULL) {
1521 		dbus_set_error(error, DBUS_ERROR_FAILED,
1522 			       "failed to find peer");
1523 		return FALSE;
1524 	}
1525 
1526 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
1527 					      &info->level, error)) {
1528 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1529 		return FALSE;
1530 	}
1531 
1532 	return TRUE;
1533 }
1534 
1535 
1536 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
1537 							DBusError *error,
1538 							void *user_data)
1539 {
1540 	struct peer_handler_args *peer_args = user_data;
1541 	const struct p2p_peer_info *info;
1542 
1543 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1544 				  peer_args->p2p_device_addr, 0);
1545 	if (info == NULL) {
1546 		dbus_set_error(error, DBUS_ERROR_FAILED,
1547 			       "failed to find peer");
1548 		return FALSE;
1549 	}
1550 
1551 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1552 					      &info->dev_capab, error)) {
1553 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1554 		return FALSE;
1555 	}
1556 
1557 	return TRUE;
1558 }
1559 
1560 
1561 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
1562 						       DBusError *error,
1563 						       void *user_data)
1564 {
1565 	struct peer_handler_args *peer_args = user_data;
1566 	const struct p2p_peer_info *info;
1567 
1568 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1569 				  peer_args->p2p_device_addr, 0);
1570 	if (info == NULL) {
1571 		dbus_set_error(error, DBUS_ERROR_FAILED,
1572 			       "failed to find peer");
1573 		return FALSE;
1574 	}
1575 
1576 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1577 					      &info->group_capab, error)) {
1578 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1579 		return FALSE;
1580 	}
1581 
1582 	return TRUE;
1583 }
1584 
1585 
1586 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
1587 	DBusMessageIter *iter, DBusError *error, void *user_data)
1588 {
1589 	struct peer_handler_args *peer_args = user_data;
1590 	const struct p2p_peer_info *info;
1591 	DBusMessageIter variant_iter, array_iter;
1592 
1593 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1594 				  peer_args->p2p_device_addr, 0);
1595 	if (info == NULL) {
1596 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1597 		return FALSE;
1598 	}
1599 
1600 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1601 					      DBUS_TYPE_ARRAY_AS_STRING
1602 					      DBUS_TYPE_ARRAY_AS_STRING
1603 					      DBUS_TYPE_BYTE_AS_STRING,
1604 					      &variant_iter) ||
1605 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
1606 					      DBUS_TYPE_ARRAY_AS_STRING
1607 					      DBUS_TYPE_BYTE_AS_STRING,
1608 					      &array_iter)) {
1609 		dbus_set_error(error, DBUS_ERROR_FAILED,
1610 			       "%s: failed to construct message 1", __func__);
1611 		return FALSE;
1612 	}
1613 
1614 	if (info->wps_sec_dev_type_list_len) {
1615 		const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
1616 		int num_sec_device_types =
1617 			info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
1618 		int i;
1619 		DBusMessageIter inner_array_iter;
1620 
1621 		for (i = 0; i < num_sec_device_types; i++) {
1622 			if (!dbus_message_iter_open_container(
1623 				    &array_iter, DBUS_TYPE_ARRAY,
1624 				    DBUS_TYPE_BYTE_AS_STRING,
1625 				    &inner_array_iter) ||
1626 			    !dbus_message_iter_append_fixed_array(
1627 				    &inner_array_iter, DBUS_TYPE_BYTE,
1628 				    &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
1629 			    !dbus_message_iter_close_container(
1630 				    &array_iter, &inner_array_iter)) {
1631 				dbus_set_error(error, DBUS_ERROR_FAILED,
1632 					       "%s: failed to construct message 2 (%d)",
1633 					       __func__, i);
1634 				return FALSE;
1635 			}
1636 
1637 			sec_dev_type_list += WPS_DEV_TYPE_LEN;
1638 		}
1639 	}
1640 
1641 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
1642 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
1643 		dbus_set_error(error, DBUS_ERROR_FAILED,
1644 			       "%s: failed to construct message 3", __func__);
1645 		return FALSE;
1646 	}
1647 
1648 	return TRUE;
1649 }
1650 
1651 
1652 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
1653 						       DBusError *error,
1654 						       void *user_data)
1655 {
1656 	struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1657 	unsigned int i, num = 0;
1658 	struct peer_handler_args *peer_args = user_data;
1659 	const struct p2p_peer_info *info;
1660 
1661 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1662 				  peer_args->p2p_device_addr, 0);
1663 	if (info == NULL) {
1664 		dbus_set_error(error, DBUS_ERROR_FAILED,
1665 			       "failed to find peer");
1666 		return FALSE;
1667 	}
1668 
1669 	/* Add WPS vendor extensions attribute */
1670 	os_memset(vendor_extension, 0, sizeof(vendor_extension));
1671 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1672 		if (info->wps_vendor_ext[i] == NULL)
1673 			continue;
1674 		vendor_extension[num] = info->wps_vendor_ext[i];
1675 		num++;
1676 	}
1677 
1678 	if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
1679 							  vendor_extension,
1680 							  num, error))
1681 		return FALSE;
1682 
1683 	return TRUE;
1684 }
1685 
1686 
1687 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1688 					  DBusError *error, void *user_data)
1689 {
1690 	struct peer_handler_args *peer_args = user_data;
1691 	const struct p2p_peer_info *info;
1692 
1693 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1694 				  peer_args->p2p_device_addr, 0);
1695 	if (info == NULL) {
1696 		dbus_set_error(error, DBUS_ERROR_FAILED,
1697 			       "failed to find peer");
1698 		return FALSE;
1699 	}
1700 
1701 	if (info->wfd_subelems == NULL)
1702 		return wpas_dbus_simple_array_property_getter(iter,
1703 							      DBUS_TYPE_BYTE,
1704 							      NULL, 0, error);
1705 
1706 	return wpas_dbus_simple_array_property_getter(
1707 		iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf,
1708 		info->wfd_subelems->used, error);
1709 }
1710 
1711 
1712 dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
1713 						     DBusError *error,
1714 						     void *user_data)
1715 {
1716 	struct peer_handler_args *peer_args = user_data;
1717 	const struct p2p_peer_info *info;
1718 
1719 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1720 				  peer_args->p2p_device_addr, 0);
1721 	if (info == NULL) {
1722 		dbus_set_error(error, DBUS_ERROR_FAILED,
1723 			       "failed to find peer");
1724 		return FALSE;
1725 	}
1726 
1727 	return wpas_dbus_simple_array_property_getter(
1728 		iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
1729 		ETH_ALEN, error);
1730 }
1731 
1732 
1733 struct peer_group_data {
1734 	struct wpa_supplicant *wpa_s;
1735 	const struct p2p_peer_info *info;
1736 	char **paths;
1737 	unsigned int nb_paths;
1738 	int error;
1739 };
1740 
1741 
1742 static int match_group_where_peer_is_client(struct p2p_group *group,
1743 					    void *user_data)
1744 {
1745 	struct peer_group_data *data = user_data;
1746 	const struct p2p_group_config *cfg;
1747 	struct wpa_supplicant *wpa_s_go;
1748 	char **paths;
1749 
1750 	if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1751 		return 1;
1752 
1753 	cfg = p2p_group_get_config(group);
1754 
1755 	wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1756 					 cfg->ssid_len);
1757 	if (wpa_s_go == NULL)
1758 		return 1;
1759 
1760 	paths = os_realloc_array(data->paths, data->nb_paths + 1,
1761 				 sizeof(char *));
1762 	if (paths == NULL)
1763 		goto out_of_memory;
1764 
1765 	data->paths = paths;
1766 	data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
1767 	data->nb_paths++;
1768 
1769 	return 1;
1770 
1771 out_of_memory:
1772 	data->error = ENOMEM;
1773 	return 0;
1774 }
1775 
1776 
1777 dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
1778 					     DBusError *error,
1779 					     void *user_data)
1780 {
1781 	struct peer_handler_args *peer_args = user_data;
1782 	const struct p2p_peer_info *info;
1783 	struct peer_group_data data;
1784 	struct wpa_supplicant *wpa_s, *wpa_s_go;
1785 	dbus_bool_t success = FALSE;
1786 
1787 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1788 				  peer_args->p2p_device_addr, 0);
1789 	if (info == NULL) {
1790 		dbus_set_error(error, DBUS_ERROR_FAILED,
1791 			       "failed to find peer");
1792 		return FALSE;
1793 	}
1794 
1795 	os_memset(&data, 0, sizeof(data));
1796 
1797 	wpa_s = peer_args->wpa_s;
1798 	wpa_s = wpa_s->global->p2p_init_wpa_s;
1799 
1800 	wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
1801 	if (wpa_s_go) {
1802 		data.paths = os_calloc(1, sizeof(char *));
1803 		if (data.paths == NULL)
1804 			goto out_of_memory;
1805 		data.paths[0] = wpa_s_go->dbus_groupobj_path;
1806 		data.nb_paths = 1;
1807 	}
1808 
1809 	data.wpa_s = peer_args->wpa_s;
1810 	data.info = info;
1811 
1812 	p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
1813 			       match_group_where_peer_is_client, &data);
1814 	if (data.error)
1815 		goto out_of_memory;
1816 
1817 	if (data.paths == NULL) {
1818 		return wpas_dbus_simple_array_property_getter(
1819 			iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1820 	}
1821 
1822 	success = wpas_dbus_simple_array_property_getter(iter,
1823 							 DBUS_TYPE_OBJECT_PATH,
1824 							 data.paths,
1825 							 data.nb_paths, error);
1826 	goto out;
1827 
1828 out_of_memory:
1829 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1830 out:
1831 	os_free(data.paths);
1832 	return success;
1833 }
1834 
1835 
1836 /**
1837  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1838  * @iter: Pointer to incoming dbus message iter
1839  * @error: Location to store error on failure
1840  * @user_data: Function specific data
1841  * Returns: TRUE on success, FALSE on failure
1842  *
1843  * Getter for "PersistentGroups" property.
1844  */
1845 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1846 					       DBusError *error,
1847 					       void *user_data)
1848 {
1849 	struct wpa_supplicant *wpa_s = user_data;
1850 	struct wpa_ssid *ssid;
1851 	char **paths;
1852 	unsigned int i = 0, num = 0;
1853 	dbus_bool_t success = FALSE;
1854 
1855 	wpa_s = wpa_s->global->p2p_init_wpa_s;
1856 	if (!wpa_s->parent->dbus_new_path)
1857 		return FALSE;
1858 
1859 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1860 		if (network_is_persistent_group(ssid))
1861 			num++;
1862 
1863 	paths = os_calloc(num, sizeof(char *));
1864 	if (!paths) {
1865 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1866 		return FALSE;
1867 	}
1868 
1869 	/* Loop through configured networks and append object path of each */
1870 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1871 		if (!network_is_persistent_group(ssid))
1872 			continue;
1873 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1874 		if (paths[i] == NULL) {
1875 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1876 					     "no memory");
1877 			goto out;
1878 		}
1879 		/* Construct the object path for this network. */
1880 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1881 			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1882 			    wpa_s->parent->dbus_new_path, ssid->id);
1883 	}
1884 
1885 	success = wpas_dbus_simple_array_property_getter(iter,
1886 							 DBUS_TYPE_OBJECT_PATH,
1887 							 paths, num, error);
1888 
1889 out:
1890 	while (i)
1891 		os_free(paths[--i]);
1892 	os_free(paths);
1893 	return success;
1894 }
1895 
1896 
1897 /**
1898  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1899  *	group
1900  * @iter: Pointer to incoming dbus message iter
1901  * @error: Location to store error on failure
1902  * @user_data: Function specific data
1903  * Returns: TRUE on success, FALSE on failure
1904  *
1905  * Getter for "Properties" property of a persistent group.
1906  */
1907 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1908 							 DBusError *error,
1909 							 void *user_data)
1910 {
1911 	struct network_handler_args *net = user_data;
1912 
1913 	/* Leveraging the fact that persistent group object is still
1914 	 * represented in same manner as network within.
1915 	 */
1916 	return wpas_dbus_getter_network_properties(iter, error, net);
1917 }
1918 
1919 
1920 /**
1921  * wpas_dbus_setter_persistent_group_properties - Set options for a persistent
1922  *	group
1923  * @iter: Pointer to incoming dbus message iter
1924  * @error: Location to store error on failure
1925  * @user_data: Function specific data
1926  * Returns: TRUE on success, FALSE on failure
1927  *
1928  * Setter for "Properties" property of a persistent group.
1929  */
1930 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1931 							 DBusError *error,
1932 							 void *user_data)
1933 {
1934 	struct network_handler_args *net = user_data;
1935 	struct wpa_ssid *ssid = net->ssid;
1936 	DBusMessageIter	variant_iter;
1937 
1938 	/*
1939 	 * Leveraging the fact that persistent group object is still
1940 	 * represented in same manner as network within.
1941 	 */
1942 	dbus_message_iter_recurse(iter, &variant_iter);
1943 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1944 }
1945 
1946 
1947 /**
1948  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1949  *	persistent_group
1950  * @message: Pointer to incoming dbus message
1951  * @wpa_s: wpa_supplicant structure for a network interface
1952  * Returns: A dbus message containing the object path of the new
1953  * persistent group
1954  *
1955  * Handler function for "AddPersistentGroup" method call of a P2P Device
1956  * interface.
1957  */
1958 DBusMessage * wpas_dbus_handler_add_persistent_group(
1959 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1960 {
1961 	DBusMessage *reply = NULL;
1962 	DBusMessageIter	iter;
1963 	struct wpa_ssid *ssid = NULL;
1964 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1965 	DBusError error;
1966 
1967 	dbus_message_iter_init(message, &iter);
1968 
1969 	wpa_s = wpa_s->global->p2p_init_wpa_s;
1970 	if (wpa_s->parent->dbus_new_path)
1971 		ssid = wpa_config_add_network(wpa_s->conf);
1972 	if (ssid == NULL) {
1973 		wpa_printf(MSG_ERROR,
1974 			   "dbus: %s: Cannot add new persistent group",
1975 			   __func__);
1976 		reply = wpas_dbus_error_unknown_error(
1977 			message,
1978 			"wpa_supplicant could not add a persistent group on this interface.");
1979 		goto err;
1980 	}
1981 
1982 	/* Mark the ssid as being a persistent group before the notification */
1983 	ssid->disabled = 2;
1984 	ssid->p2p_persistent_group = 1;
1985 	wpas_notify_persistent_group_added(wpa_s, ssid);
1986 
1987 	wpa_config_set_network_defaults(ssid);
1988 
1989 	dbus_error_init(&error);
1990 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1991 		wpa_printf(MSG_DEBUG,
1992 			   "dbus: %s: Control interface could not set persistent group properties",
1993 			   __func__);
1994 		reply = wpas_dbus_reply_new_from_error(
1995 			message, &error, DBUS_ERROR_INVALID_ARGS,
1996 			"Failed to set network properties");
1997 		dbus_error_free(&error);
1998 		goto err;
1999 	}
2000 
2001 	/* Construct the object path for this network. */
2002 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
2003 		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
2004 		    wpa_s->parent->dbus_new_path, ssid->id);
2005 
2006 	reply = dbus_message_new_method_return(message);
2007 	if (reply == NULL) {
2008 		reply = wpas_dbus_error_no_memory(message);
2009 		goto err;
2010 	}
2011 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
2012 				      DBUS_TYPE_INVALID)) {
2013 		dbus_message_unref(reply);
2014 		reply = wpas_dbus_error_no_memory(message);
2015 		goto err;
2016 	}
2017 
2018 	return reply;
2019 
2020 err:
2021 	if (ssid) {
2022 		wpas_notify_persistent_group_removed(wpa_s, ssid);
2023 		wpa_config_remove_network(wpa_s->conf, ssid->id);
2024 	}
2025 	return reply;
2026 }
2027 
2028 
2029 /**
2030  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
2031  *	group
2032  * @message: Pointer to incoming dbus message
2033  * @wpa_s: wpa_supplicant structure for a network interface
2034  * Returns: NULL on success or dbus error on failure
2035  *
2036  * Handler function for "RemovePersistentGroup" method call of a P2P Device
2037  * interface.
2038  */
2039 DBusMessage * wpas_dbus_handler_remove_persistent_group(
2040 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2041 {
2042 	DBusMessage *reply = NULL;
2043 	const char *op;
2044 	char *iface = NULL, *persistent_group_id;
2045 	int id;
2046 	struct wpa_ssid *ssid;
2047 
2048 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
2049 			      DBUS_TYPE_INVALID);
2050 
2051 	wpa_s = wpa_s->global->p2p_init_wpa_s;
2052 
2053 	/*
2054 	 * Extract the network ID and ensure the network is actually a child of
2055 	 * this interface.
2056 	 */
2057 	iface = wpas_dbus_new_decompose_object_path(
2058 		op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
2059 		&persistent_group_id);
2060 	if (iface == NULL || persistent_group_id == NULL ||
2061 	    !wpa_s->parent->dbus_new_path ||
2062 	    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
2063 		reply = wpas_dbus_error_invalid_args(message, op);
2064 		goto out;
2065 	}
2066 
2067 	id = strtoul(persistent_group_id, NULL, 10);
2068 	if (errno == EINVAL) {
2069 		reply = wpas_dbus_error_invalid_args(message, op);
2070 		goto out;
2071 	}
2072 
2073 	ssid = wpa_config_get_network(wpa_s->conf, id);
2074 	if (ssid == NULL) {
2075 		reply = wpas_dbus_error_persistent_group_unknown(message);
2076 		goto out;
2077 	}
2078 
2079 	wpas_notify_persistent_group_removed(wpa_s, ssid);
2080 
2081 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
2082 		wpa_printf(MSG_ERROR,
2083 			   "dbus: %s: error occurred when removing persistent group %d",
2084 			   __func__, id);
2085 		reply = wpas_dbus_error_unknown_error(
2086 			message,
2087 			"error removing the specified persistent group on this interface.");
2088 		goto out;
2089 	}
2090 
2091 out:
2092 	os_free(iface);
2093 	return reply;
2094 }
2095 
2096 
2097 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
2098 				    struct wpa_ssid *ssid)
2099 {
2100 	wpas_notify_persistent_group_removed(wpa_s, ssid);
2101 
2102 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
2103 		wpa_printf(MSG_ERROR,
2104 			   "dbus: %s: error occurred when removing persistent group %d",
2105 			   __func__, ssid->id);
2106 		return;
2107 	}
2108 }
2109 
2110 
2111 /**
2112  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
2113  * persistent groups
2114  * @message: Pointer to incoming dbus message
2115  * @wpa_s: wpa_supplicant structure for a network interface
2116  * Returns: NULL on success or dbus error on failure
2117  *
2118  * Handler function for "RemoveAllPersistentGroups" method call of a
2119  * P2P Device interface.
2120  */
2121 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
2122 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2123 {
2124 	struct wpa_ssid *ssid, *next;
2125 	struct wpa_config *config;
2126 
2127 	wpa_s = wpa_s->global->p2p_init_wpa_s;
2128 
2129 	config = wpa_s->conf;
2130 	ssid = config->ssid;
2131 	while (ssid) {
2132 		next = ssid->next;
2133 		if (network_is_persistent_group(ssid))
2134 			remove_persistent_group(wpa_s, ssid);
2135 		ssid = next;
2136 	}
2137 	return NULL;
2138 }
2139 
2140 
2141 /*
2142  * Group object properties accessor methods
2143  */
2144 
2145 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
2146 					       DBusError *error,
2147 					       void *user_data)
2148 {
2149 	struct wpa_supplicant *wpa_s = user_data;
2150 	struct wpa_ssid *ssid;
2151 	unsigned int num_members;
2152 	char **paths;
2153 	unsigned int i;
2154 	void *next = NULL;
2155 	const u8 *addr;
2156 	dbus_bool_t success = FALSE;
2157 
2158 	if (!wpa_s->parent->parent->dbus_new_path)
2159 		return FALSE;
2160 
2161 	/* Verify correct role for this property */
2162 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
2163 		return wpas_dbus_simple_array_property_getter(
2164 			iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
2165 	}
2166 
2167 	ssid = wpa_s->conf->ssid;
2168 	/* At present WPAS P2P_GO mode only applicable for p2p_go */
2169 	if (ssid->mode != WPAS_MODE_P2P_GO &&
2170 	    ssid->mode != WPAS_MODE_AP &&
2171 	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
2172 		return FALSE;
2173 
2174 	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
2175 
2176 	paths = os_calloc(num_members, sizeof(char *));
2177 	if (!paths)
2178 		goto out_of_memory;
2179 
2180 	i = 0;
2181 	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
2182 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2183 		if (!paths[i])
2184 			goto out_of_memory;
2185 		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
2186 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
2187 			    "/" COMPACT_MACSTR,
2188 			    wpa_s->parent->parent->dbus_new_path,
2189 			    MAC2STR(addr));
2190 		i++;
2191 	}
2192 
2193 	success = wpas_dbus_simple_array_property_getter(iter,
2194 							 DBUS_TYPE_OBJECT_PATH,
2195 							 paths, num_members,
2196 							 error);
2197 
2198 	for (i = 0; i < num_members; i++)
2199 		os_free(paths[i]);
2200 	os_free(paths);
2201 	return success;
2202 
2203 out_of_memory:
2204 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2205 	if (paths) {
2206 		for (i = 0; i < num_members; i++)
2207 			os_free(paths[i]);
2208 		os_free(paths);
2209 	}
2210 	return FALSE;
2211 }
2212 
2213 
2214 dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
2215 					    DBusError *error, void *user_data)
2216 {
2217 	struct wpa_supplicant *wpa_s = user_data;
2218 
2219 	if (wpa_s->current_ssid == NULL)
2220 		return FALSE;
2221 	return wpas_dbus_simple_array_property_getter(
2222 		iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
2223 		wpa_s->current_ssid->ssid_len, error);
2224 }
2225 
2226 
2227 dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
2228 					     DBusError *error,
2229 					     void *user_data)
2230 {
2231 	struct wpa_supplicant *wpa_s = user_data;
2232 	u8 role = wpas_get_p2p_role(wpa_s);
2233 	u8 *p_bssid;
2234 
2235 	if (role == WPAS_P2P_ROLE_CLIENT) {
2236 		if (wpa_s->current_ssid == NULL)
2237 			return FALSE;
2238 		p_bssid = wpa_s->current_ssid->bssid;
2239 	} else {
2240 		if (wpa_s->ap_iface == NULL)
2241 			return FALSE;
2242 		p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
2243 	}
2244 
2245 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2246 						      p_bssid, ETH_ALEN,
2247 						      error);
2248 }
2249 
2250 
2251 dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
2252 						 DBusError *error,
2253 						 void *user_data)
2254 {
2255 	struct wpa_supplicant *wpa_s = user_data;
2256 	u16 op_freq;
2257 	u8 role = wpas_get_p2p_role(wpa_s);
2258 
2259 	if (role == WPAS_P2P_ROLE_CLIENT) {
2260 		if (wpa_s->go_params == NULL)
2261 			return FALSE;
2262 		op_freq = wpa_s->go_params->freq;
2263 	} else {
2264 		if (wpa_s->ap_iface == NULL)
2265 			return FALSE;
2266 		op_freq = wpa_s->ap_iface->freq;
2267 	}
2268 
2269 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
2270 						&op_freq, error);
2271 }
2272 
2273 
2274 dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
2275 						  DBusError *error,
2276 						  void *user_data)
2277 {
2278 	struct wpa_supplicant *wpa_s = user_data;
2279 	char *p_pass;
2280 	struct wpa_ssid *ssid = wpa_s->current_ssid;
2281 
2282 	if (ssid == NULL)
2283 		return FALSE;
2284 
2285 	p_pass = ssid->passphrase;
2286 	if (!p_pass)
2287 		p_pass = "";
2288 
2289 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2290 						&p_pass, error);
2291 
2292 }
2293 
2294 
2295 dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
2296 					   DBusError *error, void *user_data)
2297 {
2298 	struct wpa_supplicant *wpa_s = user_data;
2299 	u8 *p_psk = NULL;
2300 	u8 psk_len = 0;
2301 	struct wpa_ssid *ssid = wpa_s->current_ssid;
2302 
2303 	if (ssid == NULL)
2304 		return FALSE;
2305 
2306 	if (ssid->psk_set) {
2307 		p_psk = ssid->psk;
2308 		psk_len = sizeof(ssid->psk);
2309 	}
2310 
2311 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2312 						      p_psk, psk_len, error);
2313 }
2314 
2315 
2316 dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
2317 						  DBusError *error,
2318 						  void *user_data)
2319 {
2320 	struct wpa_supplicant *wpa_s = user_data;
2321 	struct hostapd_data *hapd;
2322 	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
2323 	unsigned int i, num_vendor_ext = 0;
2324 
2325 	os_memset(vendor_ext, 0, sizeof(vendor_ext));
2326 
2327 	/* Verify correct role for this property */
2328 	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
2329 		if (wpa_s->ap_iface == NULL)
2330 			return FALSE;
2331 		hapd = wpa_s->ap_iface->bss[0];
2332 
2333 		/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
2334 		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2335 			if (hapd->conf->wps_vendor_ext[i] == NULL)
2336 				continue;
2337 			vendor_ext[num_vendor_ext++] =
2338 				hapd->conf->wps_vendor_ext[i];
2339 		}
2340 	}
2341 
2342 	/* Return vendor extensions or no data */
2343 	return wpas_dbus_simple_array_array_property_getter(iter,
2344 							    DBUS_TYPE_BYTE,
2345 							    vendor_ext,
2346 							    num_vendor_ext,
2347 							    error);
2348 }
2349 
2350 
2351 dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
2352 						  DBusError *error,
2353 						  void *user_data)
2354 {
2355 	struct wpa_supplicant *wpa_s = user_data;
2356 	DBusMessageIter variant_iter, iter_dict, array_iter, sub;
2357 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
2358 	unsigned int i;
2359 	struct hostapd_data *hapd = NULL;
2360 
2361 	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
2362 	    wpa_s->ap_iface != NULL)
2363 		hapd = wpa_s->ap_iface->bss[0];
2364 	else
2365 		return FALSE;
2366 
2367 	dbus_message_iter_recurse(iter, &variant_iter);
2368 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
2369 		return FALSE;
2370 
2371 	/*
2372 	 * This is supposed to be array of bytearrays (aay), but the earlier
2373 	 * implementation used a dict with "WPSVendorExtensions" as the key in
2374 	 * this setter function which does not match the format used by the
2375 	 * getter function. For backwards compatibility, allow both formats to
2376 	 * be used in the setter.
2377 	 */
2378 	if (dbus_message_iter_get_element_type(&variant_iter) ==
2379 	    DBUS_TYPE_ARRAY) {
2380 		/* This is the proper format matching the getter */
2381 		struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
2382 
2383 		dbus_message_iter_recurse(&variant_iter, &array_iter);
2384 
2385 		if (dbus_message_iter_get_arg_type(&array_iter) !=
2386 		    DBUS_TYPE_ARRAY ||
2387 		    dbus_message_iter_get_element_type(&array_iter) !=
2388 		    DBUS_TYPE_BYTE) {
2389 			wpa_printf(MSG_DEBUG,
2390 				   "dbus: Not an array of array of bytes");
2391 			return FALSE;
2392 		}
2393 
2394 		i = 0;
2395 		os_memset(vals, 0, sizeof(vals));
2396 
2397 		while (dbus_message_iter_get_arg_type(&array_iter) ==
2398 		       DBUS_TYPE_ARRAY) {
2399 			char *val;
2400 			int len;
2401 
2402 			if (i == MAX_WPS_VENDOR_EXTENSIONS) {
2403 				wpa_printf(MSG_DEBUG,
2404 					   "dbus: Too many WPSVendorExtensions values");
2405 				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2406 				break;
2407 			}
2408 
2409 			dbus_message_iter_recurse(&array_iter, &sub);
2410 			dbus_message_iter_get_fixed_array(&sub, &val, &len);
2411 			wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
2412 				    val, len);
2413 			vals[i] = wpabuf_alloc_copy(val, len);
2414 			if (vals[i] == NULL) {
2415 				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2416 				break;
2417 			}
2418 			i++;
2419 			dbus_message_iter_next(&array_iter);
2420 		}
2421 
2422 		if (i > MAX_WPS_VENDOR_EXTENSIONS) {
2423 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
2424 				wpabuf_free(vals[i]);
2425 			return FALSE;
2426 		}
2427 
2428 		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2429 			wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2430 			hapd->conf->wps_vendor_ext[i] = vals[i];
2431 		}
2432 
2433 		hostapd_update_wps(hapd);
2434 
2435 		return TRUE;
2436 	}
2437 
2438 	if (dbus_message_iter_get_element_type(&variant_iter) !=
2439 	    DBUS_TYPE_DICT_ENTRY)
2440 		return FALSE;
2441 
2442 	wpa_printf(MSG_DEBUG,
2443 		   "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
2444 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
2445 		return FALSE;
2446 
2447 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2448 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
2449 			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2450 					     "invalid message format");
2451 			return FALSE;
2452 		}
2453 
2454 		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
2455 			if (entry.type != DBUS_TYPE_ARRAY ||
2456 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
2457 			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
2458 				goto error;
2459 
2460 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2461 				wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2462 				if (i < entry.array_len) {
2463 					hapd->conf->wps_vendor_ext[i] =
2464 						entry.binarray_value[i];
2465 					entry.binarray_value[i] = NULL;
2466 				} else
2467 					hapd->conf->wps_vendor_ext[i] = NULL;
2468 			}
2469 
2470 			hostapd_update_wps(hapd);
2471 		} else
2472 			goto error;
2473 
2474 		wpa_dbus_dict_entry_clear(&entry);
2475 	}
2476 
2477 	return TRUE;
2478 
2479 error:
2480 	wpa_dbus_dict_entry_clear(&entry);
2481 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2482 			     "invalid message format");
2483 	return FALSE;
2484 }
2485 
2486 
2487 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
2488 						struct wpa_supplicant *wpa_s)
2489 {
2490 	DBusMessageIter iter_dict;
2491 	DBusMessage *reply = NULL;
2492 	DBusMessageIter iter;
2493 	struct wpa_dbus_dict_entry entry;
2494 	int upnp = 0;
2495 	int bonjour = 0;
2496 	char *service = NULL;
2497 	struct wpabuf *query = NULL;
2498 	struct wpabuf *resp = NULL;
2499 	u8 version = 0;
2500 
2501 	dbus_message_iter_init(message, &iter);
2502 
2503 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2504 		goto error;
2505 
2506 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2507 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2508 			goto error;
2509 
2510 		if (os_strcmp(entry.key, "service_type") == 0 &&
2511 		    entry.type == DBUS_TYPE_STRING) {
2512 			if (os_strcmp(entry.str_value, "upnp") == 0)
2513 				upnp = 1;
2514 			else if (os_strcmp(entry.str_value, "bonjour") == 0)
2515 				bonjour = 1;
2516 			else
2517 				goto error_clear;
2518 		} else if (os_strcmp(entry.key, "version") == 0 &&
2519 			   entry.type == DBUS_TYPE_INT32) {
2520 			version = entry.uint32_value;
2521 		} else if (os_strcmp(entry.key, "service") == 0 &&
2522 			   entry.type == DBUS_TYPE_STRING) {
2523 			os_free(service);
2524 			service = os_strdup(entry.str_value);
2525 		} else if (os_strcmp(entry.key, "query") == 0) {
2526 			if (entry.type != DBUS_TYPE_ARRAY ||
2527 			    entry.array_type != DBUS_TYPE_BYTE)
2528 				goto error_clear;
2529 			query = wpabuf_alloc_copy(
2530 				entry.bytearray_value,
2531 				entry.array_len);
2532 		} else if (os_strcmp(entry.key, "response") == 0) {
2533 			if (entry.type != DBUS_TYPE_ARRAY ||
2534 			    entry.array_type != DBUS_TYPE_BYTE)
2535 				goto error_clear;
2536 			resp = wpabuf_alloc_copy(entry.bytearray_value,
2537 						 entry.array_len);
2538 		}
2539 		wpa_dbus_dict_entry_clear(&entry);
2540 	}
2541 
2542 	if (upnp == 1) {
2543 		if (version <= 0 || service == NULL)
2544 			goto error;
2545 
2546 		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
2547 			goto error;
2548 
2549 	} else if (bonjour == 1) {
2550 		if (query == NULL || resp == NULL)
2551 			goto error;
2552 
2553 		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
2554 			goto error;
2555 		query = NULL;
2556 		resp = NULL;
2557 	} else
2558 		goto error;
2559 
2560 	os_free(service);
2561 	return reply;
2562 error_clear:
2563 	wpa_dbus_dict_entry_clear(&entry);
2564 error:
2565 	os_free(service);
2566 	wpabuf_free(query);
2567 	wpabuf_free(resp);
2568 	return wpas_dbus_error_invalid_args(message, NULL);
2569 }
2570 
2571 
2572 DBusMessage * wpas_dbus_handler_p2p_delete_service(
2573 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2574 {
2575 	DBusMessageIter iter_dict;
2576 	DBusMessage *reply = NULL;
2577 	DBusMessageIter iter;
2578 	struct wpa_dbus_dict_entry entry;
2579 	int upnp = 0;
2580 	int bonjour = 0;
2581 	int ret = 0;
2582 	char *service = NULL;
2583 	struct wpabuf *query = NULL;
2584 	u8 version = 0;
2585 
2586 	dbus_message_iter_init(message, &iter);
2587 
2588 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2589 		goto error;
2590 
2591 	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2592 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2593 			goto error;
2594 
2595 		if (os_strcmp(entry.key, "service_type") == 0 &&
2596 		    entry.type == DBUS_TYPE_STRING) {
2597 			if (os_strcmp(entry.str_value, "upnp") == 0)
2598 				upnp = 1;
2599 			else if (os_strcmp(entry.str_value, "bonjour") == 0)
2600 				bonjour = 1;
2601 			else
2602 				goto error_clear;
2603 			wpa_dbus_dict_entry_clear(&entry);
2604 		}
2605 	}
2606 	if (upnp == 1) {
2607 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2608 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2609 				goto error;
2610 			if (os_strcmp(entry.key, "version") == 0 &&
2611 			    entry.type == DBUS_TYPE_INT32)
2612 				version = entry.uint32_value;
2613 			else if (os_strcmp(entry.key, "service") == 0 &&
2614 				 entry.type == DBUS_TYPE_STRING) {
2615 				os_free(service);
2616 				service = os_strdup(entry.str_value);
2617 			} else
2618 				goto error_clear;
2619 
2620 			wpa_dbus_dict_entry_clear(&entry);
2621 		}
2622 
2623 		if (version <= 0 || service == NULL)
2624 			goto error;
2625 
2626 		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
2627 		if (ret != 0)
2628 			goto error;
2629 	} else if (bonjour == 1) {
2630 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2631 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2632 				goto error;
2633 
2634 			if (os_strcmp(entry.key, "query") == 0) {
2635 				if (entry.type != DBUS_TYPE_ARRAY ||
2636 				    entry.array_type != DBUS_TYPE_BYTE)
2637 					goto error_clear;
2638 				wpabuf_free(query);
2639 				query = wpabuf_alloc_copy(
2640 					entry.bytearray_value,
2641 					entry.array_len);
2642 			} else
2643 				goto error_clear;
2644 
2645 			wpa_dbus_dict_entry_clear(&entry);
2646 		}
2647 
2648 		if (query == NULL)
2649 			goto error;
2650 
2651 		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2652 		if (ret != 0)
2653 			goto error;
2654 	} else
2655 		goto error;
2656 
2657 	wpabuf_free(query);
2658 	os_free(service);
2659 	return reply;
2660 error_clear:
2661 	wpa_dbus_dict_entry_clear(&entry);
2662 error:
2663 	wpabuf_free(query);
2664 	os_free(service);
2665 	return wpas_dbus_error_invalid_args(message, NULL);
2666 }
2667 
2668 
2669 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
2670 						  struct wpa_supplicant *wpa_s)
2671 {
2672 	wpas_p2p_service_flush(wpa_s);
2673 	return NULL;
2674 }
2675 
2676 
2677 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
2678 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2679 {
2680 	DBusMessageIter iter_dict;
2681 	DBusMessage *reply = NULL;
2682 	DBusMessageIter iter;
2683 	struct wpa_dbus_dict_entry entry;
2684 	int upnp = 0;
2685 	char *service = NULL;
2686 	char *peer_object_path = NULL;
2687 	struct wpabuf *tlv = NULL;
2688 	u8 version = 0;
2689 	u64 ref = 0;
2690 	u8 addr_buf[ETH_ALEN], *addr;
2691 
2692 	dbus_message_iter_init(message, &iter);
2693 
2694 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2695 		goto error;
2696 
2697 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2698 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2699 			goto error;
2700 		if (os_strcmp(entry.key, "peer_object") == 0 &&
2701 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
2702 			peer_object_path = os_strdup(entry.str_value);
2703 		} else if (os_strcmp(entry.key, "service_type") == 0 &&
2704 			   entry.type == DBUS_TYPE_STRING) {
2705 			if (os_strcmp(entry.str_value, "upnp") == 0)
2706 				upnp = 1;
2707 			else
2708 				goto error_clear;
2709 		} else if (os_strcmp(entry.key, "version") == 0 &&
2710 			   entry.type == DBUS_TYPE_INT32) {
2711 			version = entry.uint32_value;
2712 		} else if (os_strcmp(entry.key, "service") == 0 &&
2713 			   entry.type == DBUS_TYPE_STRING) {
2714 			service = os_strdup(entry.str_value);
2715 		} else if (os_strcmp(entry.key, "tlv") == 0) {
2716 			if (entry.type != DBUS_TYPE_ARRAY ||
2717 			    entry.array_type != DBUS_TYPE_BYTE)
2718 				goto error_clear;
2719 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
2720 						entry.array_len);
2721 		} else
2722 			goto error_clear;
2723 
2724 		wpa_dbus_dict_entry_clear(&entry);
2725 	}
2726 
2727 	if (!peer_object_path) {
2728 		addr = NULL;
2729 	} else {
2730 		if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
2731 		    !p2p_peer_known(wpa_s->global->p2p, addr_buf))
2732 			goto error;
2733 
2734 		addr = addr_buf;
2735 	}
2736 
2737 	if (upnp == 1) {
2738 		if (version <= 0 || service == NULL)
2739 			goto error;
2740 
2741 		ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
2742 	} else {
2743 		if (tlv == NULL)
2744 			goto error;
2745 		ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
2746 		wpabuf_free(tlv);
2747 	}
2748 
2749 	if (ref != 0) {
2750 		reply = dbus_message_new_method_return(message);
2751 		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2752 					 &ref, DBUS_TYPE_INVALID);
2753 	} else {
2754 		reply = wpas_dbus_error_unknown_error(
2755 			message, "Unable to send SD request");
2756 	}
2757 out:
2758 	os_free(service);
2759 	os_free(peer_object_path);
2760 	return reply;
2761 error_clear:
2762 	wpa_dbus_dict_entry_clear(&entry);
2763 error:
2764 	if (tlv)
2765 		wpabuf_free(tlv);
2766 	reply = wpas_dbus_error_invalid_args(message, NULL);
2767 	goto out;
2768 }
2769 
2770 
2771 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2772 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2773 {
2774 	DBusMessageIter iter_dict;
2775 	DBusMessage *reply = NULL;
2776 	DBusMessageIter iter;
2777 	struct wpa_dbus_dict_entry entry;
2778 	char *peer_object_path = NULL;
2779 	struct wpabuf *tlv = NULL;
2780 	int freq = 0;
2781 	int dlg_tok = 0;
2782 	u8 addr[ETH_ALEN];
2783 
2784 	dbus_message_iter_init(message, &iter);
2785 
2786 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2787 		goto error;
2788 
2789 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2790 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2791 			goto error;
2792 
2793 		if (os_strcmp(entry.key, "peer_object") == 0 &&
2794 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
2795 			peer_object_path = os_strdup(entry.str_value);
2796 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
2797 			   entry.type == DBUS_TYPE_INT32) {
2798 			freq = entry.uint32_value;
2799 		} else if (os_strcmp(entry.key, "dialog_token") == 0 &&
2800 			   (entry.type == DBUS_TYPE_UINT32 ||
2801 			    entry.type == DBUS_TYPE_INT32)) {
2802 			dlg_tok = entry.uint32_value;
2803 		} else if (os_strcmp(entry.key, "tlvs") == 0) {
2804 			if (entry.type != DBUS_TYPE_ARRAY ||
2805 			    entry.array_type != DBUS_TYPE_BYTE)
2806 				goto error_clear;
2807 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
2808 						entry.array_len);
2809 		} else
2810 			goto error_clear;
2811 
2812 		wpa_dbus_dict_entry_clear(&entry);
2813 	}
2814 	if (parse_peer_object_path(peer_object_path, addr) < 0 ||
2815 	    !p2p_peer_known(wpa_s->global->p2p, addr) ||
2816 	    tlv == NULL)
2817 		goto error;
2818 
2819 	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2820 	wpabuf_free(tlv);
2821 out:
2822 	os_free(peer_object_path);
2823 	return reply;
2824 error_clear:
2825 	wpa_dbus_dict_entry_clear(&entry);
2826 error:
2827 	reply = wpas_dbus_error_invalid_args(message, NULL);
2828 	goto out;
2829 }
2830 
2831 
2832 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2833 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2834 {
2835 	DBusMessageIter iter;
2836 	u64 req = 0;
2837 
2838 	dbus_message_iter_init(message, &iter);
2839 	dbus_message_iter_get_basic(&iter, &req);
2840 
2841 	if (req == 0)
2842 		goto error;
2843 
2844 	if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
2845 		goto error;
2846 
2847 	return NULL;
2848 error:
2849 	return wpas_dbus_error_invalid_args(message, NULL);
2850 }
2851 
2852 
2853 DBusMessage * wpas_dbus_handler_p2p_service_update(
2854 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2855 {
2856 	wpas_p2p_sd_service_update(wpa_s);
2857 	return NULL;
2858 }
2859 
2860 
2861 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2862 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2863 {
2864 	DBusMessageIter iter;
2865 	int ext = 0;
2866 
2867 	dbus_message_iter_init(message, &iter);
2868 	dbus_message_iter_get_basic(&iter, &ext);
2869 
2870 	wpa_s->p2p_sd_over_ctrl_iface = ext;
2871 
2872 	return NULL;
2873 
2874 }
2875 
2876 
2877 #ifdef CONFIG_WIFI_DISPLAY
2878 
2879 dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
2880 					    DBusError *error, void *user_data)
2881 {
2882 	struct wpa_global *global = user_data;
2883 	struct wpabuf *ie;
2884 	dbus_bool_t ret;
2885 
2886 	ie = wifi_display_get_wfd_ie(global);
2887 	if (ie == NULL)
2888 		return wpas_dbus_simple_array_property_getter(iter,
2889 							      DBUS_TYPE_BYTE,
2890 							      NULL, 0, error);
2891 
2892 	ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2893 						     wpabuf_head(ie),
2894 						     wpabuf_len(ie), error);
2895 	wpabuf_free(ie);
2896 
2897 	return ret;
2898 }
2899 
2900 
2901 dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
2902 					    DBusError *error, void *user_data)
2903 {
2904 	struct wpa_global *global = user_data;
2905 	DBusMessageIter variant, array;
2906 	struct wpabuf *ie = NULL;
2907 	const u8 *data;
2908 	int len;
2909 
2910 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
2911 		goto err;
2912 
2913 	dbus_message_iter_recurse(iter, &variant);
2914 	if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
2915 		goto err;
2916 
2917 	dbus_message_iter_recurse(&variant, &array);
2918 	dbus_message_iter_get_fixed_array(&array, &data, &len);
2919 	if (len == 0) {
2920 		wifi_display_enable(global, 0);
2921 		wifi_display_deinit(global);
2922 
2923 		return TRUE;
2924 	}
2925 
2926 	ie = wpabuf_alloc(len);
2927 	if (ie == NULL)
2928 		goto err;
2929 
2930 	wpabuf_put_data(ie, data, len);
2931 	if (wifi_display_subelem_set_from_ies(global, ie) != 0)
2932 		goto err;
2933 
2934 	if (global->wifi_display == 0)
2935 		wifi_display_enable(global, 1);
2936 
2937 	wpabuf_free(ie);
2938 
2939 	return TRUE;
2940 err:
2941 	wpabuf_free(ie);
2942 
2943 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2944 			     "invalid message format");
2945 	return FALSE;
2946 }
2947 
2948 #endif /* CONFIG_WIFI_DISPLAY */
2949