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