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