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