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