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