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