dbus_new_handlers_p2p.c revision 75ecf5267604f166b85a7ee2cf0d9cb682966680
1/*
2 * WPA Supplicant / dbus-based control interface (P2P)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Alternatively, this software may be distributed under the terms of BSD
9 * license.
10 *
11 * See README and COPYING for more details.
12 */
13
14#include "includes.h"
15
16#include "utils/includes.h"
17#include "common.h"
18#include "../config.h"
19#include "../wpa_supplicant_i.h"
20#include "../wps_supplicant.h"
21#include "../notify.h"
22#include "dbus_new_helpers.h"
23#include "dbus_new.h"
24#include "dbus_new_handlers.h"
25#include "dbus_new_handlers_p2p.h"
26#include "dbus_dict_helpers.h"
27#include "p2p/p2p.h"
28#include "common/ieee802_11_defs.h"
29#include "ap/hostapd.h"
30#include "ap/ap_config.h"
31#include "ap/wps_hostapd.h"
32
33#include "../p2p_supplicant.h"
34
35/**
36 * Parses out the mac address from the peer object path.
37 * @peer_path - object path of the form
38 *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
39 * @addr - out param must be of ETH_ALEN size
40 * Returns 0 if valid (including MAC), -1 otherwise
41 */
42static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
43{
44	char *p;
45
46	if (!peer_path)
47		return -1;
48	p = strrchr(peer_path, '/');
49	if (!p)
50		return -1;
51	p++;
52	return hwaddr_compact_aton(p, addr);
53}
54
55
56/**
57 * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
58 * error message
59 * @message: Pointer to incoming dbus message this error refers to
60 * Returns: a dbus error message
61 *
62 * Convenience function to create and return an invalid persistent group error.
63 */
64static DBusMessage * wpas_dbus_error_persistent_group_unknown(
65	DBusMessage *message)
66{
67	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
68				      "There is no such persistent group in "
69				      "this P2P device.");
70}
71
72
73DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
74					struct wpa_supplicant * wpa_s)
75{
76	struct wpa_dbus_dict_entry entry;
77	DBusMessage *reply = NULL;
78	DBusMessageIter iter;
79	DBusMessageIter iter_dict;
80	unsigned int timeout = 0;
81	unsigned int searchonly = 0;
82	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
83	int num_req_dev_types = 0;
84	unsigned int i;
85	u8 *req_dev_types = NULL;
86
87	dbus_message_iter_init(message, &iter);
88
89	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
90		goto error;
91
92	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
93		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
94			goto error;
95
96		if (!os_strcmp(entry.key, "Timeout") &&
97		    (entry.type == DBUS_TYPE_INT32)) {
98			timeout = entry.uint32_value;
99		} else if (!os_strcmp(entry.key, "SearchOnly") &&
100			   (entry.type == DBUS_TYPE_BOOLEAN)) {
101			searchonly = (entry.bool_value == TRUE) ? 1 : 0;
102		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
103			if ((entry.type != DBUS_TYPE_ARRAY) ||
104			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
105				goto error_clear;
106
107			req_dev_types =
108				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
109			if (!req_dev_types)
110				goto error_clear;
111
112			for (i = 0; i < entry.array_len; i++) {
113				if (wpabuf_len(entry.binarray_value[i]) !=
114							WPS_DEV_TYPE_LEN)
115					goto error_clear;
116				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
117					  wpabuf_head(entry.binarray_value[i]),
118					  WPS_DEV_TYPE_LEN);
119			}
120
121			num_req_dev_types = entry.array_len;
122		} else
123			goto error_clear;
124		wpa_dbus_dict_entry_clear(&entry);
125	}
126
127	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
128	return reply;
129
130error_clear:
131	os_free(req_dev_types);
132	wpa_dbus_dict_entry_clear(&entry);
133error:
134	reply = wpas_dbus_error_invalid_args(message, entry.key);
135	return reply;
136}
137
138DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
139					     struct wpa_supplicant * wpa_s)
140{
141	wpas_p2p_stop_find(wpa_s);
142	return NULL;
143}
144
145DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
146					      struct wpa_supplicant * wpa_s)
147{
148	DBusMessageIter iter;
149	char *peer_object_path = NULL;
150	u8 peer_addr[ETH_ALEN];
151
152	dbus_message_iter_init(message, &iter);
153	dbus_message_iter_get_basic(&iter, &peer_object_path);
154
155	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
156		return wpas_dbus_error_invalid_args(message, NULL);
157
158	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
159		return wpas_dbus_error_unknown_error(message,
160				"Failed to call wpas_p2p_reject method.");
161
162	return NULL;
163}
164
165DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
166					  struct wpa_supplicant * wpa_s)
167{
168	dbus_int32_t timeout = 0;
169
170	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
171				   DBUS_TYPE_INVALID))
172		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
173					      NULL);
174
175	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
176		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
177					      NULL);
178
179	return NULL;
180}
181
182DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
183						  struct wpa_supplicant * wpa_s)
184{
185	unsigned int period = 0, interval = 0;
186	struct wpa_dbus_dict_entry entry;
187	DBusMessageIter iter;
188	DBusMessageIter iter_dict;
189
190	dbus_message_iter_init(message, &iter);
191
192	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
193		goto error;
194
195	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
196		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
197			goto error;
198
199		if (!strcmp(entry.key, "period") &&
200		    (entry.type == DBUS_TYPE_INT32))
201			period = entry.uint32_value;
202		else if (!strcmp(entry.key, "interval") &&
203			 (entry.type == DBUS_TYPE_INT32))
204			interval = entry.uint32_value;
205		else
206			goto error_clear;
207		wpa_dbus_dict_entry_clear(&entry);
208	}
209
210	if (wpas_p2p_ext_listen(wpa_s, period, interval))
211		return wpas_dbus_error_unknown_error(message,
212					"failed to initiate a p2p_ext_listen.");
213
214	return NULL;
215
216error_clear:
217	wpa_dbus_dict_entry_clear(&entry);
218error:
219	return wpas_dbus_error_invalid_args(message, entry.key);
220}
221
222DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
223						    struct wpa_supplicant *
224						    wpa_s)
225{
226	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
227	struct wpa_dbus_dict_entry entry;
228	DBusMessageIter iter;
229	DBusMessageIter iter_dict;
230
231	dbus_message_iter_init(message, &iter);
232
233	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
234		goto error;
235
236	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
237		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
238			goto error;
239
240		if (!strcmp(entry.key, "duration1") &&
241		    (entry.type == DBUS_TYPE_INT32))
242			dur1 = entry.uint32_value;
243		else if (!strcmp(entry.key, "interval1") &&
244			 entry.type == DBUS_TYPE_INT32)
245			int1 = entry.uint32_value;
246		else if (!strcmp(entry.key, "duration2") &&
247			 entry.type == DBUS_TYPE_INT32)
248			dur2 = entry.uint32_value;
249		else if (!strcmp(entry.key, "interval2") &&
250			 entry.type == DBUS_TYPE_INT32)
251			int2 = entry.uint32_value;
252		else
253			goto error_clear;
254
255		wpa_dbus_dict_entry_clear(&entry);
256	}
257	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
258		return wpas_dbus_error_unknown_error(message,
259				"Failed to invoke presence request.");
260
261	return NULL;
262
263error_clear:
264	wpa_dbus_dict_entry_clear(&entry);
265error:
266	return wpas_dbus_error_invalid_args(message, entry.key);
267}
268
269DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
270					     struct wpa_supplicant * wpa_s)
271{
272	DBusMessageIter iter_dict;
273	DBusMessage *reply = NULL;
274	DBusMessageIter iter;
275	struct wpa_dbus_dict_entry entry;
276	char *pg_object_path = NULL;
277	int persistent_group = 0;
278	int freq = 0;
279	char *iface = NULL;
280	char *net_id_str = NULL;
281	unsigned int group_id = 0;
282	struct wpa_ssid *ssid;
283
284	dbus_message_iter_init(message, &iter);
285
286	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
287		goto inv_args;
288
289	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
290		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
291			goto inv_args;
292
293		if (!strcmp(entry.key, "persistent") &&
294		    (entry.type == DBUS_TYPE_BOOLEAN)) {
295			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
296		} else if (!strcmp(entry.key, "frequency") &&
297			   (entry.type == DBUS_TYPE_INT32)) {
298			freq = entry.int32_value;
299			if (freq <= 0)
300				goto inv_args_clear;
301		} else if (!strcmp(entry.key, "persistent_group_object") &&
302			   entry.type == DBUS_TYPE_OBJECT_PATH)
303			pg_object_path = os_strdup(entry.str_value);
304		else
305			goto inv_args_clear;
306
307		wpa_dbus_dict_entry_clear(&entry);
308	}
309
310	if (pg_object_path != NULL) {
311		/*
312		 * A persistent group Object Path is defined meaning we want
313		 * to re-invoke a persistent group.
314		 */
315
316		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
317							    &net_id_str, NULL);
318		if (iface == NULL ||
319		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
320			reply =
321			    wpas_dbus_error_invalid_args(message,
322							 pg_object_path);
323			goto out;
324		}
325
326		group_id = strtoul(net_id_str, NULL, 10);
327		if (errno == EINVAL) {
328			reply = wpas_dbus_error_invalid_args(
329						message, pg_object_path);
330			goto out;
331		}
332
333		/* Get the SSID structure form the persistant group id */
334		ssid = wpa_config_get_network(wpa_s->conf, group_id);
335		if (ssid == NULL || ssid->disabled != 2)
336			goto inv_args;
337
338		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
339			reply = wpas_dbus_error_unknown_error(message,
340							      "Failed to reinvoke a persistent group");
341			goto out;
342		}
343	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
344		goto inv_args;
345
346out:
347	os_free(pg_object_path);
348	os_free(net_id_str);
349	os_free(iface);
350	return reply;
351inv_args_clear:
352	wpa_dbus_dict_entry_clear(&entry);
353inv_args:
354	reply = wpas_dbus_error_invalid_args(message, NULL);
355	goto out;
356}
357
358DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
359					      struct wpa_supplicant *wpa_s)
360{
361	if (wpas_p2p_disconnect(wpa_s))
362		return wpas_dbus_error_unknown_error(message,
363						"failed to disconnect");
364
365	return NULL;
366}
367
368DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
369					 struct wpa_supplicant * wpa_s)
370{
371	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
372	wpa_s->force_long_sd = 0;
373	p2p_flush(wpa_s->global->p2p);
374
375	return NULL;
376}
377
378DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
379					   struct wpa_supplicant * wpa_s)
380{
381	DBusMessageIter iter_dict;
382	DBusMessage *reply = NULL;
383	DBusMessageIter iter;
384	struct wpa_dbus_dict_entry entry;
385	char *peer_object_path = NULL;
386	int persistent_group = 0;
387	int join = 0;
388	int authorize_only = 0;
389	int go_intent = -1;
390	int freq = 0;
391	u8 addr[ETH_ALEN];
392	char *pin = NULL;
393	enum p2p_wps_method wps_method = WPS_NOT_READY;
394	int new_pin;
395	char *err_msg = NULL;
396	char *iface = NULL;
397
398	dbus_message_iter_init(message, &iter);
399
400	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
401		goto inv_args;
402
403	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
404		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
405			goto inv_args;
406
407		if (!strcmp(entry.key, "peer") &&
408		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
409			peer_object_path = os_strdup(entry.str_value);
410		} else if (!strcmp(entry.key, "persistent") &&
411			   (entry.type == DBUS_TYPE_BOOLEAN)) {
412			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
413		} else if (!strcmp(entry.key, "join") &&
414			   (entry.type == DBUS_TYPE_BOOLEAN)) {
415			join = (entry.bool_value == TRUE) ? 1 : 0;
416		} else if (!strcmp(entry.key, "authorize_only") &&
417			   (entry.type == DBUS_TYPE_BOOLEAN)) {
418			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
419		} else if (!strcmp(entry.key, "frequency") &&
420			   (entry.type == DBUS_TYPE_INT32)) {
421			freq = entry.int32_value;
422			if (freq <= 0)
423				goto inv_args_clear;
424		} else if (!strcmp(entry.key, "go_intent") &&
425			   (entry.type == DBUS_TYPE_INT32)) {
426			go_intent = entry.int32_value;
427			if ((go_intent < 0) || (go_intent > 15))
428				goto inv_args_clear;
429		} else if (!strcmp(entry.key, "wps_method") &&
430			   (entry.type == DBUS_TYPE_STRING)) {
431			if (!strcmp(entry.str_value, "pbc"))
432				wps_method = WPS_PBC;
433			else if (!strcmp(entry.str_value, "pin"))
434				wps_method = WPS_PIN_DISPLAY;
435			else if (!strcmp(entry.str_value, "label"))
436				wps_method = WPS_PIN_LABEL;
437			else if (!strcmp(entry.str_value, "display"))
438				wps_method = WPS_PIN_DISPLAY;
439			else if (!strcmp(entry.str_value, "keypad"))
440				wps_method = WPS_PIN_KEYPAD;
441			else
442				goto inv_args_clear;
443		} else if (!strcmp(entry.key, "pin") &&
444			   (entry.type == DBUS_TYPE_STRING)) {
445			pin = os_strdup(entry.str_value);
446		} else
447			goto inv_args_clear;
448
449		wpa_dbus_dict_entry_clear(&entry);
450	}
451
452	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
453	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
454	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
455		reply = wpas_dbus_error_invalid_args(message, NULL);
456		goto inv_args;
457	}
458
459	/*
460	 * Validate the wps_method specified and the pin value.
461	 */
462	if ((!pin || !pin[0]) &&
463	    ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
464		goto inv_args;
465
466	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
467				   persistent_group, join, authorize_only,
468				   go_intent, freq);
469
470	if (new_pin >= 0) {
471		reply = dbus_message_new_method_return(message);
472		dbus_message_append_args(reply, DBUS_TYPE_INT32,
473					 &new_pin, DBUS_TYPE_INVALID);
474	} else {
475		switch (new_pin) {
476		case -2:
477			err_msg = "connect failed due to"
478					" channel unavailability.";
479			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
480			break;
481
482		case -3:
483			err_msg = "connect failed due to"
484					" unsupported channel.";
485			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
486			break;
487
488		default:
489			err_msg = "connect failed due to"
490					" unspecified error.";
491			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
492			break;
493		}
494		/*
495		 * TODO::
496		 * Do we need specialized errors corresponding to above
497		 * error conditions as against just returning a different
498		 * error message?
499		 */
500		reply = dbus_message_new_error(message, iface, err_msg);
501	}
502
503out:
504	os_free(peer_object_path);
505	os_free(pin);
506	return reply;
507inv_args_clear:
508	wpa_dbus_dict_entry_clear(&entry);
509inv_args:
510	reply = wpas_dbus_error_invalid_args(message, NULL);
511	goto out;
512}
513
514DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
515					  struct wpa_supplicant *wpa_s)
516{
517	DBusMessageIter iter_dict;
518	DBusMessage *reply = NULL;
519	DBusMessageIter iter;
520	struct wpa_dbus_dict_entry entry;
521	char *peer_object_path = NULL;
522	char *pg_object_path = NULL;
523	char *iface = NULL;
524	char *net_id_str = NULL;
525	u8 peer_addr[ETH_ALEN];
526	unsigned int group_id = 0;
527	int persistent = 0;
528	struct wpa_ssid *ssid;
529
530	dbus_message_iter_init(message, &iter);
531
532	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
533		goto err;
534
535	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
536		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
537			goto err;
538
539		if (!strcmp(entry.key, "peer") &&
540		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
541			peer_object_path = os_strdup(entry.str_value);
542			wpa_dbus_dict_entry_clear(&entry);
543		} else if (!strcmp(entry.key, "persistent_group_object") &&
544			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
545			pg_object_path = os_strdup(entry.str_value);
546			persistent = 1;
547			wpa_dbus_dict_entry_clear(&entry);
548		} else {
549			wpa_dbus_dict_entry_clear(&entry);
550			goto err;
551		}
552	}
553
554	if (!peer_object_path ||
555	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
556	    (p2p_get_peer_info(wpa_s->global->p2p,
557			       peer_addr, 0, NULL, 0) < 0)) {
558		goto err;
559	}
560
561	if (persistent) {
562		/*
563		 * A group ID is defined meaning we want to re-invoke a
564		 * persisatnt group
565		 */
566
567		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
568							    &net_id_str, NULL);
569		if (iface == NULL ||
570		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
571			reply =
572			    wpas_dbus_error_invalid_args(message,
573							 pg_object_path);
574			goto out;
575		}
576
577		group_id = strtoul(net_id_str, NULL, 10);
578		if (errno == EINVAL) {
579			reply = wpas_dbus_error_invalid_args(
580						message, pg_object_path);
581			goto out;
582		}
583
584		/* Get the SSID structure form the persistant group id */
585		ssid = wpa_config_get_network(wpa_s->conf, group_id);
586		if (ssid == NULL || ssid->disabled != 2)
587			goto err;
588
589		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
590			reply = wpas_dbus_error_unknown_error(
591					message,
592					"Failed to reinvoke a persistent group");
593			goto out;
594		}
595	} else {
596		/*
597		 * No group ID means propose to a peer to join my active group
598		 */
599		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
600					 peer_addr, NULL)) {
601			reply = wpas_dbus_error_unknown_error(
602					message,
603					"Failed to join to an active group");
604			goto out;
605		}
606	}
607
608out:
609	os_free(pg_object_path);
610	os_free(peer_object_path);
611	return reply;
612
613err:
614	reply = wpas_dbus_error_invalid_args(message, NULL);
615	goto out;
616}
617
618DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
619						 struct wpa_supplicant *wpa_s)
620{
621	DBusMessageIter iter;
622	char *peer_object_path = NULL;
623	char *config_method = NULL;
624	u8 peer_addr[ETH_ALEN];
625
626	dbus_message_iter_init(message, &iter);
627	dbus_message_iter_get_basic(&iter, &peer_object_path);
628
629	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
630		return wpas_dbus_error_invalid_args(message, NULL);
631
632	dbus_message_iter_next(&iter);
633	dbus_message_iter_get_basic(&iter, &config_method);
634
635	/*
636	 * Validation checks on config_method are being duplicated here
637	 * to be able to return invalid args reply since the error code
638	 * from p2p module are not granular enough (yet).
639	 */
640	if (os_strcmp(config_method, "display") &&
641	    os_strcmp(config_method, "keypad") &&
642	    os_strcmp(config_method, "pbc") &&
643	    os_strcmp(config_method, "pushbutton"))
644		return wpas_dbus_error_invalid_args(message, NULL);
645
646	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
647		return wpas_dbus_error_unknown_error(message,
648				"Failed to send provision discovery request");
649
650	return NULL;
651}
652
653/*
654 * P2P Device property accessor methods.
655 */
656
657DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
658						    struct wpa_supplicant *
659						    wpa_s)
660{
661	DBusMessage *reply = NULL;
662	DBusMessageIter iter, variant_iter, dict_iter;
663	const char *dev_name;
664	int num_sec_dev_types = 0;
665	int num_vendor_extensions = 0;
666	int i;
667	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
668
669	if (message == NULL)
670		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
671	else
672		reply = dbus_message_new_method_return(message);
673
674	if (!reply)
675		goto err_no_mem;
676
677	dbus_message_iter_init_append(reply, &iter);
678
679	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
680					      "a{sv}", &variant_iter) ||
681	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
682		goto err_no_mem;
683
684	/* DeviceName */
685	dev_name = wpa_s->conf->device_name;
686	if (dev_name &&
687	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
688		goto err_no_mem;
689
690	/* Primary device type */
691	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
692	    				     (char *)wpa_s->conf->device_type,
693	    				     WPS_DEV_TYPE_LEN))
694		goto err_no_mem;
695
696	/* Secondary device types */
697	for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
698		if (wpa_s->conf->sec_device_type[i] == NULL)
699			break;
700		num_sec_dev_types++;
701	}
702
703	if (!wpa_dbus_dict_append_string_array(
704			&dict_iter, "SecondaryDeviceTypes",
705			(const char **)wpa_s->conf->sec_device_type,
706			num_sec_dev_types))
707		goto err_no_mem;
708
709	/* Vendor Extensions */
710	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
711		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
712			continue;
713		vendor_ext[num_vendor_extensions++] =
714			wpa_s->conf->wps_vendor_ext[i];
715	}
716
717	if (num_vendor_extensions &&
718	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
719					       "VendorExtension",
720					       vendor_ext,
721					       num_vendor_extensions))
722		goto err_no_mem;
723
724	/* GO Intent */
725	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
726					 wpa_s->conf->p2p_go_intent))
727		goto err_no_mem;
728
729	/* Persistant Reconnect */
730	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
731				       wpa_s->conf->persistent_reconnect))
732		goto err_no_mem;
733
734	/* Listen Reg Class */
735	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
736					 wpa_s->conf->p2p_listen_reg_class))
737		goto err_no_mem;
738
739	/* Listen Channel */
740	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
741					 wpa_s->conf->p2p_listen_channel))
742		goto err_no_mem;
743
744	/* Oper Reg Class */
745	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
746					 wpa_s->conf->p2p_oper_reg_class))
747		goto err_no_mem;
748
749	/* Oper Channel */
750	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
751					 wpa_s->conf->p2p_oper_channel))
752		goto err_no_mem;
753
754	/* SSID Postfix */
755	if (wpa_s->conf->p2p_ssid_postfix &&
756	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
757					 wpa_s->conf->p2p_ssid_postfix))
758		goto err_no_mem;
759
760	/* Intra Bss */
761	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
762				       wpa_s->conf->p2p_intra_bss))
763		goto err_no_mem;
764
765	/* Group Idle */
766	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
767					 wpa_s->conf->p2p_group_idle))
768		goto err_no_mem;
769
770	/* Dissasociation low ack */
771	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
772					 wpa_s->conf->disassoc_low_ack))
773		goto err_no_mem;
774
775	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
776	    !dbus_message_iter_close_container(&iter, &variant_iter))
777		goto err_no_mem;
778
779	return reply;
780err_no_mem:
781	dbus_message_unref(reply);
782	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
783}
784
785DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
786						    struct wpa_supplicant *
787						    wpa_s)
788{
789	DBusMessage *reply = NULL;
790	DBusMessageIter iter, variant_iter;
791	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
792	DBusMessageIter iter_dict;
793	unsigned int i;
794
795	dbus_message_iter_init(message, &iter);
796
797	dbus_message_iter_next(&iter);
798	dbus_message_iter_next(&iter);
799
800	dbus_message_iter_recurse(&iter, &variant_iter);
801
802	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
803		return wpas_dbus_error_invalid_args(message, NULL);
804
805	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
806		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
807			return wpas_dbus_error_invalid_args(message, NULL);
808
809		if (os_strcmp(entry.key, "DeviceName") == 0) {
810			char *devname;
811
812			if (entry.type != DBUS_TYPE_STRING)
813				goto error_clear;
814
815			devname = os_strdup(entry.str_value);
816			if (devname == NULL)
817				goto err_no_mem_clear;
818
819			os_free(wpa_s->conf->device_name);
820			wpa_s->conf->device_name = devname;
821
822			wpa_s->conf->changed_parameters |=
823							CFG_CHANGED_DEVICE_NAME;
824		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
825			if (entry.type != DBUS_TYPE_ARRAY ||
826			    entry.array_type != DBUS_TYPE_BYTE ||
827			    entry.array_len != WPS_DEV_TYPE_LEN)
828				goto error_clear;
829
830			os_memcpy(wpa_s->conf->device_type,
831				  entry.bytearray_value,
832				  WPS_DEV_TYPE_LEN);
833			wpa_s->conf->changed_parameters |=
834				CFG_CHANGED_DEVICE_TYPE;
835		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
836			if (entry.type != DBUS_TYPE_ARRAY ||
837			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
838			    entry.array_len > MAX_SEC_DEVICE_TYPES)
839				goto error;
840
841			for (i = 0; i < entry.array_len; i++)
842				if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
843					goto err_no_mem_clear;
844			for (i = 0; i < entry.array_len; i++)
845				os_memcpy(wpa_s->conf->sec_device_type[i],
846					  wpabuf_head(entry.binarray_value[i]),
847					  WPS_DEV_TYPE_LEN);
848			wpa_s->conf->num_sec_device_types = entry.array_len;
849			wpa_s->conf->changed_parameters |=
850					CFG_CHANGED_SEC_DEVICE_TYPE;
851		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
852			if ((entry.type != DBUS_TYPE_ARRAY) ||
853			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
854			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
855				goto error_clear;
856
857			wpa_s->conf->changed_parameters |=
858					CFG_CHANGED_VENDOR_EXTENSION;
859
860			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
861				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
862				if (i < entry.array_len) {
863					wpa_s->conf->wps_vendor_ext[i] =
864						entry.binarray_value[i];
865					entry.binarray_value[i] = NULL;
866				} else
867					wpa_s->conf->wps_vendor_ext[i] = NULL;
868			}
869		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
870			   (entry.type == DBUS_TYPE_UINT32) &&
871			   (entry.uint32_value <= 15))
872			wpa_s->conf->p2p_go_intent = entry.uint32_value;
873
874		else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
875			 (entry.type == DBUS_TYPE_BOOLEAN))
876			wpa_s->conf->persistent_reconnect = entry.bool_value;
877
878		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
879			 (entry.type == DBUS_TYPE_UINT32)) {
880			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
881			wpa_s->conf->changed_parameters |=
882				CFG_CHANGED_P2P_LISTEN_CHANNEL;
883		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
884			   (entry.type == DBUS_TYPE_UINT32)) {
885			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
886			wpa_s->conf->changed_parameters |=
887				CFG_CHANGED_P2P_LISTEN_CHANNEL;
888		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
889			   (entry.type == DBUS_TYPE_UINT32)) {
890			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
891			wpa_s->conf->changed_parameters |=
892				CFG_CHANGED_P2P_OPER_CHANNEL;
893		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
894			   (entry.type == DBUS_TYPE_UINT32)) {
895			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
896			wpa_s->conf->changed_parameters |=
897				CFG_CHANGED_P2P_OPER_CHANNEL;
898		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
899			char *postfix;
900
901			if (entry.type != DBUS_TYPE_STRING)
902				goto error_clear;
903
904			postfix = os_strdup(entry.str_value);
905			if (!postfix)
906				goto err_no_mem_clear;
907
908			os_free(wpa_s->conf->p2p_ssid_postfix);
909			wpa_s->conf->p2p_ssid_postfix = postfix;
910
911			wpa_s->conf->changed_parameters |=
912					CFG_CHANGED_P2P_SSID_POSTFIX;
913		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
914			   (entry.type == DBUS_TYPE_BOOLEAN)) {
915			wpa_s->conf->p2p_intra_bss = entry.bool_value;
916			wpa_s->conf->changed_parameters |=
917						      CFG_CHANGED_P2P_INTRA_BSS;
918		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
919			   (entry.type == DBUS_TYPE_UINT32))
920			wpa_s->conf->p2p_group_idle = entry.uint32_value;
921		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
922			 entry.type == DBUS_TYPE_UINT32)
923			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
924		else
925			goto error_clear;
926
927		wpa_dbus_dict_entry_clear(&entry);
928	}
929
930	if (wpa_s->conf->changed_parameters) {
931		/* Some changed parameters requires to update config*/
932		wpa_supplicant_update_config(wpa_s);
933	}
934
935	return reply;
936
937 error_clear:
938	wpa_dbus_dict_entry_clear(&entry);
939 error:
940	reply = wpas_dbus_error_invalid_args(message, entry.key);
941	wpa_dbus_dict_entry_clear(&entry);
942
943	return reply;
944 err_no_mem_clear:
945	wpa_dbus_dict_entry_clear(&entry);
946	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
947}
948
949DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
950					struct wpa_supplicant * wpa_s)
951{
952	DBusMessage *reply = NULL;
953	struct p2p_data *p2p = wpa_s->global->p2p;
954	int next = 0, i = 0;
955	int num = 0, out_of_mem = 0;
956	const u8 *addr;
957	const struct p2p_peer_info *peer_info = NULL;
958
959	struct dl_list peer_objpath_list;
960	struct peer_objpath_node {
961		struct dl_list list;
962		char path[WPAS_DBUS_OBJECT_PATH_MAX];
963	} *node, *tmp;
964
965	char **peer_obj_paths = NULL;
966
967	dl_list_init(&peer_objpath_list);
968
969	/* Get the first peer info */
970	peer_info = p2p_get_peer_found(p2p, NULL, next);
971
972	/* Get next and accumulate them */
973	next = 1;
974	while (peer_info != NULL) {
975		node = os_zalloc(sizeof(struct peer_objpath_node));
976		if (!node) {
977			out_of_mem = 1;
978			goto error;
979		}
980
981		addr = peer_info->p2p_device_addr;
982		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
983			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
984			    "/" COMPACT_MACSTR,
985			    wpa_s->dbus_new_path, MAC2STR(addr));
986		dl_list_add_tail(&peer_objpath_list, &node->list);
987		num++;
988
989		peer_info = p2p_get_peer_found(p2p, addr, next);
990	}
991
992	/*
993	 * Now construct the peer object paths in a form suitable for
994	 * array_property_getter helper below.
995	 */
996	peer_obj_paths = os_zalloc(num * sizeof(char *));
997
998	if (!peer_obj_paths) {
999		out_of_mem = 1;
1000		goto error;
1001	}
1002
1003	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1004			      struct peer_objpath_node, list)
1005		peer_obj_paths[i++] = node->path;
1006
1007	reply = wpas_dbus_simple_array_property_getter(message,
1008						       DBUS_TYPE_OBJECT_PATH,
1009						       peer_obj_paths, num);
1010
1011error:
1012	if (peer_obj_paths)
1013		os_free(peer_obj_paths);
1014
1015	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1016			      struct peer_objpath_node, list) {
1017		dl_list_del(&node->list);
1018		os_free(node);
1019	}
1020	if (out_of_mem)
1021		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1022					       NULL);
1023
1024	return reply;
1025}
1026
1027enum wpas_p2p_role {
1028	WPAS_P2P_ROLE_DEVICE,
1029	WPAS_P2P_ROLE_GO,
1030	WPAS_P2P_ROLE_CLIENT,
1031};
1032
1033static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1034{
1035	struct wpa_ssid *ssid = wpa_s->current_ssid;
1036
1037	if (!ssid)
1038		return WPAS_P2P_ROLE_DEVICE;
1039	if (wpa_s->wpa_state != WPA_COMPLETED)
1040		return WPAS_P2P_ROLE_DEVICE;
1041
1042	switch (ssid->mode) {
1043	case WPAS_MODE_P2P_GO:
1044	case WPAS_MODE_P2P_GROUP_FORMATION:
1045		return WPAS_P2P_ROLE_GO;
1046	case WPAS_MODE_INFRA:
1047		if (ssid->p2p_group)
1048			return WPAS_P2P_ROLE_CLIENT;
1049		return WPAS_P2P_ROLE_DEVICE;
1050	default:
1051		return WPAS_P2P_ROLE_DEVICE;
1052	}
1053}
1054
1055DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
1056				       struct wpa_supplicant * wpa_s)
1057{
1058	char *str;
1059
1060	switch (wpas_get_p2p_role(wpa_s)) {
1061	case WPAS_P2P_ROLE_GO:
1062		str = "GO";
1063		break;
1064	case WPAS_P2P_ROLE_CLIENT:
1065		str = "client";
1066		break;
1067	default:
1068		str = "device";
1069	}
1070
1071	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1072						&str);
1073}
1074
1075DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
1076					struct wpa_supplicant * wpa_s)
1077{
1078	if (wpa_s->dbus_groupobj_path == NULL)
1079		return NULL;
1080
1081	return wpas_dbus_simple_property_getter(message,
1082						DBUS_TYPE_OBJECT_PATH,
1083						&wpa_s->dbus_groupobj_path);
1084}
1085
1086DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
1087					 struct wpa_supplicant * wpa_s)
1088{
1089	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1090
1091	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1092		return NULL;
1093
1094	os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1095		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1096		    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1097	path = go_peer_obj_path;
1098	return wpas_dbus_simple_property_getter(message,
1099						DBUS_TYPE_OBJECT_PATH, &path);
1100}
1101
1102/*
1103 * Peer object properties accessor methods
1104 */
1105
1106DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
1107						  struct peer_handler_args *
1108						  peer_args)
1109{
1110	DBusMessage *reply = NULL;
1111	DBusMessageIter iter, variant_iter, dict_iter;
1112	const struct p2p_peer_info *info = NULL;
1113	char devtype[WPS_DEV_TYPE_BUFSIZE];
1114
1115	/* get the peer info */
1116	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1117				  peer_args->p2p_device_addr, 0);
1118	if (info == NULL)
1119		return NULL;
1120
1121	if (message == NULL)
1122		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1123	else
1124		reply = dbus_message_new_method_return(message);
1125
1126	if (!reply)
1127		goto err_no_mem;
1128
1129	dbus_message_iter_init_append(reply, &iter);
1130	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1131					      "a{sv}", &variant_iter) ||
1132	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1133		goto err_no_mem;
1134
1135	/* Fill out the dictionary */
1136	wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1137	if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1138					 info->device_name))
1139		goto err_no_mem;
1140	if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1141					 devtype))
1142		goto err_no_mem;
1143	if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1144					 info->config_methods))
1145		goto err_no_mem;
1146	if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1147					 info->level))
1148		goto err_no_mem;
1149	if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1150				       info->dev_capab))
1151		goto err_no_mem;
1152	if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1153				       info->group_capab))
1154		goto err_no_mem;
1155
1156	if (info->wps_sec_dev_type_list_len) {
1157		char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1158		u8 *sec_dev_type_list = NULL;
1159		char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1160		int num_sec_dev_types = 0;
1161		int i;
1162
1163		sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1164
1165		if (sec_dev_type_list == NULL)
1166			goto err_no_mem;
1167
1168		os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1169			  info->wps_sec_dev_type_list_len);
1170
1171		for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1172		       i < (int) (info->wps_sec_dev_type_list_len /
1173				  WPS_DEV_TYPE_LEN);
1174		     i++) {
1175			sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1176
1177			if (!sec_dev_types[i] ||
1178			    wps_dev_type_bin2str(
1179					&sec_dev_type_list[i *
1180							   WPS_DEV_TYPE_LEN],
1181					sec_dev_types[i],
1182					sizeof(secdevtype)) == NULL) {
1183				while (--i >= 0)
1184					os_free(sec_dev_types[i]);
1185				os_free(sec_dev_type_list);
1186				goto err_no_mem;
1187			}
1188
1189			num_sec_dev_types++;
1190		}
1191
1192		os_free(sec_dev_type_list);
1193
1194		if (num_sec_dev_types) {
1195			if (!wpa_dbus_dict_append_string_array(&dict_iter,
1196						"SecondaryDeviceTypes",
1197						(const char **)sec_dev_types,
1198						num_sec_dev_types)) {
1199				for (i = 0; i < num_sec_dev_types; i++)
1200					os_free(sec_dev_types[i]);
1201				goto err_no_mem;
1202			}
1203
1204			for (i = 0; i < num_sec_dev_types; i++)
1205				os_free(sec_dev_types[i]);
1206		}
1207	}
1208
1209	{
1210		/* Add WPS vendor extensions attribute */
1211		const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1212		int i, num = 0;
1213
1214		for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1215			if (info->wps_vendor_ext[i] == NULL)
1216				continue;
1217			vendor_extension[num] = info->wps_vendor_ext[i];
1218			num++;
1219		}
1220
1221		if (!wpa_dbus_dict_append_wpabuf_array(
1222					&dict_iter, "VendorExtension",
1223					vendor_extension, num))
1224			goto err_no_mem;
1225	}
1226
1227	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1228	    !dbus_message_iter_close_container(&iter, &variant_iter))
1229		goto err_no_mem;
1230
1231	return reply;
1232err_no_mem:
1233	dbus_message_unref(reply);
1234	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1235}
1236
1237DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
1238					   struct peer_handler_args * peer_args)
1239{
1240	return NULL;
1241}
1242
1243
1244/**
1245 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1246 * @message: Pointer to incoming dbus message
1247 * @wpa_s: wpa_supplicant structure for a network interface
1248 * Returns: a dbus message containing an array of all persistent group
1249 * dbus object paths.
1250 *
1251 * Getter for "Networks" property.
1252 */
1253DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
1254						 struct wpa_supplicant *wpa_s)
1255{
1256	DBusMessage *reply = NULL;
1257	struct wpa_ssid *ssid;
1258	char **paths;
1259	unsigned int i = 0, num = 0;
1260
1261	if (wpa_s->conf == NULL) {
1262		wpa_printf(MSG_ERROR, "dbus: %s: "
1263			   "An error occurred getting persistent groups list",
1264			   __func__);
1265		return wpas_dbus_error_unknown_error(message, NULL);
1266	}
1267
1268	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1269		if (network_is_persistent_group(ssid))
1270			num++;
1271
1272	paths = os_zalloc(num * sizeof(char *));
1273	if (!paths) {
1274		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1275					      NULL);
1276	}
1277
1278	/* Loop through configured networks and append object path of each */
1279	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1280		if (!network_is_persistent_group(ssid))
1281			continue;
1282		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1283		if (paths[i] == NULL) {
1284			reply = dbus_message_new_error(message,
1285						       DBUS_ERROR_NO_MEMORY,
1286						       NULL);
1287			goto out;
1288		}
1289		/* Construct the object path for this network. */
1290		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1291			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1292			    wpa_s->dbus_new_path, ssid->id);
1293	}
1294
1295	reply = wpas_dbus_simple_array_property_getter(message,
1296						       DBUS_TYPE_OBJECT_PATH,
1297						       paths, num);
1298
1299out:
1300	while (i)
1301		os_free(paths[--i]);
1302	os_free(paths);
1303	return reply;
1304}
1305
1306
1307/**
1308 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1309 *	group
1310 * @message: Pointer to incoming dbus message
1311 * @net: wpa_supplicant structure for a network interface and
1312 * wpa_ssid structure for a configured persistent group (internally network)
1313 * Returns: DBus message with network properties or DBus error on failure
1314 *
1315 * Getter for "Properties" property of a persistent group.
1316 */
1317DBusMessage * wpas_dbus_getter_persistent_group_properties(
1318	DBusMessage *message, struct network_handler_args *net)
1319{
1320	/*
1321	 * Leveraging the fact that persistent group object is still
1322	 * represented in same manner as network within.
1323	 */
1324	return wpas_dbus_getter_network_properties(message, net);
1325}
1326
1327
1328/**
1329 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1330 *	group
1331 * @message: Pointer to incoming dbus message
1332 * @net: wpa_supplicant structure for a network interface and
1333 * wpa_ssid structure for a configured persistent group (internally network)
1334 * Returns: DBus message with network properties or DBus error on failure
1335 *
1336 * Setter for "Properties" property of a persistent group.
1337 */
1338DBusMessage * wpas_dbus_setter_persistent_group_properties(
1339	DBusMessage *message, struct network_handler_args *net)
1340{
1341	struct wpa_ssid *ssid = net->ssid;
1342	DBusMessage *reply = NULL;
1343	DBusMessageIter	iter, variant_iter;
1344
1345	dbus_message_iter_init(message, &iter);
1346
1347	dbus_message_iter_next(&iter);
1348	dbus_message_iter_next(&iter);
1349
1350	dbus_message_iter_recurse(&iter, &variant_iter);
1351
1352	/*
1353	 * Leveraging the fact that persistent group object is still
1354	 * represented in same manner as network within.
1355	 */
1356	reply = set_network_properties(message, net->wpa_s, ssid,
1357				       &variant_iter);
1358	if (reply)
1359		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
1360			   "persistent group properties");
1361
1362	return reply;
1363}
1364
1365
1366/**
1367 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1368 *	persistent_group
1369 * @message: Pointer to incoming dbus message
1370 * @wpa_s: wpa_supplicant structure for a network interface
1371 * Returns: A dbus message containing the object path of the new
1372 * persistent group
1373 *
1374 * Handler function for "AddPersistentGroup" method call of a P2P Device
1375 * interface.
1376 */
1377DBusMessage * wpas_dbus_handler_add_persistent_group(
1378	DBusMessage *message, struct wpa_supplicant *wpa_s)
1379{
1380	DBusMessage *reply = NULL;
1381	DBusMessageIter	iter;
1382	struct wpa_ssid *ssid = NULL;
1383	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1384
1385	dbus_message_iter_init(message, &iter);
1386
1387	ssid = wpa_config_add_network(wpa_s->conf);
1388	if (ssid == NULL) {
1389		wpa_printf(MSG_ERROR, "dbus: %s: "
1390			   "Cannot add new persistent group", __func__);
1391		reply = wpas_dbus_error_unknown_error(
1392			message,
1393			"wpa_supplicant could not add "
1394			"a persistent group on this interface.");
1395		goto err;
1396	}
1397
1398	/* Mark the ssid as being a persistent group before the notification */
1399	ssid->disabled = 2;
1400	ssid->p2p_persistent_group = 1;
1401	wpas_notify_persistent_group_added(wpa_s, ssid);
1402
1403	wpa_config_set_network_defaults(ssid);
1404
1405	reply = set_network_properties(message, wpa_s, ssid, &iter);
1406	if (reply) {
1407		wpa_printf(MSG_DEBUG, "dbus: %s: "
1408			   "Control interface could not set persistent group "
1409			   "properties", __func__);
1410		goto err;
1411	}
1412
1413	/* Construct the object path for this network. */
1414	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1415		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1416		    wpa_s->dbus_new_path, ssid->id);
1417
1418	reply = dbus_message_new_method_return(message);
1419	if (reply == NULL) {
1420		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1421					       NULL);
1422		goto err;
1423	}
1424	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1425				      DBUS_TYPE_INVALID)) {
1426		dbus_message_unref(reply);
1427		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1428					       NULL);
1429		goto err;
1430	}
1431
1432	return reply;
1433
1434err:
1435	if (ssid) {
1436		wpas_notify_persistent_group_removed(wpa_s, ssid);
1437		wpa_config_remove_network(wpa_s->conf, ssid->id);
1438	}
1439	return reply;
1440}
1441
1442
1443/**
1444 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1445 *	group
1446 * @message: Pointer to incoming dbus message
1447 * @wpa_s: wpa_supplicant structure for a network interface
1448 * Returns: NULL on success or dbus error on failure
1449 *
1450 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1451 * interface.
1452 */
1453DBusMessage * wpas_dbus_handler_remove_persistent_group(
1454	DBusMessage *message, struct wpa_supplicant *wpa_s)
1455{
1456	DBusMessage *reply = NULL;
1457	const char *op;
1458	char *iface = NULL, *persistent_group_id = NULL;
1459	int id;
1460	struct wpa_ssid *ssid;
1461
1462	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1463			      DBUS_TYPE_INVALID);
1464
1465	/*
1466	 * Extract the network ID and ensure the network is actually a child of
1467	 * this interface.
1468	 */
1469	iface = wpas_dbus_new_decompose_object_path(op, 1,
1470						    &persistent_group_id,
1471						    NULL);
1472	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1473		reply = wpas_dbus_error_invalid_args(message, op);
1474		goto out;
1475	}
1476
1477	id = strtoul(persistent_group_id, NULL, 10);
1478	if (errno == EINVAL) {
1479		reply = wpas_dbus_error_invalid_args(message, op);
1480		goto out;
1481	}
1482
1483	ssid = wpa_config_get_network(wpa_s->conf, id);
1484	if (ssid == NULL) {
1485		reply = wpas_dbus_error_persistent_group_unknown(message);
1486		goto out;
1487	}
1488
1489	wpas_notify_persistent_group_removed(wpa_s, ssid);
1490
1491	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1492		wpa_printf(MSG_ERROR, "dbus: %s: "
1493			   "error occurred when removing persistent group %d",
1494			   __func__, id);
1495		reply = wpas_dbus_error_unknown_error(
1496			message,
1497			"error removing the specified persistent group on "
1498			"this interface.");
1499		goto out;
1500	}
1501
1502out:
1503	os_free(iface);
1504	os_free(persistent_group_id);
1505	return reply;
1506}
1507
1508
1509static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1510				    struct wpa_ssid *ssid)
1511{
1512	wpas_notify_persistent_group_removed(wpa_s, ssid);
1513
1514	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1515		wpa_printf(MSG_ERROR, "dbus: %s: "
1516			   "error occurred when removing persistent group %d",
1517			   __func__, ssid->id);
1518		return;
1519	}
1520}
1521
1522
1523/**
1524 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1525 * persistent groups
1526 * @message: Pointer to incoming dbus message
1527 * @wpa_s: wpa_supplicant structure for a network interface
1528 * Returns: NULL on success or dbus error on failure
1529 *
1530 * Handler function for "RemoveAllPersistentGroups" method call of a
1531 * P2P Device interface.
1532 */
1533DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1534	DBusMessage *message, struct wpa_supplicant *wpa_s)
1535{
1536	struct wpa_ssid *ssid, *next;
1537	struct wpa_config *config;
1538
1539	config = wpa_s->conf;
1540	ssid = config->ssid;
1541	while (ssid) {
1542		next = ssid->next;
1543		if (network_is_persistent_group(ssid))
1544			remove_persistent_group(wpa_s, ssid);
1545		ssid = next;
1546	}
1547	return NULL;
1548}
1549
1550
1551/*
1552 * Group object properties accessor methods
1553 */
1554
1555DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
1556						struct wpa_supplicant * wpa_s)
1557{
1558	DBusMessage *reply = NULL;
1559	struct wpa_ssid *ssid;
1560	unsigned int num_members;
1561	char **paths;
1562	unsigned int i;
1563	void *next = NULL;
1564	const u8 *addr;
1565
1566	/* Ensure we are a GO */
1567	if (wpa_s->wpa_state != WPA_COMPLETED)
1568		goto out;
1569
1570	ssid = wpa_s->conf->ssid;
1571	/* At present WPAS P2P_GO mode only applicable for p2p_go */
1572	if (ssid->mode != WPAS_MODE_P2P_GO &&
1573	    ssid->mode != WPAS_MODE_AP &&
1574	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1575		goto out;
1576
1577	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1578
1579	paths = os_zalloc(num_members * sizeof(char *));
1580	if (!paths)
1581		goto out_of_memory;
1582
1583	i = 0;
1584	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1585		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1586		if (!paths[i])
1587			goto out_of_memory;
1588		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1589			    "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1590			    "/" COMPACT_MACSTR,
1591			    wpa_s->dbus_groupobj_path, MAC2STR(addr));
1592		i++;
1593	}
1594
1595	reply = wpas_dbus_simple_array_property_getter(message,
1596						       DBUS_TYPE_OBJECT_PATH,
1597						       paths, num_members);
1598
1599out_free:
1600	for (i = 0; i < num_members; i++)
1601		os_free(paths[i]);
1602	os_free(paths);
1603out:
1604	return reply;
1605out_of_memory:
1606	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1607	goto out_free;
1608}
1609
1610
1611DBusMessage *wpas_dbus_getter_p2p_group_properties(
1612	DBusMessage *message,
1613	struct wpa_supplicant *wpa_s)
1614{
1615	DBusMessage *reply = NULL;
1616	DBusMessageIter iter, variant_iter, dict_iter;
1617	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1618	const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1619	int num_vendor_ext = 0;
1620	int i;
1621
1622	if (!hapd) {
1623		reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1624					       NULL);
1625		return reply;
1626	}
1627
1628	if (message == NULL)
1629		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1630	else
1631		reply = dbus_message_new_method_return(message);
1632
1633	if (!reply)
1634		goto err_no_mem;
1635
1636	dbus_message_iter_init_append(reply, &iter);
1637
1638	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1639					      "a{sv}", &variant_iter) ||
1640	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1641		goto err_no_mem;
1642
1643	/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1644	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1645		if (hapd->conf->wps_vendor_ext[i] == NULL)
1646			continue;
1647		vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1648	}
1649
1650	if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1651					       "WPSVendorExtensions",
1652					       vendor_ext, num_vendor_ext))
1653		goto err_no_mem;
1654
1655	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1656	    !dbus_message_iter_close_container(&iter, &variant_iter))
1657		goto err_no_mem;
1658
1659	return reply;
1660
1661err_no_mem:
1662	dbus_message_unref(reply);
1663	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1664}
1665
1666DBusMessage *wpas_dbus_setter_p2p_group_properties(
1667	DBusMessage *message,
1668	struct wpa_supplicant *wpa_s)
1669{
1670	DBusMessage *reply = NULL;
1671	DBusMessageIter iter, variant_iter;
1672	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
1673	DBusMessageIter iter_dict;
1674	unsigned int i;
1675
1676	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1677
1678	if (!hapd)
1679		goto error;
1680
1681	dbus_message_iter_init(message, &iter);
1682
1683	dbus_message_iter_next(&iter);
1684	dbus_message_iter_next(&iter);
1685
1686	dbus_message_iter_recurse(&iter, &variant_iter);
1687
1688	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1689		return wpas_dbus_error_invalid_args(message, NULL);
1690
1691	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1692		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1693			reply = wpas_dbus_error_invalid_args(message, NULL);
1694			break;
1695		}
1696
1697		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1698			if (entry.type != DBUS_TYPE_ARRAY ||
1699			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1700			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1701				goto error;
1702
1703			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1704				if (i < entry.array_len) {
1705					hapd->conf->wps_vendor_ext[i] =
1706						entry.binarray_value[i];
1707					entry.binarray_value[i] = NULL;
1708				} else
1709					hapd->conf->wps_vendor_ext[i] = NULL;
1710			}
1711
1712			hostapd_update_wps(hapd);
1713		} else
1714			goto error;
1715
1716		wpa_dbus_dict_entry_clear(&entry);
1717	}
1718
1719	return reply;
1720
1721error:
1722	reply = wpas_dbus_error_invalid_args(message, entry.key);
1723	wpa_dbus_dict_entry_clear(&entry);
1724
1725	return reply;
1726}
1727
1728DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
1729					       struct wpa_supplicant * wpa_s)
1730{
1731	DBusMessageIter iter_dict;
1732	DBusMessage *reply = NULL;
1733	DBusMessageIter iter;
1734	struct wpa_dbus_dict_entry entry;
1735	int upnp = 0;
1736	int bonjour = 0;
1737	char *service = NULL;
1738	struct wpabuf *query = NULL;
1739	struct wpabuf *resp = NULL;
1740	u8 version = 0;
1741
1742	dbus_message_iter_init(message, &iter);
1743
1744	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1745		goto error;
1746
1747	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1748		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1749			goto error;
1750
1751		if (!strcmp(entry.key, "service_type") &&
1752		    (entry.type == DBUS_TYPE_STRING)) {
1753			if (!strcmp(entry.str_value, "upnp"))
1754				upnp = 1;
1755			else if (!strcmp(entry.str_value, "bonjour"))
1756				bonjour = 1;
1757			else
1758				goto error_clear;
1759			wpa_dbus_dict_entry_clear(&entry);
1760		}
1761	}
1762
1763	if (upnp == 1) {
1764		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1765			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1766				goto error;
1767
1768			if (!strcmp(entry.key, "version") &&
1769			    entry.type == DBUS_TYPE_INT32)
1770				version = entry.uint32_value;
1771			else if (!strcmp(entry.key, "service") &&
1772				 entry.type == DBUS_TYPE_STRING)
1773				service = os_strdup(entry.str_value);
1774			wpa_dbus_dict_entry_clear(&entry);
1775		}
1776		if (version <= 0 || service == NULL)
1777			goto error;
1778
1779		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1780			goto error;
1781
1782		os_free(service);
1783	} else if (bonjour == 1) {
1784		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1785			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1786				goto error;
1787
1788			if (!strcmp(entry.key, "query")) {
1789				if ((entry.type != DBUS_TYPE_ARRAY) ||
1790				    (entry.array_type != DBUS_TYPE_BYTE))
1791					goto error_clear;
1792				query = wpabuf_alloc_copy(entry.bytearray_value,
1793							  entry.array_len);
1794			} else if (!strcmp(entry.key, "response")) {
1795				if ((entry.type != DBUS_TYPE_ARRAY) ||
1796				    (entry.array_type != DBUS_TYPE_BYTE))
1797					goto error_clear;
1798				resp = wpabuf_alloc_copy(entry.bytearray_value,
1799							 entry.array_len);
1800			}
1801
1802			wpa_dbus_dict_entry_clear(&entry);
1803		}
1804
1805		if (query == NULL || resp == NULL)
1806			goto error;
1807
1808		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1809			wpabuf_free(query);
1810			wpabuf_free(resp);
1811			goto error;
1812		}
1813	} else
1814		goto error;
1815
1816	return reply;
1817error_clear:
1818	wpa_dbus_dict_entry_clear(&entry);
1819error:
1820	return wpas_dbus_error_invalid_args(message, NULL);
1821}
1822
1823DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
1824						  struct wpa_supplicant * wpa_s)
1825{
1826	DBusMessageIter iter_dict;
1827	DBusMessage *reply = NULL;
1828	DBusMessageIter iter;
1829	struct wpa_dbus_dict_entry entry;
1830	int upnp = 0;
1831	int bonjour = 0;
1832	int ret = 0;
1833	char *service = NULL;
1834	struct wpabuf *query = NULL;
1835	u8 version = 0;
1836
1837	dbus_message_iter_init(message, &iter);
1838
1839	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1840		goto error;
1841
1842	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1843		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1844			goto error;
1845
1846		if (!strcmp(entry.key, "service_type") &&
1847		    (entry.type == DBUS_TYPE_STRING)) {
1848			if (!strcmp(entry.str_value, "upnp"))
1849				upnp = 1;
1850			else if (!strcmp(entry.str_value, "bonjour"))
1851				bonjour = 1;
1852			else
1853				goto error_clear;
1854			wpa_dbus_dict_entry_clear(&entry);
1855		}
1856	}
1857	if (upnp == 1) {
1858		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1859			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1860				goto error;
1861			if (!strcmp(entry.key, "version") &&
1862			    entry.type == DBUS_TYPE_INT32)
1863				version = entry.uint32_value;
1864			else if (!strcmp(entry.key, "service") &&
1865				 entry.type == DBUS_TYPE_STRING)
1866				service = os_strdup(entry.str_value);
1867			else
1868				goto error_clear;
1869
1870			wpa_dbus_dict_entry_clear(&entry);
1871		}
1872
1873		if (version <= 0 || service == NULL)
1874			goto error;
1875
1876		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1877		os_free(service);
1878		if (ret != 0)
1879			goto error;
1880	} else if (bonjour == 1) {
1881		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1882			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1883				goto error;
1884
1885			if (!strcmp(entry.key, "query")) {
1886				if ((entry.type != DBUS_TYPE_ARRAY) ||
1887				    (entry.array_type != DBUS_TYPE_BYTE))
1888					goto error_clear;
1889				query = wpabuf_alloc_copy(entry.bytearray_value,
1890							  entry.array_len);
1891			} else
1892				goto error_clear;
1893
1894			wpa_dbus_dict_entry_clear(&entry);
1895		}
1896
1897		if (query == NULL)
1898			goto error;
1899
1900		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1901		if (ret != 0)
1902			goto error;
1903		wpabuf_free(query);
1904	} else
1905		goto error;
1906
1907	return reply;
1908error_clear:
1909	wpa_dbus_dict_entry_clear(&entry);
1910error:
1911	return wpas_dbus_error_invalid_args(message, NULL);
1912}
1913
1914DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
1915						 struct wpa_supplicant * wpa_s)
1916{
1917	wpas_p2p_service_flush(wpa_s);
1918	return NULL;
1919}
1920
1921DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
1922						  struct wpa_supplicant * wpa_s)
1923{
1924	DBusMessageIter iter_dict;
1925	DBusMessage *reply = NULL;
1926	DBusMessageIter iter;
1927	struct wpa_dbus_dict_entry entry;
1928	int upnp = 0;
1929	char *service = NULL;
1930	char *peer_object_path = NULL;
1931	struct wpabuf *tlv = NULL;
1932	u8 version = 0;
1933	u64 ref = 0;
1934	u8 addr[ETH_ALEN];
1935
1936	dbus_message_iter_init(message, &iter);
1937
1938	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1939		goto error;
1940
1941	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1942		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1943			goto error;
1944		if (!strcmp(entry.key, "peer_object") &&
1945		    entry.type == DBUS_TYPE_OBJECT_PATH) {
1946			peer_object_path = os_strdup(entry.str_value);
1947		} else if (!strcmp(entry.key, "service_type") &&
1948			   entry.type == DBUS_TYPE_STRING) {
1949			if (!strcmp(entry.str_value, "upnp"))
1950				upnp = 1;
1951			else
1952				goto error_clear;
1953		} else if (!strcmp(entry.key, "version") &&
1954			   entry.type == DBUS_TYPE_INT32) {
1955			version = entry.uint32_value;
1956		} else if (!strcmp(entry.key, "service") &&
1957			   entry.type == DBUS_TYPE_STRING) {
1958			service = os_strdup(entry.str_value);
1959		} else if (!strcmp(entry.key, "tlv")) {
1960			if (entry.type != DBUS_TYPE_ARRAY ||
1961			    entry.array_type != DBUS_TYPE_BYTE)
1962				goto error_clear;
1963			tlv = wpabuf_alloc_copy(entry.bytearray_value,
1964						entry.array_len);
1965		} else
1966			goto error_clear;
1967
1968		wpa_dbus_dict_entry_clear(&entry);
1969	}
1970
1971	if (!peer_object_path ||
1972	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
1973	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1974		goto error;
1975
1976	if (upnp == 1) {
1977		if (version <= 0 || service == NULL)
1978			goto error;
1979
1980		ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
1981							      version, service);
1982	} else {
1983		if (tlv == NULL)
1984			goto error;
1985		ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1986		wpabuf_free(tlv);
1987	}
1988
1989	if (ref != 0) {
1990		reply = dbus_message_new_method_return(message);
1991		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
1992					 &ref, DBUS_TYPE_INVALID);
1993	} else {
1994		reply = wpas_dbus_error_unknown_error(message,
1995				"Unable to send SD request");
1996	}
1997out:
1998	os_free(service);
1999	os_free(peer_object_path);
2000	return reply;
2001error_clear:
2002	wpa_dbus_dict_entry_clear(&entry);
2003error:
2004	if (tlv)
2005		wpabuf_free(tlv);
2006	reply = wpas_dbus_error_invalid_args(message, NULL);
2007	goto out;
2008}
2009
2010DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
2011	DBusMessage *message, struct wpa_supplicant *wpa_s)
2012{
2013	DBusMessageIter iter_dict;
2014	DBusMessage *reply = NULL;
2015	DBusMessageIter iter;
2016	struct wpa_dbus_dict_entry entry;
2017	char *peer_object_path = NULL;
2018	struct wpabuf *tlv = NULL;
2019	int freq = 0;
2020	int dlg_tok = 0;
2021	u8 addr[ETH_ALEN];
2022
2023	dbus_message_iter_init(message, &iter);
2024
2025	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
2026		goto error;
2027
2028	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2029		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2030			goto error;
2031
2032		if (!strcmp(entry.key, "peer_object") &&
2033		    entry.type == DBUS_TYPE_OBJECT_PATH) {
2034			peer_object_path = os_strdup(entry.str_value);
2035		} else if (!strcmp(entry.key, "frequency") &&
2036			   entry.type == DBUS_TYPE_INT32) {
2037			freq = entry.uint32_value;
2038		} else if (!strcmp(entry.key, "dialog_token") &&
2039			   entry.type == DBUS_TYPE_UINT32) {
2040			dlg_tok = entry.uint32_value;
2041		} else if (!strcmp(entry.key, "tlvs")) {
2042			if (entry.type != DBUS_TYPE_ARRAY ||
2043			    entry.array_type != DBUS_TYPE_BYTE)
2044				goto error_clear;
2045			tlv = wpabuf_alloc_copy(entry.bytearray_value,
2046						entry.array_len);
2047		} else
2048			goto error_clear;
2049
2050		wpa_dbus_dict_entry_clear(&entry);
2051	}
2052	if (!peer_object_path ||
2053	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
2054	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2055		goto error;
2056
2057	if (tlv == NULL)
2058		goto error;
2059
2060	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2061	wpabuf_free(tlv);
2062out:
2063	os_free(peer_object_path);
2064	return reply;
2065error_clear:
2066	wpa_dbus_dict_entry_clear(&entry);
2067error:
2068	reply = wpas_dbus_error_invalid_args(message, NULL);
2069	goto out;
2070}
2071
2072DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
2073							 *wpa_s)
2074{
2075	DBusMessageIter iter;
2076	u64 req = 0;
2077
2078	dbus_message_iter_init(message, &iter);
2079	dbus_message_iter_get_basic(&iter, &req);
2080
2081	if (req == 0)
2082		goto error;
2083
2084	if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
2085		goto error;
2086
2087	return NULL;
2088error:
2089	return wpas_dbus_error_invalid_args(message, NULL);
2090}
2091
2092DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
2093						  struct wpa_supplicant * wpa_s)
2094{
2095	wpas_p2p_sd_service_update(wpa_s);
2096	return NULL;
2097}
2098
2099DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
2100						      struct wpa_supplicant *
2101						      wpa_s)
2102{
2103	DBusMessageIter iter;
2104	int ext = 0;
2105
2106	dbus_message_iter_init(message, &iter);
2107	dbus_message_iter_get_basic(&iter, &ext);
2108
2109	wpa_s->p2p_sd_over_ctrl_iface = ext;
2110
2111	return NULL;
2112
2113}
2114