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	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
664		iter_secdev_dict_array;
665	const char *dev_name;
666	int num_vendor_extensions = 0;
667	int i;
668	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
669
670	if (message == NULL)
671		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
672	else
673		reply = dbus_message_new_method_return(message);
674
675	if (!reply)
676		goto err_no_mem;
677
678	dbus_message_iter_init_append(reply, &iter);
679
680	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
681					      "a{sv}", &variant_iter) ||
682	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
683		goto err_no_mem;
684
685	/* DeviceName */
686	dev_name = wpa_s->conf->device_name;
687	if (dev_name &&
688	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
689		goto err_no_mem;
690
691	/* Primary device type */
692	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
693	    				     (char *)wpa_s->conf->device_type,
694	    				     WPS_DEV_TYPE_LEN))
695		goto err_no_mem;
696
697	/* Secondary device types */
698	if (wpa_s->conf->num_sec_device_types) {
699		if (!wpa_dbus_dict_begin_array(&dict_iter,
700					       "SecondaryDeviceTypes",
701					       DBUS_TYPE_ARRAY_AS_STRING
702					       DBUS_TYPE_BYTE_AS_STRING,
703					       &iter_secdev_dict_entry,
704					       &iter_secdev_dict_val,
705					       &iter_secdev_dict_array))
706			goto err_no_mem;
707
708		for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
709			wpa_dbus_dict_bin_array_add_element(
710				&iter_secdev_dict_array,
711				wpa_s->conf->sec_device_type[i],
712				WPS_DEV_TYPE_LEN);
713
714		if (!wpa_dbus_dict_end_array(&dict_iter,
715					     &iter_secdev_dict_entry,
716					     &iter_secdev_dict_val,
717					     &iter_secdev_dict_array))
718			goto err_no_mem;
719	}
720
721	/* Vendor Extensions */
722	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
723		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
724			continue;
725		vendor_ext[num_vendor_extensions++] =
726			wpa_s->conf->wps_vendor_ext[i];
727	}
728
729	if (num_vendor_extensions &&
730	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
731					       "VendorExtension",
732					       vendor_ext,
733					       num_vendor_extensions))
734		goto err_no_mem;
735
736	/* GO Intent */
737	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
738					 wpa_s->conf->p2p_go_intent))
739		goto err_no_mem;
740
741	/* Persistant Reconnect */
742	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
743				       wpa_s->conf->persistent_reconnect))
744		goto err_no_mem;
745
746	/* Listen Reg Class */
747	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
748					 wpa_s->conf->p2p_listen_reg_class))
749		goto err_no_mem;
750
751	/* Listen Channel */
752	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
753					 wpa_s->conf->p2p_listen_channel))
754		goto err_no_mem;
755
756	/* Oper Reg Class */
757	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
758					 wpa_s->conf->p2p_oper_reg_class))
759		goto err_no_mem;
760
761	/* Oper Channel */
762	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
763					 wpa_s->conf->p2p_oper_channel))
764		goto err_no_mem;
765
766	/* SSID Postfix */
767	if (wpa_s->conf->p2p_ssid_postfix &&
768	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
769					 wpa_s->conf->p2p_ssid_postfix))
770		goto err_no_mem;
771
772	/* Intra Bss */
773	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
774				       wpa_s->conf->p2p_intra_bss))
775		goto err_no_mem;
776
777	/* Group Idle */
778	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
779					 wpa_s->conf->p2p_group_idle))
780		goto err_no_mem;
781
782	/* Dissasociation low ack */
783	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
784					 wpa_s->conf->disassoc_low_ack))
785		goto err_no_mem;
786
787	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
788	    !dbus_message_iter_close_container(&iter, &variant_iter))
789		goto err_no_mem;
790
791	return reply;
792err_no_mem:
793	dbus_message_unref(reply);
794	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
795}
796
797DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
798						    struct wpa_supplicant *
799						    wpa_s)
800{
801	DBusMessage *reply = NULL;
802	DBusMessageIter iter, variant_iter;
803	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
804	DBusMessageIter iter_dict;
805	unsigned int i;
806
807	dbus_message_iter_init(message, &iter);
808
809	dbus_message_iter_next(&iter);
810	dbus_message_iter_next(&iter);
811
812	dbus_message_iter_recurse(&iter, &variant_iter);
813
814	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
815		return wpas_dbus_error_invalid_args(message, NULL);
816
817	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
818		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
819			return wpas_dbus_error_invalid_args(message, NULL);
820
821		if (os_strcmp(entry.key, "DeviceName") == 0) {
822			char *devname;
823
824			if (entry.type != DBUS_TYPE_STRING)
825				goto error_clear;
826
827			devname = os_strdup(entry.str_value);
828			if (devname == NULL)
829				goto err_no_mem_clear;
830
831			os_free(wpa_s->conf->device_name);
832			wpa_s->conf->device_name = devname;
833
834			wpa_s->conf->changed_parameters |=
835							CFG_CHANGED_DEVICE_NAME;
836		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
837			if (entry.type != DBUS_TYPE_ARRAY ||
838			    entry.array_type != DBUS_TYPE_BYTE ||
839			    entry.array_len != WPS_DEV_TYPE_LEN)
840				goto error_clear;
841
842			os_memcpy(wpa_s->conf->device_type,
843				  entry.bytearray_value,
844				  WPS_DEV_TYPE_LEN);
845			wpa_s->conf->changed_parameters |=
846				CFG_CHANGED_DEVICE_TYPE;
847		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
848			if (entry.type != DBUS_TYPE_ARRAY ||
849			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
850			    entry.array_len > MAX_SEC_DEVICE_TYPES)
851				goto error;
852
853			for (i = 0; i < entry.array_len; i++)
854				if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
855					goto err_no_mem_clear;
856			for (i = 0; i < entry.array_len; i++)
857				os_memcpy(wpa_s->conf->sec_device_type[i],
858					  wpabuf_head(entry.binarray_value[i]),
859					  WPS_DEV_TYPE_LEN);
860			wpa_s->conf->num_sec_device_types = entry.array_len;
861			wpa_s->conf->changed_parameters |=
862					CFG_CHANGED_SEC_DEVICE_TYPE;
863		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
864			if ((entry.type != DBUS_TYPE_ARRAY) ||
865			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
866			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
867				goto error_clear;
868
869			wpa_s->conf->changed_parameters |=
870					CFG_CHANGED_VENDOR_EXTENSION;
871
872			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
873				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
874				if (i < entry.array_len) {
875					wpa_s->conf->wps_vendor_ext[i] =
876						entry.binarray_value[i];
877					entry.binarray_value[i] = NULL;
878				} else
879					wpa_s->conf->wps_vendor_ext[i] = NULL;
880			}
881		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
882			   (entry.type == DBUS_TYPE_UINT32) &&
883			   (entry.uint32_value <= 15))
884			wpa_s->conf->p2p_go_intent = entry.uint32_value;
885
886		else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
887			 (entry.type == DBUS_TYPE_BOOLEAN))
888			wpa_s->conf->persistent_reconnect = entry.bool_value;
889
890		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
891			 (entry.type == DBUS_TYPE_UINT32)) {
892			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
893			wpa_s->conf->changed_parameters |=
894				CFG_CHANGED_P2P_LISTEN_CHANNEL;
895		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
896			   (entry.type == DBUS_TYPE_UINT32)) {
897			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
898			wpa_s->conf->changed_parameters |=
899				CFG_CHANGED_P2P_LISTEN_CHANNEL;
900		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
901			   (entry.type == DBUS_TYPE_UINT32)) {
902			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
903			wpa_s->conf->changed_parameters |=
904				CFG_CHANGED_P2P_OPER_CHANNEL;
905		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
906			   (entry.type == DBUS_TYPE_UINT32)) {
907			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
908			wpa_s->conf->changed_parameters |=
909				CFG_CHANGED_P2P_OPER_CHANNEL;
910		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
911			char *postfix;
912
913			if (entry.type != DBUS_TYPE_STRING)
914				goto error_clear;
915
916			postfix = os_strdup(entry.str_value);
917			if (!postfix)
918				goto err_no_mem_clear;
919
920			os_free(wpa_s->conf->p2p_ssid_postfix);
921			wpa_s->conf->p2p_ssid_postfix = postfix;
922
923			wpa_s->conf->changed_parameters |=
924					CFG_CHANGED_P2P_SSID_POSTFIX;
925		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
926			   (entry.type == DBUS_TYPE_BOOLEAN)) {
927			wpa_s->conf->p2p_intra_bss = entry.bool_value;
928			wpa_s->conf->changed_parameters |=
929						      CFG_CHANGED_P2P_INTRA_BSS;
930		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
931			   (entry.type == DBUS_TYPE_UINT32))
932			wpa_s->conf->p2p_group_idle = entry.uint32_value;
933		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
934			 entry.type == DBUS_TYPE_UINT32)
935			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
936		else
937			goto error_clear;
938
939		wpa_dbus_dict_entry_clear(&entry);
940	}
941
942	if (wpa_s->conf->changed_parameters) {
943		/* Some changed parameters requires to update config*/
944		wpa_supplicant_update_config(wpa_s);
945	}
946
947	return reply;
948
949 error_clear:
950	wpa_dbus_dict_entry_clear(&entry);
951 error:
952	reply = wpas_dbus_error_invalid_args(message, entry.key);
953	wpa_dbus_dict_entry_clear(&entry);
954
955	return reply;
956 err_no_mem_clear:
957	wpa_dbus_dict_entry_clear(&entry);
958	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
959}
960
961DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
962					struct wpa_supplicant * wpa_s)
963{
964	DBusMessage *reply = NULL;
965	struct p2p_data *p2p = wpa_s->global->p2p;
966	int next = 0, i = 0;
967	int num = 0, out_of_mem = 0;
968	const u8 *addr;
969	const struct p2p_peer_info *peer_info = NULL;
970
971	struct dl_list peer_objpath_list;
972	struct peer_objpath_node {
973		struct dl_list list;
974		char path[WPAS_DBUS_OBJECT_PATH_MAX];
975	} *node, *tmp;
976
977	char **peer_obj_paths = NULL;
978
979	dl_list_init(&peer_objpath_list);
980
981	/* Get the first peer info */
982	peer_info = p2p_get_peer_found(p2p, NULL, next);
983
984	/* Get next and accumulate them */
985	next = 1;
986	while (peer_info != NULL) {
987		node = os_zalloc(sizeof(struct peer_objpath_node));
988		if (!node) {
989			out_of_mem = 1;
990			goto error;
991		}
992
993		addr = peer_info->p2p_device_addr;
994		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
995			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
996			    "/" COMPACT_MACSTR,
997			    wpa_s->dbus_new_path, MAC2STR(addr));
998		dl_list_add_tail(&peer_objpath_list, &node->list);
999		num++;
1000
1001		peer_info = p2p_get_peer_found(p2p, addr, next);
1002	}
1003
1004	/*
1005	 * Now construct the peer object paths in a form suitable for
1006	 * array_property_getter helper below.
1007	 */
1008	peer_obj_paths = os_zalloc(num * sizeof(char *));
1009
1010	if (!peer_obj_paths) {
1011		out_of_mem = 1;
1012		goto error;
1013	}
1014
1015	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1016			      struct peer_objpath_node, list)
1017		peer_obj_paths[i++] = node->path;
1018
1019	reply = wpas_dbus_simple_array_property_getter(message,
1020						       DBUS_TYPE_OBJECT_PATH,
1021						       peer_obj_paths, num);
1022
1023error:
1024	if (peer_obj_paths)
1025		os_free(peer_obj_paths);
1026
1027	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1028			      struct peer_objpath_node, list) {
1029		dl_list_del(&node->list);
1030		os_free(node);
1031	}
1032	if (out_of_mem)
1033		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1034					       NULL);
1035
1036	return reply;
1037}
1038
1039enum wpas_p2p_role {
1040	WPAS_P2P_ROLE_DEVICE,
1041	WPAS_P2P_ROLE_GO,
1042	WPAS_P2P_ROLE_CLIENT,
1043};
1044
1045static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1046{
1047	struct wpa_ssid *ssid = wpa_s->current_ssid;
1048
1049	if (!ssid)
1050		return WPAS_P2P_ROLE_DEVICE;
1051	if (wpa_s->wpa_state != WPA_COMPLETED)
1052		return WPAS_P2P_ROLE_DEVICE;
1053
1054	switch (ssid->mode) {
1055	case WPAS_MODE_P2P_GO:
1056	case WPAS_MODE_P2P_GROUP_FORMATION:
1057		return WPAS_P2P_ROLE_GO;
1058	case WPAS_MODE_INFRA:
1059		if (ssid->p2p_group)
1060			return WPAS_P2P_ROLE_CLIENT;
1061		return WPAS_P2P_ROLE_DEVICE;
1062	default:
1063		return WPAS_P2P_ROLE_DEVICE;
1064	}
1065}
1066
1067DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
1068				       struct wpa_supplicant * wpa_s)
1069{
1070	char *str;
1071
1072	switch (wpas_get_p2p_role(wpa_s)) {
1073	case WPAS_P2P_ROLE_GO:
1074		str = "GO";
1075		break;
1076	case WPAS_P2P_ROLE_CLIENT:
1077		str = "client";
1078		break;
1079	default:
1080		str = "device";
1081	}
1082
1083	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1084						&str);
1085}
1086
1087DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
1088					struct wpa_supplicant * wpa_s)
1089{
1090	if (wpa_s->dbus_groupobj_path == NULL)
1091		return NULL;
1092
1093	return wpas_dbus_simple_property_getter(message,
1094						DBUS_TYPE_OBJECT_PATH,
1095						&wpa_s->dbus_groupobj_path);
1096}
1097
1098DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
1099					 struct wpa_supplicant * wpa_s)
1100{
1101	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1102
1103	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1104		return NULL;
1105
1106	os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1107		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1108		    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1109	path = go_peer_obj_path;
1110	return wpas_dbus_simple_property_getter(message,
1111						DBUS_TYPE_OBJECT_PATH, &path);
1112}
1113
1114/*
1115 * Peer object properties accessor methods
1116 */
1117
1118DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
1119						  struct peer_handler_args *
1120						  peer_args)
1121{
1122	DBusMessage *reply = NULL;
1123	DBusMessageIter iter, variant_iter, dict_iter;
1124	const struct p2p_peer_info *info = NULL;
1125	char devtype[WPS_DEV_TYPE_BUFSIZE];
1126
1127	/* get the peer info */
1128	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1129				  peer_args->p2p_device_addr, 0);
1130	if (info == NULL)
1131		return NULL;
1132
1133	if (message == NULL)
1134		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1135	else
1136		reply = dbus_message_new_method_return(message);
1137
1138	if (!reply)
1139		goto err_no_mem;
1140
1141	dbus_message_iter_init_append(reply, &iter);
1142	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1143					      "a{sv}", &variant_iter) ||
1144	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1145		goto err_no_mem;
1146
1147	/* Fill out the dictionary */
1148	wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1149	if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1150					 info->device_name))
1151		goto err_no_mem;
1152	if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1153					 devtype))
1154		goto err_no_mem;
1155	if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1156					 info->config_methods))
1157		goto err_no_mem;
1158	if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1159					 info->level))
1160		goto err_no_mem;
1161	if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1162				       info->dev_capab))
1163		goto err_no_mem;
1164	if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1165				       info->group_capab))
1166		goto err_no_mem;
1167
1168	if (info->wps_sec_dev_type_list_len) {
1169		char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1170		u8 *sec_dev_type_list = NULL;
1171		char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1172		int num_sec_dev_types = 0;
1173		int i;
1174
1175		sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1176
1177		if (sec_dev_type_list == NULL)
1178			goto err_no_mem;
1179
1180		os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1181			  info->wps_sec_dev_type_list_len);
1182
1183		for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1184		       i < (int) (info->wps_sec_dev_type_list_len /
1185				  WPS_DEV_TYPE_LEN);
1186		     i++) {
1187			sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1188
1189			if (!sec_dev_types[i] ||
1190			    wps_dev_type_bin2str(
1191					&sec_dev_type_list[i *
1192							   WPS_DEV_TYPE_LEN],
1193					sec_dev_types[i],
1194					sizeof(secdevtype)) == NULL) {
1195				while (--i >= 0)
1196					os_free(sec_dev_types[i]);
1197				os_free(sec_dev_type_list);
1198				goto err_no_mem;
1199			}
1200
1201			num_sec_dev_types++;
1202		}
1203
1204		os_free(sec_dev_type_list);
1205
1206		if (num_sec_dev_types) {
1207			if (!wpa_dbus_dict_append_string_array(&dict_iter,
1208						"SecondaryDeviceTypes",
1209						(const char **)sec_dev_types,
1210						num_sec_dev_types)) {
1211				for (i = 0; i < num_sec_dev_types; i++)
1212					os_free(sec_dev_types[i]);
1213				goto err_no_mem;
1214			}
1215
1216			for (i = 0; i < num_sec_dev_types; i++)
1217				os_free(sec_dev_types[i]);
1218		}
1219	}
1220
1221	{
1222		/* Add WPS vendor extensions attribute */
1223		const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1224		int i, num = 0;
1225
1226		for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1227			if (info->wps_vendor_ext[i] == NULL)
1228				continue;
1229			vendor_extension[num] = info->wps_vendor_ext[i];
1230			num++;
1231		}
1232
1233		if (!wpa_dbus_dict_append_wpabuf_array(
1234					&dict_iter, "VendorExtension",
1235					vendor_extension, num))
1236			goto err_no_mem;
1237	}
1238
1239	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1240	    !dbus_message_iter_close_container(&iter, &variant_iter))
1241		goto err_no_mem;
1242
1243	return reply;
1244err_no_mem:
1245	dbus_message_unref(reply);
1246	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1247}
1248
1249DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
1250					   struct peer_handler_args * peer_args)
1251{
1252	return NULL;
1253}
1254
1255
1256/**
1257 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1258 * @message: Pointer to incoming dbus message
1259 * @wpa_s: wpa_supplicant structure for a network interface
1260 * Returns: a dbus message containing an array of all persistent group
1261 * dbus object paths.
1262 *
1263 * Getter for "Networks" property.
1264 */
1265DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
1266						 struct wpa_supplicant *wpa_s)
1267{
1268	DBusMessage *reply = NULL;
1269	struct wpa_ssid *ssid;
1270	char **paths;
1271	unsigned int i = 0, num = 0;
1272
1273	if (wpa_s->conf == NULL) {
1274		wpa_printf(MSG_ERROR, "dbus: %s: "
1275			   "An error occurred getting persistent groups list",
1276			   __func__);
1277		return wpas_dbus_error_unknown_error(message, NULL);
1278	}
1279
1280	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1281		if (network_is_persistent_group(ssid))
1282			num++;
1283
1284	paths = os_zalloc(num * sizeof(char *));
1285	if (!paths) {
1286		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1287					      NULL);
1288	}
1289
1290	/* Loop through configured networks and append object path of each */
1291	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1292		if (!network_is_persistent_group(ssid))
1293			continue;
1294		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1295		if (paths[i] == NULL) {
1296			reply = dbus_message_new_error(message,
1297						       DBUS_ERROR_NO_MEMORY,
1298						       NULL);
1299			goto out;
1300		}
1301		/* Construct the object path for this network. */
1302		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1303			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1304			    wpa_s->dbus_new_path, ssid->id);
1305	}
1306
1307	reply = wpas_dbus_simple_array_property_getter(message,
1308						       DBUS_TYPE_OBJECT_PATH,
1309						       paths, num);
1310
1311out:
1312	while (i)
1313		os_free(paths[--i]);
1314	os_free(paths);
1315	return reply;
1316}
1317
1318
1319/**
1320 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1321 *	group
1322 * @message: Pointer to incoming dbus message
1323 * @net: wpa_supplicant structure for a network interface and
1324 * wpa_ssid structure for a configured persistent group (internally network)
1325 * Returns: DBus message with network properties or DBus error on failure
1326 *
1327 * Getter for "Properties" property of a persistent group.
1328 */
1329DBusMessage * wpas_dbus_getter_persistent_group_properties(
1330	DBusMessage *message, struct network_handler_args *net)
1331{
1332	/*
1333	 * Leveraging the fact that persistent group object is still
1334	 * represented in same manner as network within.
1335	 */
1336	return wpas_dbus_getter_network_properties(message, net);
1337}
1338
1339
1340/**
1341 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1342 *	group
1343 * @message: Pointer to incoming dbus message
1344 * @net: wpa_supplicant structure for a network interface and
1345 * wpa_ssid structure for a configured persistent group (internally network)
1346 * Returns: DBus message with network properties or DBus error on failure
1347 *
1348 * Setter for "Properties" property of a persistent group.
1349 */
1350DBusMessage * wpas_dbus_setter_persistent_group_properties(
1351	DBusMessage *message, struct network_handler_args *net)
1352{
1353	struct wpa_ssid *ssid = net->ssid;
1354	DBusMessage *reply = NULL;
1355	DBusMessageIter	iter, variant_iter;
1356
1357	dbus_message_iter_init(message, &iter);
1358
1359	dbus_message_iter_next(&iter);
1360	dbus_message_iter_next(&iter);
1361
1362	dbus_message_iter_recurse(&iter, &variant_iter);
1363
1364	/*
1365	 * Leveraging the fact that persistent group object is still
1366	 * represented in same manner as network within.
1367	 */
1368	reply = set_network_properties(message, net->wpa_s, ssid,
1369				       &variant_iter);
1370	if (reply)
1371		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
1372			   "persistent group properties");
1373
1374	return reply;
1375}
1376
1377
1378/**
1379 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1380 *	persistent_group
1381 * @message: Pointer to incoming dbus message
1382 * @wpa_s: wpa_supplicant structure for a network interface
1383 * Returns: A dbus message containing the object path of the new
1384 * persistent group
1385 *
1386 * Handler function for "AddPersistentGroup" method call of a P2P Device
1387 * interface.
1388 */
1389DBusMessage * wpas_dbus_handler_add_persistent_group(
1390	DBusMessage *message, struct wpa_supplicant *wpa_s)
1391{
1392	DBusMessage *reply = NULL;
1393	DBusMessageIter	iter;
1394	struct wpa_ssid *ssid = NULL;
1395	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1396
1397	dbus_message_iter_init(message, &iter);
1398
1399	ssid = wpa_config_add_network(wpa_s->conf);
1400	if (ssid == NULL) {
1401		wpa_printf(MSG_ERROR, "dbus: %s: "
1402			   "Cannot add new persistent group", __func__);
1403		reply = wpas_dbus_error_unknown_error(
1404			message,
1405			"wpa_supplicant could not add "
1406			"a persistent group on this interface.");
1407		goto err;
1408	}
1409
1410	/* Mark the ssid as being a persistent group before the notification */
1411	ssid->disabled = 2;
1412	ssid->p2p_persistent_group = 1;
1413	wpas_notify_persistent_group_added(wpa_s, ssid);
1414
1415	wpa_config_set_network_defaults(ssid);
1416
1417	reply = set_network_properties(message, wpa_s, ssid, &iter);
1418	if (reply) {
1419		wpa_printf(MSG_DEBUG, "dbus: %s: "
1420			   "Control interface could not set persistent group "
1421			   "properties", __func__);
1422		goto err;
1423	}
1424
1425	/* Construct the object path for this network. */
1426	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1427		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1428		    wpa_s->dbus_new_path, ssid->id);
1429
1430	reply = dbus_message_new_method_return(message);
1431	if (reply == NULL) {
1432		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1433					       NULL);
1434		goto err;
1435	}
1436	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1437				      DBUS_TYPE_INVALID)) {
1438		dbus_message_unref(reply);
1439		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1440					       NULL);
1441		goto err;
1442	}
1443
1444	return reply;
1445
1446err:
1447	if (ssid) {
1448		wpas_notify_persistent_group_removed(wpa_s, ssid);
1449		wpa_config_remove_network(wpa_s->conf, ssid->id);
1450	}
1451	return reply;
1452}
1453
1454
1455/**
1456 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1457 *	group
1458 * @message: Pointer to incoming dbus message
1459 * @wpa_s: wpa_supplicant structure for a network interface
1460 * Returns: NULL on success or dbus error on failure
1461 *
1462 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1463 * interface.
1464 */
1465DBusMessage * wpas_dbus_handler_remove_persistent_group(
1466	DBusMessage *message, struct wpa_supplicant *wpa_s)
1467{
1468	DBusMessage *reply = NULL;
1469	const char *op;
1470	char *iface = NULL, *persistent_group_id = NULL;
1471	int id;
1472	struct wpa_ssid *ssid;
1473
1474	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1475			      DBUS_TYPE_INVALID);
1476
1477	/*
1478	 * Extract the network ID and ensure the network is actually a child of
1479	 * this interface.
1480	 */
1481	iface = wpas_dbus_new_decompose_object_path(op, 1,
1482						    &persistent_group_id,
1483						    NULL);
1484	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1485		reply = wpas_dbus_error_invalid_args(message, op);
1486		goto out;
1487	}
1488
1489	id = strtoul(persistent_group_id, NULL, 10);
1490	if (errno == EINVAL) {
1491		reply = wpas_dbus_error_invalid_args(message, op);
1492		goto out;
1493	}
1494
1495	ssid = wpa_config_get_network(wpa_s->conf, id);
1496	if (ssid == NULL) {
1497		reply = wpas_dbus_error_persistent_group_unknown(message);
1498		goto out;
1499	}
1500
1501	wpas_notify_persistent_group_removed(wpa_s, ssid);
1502
1503	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1504		wpa_printf(MSG_ERROR, "dbus: %s: "
1505			   "error occurred when removing persistent group %d",
1506			   __func__, id);
1507		reply = wpas_dbus_error_unknown_error(
1508			message,
1509			"error removing the specified persistent group on "
1510			"this interface.");
1511		goto out;
1512	}
1513
1514out:
1515	os_free(iface);
1516	os_free(persistent_group_id);
1517	return reply;
1518}
1519
1520
1521static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1522				    struct wpa_ssid *ssid)
1523{
1524	wpas_notify_persistent_group_removed(wpa_s, ssid);
1525
1526	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1527		wpa_printf(MSG_ERROR, "dbus: %s: "
1528			   "error occurred when removing persistent group %d",
1529			   __func__, ssid->id);
1530		return;
1531	}
1532}
1533
1534
1535/**
1536 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1537 * persistent groups
1538 * @message: Pointer to incoming dbus message
1539 * @wpa_s: wpa_supplicant structure for a network interface
1540 * Returns: NULL on success or dbus error on failure
1541 *
1542 * Handler function for "RemoveAllPersistentGroups" method call of a
1543 * P2P Device interface.
1544 */
1545DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1546	DBusMessage *message, struct wpa_supplicant *wpa_s)
1547{
1548	struct wpa_ssid *ssid, *next;
1549	struct wpa_config *config;
1550
1551	config = wpa_s->conf;
1552	ssid = config->ssid;
1553	while (ssid) {
1554		next = ssid->next;
1555		if (network_is_persistent_group(ssid))
1556			remove_persistent_group(wpa_s, ssid);
1557		ssid = next;
1558	}
1559	return NULL;
1560}
1561
1562
1563/*
1564 * Group object properties accessor methods
1565 */
1566
1567DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
1568						struct wpa_supplicant * wpa_s)
1569{
1570	DBusMessage *reply = NULL;
1571	struct wpa_ssid *ssid;
1572	unsigned int num_members;
1573	char **paths;
1574	unsigned int i;
1575	void *next = NULL;
1576	const u8 *addr;
1577
1578	/* Ensure we are a GO */
1579	if (wpa_s->wpa_state != WPA_COMPLETED)
1580		goto out;
1581
1582	ssid = wpa_s->conf->ssid;
1583	/* At present WPAS P2P_GO mode only applicable for p2p_go */
1584	if (ssid->mode != WPAS_MODE_P2P_GO &&
1585	    ssid->mode != WPAS_MODE_AP &&
1586	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1587		goto out;
1588
1589	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1590
1591	paths = os_zalloc(num_members * sizeof(char *));
1592	if (!paths)
1593		goto out_of_memory;
1594
1595	i = 0;
1596	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1597		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1598		if (!paths[i])
1599			goto out_of_memory;
1600		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1601			    "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1602			    "/" COMPACT_MACSTR,
1603			    wpa_s->dbus_groupobj_path, MAC2STR(addr));
1604		i++;
1605	}
1606
1607	reply = wpas_dbus_simple_array_property_getter(message,
1608						       DBUS_TYPE_OBJECT_PATH,
1609						       paths, num_members);
1610
1611out_free:
1612	for (i = 0; i < num_members; i++)
1613		os_free(paths[i]);
1614	os_free(paths);
1615out:
1616	return reply;
1617out_of_memory:
1618	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1619	goto out_free;
1620}
1621
1622
1623DBusMessage *wpas_dbus_getter_p2p_group_properties(
1624	DBusMessage *message,
1625	struct wpa_supplicant *wpa_s)
1626{
1627	DBusMessage *reply = NULL;
1628	DBusMessageIter iter, variant_iter, dict_iter;
1629	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1630	const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1631	int num_vendor_ext = 0;
1632	int i;
1633
1634	if (!hapd) {
1635		reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1636					       NULL);
1637		return reply;
1638	}
1639
1640	if (message == NULL)
1641		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1642	else
1643		reply = dbus_message_new_method_return(message);
1644
1645	if (!reply)
1646		goto err_no_mem;
1647
1648	dbus_message_iter_init_append(reply, &iter);
1649
1650	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1651					      "a{sv}", &variant_iter) ||
1652	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1653		goto err_no_mem;
1654
1655	/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1656	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1657		if (hapd->conf->wps_vendor_ext[i] == NULL)
1658			continue;
1659		vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1660	}
1661
1662	if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1663					       "WPSVendorExtensions",
1664					       vendor_ext, num_vendor_ext))
1665		goto err_no_mem;
1666
1667	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1668	    !dbus_message_iter_close_container(&iter, &variant_iter))
1669		goto err_no_mem;
1670
1671	return reply;
1672
1673err_no_mem:
1674	dbus_message_unref(reply);
1675	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1676}
1677
1678DBusMessage *wpas_dbus_setter_p2p_group_properties(
1679	DBusMessage *message,
1680	struct wpa_supplicant *wpa_s)
1681{
1682	DBusMessage *reply = NULL;
1683	DBusMessageIter iter, variant_iter;
1684	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
1685	DBusMessageIter iter_dict;
1686	unsigned int i;
1687
1688	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1689
1690	if (!hapd)
1691		goto error;
1692
1693	dbus_message_iter_init(message, &iter);
1694
1695	dbus_message_iter_next(&iter);
1696	dbus_message_iter_next(&iter);
1697
1698	dbus_message_iter_recurse(&iter, &variant_iter);
1699
1700	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1701		return wpas_dbus_error_invalid_args(message, NULL);
1702
1703	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1704		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1705			reply = wpas_dbus_error_invalid_args(message, NULL);
1706			break;
1707		}
1708
1709		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1710			if (entry.type != DBUS_TYPE_ARRAY ||
1711			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1712			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1713				goto error;
1714
1715			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1716				if (i < entry.array_len) {
1717					hapd->conf->wps_vendor_ext[i] =
1718						entry.binarray_value[i];
1719					entry.binarray_value[i] = NULL;
1720				} else
1721					hapd->conf->wps_vendor_ext[i] = NULL;
1722			}
1723
1724			hostapd_update_wps(hapd);
1725		} else
1726			goto error;
1727
1728		wpa_dbus_dict_entry_clear(&entry);
1729	}
1730
1731	return reply;
1732
1733error:
1734	reply = wpas_dbus_error_invalid_args(message, entry.key);
1735	wpa_dbus_dict_entry_clear(&entry);
1736
1737	return reply;
1738}
1739
1740DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
1741					       struct wpa_supplicant * wpa_s)
1742{
1743	DBusMessageIter iter_dict;
1744	DBusMessage *reply = NULL;
1745	DBusMessageIter iter;
1746	struct wpa_dbus_dict_entry entry;
1747	int upnp = 0;
1748	int bonjour = 0;
1749	char *service = NULL;
1750	struct wpabuf *query = NULL;
1751	struct wpabuf *resp = NULL;
1752	u8 version = 0;
1753
1754	dbus_message_iter_init(message, &iter);
1755
1756	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1757		goto error;
1758
1759	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1760		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1761			goto error;
1762
1763		if (!strcmp(entry.key, "service_type") &&
1764		    (entry.type == DBUS_TYPE_STRING)) {
1765			if (!strcmp(entry.str_value, "upnp"))
1766				upnp = 1;
1767			else if (!strcmp(entry.str_value, "bonjour"))
1768				bonjour = 1;
1769			else
1770				goto error_clear;
1771			wpa_dbus_dict_entry_clear(&entry);
1772		}
1773	}
1774
1775	if (upnp == 1) {
1776		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1777			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1778				goto error;
1779
1780			if (!strcmp(entry.key, "version") &&
1781			    entry.type == DBUS_TYPE_INT32)
1782				version = entry.uint32_value;
1783			else if (!strcmp(entry.key, "service") &&
1784				 entry.type == DBUS_TYPE_STRING)
1785				service = os_strdup(entry.str_value);
1786			wpa_dbus_dict_entry_clear(&entry);
1787		}
1788		if (version <= 0 || service == NULL)
1789			goto error;
1790
1791		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1792			goto error;
1793
1794		os_free(service);
1795	} else if (bonjour == 1) {
1796		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1797			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1798				goto error;
1799
1800			if (!strcmp(entry.key, "query")) {
1801				if ((entry.type != DBUS_TYPE_ARRAY) ||
1802				    (entry.array_type != DBUS_TYPE_BYTE))
1803					goto error_clear;
1804				query = wpabuf_alloc_copy(entry.bytearray_value,
1805							  entry.array_len);
1806			} else if (!strcmp(entry.key, "response")) {
1807				if ((entry.type != DBUS_TYPE_ARRAY) ||
1808				    (entry.array_type != DBUS_TYPE_BYTE))
1809					goto error_clear;
1810				resp = wpabuf_alloc_copy(entry.bytearray_value,
1811							 entry.array_len);
1812			}
1813
1814			wpa_dbus_dict_entry_clear(&entry);
1815		}
1816
1817		if (query == NULL || resp == NULL)
1818			goto error;
1819
1820		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1821			wpabuf_free(query);
1822			wpabuf_free(resp);
1823			goto error;
1824		}
1825	} else
1826		goto error;
1827
1828	return reply;
1829error_clear:
1830	wpa_dbus_dict_entry_clear(&entry);
1831error:
1832	return wpas_dbus_error_invalid_args(message, NULL);
1833}
1834
1835DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
1836						  struct wpa_supplicant * wpa_s)
1837{
1838	DBusMessageIter iter_dict;
1839	DBusMessage *reply = NULL;
1840	DBusMessageIter iter;
1841	struct wpa_dbus_dict_entry entry;
1842	int upnp = 0;
1843	int bonjour = 0;
1844	int ret = 0;
1845	char *service = NULL;
1846	struct wpabuf *query = NULL;
1847	u8 version = 0;
1848
1849	dbus_message_iter_init(message, &iter);
1850
1851	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1852		goto error;
1853
1854	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1855		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1856			goto error;
1857
1858		if (!strcmp(entry.key, "service_type") &&
1859		    (entry.type == DBUS_TYPE_STRING)) {
1860			if (!strcmp(entry.str_value, "upnp"))
1861				upnp = 1;
1862			else if (!strcmp(entry.str_value, "bonjour"))
1863				bonjour = 1;
1864			else
1865				goto error_clear;
1866			wpa_dbus_dict_entry_clear(&entry);
1867		}
1868	}
1869	if (upnp == 1) {
1870		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1871			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1872				goto error;
1873			if (!strcmp(entry.key, "version") &&
1874			    entry.type == DBUS_TYPE_INT32)
1875				version = entry.uint32_value;
1876			else if (!strcmp(entry.key, "service") &&
1877				 entry.type == DBUS_TYPE_STRING)
1878				service = os_strdup(entry.str_value);
1879			else
1880				goto error_clear;
1881
1882			wpa_dbus_dict_entry_clear(&entry);
1883		}
1884
1885		if (version <= 0 || service == NULL)
1886			goto error;
1887
1888		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1889		os_free(service);
1890		if (ret != 0)
1891			goto error;
1892	} else if (bonjour == 1) {
1893		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1894			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1895				goto error;
1896
1897			if (!strcmp(entry.key, "query")) {
1898				if ((entry.type != DBUS_TYPE_ARRAY) ||
1899				    (entry.array_type != DBUS_TYPE_BYTE))
1900					goto error_clear;
1901				query = wpabuf_alloc_copy(entry.bytearray_value,
1902							  entry.array_len);
1903			} else
1904				goto error_clear;
1905
1906			wpa_dbus_dict_entry_clear(&entry);
1907		}
1908
1909		if (query == NULL)
1910			goto error;
1911
1912		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1913		if (ret != 0)
1914			goto error;
1915		wpabuf_free(query);
1916	} else
1917		goto error;
1918
1919	return reply;
1920error_clear:
1921	wpa_dbus_dict_entry_clear(&entry);
1922error:
1923	return wpas_dbus_error_invalid_args(message, NULL);
1924}
1925
1926DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
1927						 struct wpa_supplicant * wpa_s)
1928{
1929	wpas_p2p_service_flush(wpa_s);
1930	return NULL;
1931}
1932
1933DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
1934						  struct wpa_supplicant * wpa_s)
1935{
1936	DBusMessageIter iter_dict;
1937	DBusMessage *reply = NULL;
1938	DBusMessageIter iter;
1939	struct wpa_dbus_dict_entry entry;
1940	int upnp = 0;
1941	char *service = NULL;
1942	char *peer_object_path = NULL;
1943	struct wpabuf *tlv = NULL;
1944	u8 version = 0;
1945	u64 ref = 0;
1946	u8 addr[ETH_ALEN];
1947
1948	dbus_message_iter_init(message, &iter);
1949
1950	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1951		goto error;
1952
1953	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1954		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1955			goto error;
1956		if (!strcmp(entry.key, "peer_object") &&
1957		    entry.type == DBUS_TYPE_OBJECT_PATH) {
1958			peer_object_path = os_strdup(entry.str_value);
1959		} else if (!strcmp(entry.key, "service_type") &&
1960			   entry.type == DBUS_TYPE_STRING) {
1961			if (!strcmp(entry.str_value, "upnp"))
1962				upnp = 1;
1963			else
1964				goto error_clear;
1965		} else if (!strcmp(entry.key, "version") &&
1966			   entry.type == DBUS_TYPE_INT32) {
1967			version = entry.uint32_value;
1968		} else if (!strcmp(entry.key, "service") &&
1969			   entry.type == DBUS_TYPE_STRING) {
1970			service = os_strdup(entry.str_value);
1971		} else if (!strcmp(entry.key, "tlv")) {
1972			if (entry.type != DBUS_TYPE_ARRAY ||
1973			    entry.array_type != DBUS_TYPE_BYTE)
1974				goto error_clear;
1975			tlv = wpabuf_alloc_copy(entry.bytearray_value,
1976						entry.array_len);
1977		} else
1978			goto error_clear;
1979
1980		wpa_dbus_dict_entry_clear(&entry);
1981	}
1982
1983	if (!peer_object_path ||
1984	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
1985	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1986		goto error;
1987
1988	if (upnp == 1) {
1989		if (version <= 0 || service == NULL)
1990			goto error;
1991
1992		ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
1993							      version, service);
1994	} else {
1995		if (tlv == NULL)
1996			goto error;
1997		ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1998		wpabuf_free(tlv);
1999	}
2000
2001	if (ref != 0) {
2002		reply = dbus_message_new_method_return(message);
2003		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2004					 &ref, DBUS_TYPE_INVALID);
2005	} else {
2006		reply = wpas_dbus_error_unknown_error(message,
2007				"Unable to send SD request");
2008	}
2009out:
2010	os_free(service);
2011	os_free(peer_object_path);
2012	return reply;
2013error_clear:
2014	wpa_dbus_dict_entry_clear(&entry);
2015error:
2016	if (tlv)
2017		wpabuf_free(tlv);
2018	reply = wpas_dbus_error_invalid_args(message, NULL);
2019	goto out;
2020}
2021
2022DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
2023	DBusMessage *message, struct wpa_supplicant *wpa_s)
2024{
2025	DBusMessageIter iter_dict;
2026	DBusMessage *reply = NULL;
2027	DBusMessageIter iter;
2028	struct wpa_dbus_dict_entry entry;
2029	char *peer_object_path = NULL;
2030	struct wpabuf *tlv = NULL;
2031	int freq = 0;
2032	int dlg_tok = 0;
2033	u8 addr[ETH_ALEN];
2034
2035	dbus_message_iter_init(message, &iter);
2036
2037	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
2038		goto error;
2039
2040	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2041		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2042			goto error;
2043
2044		if (!strcmp(entry.key, "peer_object") &&
2045		    entry.type == DBUS_TYPE_OBJECT_PATH) {
2046			peer_object_path = os_strdup(entry.str_value);
2047		} else if (!strcmp(entry.key, "frequency") &&
2048			   entry.type == DBUS_TYPE_INT32) {
2049			freq = entry.uint32_value;
2050		} else if (!strcmp(entry.key, "dialog_token") &&
2051			   entry.type == DBUS_TYPE_UINT32) {
2052			dlg_tok = entry.uint32_value;
2053		} else if (!strcmp(entry.key, "tlvs")) {
2054			if (entry.type != DBUS_TYPE_ARRAY ||
2055			    entry.array_type != DBUS_TYPE_BYTE)
2056				goto error_clear;
2057			tlv = wpabuf_alloc_copy(entry.bytearray_value,
2058						entry.array_len);
2059		} else
2060			goto error_clear;
2061
2062		wpa_dbus_dict_entry_clear(&entry);
2063	}
2064	if (!peer_object_path ||
2065	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
2066	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2067		goto error;
2068
2069	if (tlv == NULL)
2070		goto error;
2071
2072	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2073	wpabuf_free(tlv);
2074out:
2075	os_free(peer_object_path);
2076	return reply;
2077error_clear:
2078	wpa_dbus_dict_entry_clear(&entry);
2079error:
2080	reply = wpas_dbus_error_invalid_args(message, NULL);
2081	goto out;
2082}
2083
2084DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
2085							 *wpa_s)
2086{
2087	DBusMessageIter iter;
2088	u64 req = 0;
2089
2090	dbus_message_iter_init(message, &iter);
2091	dbus_message_iter_get_basic(&iter, &req);
2092
2093	if (req == 0)
2094		goto error;
2095
2096	if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
2097		goto error;
2098
2099	return NULL;
2100error:
2101	return wpas_dbus_error_invalid_args(message, NULL);
2102}
2103
2104DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
2105						  struct wpa_supplicant * wpa_s)
2106{
2107	wpas_p2p_sd_service_update(wpa_s);
2108	return NULL;
2109}
2110
2111DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
2112						      struct wpa_supplicant *
2113						      wpa_s)
2114{
2115	DBusMessageIter iter;
2116	int ext = 0;
2117
2118	dbus_message_iter_init(message, &iter);
2119	dbus_message_iter_get_basic(&iter, &ext);
2120
2121	wpa_s->p2p_sd_over_ctrl_iface = ext;
2122
2123	return NULL;
2124
2125}
2126