xref: /freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c (revision f39bffc62c1395bde25d152c7f68fdf7cbaab414)
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5  * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10 
11 #include "includes.h"
12 
13 #include "common.h"
14 #include "common/ieee802_11_defs.h"
15 #include "eap_peer/eap_methods.h"
16 #include "eapol_supp/eapol_supp_sm.h"
17 #include "rsn_supp/wpa.h"
18 #include "../config.h"
19 #include "../wpa_supplicant_i.h"
20 #include "../driver_i.h"
21 #include "../notify.h"
22 #include "../bss.h"
23 #include "../scan.h"
24 #include "../autoscan.h"
25 #include "dbus_new_helpers.h"
26 #include "dbus_new.h"
27 #include "dbus_new_handlers.h"
28 #include "dbus_dict_helpers.h"
29 #include "dbus_common_i.h"
30 #include "drivers/driver.h"
31 
32 static const char * const debug_strings[] = {
33 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
34 };
35 
36 
37 /**
38  * wpas_dbus_error_unknown_error - Return a new UnknownError error message
39  * @message: Pointer to incoming dbus message this error refers to
40  * @arg: Optional string appended to error message
41  * Returns: a dbus error message
42  *
43  * Convenience function to create and return an UnknownError
44  */
45 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
46 					    const char *arg)
47 {
48 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
49 				      arg);
50 }
51 
52 
53 /**
54  * wpas_dbus_error_iface_unknown - Return a new invalid interface 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 interface error
59  */
60 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
61 {
62 	return dbus_message_new_error(
63 		message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
64 		"wpa_supplicant knows nothing about this interface.");
65 }
66 
67 
68 /**
69  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
70  * @message: Pointer to incoming dbus message this error refers to
71  * Returns: a dbus error message
72  *
73  * Convenience function to create and return an invalid network error
74  */
75 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
76 {
77 	return dbus_message_new_error(
78 		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
79 		"There is no such a network in this interface.");
80 }
81 
82 
83 /**
84  * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
85  * @message: Pointer to incoming dbus message this error refers to
86  * Returns: a dbus error message
87  *
88  * Convenience function to create and return an invalid options error
89  */
90 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
91 					  const char *arg)
92 {
93 	DBusMessage *reply;
94 
95 	reply = dbus_message_new_error(
96 		message, WPAS_DBUS_ERROR_INVALID_ARGS,
97 		"Did not receive correct message arguments.");
98 	if (arg != NULL)
99 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
100 					 DBUS_TYPE_INVALID);
101 
102 	return reply;
103 }
104 
105 
106 /**
107  * wpas_dbus_error_scan_error - Return a new ScanError error message
108  * @message: Pointer to incoming dbus message this error refers to
109  * @error: Optional string to be used as the error message
110  * Returns: a dbus error message
111  *
112  * Convenience function to create and return a scan error
113  */
114 static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
115 						const char *error)
116 {
117 	return dbus_message_new_error(message,
118 				      WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
119 				      error);
120 }
121 
122 
123 DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
124 {
125 	wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
126 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
127 }
128 
129 
130 static const char * const dont_quote[] = {
131 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
132 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
133 	"bssid", "scan_freq", "freq_list", NULL
134 };
135 
136 static dbus_bool_t should_quote_opt(const char *key)
137 {
138 	int i = 0;
139 
140 	while (dont_quote[i] != NULL) {
141 		if (os_strcmp(key, dont_quote[i]) == 0)
142 			return FALSE;
143 		i++;
144 	}
145 	return TRUE;
146 }
147 
148 /**
149  * get_iface_by_dbus_path - Get a new network interface
150  * @global: Pointer to global data from wpa_supplicant_init()
151  * @path: Pointer to a dbus object path representing an interface
152  * Returns: Pointer to the interface or %NULL if not found
153  */
154 static struct wpa_supplicant * get_iface_by_dbus_path(
155 	struct wpa_global *global, const char *path)
156 {
157 	struct wpa_supplicant *wpa_s;
158 
159 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
160 		if (wpa_s->dbus_new_path &&
161 		    os_strcmp(wpa_s->dbus_new_path, path) == 0)
162 			return wpa_s;
163 	}
164 	return NULL;
165 }
166 
167 
168 /**
169  * set_network_properties - Set properties of a configured network
170  * @wpa_s: wpa_supplicant structure for a network interface
171  * @ssid: wpa_ssid structure for a configured network
172  * @iter: DBus message iterator containing dictionary of network
173  * properties to set.
174  * @error: On failure, an error describing the failure
175  * Returns: TRUE if the request succeeds, FALSE if it failed
176  *
177  * Sets network configuration with parameters given id DBus dictionary
178  */
179 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
180 				   struct wpa_ssid *ssid,
181 				   DBusMessageIter *iter,
182 				   DBusError *error)
183 {
184 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
185 	DBusMessageIter	iter_dict;
186 	char *value = NULL;
187 
188 	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
189 		return FALSE;
190 
191 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
192 		size_t size = 50;
193 		int ret;
194 
195 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
196 			goto error;
197 
198 		value = NULL;
199 		if (entry.type == DBUS_TYPE_ARRAY &&
200 		    entry.array_type == DBUS_TYPE_BYTE) {
201 			if (entry.array_len <= 0)
202 				goto error;
203 
204 			size = entry.array_len * 2 + 1;
205 			value = os_zalloc(size);
206 			if (value == NULL)
207 				goto error;
208 
209 			ret = wpa_snprintf_hex(value, size,
210 					       (u8 *) entry.bytearray_value,
211 					       entry.array_len);
212 			if (ret <= 0)
213 				goto error;
214 		} else if (entry.type == DBUS_TYPE_STRING) {
215 			if (should_quote_opt(entry.key)) {
216 				size = os_strlen(entry.str_value);
217 				if (size == 0)
218 					goto error;
219 
220 				size += 3;
221 				value = os_zalloc(size);
222 				if (value == NULL)
223 					goto error;
224 
225 				ret = os_snprintf(value, size, "\"%s\"",
226 						  entry.str_value);
227 				if (os_snprintf_error(size, ret))
228 					goto error;
229 			} else {
230 				value = os_strdup(entry.str_value);
231 				if (value == NULL)
232 					goto error;
233 			}
234 		} else if (entry.type == DBUS_TYPE_UINT32) {
235 			value = os_zalloc(size);
236 			if (value == NULL)
237 				goto error;
238 
239 			ret = os_snprintf(value, size, "%u",
240 					  entry.uint32_value);
241 			if (os_snprintf_error(size, ret))
242 				goto error;
243 		} else if (entry.type == DBUS_TYPE_INT32) {
244 			value = os_zalloc(size);
245 			if (value == NULL)
246 				goto error;
247 
248 			ret = os_snprintf(value, size, "%d",
249 					  entry.int32_value);
250 			if (os_snprintf_error(size, ret))
251 				goto error;
252 		} else
253 			goto error;
254 
255 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
256 			goto error;
257 
258 		if (os_strcmp(entry.key, "bssid") != 0 &&
259 		    os_strcmp(entry.key, "priority") != 0)
260 			wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
261 
262 		if (wpa_s->current_ssid == ssid ||
263 		    wpa_s->current_ssid == NULL) {
264 			/*
265 			 * Invalidate the EAP session cache if anything in the
266 			 * current or previously used configuration changes.
267 			 */
268 			eapol_sm_invalidate_cached_session(wpa_s->eapol);
269 		}
270 
271 		if ((os_strcmp(entry.key, "psk") == 0 &&
272 		     value[0] == '"' && ssid->ssid_len) ||
273 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
274 			wpa_config_update_psk(ssid);
275 		else if (os_strcmp(entry.key, "priority") == 0)
276 			wpa_config_update_prio_list(wpa_s->conf);
277 
278 		os_free(value);
279 		value = NULL;
280 		wpa_dbus_dict_entry_clear(&entry);
281 	}
282 
283 	return TRUE;
284 
285 error:
286 	os_free(value);
287 	wpa_dbus_dict_entry_clear(&entry);
288 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
289 			     "invalid message format");
290 	return FALSE;
291 }
292 
293 
294 /**
295  * wpas_dbus_simple_property_getter - Get basic type property
296  * @iter: Message iter to use when appending arguments
297  * @type: DBus type of property (must be basic type)
298  * @val: pointer to place holding property value
299  * @error: On failure an error describing the failure
300  * Returns: TRUE if the request was successful, FALSE if it failed
301  *
302  * Generic getter for basic type properties. Type is required to be basic.
303  */
304 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
305 					     const int type,
306 					     const void *val,
307 					     DBusError *error)
308 {
309 	DBusMessageIter variant_iter;
310 
311 	if (!dbus_type_is_basic(type)) {
312 		dbus_set_error(error, DBUS_ERROR_FAILED,
313 			       "%s: given type is not basic", __func__);
314 		return FALSE;
315 	}
316 
317 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
318 					      wpa_dbus_type_as_string(type),
319 					      &variant_iter) ||
320 	    !dbus_message_iter_append_basic(&variant_iter, type, val) ||
321 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
322 		dbus_set_error(error, DBUS_ERROR_FAILED,
323 			       "%s: error constructing reply", __func__);
324 		return FALSE;
325 	}
326 
327 	return TRUE;
328 }
329 
330 
331 /**
332  * wpas_dbus_simple_property_setter - Set basic type property
333  * @message: Pointer to incoming dbus message
334  * @type: DBus type of property (must be basic type)
335  * @val: pointer to place where value being set will be stored
336  * Returns: TRUE if the request was successful, FALSE if it failed
337  *
338  * Generic setter for basic type properties. Type is required to be basic.
339  */
340 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
341 					     DBusError *error,
342 					     const int type, void *val)
343 {
344 	DBusMessageIter variant_iter;
345 
346 	if (!dbus_type_is_basic(type)) {
347 		dbus_set_error(error, DBUS_ERROR_FAILED,
348 			       "%s: given type is not basic", __func__);
349 		return FALSE;
350 	}
351 
352 	/* Look at the new value */
353 	dbus_message_iter_recurse(iter, &variant_iter);
354 	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
355 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
356 				     "wrong property type");
357 		return FALSE;
358 	}
359 	dbus_message_iter_get_basic(&variant_iter, val);
360 
361 	return TRUE;
362 }
363 
364 
365 /**
366  * wpas_dbus_simple_array_property_getter - Get array type property
367  * @iter: Pointer to incoming dbus message iterator
368  * @type: DBus type of property array elements (must be basic type)
369  * @array: pointer to array of elements to put into response message
370  * @array_len: length of above array
371  * @error: a pointer to an error to fill on failure
372  * Returns: TRUE if the request succeeded, FALSE if it failed
373  *
374  * Generic getter for array type properties. Array elements type is
375  * required to be basic.
376  */
377 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
378 						   const int type,
379 						   const void *array,
380 						   size_t array_len,
381 						   DBusError *error)
382 {
383 	DBusMessageIter variant_iter, array_iter;
384 	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
385 	const char *sub_type_str;
386 	size_t element_size, i;
387 
388 	if (!dbus_type_is_basic(type)) {
389 		dbus_set_error(error, DBUS_ERROR_FAILED,
390 			       "%s: given type is not basic", __func__);
391 		return FALSE;
392 	}
393 
394 	sub_type_str = wpa_dbus_type_as_string(type);
395 	type_str[1] = sub_type_str[0];
396 
397 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
398 					      type_str, &variant_iter) ||
399 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
400 					      sub_type_str, &array_iter)) {
401 		dbus_set_error(error, DBUS_ERROR_FAILED,
402 			       "%s: failed to construct message", __func__);
403 		return FALSE;
404 	}
405 
406 	switch (type) {
407 	case DBUS_TYPE_BYTE:
408 	case DBUS_TYPE_BOOLEAN:
409 		element_size = 1;
410 		break;
411 	case DBUS_TYPE_INT16:
412 	case DBUS_TYPE_UINT16:
413 		element_size = sizeof(uint16_t);
414 		break;
415 	case DBUS_TYPE_INT32:
416 	case DBUS_TYPE_UINT32:
417 		element_size = sizeof(uint32_t);
418 		break;
419 	case DBUS_TYPE_INT64:
420 	case DBUS_TYPE_UINT64:
421 		element_size = sizeof(uint64_t);
422 		break;
423 	case DBUS_TYPE_DOUBLE:
424 		element_size = sizeof(double);
425 		break;
426 	case DBUS_TYPE_STRING:
427 	case DBUS_TYPE_OBJECT_PATH:
428 		element_size = sizeof(char *);
429 		break;
430 	default:
431 		dbus_set_error(error, DBUS_ERROR_FAILED,
432 			       "%s: unknown element type %d", __func__, type);
433 		return FALSE;
434 	}
435 
436 	for (i = 0; i < array_len; i++) {
437 		if (!dbus_message_iter_append_basic(&array_iter, type,
438 						    array + i * element_size)) {
439 			dbus_set_error(error, DBUS_ERROR_FAILED,
440 				       "%s: failed to construct message 2.5",
441 				       __func__);
442 			return FALSE;
443 		}
444 	}
445 
446 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
447 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
448 		dbus_set_error(error, DBUS_ERROR_FAILED,
449 			       "%s: failed to construct message 3", __func__);
450 		return FALSE;
451 	}
452 
453 	return TRUE;
454 }
455 
456 
457 /**
458  * wpas_dbus_simple_array_array_property_getter - Get array array type property
459  * @iter: Pointer to incoming dbus message iterator
460  * @type: DBus type of property array elements (must be basic type)
461  * @array: pointer to array of elements to put into response message
462  * @array_len: length of above array
463  * @error: a pointer to an error to fill on failure
464  * Returns: TRUE if the request succeeded, FALSE if it failed
465  *
466  * Generic getter for array type properties. Array elements type is
467  * required to be basic.
468  */
469 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
470 							 const int type,
471 							 struct wpabuf **array,
472 							 size_t array_len,
473 							 DBusError *error)
474 {
475 	DBusMessageIter variant_iter, array_iter;
476 	char type_str[] = "aa?";
477 	char inner_type_str[] = "a?";
478 	const char *sub_type_str;
479 	size_t i;
480 
481 	if (!dbus_type_is_basic(type)) {
482 		dbus_set_error(error, DBUS_ERROR_FAILED,
483 			       "%s: given type is not basic", __func__);
484 		return FALSE;
485 	}
486 
487 	sub_type_str = wpa_dbus_type_as_string(type);
488 	type_str[2] = sub_type_str[0];
489 	inner_type_str[1] = sub_type_str[0];
490 
491 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
492 					      type_str, &variant_iter) ||
493 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
494 					      inner_type_str, &array_iter)) {
495 		dbus_set_error(error, DBUS_ERROR_FAILED,
496 			       "%s: failed to construct message", __func__);
497 		return FALSE;
498 	}
499 
500 	for (i = 0; i < array_len && array[i]; i++) {
501 		wpa_dbus_dict_bin_array_add_element(&array_iter,
502 						    wpabuf_head(array[i]),
503 						    wpabuf_len(array[i]));
504 
505 	}
506 
507 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
508 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
509 		dbus_set_error(error, DBUS_ERROR_FAILED,
510 			       "%s: failed to close message", __func__);
511 		return FALSE;
512 	}
513 
514 	return TRUE;
515 }
516 
517 
518 /**
519  * wpas_dbus_handler_create_interface - Request registration of a network iface
520  * @message: Pointer to incoming dbus message
521  * @global: %wpa_supplicant global data structure
522  * Returns: The object path of the new interface object,
523  *          or a dbus error message with more information
524  *
525  * Handler function for "CreateInterface" method call. Handles requests
526  * by dbus clients to register a network interface that wpa_supplicant
527  * will manage.
528  */
529 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
530 						 struct wpa_global *global)
531 {
532 	DBusMessageIter iter_dict;
533 	DBusMessage *reply = NULL;
534 	DBusMessageIter iter;
535 	struct wpa_dbus_dict_entry entry;
536 	char *driver = NULL;
537 	char *ifname = NULL;
538 	char *confname = NULL;
539 	char *bridge_ifname = NULL;
540 
541 	dbus_message_iter_init(message, &iter);
542 
543 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
544 		goto error;
545 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
546 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
547 			goto error;
548 		if (os_strcmp(entry.key, "Driver") == 0 &&
549 		    entry.type == DBUS_TYPE_STRING) {
550 			os_free(driver);
551 			driver = os_strdup(entry.str_value);
552 			wpa_dbus_dict_entry_clear(&entry);
553 			if (driver == NULL)
554 				goto oom;
555 		} else if (os_strcmp(entry.key, "Ifname") == 0 &&
556 			   entry.type == DBUS_TYPE_STRING) {
557 			os_free(ifname);
558 			ifname = os_strdup(entry.str_value);
559 			wpa_dbus_dict_entry_clear(&entry);
560 			if (ifname == NULL)
561 				goto oom;
562 		} else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
563 			   entry.type == DBUS_TYPE_STRING) {
564 			os_free(confname);
565 			confname = os_strdup(entry.str_value);
566 			wpa_dbus_dict_entry_clear(&entry);
567 			if (confname == NULL)
568 				goto oom;
569 		} else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
570 			   entry.type == DBUS_TYPE_STRING) {
571 			os_free(bridge_ifname);
572 			bridge_ifname = os_strdup(entry.str_value);
573 			wpa_dbus_dict_entry_clear(&entry);
574 			if (bridge_ifname == NULL)
575 				goto oom;
576 		} else {
577 			wpa_dbus_dict_entry_clear(&entry);
578 			goto error;
579 		}
580 	}
581 
582 	if (ifname == NULL)
583 		goto error; /* Required Ifname argument missing */
584 
585 	/*
586 	 * Try to get the wpa_supplicant record for this iface, return
587 	 * an error if we already control it.
588 	 */
589 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
590 		reply = dbus_message_new_error(
591 			message, WPAS_DBUS_ERROR_IFACE_EXISTS,
592 			"wpa_supplicant already controls this interface.");
593 	} else {
594 		struct wpa_supplicant *wpa_s;
595 		struct wpa_interface iface;
596 
597 		os_memset(&iface, 0, sizeof(iface));
598 		iface.driver = driver;
599 		iface.ifname = ifname;
600 		iface.confname = confname;
601 		iface.bridge_ifname = bridge_ifname;
602 		/* Otherwise, have wpa_supplicant attach to it. */
603 		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
604 		if (wpa_s && wpa_s->dbus_new_path) {
605 			const char *path = wpa_s->dbus_new_path;
606 
607 			reply = dbus_message_new_method_return(message);
608 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
609 						 &path, DBUS_TYPE_INVALID);
610 		} else {
611 			reply = wpas_dbus_error_unknown_error(
612 				message,
613 				"wpa_supplicant couldn't grab this interface.");
614 		}
615 	}
616 
617 out:
618 	os_free(driver);
619 	os_free(ifname);
620 	os_free(confname);
621 	os_free(bridge_ifname);
622 	return reply;
623 
624 error:
625 	reply = wpas_dbus_error_invalid_args(message, NULL);
626 	goto out;
627 oom:
628 	reply = wpas_dbus_error_no_memory(message);
629 	goto out;
630 }
631 
632 
633 /**
634  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
635  * @message: Pointer to incoming dbus message
636  * @global: wpa_supplicant global data structure
637  * Returns: a dbus message containing a UINT32 indicating success (1) or
638  *          failure (0), or returns a dbus error message with more information
639  *
640  * Handler function for "removeInterface" method call.  Handles requests
641  * by dbus clients to deregister a network interface that wpa_supplicant
642  * currently manages.
643  */
644 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
645 						 struct wpa_global *global)
646 {
647 	struct wpa_supplicant *wpa_s;
648 	char *path;
649 	DBusMessage *reply = NULL;
650 
651 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
652 			      DBUS_TYPE_INVALID);
653 
654 	wpa_s = get_iface_by_dbus_path(global, path);
655 	if (wpa_s == NULL)
656 		reply = wpas_dbus_error_iface_unknown(message);
657 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
658 		reply = wpas_dbus_error_unknown_error(
659 			message,
660 			"wpa_supplicant couldn't remove this interface.");
661 	}
662 
663 	return reply;
664 }
665 
666 
667 /**
668  * wpas_dbus_handler_get_interface - Get the object path for an interface name
669  * @message: Pointer to incoming dbus message
670  * @global: %wpa_supplicant global data structure
671  * Returns: The object path of the interface object,
672  *          or a dbus error message with more information
673  *
674  * Handler function for "getInterface" method call.
675  */
676 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
677 					      struct wpa_global *global)
678 {
679 	DBusMessage *reply = NULL;
680 	const char *ifname;
681 	const char *path;
682 	struct wpa_supplicant *wpa_s;
683 
684 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
685 			      DBUS_TYPE_INVALID);
686 
687 	wpa_s = wpa_supplicant_get_iface(global, ifname);
688 	if (wpa_s == NULL || wpa_s->dbus_new_path == NULL)
689 		return wpas_dbus_error_iface_unknown(message);
690 
691 	path = wpa_s->dbus_new_path;
692 	reply = dbus_message_new_method_return(message);
693 	if (reply == NULL)
694 		return wpas_dbus_error_no_memory(message);
695 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
696 				      DBUS_TYPE_INVALID)) {
697 		dbus_message_unref(reply);
698 		return wpas_dbus_error_no_memory(message);
699 	}
700 
701 	return reply;
702 }
703 
704 
705 /**
706  * wpas_dbus_getter_debug_level - Get debug level
707  * @iter: Pointer to incoming dbus message iter
708  * @error: Location to store error on failure
709  * @user_data: Function specific data
710  * Returns: TRUE on success, FALSE on failure
711  *
712  * Getter for "DebugLevel" property.
713  */
714 dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
715 					 DBusError *error,
716 					 void *user_data)
717 {
718 	const char *str;
719 	int idx = wpa_debug_level;
720 
721 	if (idx < 0)
722 		idx = 0;
723 	if (idx > 5)
724 		idx = 5;
725 	str = debug_strings[idx];
726 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
727 						&str, error);
728 }
729 
730 
731 /**
732  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
733  * @iter: Pointer to incoming dbus message iter
734  * @error: Location to store error on failure
735  * @user_data: Function specific data
736  * Returns: TRUE on success, FALSE on failure
737  *
738  * Getter for "DebugTimestamp" property.
739  */
740 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
741 					     DBusError *error,
742 					     void *user_data)
743 {
744 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
745 						&wpa_debug_timestamp, error);
746 
747 }
748 
749 
750 /**
751  * wpas_dbus_getter_debug_show_keys - Get debug show keys
752  * @iter: Pointer to incoming dbus message iter
753  * @error: Location to store error on failure
754  * @user_data: Function specific data
755  * Returns: TRUE on success, FALSE on failure
756  *
757  * Getter for "DebugShowKeys" property.
758  */
759 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
760 					     DBusError *error,
761 					     void *user_data)
762 {
763 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
764 						&wpa_debug_show_keys, error);
765 
766 }
767 
768 /**
769  * wpas_dbus_setter_debug_level - Set debug level
770  * @iter: Pointer to incoming dbus message iter
771  * @error: Location to store error on failure
772  * @user_data: Function specific data
773  * Returns: TRUE on success, FALSE on failure
774  *
775  * Setter for "DebugLevel" property.
776  */
777 dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
778 					 DBusError *error, void *user_data)
779 {
780 	struct wpa_global *global = user_data;
781 	const char *str = NULL;
782 	int i, val = -1;
783 
784 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
785 					      &str))
786 		return FALSE;
787 
788 	for (i = 0; debug_strings[i]; i++)
789 		if (os_strcmp(debug_strings[i], str) == 0) {
790 			val = i;
791 			break;
792 		}
793 
794 	if (val < 0 ||
795 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
796 					    wpa_debug_show_keys)) {
797 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
798 				     "wrong debug level value");
799 		return FALSE;
800 	}
801 
802 	return TRUE;
803 }
804 
805 
806 /**
807  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
808  * @iter: Pointer to incoming dbus message iter
809  * @error: Location to store error on failure
810  * @user_data: Function specific data
811  * Returns: TRUE on success, FALSE on failure
812  *
813  * Setter for "DebugTimestamp" property.
814  */
815 dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
816 					     DBusError *error,
817 					     void *user_data)
818 {
819 	struct wpa_global *global = user_data;
820 	dbus_bool_t val;
821 
822 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
823 					      &val))
824 		return FALSE;
825 
826 	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
827 					wpa_debug_show_keys);
828 	return TRUE;
829 }
830 
831 
832 /**
833  * wpas_dbus_setter_debug_show_keys - Set debug show keys
834  * @iter: Pointer to incoming dbus message iter
835  * @error: Location to store error on failure
836  * @user_data: Function specific data
837  * Returns: TRUE on success, FALSE on failure
838  *
839  * Setter for "DebugShowKeys" property.
840  */
841 dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
842 					     DBusError *error,
843 					     void *user_data)
844 {
845 	struct wpa_global *global = user_data;
846 	dbus_bool_t val;
847 
848 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
849 					      &val))
850 		return FALSE;
851 
852 	wpa_supplicant_set_debug_params(global, wpa_debug_level,
853 					wpa_debug_timestamp,
854 					val ? 1 : 0);
855 	return TRUE;
856 }
857 
858 
859 /**
860  * wpas_dbus_getter_interfaces - Request registered interfaces list
861  * @iter: Pointer to incoming dbus message iter
862  * @error: Location to store error on failure
863  * @user_data: Function specific data
864  * Returns: TRUE on success, FALSE on failure
865  *
866  * Getter for "Interfaces" property. Handles requests
867  * by dbus clients to return list of registered interfaces objects
868  * paths
869  */
870 dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
871 					DBusError *error,
872 					void *user_data)
873 {
874 	struct wpa_global *global = user_data;
875 	struct wpa_supplicant *wpa_s;
876 	const char **paths;
877 	unsigned int i = 0, num = 0;
878 	dbus_bool_t success;
879 
880 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
881 		if (wpa_s->dbus_new_path)
882 			num++;
883 	}
884 
885 	paths = os_calloc(num, sizeof(char *));
886 	if (!paths) {
887 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
888 		return FALSE;
889 	}
890 
891 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
892 		if (wpa_s->dbus_new_path)
893 			paths[i++] = wpa_s->dbus_new_path;
894 	}
895 
896 	success = wpas_dbus_simple_array_property_getter(iter,
897 							 DBUS_TYPE_OBJECT_PATH,
898 							 paths, num, error);
899 
900 	os_free(paths);
901 	return success;
902 }
903 
904 
905 /**
906  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
907  * @iter: Pointer to incoming dbus message iter
908  * @error: Location to store error on failure
909  * @user_data: Function specific data
910  * Returns: TRUE on success, FALSE on failure
911  *
912  * Getter for "EapMethods" property. Handles requests
913  * by dbus clients to return list of strings with supported EAP methods
914  */
915 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
916 					 DBusError *error, void *user_data)
917 {
918 	char **eap_methods;
919 	size_t num_items = 0;
920 	dbus_bool_t success;
921 
922 	eap_methods = eap_get_names_as_string_array(&num_items);
923 	if (!eap_methods) {
924 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
925 		return FALSE;
926 	}
927 
928 	success = wpas_dbus_simple_array_property_getter(iter,
929 							 DBUS_TYPE_STRING,
930 							 eap_methods,
931 							 num_items, error);
932 
933 	while (num_items)
934 		os_free(eap_methods[--num_items]);
935 	os_free(eap_methods);
936 	return success;
937 }
938 
939 
940 /**
941  * wpas_dbus_getter_global_capabilities - Request supported global capabilities
942  * @iter: Pointer to incoming dbus message iter
943  * @error: Location to store error on failure
944  * @user_data: Function specific data
945  * Returns: TRUE on success, FALSE on failure
946  *
947  * Getter for "Capabilities" property. Handles requests by dbus clients to
948  * return a list of strings with supported capabilities like AP, RSN IBSS,
949  * and P2P that are determined at compile time.
950  */
951 dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
952 						 DBusError *error,
953 						 void *user_data)
954 {
955 	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
956 	size_t num_items = 0;
957 
958 #ifdef CONFIG_AP
959 	capabilities[num_items++] = "ap";
960 #endif /* CONFIG_AP */
961 #ifdef CONFIG_IBSS_RSN
962 	capabilities[num_items++] = "ibss-rsn";
963 #endif /* CONFIG_IBSS_RSN */
964 #ifdef CONFIG_P2P
965 	capabilities[num_items++] = "p2p";
966 #endif /* CONFIG_P2P */
967 #ifdef CONFIG_INTERWORKING
968 	capabilities[num_items++] = "interworking";
969 #endif /* CONFIG_INTERWORKING */
970 
971 	return wpas_dbus_simple_array_property_getter(iter,
972 						      DBUS_TYPE_STRING,
973 						      capabilities,
974 						      num_items, error);
975 }
976 
977 
978 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
979 				   char **type, DBusMessage **reply)
980 {
981 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
982 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
983 			   __func__);
984 		*reply = wpas_dbus_error_invalid_args(
985 			message, "Wrong Type value type. String required");
986 		return -1;
987 	}
988 	dbus_message_iter_get_basic(var, type);
989 	return 0;
990 }
991 
992 
993 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
994 				    struct wpa_driver_scan_params *params,
995 				    DBusMessage **reply)
996 {
997 	struct wpa_driver_scan_ssid *ssids = params->ssids;
998 	size_t ssids_num = 0;
999 	u8 *ssid;
1000 	DBusMessageIter array_iter, sub_array_iter;
1001 	char *val;
1002 	int len;
1003 
1004 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1005 		wpa_printf(MSG_DEBUG,
1006 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1007 			   __func__);
1008 		*reply = wpas_dbus_error_invalid_args(
1009 			message,
1010 			"Wrong SSIDs value type. Array of arrays of bytes required");
1011 		return -1;
1012 	}
1013 
1014 	dbus_message_iter_recurse(var, &array_iter);
1015 
1016 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1017 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1018 		wpa_printf(MSG_DEBUG,
1019 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1020 			   __func__);
1021 		*reply = wpas_dbus_error_invalid_args(
1022 			message,
1023 			"Wrong SSIDs value type. Array of arrays of bytes required");
1024 		return -1;
1025 	}
1026 
1027 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1028 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1029 			wpa_printf(MSG_DEBUG,
1030 				   "%s[dbus]: Too many ssids specified on scan dbus call",
1031 				   __func__);
1032 			*reply = wpas_dbus_error_invalid_args(
1033 				message,
1034 				"Too many ssids specified. Specify at most four");
1035 			return -1;
1036 		}
1037 
1038 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1039 
1040 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1041 
1042 		if (len > SSID_MAX_LEN) {
1043 			wpa_printf(MSG_DEBUG,
1044 				   "%s[dbus]: SSID too long (len=%d max_len=%d)",
1045 				   __func__, len, SSID_MAX_LEN);
1046 			*reply = wpas_dbus_error_invalid_args(
1047 				message, "Invalid SSID: too long");
1048 			return -1;
1049 		}
1050 
1051 		if (len != 0) {
1052 			ssid = os_malloc(len);
1053 			if (ssid == NULL) {
1054 				*reply = wpas_dbus_error_no_memory(message);
1055 				return -1;
1056 			}
1057 			os_memcpy(ssid, val, len);
1058 		} else {
1059 			/* Allow zero-length SSIDs */
1060 			ssid = NULL;
1061 		}
1062 
1063 		ssids[ssids_num].ssid = ssid;
1064 		ssids[ssids_num].ssid_len = len;
1065 
1066 		dbus_message_iter_next(&array_iter);
1067 		ssids_num++;
1068 	}
1069 
1070 	params->num_ssids = ssids_num;
1071 	return 0;
1072 }
1073 
1074 
1075 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1076 				  struct wpa_driver_scan_params *params,
1077 				  DBusMessage **reply)
1078 {
1079 	u8 *ies = NULL, *nies;
1080 	int ies_len = 0;
1081 	DBusMessageIter array_iter, sub_array_iter;
1082 	char *val;
1083 	int len;
1084 
1085 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1086 		wpa_printf(MSG_DEBUG,
1087 			   "%s[dbus]: ies must be an array of arrays of bytes",
1088 			   __func__);
1089 		*reply = wpas_dbus_error_invalid_args(
1090 			message,
1091 			"Wrong IEs value type. Array of arrays of bytes required");
1092 		return -1;
1093 	}
1094 
1095 	dbus_message_iter_recurse(var, &array_iter);
1096 
1097 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1098 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1099 		wpa_printf(MSG_DEBUG,
1100 			   "%s[dbus]: ies must be an array of arrays of bytes",
1101 			   __func__);
1102 		*reply = wpas_dbus_error_invalid_args(
1103 			message, "Wrong IEs value type. Array required");
1104 		return -1;
1105 	}
1106 
1107 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1108 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1109 
1110 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1111 		if (len == 0) {
1112 			dbus_message_iter_next(&array_iter);
1113 			continue;
1114 		}
1115 
1116 		nies = os_realloc(ies, ies_len + len);
1117 		if (nies == NULL) {
1118 			os_free(ies);
1119 			*reply = wpas_dbus_error_no_memory(message);
1120 			return -1;
1121 		}
1122 		ies = nies;
1123 		os_memcpy(ies + ies_len, val, len);
1124 		ies_len += len;
1125 
1126 		dbus_message_iter_next(&array_iter);
1127 	}
1128 
1129 	params->extra_ies = ies;
1130 	params->extra_ies_len = ies_len;
1131 	return 0;
1132 }
1133 
1134 
1135 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1136 				       DBusMessageIter *var,
1137 				       struct wpa_driver_scan_params *params,
1138 				       DBusMessage **reply)
1139 {
1140 	DBusMessageIter array_iter, sub_array_iter;
1141 	int *freqs = NULL, *nfreqs;
1142 	int freqs_num = 0;
1143 
1144 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1145 		wpa_printf(MSG_DEBUG,
1146 			   "%s[dbus]: Channels must be an array of structs",
1147 			   __func__);
1148 		*reply = wpas_dbus_error_invalid_args(
1149 			message,
1150 			"Wrong Channels value type. Array of structs required");
1151 		return -1;
1152 	}
1153 
1154 	dbus_message_iter_recurse(var, &array_iter);
1155 
1156 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1157 		wpa_printf(MSG_DEBUG,
1158 			   "%s[dbus]: Channels must be an array of structs",
1159 			   __func__);
1160 		*reply = wpas_dbus_error_invalid_args(
1161 			message,
1162 			"Wrong Channels value type. Array of structs required");
1163 		return -1;
1164 	}
1165 
1166 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1167 	{
1168 		int freq, width;
1169 
1170 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1171 
1172 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1173 		    DBUS_TYPE_UINT32) {
1174 			wpa_printf(MSG_DEBUG,
1175 				   "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
1176 				   __func__,
1177 				   dbus_message_iter_get_arg_type(
1178 					   &sub_array_iter));
1179 			*reply = wpas_dbus_error_invalid_args(
1180 				message,
1181 				"Wrong Channel struct. Two UINT32s required");
1182 			os_free(freqs);
1183 			return -1;
1184 		}
1185 		dbus_message_iter_get_basic(&sub_array_iter, &freq);
1186 
1187 		if (!dbus_message_iter_next(&sub_array_iter) ||
1188 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
1189 		    DBUS_TYPE_UINT32) {
1190 			wpa_printf(MSG_DEBUG,
1191 				   "%s[dbus]: Channel must by specified by struct of two UINT32s",
1192 				   __func__);
1193 			*reply = wpas_dbus_error_invalid_args(
1194 				message,
1195 				"Wrong Channel struct. Two UINT32s required");
1196 			os_free(freqs);
1197 			return -1;
1198 		}
1199 
1200 		dbus_message_iter_get_basic(&sub_array_iter, &width);
1201 
1202 #define FREQS_ALLOC_CHUNK 32
1203 		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1204 			nfreqs = os_realloc_array(
1205 				freqs, freqs_num + FREQS_ALLOC_CHUNK,
1206 				sizeof(int));
1207 			if (nfreqs == NULL)
1208 				os_free(freqs);
1209 			freqs = nfreqs;
1210 		}
1211 		if (freqs == NULL) {
1212 			*reply = wpas_dbus_error_no_memory(message);
1213 			return -1;
1214 		}
1215 
1216 		freqs[freqs_num] = freq;
1217 
1218 		freqs_num++;
1219 		dbus_message_iter_next(&array_iter);
1220 	}
1221 
1222 	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1223 	if (nfreqs == NULL)
1224 		os_free(freqs);
1225 	freqs = nfreqs;
1226 	if (freqs == NULL) {
1227 		*reply = wpas_dbus_error_no_memory(message);
1228 		return -1;
1229 	}
1230 	freqs[freqs_num] = 0;
1231 
1232 	params->freqs = freqs;
1233 	return 0;
1234 }
1235 
1236 
1237 static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1238 					 DBusMessageIter *var,
1239 					 dbus_bool_t *allow,
1240 					 DBusMessage **reply)
1241 {
1242 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1243 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
1244 			   __func__);
1245 		*reply = wpas_dbus_error_invalid_args(
1246 			message, "Wrong Type value type. Boolean required");
1247 		return -1;
1248 	}
1249 	dbus_message_iter_get_basic(var, allow);
1250 	return 0;
1251 }
1252 
1253 
1254 /**
1255  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1256  * @message: Pointer to incoming dbus message
1257  * @wpa_s: wpa_supplicant structure for a network interface
1258  * Returns: NULL indicating success or DBus error message on failure
1259  *
1260  * Handler function for "Scan" method call of a network device. Requests
1261  * that wpa_supplicant perform a wireless scan as soon as possible
1262  * on a particular wireless interface.
1263  */
1264 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1265 				     struct wpa_supplicant *wpa_s)
1266 {
1267 	DBusMessage *reply = NULL;
1268 	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1269 	char *key = NULL, *type = NULL;
1270 	struct wpa_driver_scan_params params;
1271 	size_t i;
1272 	dbus_bool_t allow_roam = 1;
1273 
1274 	os_memset(&params, 0, sizeof(params));
1275 
1276 	dbus_message_iter_init(message, &iter);
1277 
1278 	dbus_message_iter_recurse(&iter, &dict_iter);
1279 
1280 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1281 	       DBUS_TYPE_DICT_ENTRY) {
1282 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1283 		dbus_message_iter_get_basic(&entry_iter, &key);
1284 		dbus_message_iter_next(&entry_iter);
1285 		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1286 
1287 		if (os_strcmp(key, "Type") == 0) {
1288 			if (wpas_dbus_get_scan_type(message, &variant_iter,
1289 						    &type, &reply) < 0)
1290 				goto out;
1291 		} else if (os_strcmp(key, "SSIDs") == 0) {
1292 			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1293 						     &params, &reply) < 0)
1294 				goto out;
1295 		} else if (os_strcmp(key, "IEs") == 0) {
1296 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1297 						   &params, &reply) < 0)
1298 				goto out;
1299 		} else if (os_strcmp(key, "Channels") == 0) {
1300 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1301 							&params, &reply) < 0)
1302 				goto out;
1303 		} else if (os_strcmp(key, "AllowRoam") == 0) {
1304 			if (wpas_dbus_get_scan_allow_roam(message,
1305 							  &variant_iter,
1306 							  &allow_roam,
1307 							  &reply) < 0)
1308 				goto out;
1309 		} else {
1310 			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1311 				   __func__, key);
1312 			reply = wpas_dbus_error_invalid_args(message, key);
1313 			goto out;
1314 		}
1315 
1316 		dbus_message_iter_next(&dict_iter);
1317 	}
1318 
1319 	if (!type) {
1320 		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1321 			   __func__);
1322 		reply = wpas_dbus_error_invalid_args(message, key);
1323 		goto out;
1324 	}
1325 
1326 	if (os_strcmp(type, "passive") == 0) {
1327 		if (params.num_ssids || params.extra_ies_len) {
1328 			wpa_printf(MSG_DEBUG,
1329 				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
1330 				   __func__);
1331 			reply = wpas_dbus_error_invalid_args(
1332 				message,
1333 				"You can specify only Channels in passive scan");
1334 			goto out;
1335 		} else {
1336 			if (wpa_s->sched_scanning) {
1337 				wpa_printf(MSG_DEBUG,
1338 					   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1339 					   __func__);
1340 				wpa_supplicant_cancel_sched_scan(wpa_s);
1341 			}
1342 
1343 			if (params.freqs && params.freqs[0]) {
1344 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1345 				if (wpa_supplicant_trigger_scan(wpa_s,
1346 								&params)) {
1347 					reply = wpas_dbus_error_scan_error(
1348 						message,
1349 						"Scan request rejected");
1350 				}
1351 			} else {
1352 				wpa_s->scan_req = MANUAL_SCAN_REQ;
1353 				wpa_supplicant_req_scan(wpa_s, 0, 0);
1354 			}
1355 		}
1356 	} else if (os_strcmp(type, "active") == 0) {
1357 		if (!params.num_ssids) {
1358 			/* Add wildcard ssid */
1359 			params.num_ssids++;
1360 		}
1361 #ifdef CONFIG_AUTOSCAN
1362 		autoscan_deinit(wpa_s);
1363 #endif /* CONFIG_AUTOSCAN */
1364 		if (wpa_s->sched_scanning) {
1365 			wpa_printf(MSG_DEBUG,
1366 				   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1367 				   __func__);
1368 			wpa_supplicant_cancel_sched_scan(wpa_s);
1369 		}
1370 
1371 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1372 		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1373 			reply = wpas_dbus_error_scan_error(
1374 				message, "Scan request rejected");
1375 		}
1376 	} else {
1377 		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1378 			   __func__, type);
1379 		reply = wpas_dbus_error_invalid_args(message,
1380 						     "Wrong scan type");
1381 		goto out;
1382 	}
1383 
1384 	if (!allow_roam)
1385 		wpa_s->scan_res_handler = scan_only_handler;
1386 
1387 out:
1388 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1389 		os_free((u8 *) params.ssids[i].ssid);
1390 	os_free((u8 *) params.extra_ies);
1391 	os_free(params.freqs);
1392 	return reply;
1393 }
1394 
1395 
1396 /**
1397  * wpas_dbus_handler_signal_poll - Request immediate signal properties
1398  * @message: Pointer to incoming dbus message
1399  * @wpa_s: wpa_supplicant structure for a network interface
1400  * Returns: NULL indicating success or DBus error message on failure
1401  *
1402  * Handler function for "SignalPoll" method call of a network device. Requests
1403  * that wpa_supplicant read signal properties like RSSI, noise, and link
1404  * speed and return them.
1405  */
1406 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1407 					    struct wpa_supplicant *wpa_s)
1408 {
1409 	struct wpa_signal_info si;
1410 	DBusMessage *reply = NULL;
1411 	DBusMessageIter iter, iter_dict, variant_iter;
1412 	int ret;
1413 
1414 	ret = wpa_drv_signal_poll(wpa_s, &si);
1415 	if (ret) {
1416 		return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1417 					      "Failed to read signal");
1418 	}
1419 
1420 	reply = dbus_message_new_method_return(message);
1421 	if (reply == NULL)
1422 		goto nomem;
1423 
1424 	dbus_message_iter_init_append(reply, &iter);
1425 
1426 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1427 					      "a{sv}", &variant_iter) ||
1428 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1429 	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1430 					si.current_signal) ||
1431 	    !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
1432 					si.current_txrate / 1000) ||
1433 	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1434 					si.current_noise) ||
1435 	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1436 					 si.frequency) ||
1437 	    (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
1438 	     !wpa_dbus_dict_append_string(
1439 		     &iter_dict, "width",
1440 		     channel_width_to_string(si.chanwidth))) ||
1441 	    (si.center_frq1 > 0 && si.center_frq2 > 0 &&
1442 	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1443 					  si.center_frq1) ||
1444 	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1445 					  si.center_frq2))) ||
1446 	    (si.avg_signal &&
1447 	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1448 					 si.avg_signal)) ||
1449 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1450 	    !dbus_message_iter_close_container(&iter, &variant_iter))
1451 		goto nomem;
1452 
1453 	return reply;
1454 
1455 nomem:
1456 	if (reply)
1457 		dbus_message_unref(reply);
1458 	return wpas_dbus_error_no_memory(message);
1459 }
1460 
1461 
1462 /*
1463  * wpas_dbus_handler_disconnect - Terminate the current connection
1464  * @message: Pointer to incoming dbus message
1465  * @wpa_s: wpa_supplicant structure for a network interface
1466  * Returns: NotConnected DBus error message if already not connected
1467  * or NULL otherwise.
1468  *
1469  * Handler function for "Disconnect" method call of network interface.
1470  */
1471 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1472 					   struct wpa_supplicant *wpa_s)
1473 {
1474 	if (wpa_s->current_ssid != NULL) {
1475 		wpa_s->disconnected = 1;
1476 		wpa_supplicant_deauthenticate(wpa_s,
1477 					      WLAN_REASON_DEAUTH_LEAVING);
1478 
1479 		return NULL;
1480 	}
1481 
1482 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1483 				      "This interface is not connected");
1484 }
1485 
1486 
1487 /**
1488  * wpas_dbus_new_iface_add_network - Add a new configured network
1489  * @message: Pointer to incoming dbus message
1490  * @wpa_s: wpa_supplicant structure for a network interface
1491  * Returns: A dbus message containing the object path of the new network
1492  *
1493  * Handler function for "AddNetwork" method call of a network interface.
1494  */
1495 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1496 					    struct wpa_supplicant *wpa_s)
1497 {
1498 	DBusMessage *reply = NULL;
1499 	DBusMessageIter	iter;
1500 	struct wpa_ssid *ssid = NULL;
1501 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1502 	DBusError error;
1503 
1504 	dbus_message_iter_init(message, &iter);
1505 
1506 	if (wpa_s->dbus_new_path)
1507 		ssid = wpa_config_add_network(wpa_s->conf);
1508 	if (ssid == NULL) {
1509 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
1510 			   __func__);
1511 		reply = wpas_dbus_error_unknown_error(
1512 			message,
1513 			"wpa_supplicant could not add a network on this interface.");
1514 		goto err;
1515 	}
1516 	wpas_notify_network_added(wpa_s, ssid);
1517 	ssid->disabled = 1;
1518 	wpa_config_set_network_defaults(ssid);
1519 
1520 	dbus_error_init(&error);
1521 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1522 		wpa_printf(MSG_DEBUG,
1523 			   "%s[dbus]: control interface couldn't set network properties",
1524 			   __func__);
1525 		reply = wpas_dbus_reply_new_from_error(message, &error,
1526 						       DBUS_ERROR_INVALID_ARGS,
1527 						       "Failed to add network");
1528 		dbus_error_free(&error);
1529 		goto err;
1530 	}
1531 
1532 	/* Construct the object path for this network. */
1533 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1534 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1535 		    wpa_s->dbus_new_path, ssid->id);
1536 
1537 	reply = dbus_message_new_method_return(message);
1538 	if (reply == NULL) {
1539 		reply = wpas_dbus_error_no_memory(message);
1540 		goto err;
1541 	}
1542 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1543 				      DBUS_TYPE_INVALID)) {
1544 		dbus_message_unref(reply);
1545 		reply = wpas_dbus_error_no_memory(message);
1546 		goto err;
1547 	}
1548 
1549 	return reply;
1550 
1551 err:
1552 	if (ssid) {
1553 		wpas_notify_network_removed(wpa_s, ssid);
1554 		wpa_config_remove_network(wpa_s->conf, ssid->id);
1555 	}
1556 	return reply;
1557 }
1558 
1559 
1560 /**
1561  * wpas_dbus_handler_reassociate - Reassociate
1562  * @message: Pointer to incoming dbus message
1563  * @wpa_s: wpa_supplicant structure for a network interface
1564  * Returns: InterfaceDisabled DBus error message if disabled
1565  * or NULL otherwise.
1566  *
1567  * Handler function for "Reassociate" method call of network interface.
1568  */
1569 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1570 					    struct wpa_supplicant *wpa_s)
1571 {
1572 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1573 		wpas_request_connection(wpa_s);
1574 		return NULL;
1575 	}
1576 
1577 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1578 				      "This interface is disabled");
1579 }
1580 
1581 
1582 /**
1583  * wpas_dbus_handler_reattach - Reattach to current AP
1584  * @message: Pointer to incoming dbus message
1585  * @wpa_s: wpa_supplicant structure for a network interface
1586  * Returns: NotConnected DBus error message if not connected
1587  * or NULL otherwise.
1588  *
1589  * Handler function for "Reattach" method call of network interface.
1590  */
1591 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1592 					 struct wpa_supplicant *wpa_s)
1593 {
1594 	if (wpa_s->current_ssid != NULL) {
1595 		wpa_s->reattach = 1;
1596 		wpas_request_connection(wpa_s);
1597 		return NULL;
1598 	}
1599 
1600 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1601 				      "This interface is not connected");
1602 }
1603 
1604 
1605 /**
1606  * wpas_dbus_handler_reconnect - Reconnect if disconnected
1607  * @message: Pointer to incoming dbus message
1608  * @wpa_s: wpa_supplicant structure for a network interface
1609  * Returns: InterfaceDisabled DBus error message if disabled
1610  * or NULL otherwise.
1611  *
1612  * Handler function for "Reconnect" method call of network interface.
1613  */
1614 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
1615 		struct wpa_supplicant *wpa_s)
1616 {
1617 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
1618 		return dbus_message_new_error(message,
1619 					      WPAS_DBUS_ERROR_IFACE_DISABLED,
1620 					      "This interface is disabled");
1621 	}
1622 
1623 	if (wpa_s->disconnected)
1624 		wpas_request_connection(wpa_s);
1625 	return NULL;
1626 }
1627 
1628 
1629 /**
1630  * wpas_dbus_handler_remove_network - Remove a configured network
1631  * @message: Pointer to incoming dbus message
1632  * @wpa_s: wpa_supplicant structure for a network interface
1633  * Returns: NULL on success or dbus error on failure
1634  *
1635  * Handler function for "RemoveNetwork" method call of a network interface.
1636  */
1637 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1638 					       struct wpa_supplicant *wpa_s)
1639 {
1640 	DBusMessage *reply = NULL;
1641 	const char *op;
1642 	char *iface, *net_id;
1643 	int id;
1644 	struct wpa_ssid *ssid;
1645 	int was_disabled;
1646 
1647 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1648 			      DBUS_TYPE_INVALID);
1649 
1650 	/* Extract the network ID and ensure the network */
1651 	/* is actually a child of this interface */
1652 	iface = wpas_dbus_new_decompose_object_path(op,
1653 						    WPAS_DBUS_NEW_NETWORKS_PART,
1654 						    &net_id);
1655 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1656 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1657 		reply = wpas_dbus_error_invalid_args(message, op);
1658 		goto out;
1659 	}
1660 
1661 	errno = 0;
1662 	id = strtoul(net_id, NULL, 10);
1663 	if (errno != 0) {
1664 		reply = wpas_dbus_error_invalid_args(message, op);
1665 		goto out;
1666 	}
1667 
1668 	ssid = wpa_config_get_network(wpa_s->conf, id);
1669 	if (ssid == NULL) {
1670 		reply = wpas_dbus_error_network_unknown(message);
1671 		goto out;
1672 	}
1673 
1674 	was_disabled = ssid->disabled;
1675 
1676 	wpas_notify_network_removed(wpa_s, ssid);
1677 
1678 	if (ssid == wpa_s->current_ssid)
1679 		wpa_supplicant_deauthenticate(wpa_s,
1680 					      WLAN_REASON_DEAUTH_LEAVING);
1681 	else if (!was_disabled && wpa_s->sched_scanning) {
1682 		wpa_printf(MSG_DEBUG,
1683 			   "Stop ongoing sched_scan to remove network from filters");
1684 		wpa_supplicant_cancel_sched_scan(wpa_s);
1685 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1686 	}
1687 
1688 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1689 		wpa_printf(MSG_ERROR,
1690 			   "%s[dbus]: error occurred when removing network %d",
1691 			   __func__, id);
1692 		reply = wpas_dbus_error_unknown_error(
1693 			message,
1694 			"error removing the specified network on is interface.");
1695 		goto out;
1696 	}
1697 
1698 out:
1699 	os_free(iface);
1700 	return reply;
1701 }
1702 
1703 
1704 static void remove_network(void *arg, struct wpa_ssid *ssid)
1705 {
1706 	struct wpa_supplicant *wpa_s = arg;
1707 
1708 	wpas_notify_network_removed(wpa_s, ssid);
1709 
1710 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1711 		wpa_printf(MSG_ERROR,
1712 			   "%s[dbus]: error occurred when removing network %d",
1713 			   __func__, ssid->id);
1714 		return;
1715 	}
1716 
1717 	if (ssid == wpa_s->current_ssid)
1718 		wpa_supplicant_deauthenticate(wpa_s,
1719 					      WLAN_REASON_DEAUTH_LEAVING);
1720 }
1721 
1722 
1723 /**
1724  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1725  * @message: Pointer to incoming dbus message
1726  * @wpa_s: wpa_supplicant structure for a network interface
1727  * Returns: NULL on success or dbus error on failure
1728  *
1729  * Handler function for "RemoveAllNetworks" method call of a network interface.
1730  */
1731 DBusMessage * wpas_dbus_handler_remove_all_networks(
1732 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1733 {
1734 	if (wpa_s->sched_scanning)
1735 		wpa_supplicant_cancel_sched_scan(wpa_s);
1736 
1737 	/* NB: could check for failure and return an error */
1738 	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1739 	return NULL;
1740 }
1741 
1742 
1743 /**
1744  * wpas_dbus_handler_select_network - Attempt association with a network
1745  * @message: Pointer to incoming dbus message
1746  * @wpa_s: wpa_supplicant structure for a network interface
1747  * Returns: NULL on success or dbus error on failure
1748  *
1749  * Handler function for "SelectNetwork" method call of network interface.
1750  */
1751 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1752 					       struct wpa_supplicant *wpa_s)
1753 {
1754 	DBusMessage *reply = NULL;
1755 	const char *op;
1756 	char *iface, *net_id;
1757 	int id;
1758 	struct wpa_ssid *ssid;
1759 
1760 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1761 			      DBUS_TYPE_INVALID);
1762 
1763 	/* Extract the network ID and ensure the network */
1764 	/* is actually a child of this interface */
1765 	iface = wpas_dbus_new_decompose_object_path(op,
1766 						    WPAS_DBUS_NEW_NETWORKS_PART,
1767 						    &net_id);
1768 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1769 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1770 		reply = wpas_dbus_error_invalid_args(message, op);
1771 		goto out;
1772 	}
1773 
1774 	errno = 0;
1775 	id = strtoul(net_id, NULL, 10);
1776 	if (errno != 0) {
1777 		reply = wpas_dbus_error_invalid_args(message, op);
1778 		goto out;
1779 	}
1780 
1781 	ssid = wpa_config_get_network(wpa_s->conf, id);
1782 	if (ssid == NULL) {
1783 		reply = wpas_dbus_error_network_unknown(message);
1784 		goto out;
1785 	}
1786 
1787 	/* Finally, associate with the network */
1788 	wpa_supplicant_select_network(wpa_s, ssid);
1789 
1790 out:
1791 	os_free(iface);
1792 	return reply;
1793 }
1794 
1795 
1796 /**
1797  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1798  * @message: Pointer to incoming dbus message
1799  * @wpa_s: wpa_supplicant structure for a network interface
1800  * Returns: NULL on success or dbus error on failure
1801  *
1802  * Handler function for "NetworkReply" method call of network interface.
1803  */
1804 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1805 					      struct wpa_supplicant *wpa_s)
1806 {
1807 #ifdef IEEE8021X_EAPOL
1808 	DBusMessage *reply = NULL;
1809 	const char *op, *field, *value;
1810 	char *iface, *net_id;
1811 	int id;
1812 	struct wpa_ssid *ssid;
1813 
1814 	if (!dbus_message_get_args(message, NULL,
1815 				   DBUS_TYPE_OBJECT_PATH, &op,
1816 				   DBUS_TYPE_STRING, &field,
1817 				   DBUS_TYPE_STRING, &value,
1818 				   DBUS_TYPE_INVALID))
1819 		return wpas_dbus_error_invalid_args(message, NULL);
1820 
1821 	/* Extract the network ID and ensure the network */
1822 	/* is actually a child of this interface */
1823 	iface = wpas_dbus_new_decompose_object_path(op,
1824 						    WPAS_DBUS_NEW_NETWORKS_PART,
1825 						    &net_id);
1826 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1827 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1828 		reply = wpas_dbus_error_invalid_args(message, op);
1829 		goto out;
1830 	}
1831 
1832 	errno = 0;
1833 	id = strtoul(net_id, NULL, 10);
1834 	if (errno != 0) {
1835 		reply = wpas_dbus_error_invalid_args(message, net_id);
1836 		goto out;
1837 	}
1838 
1839 	ssid = wpa_config_get_network(wpa_s->conf, id);
1840 	if (ssid == NULL) {
1841 		reply = wpas_dbus_error_network_unknown(message);
1842 		goto out;
1843 	}
1844 
1845 	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1846 						      field, value) < 0)
1847 		reply = wpas_dbus_error_invalid_args(message, field);
1848 	else {
1849 		/* Tell EAP to retry immediately */
1850 		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1851 	}
1852 
1853 out:
1854 	os_free(iface);
1855 	return reply;
1856 #else /* IEEE8021X_EAPOL */
1857 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1858 	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1859 #endif /* IEEE8021X_EAPOL */
1860 }
1861 
1862 
1863 #ifndef CONFIG_NO_CONFIG_BLOBS
1864 
1865 /**
1866  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1867  * @message: Pointer to incoming dbus message
1868  * @wpa_s: %wpa_supplicant data structure
1869  * Returns: A dbus message containing an error on failure or NULL on success
1870  *
1871  * Asks wpa_supplicant to internally store a binary blobs.
1872  */
1873 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1874 					 struct wpa_supplicant *wpa_s)
1875 {
1876 	DBusMessage *reply = NULL;
1877 	DBusMessageIter	iter, array_iter;
1878 
1879 	char *blob_name;
1880 	u8 *blob_data;
1881 	int blob_len;
1882 	struct wpa_config_blob *blob = NULL;
1883 
1884 	dbus_message_iter_init(message, &iter);
1885 	dbus_message_iter_get_basic(&iter, &blob_name);
1886 
1887 	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1888 		return dbus_message_new_error(message,
1889 					      WPAS_DBUS_ERROR_BLOB_EXISTS,
1890 					      NULL);
1891 	}
1892 
1893 	dbus_message_iter_next(&iter);
1894 	dbus_message_iter_recurse(&iter, &array_iter);
1895 
1896 	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1897 
1898 	blob = os_zalloc(sizeof(*blob));
1899 	if (!blob) {
1900 		reply = wpas_dbus_error_no_memory(message);
1901 		goto err;
1902 	}
1903 
1904 	blob->data = os_malloc(blob_len);
1905 	blob->name = os_strdup(blob_name);
1906 	if (!blob->data || !blob->name) {
1907 		reply = wpas_dbus_error_no_memory(message);
1908 		goto err;
1909 	}
1910 	os_memcpy(blob->data, blob_data, blob_len);
1911 	blob->len = blob_len;
1912 
1913 	wpa_config_set_blob(wpa_s->conf, blob);
1914 	wpas_notify_blob_added(wpa_s, blob->name);
1915 
1916 	return reply;
1917 
1918 err:
1919 	if (blob) {
1920 		os_free(blob->name);
1921 		os_free(blob->data);
1922 		os_free(blob);
1923 	}
1924 	return reply;
1925 }
1926 
1927 
1928 /**
1929  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1930  * @message: Pointer to incoming dbus message
1931  * @wpa_s: %wpa_supplicant data structure
1932  * Returns: A dbus message containing array of bytes (blob)
1933  *
1934  * Gets one wpa_supplicant's binary blobs.
1935  */
1936 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1937 					 struct wpa_supplicant *wpa_s)
1938 {
1939 	DBusMessage *reply = NULL;
1940 	DBusMessageIter	iter, array_iter;
1941 
1942 	char *blob_name;
1943 	const struct wpa_config_blob *blob;
1944 
1945 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1946 			      DBUS_TYPE_INVALID);
1947 
1948 	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1949 	if (!blob) {
1950 		return dbus_message_new_error(message,
1951 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1952 					      "Blob id not set");
1953 	}
1954 
1955 	reply = dbus_message_new_method_return(message);
1956 	if (!reply)
1957 		return wpas_dbus_error_no_memory(message);
1958 
1959 	dbus_message_iter_init_append(reply, &iter);
1960 
1961 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1962 					      DBUS_TYPE_BYTE_AS_STRING,
1963 					      &array_iter) ||
1964 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1965 						  &(blob->data), blob->len) ||
1966 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
1967 		dbus_message_unref(reply);
1968 		reply = wpas_dbus_error_no_memory(message);
1969 	}
1970 
1971 	return reply;
1972 }
1973 
1974 
1975 /**
1976  * wpas_remove_handler_remove_blob - Remove named binary blob
1977  * @message: Pointer to incoming dbus message
1978  * @wpa_s: %wpa_supplicant data structure
1979  * Returns: NULL on success or dbus error
1980  *
1981  * Asks wpa_supplicant to internally remove a binary blobs.
1982  */
1983 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1984 					    struct wpa_supplicant *wpa_s)
1985 {
1986 	DBusMessage *reply = NULL;
1987 	char *blob_name;
1988 
1989 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1990 			      DBUS_TYPE_INVALID);
1991 
1992 	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1993 		return dbus_message_new_error(message,
1994 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1995 					      "Blob id not set");
1996 	}
1997 	wpas_notify_blob_removed(wpa_s, blob_name);
1998 
1999 	return reply;
2000 
2001 }
2002 
2003 #endif /* CONFIG_NO_CONFIG_BLOBS */
2004 
2005 
2006 /*
2007  * wpas_dbus_handler_flush_bss - Flush the BSS cache
2008  * @message: Pointer to incoming dbus message
2009  * @wpa_s: wpa_supplicant structure for a network interface
2010  * Returns: NULL
2011  *
2012  * Handler function for "FlushBSS" method call of network interface.
2013  */
2014 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2015 					  struct wpa_supplicant *wpa_s)
2016 {
2017 	dbus_uint32_t age;
2018 
2019 	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2020 			      DBUS_TYPE_INVALID);
2021 
2022 	if (age == 0)
2023 		wpa_bss_flush(wpa_s);
2024 	else
2025 		wpa_bss_flush_by_age(wpa_s, age);
2026 
2027 	return NULL;
2028 }
2029 
2030 
2031 #ifdef CONFIG_AUTOSCAN
2032 /**
2033  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2034  * @message: Pointer to incoming dbus message
2035  * @wpa_s: wpa_supplicant structure for a network interface
2036  * Returns: NULL
2037  *
2038  * Handler function for "AutoScan" method call of network interface.
2039  */
2040 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2041 					 struct wpa_supplicant *wpa_s)
2042 {
2043 	DBusMessage *reply = NULL;
2044 	enum wpa_states state = wpa_s->wpa_state;
2045 	char *arg;
2046 
2047 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2048 			      DBUS_TYPE_INVALID);
2049 
2050 	if (arg != NULL && os_strlen(arg) > 0) {
2051 		char *tmp;
2052 
2053 		tmp = os_strdup(arg);
2054 		if (tmp == NULL) {
2055 			reply = wpas_dbus_error_no_memory(message);
2056 		} else {
2057 			os_free(wpa_s->conf->autoscan);
2058 			wpa_s->conf->autoscan = tmp;
2059 			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2060 				autoscan_init(wpa_s, 1);
2061 			else if (state == WPA_SCANNING)
2062 				wpa_supplicant_reinit_autoscan(wpa_s);
2063 		}
2064 	} else if (arg != NULL && os_strlen(arg) == 0) {
2065 		os_free(wpa_s->conf->autoscan);
2066 		wpa_s->conf->autoscan = NULL;
2067 		autoscan_deinit(wpa_s);
2068 	} else
2069 		reply = dbus_message_new_error(message,
2070 					       DBUS_ERROR_INVALID_ARGS,
2071 					       NULL);
2072 
2073 	return reply;
2074 }
2075 #endif /* CONFIG_AUTOSCAN */
2076 
2077 
2078 /*
2079  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2080  * @message: Pointer to incoming dbus message
2081  * @wpa_s: wpa_supplicant structure for a network interface
2082  * Returns: NULL
2083  *
2084  * Handler function for "EAPLogoff" method call of network interface.
2085  */
2086 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2087 					   struct wpa_supplicant *wpa_s)
2088 {
2089 	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2090 	return NULL;
2091 }
2092 
2093 
2094 /*
2095  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2096  * @message: Pointer to incoming dbus message
2097  * @wpa_s: wpa_supplicant structure for a network interface
2098  * Returns: NULL
2099  *
2100  * Handler function for "EAPLogin" method call of network interface.
2101  */
2102 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2103 					  struct wpa_supplicant *wpa_s)
2104 {
2105 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2106 	return NULL;
2107 }
2108 
2109 
2110 #ifdef CONFIG_TDLS
2111 
2112 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2113 				  u8 *peer_address, DBusMessage **error)
2114 {
2115 	const char *peer_string;
2116 
2117 	*error = NULL;
2118 
2119 	if (!dbus_message_get_args(message, NULL,
2120 				   DBUS_TYPE_STRING, &peer_string,
2121 				   DBUS_TYPE_INVALID)) {
2122 		*error = wpas_dbus_error_invalid_args(message, NULL);
2123 		return -1;
2124 	}
2125 
2126 	if (hwaddr_aton(peer_string, peer_address)) {
2127 		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2128 			   func_name, peer_string);
2129 		*error = wpas_dbus_error_invalid_args(
2130 			message, "Invalid hardware address format");
2131 		return -1;
2132 	}
2133 
2134 	return 0;
2135 }
2136 
2137 
2138 /*
2139  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2140  * @message: Pointer to incoming dbus message
2141  * @wpa_s: wpa_supplicant structure for a network interface
2142  * Returns: NULL indicating success or DBus error message on failure
2143  *
2144  * Handler function for "TDLSDiscover" method call of network interface.
2145  */
2146 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2147 					      struct wpa_supplicant *wpa_s)
2148 {
2149 	u8 peer[ETH_ALEN];
2150 	DBusMessage *error_reply;
2151 	int ret;
2152 
2153 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2154 		return error_reply;
2155 
2156 	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2157 
2158 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2159 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2160 	else
2161 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2162 
2163 	if (ret) {
2164 		return wpas_dbus_error_unknown_error(
2165 			message, "error performing TDLS discovery");
2166 	}
2167 
2168 	return NULL;
2169 }
2170 
2171 
2172 /*
2173  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2174  * @message: Pointer to incoming dbus message
2175  * @wpa_s: wpa_supplicant structure for a network interface
2176  * Returns: NULL indicating success or DBus error message on failure
2177  *
2178  * Handler function for "TDLSSetup" method call of network interface.
2179  */
2180 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2181 					   struct wpa_supplicant *wpa_s)
2182 {
2183 	u8 peer[ETH_ALEN];
2184 	DBusMessage *error_reply;
2185 	int ret;
2186 
2187 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2188 		return error_reply;
2189 
2190 	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2191 
2192 	wpa_tdls_remove(wpa_s->wpa, peer);
2193 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2194 		ret = wpa_tdls_start(wpa_s->wpa, peer);
2195 	else
2196 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2197 
2198 	if (ret) {
2199 		return wpas_dbus_error_unknown_error(
2200 			message, "error performing TDLS setup");
2201 	}
2202 
2203 	return NULL;
2204 }
2205 
2206 
2207 /*
2208  * wpas_dbus_handler_tdls_status - Return TDLS session status
2209  * @message: Pointer to incoming dbus message
2210  * @wpa_s: wpa_supplicant structure for a network interface
2211  * Returns: A string representing the state of the link to this TDLS peer
2212  *
2213  * Handler function for "TDLSStatus" method call of network interface.
2214  */
2215 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2216 					    struct wpa_supplicant *wpa_s)
2217 {
2218 	u8 peer[ETH_ALEN];
2219 	DBusMessage *reply;
2220 	const char *tdls_status;
2221 
2222 	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2223 		return reply;
2224 
2225 	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2226 
2227 	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2228 
2229 	reply = dbus_message_new_method_return(message);
2230 	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2231 				 &tdls_status, DBUS_TYPE_INVALID);
2232 	return reply;
2233 }
2234 
2235 
2236 /*
2237  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2238  * @message: Pointer to incoming dbus message
2239  * @wpa_s: wpa_supplicant structure for a network interface
2240  * Returns: NULL indicating success or DBus error message on failure
2241  *
2242  * Handler function for "TDLSTeardown" method call of network interface.
2243  */
2244 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2245 					      struct wpa_supplicant *wpa_s)
2246 {
2247 	u8 peer[ETH_ALEN];
2248 	DBusMessage *error_reply;
2249 	int ret;
2250 
2251 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2252 		return error_reply;
2253 
2254 	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2255 
2256 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2257 		ret = wpa_tdls_teardown_link(
2258 			wpa_s->wpa, peer,
2259 			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2260 	else
2261 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2262 
2263 	if (ret) {
2264 		return wpas_dbus_error_unknown_error(
2265 			message, "error performing TDLS teardown");
2266 	}
2267 
2268 	return NULL;
2269 }
2270 
2271 #endif /* CONFIG_TDLS */
2272 
2273 
2274 /**
2275  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2276  * @message: Pointer to incoming dbus message
2277  * @wpa_s: %wpa_supplicant data structure
2278  * Returns: A dbus message containing an error on failure or NULL on success
2279  *
2280  * Sets the PKCS #11 engine and module path.
2281  */
2282 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2283 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2284 {
2285 	DBusMessageIter iter;
2286 	char *value = NULL;
2287 	char *pkcs11_engine_path = NULL;
2288 	char *pkcs11_module_path = NULL;
2289 
2290 	dbus_message_iter_init(message, &iter);
2291 	dbus_message_iter_get_basic(&iter, &value);
2292 	if (value == NULL) {
2293 		return dbus_message_new_error(
2294 			message, DBUS_ERROR_INVALID_ARGS,
2295 			"Invalid pkcs11_engine_path argument");
2296 	}
2297 	/* Empty path defaults to NULL */
2298 	if (os_strlen(value))
2299 		pkcs11_engine_path = value;
2300 
2301 	dbus_message_iter_next(&iter);
2302 	dbus_message_iter_get_basic(&iter, &value);
2303 	if (value == NULL) {
2304 		os_free(pkcs11_engine_path);
2305 		return dbus_message_new_error(
2306 			message, DBUS_ERROR_INVALID_ARGS,
2307 			"Invalid pkcs11_module_path argument");
2308 	}
2309 	/* Empty path defaults to NULL */
2310 	if (os_strlen(value))
2311 		pkcs11_module_path = value;
2312 
2313 	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2314 						   pkcs11_module_path))
2315 		return dbus_message_new_error(
2316 			message, DBUS_ERROR_FAILED,
2317 			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
2318 
2319 	if (wpa_s->dbus_new_path) {
2320 		wpa_dbus_mark_property_changed(
2321 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2322 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2323 		wpa_dbus_mark_property_changed(
2324 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2325 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2326 	}
2327 
2328 	return NULL;
2329 }
2330 
2331 
2332 /**
2333  * wpas_dbus_getter_capabilities - Return interface capabilities
2334  * @iter: Pointer to incoming dbus message iter
2335  * @error: Location to store error on failure
2336  * @user_data: Function specific data
2337  * Returns: TRUE on success, FALSE on failure
2338  *
2339  * Getter for "Capabilities" property of an interface.
2340  */
2341 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
2342 					  DBusError *error, void *user_data)
2343 {
2344 	struct wpa_supplicant *wpa_s = user_data;
2345 	struct wpa_driver_capa capa;
2346 	int res;
2347 	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2348 		variant_iter;
2349 	const char *scans[] = { "active", "passive", "ssid" };
2350 
2351 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2352 					      "a{sv}", &variant_iter) ||
2353 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2354 		goto nomem;
2355 
2356 	res = wpa_drv_get_capa(wpa_s, &capa);
2357 
2358 	/***** pairwise cipher */
2359 	if (res < 0) {
2360 		const char *args[] = {"ccmp", "tkip", "none"};
2361 
2362 		if (!wpa_dbus_dict_append_string_array(
2363 			    &iter_dict, "Pairwise", args,
2364 			    ARRAY_SIZE(args)))
2365 			goto nomem;
2366 	} else {
2367 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2368 						      &iter_dict_entry,
2369 						      &iter_dict_val,
2370 						      &iter_array) ||
2371 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2372 		     !wpa_dbus_dict_string_array_add_element(
2373 			     &iter_array, "ccmp-256")) ||
2374 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2375 		     !wpa_dbus_dict_string_array_add_element(
2376 			     &iter_array, "gcmp-256")) ||
2377 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2378 		     !wpa_dbus_dict_string_array_add_element(
2379 			     &iter_array, "ccmp")) ||
2380 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2381 		     !wpa_dbus_dict_string_array_add_element(
2382 			     &iter_array, "gcmp")) ||
2383 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2384 		     !wpa_dbus_dict_string_array_add_element(
2385 			     &iter_array, "tkip")) ||
2386 		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2387 		     !wpa_dbus_dict_string_array_add_element(
2388 			     &iter_array, "none")) ||
2389 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2390 						    &iter_dict_entry,
2391 						    &iter_dict_val,
2392 						    &iter_array))
2393 			goto nomem;
2394 	}
2395 
2396 	/***** group cipher */
2397 	if (res < 0) {
2398 		const char *args[] = {
2399 			"ccmp", "tkip", "wep104", "wep40"
2400 		};
2401 
2402 		if (!wpa_dbus_dict_append_string_array(
2403 			    &iter_dict, "Group", args,
2404 			    ARRAY_SIZE(args)))
2405 			goto nomem;
2406 	} else {
2407 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2408 						      &iter_dict_entry,
2409 						      &iter_dict_val,
2410 						      &iter_array) ||
2411 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2412 		     !wpa_dbus_dict_string_array_add_element(
2413 			     &iter_array, "ccmp-256")) ||
2414 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2415 		     !wpa_dbus_dict_string_array_add_element(
2416 			     &iter_array, "gcmp-256")) ||
2417 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2418 		     !wpa_dbus_dict_string_array_add_element(
2419 			     &iter_array, "ccmp")) ||
2420 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2421 		     !wpa_dbus_dict_string_array_add_element(
2422 			     &iter_array, "gcmp")) ||
2423 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2424 		     !wpa_dbus_dict_string_array_add_element(
2425 			     &iter_array, "tkip")) ||
2426 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
2427 		     !wpa_dbus_dict_string_array_add_element(
2428 			     &iter_array, "wep104")) ||
2429 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
2430 		     !wpa_dbus_dict_string_array_add_element(
2431 			     &iter_array, "wep40")) ||
2432 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2433 						    &iter_dict_entry,
2434 						    &iter_dict_val,
2435 						    &iter_array))
2436 			goto nomem;
2437 	}
2438 
2439 	/***** key management */
2440 	if (res < 0) {
2441 		const char *args[] = {
2442 			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2443 #ifdef CONFIG_WPS
2444 			"wps",
2445 #endif /* CONFIG_WPS */
2446 			"none"
2447 		};
2448 		if (!wpa_dbus_dict_append_string_array(
2449 			    &iter_dict, "KeyMgmt", args,
2450 			    ARRAY_SIZE(args)))
2451 			goto nomem;
2452 	} else {
2453 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2454 						      &iter_dict_entry,
2455 						      &iter_dict_val,
2456 						      &iter_array) ||
2457 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2458 							    "none") ||
2459 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2460 							    "ieee8021x"))
2461 			goto nomem;
2462 
2463 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2464 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2465 			if (!wpa_dbus_dict_string_array_add_element(
2466 				    &iter_array, "wpa-eap") ||
2467 			    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
2468 			     !wpa_dbus_dict_string_array_add_element(
2469 				     &iter_array, "wpa-ft-eap")))
2470 				goto nomem;
2471 
2472 /* TODO: Ensure that driver actually supports sha256 encryption. */
2473 #ifdef CONFIG_IEEE80211W
2474 			if (!wpa_dbus_dict_string_array_add_element(
2475 				    &iter_array, "wpa-eap-sha256"))
2476 				goto nomem;
2477 #endif /* CONFIG_IEEE80211W */
2478 		}
2479 
2480 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2481 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2482 			if (!wpa_dbus_dict_string_array_add_element(
2483 				    &iter_array, "wpa-psk") ||
2484 			    ((capa.key_mgmt &
2485 			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
2486 			     !wpa_dbus_dict_string_array_add_element(
2487 				     &iter_array, "wpa-ft-psk")))
2488 				goto nomem;
2489 
2490 /* TODO: Ensure that driver actually supports sha256 encryption. */
2491 #ifdef CONFIG_IEEE80211W
2492 			if (!wpa_dbus_dict_string_array_add_element(
2493 				    &iter_array, "wpa-psk-sha256"))
2494 				goto nomem;
2495 #endif /* CONFIG_IEEE80211W */
2496 		}
2497 
2498 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2499 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2500 							    "wpa-none"))
2501 			goto nomem;
2502 
2503 
2504 #ifdef CONFIG_WPS
2505 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2506 							    "wps"))
2507 			goto nomem;
2508 #endif /* CONFIG_WPS */
2509 
2510 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2511 						    &iter_dict_entry,
2512 						    &iter_dict_val,
2513 						    &iter_array))
2514 			goto nomem;
2515 	}
2516 
2517 	/***** WPA protocol */
2518 	if (res < 0) {
2519 		const char *args[] = { "rsn", "wpa" };
2520 
2521 		if (!wpa_dbus_dict_append_string_array(
2522 			    &iter_dict, "Protocol", args,
2523 			    ARRAY_SIZE(args)))
2524 			goto nomem;
2525 	} else {
2526 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2527 						      &iter_dict_entry,
2528 						      &iter_dict_val,
2529 						      &iter_array) ||
2530 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2531 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
2532 		     !wpa_dbus_dict_string_array_add_element(
2533 			     &iter_array, "rsn")) ||
2534 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2535 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
2536 		     !wpa_dbus_dict_string_array_add_element(
2537 			     &iter_array, "wpa")) ||
2538 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2539 						    &iter_dict_entry,
2540 						    &iter_dict_val,
2541 						    &iter_array))
2542 			goto nomem;
2543 	}
2544 
2545 	/***** auth alg */
2546 	if (res < 0) {
2547 		const char *args[] = { "open", "shared", "leap" };
2548 
2549 		if (!wpa_dbus_dict_append_string_array(
2550 			    &iter_dict, "AuthAlg", args,
2551 			    ARRAY_SIZE(args)))
2552 			goto nomem;
2553 	} else {
2554 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2555 						      &iter_dict_entry,
2556 						      &iter_dict_val,
2557 						      &iter_array))
2558 			goto nomem;
2559 
2560 		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
2561 		     !wpa_dbus_dict_string_array_add_element(
2562 			     &iter_array, "open")) ||
2563 		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
2564 		     !wpa_dbus_dict_string_array_add_element(
2565 			     &iter_array, "shared")) ||
2566 		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
2567 		     !wpa_dbus_dict_string_array_add_element(
2568 			     &iter_array, "leap")) ||
2569 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2570 						    &iter_dict_entry,
2571 						    &iter_dict_val,
2572 						    &iter_array))
2573 			goto nomem;
2574 	}
2575 
2576 	/***** Scan */
2577 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2578 					       ARRAY_SIZE(scans)))
2579 		goto nomem;
2580 
2581 	/***** Modes */
2582 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2583 					      &iter_dict_entry,
2584 					      &iter_dict_val,
2585 					      &iter_array) ||
2586 	    !wpa_dbus_dict_string_array_add_element(
2587 		    &iter_array, "infrastructure") ||
2588 	    !wpa_dbus_dict_string_array_add_element(
2589 		    &iter_array, "ad-hoc") ||
2590 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
2591 	     !wpa_dbus_dict_string_array_add_element(
2592 		     &iter_array, "ap")) ||
2593 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
2594 	     !wpa_dbus_dict_string_array_add_element(
2595 		     &iter_array, "p2p")) ||
2596 	    !wpa_dbus_dict_end_string_array(&iter_dict,
2597 					    &iter_dict_entry,
2598 					    &iter_dict_val,
2599 					    &iter_array))
2600 		goto nomem;
2601 	/***** Modes end */
2602 
2603 	if (res >= 0) {
2604 		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2605 
2606 		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2607 						max_scan_ssid))
2608 			goto nomem;
2609 	}
2610 
2611 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
2612 	    !dbus_message_iter_close_container(iter, &variant_iter))
2613 		goto nomem;
2614 
2615 	return TRUE;
2616 
2617 nomem:
2618 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2619 	return FALSE;
2620 }
2621 
2622 
2623 /**
2624  * wpas_dbus_getter_state - Get interface state
2625  * @iter: Pointer to incoming dbus message iter
2626  * @error: Location to store error on failure
2627  * @user_data: Function specific data
2628  * Returns: TRUE on success, FALSE on failure
2629  *
2630  * Getter for "State" property.
2631  */
2632 dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
2633 				   void *user_data)
2634 {
2635 	struct wpa_supplicant *wpa_s = user_data;
2636 	const char *str_state;
2637 	char *state_ls, *tmp;
2638 	dbus_bool_t success = FALSE;
2639 
2640 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2641 
2642 	/* make state string lowercase to fit new DBus API convention
2643 	 */
2644 	state_ls = tmp = os_strdup(str_state);
2645 	if (!tmp) {
2646 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2647 		return FALSE;
2648 	}
2649 	while (*tmp) {
2650 		*tmp = tolower(*tmp);
2651 		tmp++;
2652 	}
2653 
2654 	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2655 						   &state_ls, error);
2656 
2657 	os_free(state_ls);
2658 
2659 	return success;
2660 }
2661 
2662 
2663 /**
2664  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2665  * @iter: Pointer to incoming dbus message iter
2666  * @error: Location to store error on failure
2667  * @user_data: Function specific data
2668  * Returns: TRUE on success, FALSE on failure
2669  *
2670  * Getter for "scanning" property.
2671  */
2672 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
2673 				      void *user_data)
2674 {
2675 	struct wpa_supplicant *wpa_s = user_data;
2676 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2677 
2678 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2679 						&scanning, error);
2680 }
2681 
2682 
2683 /**
2684  * wpas_dbus_getter_ap_scan - Control roaming mode
2685  * @iter: Pointer to incoming dbus message iter
2686  * @error: Location to store error on failure
2687  * @user_data: Function specific data
2688  * Returns: TRUE on success, FALSE on failure
2689  *
2690  * Getter function for "ApScan" property.
2691  */
2692 dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
2693 				     void *user_data)
2694 {
2695 	struct wpa_supplicant *wpa_s = user_data;
2696 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2697 
2698 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2699 						&ap_scan, error);
2700 }
2701 
2702 
2703 /**
2704  * wpas_dbus_setter_ap_scan - Control roaming mode
2705  * @iter: Pointer to incoming dbus message iter
2706  * @error: Location to store error on failure
2707  * @user_data: Function specific data
2708  * Returns: TRUE on success, FALSE on failure
2709  *
2710  * Setter function for "ApScan" property.
2711  */
2712 dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
2713 				     void *user_data)
2714 {
2715 	struct wpa_supplicant *wpa_s = user_data;
2716 	dbus_uint32_t ap_scan;
2717 
2718 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2719 					      &ap_scan))
2720 		return FALSE;
2721 
2722 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2723 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2724 				     "ap_scan must be 0, 1, or 2");
2725 		return FALSE;
2726 	}
2727 	return TRUE;
2728 }
2729 
2730 
2731 /**
2732  * wpas_dbus_getter_fast_reauth - Control fast
2733  * reauthentication (TLS session resumption)
2734  * @iter: Pointer to incoming dbus message iter
2735  * @error: Location to store error on failure
2736  * @user_data: Function specific data
2737  * Returns: TRUE on success, FALSE on failure
2738  *
2739  * Getter function for "FastReauth" property.
2740  */
2741 dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
2742 					 DBusError *error,
2743 					 void *user_data)
2744 {
2745 	struct wpa_supplicant *wpa_s = user_data;
2746 	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
2747 
2748 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2749 						&fast_reauth, error);
2750 }
2751 
2752 
2753 /**
2754  * wpas_dbus_setter_fast_reauth - Control fast
2755  * reauthentication (TLS session resumption)
2756  * @iter: Pointer to incoming dbus message iter
2757  * @error: Location to store error on failure
2758  * @user_data: Function specific data
2759  * Returns: TRUE on success, FALSE on failure
2760  *
2761  * Setter function for "FastReauth" property.
2762  */
2763 dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
2764 				     DBusError *error,
2765 				     void *user_data)
2766 {
2767 	struct wpa_supplicant *wpa_s = user_data;
2768 	dbus_bool_t fast_reauth;
2769 
2770 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
2771 					      &fast_reauth))
2772 		return FALSE;
2773 
2774 	wpa_s->conf->fast_reauth = fast_reauth;
2775 	return TRUE;
2776 }
2777 
2778 
2779 /**
2780  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
2781  * @iter: Pointer to incoming dbus message iter
2782  * @error: Location to store error on failure
2783  * @user_data: Function specific data
2784  * Returns: TRUE on success, FALSE on failure
2785  *
2786  * Getter for "DisconnectReason" property.  The reason is negative if it is
2787  * locally generated.
2788  */
2789 dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
2790 					       DBusError *error,
2791 					       void *user_data)
2792 {
2793 	struct wpa_supplicant *wpa_s = user_data;
2794 	dbus_int32_t reason = wpa_s->disconnect_reason;
2795 
2796 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2797 						&reason, error);
2798 }
2799 
2800 
2801 /**
2802  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
2803  * @iter: Pointer to incoming dbus message iter
2804  * @error: Location to store error on failure
2805  * @user_data: Function specific data
2806  * Returns: TRUE on success, FALSE on failure
2807  *
2808  * Getter function for "BSSExpireAge" property.
2809  */
2810 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
2811 					    DBusError *error,
2812 					    void *user_data)
2813 {
2814 	struct wpa_supplicant *wpa_s = user_data;
2815 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
2816 
2817 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2818 						&expire_age, error);
2819 }
2820 
2821 
2822 /**
2823  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
2824  * @iter: Pointer to incoming dbus message iter
2825  * @error: Location to store error on failure
2826  * @user_data: Function specific data
2827  * Returns: TRUE on success, FALSE on failure
2828  *
2829  * Setter function for "BSSExpireAge" property.
2830  */
2831 dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
2832 					    DBusError *error,
2833 					    void *user_data)
2834 {
2835 	struct wpa_supplicant *wpa_s = user_data;
2836 	dbus_uint32_t expire_age;
2837 
2838 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2839 					      &expire_age))
2840 		return FALSE;
2841 
2842 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
2843 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2844 				     "BSSExpireAge must be >= 10");
2845 		return FALSE;
2846 	}
2847 	return TRUE;
2848 }
2849 
2850 
2851 /**
2852  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
2853  * @iter: Pointer to incoming dbus message iter
2854  * @error: Location to store error on failure
2855  * @user_data: Function specific data
2856  * Returns: TRUE on success, FALSE on failure
2857  *
2858  * Getter function for "BSSExpireCount" property.
2859  */
2860 dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
2861 					      DBusError *error,
2862 					      void *user_data)
2863 {
2864 	struct wpa_supplicant *wpa_s = user_data;
2865 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
2866 
2867 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2868 						&expire_count, error);
2869 }
2870 
2871 
2872 /**
2873  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
2874  * @iter: Pointer to incoming dbus message iter
2875  * @error: Location to store error on failure
2876  * @user_data: Function specific data
2877  * Returns: TRUE on success, FALSE on failure
2878  *
2879  * Setter function for "BSSExpireCount" property.
2880  */
2881 dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
2882 					      DBusError *error,
2883 					      void *user_data)
2884 {
2885 	struct wpa_supplicant *wpa_s = user_data;
2886 	dbus_uint32_t expire_count;
2887 
2888 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2889 					      &expire_count))
2890 		return FALSE;
2891 
2892 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
2893 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2894 				     "BSSExpireCount must be > 0");
2895 		return FALSE;
2896 	}
2897 	return TRUE;
2898 }
2899 
2900 
2901 /**
2902  * wpas_dbus_getter_country - Control country code
2903  * @iter: Pointer to incoming dbus message iter
2904  * @error: Location to store error on failure
2905  * @user_data: Function specific data
2906  * Returns: TRUE on success, FALSE on failure
2907  *
2908  * Getter function for "Country" property.
2909  */
2910 dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
2911 				     void *user_data)
2912 {
2913 	struct wpa_supplicant *wpa_s = user_data;
2914 	char country[3];
2915 	char *str = country;
2916 
2917 	country[0] = wpa_s->conf->country[0];
2918 	country[1] = wpa_s->conf->country[1];
2919 	country[2] = '\0';
2920 
2921 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2922 						&str, error);
2923 }
2924 
2925 
2926 /**
2927  * wpas_dbus_setter_country - Control country code
2928  * @iter: Pointer to incoming dbus message iter
2929  * @error: Location to store error on failure
2930  * @user_data: Function specific data
2931  * Returns: TRUE on success, FALSE on failure
2932  *
2933  * Setter function for "Country" property.
2934  */
2935 dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
2936 				     void *user_data)
2937 {
2938 	struct wpa_supplicant *wpa_s = user_data;
2939 	const char *country;
2940 
2941 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
2942 					      &country))
2943 		return FALSE;
2944 
2945 	if (!country[0] || !country[1]) {
2946 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2947 				     "invalid country code");
2948 		return FALSE;
2949 	}
2950 
2951 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
2952 		wpa_printf(MSG_DEBUG, "Failed to set country");
2953 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2954 				     "failed to set country code");
2955 		return FALSE;
2956 	}
2957 
2958 	wpa_s->conf->country[0] = country[0];
2959 	wpa_s->conf->country[1] = country[1];
2960 	return TRUE;
2961 }
2962 
2963 
2964 /**
2965  * wpas_dbus_getter_scan_interval - Get scan interval
2966  * @iter: Pointer to incoming dbus message iter
2967  * @error: Location to store error on failure
2968  * @user_data: Function specific data
2969  * Returns: TRUE on success, FALSE on failure
2970  *
2971  * Getter function for "ScanInterval" property.
2972  */
2973 dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
2974 					   DBusError *error,
2975 					   void *user_data)
2976 {
2977 	struct wpa_supplicant *wpa_s = user_data;
2978 	dbus_int32_t scan_interval = wpa_s->scan_interval;
2979 
2980 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2981 						&scan_interval, error);
2982 }
2983 
2984 
2985 /**
2986  * wpas_dbus_setter_scan_interval - Control scan interval
2987  * @iter: Pointer to incoming dbus message iter
2988  * @error: Location to store error on failure
2989  * @user_data: Function specific data
2990  * Returns: TRUE on success, FALSE on failure
2991  *
2992  * Setter function for "ScanInterval" property.
2993  */
2994 dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
2995 					   DBusError *error,
2996 					   void *user_data)
2997 {
2998 	struct wpa_supplicant *wpa_s = user_data;
2999 	dbus_int32_t scan_interval;
3000 
3001 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3002 					      &scan_interval))
3003 		return FALSE;
3004 
3005 	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3006 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3007 				     "scan_interval must be >= 0");
3008 		return FALSE;
3009 	}
3010 	return TRUE;
3011 }
3012 
3013 
3014 /**
3015  * wpas_dbus_getter_ifname - Get interface name
3016  * @iter: Pointer to incoming dbus message iter
3017  * @error: Location to store error on failure
3018  * @user_data: Function specific data
3019  * Returns: TRUE on success, FALSE on failure
3020  *
3021  * Getter for "Ifname" property.
3022  */
3023 dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
3024 				    void *user_data)
3025 {
3026 	struct wpa_supplicant *wpa_s = user_data;
3027 	const char *ifname = wpa_s->ifname;
3028 
3029 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3030 						&ifname, error);
3031 }
3032 
3033 
3034 /**
3035  * wpas_dbus_getter_driver - Get interface name
3036  * @iter: Pointer to incoming dbus message iter
3037  * @error: Location to store error on failure
3038  * @user_data: Function specific data
3039  * Returns: TRUE on success, FALSE on failure
3040  *
3041  * Getter for "Driver" property.
3042  */
3043 dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
3044 				    void *user_data)
3045 {
3046 	struct wpa_supplicant *wpa_s = user_data;
3047 	const char *driver;
3048 
3049 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3050 		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
3051 			   __func__);
3052 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3053 			       __func__);
3054 		return FALSE;
3055 	}
3056 
3057 	driver = wpa_s->driver->name;
3058 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3059 						&driver, error);
3060 }
3061 
3062 
3063 /**
3064  * wpas_dbus_getter_current_bss - Get current bss object path
3065  * @iter: Pointer to incoming dbus message iter
3066  * @error: Location to store error on failure
3067  * @user_data: Function specific data
3068  * Returns: TRUE on success, FALSE on failure
3069  *
3070  * Getter for "CurrentBSS" property.
3071  */
3072 dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
3073 					 DBusError *error,
3074 					 void *user_data)
3075 {
3076 	struct wpa_supplicant *wpa_s = user_data;
3077 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3078 
3079 	if (wpa_s->current_bss && wpa_s->dbus_new_path)
3080 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3081 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3082 			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3083 	else
3084 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3085 
3086 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3087 						&bss_obj_path, error);
3088 }
3089 
3090 
3091 /**
3092  * wpas_dbus_getter_current_network - Get current network object path
3093  * @iter: Pointer to incoming dbus message iter
3094  * @error: Location to store error on failure
3095  * @user_data: Function specific data
3096  * Returns: TRUE on success, FALSE on failure
3097  *
3098  * Getter for "CurrentNetwork" property.
3099  */
3100 dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
3101 					     DBusError *error,
3102 					     void *user_data)
3103 {
3104 	struct wpa_supplicant *wpa_s = user_data;
3105 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3106 
3107 	if (wpa_s->current_ssid && wpa_s->dbus_new_path)
3108 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3109 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3110 			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3111 	else
3112 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3113 
3114 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3115 						&net_obj_path, error);
3116 }
3117 
3118 
3119 /**
3120  * wpas_dbus_getter_current_auth_mode - Get current authentication type
3121  * @iter: Pointer to incoming dbus message iter
3122  * @error: Location to store error on failure
3123  * @user_data: Function specific data
3124  * Returns: TRUE on success, FALSE on failure
3125  *
3126  * Getter for "CurrentAuthMode" property.
3127  */
3128 dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
3129 					       DBusError *error,
3130 					       void *user_data)
3131 {
3132 	struct wpa_supplicant *wpa_s = user_data;
3133 	const char *eap_mode;
3134 	const char *auth_mode;
3135 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3136 
3137 	if (wpa_s->wpa_state != WPA_COMPLETED) {
3138 		auth_mode = "INACTIVE";
3139 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3140 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3141 		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3142 		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3143 			    "EAP-%s", eap_mode);
3144 		auth_mode = eap_mode_buf;
3145 
3146 	} else {
3147 		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3148 					     wpa_s->current_ssid->proto);
3149 	}
3150 
3151 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3152 						&auth_mode, error);
3153 }
3154 
3155 
3156 /**
3157  * wpas_dbus_getter_bridge_ifname - Get interface name
3158  * @iter: Pointer to incoming dbus message iter
3159  * @error: Location to store error on failure
3160  * @user_data: Function specific data
3161  * Returns: TRUE on success, FALSE on failure
3162  *
3163  * Getter for "BridgeIfname" property.
3164  */
3165 dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
3166 					   DBusError *error,
3167 					   void *user_data)
3168 {
3169 	struct wpa_supplicant *wpa_s = user_data;
3170 	const char *bridge_ifname = wpa_s->bridge_ifname;
3171 
3172 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3173 						&bridge_ifname, error);
3174 }
3175 
3176 
3177 /**
3178  * wpas_dbus_getter_bsss - Get array of BSSs objects
3179  * @iter: Pointer to incoming dbus message iter
3180  * @error: Location to store error on failure
3181  * @user_data: Function specific data
3182  * Returns: TRUE on success, FALSE on failure
3183  *
3184  * Getter for "BSSs" property.
3185  */
3186 dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
3187 				  void *user_data)
3188 {
3189 	struct wpa_supplicant *wpa_s = user_data;
3190 	struct wpa_bss *bss;
3191 	char **paths;
3192 	unsigned int i = 0;
3193 	dbus_bool_t success = FALSE;
3194 
3195 	if (!wpa_s->dbus_new_path) {
3196 		dbus_set_error(error, DBUS_ERROR_FAILED,
3197 			       "%s: no D-Bus interface", __func__);
3198 		return FALSE;
3199 	}
3200 
3201 	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3202 	if (!paths) {
3203 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3204 		return FALSE;
3205 	}
3206 
3207 	/* Loop through scan results and append each result's object path */
3208 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3209 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3210 		if (paths[i] == NULL) {
3211 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3212 					     "no memory");
3213 			goto out;
3214 		}
3215 		/* Construct the object path for this BSS. */
3216 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3217 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3218 			    wpa_s->dbus_new_path, bss->id);
3219 	}
3220 
3221 	success = wpas_dbus_simple_array_property_getter(iter,
3222 							 DBUS_TYPE_OBJECT_PATH,
3223 							 paths, wpa_s->num_bss,
3224 							 error);
3225 
3226 out:
3227 	while (i)
3228 		os_free(paths[--i]);
3229 	os_free(paths);
3230 	return success;
3231 }
3232 
3233 
3234 /**
3235  * wpas_dbus_getter_networks - Get array of networks objects
3236  * @iter: Pointer to incoming dbus message iter
3237  * @error: Location to store error on failure
3238  * @user_data: Function specific data
3239  * Returns: TRUE on success, FALSE on failure
3240  *
3241  * Getter for "Networks" property.
3242  */
3243 dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
3244 				      void *user_data)
3245 {
3246 	struct wpa_supplicant *wpa_s = user_data;
3247 	struct wpa_ssid *ssid;
3248 	char **paths;
3249 	unsigned int i = 0, num = 0;
3250 	dbus_bool_t success = FALSE;
3251 
3252 	if (!wpa_s->dbus_new_path) {
3253 		dbus_set_error(error, DBUS_ERROR_FAILED,
3254 			       "%s: no D-Bus interface", __func__);
3255 		return FALSE;
3256 	}
3257 
3258 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3259 		if (!network_is_persistent_group(ssid))
3260 			num++;
3261 
3262 	paths = os_calloc(num, sizeof(char *));
3263 	if (!paths) {
3264 		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3265 		return FALSE;
3266 	}
3267 
3268 	/* Loop through configured networks and append object path of each */
3269 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3270 		if (network_is_persistent_group(ssid))
3271 			continue;
3272 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3273 		if (paths[i] == NULL) {
3274 			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
3275 				       "no memory");
3276 			goto out;
3277 		}
3278 
3279 		/* Construct the object path for this network. */
3280 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3281 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3282 			    wpa_s->dbus_new_path, ssid->id);
3283 	}
3284 
3285 	success = wpas_dbus_simple_array_property_getter(iter,
3286 							 DBUS_TYPE_OBJECT_PATH,
3287 							 paths, num, error);
3288 
3289 out:
3290 	while (i)
3291 		os_free(paths[--i]);
3292 	os_free(paths);
3293 	return success;
3294 }
3295 
3296 
3297 /**
3298  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3299  * @iter: Pointer to incoming dbus message iter
3300  * @error: Location to store error on failure
3301  * @user_data: Function specific data
3302  * Returns: A dbus message containing the PKCS #11 engine path
3303  *
3304  * Getter for "PKCS11EnginePath" property.
3305  */
3306 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
3307 						DBusError *error,
3308 						void *user_data)
3309 {
3310 	struct wpa_supplicant *wpa_s = user_data;
3311 	const char *pkcs11_engine_path;
3312 
3313 	if (wpa_s->conf->pkcs11_engine_path == NULL)
3314 		pkcs11_engine_path = "";
3315 	else
3316 		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
3317 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3318 						&pkcs11_engine_path, error);
3319 }
3320 
3321 
3322 /**
3323  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3324  * @iter: Pointer to incoming dbus message iter
3325  * @error: Location to store error on failure
3326  * @user_data: Function specific data
3327  * Returns: A dbus message containing the PKCS #11 module path
3328  *
3329  * Getter for "PKCS11ModulePath" property.
3330  */
3331 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
3332 						DBusError *error,
3333 						void *user_data)
3334 {
3335 	struct wpa_supplicant *wpa_s = user_data;
3336 	const char *pkcs11_module_path;
3337 
3338 	if (wpa_s->conf->pkcs11_module_path == NULL)
3339 		pkcs11_module_path = "";
3340 	else
3341 		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
3342 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3343 						&pkcs11_module_path, error);
3344 }
3345 
3346 
3347 /**
3348  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3349  * @iter: Pointer to incoming dbus message iter
3350  * @error: Location to store error on failure
3351  * @user_data: Function specific data
3352  * Returns: TRUE on success, FALSE on failure
3353  *
3354  * Getter for "Blobs" property.
3355  */
3356 dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
3357 				   void *user_data)
3358 {
3359 	struct wpa_supplicant *wpa_s = user_data;
3360 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3361 	struct wpa_config_blob *blob;
3362 
3363 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3364 					      "a{say}", &variant_iter) ||
3365 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3366 					      "{say}", &dict_iter)) {
3367 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3368 		return FALSE;
3369 	}
3370 
3371 	blob = wpa_s->conf->blobs;
3372 	while (blob) {
3373 		if (!dbus_message_iter_open_container(&dict_iter,
3374 						      DBUS_TYPE_DICT_ENTRY,
3375 						      NULL, &entry_iter) ||
3376 		    !dbus_message_iter_append_basic(&entry_iter,
3377 						    DBUS_TYPE_STRING,
3378 						    &(blob->name)) ||
3379 		    !dbus_message_iter_open_container(&entry_iter,
3380 						      DBUS_TYPE_ARRAY,
3381 						      DBUS_TYPE_BYTE_AS_STRING,
3382 						      &array_iter) ||
3383 		    !dbus_message_iter_append_fixed_array(&array_iter,
3384 							  DBUS_TYPE_BYTE,
3385 							  &(blob->data),
3386 							  blob->len) ||
3387 		    !dbus_message_iter_close_container(&entry_iter,
3388 						       &array_iter) ||
3389 		    !dbus_message_iter_close_container(&dict_iter,
3390 						       &entry_iter)) {
3391 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3392 					     "no memory");
3393 			return FALSE;
3394 		}
3395 
3396 		blob = blob->next;
3397 	}
3398 
3399 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3400 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3401 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3402 		return FALSE;
3403 	}
3404 
3405 	return TRUE;
3406 }
3407 
3408 
3409 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
3410 				       DBusError *error, const char *func_name)
3411 {
3412 	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
3413 
3414 	if (!res) {
3415 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
3416 			   func_name, args->id);
3417 		dbus_set_error(error, DBUS_ERROR_FAILED,
3418 			       "%s: BSS %d not found",
3419 			       func_name, args->id);
3420 	}
3421 
3422 	return res;
3423 }
3424 
3425 
3426 /**
3427  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
3428  * @iter: Pointer to incoming dbus message iter
3429  * @error: Location to store error on failure
3430  * @user_data: Function specific data
3431  * Returns: TRUE on success, FALSE on failure
3432  *
3433  * Getter for "BSSID" property.
3434  */
3435 dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
3436 				       void *user_data)
3437 {
3438 	struct bss_handler_args *args = user_data;
3439 	struct wpa_bss *res;
3440 
3441 	res = get_bss_helper(args, error, __func__);
3442 	if (!res)
3443 		return FALSE;
3444 
3445 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3446 						      res->bssid, ETH_ALEN,
3447 						      error);
3448 }
3449 
3450 
3451 /**
3452  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
3453  * @iter: Pointer to incoming dbus message iter
3454  * @error: Location to store error on failure
3455  * @user_data: Function specific data
3456  * Returns: TRUE on success, FALSE on failure
3457  *
3458  * Getter for "SSID" property.
3459  */
3460 dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
3461 				      void *user_data)
3462 {
3463 	struct bss_handler_args *args = user_data;
3464 	struct wpa_bss *res;
3465 
3466 	res = get_bss_helper(args, error, __func__);
3467 	if (!res)
3468 		return FALSE;
3469 
3470 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3471 						      res->ssid, res->ssid_len,
3472 						      error);
3473 }
3474 
3475 
3476 /**
3477  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
3478  * @iter: Pointer to incoming dbus message iter
3479  * @error: Location to store error on failure
3480  * @user_data: Function specific data
3481  * Returns: TRUE on success, FALSE on failure
3482  *
3483  * Getter for "Privacy" property.
3484  */
3485 dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
3486 					 DBusError *error, void *user_data)
3487 {
3488 	struct bss_handler_args *args = user_data;
3489 	struct wpa_bss *res;
3490 	dbus_bool_t privacy;
3491 
3492 	res = get_bss_helper(args, error, __func__);
3493 	if (!res)
3494 		return FALSE;
3495 
3496 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
3497 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3498 						&privacy, error);
3499 }
3500 
3501 
3502 /**
3503  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
3504  * @iter: Pointer to incoming dbus message iter
3505  * @error: Location to store error on failure
3506  * @user_data: Function specific data
3507  * Returns: TRUE on success, FALSE on failure
3508  *
3509  * Getter for "Mode" property.
3510  */
3511 dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
3512 				      void *user_data)
3513 {
3514 	struct bss_handler_args *args = user_data;
3515 	struct wpa_bss *res;
3516 	const char *mode;
3517 
3518 	res = get_bss_helper(args, error, __func__);
3519 	if (!res)
3520 		return FALSE;
3521 	if (bss_is_dmg(res)) {
3522 		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
3523 		case IEEE80211_CAP_DMG_PBSS:
3524 		case IEEE80211_CAP_DMG_IBSS:
3525 			mode = "ad-hoc";
3526 			break;
3527 		case IEEE80211_CAP_DMG_AP:
3528 			mode = "infrastructure";
3529 			break;
3530 		}
3531 	} else {
3532 		if (res->caps & IEEE80211_CAP_IBSS)
3533 			mode = "ad-hoc";
3534 		else
3535 			mode = "infrastructure";
3536 	}
3537 
3538 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3539 						&mode, error);
3540 }
3541 
3542 
3543 /**
3544  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
3545  * @iter: Pointer to incoming dbus message iter
3546  * @error: Location to store error on failure
3547  * @user_data: Function specific data
3548  * Returns: TRUE on success, FALSE on failure
3549  *
3550  * Getter for "Level" property.
3551  */
3552 dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
3553 					DBusError *error, void *user_data)
3554 {
3555 	struct bss_handler_args *args = user_data;
3556 	struct wpa_bss *res;
3557 	s16 level;
3558 
3559 	res = get_bss_helper(args, error, __func__);
3560 	if (!res)
3561 		return FALSE;
3562 
3563 	level = (s16) res->level;
3564 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3565 						&level, error);
3566 }
3567 
3568 
3569 /**
3570  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
3571  * @iter: Pointer to incoming dbus message iter
3572  * @error: Location to store error on failure
3573  * @user_data: Function specific data
3574  * Returns: TRUE on success, FALSE on failure
3575  *
3576  * Getter for "Frequency" property.
3577  */
3578 dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
3579 					   DBusError *error, void *user_data)
3580 {
3581 	struct bss_handler_args *args = user_data;
3582 	struct wpa_bss *res;
3583 	u16 freq;
3584 
3585 	res = get_bss_helper(args, error, __func__);
3586 	if (!res)
3587 		return FALSE;
3588 
3589 	freq = (u16) res->freq;
3590 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3591 						&freq, error);
3592 }
3593 
3594 
3595 static int cmp_u8s_desc(const void *a, const void *b)
3596 {
3597 	return (*(u8 *) b - *(u8 *) a);
3598 }
3599 
3600 
3601 /**
3602  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
3603  * @iter: Pointer to incoming dbus message iter
3604  * @error: Location to store error on failure
3605  * @user_data: Function specific data
3606  * Returns: TRUE on success, FALSE on failure
3607  *
3608  * Getter for "Rates" property.
3609  */
3610 dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
3611 				       DBusError *error, void *user_data)
3612 {
3613 	struct bss_handler_args *args = user_data;
3614 	struct wpa_bss *res;
3615 	u8 *ie_rates = NULL;
3616 	u32 *real_rates;
3617 	int rates_num, i;
3618 	dbus_bool_t success = FALSE;
3619 
3620 	res = get_bss_helper(args, error, __func__);
3621 	if (!res)
3622 		return FALSE;
3623 
3624 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
3625 	if (rates_num < 0)
3626 		return FALSE;
3627 
3628 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
3629 
3630 	real_rates = os_malloc(sizeof(u32) * rates_num);
3631 	if (!real_rates) {
3632 		os_free(ie_rates);
3633 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3634 		return FALSE;
3635 	}
3636 
3637 	for (i = 0; i < rates_num; i++)
3638 		real_rates[i] = ie_rates[i] * 500000;
3639 
3640 	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
3641 							 real_rates, rates_num,
3642 							 error);
3643 
3644 	os_free(ie_rates);
3645 	os_free(real_rates);
3646 	return success;
3647 }
3648 
3649 
3650 static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
3651 						   struct wpa_ie_data *ie_data,
3652 						   DBusError *error)
3653 {
3654 	DBusMessageIter iter_dict, variant_iter;
3655 	const char *group;
3656 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
3657 	const char *key_mgmt[9]; /* max 9 key managements may be supported */
3658 	int n;
3659 
3660 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3661 					      "a{sv}", &variant_iter))
3662 		goto nomem;
3663 
3664 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3665 		goto nomem;
3666 
3667 	/* KeyMgmt */
3668 	n = 0;
3669 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
3670 		key_mgmt[n++] = "wpa-psk";
3671 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
3672 		key_mgmt[n++] = "wpa-ft-psk";
3673 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
3674 		key_mgmt[n++] = "wpa-psk-sha256";
3675 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
3676 		key_mgmt[n++] = "wpa-eap";
3677 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
3678 		key_mgmt[n++] = "wpa-ft-eap";
3679 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
3680 		key_mgmt[n++] = "wpa-eap-sha256";
3681 #ifdef CONFIG_SUITEB
3682 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
3683 		key_mgmt[n++] = "wpa-eap-suite-b";
3684 #endif /* CONFIG_SUITEB */
3685 #ifdef CONFIG_SUITEB192
3686 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
3687 		key_mgmt[n++] = "wpa-eap-suite-b-192";
3688 #endif /* CONFIG_SUITEB192 */
3689 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
3690 		key_mgmt[n++] = "wpa-none";
3691 
3692 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
3693 					       key_mgmt, n))
3694 		goto nomem;
3695 
3696 	/* Group */
3697 	switch (ie_data->group_cipher) {
3698 	case WPA_CIPHER_WEP40:
3699 		group = "wep40";
3700 		break;
3701 	case WPA_CIPHER_TKIP:
3702 		group = "tkip";
3703 		break;
3704 	case WPA_CIPHER_CCMP:
3705 		group = "ccmp";
3706 		break;
3707 	case WPA_CIPHER_GCMP:
3708 		group = "gcmp";
3709 		break;
3710 	case WPA_CIPHER_WEP104:
3711 		group = "wep104";
3712 		break;
3713 	case WPA_CIPHER_CCMP_256:
3714 		group = "ccmp-256";
3715 		break;
3716 	case WPA_CIPHER_GCMP_256:
3717 		group = "gcmp-256";
3718 		break;
3719 	default:
3720 		group = "";
3721 		break;
3722 	}
3723 
3724 	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
3725 		goto nomem;
3726 
3727 	/* Pairwise */
3728 	n = 0;
3729 	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
3730 		pairwise[n++] = "tkip";
3731 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
3732 		pairwise[n++] = "ccmp";
3733 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
3734 		pairwise[n++] = "gcmp";
3735 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
3736 		pairwise[n++] = "ccmp-256";
3737 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
3738 		pairwise[n++] = "gcmp-256";
3739 
3740 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
3741 					       pairwise, n))
3742 		goto nomem;
3743 
3744 	/* Management group (RSN only) */
3745 	if (ie_data->proto == WPA_PROTO_RSN) {
3746 		switch (ie_data->mgmt_group_cipher) {
3747 #ifdef CONFIG_IEEE80211W
3748 		case WPA_CIPHER_AES_128_CMAC:
3749 			group = "aes128cmac";
3750 			break;
3751 #endif /* CONFIG_IEEE80211W */
3752 		default:
3753 			group = "";
3754 			break;
3755 		}
3756 
3757 		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
3758 						 group))
3759 			goto nomem;
3760 	}
3761 
3762 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3763 	    !dbus_message_iter_close_container(iter, &variant_iter))
3764 		goto nomem;
3765 
3766 	return TRUE;
3767 
3768 nomem:
3769 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3770 	return FALSE;
3771 }
3772 
3773 
3774 /**
3775  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
3776  * @iter: Pointer to incoming dbus message iter
3777  * @error: Location to store error on failure
3778  * @user_data: Function specific data
3779  * Returns: TRUE on success, FALSE on failure
3780  *
3781  * Getter for "WPA" property.
3782  */
3783 dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
3784 				     void *user_data)
3785 {
3786 	struct bss_handler_args *args = user_data;
3787 	struct wpa_bss *res;
3788 	struct wpa_ie_data wpa_data;
3789 	const u8 *ie;
3790 
3791 	res = get_bss_helper(args, error, __func__);
3792 	if (!res)
3793 		return FALSE;
3794 
3795 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3796 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
3797 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3798 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3799 				     "failed to parse WPA IE");
3800 		return FALSE;
3801 	}
3802 
3803 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3804 }
3805 
3806 
3807 /**
3808  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
3809  * @iter: Pointer to incoming dbus message iter
3810  * @error: Location to store error on failure
3811  * @user_data: Function specific data
3812  * Returns: TRUE on success, FALSE on failure
3813  *
3814  * Getter for "RSN" property.
3815  */
3816 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
3817 				     void *user_data)
3818 {
3819 	struct bss_handler_args *args = user_data;
3820 	struct wpa_bss *res;
3821 	struct wpa_ie_data wpa_data;
3822 	const u8 *ie;
3823 
3824 	res = get_bss_helper(args, error, __func__);
3825 	if (!res)
3826 		return FALSE;
3827 
3828 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3829 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
3830 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3831 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3832 				     "failed to parse RSN IE");
3833 		return FALSE;
3834 	}
3835 
3836 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3837 }
3838 
3839 
3840 /**
3841  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
3842  * @iter: Pointer to incoming dbus message iter
3843  * @error: Location to store error on failure
3844  * @user_data: Function specific data
3845  * Returns: TRUE on success, FALSE on failure
3846  *
3847  * Getter for "WPS" property.
3848  */
3849 dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
3850 				     void *user_data)
3851 {
3852 	struct bss_handler_args *args = user_data;
3853 	struct wpa_bss *res;
3854 #ifdef CONFIG_WPS
3855 	struct wpabuf *wps_ie;
3856 #endif /* CONFIG_WPS */
3857 	DBusMessageIter iter_dict, variant_iter;
3858 	int wps_support = 0;
3859 	const char *type = "";
3860 
3861 	res = get_bss_helper(args, error, __func__);
3862 	if (!res)
3863 		return FALSE;
3864 
3865 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3866 					      "a{sv}", &variant_iter) ||
3867 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3868 		goto nomem;
3869 
3870 #ifdef CONFIG_WPS
3871 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
3872 	if (wps_ie) {
3873 		wps_support = 1;
3874 		if (wps_is_selected_pbc_registrar(wps_ie))
3875 			type = "pbc";
3876 		else if (wps_is_selected_pin_registrar(wps_ie))
3877 			type = "pin";
3878 
3879 		wpabuf_free(wps_ie);
3880 	}
3881 #endif /* CONFIG_WPS */
3882 
3883 	if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
3884 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3885 	    !dbus_message_iter_close_container(iter, &variant_iter))
3886 		goto nomem;
3887 
3888 	return TRUE;
3889 
3890 nomem:
3891 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3892 	return FALSE;
3893 }
3894 
3895 
3896 /**
3897  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
3898  * @iter: Pointer to incoming dbus message iter
3899  * @error: Location to store error on failure
3900  * @user_data: Function specific data
3901  * Returns: TRUE on success, FALSE on failure
3902  *
3903  * Getter for "IEs" property.
3904  */
3905 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
3906 				     void *user_data)
3907 {
3908 	struct bss_handler_args *args = user_data;
3909 	struct wpa_bss *res;
3910 
3911 	res = get_bss_helper(args, error, __func__);
3912 	if (!res)
3913 		return FALSE;
3914 
3915 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3916 						      res + 1, res->ie_len,
3917 						      error);
3918 }
3919 
3920 
3921 /**
3922  * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
3923  * @iter: Pointer to incoming dbus message iter
3924  * @error: Location to store error on failure
3925  * @user_data: Function specific data
3926  * Returns: TRUE on success, FALSE on failure
3927  *
3928  * Getter for BSS age
3929  */
3930 dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
3931 				     void *user_data)
3932 {
3933 	struct bss_handler_args *args = user_data;
3934 	struct wpa_bss *res;
3935 	struct os_reltime now, diff = { 0, 0 };
3936 	u32 age;
3937 
3938 	res = get_bss_helper(args, error, __func__);
3939 	if (!res)
3940 		return FALSE;
3941 
3942 	os_get_reltime(&now);
3943 	os_reltime_sub(&now, &res->last_update, &diff);
3944 	age = diff.sec > 0 ? diff.sec : 0;
3945 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
3946 						error);
3947 }
3948 
3949 
3950 /**
3951  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
3952  * @iter: Pointer to incoming dbus message iter
3953  * @error: Location to store error on failure
3954  * @user_data: Function specific data
3955  * Returns: TRUE on success, FALSE on failure
3956  *
3957  * Getter for "enabled" property of a configured network.
3958  */
3959 dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
3960 				     void *user_data)
3961 {
3962 	struct network_handler_args *net = user_data;
3963 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
3964 
3965 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3966 						&enabled, error);
3967 }
3968 
3969 
3970 /**
3971  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
3972  * @iter: Pointer to incoming dbus message iter
3973  * @error: Location to store error on failure
3974  * @user_data: Function specific data
3975  * Returns: TRUE on success, FALSE on failure
3976  *
3977  * Setter for "Enabled" property of a configured network.
3978  */
3979 dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
3980 				     void *user_data)
3981 {
3982 	struct network_handler_args *net = user_data;
3983 	struct wpa_supplicant *wpa_s;
3984 	struct wpa_ssid *ssid;
3985 	dbus_bool_t enable;
3986 
3987 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3988 					      &enable))
3989 		return FALSE;
3990 
3991 	wpa_s = net->wpa_s;
3992 	ssid = net->ssid;
3993 
3994 	if (enable)
3995 		wpa_supplicant_enable_network(wpa_s, ssid);
3996 	else
3997 		wpa_supplicant_disable_network(wpa_s, ssid);
3998 
3999 	return TRUE;
4000 }
4001 
4002 
4003 /**
4004  * wpas_dbus_getter_network_properties - Get options for a configured network
4005  * @iter: Pointer to incoming dbus message iter
4006  * @error: Location to store error on failure
4007  * @user_data: Function specific data
4008  * Returns: TRUE on success, FALSE on failure
4009  *
4010  * Getter for "Properties" property of a configured network.
4011  */
4012 dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
4013 						DBusError *error,
4014 						void *user_data)
4015 {
4016 	struct network_handler_args *net = user_data;
4017 	DBusMessageIter	variant_iter, dict_iter;
4018 	char **iterator;
4019 	char **props = wpa_config_get_all(net->ssid, 1);
4020 	dbus_bool_t success = FALSE;
4021 
4022 	if (!props) {
4023 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4024 		return FALSE;
4025 	}
4026 
4027 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4028 					      &variant_iter) ||
4029 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
4030 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4031 		goto out;
4032 	}
4033 
4034 	iterator = props;
4035 	while (*iterator) {
4036 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
4037 						 *(iterator + 1))) {
4038 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4039 					     "no memory");
4040 			goto out;
4041 		}
4042 		iterator += 2;
4043 	}
4044 
4045 
4046 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
4047 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4048 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4049 		goto out;
4050 	}
4051 
4052 	success = TRUE;
4053 
4054 out:
4055 	iterator = props;
4056 	while (*iterator) {
4057 		os_free(*iterator);
4058 		iterator++;
4059 	}
4060 	os_free(props);
4061 	return success;
4062 }
4063 
4064 
4065 /**
4066  * wpas_dbus_setter_network_properties - Set options for a configured network
4067  * @iter: Pointer to incoming dbus message iter
4068  * @error: Location to store error on failure
4069  * @user_data: Function specific data
4070  * Returns: TRUE on success, FALSE on failure
4071  *
4072  * Setter for "Properties" property of a configured network.
4073  */
4074 dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
4075 						DBusError *error,
4076 						void *user_data)
4077 {
4078 	struct network_handler_args *net = user_data;
4079 	struct wpa_ssid *ssid = net->ssid;
4080 	DBusMessageIter	variant_iter;
4081 
4082 	dbus_message_iter_recurse(iter, &variant_iter);
4083 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4084 }
4085 
4086 
4087 #ifdef CONFIG_AP
4088 
4089 DBusMessage * wpas_dbus_handler_subscribe_preq(
4090 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4091 {
4092 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4093 	char *name;
4094 
4095 	if (wpa_s->preq_notify_peer != NULL) {
4096 		if (os_strcmp(dbus_message_get_sender(message),
4097 			      wpa_s->preq_notify_peer) == 0)
4098 			return NULL;
4099 
4100 		return dbus_message_new_error(message,
4101 			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4102 			"Another application is already subscribed");
4103 	}
4104 
4105 	name = os_strdup(dbus_message_get_sender(message));
4106 	if (!name)
4107 		return wpas_dbus_error_no_memory(message);
4108 
4109 	wpa_s->preq_notify_peer = name;
4110 
4111 	/* Subscribe to clean up if application closes socket */
4112 	wpas_dbus_subscribe_noc(priv);
4113 
4114 	/*
4115 	 * Double-check it's still alive to make sure that we didn't
4116 	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4117 	 */
4118 	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4119 		/*
4120 		 * Application no longer exists, clean up.
4121 		 * The return value is irrelevant now.
4122 		 *
4123 		 * Need to check if the NameOwnerChanged handling
4124 		 * already cleaned up because we have processed
4125 		 * DBus messages while checking if the name still
4126 		 * has an owner.
4127 		 */
4128 		if (!wpa_s->preq_notify_peer)
4129 			return NULL;
4130 		os_free(wpa_s->preq_notify_peer);
4131 		wpa_s->preq_notify_peer = NULL;
4132 		wpas_dbus_unsubscribe_noc(priv);
4133 	}
4134 
4135 	return NULL;
4136 }
4137 
4138 
4139 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
4140 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4141 {
4142 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4143 
4144 	if (!wpa_s->preq_notify_peer)
4145 		return dbus_message_new_error(message,
4146 			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
4147 			"Not subscribed");
4148 
4149 	if (os_strcmp(wpa_s->preq_notify_peer,
4150 		      dbus_message_get_sender(message)))
4151 		return dbus_message_new_error(message,
4152 			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
4153 			"Can't unsubscribe others");
4154 
4155 	os_free(wpa_s->preq_notify_peer);
4156 	wpa_s->preq_notify_peer = NULL;
4157 	wpas_dbus_unsubscribe_noc(priv);
4158 	return NULL;
4159 }
4160 
4161 
4162 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
4163 			   const u8 *addr, const u8 *dst, const u8 *bssid,
4164 			   const u8 *ie, size_t ie_len, u32 ssi_signal)
4165 {
4166 	DBusMessage *msg;
4167 	DBusMessageIter iter, dict_iter;
4168 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4169 
4170 	/* Do nothing if the control interface is not turned on */
4171 	if (priv == NULL || !wpa_s->dbus_new_path)
4172 		return;
4173 
4174 	if (wpa_s->preq_notify_peer == NULL)
4175 		return;
4176 
4177 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4178 				      WPAS_DBUS_NEW_IFACE_INTERFACE,
4179 				      "ProbeRequest");
4180 	if (msg == NULL)
4181 		return;
4182 
4183 	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
4184 
4185 	dbus_message_iter_init_append(msg, &iter);
4186 
4187 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
4188 	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
4189 						      (const char *) addr,
4190 						      ETH_ALEN)) ||
4191 	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
4192 						     (const char *) dst,
4193 						     ETH_ALEN)) ||
4194 	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
4195 						       (const char *) bssid,
4196 						       ETH_ALEN)) ||
4197 	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
4198 							      (const char *) ie,
4199 							      ie_len)) ||
4200 	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
4201 						       ssi_signal)) ||
4202 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
4203 		goto fail;
4204 
4205 	dbus_connection_send(priv->con, msg, NULL);
4206 	goto out;
4207 fail:
4208 	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4209 out:
4210 	dbus_message_unref(msg);
4211 }
4212 
4213 #endif /* CONFIG_AP */
4214