xref: /freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c (revision 963f5dc7a30624e95d72fb7f87b8892651164e46)
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 "ap/hostapd.h"
19 #include "ap/sta_info.h"
20 #include "ap/ap_drv_ops.h"
21 #include "../config.h"
22 #include "../wpa_supplicant_i.h"
23 #include "../driver_i.h"
24 #include "../notify.h"
25 #include "../bss.h"
26 #include "../scan.h"
27 #include "../autoscan.h"
28 #include "../ap.h"
29 #include "dbus_new_helpers.h"
30 #include "dbus_new.h"
31 #include "dbus_new_handlers.h"
32 #include "dbus_dict_helpers.h"
33 #include "dbus_common_i.h"
34 #include "drivers/driver.h"
35 #ifdef CONFIG_MESH
36 #include "ap/hostapd.h"
37 #include "ap/sta_info.h"
38 #endif /* CONFIG_MESH */
39 
40 static const char * const debug_strings[] = {
41 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
42 };
43 
44 
45 /**
46  * wpas_dbus_error_unknown_error - Return a new UnknownError error message
47  * @message: Pointer to incoming dbus message this error refers to
48  * @arg: Optional string appended to error message
49  * Returns: a dbus error message
50  *
51  * Convenience function to create and return an UnknownError
52  */
53 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
54 					    const char *arg)
55 {
56 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
57 				      arg);
58 }
59 
60 
61 /**
62  * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
63  * @message: Pointer to incoming dbus message this error refers to
64  * Returns: A dbus error message
65  *
66  * Convenience function to create and return an invalid interface error
67  */
68 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
69 {
70 	return dbus_message_new_error(
71 		message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
72 		"wpa_supplicant knows nothing about this interface.");
73 }
74 
75 
76 /**
77  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
78  * @message: Pointer to incoming dbus message this error refers to
79  * Returns: a dbus error message
80  *
81  * Convenience function to create and return an invalid network error
82  */
83 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
84 {
85 	return dbus_message_new_error(
86 		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
87 		"There is no such a network in this interface.");
88 }
89 
90 
91 /**
92  * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
93  * @message: Pointer to incoming dbus message this error refers to
94  * Returns: a dbus error message
95  *
96  * Convenience function to create and return an invalid options error
97  */
98 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
99 					  const char *arg)
100 {
101 	DBusMessage *reply;
102 
103 	reply = dbus_message_new_error(
104 		message, WPAS_DBUS_ERROR_INVALID_ARGS,
105 		"Did not receive correct message arguments.");
106 	if (arg != NULL)
107 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
108 					 DBUS_TYPE_INVALID);
109 
110 	return reply;
111 }
112 
113 
114 /**
115  * wpas_dbus_error_scan_error - Return a new ScanError error message
116  * @message: Pointer to incoming dbus message this error refers to
117  * @error: Optional string to be used as the error message
118  * Returns: a dbus error message
119  *
120  * Convenience function to create and return a scan error
121  */
122 static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
123 						const char *error)
124 {
125 	return dbus_message_new_error(message,
126 				      WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
127 				      error);
128 }
129 
130 
131 DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
132 {
133 	wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
134 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
135 }
136 
137 
138 static const char * const dont_quote[] = {
139 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
140 	"bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
141 	"bssid_ignore", "bssid_accept", /* deprecated aliases */
142 	"bssid_blacklist", "bssid_whitelist",
143 	"group_mgmt",
144 	"ignore_broadcast_ssid",
145 #ifdef CONFIG_MESH
146 	"mesh_basic_rates",
147 #endif /* CONFIG_MESH */
148 #ifdef CONFIG_P2P
149 	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
150 #endif /* CONFIG_P2P */
151 	NULL
152 };
153 
154 static dbus_bool_t should_quote_opt(const char *key)
155 {
156 	int i = 0;
157 
158 	while (dont_quote[i] != NULL) {
159 		if (os_strcmp(key, dont_quote[i]) == 0)
160 			return FALSE;
161 		i++;
162 	}
163 	return TRUE;
164 }
165 
166 /**
167  * get_iface_by_dbus_path - Get a new network interface
168  * @global: Pointer to global data from wpa_supplicant_init()
169  * @path: Pointer to a dbus object path representing an interface
170  * Returns: Pointer to the interface or %NULL if not found
171  */
172 static struct wpa_supplicant * get_iface_by_dbus_path(
173 	struct wpa_global *global, const char *path)
174 {
175 	struct wpa_supplicant *wpa_s;
176 
177 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
178 		if (wpa_s->dbus_new_path &&
179 		    os_strcmp(wpa_s->dbus_new_path, path) == 0)
180 			return wpa_s;
181 	}
182 	return NULL;
183 }
184 
185 
186 /**
187  * set_network_properties - Set properties of a configured network
188  * @wpa_s: wpa_supplicant structure for a network interface
189  * @ssid: wpa_ssid structure for a configured network
190  * @iter: DBus message iterator containing dictionary of network
191  * properties to set.
192  * @error: On failure, an error describing the failure
193  * Returns: TRUE if the request succeeds, FALSE if it failed
194  *
195  * Sets network configuration with parameters given id DBus dictionary
196  */
197 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
198 				   struct wpa_ssid *ssid,
199 				   DBusMessageIter *iter,
200 				   DBusError *error)
201 {
202 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
203 	DBusMessageIter	iter_dict;
204 	char *value = NULL;
205 
206 	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
207 		return FALSE;
208 
209 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
210 		size_t size = 50;
211 		int ret;
212 
213 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
214 			goto error;
215 
216 		value = NULL;
217 		if (entry.type == DBUS_TYPE_ARRAY &&
218 		    entry.array_type == DBUS_TYPE_BYTE) {
219 			if (entry.array_len <= 0)
220 				goto error;
221 
222 			size = entry.array_len * 2 + 1;
223 			value = os_zalloc(size);
224 			if (value == NULL)
225 				goto error;
226 
227 			ret = wpa_snprintf_hex(value, size,
228 					       (u8 *) entry.bytearray_value,
229 					       entry.array_len);
230 			if (ret <= 0)
231 				goto error;
232 		} else if (entry.type == DBUS_TYPE_STRING) {
233 			if (should_quote_opt(entry.key)) {
234 				size = os_strlen(entry.str_value);
235 
236 				size += 3;
237 				value = os_zalloc(size);
238 				if (value == NULL)
239 					goto error;
240 
241 				ret = os_snprintf(value, size, "\"%s\"",
242 						  entry.str_value);
243 				if (os_snprintf_error(size, ret))
244 					goto error;
245 			} else {
246 				value = os_strdup(entry.str_value);
247 				if (value == NULL)
248 					goto error;
249 			}
250 		} else if (entry.type == DBUS_TYPE_UINT32) {
251 			value = os_zalloc(size);
252 			if (value == NULL)
253 				goto error;
254 
255 			ret = os_snprintf(value, size, "%u",
256 					  entry.uint32_value);
257 			if (os_snprintf_error(size, ret))
258 				goto error;
259 		} else if (entry.type == DBUS_TYPE_INT32) {
260 			value = os_zalloc(size);
261 			if (value == NULL)
262 				goto error;
263 
264 			ret = os_snprintf(value, size, "%d",
265 					  entry.int32_value);
266 			if (os_snprintf_error(size, ret))
267 				goto error;
268 		} else
269 			goto error;
270 
271 		ret = wpa_config_set(ssid, entry.key, value, 0);
272 		if (ret < 0)
273 			goto error;
274 		if (ret == 1)
275 			goto skip_update;
276 
277 #ifdef CONFIG_BGSCAN
278 		if (os_strcmp(entry.key, "bgscan") == 0) {
279 			/*
280 			 * Reset the bgscan parameters for the current network
281 			 * and continue. There's no need to flush caches for
282 			 * bgscan parameter changes.
283 			 */
284 			if (wpa_s->current_ssid == ssid &&
285 			    wpa_s->wpa_state == WPA_COMPLETED)
286 				wpa_supplicant_reset_bgscan(wpa_s);
287 			os_free(value);
288 			value = NULL;
289 			wpa_dbus_dict_entry_clear(&entry);
290 			continue;
291 		}
292 #endif /* CONFIG_BGSCAN */
293 
294 		if (os_strcmp(entry.key, "bssid") != 0 &&
295 		    os_strcmp(entry.key, "priority") != 0)
296 			wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
297 
298 		if (wpa_s->current_ssid == ssid ||
299 		    wpa_s->current_ssid == NULL) {
300 			/*
301 			 * Invalidate the EAP session cache if anything in the
302 			 * current or previously used configuration changes.
303 			 */
304 			eapol_sm_invalidate_cached_session(wpa_s->eapol);
305 		}
306 
307 		if ((os_strcmp(entry.key, "psk") == 0 &&
308 		     value[0] == '"' && ssid->ssid_len) ||
309 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
310 			wpa_config_update_psk(ssid);
311 		else if (os_strcmp(entry.key, "priority") == 0)
312 			wpa_config_update_prio_list(wpa_s->conf);
313 
314 	skip_update:
315 		os_free(value);
316 		value = NULL;
317 		wpa_dbus_dict_entry_clear(&entry);
318 	}
319 
320 	return TRUE;
321 
322 error:
323 	os_free(value);
324 	wpa_dbus_dict_entry_clear(&entry);
325 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
326 			     "invalid message format");
327 	return FALSE;
328 }
329 
330 
331 /**
332  * wpas_dbus_simple_property_getter - Get basic type property
333  * @iter: Message iter to use when appending arguments
334  * @type: DBus type of property (must be basic type)
335  * @val: pointer to place holding property value
336  * @error: On failure an error describing the failure
337  * Returns: TRUE if the request was successful, FALSE if it failed
338  *
339  * Generic getter for basic type properties. Type is required to be basic.
340  */
341 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
342 					     const int type,
343 					     const void *val,
344 					     DBusError *error)
345 {
346 	DBusMessageIter variant_iter;
347 
348 	if (!dbus_type_is_basic(type)) {
349 		dbus_set_error(error, DBUS_ERROR_FAILED,
350 			       "%s: given type is not basic", __func__);
351 		return FALSE;
352 	}
353 
354 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
355 					      wpa_dbus_type_as_string(type),
356 					      &variant_iter) ||
357 	    !dbus_message_iter_append_basic(&variant_iter, type, val) ||
358 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
359 		dbus_set_error(error, DBUS_ERROR_FAILED,
360 			       "%s: error constructing reply", __func__);
361 		return FALSE;
362 	}
363 
364 	return TRUE;
365 }
366 
367 
368 /**
369  * wpas_dbus_simple_property_setter - Set basic type property
370  * @message: Pointer to incoming dbus message
371  * @type: DBus type of property (must be basic type)
372  * @val: pointer to place where value being set will be stored
373  * Returns: TRUE if the request was successful, FALSE if it failed
374  *
375  * Generic setter for basic type properties. Type is required to be basic.
376  */
377 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
378 					     DBusError *error,
379 					     const int type, void *val)
380 {
381 	DBusMessageIter variant_iter;
382 
383 	if (!dbus_type_is_basic(type)) {
384 		dbus_set_error(error, DBUS_ERROR_FAILED,
385 			       "%s: given type is not basic", __func__);
386 		return FALSE;
387 	}
388 
389 	/* Look at the new value */
390 	dbus_message_iter_recurse(iter, &variant_iter);
391 	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
392 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
393 				     "wrong property type");
394 		return FALSE;
395 	}
396 	dbus_message_iter_get_basic(&variant_iter, val);
397 
398 	return TRUE;
399 }
400 
401 
402 /**
403  * wpas_dbus_simple_array_property_getter - Get array type property
404  * @iter: Pointer to incoming dbus message iterator
405  * @type: DBus type of property array elements (must be basic type)
406  * @array: pointer to array of elements to put into response message
407  * @array_len: length of above array
408  * @error: a pointer to an error to fill on failure
409  * Returns: TRUE if the request succeeded, FALSE if it failed
410  *
411  * Generic getter for array type properties. Array elements type is
412  * required to be basic.
413  */
414 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
415 						   const int type,
416 						   const void *array,
417 						   size_t array_len,
418 						   DBusError *error)
419 {
420 	DBusMessageIter variant_iter, array_iter;
421 	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
422 	const char *sub_type_str;
423 	size_t element_size, i;
424 
425 	if (!dbus_type_is_basic(type)) {
426 		dbus_set_error(error, DBUS_ERROR_FAILED,
427 			       "%s: given type is not basic", __func__);
428 		return FALSE;
429 	}
430 
431 	sub_type_str = wpa_dbus_type_as_string(type);
432 	type_str[1] = sub_type_str[0];
433 
434 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
435 					      type_str, &variant_iter) ||
436 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
437 					      sub_type_str, &array_iter)) {
438 		dbus_set_error(error, DBUS_ERROR_FAILED,
439 			       "%s: failed to construct message", __func__);
440 		return FALSE;
441 	}
442 
443 	switch (type) {
444 	case DBUS_TYPE_BYTE:
445 	case DBUS_TYPE_BOOLEAN:
446 		element_size = 1;
447 		break;
448 	case DBUS_TYPE_INT16:
449 	case DBUS_TYPE_UINT16:
450 		element_size = sizeof(uint16_t);
451 		break;
452 	case DBUS_TYPE_INT32:
453 	case DBUS_TYPE_UINT32:
454 		element_size = sizeof(uint32_t);
455 		break;
456 	case DBUS_TYPE_INT64:
457 	case DBUS_TYPE_UINT64:
458 		element_size = sizeof(uint64_t);
459 		break;
460 	case DBUS_TYPE_DOUBLE:
461 		element_size = sizeof(double);
462 		break;
463 	case DBUS_TYPE_STRING:
464 	case DBUS_TYPE_OBJECT_PATH:
465 		element_size = sizeof(char *);
466 		break;
467 	default:
468 		dbus_set_error(error, DBUS_ERROR_FAILED,
469 			       "%s: unknown element type %d", __func__, type);
470 		return FALSE;
471 	}
472 
473 	for (i = 0; i < array_len; i++) {
474 		if (!dbus_message_iter_append_basic(&array_iter, type,
475 						    (const char *) array +
476 						    i * element_size)) {
477 			dbus_set_error(error, DBUS_ERROR_FAILED,
478 				       "%s: failed to construct message 2.5",
479 				       __func__);
480 			return FALSE;
481 		}
482 	}
483 
484 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
485 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
486 		dbus_set_error(error, DBUS_ERROR_FAILED,
487 			       "%s: failed to construct message 3", __func__);
488 		return FALSE;
489 	}
490 
491 	return TRUE;
492 }
493 
494 
495 /**
496  * wpas_dbus_simple_array_array_property_getter - Get array array type property
497  * @iter: Pointer to incoming dbus message iterator
498  * @type: DBus type of property array elements (must be basic type)
499  * @array: pointer to array of elements to put into response message
500  * @array_len: length of above array
501  * @error: a pointer to an error to fill on failure
502  * Returns: TRUE if the request succeeded, FALSE if it failed
503  *
504  * Generic getter for array type properties. Array elements type is
505  * required to be basic.
506  */
507 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
508 							 const int type,
509 							 struct wpabuf **array,
510 							 size_t array_len,
511 							 DBusError *error)
512 {
513 	DBusMessageIter variant_iter, array_iter;
514 	char type_str[] = "aa?";
515 	char inner_type_str[] = "a?";
516 	const char *sub_type_str;
517 	size_t i;
518 
519 	if (!dbus_type_is_basic(type)) {
520 		dbus_set_error(error, DBUS_ERROR_FAILED,
521 			       "%s: given type is not basic", __func__);
522 		return FALSE;
523 	}
524 
525 	sub_type_str = wpa_dbus_type_as_string(type);
526 	type_str[2] = sub_type_str[0];
527 	inner_type_str[1] = sub_type_str[0];
528 
529 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
530 					      type_str, &variant_iter) ||
531 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
532 					      inner_type_str, &array_iter)) {
533 		dbus_set_error(error, DBUS_ERROR_FAILED,
534 			       "%s: failed to construct message", __func__);
535 		return FALSE;
536 	}
537 
538 	for (i = 0; i < array_len && array[i]; i++) {
539 		wpa_dbus_dict_bin_array_add_element(&array_iter,
540 						    wpabuf_head(array[i]),
541 						    wpabuf_len(array[i]));
542 
543 	}
544 
545 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
546 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
547 		dbus_set_error(error, DBUS_ERROR_FAILED,
548 			       "%s: failed to close message", __func__);
549 		return FALSE;
550 	}
551 
552 	return TRUE;
553 }
554 
555 
556 /**
557  * wpas_dbus_string_property_getter - Get string type property
558  * @iter: Message iter to use when appending arguments
559  * @val: Pointer to place holding property value, can be %NULL
560  * @error: On failure an error describing the failure
561  * Returns: TRUE if the request was successful, FALSE if it failed
562  *
563  * Generic getter for string type properties. %NULL is converted to an empty
564  * string.
565  */
566 dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
567 					     const void *val,
568 					     DBusError *error)
569 {
570 	if (!val)
571 		val = "";
572 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
573 						&val, error);
574 }
575 
576 
577 /**
578  * wpas_dbus_handler_create_interface - Request registration of a network iface
579  * @message: Pointer to incoming dbus message
580  * @global: %wpa_supplicant global data structure
581  * Returns: The object path of the new interface object,
582  *          or a dbus error message with more information
583  *
584  * Handler function for "CreateInterface" method call. Handles requests
585  * by dbus clients to register a network interface that wpa_supplicant
586  * will manage.
587  */
588 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
589 						 struct wpa_global *global)
590 {
591 	DBusMessageIter iter_dict;
592 	DBusMessage *reply = NULL;
593 	DBusMessageIter iter;
594 	struct wpa_dbus_dict_entry entry;
595 	char *driver = NULL;
596 	char *ifname = NULL;
597 	char *confname = NULL;
598 	char *bridge_ifname = NULL;
599 
600 	dbus_message_iter_init(message, &iter);
601 
602 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
603 		goto error;
604 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
605 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
606 			goto error;
607 		if (os_strcmp(entry.key, "Driver") == 0 &&
608 		    entry.type == DBUS_TYPE_STRING) {
609 			os_free(driver);
610 			driver = os_strdup(entry.str_value);
611 			wpa_dbus_dict_entry_clear(&entry);
612 			if (driver == NULL)
613 				goto oom;
614 		} else if (os_strcmp(entry.key, "Ifname") == 0 &&
615 			   entry.type == DBUS_TYPE_STRING) {
616 			os_free(ifname);
617 			ifname = os_strdup(entry.str_value);
618 			wpa_dbus_dict_entry_clear(&entry);
619 			if (ifname == NULL)
620 				goto oom;
621 		} else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
622 			   entry.type == DBUS_TYPE_STRING) {
623 			os_free(confname);
624 			confname = os_strdup(entry.str_value);
625 			wpa_dbus_dict_entry_clear(&entry);
626 			if (confname == NULL)
627 				goto oom;
628 		} else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
629 			   entry.type == DBUS_TYPE_STRING) {
630 			os_free(bridge_ifname);
631 			bridge_ifname = os_strdup(entry.str_value);
632 			wpa_dbus_dict_entry_clear(&entry);
633 			if (bridge_ifname == NULL)
634 				goto oom;
635 		} else {
636 			wpa_dbus_dict_entry_clear(&entry);
637 			goto error;
638 		}
639 	}
640 
641 	if (ifname == NULL)
642 		goto error; /* Required Ifname argument missing */
643 
644 	/*
645 	 * Try to get the wpa_supplicant record for this iface, return
646 	 * an error if we already control it.
647 	 */
648 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
649 		reply = dbus_message_new_error(
650 			message, WPAS_DBUS_ERROR_IFACE_EXISTS,
651 			"wpa_supplicant already controls this interface.");
652 	} else {
653 		struct wpa_supplicant *wpa_s;
654 		struct wpa_interface iface;
655 
656 		os_memset(&iface, 0, sizeof(iface));
657 		iface.driver = driver;
658 		iface.ifname = ifname;
659 		iface.confname = confname;
660 		iface.bridge_ifname = bridge_ifname;
661 		/* Otherwise, have wpa_supplicant attach to it. */
662 		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
663 		if (wpa_s && wpa_s->dbus_new_path) {
664 			const char *path = wpa_s->dbus_new_path;
665 
666 			reply = dbus_message_new_method_return(message);
667 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
668 						 &path, DBUS_TYPE_INVALID);
669 		} else {
670 			reply = wpas_dbus_error_unknown_error(
671 				message,
672 				"wpa_supplicant couldn't grab this interface.");
673 		}
674 	}
675 
676 out:
677 	os_free(driver);
678 	os_free(ifname);
679 	os_free(confname);
680 	os_free(bridge_ifname);
681 	return reply;
682 
683 error:
684 	reply = wpas_dbus_error_invalid_args(message, NULL);
685 	goto out;
686 oom:
687 	reply = wpas_dbus_error_no_memory(message);
688 	goto out;
689 }
690 
691 
692 /**
693  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
694  * @message: Pointer to incoming dbus message
695  * @global: wpa_supplicant global data structure
696  * Returns: a dbus message containing a UINT32 indicating success (1) or
697  *          failure (0), or returns a dbus error message with more information
698  *
699  * Handler function for "removeInterface" method call.  Handles requests
700  * by dbus clients to deregister a network interface that wpa_supplicant
701  * currently manages.
702  */
703 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
704 						 struct wpa_global *global)
705 {
706 	struct wpa_supplicant *wpa_s;
707 	char *path;
708 	DBusMessage *reply = NULL;
709 
710 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
711 			      DBUS_TYPE_INVALID);
712 
713 	wpa_s = get_iface_by_dbus_path(global, path);
714 	if (wpa_s == NULL)
715 		reply = wpas_dbus_error_iface_unknown(message);
716 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
717 		reply = wpas_dbus_error_unknown_error(
718 			message,
719 			"wpa_supplicant couldn't remove this interface.");
720 	}
721 
722 	return reply;
723 }
724 
725 
726 /**
727  * wpas_dbus_handler_get_interface - Get the object path for an interface name
728  * @message: Pointer to incoming dbus message
729  * @global: %wpa_supplicant global data structure
730  * Returns: The object path of the interface object,
731  *          or a dbus error message with more information
732  *
733  * Handler function for "getInterface" method call.
734  */
735 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
736 					      struct wpa_global *global)
737 {
738 	DBusMessage *reply = NULL;
739 	const char *ifname;
740 	const char *path;
741 	struct wpa_supplicant *wpa_s;
742 
743 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
744 			      DBUS_TYPE_INVALID);
745 
746 	wpa_s = wpa_supplicant_get_iface(global, ifname);
747 	if (wpa_s == NULL || wpa_s->dbus_new_path == NULL)
748 		return wpas_dbus_error_iface_unknown(message);
749 
750 	path = wpa_s->dbus_new_path;
751 	reply = dbus_message_new_method_return(message);
752 	if (reply == NULL)
753 		return wpas_dbus_error_no_memory(message);
754 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
755 				      DBUS_TYPE_INVALID)) {
756 		dbus_message_unref(reply);
757 		return wpas_dbus_error_no_memory(message);
758 	}
759 
760 	return reply;
761 }
762 
763 
764 /**
765  * wpas_dbus_getter_debug_level - Get debug level
766  * @iter: Pointer to incoming dbus message iter
767  * @error: Location to store error on failure
768  * @user_data: Function specific data
769  * Returns: TRUE on success, FALSE on failure
770  *
771  * Getter for "DebugLevel" property.
772  */
773 dbus_bool_t wpas_dbus_getter_debug_level(
774 	const struct wpa_dbus_property_desc *property_desc,
775 	DBusMessageIter *iter, DBusError *error, void *user_data)
776 {
777 	const char *str;
778 	int idx = wpa_debug_level;
779 
780 	if (idx < 0)
781 		idx = 0;
782 	if (idx > 5)
783 		idx = 5;
784 	str = debug_strings[idx];
785 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
786 						&str, error);
787 }
788 
789 
790 /**
791  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
792  * @iter: Pointer to incoming dbus message iter
793  * @error: Location to store error on failure
794  * @user_data: Function specific data
795  * Returns: TRUE on success, FALSE on failure
796  *
797  * Getter for "DebugTimestamp" property.
798  */
799 dbus_bool_t wpas_dbus_getter_debug_timestamp(
800 	const struct wpa_dbus_property_desc *property_desc,
801 	DBusMessageIter *iter, DBusError *error, void *user_data)
802 {
803 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
804 						&wpa_debug_timestamp, error);
805 
806 }
807 
808 
809 /**
810  * wpas_dbus_getter_debug_show_keys - Get debug show keys
811  * @iter: Pointer to incoming dbus message iter
812  * @error: Location to store error on failure
813  * @user_data: Function specific data
814  * Returns: TRUE on success, FALSE on failure
815  *
816  * Getter for "DebugShowKeys" property.
817  */
818 dbus_bool_t wpas_dbus_getter_debug_show_keys(
819 	const struct wpa_dbus_property_desc *property_desc,
820 	DBusMessageIter *iter, DBusError *error, void *user_data)
821 {
822 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
823 						&wpa_debug_show_keys, error);
824 
825 }
826 
827 /**
828  * wpas_dbus_setter_debug_level - Set debug level
829  * @iter: Pointer to incoming dbus message iter
830  * @error: Location to store error on failure
831  * @user_data: Function specific data
832  * Returns: TRUE on success, FALSE on failure
833  *
834  * Setter for "DebugLevel" property.
835  */
836 dbus_bool_t wpas_dbus_setter_debug_level(
837 	const struct wpa_dbus_property_desc *property_desc,
838 	DBusMessageIter *iter, DBusError *error, void *user_data)
839 {
840 	struct wpa_global *global = user_data;
841 	const char *str = NULL;
842 	int i, val = -1;
843 
844 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
845 					      &str))
846 		return FALSE;
847 
848 	for (i = 0; debug_strings[i]; i++)
849 		if (os_strcmp(debug_strings[i], str) == 0) {
850 			val = i;
851 			break;
852 		}
853 
854 	if (val < 0 ||
855 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
856 					    wpa_debug_show_keys)) {
857 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
858 				     "wrong debug level value");
859 		return FALSE;
860 	}
861 
862 	return TRUE;
863 }
864 
865 
866 /**
867  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
868  * @iter: Pointer to incoming dbus message iter
869  * @error: Location to store error on failure
870  * @user_data: Function specific data
871  * Returns: TRUE on success, FALSE on failure
872  *
873  * Setter for "DebugTimestamp" property.
874  */
875 dbus_bool_t wpas_dbus_setter_debug_timestamp(
876 	const struct wpa_dbus_property_desc *property_desc,
877 	DBusMessageIter *iter, DBusError *error, void *user_data)
878 {
879 	struct wpa_global *global = user_data;
880 	dbus_bool_t val;
881 
882 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
883 					      &val))
884 		return FALSE;
885 
886 	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
887 					wpa_debug_show_keys);
888 	return TRUE;
889 }
890 
891 
892 /**
893  * wpas_dbus_setter_debug_show_keys - Set debug show keys
894  * @iter: Pointer to incoming dbus message iter
895  * @error: Location to store error on failure
896  * @user_data: Function specific data
897  * Returns: TRUE on success, FALSE on failure
898  *
899  * Setter for "DebugShowKeys" property.
900  */
901 dbus_bool_t wpas_dbus_setter_debug_show_keys(
902 	const struct wpa_dbus_property_desc *property_desc,
903 	DBusMessageIter *iter, DBusError *error, void *user_data)
904 {
905 	struct wpa_global *global = user_data;
906 	dbus_bool_t val;
907 
908 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
909 					      &val))
910 		return FALSE;
911 
912 	wpa_supplicant_set_debug_params(global, wpa_debug_level,
913 					wpa_debug_timestamp,
914 					val ? 1 : 0);
915 	return TRUE;
916 }
917 
918 
919 /**
920  * wpas_dbus_getter_interfaces - Request registered interfaces list
921  * @iter: Pointer to incoming dbus message iter
922  * @error: Location to store error on failure
923  * @user_data: Function specific data
924  * Returns: TRUE on success, FALSE on failure
925  *
926  * Getter for "Interfaces" property. Handles requests
927  * by dbus clients to return list of registered interfaces objects
928  * paths
929  */
930 dbus_bool_t wpas_dbus_getter_interfaces(
931 	const struct wpa_dbus_property_desc *property_desc,
932 	DBusMessageIter *iter, DBusError *error, void *user_data)
933 {
934 	struct wpa_global *global = user_data;
935 	struct wpa_supplicant *wpa_s;
936 	const char **paths;
937 	unsigned int i = 0, num = 0;
938 	dbus_bool_t success;
939 
940 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
941 		if (wpa_s->dbus_new_path)
942 			num++;
943 	}
944 
945 	paths = os_calloc(num, sizeof(char *));
946 	if (!paths) {
947 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
948 		return FALSE;
949 	}
950 
951 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
952 		if (wpa_s->dbus_new_path)
953 			paths[i++] = wpa_s->dbus_new_path;
954 	}
955 
956 	success = wpas_dbus_simple_array_property_getter(iter,
957 							 DBUS_TYPE_OBJECT_PATH,
958 							 paths, num, error);
959 
960 	os_free(paths);
961 	return success;
962 }
963 
964 
965 /**
966  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
967  * @iter: Pointer to incoming dbus message iter
968  * @error: Location to store error on failure
969  * @user_data: Function specific data
970  * Returns: TRUE on success, FALSE on failure
971  *
972  * Getter for "EapMethods" property. Handles requests
973  * by dbus clients to return list of strings with supported EAP methods
974  */
975 dbus_bool_t wpas_dbus_getter_eap_methods(
976 	const struct wpa_dbus_property_desc *property_desc,
977 	DBusMessageIter *iter, DBusError *error, void *user_data)
978 {
979 	char **eap_methods;
980 	size_t num_items = 0;
981 	dbus_bool_t success;
982 
983 	eap_methods = eap_get_names_as_string_array(&num_items);
984 	if (!eap_methods) {
985 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
986 		return FALSE;
987 	}
988 
989 	success = wpas_dbus_simple_array_property_getter(iter,
990 							 DBUS_TYPE_STRING,
991 							 eap_methods,
992 							 num_items, error);
993 
994 	while (num_items)
995 		os_free(eap_methods[--num_items]);
996 	os_free(eap_methods);
997 	return success;
998 }
999 
1000 
1001 /**
1002  * wpas_dbus_getter_global_capabilities - Request supported global capabilities
1003  * @iter: Pointer to incoming dbus message iter
1004  * @error: Location to store error on failure
1005  * @user_data: Function specific data
1006  * Returns: TRUE on success, FALSE on failure
1007  *
1008  * Getter for "Capabilities" property. Handles requests by dbus clients to
1009  * return a list of strings with supported capabilities like AP, RSN IBSS,
1010  * and P2P that are determined at compile time.
1011  */
1012 dbus_bool_t wpas_dbus_getter_global_capabilities(
1013 	const struct wpa_dbus_property_desc *property_desc,
1014 	DBusMessageIter *iter, DBusError *error, void *user_data)
1015 {
1016 	const char *capabilities[13];
1017 	size_t num_items = 0;
1018 	struct wpa_global *global = user_data;
1019 	struct wpa_supplicant *wpa_s;
1020 #ifdef CONFIG_FILS
1021 	int fils_supported = 0, fils_sk_pfs_supported = 0;
1022 #endif /* CONFIG_FILS */
1023 	int ext_key_id_supported = 0;
1024 
1025 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
1026 #ifdef CONFIG_FILS
1027 		if (wpa_is_fils_supported(wpa_s))
1028 			fils_supported = 1;
1029 		if (wpa_is_fils_sk_pfs_supported(wpa_s))
1030 			fils_sk_pfs_supported = 1;
1031 #endif /* CONFIG_FILS */
1032 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
1033 			ext_key_id_supported = 1;
1034 	}
1035 
1036 #ifdef CONFIG_AP
1037 	capabilities[num_items++] = "ap";
1038 #endif /* CONFIG_AP */
1039 #ifdef CONFIG_IBSS_RSN
1040 	capabilities[num_items++] = "ibss-rsn";
1041 #endif /* CONFIG_IBSS_RSN */
1042 #ifdef CONFIG_P2P
1043 	capabilities[num_items++] = "p2p";
1044 #endif /* CONFIG_P2P */
1045 #ifdef CONFIG_INTERWORKING
1046 	capabilities[num_items++] = "interworking";
1047 #endif /* CONFIG_INTERWORKING */
1048 	capabilities[num_items++] = "pmf";
1049 #ifdef CONFIG_MESH
1050 	capabilities[num_items++] = "mesh";
1051 #endif /* CONFIG_MESH */
1052 #ifdef CONFIG_FILS
1053 	if (fils_supported)
1054 		capabilities[num_items++] = "fils";
1055 	if (fils_sk_pfs_supported)
1056 		capabilities[num_items++] = "fils_sk_pfs";
1057 #endif /* CONFIG_FILS */
1058 #ifdef CONFIG_IEEE80211R
1059 	capabilities[num_items++] = "ft";
1060 #endif /* CONFIG_IEEE80211R */
1061 #ifdef CONFIG_SHA384
1062 	capabilities[num_items++] = "sha384";
1063 #endif /* CONFIG_SHA384 */
1064 #ifdef CONFIG_OWE
1065 	capabilities[num_items++] = "owe";
1066 #endif /* CONFIG_OWE */
1067 #ifdef CONFIG_SUITEB192
1068 	capabilities[num_items++] = "suiteb192";
1069 #endif /* CONFIG_SUITEB192 */
1070 	if (ext_key_id_supported)
1071 		capabilities[num_items++] = "extended_key_id";
1072 
1073 	return wpas_dbus_simple_array_property_getter(iter,
1074 						      DBUS_TYPE_STRING,
1075 						      capabilities,
1076 						      num_items, error);
1077 }
1078 
1079 
1080 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
1081 				   char **type, DBusMessage **reply)
1082 {
1083 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
1084 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
1085 			   __func__);
1086 		*reply = wpas_dbus_error_invalid_args(
1087 			message, "Wrong Type value type. String required");
1088 		return -1;
1089 	}
1090 	dbus_message_iter_get_basic(var, type);
1091 	return 0;
1092 }
1093 
1094 
1095 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1096 				    struct wpa_driver_scan_params *params,
1097 				    DBusMessage **reply)
1098 {
1099 	struct wpa_driver_scan_ssid *ssids = params->ssids;
1100 	size_t ssids_num = 0;
1101 	u8 *ssid;
1102 	DBusMessageIter array_iter, sub_array_iter;
1103 	char *val;
1104 	int len;
1105 
1106 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1107 		wpa_printf(MSG_DEBUG,
1108 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1109 			   __func__);
1110 		*reply = wpas_dbus_error_invalid_args(
1111 			message,
1112 			"Wrong SSIDs value type. Array of arrays of bytes required");
1113 		return -1;
1114 	}
1115 
1116 	dbus_message_iter_recurse(var, &array_iter);
1117 
1118 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1119 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1120 		wpa_printf(MSG_DEBUG,
1121 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1122 			   __func__);
1123 		*reply = wpas_dbus_error_invalid_args(
1124 			message,
1125 			"Wrong SSIDs value type. Array of arrays of bytes required");
1126 		return -1;
1127 	}
1128 
1129 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1130 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1131 			wpa_printf(MSG_DEBUG,
1132 				   "%s[dbus]: Too many ssids specified on scan dbus call",
1133 				   __func__);
1134 			*reply = wpas_dbus_error_invalid_args(
1135 				message,
1136 				"Too many ssids specified. Specify at most four");
1137 			return -1;
1138 		}
1139 
1140 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1141 
1142 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1143 
1144 		if (len > SSID_MAX_LEN) {
1145 			wpa_printf(MSG_DEBUG,
1146 				   "%s[dbus]: SSID too long (len=%d max_len=%d)",
1147 				   __func__, len, SSID_MAX_LEN);
1148 			*reply = wpas_dbus_error_invalid_args(
1149 				message, "Invalid SSID: too long");
1150 			return -1;
1151 		}
1152 
1153 		if (len != 0) {
1154 			ssid = os_memdup(val, len);
1155 			if (ssid == NULL) {
1156 				*reply = wpas_dbus_error_no_memory(message);
1157 				return -1;
1158 			}
1159 		} else {
1160 			/* Allow zero-length SSIDs */
1161 			ssid = NULL;
1162 		}
1163 
1164 		ssids[ssids_num].ssid = ssid;
1165 		ssids[ssids_num].ssid_len = len;
1166 
1167 		dbus_message_iter_next(&array_iter);
1168 		ssids_num++;
1169 	}
1170 
1171 	params->num_ssids = ssids_num;
1172 	return 0;
1173 }
1174 
1175 
1176 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1177 				  struct wpa_driver_scan_params *params,
1178 				  DBusMessage **reply)
1179 {
1180 	u8 *ies = NULL, *nies;
1181 	size_t ies_len = 0;
1182 	DBusMessageIter array_iter, sub_array_iter;
1183 	char *val;
1184 	int len;
1185 
1186 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1187 		wpa_printf(MSG_DEBUG,
1188 			   "%s[dbus]: ies must be an array of arrays of bytes",
1189 			   __func__);
1190 		*reply = wpas_dbus_error_invalid_args(
1191 			message,
1192 			"Wrong IEs value type. Array of arrays of bytes required");
1193 		return -1;
1194 	}
1195 
1196 	dbus_message_iter_recurse(var, &array_iter);
1197 
1198 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1199 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1200 		wpa_printf(MSG_DEBUG,
1201 			   "%s[dbus]: ies must be an array of arrays of bytes",
1202 			   __func__);
1203 		*reply = wpas_dbus_error_invalid_args(
1204 			message, "Wrong IEs value type. Array required");
1205 		return -1;
1206 	}
1207 
1208 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1209 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1210 
1211 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1212 		if (len <= 0) {
1213 			dbus_message_iter_next(&array_iter);
1214 			continue;
1215 		}
1216 
1217 		nies = os_realloc(ies, ies_len + len);
1218 		if (nies == NULL) {
1219 			os_free(ies);
1220 			*reply = wpas_dbus_error_no_memory(message);
1221 			return -1;
1222 		}
1223 		ies = nies;
1224 		os_memcpy(ies + ies_len, val, len);
1225 		ies_len += len;
1226 
1227 		dbus_message_iter_next(&array_iter);
1228 	}
1229 
1230 	params->extra_ies = ies;
1231 	params->extra_ies_len = ies_len;
1232 	return 0;
1233 }
1234 
1235 
1236 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1237 				       DBusMessageIter *var,
1238 				       struct wpa_driver_scan_params *params,
1239 				       DBusMessage **reply)
1240 {
1241 	DBusMessageIter array_iter, sub_array_iter;
1242 	int *freqs = NULL, *nfreqs;
1243 	size_t freqs_num = 0;
1244 
1245 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1246 		wpa_printf(MSG_DEBUG,
1247 			   "%s[dbus]: Channels must be an array of structs",
1248 			   __func__);
1249 		*reply = wpas_dbus_error_invalid_args(
1250 			message,
1251 			"Wrong Channels value type. Array of structs required");
1252 		return -1;
1253 	}
1254 
1255 	dbus_message_iter_recurse(var, &array_iter);
1256 
1257 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1258 		wpa_printf(MSG_DEBUG,
1259 			   "%s[dbus]: Channels must be an array of structs",
1260 			   __func__);
1261 		*reply = wpas_dbus_error_invalid_args(
1262 			message,
1263 			"Wrong Channels value type. Array of structs required");
1264 		return -1;
1265 	}
1266 
1267 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1268 	{
1269 		int freq, width;
1270 
1271 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1272 
1273 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1274 		    DBUS_TYPE_UINT32) {
1275 			wpa_printf(MSG_DEBUG,
1276 				   "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
1277 				   __func__,
1278 				   dbus_message_iter_get_arg_type(
1279 					   &sub_array_iter));
1280 			*reply = wpas_dbus_error_invalid_args(
1281 				message,
1282 				"Wrong Channel struct. Two UINT32s required");
1283 			os_free(freqs);
1284 			return -1;
1285 		}
1286 		dbus_message_iter_get_basic(&sub_array_iter, &freq);
1287 
1288 		if (!dbus_message_iter_next(&sub_array_iter) ||
1289 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
1290 		    DBUS_TYPE_UINT32) {
1291 			wpa_printf(MSG_DEBUG,
1292 				   "%s[dbus]: Channel must by specified by struct of two UINT32s",
1293 				   __func__);
1294 			*reply = wpas_dbus_error_invalid_args(
1295 				message,
1296 				"Wrong Channel struct. Two UINT32s required");
1297 			os_free(freqs);
1298 			return -1;
1299 		}
1300 
1301 		dbus_message_iter_get_basic(&sub_array_iter, &width);
1302 
1303 #define FREQS_ALLOC_CHUNK 32
1304 		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1305 			nfreqs = os_realloc_array(
1306 				freqs, freqs_num + FREQS_ALLOC_CHUNK,
1307 				sizeof(int));
1308 			if (nfreqs == NULL)
1309 				os_free(freqs);
1310 			freqs = nfreqs;
1311 		}
1312 		if (freqs == NULL) {
1313 			*reply = wpas_dbus_error_no_memory(message);
1314 			return -1;
1315 		}
1316 
1317 		freqs[freqs_num] = freq;
1318 
1319 		freqs_num++;
1320 		dbus_message_iter_next(&array_iter);
1321 	}
1322 
1323 	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1324 	if (nfreqs == NULL)
1325 		os_free(freqs);
1326 	freqs = nfreqs;
1327 	if (freqs == NULL) {
1328 		*reply = wpas_dbus_error_no_memory(message);
1329 		return -1;
1330 	}
1331 	freqs[freqs_num] = 0;
1332 
1333 	params->freqs = freqs;
1334 	return 0;
1335 }
1336 
1337 
1338 static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1339 					 DBusMessageIter *var,
1340 					 dbus_bool_t *allow,
1341 					 DBusMessage **reply)
1342 {
1343 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1344 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
1345 			   __func__);
1346 		*reply = wpas_dbus_error_invalid_args(
1347 			message, "Wrong Type value type. Boolean required");
1348 		return -1;
1349 	}
1350 	dbus_message_iter_get_basic(var, allow);
1351 	return 0;
1352 }
1353 
1354 
1355 /**
1356  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1357  * @message: Pointer to incoming dbus message
1358  * @wpa_s: wpa_supplicant structure for a network interface
1359  * Returns: NULL indicating success or DBus error message on failure
1360  *
1361  * Handler function for "Scan" method call of a network device. Requests
1362  * that wpa_supplicant perform a wireless scan as soon as possible
1363  * on a particular wireless interface.
1364  */
1365 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1366 				     struct wpa_supplicant *wpa_s)
1367 {
1368 	DBusMessage *reply = NULL;
1369 	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1370 	char *key = NULL, *type = NULL;
1371 	struct wpa_driver_scan_params params;
1372 	size_t i;
1373 	dbus_bool_t allow_roam = 1;
1374 
1375 	os_memset(&params, 0, sizeof(params));
1376 
1377 	dbus_message_iter_init(message, &iter);
1378 
1379 	dbus_message_iter_recurse(&iter, &dict_iter);
1380 
1381 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1382 	       DBUS_TYPE_DICT_ENTRY) {
1383 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1384 		dbus_message_iter_get_basic(&entry_iter, &key);
1385 		dbus_message_iter_next(&entry_iter);
1386 		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1387 
1388 		if (os_strcmp(key, "Type") == 0) {
1389 			if (wpas_dbus_get_scan_type(message, &variant_iter,
1390 						    &type, &reply) < 0)
1391 				goto out;
1392 		} else if (os_strcmp(key, "SSIDs") == 0) {
1393 			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1394 						     &params, &reply) < 0)
1395 				goto out;
1396 		} else if (os_strcmp(key, "IEs") == 0) {
1397 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1398 						   &params, &reply) < 0)
1399 				goto out;
1400 		} else if (os_strcmp(key, "Channels") == 0) {
1401 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1402 							&params, &reply) < 0)
1403 				goto out;
1404 		} else if (os_strcmp(key, "AllowRoam") == 0) {
1405 			if (wpas_dbus_get_scan_allow_roam(message,
1406 							  &variant_iter,
1407 							  &allow_roam,
1408 							  &reply) < 0)
1409 				goto out;
1410 		} else {
1411 			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1412 				   __func__, key);
1413 			reply = wpas_dbus_error_invalid_args(message, key);
1414 			goto out;
1415 		}
1416 
1417 		dbus_message_iter_next(&dict_iter);
1418 	}
1419 
1420 	if (!type) {
1421 		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1422 			   __func__);
1423 		reply = wpas_dbus_error_invalid_args(message, key);
1424 		goto out;
1425 	}
1426 
1427 	if (os_strcmp(type, "passive") == 0) {
1428 		if (params.num_ssids || params.extra_ies_len) {
1429 			wpa_printf(MSG_DEBUG,
1430 				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
1431 				   __func__);
1432 			reply = wpas_dbus_error_invalid_args(
1433 				message,
1434 				"You can specify only Channels in passive scan");
1435 			goto out;
1436 		} else {
1437 			if (wpa_s->sched_scanning) {
1438 				wpa_printf(MSG_DEBUG,
1439 					   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1440 					   __func__);
1441 				wpa_supplicant_cancel_sched_scan(wpa_s);
1442 			}
1443 
1444 			if (params.freqs && params.freqs[0]) {
1445 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1446 				if (wpa_supplicant_trigger_scan(wpa_s,
1447 								&params)) {
1448 					reply = wpas_dbus_error_scan_error(
1449 						message,
1450 						"Scan request rejected");
1451 				}
1452 			} else {
1453 				wpa_s->scan_req = MANUAL_SCAN_REQ;
1454 				wpa_supplicant_req_scan(wpa_s, 0, 0);
1455 			}
1456 		}
1457 	} else if (os_strcmp(type, "active") == 0) {
1458 		if (!params.num_ssids) {
1459 			/* Add wildcard ssid */
1460 			params.num_ssids++;
1461 		}
1462 #ifdef CONFIG_AUTOSCAN
1463 		autoscan_deinit(wpa_s);
1464 #endif /* CONFIG_AUTOSCAN */
1465 		if (wpa_s->sched_scanning) {
1466 			wpa_printf(MSG_DEBUG,
1467 				   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1468 				   __func__);
1469 			wpa_supplicant_cancel_sched_scan(wpa_s);
1470 		}
1471 
1472 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1473 		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1474 			reply = wpas_dbus_error_scan_error(
1475 				message, "Scan request rejected");
1476 		}
1477 	} else {
1478 		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1479 			   __func__, type);
1480 		reply = wpas_dbus_error_invalid_args(message,
1481 						     "Wrong scan type");
1482 		goto out;
1483 	}
1484 
1485 	if (!allow_roam)
1486 		wpa_s->scan_res_handler = scan_only_handler;
1487 
1488 out:
1489 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1490 		os_free((u8 *) params.ssids[i].ssid);
1491 	os_free((u8 *) params.extra_ies);
1492 	os_free(params.freqs);
1493 	return reply;
1494 }
1495 
1496 
1497 /*
1498  * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted
1499  * @message: Pointer to incoming dbus message
1500  * @wpa_s: wpa_supplicant structure for a network interface
1501  * Returns: Abort failed or no scan in progress DBus error message on failure
1502  * or NULL otherwise.
1503  *
1504  * Handler function for "AbortScan" method call of network interface.
1505  */
1506 DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
1507 					   struct wpa_supplicant *wpa_s)
1508 {
1509 	if (wpas_abort_ongoing_scan(wpa_s) < 0)
1510 		return dbus_message_new_error(
1511 			message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
1512 			"Abort failed or no scan in progress");
1513 
1514 	return NULL;
1515 }
1516 
1517 
1518 /**
1519  * wpas_dbus_handler_signal_poll - Request immediate signal properties
1520  * @message: Pointer to incoming dbus message
1521  * @wpa_s: wpa_supplicant structure for a network interface
1522  * Returns: NULL indicating success or DBus error message on failure
1523  *
1524  * Handler function for "SignalPoll" method call of a network device. Requests
1525  * that wpa_supplicant read signal properties like RSSI, noise, and link
1526  * speed and return them.
1527  */
1528 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1529 					    struct wpa_supplicant *wpa_s)
1530 {
1531 	struct wpa_signal_info si;
1532 	DBusMessage *reply = NULL;
1533 	DBusMessageIter iter, iter_dict, variant_iter;
1534 	int ret;
1535 
1536 	ret = wpa_drv_signal_poll(wpa_s, &si);
1537 	if (ret) {
1538 		return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1539 					      "Failed to read signal");
1540 	}
1541 
1542 	reply = dbus_message_new_method_return(message);
1543 	if (reply == NULL)
1544 		goto nomem;
1545 
1546 	dbus_message_iter_init_append(reply, &iter);
1547 
1548 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1549 					      "a{sv}", &variant_iter) ||
1550 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1551 	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1552 					si.current_signal) ||
1553 	    !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
1554 					si.current_txrate / 1000) ||
1555 	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1556 					si.current_noise) ||
1557 	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1558 					 si.frequency) ||
1559 	    (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
1560 	     !wpa_dbus_dict_append_string(
1561 		     &iter_dict, "width",
1562 		     channel_width_to_string(si.chanwidth))) ||
1563 	    (si.center_frq1 > 0 && si.center_frq2 > 0 &&
1564 	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1565 					  si.center_frq1) ||
1566 	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1567 					  si.center_frq2))) ||
1568 	    (si.avg_signal &&
1569 	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1570 					 si.avg_signal)) ||
1571 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1572 	    !dbus_message_iter_close_container(&iter, &variant_iter))
1573 		goto nomem;
1574 
1575 	return reply;
1576 
1577 nomem:
1578 	if (reply)
1579 		dbus_message_unref(reply);
1580 	return wpas_dbus_error_no_memory(message);
1581 }
1582 
1583 
1584 /*
1585  * wpas_dbus_handler_disconnect - Terminate the current connection
1586  * @message: Pointer to incoming dbus message
1587  * @wpa_s: wpa_supplicant structure for a network interface
1588  * Returns: NotConnected DBus error message if already not connected
1589  * or NULL otherwise.
1590  *
1591  * Handler function for "Disconnect" method call of network interface.
1592  */
1593 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1594 					   struct wpa_supplicant *wpa_s)
1595 {
1596 	if (wpa_s->current_ssid != NULL) {
1597 		wpas_request_disconnection(wpa_s);
1598 		return NULL;
1599 	}
1600 
1601 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1602 				      "This interface is not connected");
1603 }
1604 
1605 
1606 /**
1607  * wpas_dbus_new_iface_add_network - Add a new configured network
1608  * @message: Pointer to incoming dbus message
1609  * @wpa_s: wpa_supplicant structure for a network interface
1610  * Returns: A dbus message containing the object path of the new network
1611  *
1612  * Handler function for "AddNetwork" method call of a network interface.
1613  */
1614 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1615 					    struct wpa_supplicant *wpa_s)
1616 {
1617 	DBusMessage *reply = NULL;
1618 	DBusMessageIter	iter;
1619 	struct wpa_ssid *ssid = NULL;
1620 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1621 	DBusError error;
1622 
1623 	dbus_message_iter_init(message, &iter);
1624 
1625 	if (wpa_s->dbus_new_path)
1626 		ssid = wpa_supplicant_add_network(wpa_s);
1627 	if (ssid == NULL) {
1628 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
1629 			   __func__);
1630 		reply = wpas_dbus_error_unknown_error(
1631 			message,
1632 			"wpa_supplicant could not add a network on this interface.");
1633 		goto err;
1634 	}
1635 
1636 	dbus_error_init(&error);
1637 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1638 		wpa_printf(MSG_DEBUG,
1639 			   "%s[dbus]: control interface couldn't set network properties",
1640 			   __func__);
1641 		reply = wpas_dbus_reply_new_from_error(message, &error,
1642 						       DBUS_ERROR_INVALID_ARGS,
1643 						       "Failed to add network");
1644 		dbus_error_free(&error);
1645 		goto err;
1646 	}
1647 
1648 	/* Construct the object path for this network. */
1649 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1650 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1651 		    wpa_s->dbus_new_path, ssid->id);
1652 
1653 	reply = dbus_message_new_method_return(message);
1654 	if (reply == NULL) {
1655 		reply = wpas_dbus_error_no_memory(message);
1656 		goto err;
1657 	}
1658 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1659 				      DBUS_TYPE_INVALID)) {
1660 		dbus_message_unref(reply);
1661 		reply = wpas_dbus_error_no_memory(message);
1662 		goto err;
1663 	}
1664 
1665 	return reply;
1666 
1667 err:
1668 	if (ssid) {
1669 		wpas_notify_network_removed(wpa_s, ssid);
1670 		wpa_config_remove_network(wpa_s->conf, ssid->id);
1671 	}
1672 	return reply;
1673 }
1674 
1675 
1676 /**
1677  * wpas_dbus_handler_reassociate - Reassociate
1678  * @message: Pointer to incoming dbus message
1679  * @wpa_s: wpa_supplicant structure for a network interface
1680  * Returns: InterfaceDisabled DBus error message if disabled
1681  * or NULL otherwise.
1682  *
1683  * Handler function for "Reassociate" method call of network interface.
1684  */
1685 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1686 					    struct wpa_supplicant *wpa_s)
1687 {
1688 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1689 		wpas_request_connection(wpa_s);
1690 		return NULL;
1691 	}
1692 
1693 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1694 				      "This interface is disabled");
1695 }
1696 
1697 
1698 /**
1699  * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
1700  * @message: Pointer to incoming dbus message
1701  * @global: %wpa_supplicant global data structure
1702  * Returns: NULL
1703  *
1704  * Handler function for notifying system there will be a expected disconnect.
1705  * This will prevent wpa_supplicant from adding the BSSID to the ignore list
1706  * upon next disconnect.
1707  */
1708 DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
1709 						  struct wpa_global *global)
1710 {
1711 	struct wpa_supplicant *wpa_s = global->ifaces;
1712 
1713 	for (; wpa_s; wpa_s = wpa_s->next)
1714 		if (wpa_s->wpa_state >= WPA_ASSOCIATED)
1715 			wpa_s->own_disconnect_req = 1;
1716 	return NULL;
1717 }
1718 
1719 
1720 /**
1721  * wpas_dbus_handler_reattach - Reattach to current AP
1722  * @message: Pointer to incoming dbus message
1723  * @wpa_s: wpa_supplicant structure for a network interface
1724  * Returns: NotConnected DBus error message if not connected
1725  * or NULL otherwise.
1726  *
1727  * Handler function for "Reattach" method call of network interface.
1728  */
1729 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1730 					 struct wpa_supplicant *wpa_s)
1731 {
1732 	if (wpa_s->current_ssid != NULL) {
1733 		wpa_s->reattach = 1;
1734 		wpas_request_connection(wpa_s);
1735 		return NULL;
1736 	}
1737 
1738 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1739 				      "This interface is not connected");
1740 }
1741 
1742 
1743 /**
1744  * wpas_dbus_handler_reconnect - Reconnect if disconnected
1745  * @message: Pointer to incoming dbus message
1746  * @wpa_s: wpa_supplicant structure for a network interface
1747  * Returns: InterfaceDisabled DBus error message if disabled
1748  * or NULL otherwise.
1749  *
1750  * Handler function for "Reconnect" method call of network interface.
1751  */
1752 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
1753 		struct wpa_supplicant *wpa_s)
1754 {
1755 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
1756 		return dbus_message_new_error(message,
1757 					      WPAS_DBUS_ERROR_IFACE_DISABLED,
1758 					      "This interface is disabled");
1759 	}
1760 
1761 	if (wpa_s->disconnected)
1762 		wpas_request_connection(wpa_s);
1763 	return NULL;
1764 }
1765 
1766 
1767 /**
1768  * wpas_dbus_handler_remove_network - Remove a configured network
1769  * @message: Pointer to incoming dbus message
1770  * @wpa_s: wpa_supplicant structure for a network interface
1771  * Returns: NULL on success or dbus error on failure
1772  *
1773  * Handler function for "RemoveNetwork" method call of a network interface.
1774  */
1775 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1776 					       struct wpa_supplicant *wpa_s)
1777 {
1778 	DBusMessage *reply = NULL;
1779 	const char *op;
1780 	char *iface, *net_id;
1781 	int id;
1782 	int result;
1783 
1784 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1785 			      DBUS_TYPE_INVALID);
1786 
1787 	/* Extract the network ID and ensure the network */
1788 	/* is actually a child of this interface */
1789 	iface = wpas_dbus_new_decompose_object_path(op,
1790 						    WPAS_DBUS_NEW_NETWORKS_PART,
1791 						    &net_id);
1792 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1793 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1794 		reply = wpas_dbus_error_invalid_args(message, op);
1795 		goto out;
1796 	}
1797 
1798 	errno = 0;
1799 	id = strtoul(net_id, NULL, 10);
1800 	if (errno != 0) {
1801 		reply = wpas_dbus_error_invalid_args(message, op);
1802 		goto out;
1803 	}
1804 
1805 	result = wpa_supplicant_remove_network(wpa_s, id);
1806 	if (result == -1) {
1807 		reply = wpas_dbus_error_network_unknown(message);
1808 		goto out;
1809 	}
1810 	if (result == -2) {
1811 		wpa_printf(MSG_ERROR,
1812 			   "%s[dbus]: error occurred when removing network %d",
1813 			   __func__, id);
1814 		reply = wpas_dbus_error_unknown_error(
1815 			message,
1816 			"error removing the specified network on is interface.");
1817 		goto out;
1818 	}
1819 
1820 out:
1821 	os_free(iface);
1822 	return reply;
1823 }
1824 
1825 
1826 /**
1827  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1828  * @message: Pointer to incoming dbus message
1829  * @wpa_s: wpa_supplicant structure for a network interface
1830  * Returns: NULL on success or dbus error on failure
1831  *
1832  * Handler function for "RemoveAllNetworks" method call of a network interface.
1833  */
1834 DBusMessage * wpas_dbus_handler_remove_all_networks(
1835 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1836 {
1837 	/* NB: could check for failure and return an error */
1838 	wpa_supplicant_remove_all_networks(wpa_s);
1839 	return NULL;
1840 }
1841 
1842 
1843 /**
1844  * wpas_dbus_handler_select_network - Attempt association with a network
1845  * @message: Pointer to incoming dbus message
1846  * @wpa_s: wpa_supplicant structure for a network interface
1847  * Returns: NULL on success or dbus error on failure
1848  *
1849  * Handler function for "SelectNetwork" method call of network interface.
1850  */
1851 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1852 					       struct wpa_supplicant *wpa_s)
1853 {
1854 	DBusMessage *reply = NULL;
1855 	const char *op;
1856 	char *iface, *net_id;
1857 	int id;
1858 	struct wpa_ssid *ssid;
1859 
1860 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1861 			      DBUS_TYPE_INVALID);
1862 
1863 	/* Extract the network ID and ensure the network */
1864 	/* is actually a child of this interface */
1865 	iface = wpas_dbus_new_decompose_object_path(op,
1866 						    WPAS_DBUS_NEW_NETWORKS_PART,
1867 						    &net_id);
1868 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1869 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1870 		reply = wpas_dbus_error_invalid_args(message, op);
1871 		goto out;
1872 	}
1873 
1874 	errno = 0;
1875 	id = strtoul(net_id, NULL, 10);
1876 	if (errno != 0) {
1877 		reply = wpas_dbus_error_invalid_args(message, op);
1878 		goto out;
1879 	}
1880 
1881 	ssid = wpa_config_get_network(wpa_s->conf, id);
1882 	if (ssid == NULL) {
1883 		reply = wpas_dbus_error_network_unknown(message);
1884 		goto out;
1885 	}
1886 
1887 	/* Finally, associate with the network */
1888 	wpa_supplicant_select_network(wpa_s, ssid);
1889 
1890 out:
1891 	os_free(iface);
1892 	return reply;
1893 }
1894 
1895 
1896 /**
1897  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1898  * @message: Pointer to incoming dbus message
1899  * @wpa_s: wpa_supplicant structure for a network interface
1900  * Returns: NULL on success or dbus error on failure
1901  *
1902  * Handler function for "NetworkReply" method call of network interface.
1903  */
1904 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1905 					      struct wpa_supplicant *wpa_s)
1906 {
1907 #ifdef IEEE8021X_EAPOL
1908 	DBusMessage *reply = NULL;
1909 	const char *op, *field, *value;
1910 	char *iface, *net_id;
1911 	int id;
1912 	struct wpa_ssid *ssid;
1913 
1914 	if (!dbus_message_get_args(message, NULL,
1915 				   DBUS_TYPE_OBJECT_PATH, &op,
1916 				   DBUS_TYPE_STRING, &field,
1917 				   DBUS_TYPE_STRING, &value,
1918 				   DBUS_TYPE_INVALID))
1919 		return wpas_dbus_error_invalid_args(message, NULL);
1920 
1921 	/* Extract the network ID and ensure the network */
1922 	/* is actually a child of this interface */
1923 	iface = wpas_dbus_new_decompose_object_path(op,
1924 						    WPAS_DBUS_NEW_NETWORKS_PART,
1925 						    &net_id);
1926 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1927 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1928 		reply = wpas_dbus_error_invalid_args(message, op);
1929 		goto out;
1930 	}
1931 
1932 	errno = 0;
1933 	id = strtoul(net_id, NULL, 10);
1934 	if (errno != 0) {
1935 		reply = wpas_dbus_error_invalid_args(message, net_id);
1936 		goto out;
1937 	}
1938 
1939 	ssid = wpa_config_get_network(wpa_s->conf, id);
1940 	if (ssid == NULL) {
1941 		reply = wpas_dbus_error_network_unknown(message);
1942 		goto out;
1943 	}
1944 
1945 	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1946 						      field, value) < 0)
1947 		reply = wpas_dbus_error_invalid_args(message, field);
1948 	else {
1949 		/* Tell EAP to retry immediately */
1950 		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1951 	}
1952 
1953 out:
1954 	os_free(iface);
1955 	return reply;
1956 #else /* IEEE8021X_EAPOL */
1957 	wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
1958 	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1959 #endif /* IEEE8021X_EAPOL */
1960 }
1961 
1962 
1963 /**
1964  * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
1965  * @message: Pointer to incoming dbus message
1966  * @wpa_s: wpa_supplicant structure for a network interface
1967  * Returns: NULL on success or dbus error on failure
1968  *
1969  * Handler function for "Roam" method call of network interface.
1970  */
1971 DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
1972 				     struct wpa_supplicant *wpa_s)
1973 {
1974 #ifdef CONFIG_NO_SCAN_PROCESSING
1975 	return wpas_dbus_error_unknown_error(message,
1976 					     "scan processing not included");
1977 #else /* CONFIG_NO_SCAN_PROCESSING */
1978 	u8 bssid[ETH_ALEN];
1979 	struct wpa_bss *bss;
1980 	struct wpa_ssid *ssid = wpa_s->current_ssid;
1981 	char *addr;
1982 	struct wpa_radio_work *already_connecting;
1983 
1984 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
1985 				   DBUS_TYPE_INVALID))
1986 		return wpas_dbus_error_invalid_args(message, NULL);
1987 
1988 	if (hwaddr_aton(addr, bssid))
1989 		return wpas_dbus_error_invalid_args(
1990 			message, "Invalid hardware address format");
1991 
1992 	wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
1993 
1994 	if (!ssid)
1995 		return dbus_message_new_error(
1996 			message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1997 			"This interface is not connected");
1998 
1999 	bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
2000 	if (!bss) {
2001 		wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
2002 		return wpas_dbus_error_invalid_args(
2003 			message, "Target BSS not found");
2004 	}
2005 
2006 	already_connecting = radio_work_pending(wpa_s, "sme-connect");
2007 	wpa_s->reassociate = 1;
2008 	wpa_supplicant_connect(wpa_s, bss, ssid);
2009 
2010 	/*
2011 	 * Indicate that an explicitly requested roam is in progress so scan
2012 	 * results that come in before the 'sme-connect' radio work gets
2013 	 * executed do not override the original connection attempt.
2014 	 */
2015 	if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
2016 		wpa_s->roam_in_progress = true;
2017 
2018 	return NULL;
2019 #endif /* CONFIG_NO_SCAN_PROCESSING */
2020 }
2021 
2022 #ifndef CONFIG_NO_CONFIG_BLOBS
2023 
2024 /**
2025  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
2026  * @message: Pointer to incoming dbus message
2027  * @wpa_s: %wpa_supplicant data structure
2028  * Returns: A dbus message containing an error on failure or NULL on success
2029  *
2030  * Asks wpa_supplicant to internally store a binary blobs.
2031  */
2032 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
2033 					 struct wpa_supplicant *wpa_s)
2034 {
2035 	DBusMessage *reply = NULL;
2036 	DBusMessageIter	iter, array_iter;
2037 
2038 	char *blob_name;
2039 	u8 *blob_data;
2040 	int blob_len;
2041 	struct wpa_config_blob *blob = NULL;
2042 
2043 	dbus_message_iter_init(message, &iter);
2044 	dbus_message_iter_get_basic(&iter, &blob_name);
2045 
2046 	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
2047 		return dbus_message_new_error(message,
2048 					      WPAS_DBUS_ERROR_BLOB_EXISTS,
2049 					      NULL);
2050 	}
2051 
2052 	dbus_message_iter_next(&iter);
2053 	dbus_message_iter_recurse(&iter, &array_iter);
2054 
2055 	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
2056 
2057 	blob = os_zalloc(sizeof(*blob));
2058 	if (!blob) {
2059 		reply = wpas_dbus_error_no_memory(message);
2060 		goto err;
2061 	}
2062 
2063 	blob->data = os_memdup(blob_data, blob_len);
2064 	blob->name = os_strdup(blob_name);
2065 	if (!blob->data || !blob->name) {
2066 		reply = wpas_dbus_error_no_memory(message);
2067 		goto err;
2068 	}
2069 	blob->len = blob_len;
2070 
2071 	wpa_config_set_blob(wpa_s->conf, blob);
2072 	wpas_notify_blob_added(wpa_s, blob->name);
2073 
2074 	return reply;
2075 
2076 err:
2077 	if (blob) {
2078 		os_free(blob->name);
2079 		os_free(blob->data);
2080 		os_free(blob);
2081 	}
2082 	return reply;
2083 }
2084 
2085 
2086 /**
2087  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
2088  * @message: Pointer to incoming dbus message
2089  * @wpa_s: %wpa_supplicant data structure
2090  * Returns: A dbus message containing array of bytes (blob)
2091  *
2092  * Gets one wpa_supplicant's binary blobs.
2093  */
2094 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
2095 					 struct wpa_supplicant *wpa_s)
2096 {
2097 	DBusMessage *reply = NULL;
2098 	DBusMessageIter	iter, array_iter;
2099 
2100 	char *blob_name;
2101 	const struct wpa_config_blob *blob;
2102 
2103 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2104 			      DBUS_TYPE_INVALID);
2105 
2106 	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
2107 	if (!blob) {
2108 		return dbus_message_new_error(message,
2109 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2110 					      "Blob id not set");
2111 	}
2112 
2113 	reply = dbus_message_new_method_return(message);
2114 	if (!reply)
2115 		return wpas_dbus_error_no_memory(message);
2116 
2117 	dbus_message_iter_init_append(reply, &iter);
2118 
2119 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2120 					      DBUS_TYPE_BYTE_AS_STRING,
2121 					      &array_iter) ||
2122 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
2123 						  &(blob->data), blob->len) ||
2124 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
2125 		dbus_message_unref(reply);
2126 		reply = wpas_dbus_error_no_memory(message);
2127 	}
2128 
2129 	return reply;
2130 }
2131 
2132 
2133 /**
2134  * wpas_remove_handler_remove_blob - Remove named binary blob
2135  * @message: Pointer to incoming dbus message
2136  * @wpa_s: %wpa_supplicant data structure
2137  * Returns: NULL on success or dbus error
2138  *
2139  * Asks wpa_supplicant to internally remove a binary blobs.
2140  */
2141 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
2142 					    struct wpa_supplicant *wpa_s)
2143 {
2144 	DBusMessage *reply = NULL;
2145 	char *blob_name;
2146 
2147 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2148 			      DBUS_TYPE_INVALID);
2149 
2150 	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
2151 		return dbus_message_new_error(message,
2152 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2153 					      "Blob id not set");
2154 	}
2155 	wpas_notify_blob_removed(wpa_s, blob_name);
2156 
2157 	return reply;
2158 
2159 }
2160 
2161 #endif /* CONFIG_NO_CONFIG_BLOBS */
2162 
2163 
2164 /*
2165  * wpas_dbus_handler_flush_bss - Flush the BSS cache
2166  * @message: Pointer to incoming dbus message
2167  * @wpa_s: wpa_supplicant structure for a network interface
2168  * Returns: NULL
2169  *
2170  * Handler function for "FlushBSS" method call of network interface.
2171  */
2172 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2173 					  struct wpa_supplicant *wpa_s)
2174 {
2175 	dbus_uint32_t age;
2176 
2177 	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2178 			      DBUS_TYPE_INVALID);
2179 
2180 	if (age == 0)
2181 		wpa_bss_flush(wpa_s);
2182 	else
2183 		wpa_bss_flush_by_age(wpa_s, age);
2184 
2185 	return NULL;
2186 }
2187 
2188 
2189 #ifdef CONFIG_AUTOSCAN
2190 /**
2191  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2192  * @message: Pointer to incoming dbus message
2193  * @wpa_s: wpa_supplicant structure for a network interface
2194  * Returns: NULL
2195  *
2196  * Handler function for "AutoScan" method call of network interface.
2197  */
2198 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2199 					 struct wpa_supplicant *wpa_s)
2200 {
2201 	DBusMessage *reply = NULL;
2202 	enum wpa_states state = wpa_s->wpa_state;
2203 	char *arg;
2204 
2205 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2206 			      DBUS_TYPE_INVALID);
2207 
2208 	if (arg != NULL && os_strlen(arg) > 0) {
2209 		char *tmp;
2210 
2211 		tmp = os_strdup(arg);
2212 		if (tmp == NULL) {
2213 			reply = wpas_dbus_error_no_memory(message);
2214 		} else {
2215 			os_free(wpa_s->conf->autoscan);
2216 			wpa_s->conf->autoscan = tmp;
2217 			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2218 				autoscan_init(wpa_s, 1);
2219 			else if (state == WPA_SCANNING)
2220 				wpa_supplicant_reinit_autoscan(wpa_s);
2221 		}
2222 	} else if (arg != NULL && os_strlen(arg) == 0) {
2223 		os_free(wpa_s->conf->autoscan);
2224 		wpa_s->conf->autoscan = NULL;
2225 		autoscan_deinit(wpa_s);
2226 	} else
2227 		reply = dbus_message_new_error(message,
2228 					       DBUS_ERROR_INVALID_ARGS,
2229 					       NULL);
2230 
2231 	return reply;
2232 }
2233 #endif /* CONFIG_AUTOSCAN */
2234 
2235 
2236 /*
2237  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2238  * @message: Pointer to incoming dbus message
2239  * @wpa_s: wpa_supplicant structure for a network interface
2240  * Returns: NULL
2241  *
2242  * Handler function for "EAPLogoff" method call of network interface.
2243  */
2244 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2245 					   struct wpa_supplicant *wpa_s)
2246 {
2247 	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2248 	return NULL;
2249 }
2250 
2251 
2252 /*
2253  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2254  * @message: Pointer to incoming dbus message
2255  * @wpa_s: wpa_supplicant structure for a network interface
2256  * Returns: NULL
2257  *
2258  * Handler function for "EAPLogin" method call of network interface.
2259  */
2260 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2261 					  struct wpa_supplicant *wpa_s)
2262 {
2263 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2264 	return NULL;
2265 }
2266 
2267 
2268 #ifdef CONFIG_TDLS
2269 
2270 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2271 				  u8 *peer_address, DBusMessage **error)
2272 {
2273 	const char *peer_string;
2274 
2275 	*error = NULL;
2276 
2277 	if (!dbus_message_get_args(message, NULL,
2278 				   DBUS_TYPE_STRING, &peer_string,
2279 				   DBUS_TYPE_INVALID)) {
2280 		*error = wpas_dbus_error_invalid_args(message, NULL);
2281 		return -1;
2282 	}
2283 
2284 	if (hwaddr_aton(peer_string, peer_address)) {
2285 		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2286 			   func_name, peer_string);
2287 		*error = wpas_dbus_error_invalid_args(
2288 			message, "Invalid hardware address format");
2289 		return -1;
2290 	}
2291 
2292 	return 0;
2293 }
2294 
2295 
2296 /*
2297  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2298  * @message: Pointer to incoming dbus message
2299  * @wpa_s: wpa_supplicant structure for a network interface
2300  * Returns: NULL indicating success or DBus error message on failure
2301  *
2302  * Handler function for "TDLSDiscover" method call of network interface.
2303  */
2304 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2305 					      struct wpa_supplicant *wpa_s)
2306 {
2307 	u8 peer[ETH_ALEN];
2308 	DBusMessage *error_reply;
2309 	int ret;
2310 
2311 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2312 		return error_reply;
2313 
2314 	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2315 
2316 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2317 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2318 	else
2319 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2320 
2321 	if (ret) {
2322 		return wpas_dbus_error_unknown_error(
2323 			message, "error performing TDLS discovery");
2324 	}
2325 
2326 	return NULL;
2327 }
2328 
2329 
2330 /*
2331  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2332  * @message: Pointer to incoming dbus message
2333  * @wpa_s: wpa_supplicant structure for a network interface
2334  * Returns: NULL indicating success or DBus error message on failure
2335  *
2336  * Handler function for "TDLSSetup" method call of network interface.
2337  */
2338 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2339 					   struct wpa_supplicant *wpa_s)
2340 {
2341 	u8 peer[ETH_ALEN];
2342 	DBusMessage *error_reply;
2343 	int ret;
2344 
2345 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2346 		return error_reply;
2347 
2348 	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2349 
2350 	wpa_tdls_remove(wpa_s->wpa, peer);
2351 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2352 		ret = wpa_tdls_start(wpa_s->wpa, peer);
2353 	else
2354 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2355 
2356 	if (ret) {
2357 		return wpas_dbus_error_unknown_error(
2358 			message, "error performing TDLS setup");
2359 	}
2360 
2361 	return NULL;
2362 }
2363 
2364 
2365 /*
2366  * wpas_dbus_handler_tdls_status - Return TDLS session status
2367  * @message: Pointer to incoming dbus message
2368  * @wpa_s: wpa_supplicant structure for a network interface
2369  * Returns: A string representing the state of the link to this TDLS peer
2370  *
2371  * Handler function for "TDLSStatus" method call of network interface.
2372  */
2373 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2374 					    struct wpa_supplicant *wpa_s)
2375 {
2376 	u8 peer[ETH_ALEN];
2377 	DBusMessage *reply;
2378 	const char *tdls_status;
2379 
2380 	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2381 		return reply;
2382 
2383 	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2384 
2385 	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2386 
2387 	reply = dbus_message_new_method_return(message);
2388 	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2389 				 &tdls_status, DBUS_TYPE_INVALID);
2390 	return reply;
2391 }
2392 
2393 
2394 /*
2395  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2396  * @message: Pointer to incoming dbus message
2397  * @wpa_s: wpa_supplicant structure for a network interface
2398  * Returns: NULL indicating success or DBus error message on failure
2399  *
2400  * Handler function for "TDLSTeardown" method call of network interface.
2401  */
2402 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2403 					      struct wpa_supplicant *wpa_s)
2404 {
2405 	u8 peer[ETH_ALEN];
2406 	DBusMessage *error_reply;
2407 	int ret;
2408 
2409 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2410 		return error_reply;
2411 
2412 	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2413 
2414 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2415 		ret = wpa_tdls_teardown_link(
2416 			wpa_s->wpa, peer,
2417 			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2418 	else
2419 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2420 
2421 	if (ret) {
2422 		return wpas_dbus_error_unknown_error(
2423 			message, "error performing TDLS teardown");
2424 	}
2425 
2426 	return NULL;
2427 }
2428 
2429 /*
2430  * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer
2431  * @message: Pointer to incoming dbus message
2432  * @wpa_s: wpa_supplicant structure for a network interface
2433  * Returns: NULL indicating success or DBus error message on failure
2434  *
2435  * Handler function for "TDLSChannelSwitch" method call of network interface.
2436  */
2437 DBusMessage *
2438 wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
2439 				      struct wpa_supplicant *wpa_s)
2440 {
2441 	DBusMessageIter	iter, iter_dict;
2442 	struct wpa_dbus_dict_entry entry;
2443 	u8 peer[ETH_ALEN];
2444 	struct hostapd_freq_params freq_params;
2445 	u8 oper_class = 0;
2446 	int ret;
2447 	int is_peer_present = 0;
2448 
2449 	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
2450 		wpa_printf(MSG_INFO,
2451 			   "tdls_chanswitch: Only supported with external setup");
2452 		return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup");
2453 	}
2454 
2455 	os_memset(&freq_params, 0, sizeof(freq_params));
2456 
2457 	dbus_message_iter_init(message, &iter);
2458 
2459 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2460 		return wpas_dbus_error_invalid_args(message, NULL);
2461 
2462 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2463 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2464 			return wpas_dbus_error_invalid_args(message, NULL);
2465 
2466 		if (os_strcmp(entry.key, "PeerAddress") == 0 &&
2467 		    entry.type == DBUS_TYPE_STRING) {
2468 			if (hwaddr_aton(entry.str_value, peer)) {
2469 				wpa_printf(MSG_DEBUG,
2470 					   "tdls_chanswitch: Invalid address '%s'",
2471 					   entry.str_value);
2472 				wpa_dbus_dict_entry_clear(&entry);
2473 				return wpas_dbus_error_invalid_args(message,
2474 								    NULL);
2475 			}
2476 
2477 			is_peer_present = 1;
2478 		} else if (os_strcmp(entry.key, "OperClass") == 0 &&
2479 			   entry.type == DBUS_TYPE_BYTE) {
2480 			oper_class = entry.byte_value;
2481 		} else if (os_strcmp(entry.key, "Frequency") == 0 &&
2482 			   entry.type == DBUS_TYPE_UINT32) {
2483 			freq_params.freq = entry.uint32_value;
2484 		} else if (os_strcmp(entry.key, "SecChannelOffset") == 0 &&
2485 			   entry.type == DBUS_TYPE_UINT32) {
2486 			freq_params.sec_channel_offset = entry.uint32_value;
2487 		} else if (os_strcmp(entry.key, "CenterFrequency1") == 0 &&
2488 			   entry.type == DBUS_TYPE_UINT32) {
2489 			freq_params.center_freq1 = entry.uint32_value;
2490 		} else if (os_strcmp(entry.key, "CenterFrequency2") == 0 &&
2491 			   entry.type == DBUS_TYPE_UINT32) {
2492 			freq_params.center_freq2 = entry.uint32_value;
2493 		} else if (os_strcmp(entry.key, "Bandwidth") == 0 &&
2494 			   entry.type == DBUS_TYPE_UINT32) {
2495 			freq_params.bandwidth = entry.uint32_value;
2496 		} else if (os_strcmp(entry.key, "HT") == 0 &&
2497 			   entry.type == DBUS_TYPE_BOOLEAN) {
2498 			freq_params.ht_enabled = entry.bool_value;
2499 		} else if (os_strcmp(entry.key, "VHT") == 0 &&
2500 			   entry.type == DBUS_TYPE_BOOLEAN) {
2501 			freq_params.vht_enabled = entry.bool_value;
2502 		} else {
2503 			wpa_dbus_dict_entry_clear(&entry);
2504 			return wpas_dbus_error_invalid_args(message, NULL);
2505 		}
2506 
2507 		wpa_dbus_dict_entry_clear(&entry);
2508 	}
2509 
2510 	if (oper_class == 0) {
2511 		wpa_printf(MSG_INFO,
2512 			   "tdls_chanswitch: Invalid op class provided");
2513 		return wpas_dbus_error_invalid_args(
2514 			message, "Invalid op class provided");
2515 	}
2516 
2517 	if (freq_params.freq == 0) {
2518 		wpa_printf(MSG_INFO,
2519 			   "tdls_chanswitch: Invalid freq provided");
2520 		return wpas_dbus_error_invalid_args(message,
2521 						    "Invalid freq provided");
2522 	}
2523 
2524 	if (is_peer_present == 0) {
2525 		wpa_printf(MSG_DEBUG,
2526 			   "tdls_chanswitch: peer address not provided");
2527 		return wpas_dbus_error_invalid_args(
2528 			message, "peer address not provided");
2529 	}
2530 
2531 	wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR
2532 		   " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
2533 		   MAC2STR(peer), oper_class, freq_params.freq,
2534 		   freq_params.center_freq1, freq_params.center_freq2,
2535 		   freq_params.bandwidth, freq_params.sec_channel_offset,
2536 		   freq_params.ht_enabled ? " HT" : "",
2537 		   freq_params.vht_enabled ? " VHT" : "");
2538 
2539 	ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
2540 					  &freq_params);
2541 	if (ret)
2542 		return wpas_dbus_error_unknown_error(
2543 			message, "error processing TDLS channel switch");
2544 
2545 	return NULL;
2546 }
2547 
2548 /*
2549  * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer
2550  * @message: Pointer to incoming dbus message
2551  * @wpa_s: wpa_supplicant structure for a network interface
2552  * Returns: NULL indicating success or DBus error message on failure
2553  *
2554  * Handler function for "TDLSCancelChannelSwitch" method call of network
2555  * interface.
2556  */
2557 DBusMessage *
2558 wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
2559 					     struct wpa_supplicant *wpa_s)
2560 {
2561 	u8 peer[ETH_ALEN];
2562 	DBusMessage *error_reply;
2563 	int ret;
2564 
2565 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2566 		return error_reply;
2567 
2568 	wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR,
2569 		   MAC2STR(peer));
2570 
2571 	ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
2572 	if (ret)
2573 		return wpas_dbus_error_unknown_error(
2574 			message, "error canceling TDLS channel switch");
2575 
2576 	return NULL;
2577 }
2578 
2579 #endif /* CONFIG_TDLS */
2580 
2581 
2582 #ifndef CONFIG_NO_CONFIG_WRITE
2583 /**
2584  * wpas_dbus_handler_save_config - Save configuration to configuration file
2585  * @message: Pointer to incoming dbus message
2586  * @wpa_s: wpa_supplicant structure for a network interface
2587  * Returns: NULL on Success, Otherwise error message
2588  *
2589  * Handler function for "SaveConfig" method call of network interface.
2590  */
2591 DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
2592 					    struct wpa_supplicant *wpa_s)
2593 {
2594 	int ret;
2595 
2596 	if (!wpa_s->conf->update_config) {
2597 		return wpas_dbus_error_unknown_error(
2598 			message,
2599 			"Not allowed to update configuration (update_config=0)");
2600 	}
2601 
2602 	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2603 	if (ret)
2604 		return wpas_dbus_error_unknown_error(
2605 			message, "Failed to update configuration");
2606 	return NULL;
2607 }
2608 #endif /* CONFIG_NO_CONFIG_WRITE */
2609 
2610 
2611 /**
2612  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2613  * @message: Pointer to incoming dbus message
2614  * @wpa_s: %wpa_supplicant data structure
2615  * Returns: A dbus message containing an error on failure or NULL on success
2616  *
2617  * Sets the PKCS #11 engine and module path.
2618  */
2619 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2620 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2621 {
2622 	DBusMessageIter iter;
2623 	char *value = NULL;
2624 	char *pkcs11_engine_path = NULL;
2625 	char *pkcs11_module_path = NULL;
2626 
2627 	dbus_message_iter_init(message, &iter);
2628 	dbus_message_iter_get_basic(&iter, &value);
2629 	if (value == NULL) {
2630 		return dbus_message_new_error(
2631 			message, DBUS_ERROR_INVALID_ARGS,
2632 			"Invalid pkcs11_engine_path argument");
2633 	}
2634 	/* Empty path defaults to NULL */
2635 	if (os_strlen(value))
2636 		pkcs11_engine_path = value;
2637 
2638 	dbus_message_iter_next(&iter);
2639 	dbus_message_iter_get_basic(&iter, &value);
2640 	if (value == NULL) {
2641 		os_free(pkcs11_engine_path);
2642 		return dbus_message_new_error(
2643 			message, DBUS_ERROR_INVALID_ARGS,
2644 			"Invalid pkcs11_module_path argument");
2645 	}
2646 	/* Empty path defaults to NULL */
2647 	if (os_strlen(value))
2648 		pkcs11_module_path = value;
2649 
2650 	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2651 						   pkcs11_module_path))
2652 		return dbus_message_new_error(
2653 			message, DBUS_ERROR_FAILED,
2654 			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
2655 
2656 	if (wpa_s->dbus_new_path) {
2657 		wpa_dbus_mark_property_changed(
2658 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2659 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2660 		wpa_dbus_mark_property_changed(
2661 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2662 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2663 	}
2664 
2665 	return NULL;
2666 }
2667 
2668 
2669 /**
2670  * wpas_dbus_getter_capabilities - Return interface capabilities
2671  * @iter: Pointer to incoming dbus message iter
2672  * @error: Location to store error on failure
2673  * @user_data: Function specific data
2674  * Returns: TRUE on success, FALSE on failure
2675  *
2676  * Getter for "Capabilities" property of an interface.
2677  */
2678 dbus_bool_t wpas_dbus_getter_capabilities(
2679 	const struct wpa_dbus_property_desc *property_desc,
2680 	DBusMessageIter *iter, DBusError *error, void *user_data)
2681 {
2682 	struct wpa_supplicant *wpa_s = user_data;
2683 	struct wpa_driver_capa capa;
2684 	int res;
2685 	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2686 		variant_iter;
2687 	const char *scans[] = { "active", "passive", "ssid" };
2688 
2689 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2690 					      "a{sv}", &variant_iter) ||
2691 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2692 		goto nomem;
2693 
2694 	res = wpa_drv_get_capa(wpa_s, &capa);
2695 
2696 	/***** pairwise cipher */
2697 	if (res < 0) {
2698 #ifdef CONFIG_NO_TKIP
2699 		const char *args[] = {"ccmp", "none"};
2700 #else /* CONFIG_NO_TKIP */
2701 		const char *args[] = {"ccmp", "tkip", "none"};
2702 #endif /* CONFIG_NO_TKIP */
2703 
2704 		if (!wpa_dbus_dict_append_string_array(
2705 			    &iter_dict, "Pairwise", args,
2706 			    ARRAY_SIZE(args)))
2707 			goto nomem;
2708 	} else {
2709 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2710 						      &iter_dict_entry,
2711 						      &iter_dict_val,
2712 						      &iter_array) ||
2713 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2714 		     !wpa_dbus_dict_string_array_add_element(
2715 			     &iter_array, "ccmp-256")) ||
2716 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2717 		     !wpa_dbus_dict_string_array_add_element(
2718 			     &iter_array, "gcmp-256")) ||
2719 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2720 		     !wpa_dbus_dict_string_array_add_element(
2721 			     &iter_array, "ccmp")) ||
2722 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2723 		     !wpa_dbus_dict_string_array_add_element(
2724 			     &iter_array, "gcmp")) ||
2725 #ifndef CONFIG_NO_TKIP
2726 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2727 		     !wpa_dbus_dict_string_array_add_element(
2728 			     &iter_array, "tkip")) ||
2729 #endif /* CONFIG_NO_TKIP */
2730 		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2731 		     !wpa_dbus_dict_string_array_add_element(
2732 			     &iter_array, "none")) ||
2733 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2734 						    &iter_dict_entry,
2735 						    &iter_dict_val,
2736 						    &iter_array))
2737 			goto nomem;
2738 	}
2739 
2740 	/***** group cipher */
2741 	if (res < 0) {
2742 		const char *args[] = {
2743 			"ccmp",
2744 #ifndef CONFIG_NO_TKIP
2745 			"tkip",
2746 #endif /* CONFIG_NO_TKIP */
2747 #ifdef CONFIG_WEP
2748 			"wep104", "wep40"
2749 #endif /* CONFIG_WEP */
2750 		};
2751 
2752 		if (!wpa_dbus_dict_append_string_array(
2753 			    &iter_dict, "Group", args,
2754 			    ARRAY_SIZE(args)))
2755 			goto nomem;
2756 	} else {
2757 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2758 						      &iter_dict_entry,
2759 						      &iter_dict_val,
2760 						      &iter_array) ||
2761 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2762 		     !wpa_dbus_dict_string_array_add_element(
2763 			     &iter_array, "ccmp-256")) ||
2764 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2765 		     !wpa_dbus_dict_string_array_add_element(
2766 			     &iter_array, "gcmp-256")) ||
2767 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2768 		     !wpa_dbus_dict_string_array_add_element(
2769 			     &iter_array, "ccmp")) ||
2770 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2771 		     !wpa_dbus_dict_string_array_add_element(
2772 			     &iter_array, "gcmp")) ||
2773 #ifndef CONFIG_NO_TKIP
2774 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2775 		     !wpa_dbus_dict_string_array_add_element(
2776 			     &iter_array, "tkip")) ||
2777 #endif /* CONFIG_NO_TKIP */
2778 #ifdef CONFIG_WEP
2779 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
2780 		     !wpa_dbus_dict_string_array_add_element(
2781 			     &iter_array, "wep104")) ||
2782 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
2783 		     !wpa_dbus_dict_string_array_add_element(
2784 			     &iter_array, "wep40")) ||
2785 #endif /* CONFIG_WEP */
2786 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2787 						    &iter_dict_entry,
2788 						    &iter_dict_val,
2789 						    &iter_array))
2790 			goto nomem;
2791 	}
2792 
2793 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
2794 					      &iter_dict_entry,
2795 					      &iter_dict_val,
2796 					      &iter_array) ||
2797 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
2798 	     !wpa_dbus_dict_string_array_add_element(
2799 		     &iter_array, "aes-128-cmac")) ||
2800 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
2801 	     !wpa_dbus_dict_string_array_add_element(
2802 		     &iter_array, "bip-gmac-128")) ||
2803 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
2804 	     !wpa_dbus_dict_string_array_add_element(
2805 		     &iter_array, "bip-gmac-256")) ||
2806 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
2807 	     !wpa_dbus_dict_string_array_add_element(
2808 		     &iter_array, "bip-cmac-256")) ||
2809 	    !wpa_dbus_dict_end_string_array(&iter_dict,
2810 					    &iter_dict_entry,
2811 					    &iter_dict_val,
2812 					    &iter_array))
2813 		goto nomem;
2814 
2815 	/***** key management */
2816 	if (res < 0) {
2817 		const char *args[] = {
2818 			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2819 #ifdef CONFIG_WPS
2820 			"wps",
2821 #endif /* CONFIG_WPS */
2822 			"none"
2823 		};
2824 		if (!wpa_dbus_dict_append_string_array(
2825 			    &iter_dict, "KeyMgmt", args,
2826 			    ARRAY_SIZE(args)))
2827 			goto nomem;
2828 	} else {
2829 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2830 						      &iter_dict_entry,
2831 						      &iter_dict_val,
2832 						      &iter_array) ||
2833 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2834 							    "none") ||
2835 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2836 							    "ieee8021x"))
2837 			goto nomem;
2838 
2839 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2840 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2841 			if (!wpa_dbus_dict_string_array_add_element(
2842 				    &iter_array, "wpa-eap") ||
2843 			    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
2844 			     !wpa_dbus_dict_string_array_add_element(
2845 				     &iter_array, "wpa-ft-eap")))
2846 				goto nomem;
2847 
2848 /* TODO: Ensure that driver actually supports sha256 encryption. */
2849 			if (!wpa_dbus_dict_string_array_add_element(
2850 				    &iter_array, "wpa-eap-sha256"))
2851 				goto nomem;
2852 		}
2853 
2854 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2855 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2856 			if (!wpa_dbus_dict_string_array_add_element(
2857 				    &iter_array, "wpa-psk") ||
2858 			    ((capa.key_mgmt &
2859 			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
2860 			     !wpa_dbus_dict_string_array_add_element(
2861 				     &iter_array, "wpa-ft-psk")))
2862 				goto nomem;
2863 
2864 /* TODO: Ensure that driver actually supports sha256 encryption. */
2865 			if (!wpa_dbus_dict_string_array_add_element(
2866 				    &iter_array, "wpa-psk-sha256"))
2867 				goto nomem;
2868 		}
2869 
2870 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2871 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2872 							    "wpa-none"))
2873 			goto nomem;
2874 
2875 
2876 #ifdef CONFIG_WPS
2877 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2878 							    "wps"))
2879 			goto nomem;
2880 #endif /* CONFIG_WPS */
2881 
2882 #ifdef CONFIG_SAE
2883 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
2884 		    !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
2885 			goto nomem;
2886 #endif /* CONFIG_SAE */
2887 
2888 #ifdef CONFIG_OWE
2889 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) &&
2890 		    !wpa_dbus_dict_string_array_add_element(&iter_array, "owe"))
2891 			goto nomem;
2892 #endif /* CONFIG_OWE */
2893 
2894 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2895 						    &iter_dict_entry,
2896 						    &iter_dict_val,
2897 						    &iter_array))
2898 			goto nomem;
2899 	}
2900 
2901 	/***** WPA protocol */
2902 	if (res < 0) {
2903 		const char *args[] = { "rsn", "wpa" };
2904 
2905 		if (!wpa_dbus_dict_append_string_array(
2906 			    &iter_dict, "Protocol", args,
2907 			    ARRAY_SIZE(args)))
2908 			goto nomem;
2909 	} else {
2910 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2911 						      &iter_dict_entry,
2912 						      &iter_dict_val,
2913 						      &iter_array) ||
2914 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2915 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
2916 		     !wpa_dbus_dict_string_array_add_element(
2917 			     &iter_array, "rsn")) ||
2918 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2919 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
2920 		     !wpa_dbus_dict_string_array_add_element(
2921 			     &iter_array, "wpa")) ||
2922 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2923 						    &iter_dict_entry,
2924 						    &iter_dict_val,
2925 						    &iter_array))
2926 			goto nomem;
2927 	}
2928 
2929 	/***** auth alg */
2930 	if (res < 0) {
2931 		const char *args[] = { "open", "shared", "leap" };
2932 
2933 		if (!wpa_dbus_dict_append_string_array(
2934 			    &iter_dict, "AuthAlg", args,
2935 			    ARRAY_SIZE(args)))
2936 			goto nomem;
2937 	} else {
2938 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2939 						      &iter_dict_entry,
2940 						      &iter_dict_val,
2941 						      &iter_array))
2942 			goto nomem;
2943 
2944 		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
2945 		     !wpa_dbus_dict_string_array_add_element(
2946 			     &iter_array, "open")) ||
2947 		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
2948 		     !wpa_dbus_dict_string_array_add_element(
2949 			     &iter_array, "shared")) ||
2950 		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
2951 		     !wpa_dbus_dict_string_array_add_element(
2952 			     &iter_array, "leap")) ||
2953 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2954 						    &iter_dict_entry,
2955 						    &iter_dict_val,
2956 						    &iter_array))
2957 			goto nomem;
2958 	}
2959 
2960 	/***** Scan */
2961 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2962 					       ARRAY_SIZE(scans)))
2963 		goto nomem;
2964 
2965 	/***** Modes */
2966 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2967 					      &iter_dict_entry,
2968 					      &iter_dict_val,
2969 					      &iter_array) ||
2970 	    !wpa_dbus_dict_string_array_add_element(
2971 		    &iter_array, "infrastructure") ||
2972 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
2973 	     !wpa_dbus_dict_string_array_add_element(
2974 		     &iter_array, "ad-hoc")) ||
2975 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
2976 	     !wpa_dbus_dict_string_array_add_element(
2977 		     &iter_array, "ap")) ||
2978 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
2979 	     !wpa_s->conf->p2p_disabled &&
2980 	     !wpa_dbus_dict_string_array_add_element(
2981 		     &iter_array, "p2p")) ||
2982 #ifdef CONFIG_MESH
2983 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) &&
2984 	     !wpa_dbus_dict_string_array_add_element(
2985 		     &iter_array, "mesh")) ||
2986 #endif /* CONFIG_MESH */
2987 	    !wpa_dbus_dict_end_string_array(&iter_dict,
2988 					    &iter_dict_entry,
2989 					    &iter_dict_val,
2990 					    &iter_array))
2991 		goto nomem;
2992 	/***** Modes end */
2993 
2994 	if (res >= 0) {
2995 		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2996 
2997 		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2998 						max_scan_ssid))
2999 			goto nomem;
3000 	}
3001 
3002 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3003 	    !dbus_message_iter_close_container(iter, &variant_iter))
3004 		goto nomem;
3005 
3006 	return TRUE;
3007 
3008 nomem:
3009 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3010 	return FALSE;
3011 }
3012 
3013 
3014 /**
3015  * wpas_dbus_getter_state - Get interface state
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 "State" property.
3022  */
3023 dbus_bool_t wpas_dbus_getter_state(
3024 	const struct wpa_dbus_property_desc *property_desc,
3025 	DBusMessageIter *iter, DBusError *error, void *user_data)
3026 {
3027 	struct wpa_supplicant *wpa_s = user_data;
3028 	const char *str_state;
3029 	char *state_ls, *tmp;
3030 	dbus_bool_t success = FALSE;
3031 
3032 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
3033 
3034 	/* make state string lowercase to fit new DBus API convention
3035 	 */
3036 	state_ls = tmp = os_strdup(str_state);
3037 	if (!tmp) {
3038 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3039 		return FALSE;
3040 	}
3041 	while (*tmp) {
3042 		*tmp = tolower(*tmp);
3043 		tmp++;
3044 	}
3045 
3046 	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3047 						   &state_ls, error);
3048 
3049 	os_free(state_ls);
3050 
3051 	return success;
3052 }
3053 
3054 
3055 /**
3056  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
3057  * @iter: Pointer to incoming dbus message iter
3058  * @error: Location to store error on failure
3059  * @user_data: Function specific data
3060  * Returns: TRUE on success, FALSE on failure
3061  *
3062  * Getter for "scanning" property.
3063  */
3064 dbus_bool_t wpas_dbus_getter_scanning(
3065 	const struct wpa_dbus_property_desc *property_desc,
3066 	DBusMessageIter *iter, DBusError *error, void *user_data)
3067 {
3068 	struct wpa_supplicant *wpa_s = user_data;
3069 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
3070 
3071 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3072 						&scanning, error);
3073 }
3074 
3075 
3076 /**
3077  * wpas_dbus_getter_ap_scan - Control roaming mode
3078  * @iter: Pointer to incoming dbus message iter
3079  * @error: Location to store error on failure
3080  * @user_data: Function specific data
3081  * Returns: TRUE on success, FALSE on failure
3082  *
3083  * Getter function for "ApScan" property.
3084  */
3085 dbus_bool_t wpas_dbus_getter_ap_scan(
3086 	const struct wpa_dbus_property_desc *property_desc,
3087 	DBusMessageIter *iter, DBusError *error, void *user_data)
3088 {
3089 	struct wpa_supplicant *wpa_s = user_data;
3090 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
3091 
3092 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3093 						&ap_scan, error);
3094 }
3095 
3096 
3097 /**
3098  * wpas_dbus_setter_ap_scan - Control roaming mode
3099  * @iter: Pointer to incoming dbus message iter
3100  * @error: Location to store error on failure
3101  * @user_data: Function specific data
3102  * Returns: TRUE on success, FALSE on failure
3103  *
3104  * Setter function for "ApScan" property.
3105  */
3106 dbus_bool_t wpas_dbus_setter_ap_scan(
3107 	const struct wpa_dbus_property_desc *property_desc,
3108 	DBusMessageIter *iter, DBusError *error, void *user_data)
3109 {
3110 	struct wpa_supplicant *wpa_s = user_data;
3111 	dbus_uint32_t ap_scan;
3112 
3113 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3114 					      &ap_scan))
3115 		return FALSE;
3116 
3117 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
3118 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3119 				     "ap_scan must be 0, 1, or 2");
3120 		return FALSE;
3121 	}
3122 	return TRUE;
3123 }
3124 
3125 
3126 /**
3127  * wpas_dbus_getter_fast_reauth - Control fast
3128  * reauthentication (TLS session resumption)
3129  * @iter: Pointer to incoming dbus message iter
3130  * @error: Location to store error on failure
3131  * @user_data: Function specific data
3132  * Returns: TRUE on success, FALSE on failure
3133  *
3134  * Getter function for "FastReauth" property.
3135  */
3136 dbus_bool_t wpas_dbus_getter_fast_reauth(
3137 	const struct wpa_dbus_property_desc *property_desc,
3138 	DBusMessageIter *iter, DBusError *error, void *user_data)
3139 {
3140 	struct wpa_supplicant *wpa_s = user_data;
3141 	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
3142 
3143 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3144 						&fast_reauth, error);
3145 }
3146 
3147 
3148 /**
3149  * wpas_dbus_setter_fast_reauth - Control fast
3150  * reauthentication (TLS session resumption)
3151  * @iter: Pointer to incoming dbus message iter
3152  * @error: Location to store error on failure
3153  * @user_data: Function specific data
3154  * Returns: TRUE on success, FALSE on failure
3155  *
3156  * Setter function for "FastReauth" property.
3157  */
3158 dbus_bool_t wpas_dbus_setter_fast_reauth(
3159 	const struct wpa_dbus_property_desc *property_desc,
3160 	DBusMessageIter *iter, DBusError *error, void *user_data)
3161 {
3162 	struct wpa_supplicant *wpa_s = user_data;
3163 	dbus_bool_t fast_reauth;
3164 
3165 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3166 					      &fast_reauth))
3167 		return FALSE;
3168 
3169 	wpa_s->conf->fast_reauth = fast_reauth;
3170 	return TRUE;
3171 }
3172 
3173 
3174 /**
3175  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
3176  * @iter: Pointer to incoming dbus message iter
3177  * @error: Location to store error on failure
3178  * @user_data: Function specific data
3179  * Returns: TRUE on success, FALSE on failure
3180  *
3181  * Getter for "DisconnectReason" property.  The reason is negative if it is
3182  * locally generated.
3183  */
3184 dbus_bool_t wpas_dbus_getter_disconnect_reason(
3185 	const struct wpa_dbus_property_desc *property_desc,
3186 	DBusMessageIter *iter, DBusError *error, void *user_data)
3187 {
3188 	struct wpa_supplicant *wpa_s = user_data;
3189 	dbus_int32_t reason = wpa_s->disconnect_reason;
3190 
3191 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3192 						&reason, error);
3193 }
3194 
3195 
3196 /**
3197  * wpas_dbus_getter_auth_status_code - Get most recent auth status code
3198  * @iter: Pointer to incoming dbus message iter
3199  * @error: Location to store error on failure
3200  * @user_data: Function specific data
3201  * Returns: TRUE on success, FALSE on failure
3202  *
3203  * Getter for "AuthStatusCode" property.
3204  */
3205 dbus_bool_t wpas_dbus_getter_auth_status_code(
3206 	const struct wpa_dbus_property_desc *property_desc,
3207 	DBusMessageIter *iter, DBusError *error, void *user_data)
3208 {
3209 	struct wpa_supplicant *wpa_s = user_data;
3210 	dbus_int32_t reason = wpa_s->auth_status_code;
3211 
3212 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3213 						&reason, error);
3214 }
3215 
3216 
3217 /**
3218  * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
3219  * @iter: Pointer to incoming dbus message iter
3220  * @error: Location to store error on failure
3221  * @user_data: Function specific data
3222  * Returns: TRUE on success, FALSE on failure
3223  *
3224  * Getter for "AssocStatusCode" property.
3225  */
3226 dbus_bool_t wpas_dbus_getter_assoc_status_code(
3227 	const struct wpa_dbus_property_desc *property_desc,
3228 	DBusMessageIter *iter, DBusError *error, void *user_data)
3229 {
3230 	struct wpa_supplicant *wpa_s = user_data;
3231 	dbus_int32_t status_code = wpa_s->assoc_status_code;
3232 
3233 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3234 						&status_code, error);
3235 }
3236 
3237 
3238 /**
3239  * wpas_dbus_getter_roam_time - Get most recent roam time
3240  * @iter: Pointer to incoming dbus message iter
3241  * @error: Location to store error on failure
3242  * @user_data: Function specific data
3243  * Returns: TRUE on success, FALSE on failure
3244  *
3245  * Getter for "RoamTime" property.
3246  */
3247 dbus_bool_t wpas_dbus_getter_roam_time(
3248 	const struct wpa_dbus_property_desc *property_desc,
3249 	DBusMessageIter *iter, DBusError *error, void *user_data)
3250 {
3251 	struct wpa_supplicant *wpa_s = user_data;
3252 	dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
3253 		wpa_s->roam_time.usec / 1000;
3254 
3255 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3256 						&roam_time, error);
3257 }
3258 
3259 
3260 /**
3261  * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
3262  * @iter: Pointer to incoming dbus message iter
3263  * @error: Location to store error on failure
3264  * @user_data: Function specific data
3265  * Returns: TRUE on success, FALSE on failure
3266  *
3267  * Getter for "RoamComplete" property.
3268  */
3269 dbus_bool_t wpas_dbus_getter_roam_complete(
3270 	const struct wpa_dbus_property_desc *property_desc,
3271 	DBusMessageIter *iter, DBusError *error, void *user_data)
3272 {
3273 	struct wpa_supplicant *wpa_s = user_data;
3274 	dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
3275 
3276 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3277 						&roam_complete, error);
3278 }
3279 
3280 
3281 /**
3282  * wpas_dbus_getter_session_length - Get most recent BSS session length
3283  * @iter: Pointer to incoming dbus message iter
3284  * @error: Location to store error on failure
3285  * @user_data: Function specific data
3286  * Returns: TRUE on success, FALSE on failure
3287  *
3288  * Getter for "SessionLength" property.
3289  */
3290 dbus_bool_t wpas_dbus_getter_session_length(
3291 	const struct wpa_dbus_property_desc *property_desc,
3292 	DBusMessageIter *iter, DBusError *error, void *user_data)
3293 {
3294 	struct wpa_supplicant *wpa_s = user_data;
3295 	dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
3296 		wpa_s->session_length.usec / 1000;
3297 
3298 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3299 						&session_length, error);
3300 }
3301 
3302 
3303 /**
3304  * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
3305  * status code
3306  * @iter: Pointer to incoming dbus message iter
3307  * @error: Location to store error on failure
3308  * @user_data: Function specific data
3309  * Returns: TRUE on success, FALSE on failure
3310  *
3311  * Getter for "BSSTMStatus" property.
3312  */
3313 dbus_bool_t wpas_dbus_getter_bss_tm_status(
3314 	const struct wpa_dbus_property_desc *property_desc,
3315 	DBusMessageIter *iter, DBusError *error, void *user_data)
3316 {
3317 #ifdef CONFIG_WNM
3318 	struct wpa_supplicant *wpa_s = user_data;
3319 	dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
3320 #else /* CONFIG_WNM */
3321 	dbus_uint32_t bss_tm_status = 0;
3322 #endif /* CONFIG_WNM */
3323 
3324 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3325 						&bss_tm_status, error);
3326 }
3327 
3328 
3329 /**
3330  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
3331  * @iter: Pointer to incoming dbus message iter
3332  * @error: Location to store error on failure
3333  * @user_data: Function specific data
3334  * Returns: TRUE on success, FALSE on failure
3335  *
3336  * Getter function for "BSSExpireAge" property.
3337  */
3338 dbus_bool_t wpas_dbus_getter_bss_expire_age(
3339 	const struct wpa_dbus_property_desc *property_desc,
3340 	DBusMessageIter *iter, DBusError *error, void *user_data)
3341 {
3342 	struct wpa_supplicant *wpa_s = user_data;
3343 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
3344 
3345 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3346 						&expire_age, error);
3347 }
3348 
3349 
3350 /**
3351  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
3352  * @iter: Pointer to incoming dbus message iter
3353  * @error: Location to store error on failure
3354  * @user_data: Function specific data
3355  * Returns: TRUE on success, FALSE on failure
3356  *
3357  * Setter function for "BSSExpireAge" property.
3358  */
3359 dbus_bool_t wpas_dbus_setter_bss_expire_age(
3360 	const struct wpa_dbus_property_desc *property_desc,
3361 	DBusMessageIter *iter, DBusError *error, void *user_data)
3362 {
3363 	struct wpa_supplicant *wpa_s = user_data;
3364 	dbus_uint32_t expire_age;
3365 
3366 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3367 					      &expire_age))
3368 		return FALSE;
3369 
3370 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
3371 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3372 				     "BSSExpireAge must be >= 10");
3373 		return FALSE;
3374 	}
3375 	return TRUE;
3376 }
3377 
3378 
3379 /**
3380  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
3381  * @iter: Pointer to incoming dbus message iter
3382  * @error: Location to store error on failure
3383  * @user_data: Function specific data
3384  * Returns: TRUE on success, FALSE on failure
3385  *
3386  * Getter function for "BSSExpireCount" property.
3387  */
3388 dbus_bool_t wpas_dbus_getter_bss_expire_count(
3389 	const struct wpa_dbus_property_desc *property_desc,
3390 	DBusMessageIter *iter, DBusError *error, void *user_data)
3391 {
3392 	struct wpa_supplicant *wpa_s = user_data;
3393 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
3394 
3395 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3396 						&expire_count, error);
3397 }
3398 
3399 
3400 /**
3401  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
3402  * @iter: Pointer to incoming dbus message iter
3403  * @error: Location to store error on failure
3404  * @user_data: Function specific data
3405  * Returns: TRUE on success, FALSE on failure
3406  *
3407  * Setter function for "BSSExpireCount" property.
3408  */
3409 dbus_bool_t wpas_dbus_setter_bss_expire_count(
3410 	const struct wpa_dbus_property_desc *property_desc,
3411 	DBusMessageIter *iter, DBusError *error, void *user_data)
3412 {
3413 	struct wpa_supplicant *wpa_s = user_data;
3414 	dbus_uint32_t expire_count;
3415 
3416 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3417 					      &expire_count))
3418 		return FALSE;
3419 
3420 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
3421 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3422 				     "BSSExpireCount must be > 0");
3423 		return FALSE;
3424 	}
3425 	return TRUE;
3426 }
3427 
3428 
3429 /**
3430  * wpas_dbus_getter_country - Control country code
3431  * @iter: Pointer to incoming dbus message iter
3432  * @error: Location to store error on failure
3433  * @user_data: Function specific data
3434  * Returns: TRUE on success, FALSE on failure
3435  *
3436  * Getter function for "Country" property.
3437  */
3438 dbus_bool_t wpas_dbus_getter_country(
3439 	const struct wpa_dbus_property_desc *property_desc,
3440 	DBusMessageIter *iter, DBusError *error, void *user_data)
3441 {
3442 	struct wpa_supplicant *wpa_s = user_data;
3443 	char country[3];
3444 	char *str = country;
3445 
3446 	country[0] = wpa_s->conf->country[0];
3447 	country[1] = wpa_s->conf->country[1];
3448 	country[2] = '\0';
3449 
3450 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3451 						&str, error);
3452 }
3453 
3454 
3455 /**
3456  * wpas_dbus_setter_country - Control country code
3457  * @iter: Pointer to incoming dbus message iter
3458  * @error: Location to store error on failure
3459  * @user_data: Function specific data
3460  * Returns: TRUE on success, FALSE on failure
3461  *
3462  * Setter function for "Country" property.
3463  */
3464 dbus_bool_t wpas_dbus_setter_country(
3465 	const struct wpa_dbus_property_desc *property_desc,
3466 	DBusMessageIter *iter, DBusError *error, void *user_data)
3467 {
3468 	struct wpa_supplicant *wpa_s = user_data;
3469 	const char *country;
3470 
3471 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3472 					      &country))
3473 		return FALSE;
3474 
3475 	if (!country[0] || !country[1]) {
3476 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3477 				     "invalid country code");
3478 		return FALSE;
3479 	}
3480 
3481 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
3482 		wpa_printf(MSG_DEBUG, "Failed to set country");
3483 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3484 				     "failed to set country code");
3485 		return FALSE;
3486 	}
3487 
3488 	wpa_s->conf->country[0] = country[0];
3489 	wpa_s->conf->country[1] = country[1];
3490 	return TRUE;
3491 }
3492 
3493 
3494 /**
3495  * wpas_dbus_getter_scan_interval - Get scan interval
3496  * @iter: Pointer to incoming dbus message iter
3497  * @error: Location to store error on failure
3498  * @user_data: Function specific data
3499  * Returns: TRUE on success, FALSE on failure
3500  *
3501  * Getter function for "ScanInterval" property.
3502  */
3503 dbus_bool_t wpas_dbus_getter_scan_interval(
3504 	const struct wpa_dbus_property_desc *property_desc,
3505 	DBusMessageIter *iter, DBusError *error, void *user_data)
3506 {
3507 	struct wpa_supplicant *wpa_s = user_data;
3508 	dbus_int32_t scan_interval = wpa_s->scan_interval;
3509 
3510 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3511 						&scan_interval, error);
3512 }
3513 
3514 
3515 /**
3516  * wpas_dbus_setter_scan_interval - Control scan interval
3517  * @iter: Pointer to incoming dbus message iter
3518  * @error: Location to store error on failure
3519  * @user_data: Function specific data
3520  * Returns: TRUE on success, FALSE on failure
3521  *
3522  * Setter function for "ScanInterval" property.
3523  */
3524 dbus_bool_t wpas_dbus_setter_scan_interval(
3525 	const struct wpa_dbus_property_desc *property_desc,
3526 	DBusMessageIter *iter, DBusError *error, void *user_data)
3527 {
3528 	struct wpa_supplicant *wpa_s = user_data;
3529 	dbus_int32_t scan_interval;
3530 
3531 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3532 					      &scan_interval))
3533 		return FALSE;
3534 
3535 	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3536 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3537 				     "scan_interval must be >= 0");
3538 		return FALSE;
3539 	}
3540 	return TRUE;
3541 }
3542 
3543 
3544 /**
3545  * wpas_dbus_getter_ifname - Get interface name
3546  * @iter: Pointer to incoming dbus message iter
3547  * @error: Location to store error on failure
3548  * @user_data: Function specific data
3549  * Returns: TRUE on success, FALSE on failure
3550  *
3551  * Getter for "Ifname" property.
3552  */
3553 dbus_bool_t wpas_dbus_getter_ifname(
3554 	const struct wpa_dbus_property_desc *property_desc,
3555 	DBusMessageIter *iter, DBusError *error, void *user_data)
3556 {
3557 	struct wpa_supplicant *wpa_s = user_data;
3558 
3559 	return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
3560 }
3561 
3562 
3563 /**
3564  * wpas_dbus_getter_driver - Get interface name
3565  * @iter: Pointer to incoming dbus message iter
3566  * @error: Location to store error on failure
3567  * @user_data: Function specific data
3568  * Returns: TRUE on success, FALSE on failure
3569  *
3570  * Getter for "Driver" property.
3571  */
3572 dbus_bool_t wpas_dbus_getter_driver(
3573 	const struct wpa_dbus_property_desc *property_desc,
3574 	DBusMessageIter *iter, DBusError *error, void *user_data)
3575 {
3576 	struct wpa_supplicant *wpa_s = user_data;
3577 
3578 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3579 		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
3580 			   __func__);
3581 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3582 			       __func__);
3583 		return FALSE;
3584 	}
3585 
3586 	return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
3587 						error);
3588 }
3589 
3590 
3591 /**
3592  * wpas_dbus_getter_current_bss - Get current bss object path
3593  * @iter: Pointer to incoming dbus message iter
3594  * @error: Location to store error on failure
3595  * @user_data: Function specific data
3596  * Returns: TRUE on success, FALSE on failure
3597  *
3598  * Getter for "CurrentBSS" property.
3599  */
3600 dbus_bool_t wpas_dbus_getter_current_bss(
3601 	const struct wpa_dbus_property_desc *property_desc,
3602 	DBusMessageIter *iter, DBusError *error, void *user_data)
3603 {
3604 	struct wpa_supplicant *wpa_s = user_data;
3605 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3606 
3607 	if (wpa_s->current_bss && wpa_s->dbus_new_path)
3608 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3609 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3610 			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3611 	else
3612 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3613 
3614 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3615 						&bss_obj_path, error);
3616 }
3617 
3618 
3619 /**
3620  * wpas_dbus_getter_current_network - Get current network object path
3621  * @iter: Pointer to incoming dbus message iter
3622  * @error: Location to store error on failure
3623  * @user_data: Function specific data
3624  * Returns: TRUE on success, FALSE on failure
3625  *
3626  * Getter for "CurrentNetwork" property.
3627  */
3628 dbus_bool_t wpas_dbus_getter_current_network(
3629 	const struct wpa_dbus_property_desc *property_desc,
3630 	DBusMessageIter *iter, DBusError *error, void *user_data)
3631 {
3632 	struct wpa_supplicant *wpa_s = user_data;
3633 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3634 
3635 	if (wpa_s->current_ssid && wpa_s->dbus_new_path)
3636 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3637 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3638 			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3639 	else
3640 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3641 
3642 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3643 						&net_obj_path, error);
3644 }
3645 
3646 
3647 /**
3648  * wpas_dbus_getter_current_auth_mode - Get current authentication type
3649  * @iter: Pointer to incoming dbus message iter
3650  * @error: Location to store error on failure
3651  * @user_data: Function specific data
3652  * Returns: TRUE on success, FALSE on failure
3653  *
3654  * Getter for "CurrentAuthMode" property.
3655  */
3656 dbus_bool_t wpas_dbus_getter_current_auth_mode(
3657 	const struct wpa_dbus_property_desc *property_desc,
3658 	DBusMessageIter *iter, DBusError *error, void *user_data)
3659 {
3660 	struct wpa_supplicant *wpa_s = user_data;
3661 	const char *eap_mode;
3662 	const char *auth_mode;
3663 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3664 
3665 	if (wpa_s->wpa_state != WPA_COMPLETED) {
3666 		auth_mode = "INACTIVE";
3667 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3668 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3669 		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3670 		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3671 			    "EAP-%s", eap_mode);
3672 		auth_mode = eap_mode_buf;
3673 
3674 	} else if (wpa_s->current_ssid) {
3675 		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3676 					     wpa_s->current_ssid->proto);
3677 	} else {
3678 		auth_mode = "UNKNOWN";
3679 	}
3680 
3681 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3682 						&auth_mode, error);
3683 }
3684 
3685 
3686 /**
3687  * wpas_dbus_getter_bridge_ifname - Get interface name
3688  * @iter: Pointer to incoming dbus message iter
3689  * @error: Location to store error on failure
3690  * @user_data: Function specific data
3691  * Returns: TRUE on success, FALSE on failure
3692  *
3693  * Getter for "BridgeIfname" property.
3694  */
3695 dbus_bool_t wpas_dbus_getter_bridge_ifname(
3696 	const struct wpa_dbus_property_desc *property_desc,
3697 	DBusMessageIter *iter, DBusError *error, void *user_data)
3698 {
3699 	struct wpa_supplicant *wpa_s = user_data;
3700 
3701 	return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
3702 						error);
3703 }
3704 
3705 
3706 dbus_bool_t wpas_dbus_setter_bridge_ifname(
3707 	const struct wpa_dbus_property_desc *property_desc,
3708 	DBusMessageIter *iter, DBusError *error, void *user_data)
3709 {
3710 	struct wpa_supplicant *wpa_s = user_data;
3711 	const char *bridge_ifname = NULL;
3712 	const char *msg;
3713 	int r;
3714 
3715 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3716 					      &bridge_ifname))
3717 		return FALSE;
3718 
3719 	r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
3720 	if (r != 0) {
3721 		switch (r) {
3722 		case -EINVAL:
3723 			msg = "invalid interface name";
3724 			break;
3725 		case -EBUSY:
3726 			msg = "interface is busy";
3727 			break;
3728 		case -EIO:
3729 			msg = "socket error";
3730 			break;
3731 		default:
3732 			msg = "unknown error";
3733 			break;
3734 		}
3735 		dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
3736 		return FALSE;
3737 	}
3738 
3739 	return TRUE;
3740 }
3741 
3742 
3743 /**
3744  * wpas_dbus_getter_config_file - Get interface configuration file path
3745  * @iter: Pointer to incoming dbus message iter
3746  * @error: Location to store error on failure
3747  * @user_data: Function specific data
3748  * Returns: TRUE on success, FALSE on failure
3749  *
3750  * Getter for "ConfigFile" property.
3751  */
3752 dbus_bool_t wpas_dbus_getter_config_file(
3753 	const struct wpa_dbus_property_desc *property_desc,
3754 	DBusMessageIter *iter, DBusError *error, void *user_data)
3755 {
3756 	struct wpa_supplicant *wpa_s = user_data;
3757 
3758 	return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
3759 }
3760 
3761 
3762 /**
3763  * wpas_dbus_getter_bsss - Get array of BSSs objects
3764  * @iter: Pointer to incoming dbus message iter
3765  * @error: Location to store error on failure
3766  * @user_data: Function specific data
3767  * Returns: TRUE on success, FALSE on failure
3768  *
3769  * Getter for "BSSs" property.
3770  */
3771 dbus_bool_t wpas_dbus_getter_bsss(
3772 	const struct wpa_dbus_property_desc *property_desc,
3773 	DBusMessageIter *iter, DBusError *error, void *user_data)
3774 {
3775 	struct wpa_supplicant *wpa_s = user_data;
3776 	struct wpa_bss *bss;
3777 	char **paths;
3778 	unsigned int i = 0;
3779 	dbus_bool_t success = FALSE;
3780 
3781 	if (!wpa_s->dbus_new_path) {
3782 		dbus_set_error(error, DBUS_ERROR_FAILED,
3783 			       "%s: no D-Bus interface", __func__);
3784 		return FALSE;
3785 	}
3786 
3787 	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3788 	if (!paths) {
3789 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3790 		return FALSE;
3791 	}
3792 
3793 	/* Loop through scan results and append each result's object path */
3794 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3795 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3796 		if (paths[i] == NULL) {
3797 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3798 					     "no memory");
3799 			goto out;
3800 		}
3801 		/* Construct the object path for this BSS. */
3802 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3803 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3804 			    wpa_s->dbus_new_path, bss->id);
3805 	}
3806 
3807 	success = wpas_dbus_simple_array_property_getter(iter,
3808 							 DBUS_TYPE_OBJECT_PATH,
3809 							 paths, wpa_s->num_bss,
3810 							 error);
3811 
3812 out:
3813 	while (i)
3814 		os_free(paths[--i]);
3815 	os_free(paths);
3816 	return success;
3817 }
3818 
3819 
3820 /**
3821  * wpas_dbus_getter_networks - Get array of networks objects
3822  * @iter: Pointer to incoming dbus message iter
3823  * @error: Location to store error on failure
3824  * @user_data: Function specific data
3825  * Returns: TRUE on success, FALSE on failure
3826  *
3827  * Getter for "Networks" property.
3828  */
3829 dbus_bool_t wpas_dbus_getter_networks(
3830 	const struct wpa_dbus_property_desc *property_desc,
3831 	DBusMessageIter *iter, DBusError *error, void *user_data)
3832 {
3833 	struct wpa_supplicant *wpa_s = user_data;
3834 	struct wpa_ssid *ssid;
3835 	char **paths;
3836 	unsigned int i = 0, num = 0;
3837 	dbus_bool_t success = FALSE;
3838 
3839 	if (!wpa_s->dbus_new_path) {
3840 		dbus_set_error(error, DBUS_ERROR_FAILED,
3841 			       "%s: no D-Bus interface", __func__);
3842 		return FALSE;
3843 	}
3844 
3845 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3846 		if (!network_is_persistent_group(ssid))
3847 			num++;
3848 
3849 	paths = os_calloc(num, sizeof(char *));
3850 	if (!paths) {
3851 		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3852 		return FALSE;
3853 	}
3854 
3855 	/* Loop through configured networks and append object path of each */
3856 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3857 		if (network_is_persistent_group(ssid))
3858 			continue;
3859 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3860 		if (paths[i] == NULL) {
3861 			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
3862 				       "no memory");
3863 			goto out;
3864 		}
3865 
3866 		/* Construct the object path for this network. */
3867 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3868 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3869 			    wpa_s->dbus_new_path, ssid->id);
3870 	}
3871 
3872 	success = wpas_dbus_simple_array_property_getter(iter,
3873 							 DBUS_TYPE_OBJECT_PATH,
3874 							 paths, num, error);
3875 
3876 out:
3877 	while (i)
3878 		os_free(paths[--i]);
3879 	os_free(paths);
3880 	return success;
3881 }
3882 
3883 
3884 /**
3885  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3886  * @iter: Pointer to incoming dbus message iter
3887  * @error: Location to store error on failure
3888  * @user_data: Function specific data
3889  * Returns: A dbus message containing the PKCS #11 engine path
3890  *
3891  * Getter for "PKCS11EnginePath" property.
3892  */
3893 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
3894 	const struct wpa_dbus_property_desc *property_desc,
3895 	DBusMessageIter *iter, DBusError *error, void *user_data)
3896 {
3897 	struct wpa_supplicant *wpa_s = user_data;
3898 
3899 	return wpas_dbus_string_property_getter(iter,
3900 						wpa_s->conf->pkcs11_engine_path,
3901 						error);
3902 }
3903 
3904 
3905 /**
3906  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3907  * @iter: Pointer to incoming dbus message iter
3908  * @error: Location to store error on failure
3909  * @user_data: Function specific data
3910  * Returns: A dbus message containing the PKCS #11 module path
3911  *
3912  * Getter for "PKCS11ModulePath" property.
3913  */
3914 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
3915 	const struct wpa_dbus_property_desc *property_desc,
3916 	DBusMessageIter *iter, DBusError *error, void *user_data)
3917 {
3918 	struct wpa_supplicant *wpa_s = user_data;
3919 
3920 	return wpas_dbus_string_property_getter(iter,
3921 						wpa_s->conf->pkcs11_module_path,
3922 						error);
3923 }
3924 
3925 
3926 /**
3927  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3928  * @iter: Pointer to incoming dbus message iter
3929  * @error: Location to store error on failure
3930  * @user_data: Function specific data
3931  * Returns: TRUE on success, FALSE on failure
3932  *
3933  * Getter for "Blobs" property.
3934  */
3935 dbus_bool_t wpas_dbus_getter_blobs(
3936 	const struct wpa_dbus_property_desc *property_desc,
3937 	DBusMessageIter *iter, DBusError *error, void *user_data)
3938 {
3939 	struct wpa_supplicant *wpa_s = user_data;
3940 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3941 	struct wpa_config_blob *blob;
3942 
3943 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3944 					      "a{say}", &variant_iter) ||
3945 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3946 					      "{say}", &dict_iter)) {
3947 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3948 		return FALSE;
3949 	}
3950 
3951 	blob = wpa_s->conf->blobs;
3952 	while (blob) {
3953 		if (!dbus_message_iter_open_container(&dict_iter,
3954 						      DBUS_TYPE_DICT_ENTRY,
3955 						      NULL, &entry_iter) ||
3956 		    !dbus_message_iter_append_basic(&entry_iter,
3957 						    DBUS_TYPE_STRING,
3958 						    &(blob->name)) ||
3959 		    !dbus_message_iter_open_container(&entry_iter,
3960 						      DBUS_TYPE_ARRAY,
3961 						      DBUS_TYPE_BYTE_AS_STRING,
3962 						      &array_iter) ||
3963 		    !dbus_message_iter_append_fixed_array(&array_iter,
3964 							  DBUS_TYPE_BYTE,
3965 							  &(blob->data),
3966 							  blob->len) ||
3967 		    !dbus_message_iter_close_container(&entry_iter,
3968 						       &array_iter) ||
3969 		    !dbus_message_iter_close_container(&dict_iter,
3970 						       &entry_iter)) {
3971 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3972 					     "no memory");
3973 			return FALSE;
3974 		}
3975 
3976 		blob = blob->next;
3977 	}
3978 
3979 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3980 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3981 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3982 		return FALSE;
3983 	}
3984 
3985 	return TRUE;
3986 }
3987 
3988 
3989 dbus_bool_t wpas_dbus_getter_iface_global(
3990 	const struct wpa_dbus_property_desc *property_desc,
3991 	DBusMessageIter *iter, DBusError *error, void *user_data)
3992 {
3993 	struct wpa_supplicant *wpa_s = user_data;
3994 	int ret;
3995 	char buf[250];
3996 	char *p = buf;
3997 
3998 	if (!property_desc->data) {
3999 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4000 			       "Unhandled interface property %s",
4001 			       property_desc->dbus_property);
4002 		return FALSE;
4003 	}
4004 
4005 	ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
4006 				   sizeof(buf));
4007 	if (ret < 0)
4008 		*p = '\0';
4009 
4010 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
4011 						error);
4012 }
4013 
4014 
4015 dbus_bool_t wpas_dbus_setter_iface_global(
4016 	const struct wpa_dbus_property_desc *property_desc,
4017 	DBusMessageIter *iter, DBusError *error, void *user_data)
4018 {
4019 	struct wpa_supplicant *wpa_s = user_data;
4020 	const char *new_value = NULL;
4021 	char buf[250];
4022 	size_t combined_len;
4023 	int ret;
4024 
4025 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
4026 					      &new_value))
4027 		return FALSE;
4028 
4029 	combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
4030 		3;
4031 	if (combined_len >= sizeof(buf)) {
4032 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4033 			       "Interface property %s value too large",
4034 			       property_desc->dbus_property);
4035 		return FALSE;
4036 	}
4037 
4038 	if (!new_value[0])
4039 		new_value = "NULL";
4040 
4041 	ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
4042 			  new_value);
4043 	if (os_snprintf_error(combined_len, ret)) {
4044 		dbus_set_error(error,  WPAS_DBUS_ERROR_UNKNOWN_ERROR,
4045 			       "Failed to construct new interface property %s",
4046 			       property_desc->dbus_property);
4047 		return FALSE;
4048 	}
4049 
4050 	ret = wpa_config_process_global(wpa_s->conf, buf, -1);
4051 	if (ret < 0) {
4052 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4053 			       "Failed to set interface property %s",
4054 			       property_desc->dbus_property);
4055 		return FALSE;
4056 	} else if (ret == 0) {
4057 		wpa_supplicant_update_config(wpa_s);
4058 	}
4059 	return TRUE;
4060 }
4061 
4062 
4063 /**
4064  * wpas_dbus_getter_stas - Get connected stations for an interface
4065  * @iter: Pointer to incoming dbus message iter
4066  * @error: Location to store error on failure
4067  * @user_data: Function specific data
4068  * Returns: a list of stations
4069  *
4070  * Getter for "Stations" property.
4071  */
4072 dbus_bool_t wpas_dbus_getter_stas(
4073 	const struct wpa_dbus_property_desc *property_desc,
4074 	DBusMessageIter *iter, DBusError *error, void *user_data)
4075 {
4076 	struct wpa_supplicant *wpa_s = user_data;
4077 	struct sta_info *sta = NULL;
4078 	char **paths = NULL;
4079 	unsigned int i = 0, num = 0;
4080 	dbus_bool_t success = FALSE;
4081 
4082 	if (!wpa_s->dbus_new_path) {
4083 		dbus_set_error(error, DBUS_ERROR_FAILED,
4084 			       "%s: no D-Bus interface", __func__);
4085 		return FALSE;
4086 	}
4087 
4088 #ifdef CONFIG_AP
4089 	if (wpa_s->ap_iface) {
4090 		struct hostapd_data *hapd;
4091 
4092 		hapd = wpa_s->ap_iface->bss[0];
4093 		sta = hapd->sta_list;
4094 		num = hapd->num_sta;
4095 	}
4096 #endif /* CONFIG_AP */
4097 
4098 	paths = os_calloc(num, sizeof(char *));
4099 	if (!paths) {
4100 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4101 		return FALSE;
4102 	}
4103 
4104 	/* Loop through scan results and append each result's object path */
4105 	for (; sta; sta = sta->next) {
4106 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
4107 		if (!paths[i]) {
4108 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4109 					     "no memory");
4110 			goto out;
4111 		}
4112 		/* Construct the object path for this BSS. */
4113 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
4114 			    "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
4115 			    wpa_s->dbus_new_path, MAC2STR(sta->addr));
4116 	}
4117 
4118 	success = wpas_dbus_simple_array_property_getter(iter,
4119 							 DBUS_TYPE_OBJECT_PATH,
4120 							 paths, num,
4121 							 error);
4122 
4123 out:
4124 	while (i)
4125 		os_free(paths[--i]);
4126 	os_free(paths);
4127 	return success;
4128 }
4129 
4130 
4131 /**
4132  * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
4133  * MAC address randomization
4134  * @iter: Pointer to incoming dbus message iter
4135  * @error: Location to store error on failure
4136  * @user_data: Function specific data
4137  * Returns: TRUE on success, FALSE on failure
4138  *
4139  * Setter for "MACAddressRandomizationMask" property.
4140  */
4141 dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
4142 	const struct wpa_dbus_property_desc *property_desc,
4143 	DBusMessageIter *iter, DBusError *error, void *user_data)
4144 {
4145 	struct wpa_supplicant *wpa_s = user_data;
4146 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
4147 	const char *key;
4148 	unsigned int rand_type = 0;
4149 	const u8 *mask;
4150 	int mask_len;
4151 	unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
4152 
4153 	dbus_message_iter_recurse(iter, &variant_iter);
4154 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
4155 		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
4156 				     "invalid message format");
4157 		return FALSE;
4158 	}
4159 	dbus_message_iter_recurse(&variant_iter, &dict_iter);
4160 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
4161 	       DBUS_TYPE_DICT_ENTRY) {
4162 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
4163 		if (dbus_message_iter_get_arg_type(&entry_iter) !=
4164 		    DBUS_TYPE_STRING) {
4165 			dbus_set_error(error, DBUS_ERROR_FAILED,
4166 				       "%s: key not a string", __func__);
4167 			return FALSE;
4168 		}
4169 		dbus_message_iter_get_basic(&entry_iter, &key);
4170 		dbus_message_iter_next(&entry_iter);
4171 		if (dbus_message_iter_get_arg_type(&entry_iter) !=
4172 		    DBUS_TYPE_ARRAY ||
4173 		    dbus_message_iter_get_element_type(&entry_iter) !=
4174 		    DBUS_TYPE_BYTE) {
4175 			dbus_set_error(error, DBUS_ERROR_FAILED,
4176 				       "%s: mask was not a byte array",
4177 				       __func__);
4178 			return FALSE;
4179 		}
4180 		dbus_message_iter_recurse(&entry_iter, &array_iter);
4181 		dbus_message_iter_get_fixed_array(&array_iter, &mask,
4182 						  &mask_len);
4183 
4184 		if (os_strcmp(key, "scan") == 0) {
4185 			rand_type = MAC_ADDR_RAND_SCAN;
4186 		} else if (os_strcmp(key, "sched_scan") == 0) {
4187 			rand_type = MAC_ADDR_RAND_SCHED_SCAN;
4188 		} else if (os_strcmp(key, "pno") == 0) {
4189 			rand_type = MAC_ADDR_RAND_PNO;
4190 		} else {
4191 			dbus_set_error(error, DBUS_ERROR_FAILED,
4192 				       "%s: bad scan type \"%s\"",
4193 				       __func__, key);
4194 			return FALSE;
4195 		}
4196 
4197 		if (mask_len != ETH_ALEN) {
4198 			dbus_set_error(error, DBUS_ERROR_FAILED,
4199 				       "%s: malformed MAC mask given",
4200 				       __func__);
4201 			return FALSE;
4202 		}
4203 
4204 		if (wpas_enable_mac_addr_randomization(
4205 			    wpa_s, rand_type, wpa_s->perm_addr, mask)) {
4206 			dbus_set_error(error, DBUS_ERROR_FAILED,
4207 				       "%s: failed to set up MAC address randomization for %s",
4208 				       __func__, key);
4209 			return FALSE;
4210 		}
4211 
4212 		wpa_printf(MSG_DEBUG,
4213 			   "%s: Enabled MAC address randomization for %s with mask: "
4214 			   MACSTR, wpa_s->ifname, key, MAC2STR(mask));
4215 		rand_types_to_disable &= ~rand_type;
4216 		dbus_message_iter_next(&dict_iter);
4217 	}
4218 
4219 	if (rand_types_to_disable &&
4220 	    wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
4221 		dbus_set_error(error, DBUS_ERROR_FAILED,
4222 			       "%s: failed to disable MAC address randomization",
4223 			       __func__);
4224 		return FALSE;
4225 	}
4226 
4227 	return TRUE;
4228 }
4229 
4230 
4231 dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
4232 	const struct wpa_dbus_property_desc *property_desc,
4233 	DBusMessageIter *iter, DBusError *error, void *user_data)
4234 {
4235 	struct wpa_supplicant *wpa_s = user_data;
4236 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
4237 	unsigned int i;
4238 	u8 mask_buf[ETH_ALEN];
4239 	/* Read docs on dbus_message_iter_append_fixed_array() for why this
4240 	 * is necessary... */
4241 	u8 *mask = mask_buf;
4242 	static const struct {
4243 		const char *key;
4244 		unsigned int type;
4245 	} types[] = {
4246 		{ "scan", MAC_ADDR_RAND_SCAN },
4247 		{ "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
4248 		{ "pno", MAC_ADDR_RAND_PNO }
4249 	};
4250 
4251 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4252 					      "a{say}", &variant_iter) ||
4253 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
4254 					      "{say}", &dict_iter)) {
4255 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4256 		return FALSE;
4257 	}
4258 
4259 	for (i = 0; i < ARRAY_SIZE(types); i++) {
4260 		if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
4261 						     mask))
4262 			continue;
4263 
4264 		if (!dbus_message_iter_open_container(&dict_iter,
4265 						      DBUS_TYPE_DICT_ENTRY,
4266 						      NULL, &entry_iter) ||
4267 		    !dbus_message_iter_append_basic(&entry_iter,
4268 						    DBUS_TYPE_STRING,
4269 						    &types[i].key) ||
4270 		    !dbus_message_iter_open_container(&entry_iter,
4271 						      DBUS_TYPE_ARRAY,
4272 						      DBUS_TYPE_BYTE_AS_STRING,
4273 						      &array_iter) ||
4274 		    !dbus_message_iter_append_fixed_array(&array_iter,
4275 							  DBUS_TYPE_BYTE,
4276 							  &mask,
4277 							  ETH_ALEN) ||
4278 		    !dbus_message_iter_close_container(&entry_iter,
4279 						       &array_iter) ||
4280 		    !dbus_message_iter_close_container(&dict_iter,
4281 						       &entry_iter)) {
4282 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4283 					     "no memory");
4284 			return FALSE;
4285 		}
4286 	}
4287 
4288 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
4289 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4290 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4291 		return FALSE;
4292 	}
4293 
4294 	return TRUE;
4295 }
4296 
4297 
4298 /**
4299  * wpas_dbus_getter_sta_address - Return the address of a connected station
4300  * @iter: Pointer to incoming dbus message iter
4301  * @error: Location to store error on failure
4302  * @user_data: Function specific data
4303  * Returns: TRUE on success, FALSE on failure
4304  *
4305  * Getter for "Address" property.
4306  */
4307 dbus_bool_t wpas_dbus_getter_sta_address(
4308 	const struct wpa_dbus_property_desc *property_desc,
4309 	DBusMessageIter *iter, DBusError *error, void *user_data)
4310 {
4311 #ifdef CONFIG_AP
4312 	struct sta_handler_args *args = user_data;
4313 	struct sta_info *sta;
4314 
4315 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4316 	if (!sta)
4317 		return FALSE;
4318 
4319 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4320 						      sta->addr, ETH_ALEN,
4321 						      error);
4322 #else /* CONFIG_AP */
4323     return FALSE;
4324 #endif /* CONFIG_AP */
4325 }
4326 
4327 
4328 /**
4329  * wpas_dbus_getter_sta_aid - Return the AID of a connected station
4330  * @iter: Pointer to incoming dbus message iter
4331  * @error: Location to store error on failure
4332  * @user_data: Function specific data
4333  * Returns: TRUE on success, FALSE on failure
4334  *
4335  * Getter for "AID" property.
4336  */
4337 dbus_bool_t wpas_dbus_getter_sta_aid(
4338 	const struct wpa_dbus_property_desc *property_desc,
4339 	DBusMessageIter *iter, DBusError *error, void *user_data)
4340 {
4341 #ifdef CONFIG_AP
4342 	struct sta_handler_args *args = user_data;
4343 	struct sta_info *sta;
4344 
4345 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4346 	if (!sta)
4347 		return FALSE;
4348 
4349 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4350 						&sta->aid,
4351 						error);
4352 #else /* CONFIG_AP */
4353     return FALSE;
4354 #endif /* CONFIG_AP */
4355 }
4356 
4357 
4358 /**
4359  * wpas_dbus_getter_sta_caps - Return the capabilities of a station
4360  * @iter: Pointer to incoming dbus message iter
4361  * @error: Location to store error on failure
4362  * @user_data: Function specific data
4363  * Returns: TRUE on success, FALSE on failure
4364  *
4365  * Getter for "Capabilities" property.
4366  */
4367 dbus_bool_t wpas_dbus_getter_sta_caps(
4368 	const struct wpa_dbus_property_desc *property_desc,
4369 	DBusMessageIter *iter, DBusError *error, void *user_data)
4370 {
4371 #ifdef CONFIG_AP
4372 	struct sta_handler_args *args = user_data;
4373 	struct sta_info *sta;
4374 
4375 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4376 	if (!sta)
4377 		return FALSE;
4378 
4379 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4380 						&sta->capability,
4381 						error);
4382 #else /* CONFIG_AP */
4383     return FALSE;
4384 #endif /* CONFIG_AP */
4385 }
4386 
4387 
4388 /**
4389  * wpas_dbus_getter_rx_packets - Return the received packets for a station
4390  * @iter: Pointer to incoming dbus message iter
4391  * @error: Location to store error on failure
4392  * @user_data: Function specific data
4393  * Returns: TRUE on success, FALSE on failure
4394  *
4395  * Getter for "RxPackets" property.
4396  */
4397 dbus_bool_t wpas_dbus_getter_sta_rx_packets(
4398 	const struct wpa_dbus_property_desc *property_desc,
4399 	DBusMessageIter *iter, DBusError *error, void *user_data)
4400 {
4401 #ifdef CONFIG_AP
4402 	struct sta_handler_args *args = user_data;
4403 	struct sta_info *sta;
4404 	struct hostap_sta_driver_data data;
4405 	struct hostapd_data *hapd;
4406 
4407 	if (!args->wpa_s->ap_iface)
4408 		return FALSE;
4409 
4410 	hapd = args->wpa_s->ap_iface->bss[0];
4411 	sta = ap_get_sta(hapd, args->sta);
4412 	if (!sta)
4413 		return FALSE;
4414 
4415 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4416 		return FALSE;
4417 
4418 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4419 						&data.rx_packets,
4420 						error);
4421 #else /* CONFIG_AP */
4422     return FALSE;
4423 #endif /* CONFIG_AP */
4424 }
4425 
4426 
4427 /**
4428  * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
4429  * @iter: Pointer to incoming dbus message iter
4430  * @error: Location to store error on failure
4431  * @user_data: Function specific data
4432  * Returns: TRUE on success, FALSE on failure
4433  *
4434  * Getter for "TxPackets" property.
4435  */
4436 dbus_bool_t wpas_dbus_getter_sta_tx_packets(
4437 	const struct wpa_dbus_property_desc *property_desc,
4438 	DBusMessageIter *iter, DBusError *error, void *user_data)
4439 {
4440 #ifdef CONFIG_AP
4441 	struct sta_handler_args *args = user_data;
4442 	struct sta_info *sta;
4443 	struct hostap_sta_driver_data data;
4444 	struct hostapd_data *hapd;
4445 
4446 	if (!args->wpa_s->ap_iface)
4447 		return FALSE;
4448 
4449 	hapd = args->wpa_s->ap_iface->bss[0];
4450 	sta = ap_get_sta(hapd, args->sta);
4451 	if (!sta)
4452 		return FALSE;
4453 
4454 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4455 		return FALSE;
4456 
4457 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4458 						&data.tx_packets,
4459 						error);
4460 #else /* CONFIG_AP */
4461     return FALSE;
4462 #endif /* CONFIG_AP */
4463 }
4464 
4465 
4466 /**
4467  * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
4468  * @iter: Pointer to incoming dbus message iter
4469  * @error: Location to store error on failure
4470  * @user_data: Function specific data
4471  * Returns: TRUE on success, FALSE on failure
4472  *
4473  * Getter for "TxBytes" property.
4474  */
4475 dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
4476 	const struct wpa_dbus_property_desc *property_desc,
4477 	DBusMessageIter *iter, DBusError *error, void *user_data)
4478 {
4479 #ifdef CONFIG_AP
4480 	struct sta_handler_args *args = user_data;
4481 	struct sta_info *sta;
4482 	struct hostap_sta_driver_data data;
4483 	struct hostapd_data *hapd;
4484 
4485 	if (!args->wpa_s->ap_iface)
4486 		return FALSE;
4487 
4488 	hapd = args->wpa_s->ap_iface->bss[0];
4489 	sta = ap_get_sta(hapd, args->sta);
4490 	if (!sta)
4491 		return FALSE;
4492 
4493 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4494 		return FALSE;
4495 
4496 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4497 						&data.tx_bytes,
4498 						error);
4499 #else /* CONFIG_AP */
4500     return FALSE;
4501 #endif /* CONFIG_AP */
4502 }
4503 
4504 
4505 /**
4506  * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
4507  * @iter: Pointer to incoming dbus message iter
4508  * @error: Location to store error on failure
4509  * @user_data: Function specific data
4510  * Returns: TRUE on success, FALSE on failure
4511  *
4512  * Getter for "RxBytes" property.
4513  */
4514 dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
4515 	const struct wpa_dbus_property_desc *property_desc,
4516 	DBusMessageIter *iter, DBusError *error, void *user_data)
4517 {
4518 #ifdef CONFIG_AP
4519 	struct sta_handler_args *args = user_data;
4520 	struct sta_info *sta;
4521 	struct hostap_sta_driver_data data;
4522 	struct hostapd_data *hapd;
4523 
4524 	if (!args->wpa_s->ap_iface)
4525 		return FALSE;
4526 
4527 	hapd = args->wpa_s->ap_iface->bss[0];
4528 	sta = ap_get_sta(hapd, args->sta);
4529 	if (!sta)
4530 		return FALSE;
4531 
4532 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4533 		return FALSE;
4534 
4535 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4536 						&data.rx_bytes,
4537 						error);
4538 #else /* CONFIG_AP */
4539     return FALSE;
4540 #endif /* CONFIG_AP */
4541 }
4542 
4543 
4544 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
4545 				       DBusError *error, const char *func_name)
4546 {
4547 	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
4548 
4549 	if (!res) {
4550 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
4551 			   func_name, args->id);
4552 		dbus_set_error(error, DBUS_ERROR_FAILED,
4553 			       "%s: BSS %d not found",
4554 			       func_name, args->id);
4555 	}
4556 
4557 	return res;
4558 }
4559 
4560 
4561 /**
4562  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
4563  * @iter: Pointer to incoming dbus message iter
4564  * @error: Location to store error on failure
4565  * @user_data: Function specific data
4566  * Returns: TRUE on success, FALSE on failure
4567  *
4568  * Getter for "BSSID" property.
4569  */
4570 dbus_bool_t wpas_dbus_getter_bss_bssid(
4571 	const struct wpa_dbus_property_desc *property_desc,
4572 	DBusMessageIter *iter, DBusError *error, void *user_data)
4573 {
4574 	struct bss_handler_args *args = user_data;
4575 	struct wpa_bss *res;
4576 
4577 	res = get_bss_helper(args, error, __func__);
4578 	if (!res)
4579 		return FALSE;
4580 
4581 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4582 						      res->bssid, ETH_ALEN,
4583 						      error);
4584 }
4585 
4586 
4587 /**
4588  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
4589  * @iter: Pointer to incoming dbus message iter
4590  * @error: Location to store error on failure
4591  * @user_data: Function specific data
4592  * Returns: TRUE on success, FALSE on failure
4593  *
4594  * Getter for "SSID" property.
4595  */
4596 dbus_bool_t wpas_dbus_getter_bss_ssid(
4597 	const struct wpa_dbus_property_desc *property_desc,
4598 	DBusMessageIter *iter, DBusError *error, void *user_data)
4599 {
4600 	struct bss_handler_args *args = user_data;
4601 	struct wpa_bss *res;
4602 
4603 	res = get_bss_helper(args, error, __func__);
4604 	if (!res)
4605 		return FALSE;
4606 
4607 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4608 						      res->ssid, res->ssid_len,
4609 						      error);
4610 }
4611 
4612 
4613 /**
4614  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
4615  * @iter: Pointer to incoming dbus message iter
4616  * @error: Location to store error on failure
4617  * @user_data: Function specific data
4618  * Returns: TRUE on success, FALSE on failure
4619  *
4620  * Getter for "Privacy" property.
4621  */
4622 dbus_bool_t wpas_dbus_getter_bss_privacy(
4623 	const struct wpa_dbus_property_desc *property_desc,
4624 	DBusMessageIter *iter, DBusError *error, void *user_data)
4625 {
4626 	struct bss_handler_args *args = user_data;
4627 	struct wpa_bss *res;
4628 	dbus_bool_t privacy;
4629 
4630 	res = get_bss_helper(args, error, __func__);
4631 	if (!res)
4632 		return FALSE;
4633 
4634 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
4635 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
4636 						&privacy, error);
4637 }
4638 
4639 
4640 /**
4641  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
4642  * @iter: Pointer to incoming dbus message iter
4643  * @error: Location to store error on failure
4644  * @user_data: Function specific data
4645  * Returns: TRUE on success, FALSE on failure
4646  *
4647  * Getter for "Mode" property.
4648  */
4649 dbus_bool_t wpas_dbus_getter_bss_mode(
4650 	const struct wpa_dbus_property_desc *property_desc,
4651 	DBusMessageIter *iter, DBusError *error, void *user_data)
4652 {
4653 	struct bss_handler_args *args = user_data;
4654 	struct wpa_bss *res;
4655 	const char *mode;
4656 	const u8 *mesh;
4657 
4658 	res = get_bss_helper(args, error, __func__);
4659 	if (!res)
4660 		return FALSE;
4661 	if (bss_is_dmg(res)) {
4662 		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
4663 		case IEEE80211_CAP_DMG_PBSS:
4664 		case IEEE80211_CAP_DMG_IBSS:
4665 			mode = "ad-hoc";
4666 			break;
4667 		case IEEE80211_CAP_DMG_AP:
4668 			mode = "infrastructure";
4669 			break;
4670 		default:
4671 			mode = "";
4672 			break;
4673 		}
4674 	} else {
4675 		mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
4676 		if (mesh)
4677 			mode = "mesh";
4678 		else if (res->caps & IEEE80211_CAP_IBSS)
4679 			mode = "ad-hoc";
4680 		else
4681 			mode = "infrastructure";
4682 	}
4683 
4684 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
4685 						&mode, error);
4686 }
4687 
4688 
4689 /**
4690  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
4691  * @iter: Pointer to incoming dbus message iter
4692  * @error: Location to store error on failure
4693  * @user_data: Function specific data
4694  * Returns: TRUE on success, FALSE on failure
4695  *
4696  * Getter for "Level" property.
4697  */
4698 dbus_bool_t wpas_dbus_getter_bss_signal(
4699 	const struct wpa_dbus_property_desc *property_desc,
4700 	DBusMessageIter *iter, DBusError *error, void *user_data)
4701 {
4702 	struct bss_handler_args *args = user_data;
4703 	struct wpa_bss *res;
4704 	s16 level;
4705 
4706 	res = get_bss_helper(args, error, __func__);
4707 	if (!res)
4708 		return FALSE;
4709 
4710 	level = (s16) res->level;
4711 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
4712 						&level, error);
4713 }
4714 
4715 
4716 /**
4717  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
4718  * @iter: Pointer to incoming dbus message iter
4719  * @error: Location to store error on failure
4720  * @user_data: Function specific data
4721  * Returns: TRUE on success, FALSE on failure
4722  *
4723  * Getter for "Frequency" property.
4724  */
4725 dbus_bool_t wpas_dbus_getter_bss_frequency(
4726 	const struct wpa_dbus_property_desc *property_desc,
4727 	DBusMessageIter *iter, DBusError *error, void *user_data)
4728 {
4729 	struct bss_handler_args *args = user_data;
4730 	struct wpa_bss *res;
4731 	u16 freq;
4732 
4733 	res = get_bss_helper(args, error, __func__);
4734 	if (!res)
4735 		return FALSE;
4736 
4737 	freq = (u16) res->freq;
4738 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4739 						&freq, error);
4740 }
4741 
4742 
4743 static int cmp_u8s_desc(const void *a, const void *b)
4744 {
4745 	return (*(u8 *) b - *(u8 *) a);
4746 }
4747 
4748 
4749 /**
4750  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
4751  * @iter: Pointer to incoming dbus message iter
4752  * @error: Location to store error on failure
4753  * @user_data: Function specific data
4754  * Returns: TRUE on success, FALSE on failure
4755  *
4756  * Getter for "Rates" property.
4757  */
4758 dbus_bool_t wpas_dbus_getter_bss_rates(
4759 	const struct wpa_dbus_property_desc *property_desc,
4760 	DBusMessageIter *iter, DBusError *error, void *user_data)
4761 {
4762 	struct bss_handler_args *args = user_data;
4763 	struct wpa_bss *res;
4764 	u8 *ie_rates = NULL;
4765 	u32 *real_rates;
4766 	int rates_num, i;
4767 	dbus_bool_t success = FALSE;
4768 
4769 	res = get_bss_helper(args, error, __func__);
4770 	if (!res)
4771 		return FALSE;
4772 
4773 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
4774 	if (rates_num < 0)
4775 		return FALSE;
4776 
4777 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
4778 
4779 	real_rates = os_malloc(sizeof(u32) * rates_num);
4780 	if (!real_rates) {
4781 		os_free(ie_rates);
4782 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4783 		return FALSE;
4784 	}
4785 
4786 	for (i = 0; i < rates_num; i++)
4787 		real_rates[i] = ie_rates[i] * 500000;
4788 
4789 	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
4790 							 real_rates, rates_num,
4791 							 error);
4792 
4793 	os_free(ie_rates);
4794 	os_free(real_rates);
4795 	return success;
4796 }
4797 
4798 
4799 static dbus_bool_t wpas_dbus_get_bss_security_prop(
4800 	const struct wpa_dbus_property_desc *property_desc,
4801 	DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
4802 {
4803 	DBusMessageIter iter_dict, variant_iter;
4804 	const char *group;
4805 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
4806 	const char *key_mgmt[16]; /* max 16 key managements may be supported */
4807 	int n;
4808 
4809 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4810 					      "a{sv}", &variant_iter))
4811 		goto nomem;
4812 
4813 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
4814 		goto nomem;
4815 
4816 	/*
4817 	 * KeyMgmt
4818 	 *
4819 	 * When adding a new entry here, please take care to extend key_mgmt[]
4820 	 * and keep documentation in doc/dbus.doxygen up to date.
4821 	 */
4822 	n = 0;
4823 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
4824 		key_mgmt[n++] = "wpa-psk";
4825 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
4826 		key_mgmt[n++] = "wpa-ft-psk";
4827 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
4828 		key_mgmt[n++] = "wpa-psk-sha256";
4829 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
4830 		key_mgmt[n++] = "wpa-eap";
4831 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
4832 		key_mgmt[n++] = "wpa-ft-eap";
4833 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
4834 		key_mgmt[n++] = "wpa-eap-sha256";
4835 #ifdef CONFIG_SUITEB
4836 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
4837 		key_mgmt[n++] = "wpa-eap-suite-b";
4838 #endif /* CONFIG_SUITEB */
4839 #ifdef CONFIG_SUITEB192
4840 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
4841 		key_mgmt[n++] = "wpa-eap-suite-b-192";
4842 #endif /* CONFIG_SUITEB192 */
4843 #ifdef CONFIG_FILS
4844 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
4845 		key_mgmt[n++] = "wpa-fils-sha256";
4846 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
4847 		key_mgmt[n++] = "wpa-fils-sha384";
4848 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
4849 		key_mgmt[n++] = "wpa-ft-fils-sha256";
4850 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
4851 		key_mgmt[n++] = "wpa-ft-fils-sha384";
4852 #endif /* CONFIG_FILS */
4853 #ifdef CONFIG_SAE
4854 	if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
4855 		key_mgmt[n++] = "sae";
4856 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
4857 		key_mgmt[n++] = "ft-sae";
4858 #endif /* CONFIG_SAE */
4859 #ifdef CONFIG_OWE
4860 	if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
4861 		key_mgmt[n++] = "owe";
4862 #endif /* CONFIG_OWE */
4863 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
4864 		key_mgmt[n++] = "wpa-none";
4865 
4866 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
4867 					       key_mgmt, n))
4868 		goto nomem;
4869 
4870 	/* Group */
4871 	switch (ie_data->group_cipher) {
4872 #ifdef CONFIG_WEP
4873 	case WPA_CIPHER_WEP40:
4874 		group = "wep40";
4875 		break;
4876 	case WPA_CIPHER_WEP104:
4877 		group = "wep104";
4878 		break;
4879 #endif /* CONFIG_WEP */
4880 #ifndef CONFIG_NO_TKIP
4881 	case WPA_CIPHER_TKIP:
4882 		group = "tkip";
4883 		break;
4884 #endif /* CONFIG_NO_TKIP */
4885 	case WPA_CIPHER_CCMP:
4886 		group = "ccmp";
4887 		break;
4888 	case WPA_CIPHER_GCMP:
4889 		group = "gcmp";
4890 		break;
4891 	case WPA_CIPHER_CCMP_256:
4892 		group = "ccmp-256";
4893 		break;
4894 	case WPA_CIPHER_GCMP_256:
4895 		group = "gcmp-256";
4896 		break;
4897 	default:
4898 		group = "";
4899 		break;
4900 	}
4901 
4902 	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
4903 		goto nomem;
4904 
4905 	/* Pairwise */
4906 	n = 0;
4907 #ifndef CONFIG_NO_TKIP
4908 	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
4909 		pairwise[n++] = "tkip";
4910 #endif /* CONFIG_NO_TKIP */
4911 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
4912 		pairwise[n++] = "ccmp";
4913 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
4914 		pairwise[n++] = "gcmp";
4915 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
4916 		pairwise[n++] = "ccmp-256";
4917 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
4918 		pairwise[n++] = "gcmp-256";
4919 
4920 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
4921 					       pairwise, n))
4922 		goto nomem;
4923 
4924 	/* Management group (RSN only) */
4925 	if (ie_data->proto == WPA_PROTO_RSN) {
4926 		switch (ie_data->mgmt_group_cipher) {
4927 		case WPA_CIPHER_AES_128_CMAC:
4928 			group = "aes128cmac";
4929 			break;
4930 		default:
4931 			group = "";
4932 			break;
4933 		}
4934 
4935 		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
4936 						 group))
4937 			goto nomem;
4938 	}
4939 
4940 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
4941 	    !dbus_message_iter_close_container(iter, &variant_iter))
4942 		goto nomem;
4943 
4944 	return TRUE;
4945 
4946 nomem:
4947 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4948 	return FALSE;
4949 }
4950 
4951 
4952 /**
4953  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
4954  * @iter: Pointer to incoming dbus message iter
4955  * @error: Location to store error on failure
4956  * @user_data: Function specific data
4957  * Returns: TRUE on success, FALSE on failure
4958  *
4959  * Getter for "WPA" property.
4960  */
4961 dbus_bool_t wpas_dbus_getter_bss_wpa(
4962 	const struct wpa_dbus_property_desc *property_desc,
4963 	DBusMessageIter *iter, DBusError *error, void *user_data)
4964 {
4965 	struct bss_handler_args *args = user_data;
4966 	struct wpa_bss *res;
4967 	struct wpa_ie_data wpa_data;
4968 	const u8 *ie;
4969 
4970 	res = get_bss_helper(args, error, __func__);
4971 	if (!res)
4972 		return FALSE;
4973 
4974 	os_memset(&wpa_data, 0, sizeof(wpa_data));
4975 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
4976 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
4977 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
4978 				     "failed to parse WPA IE");
4979 		return FALSE;
4980 	}
4981 
4982 	return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
4983 }
4984 
4985 
4986 /**
4987  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
4988  * @iter: Pointer to incoming dbus message iter
4989  * @error: Location to store error on failure
4990  * @user_data: Function specific data
4991  * Returns: TRUE on success, FALSE on failure
4992  *
4993  * Getter for "RSN" property.
4994  */
4995 dbus_bool_t wpas_dbus_getter_bss_rsn(
4996 	const struct wpa_dbus_property_desc *property_desc,
4997 	DBusMessageIter *iter, DBusError *error, void *user_data)
4998 {
4999 	struct bss_handler_args *args = user_data;
5000 	struct wpa_bss *res;
5001 	struct wpa_ie_data wpa_data;
5002 	const u8 *ie;
5003 
5004 	res = get_bss_helper(args, error, __func__);
5005 	if (!res)
5006 		return FALSE;
5007 
5008 	os_memset(&wpa_data, 0, sizeof(wpa_data));
5009 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
5010 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
5011 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
5012 				     "failed to parse RSN IE");
5013 		return FALSE;
5014 	}
5015 
5016 	return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
5017 }
5018 
5019 
5020 /**
5021  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
5022  * @iter: Pointer to incoming dbus message iter
5023  * @error: Location to store error on failure
5024  * @user_data: Function specific data
5025  * Returns: TRUE on success, FALSE on failure
5026  *
5027  * Getter for "WPS" property.
5028  */
5029 dbus_bool_t wpas_dbus_getter_bss_wps(
5030 	const struct wpa_dbus_property_desc *property_desc,
5031 	DBusMessageIter *iter, DBusError *error, void *user_data)
5032 {
5033 	struct bss_handler_args *args = user_data;
5034 	struct wpa_bss *res;
5035 #ifdef CONFIG_WPS
5036 	struct wpabuf *wps_ie;
5037 #endif /* CONFIG_WPS */
5038 	DBusMessageIter iter_dict, variant_iter;
5039 	int wps_support = 0;
5040 	const char *type = "";
5041 
5042 	res = get_bss_helper(args, error, __func__);
5043 	if (!res)
5044 		return FALSE;
5045 
5046 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5047 					      "a{sv}", &variant_iter) ||
5048 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
5049 		goto nomem;
5050 
5051 #ifdef CONFIG_WPS
5052 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
5053 	if (wps_ie) {
5054 		wps_support = 1;
5055 		if (wps_is_selected_pbc_registrar(wps_ie))
5056 			type = "pbc";
5057 		else if (wps_is_selected_pin_registrar(wps_ie))
5058 			type = "pin";
5059 
5060 		wpabuf_free(wps_ie);
5061 	}
5062 #endif /* CONFIG_WPS */
5063 
5064 	if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
5065 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
5066 	    !dbus_message_iter_close_container(iter, &variant_iter))
5067 		goto nomem;
5068 
5069 	return TRUE;
5070 
5071 nomem:
5072 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5073 	return FALSE;
5074 }
5075 
5076 
5077 /**
5078  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
5079  * @iter: Pointer to incoming dbus message iter
5080  * @error: Location to store error on failure
5081  * @user_data: Function specific data
5082  * Returns: TRUE on success, FALSE on failure
5083  *
5084  * Getter for "IEs" property.
5085  */
5086 dbus_bool_t wpas_dbus_getter_bss_ies(
5087 	const struct wpa_dbus_property_desc *property_desc,
5088 	DBusMessageIter *iter, DBusError *error, void *user_data)
5089 {
5090 	struct bss_handler_args *args = user_data;
5091 	struct wpa_bss *res;
5092 
5093 	res = get_bss_helper(args, error, __func__);
5094 	if (!res)
5095 		return FALSE;
5096 
5097 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5098 						      wpa_bss_ie_ptr(res),
5099 						      res->ie_len, error);
5100 }
5101 
5102 
5103 /**
5104  * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
5105  * @iter: Pointer to incoming dbus message iter
5106  * @error: Location to store error on failure
5107  * @user_data: Function specific data
5108  * Returns: TRUE on success, FALSE on failure
5109  *
5110  * Getter for BSS age
5111  */
5112 dbus_bool_t wpas_dbus_getter_bss_age(
5113 	const struct wpa_dbus_property_desc *property_desc,
5114 	DBusMessageIter *iter, DBusError *error, void *user_data)
5115 {
5116 	struct bss_handler_args *args = user_data;
5117 	struct wpa_bss *res;
5118 	struct os_reltime now, diff = { 0, 0 };
5119 	u32 age;
5120 
5121 	res = get_bss_helper(args, error, __func__);
5122 	if (!res)
5123 		return FALSE;
5124 
5125 	os_get_reltime(&now);
5126 	os_reltime_sub(&now, &res->last_update, &diff);
5127 	age = diff.sec > 0 ? diff.sec : 0;
5128 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
5129 						error);
5130 }
5131 
5132 
5133 /**
5134  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
5135  * @iter: Pointer to incoming dbus message iter
5136  * @error: Location to store error on failure
5137  * @user_data: Function specific data
5138  * Returns: TRUE on success, FALSE on failure
5139  *
5140  * Getter for "enabled" property of a configured network.
5141  */
5142 dbus_bool_t wpas_dbus_getter_enabled(
5143 	const struct wpa_dbus_property_desc *property_desc,
5144 	DBusMessageIter *iter, DBusError *error, void *user_data)
5145 {
5146 	struct network_handler_args *net = user_data;
5147 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
5148 
5149 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
5150 						&enabled, error);
5151 }
5152 
5153 
5154 /**
5155  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
5156  * @iter: Pointer to incoming dbus message iter
5157  * @error: Location to store error on failure
5158  * @user_data: Function specific data
5159  * Returns: TRUE on success, FALSE on failure
5160  *
5161  * Setter for "Enabled" property of a configured network.
5162  */
5163 dbus_bool_t wpas_dbus_setter_enabled(
5164 	const struct wpa_dbus_property_desc *property_desc,
5165 	DBusMessageIter *iter, DBusError *error, void *user_data)
5166 {
5167 	struct network_handler_args *net = user_data;
5168 	struct wpa_supplicant *wpa_s;
5169 	struct wpa_ssid *ssid;
5170 	dbus_bool_t enable;
5171 
5172 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
5173 					      &enable))
5174 		return FALSE;
5175 
5176 	wpa_s = net->wpa_s;
5177 	ssid = net->ssid;
5178 
5179 	if (enable)
5180 		wpa_supplicant_enable_network(wpa_s, ssid);
5181 	else
5182 		wpa_supplicant_disable_network(wpa_s, ssid);
5183 
5184 	return TRUE;
5185 }
5186 
5187 
5188 /**
5189  * wpas_dbus_getter_network_properties - Get options for a configured network
5190  * @iter: Pointer to incoming dbus message iter
5191  * @error: Location to store error on failure
5192  * @user_data: Function specific data
5193  * Returns: TRUE on success, FALSE on failure
5194  *
5195  * Getter for "Properties" property of a configured network.
5196  */
5197 dbus_bool_t wpas_dbus_getter_network_properties(
5198 	const struct wpa_dbus_property_desc *property_desc,
5199 	DBusMessageIter *iter, DBusError *error, void *user_data)
5200 {
5201 	struct network_handler_args *net = user_data;
5202 	DBusMessageIter	variant_iter, dict_iter;
5203 	char **iterator;
5204 	char **props = wpa_config_get_all(net->ssid, 1);
5205 	dbus_bool_t success = FALSE;
5206 
5207 	if (!props) {
5208 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5209 		return FALSE;
5210 	}
5211 
5212 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
5213 					      &variant_iter) ||
5214 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
5215 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5216 		goto out;
5217 	}
5218 
5219 	iterator = props;
5220 	while (*iterator) {
5221 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
5222 						 *(iterator + 1))) {
5223 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
5224 					     "no memory");
5225 			goto out;
5226 		}
5227 		iterator += 2;
5228 	}
5229 
5230 
5231 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
5232 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
5233 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5234 		goto out;
5235 	}
5236 
5237 	success = TRUE;
5238 
5239 out:
5240 	iterator = props;
5241 	while (*iterator) {
5242 		os_free(*iterator);
5243 		iterator++;
5244 	}
5245 	os_free(props);
5246 	return success;
5247 }
5248 
5249 
5250 /**
5251  * wpas_dbus_setter_network_properties - Set options for a configured network
5252  * @iter: Pointer to incoming dbus message iter
5253  * @error: Location to store error on failure
5254  * @user_data: Function specific data
5255  * Returns: TRUE on success, FALSE on failure
5256  *
5257  * Setter for "Properties" property of a configured network.
5258  */
5259 dbus_bool_t wpas_dbus_setter_network_properties(
5260 	const struct wpa_dbus_property_desc *property_desc,
5261 	DBusMessageIter *iter, DBusError *error, void *user_data)
5262 {
5263 	struct network_handler_args *net = user_data;
5264 	struct wpa_ssid *ssid = net->ssid;
5265 	DBusMessageIter	variant_iter;
5266 
5267 	dbus_message_iter_recurse(iter, &variant_iter);
5268 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
5269 }
5270 
5271 
5272 #ifdef CONFIG_AP
5273 
5274 DBusMessage * wpas_dbus_handler_subscribe_preq(
5275 	DBusMessage *message, struct wpa_supplicant *wpa_s)
5276 {
5277 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5278 	char *name;
5279 
5280 	if (wpa_s->preq_notify_peer != NULL) {
5281 		if (os_strcmp(dbus_message_get_sender(message),
5282 			      wpa_s->preq_notify_peer) == 0)
5283 			return NULL;
5284 
5285 		return dbus_message_new_error(message,
5286 			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
5287 			"Another application is already subscribed");
5288 	}
5289 
5290 	name = os_strdup(dbus_message_get_sender(message));
5291 	if (!name)
5292 		return wpas_dbus_error_no_memory(message);
5293 
5294 	wpa_s->preq_notify_peer = name;
5295 
5296 	/* Subscribe to clean up if application closes socket */
5297 	wpas_dbus_subscribe_noc(priv);
5298 
5299 	/*
5300 	 * Double-check it's still alive to make sure that we didn't
5301 	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
5302 	 */
5303 	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
5304 		/*
5305 		 * Application no longer exists, clean up.
5306 		 * The return value is irrelevant now.
5307 		 *
5308 		 * Need to check if the NameOwnerChanged handling
5309 		 * already cleaned up because we have processed
5310 		 * DBus messages while checking if the name still
5311 		 * has an owner.
5312 		 */
5313 		if (!wpa_s->preq_notify_peer)
5314 			return NULL;
5315 		os_free(wpa_s->preq_notify_peer);
5316 		wpa_s->preq_notify_peer = NULL;
5317 		wpas_dbus_unsubscribe_noc(priv);
5318 	}
5319 
5320 	return NULL;
5321 }
5322 
5323 
5324 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
5325 	DBusMessage *message, struct wpa_supplicant *wpa_s)
5326 {
5327 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5328 
5329 	if (!wpa_s->preq_notify_peer)
5330 		return dbus_message_new_error(message,
5331 			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
5332 			"Not subscribed");
5333 
5334 	if (os_strcmp(wpa_s->preq_notify_peer,
5335 		      dbus_message_get_sender(message)))
5336 		return dbus_message_new_error(message,
5337 			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
5338 			"Can't unsubscribe others");
5339 
5340 	os_free(wpa_s->preq_notify_peer);
5341 	wpa_s->preq_notify_peer = NULL;
5342 	wpas_dbus_unsubscribe_noc(priv);
5343 	return NULL;
5344 }
5345 
5346 
5347 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
5348 			   const u8 *addr, const u8 *dst, const u8 *bssid,
5349 			   const u8 *ie, size_t ie_len, u32 ssi_signal)
5350 {
5351 	DBusMessage *msg;
5352 	DBusMessageIter iter, dict_iter;
5353 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5354 
5355 	/* Do nothing if the control interface is not turned on */
5356 	if (priv == NULL || !wpa_s->dbus_new_path)
5357 		return;
5358 
5359 	if (wpa_s->preq_notify_peer == NULL)
5360 		return;
5361 
5362 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
5363 				      WPAS_DBUS_NEW_IFACE_INTERFACE,
5364 				      "ProbeRequest");
5365 	if (msg == NULL)
5366 		return;
5367 
5368 	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
5369 
5370 	dbus_message_iter_init_append(msg, &iter);
5371 
5372 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
5373 	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
5374 						      (const char *) addr,
5375 						      ETH_ALEN)) ||
5376 	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
5377 						     (const char *) dst,
5378 						     ETH_ALEN)) ||
5379 	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
5380 						       (const char *) bssid,
5381 						       ETH_ALEN)) ||
5382 	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
5383 							      (const char *) ie,
5384 							      ie_len)) ||
5385 	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
5386 						       ssi_signal)) ||
5387 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
5388 		goto fail;
5389 
5390 	dbus_connection_send(priv->con, msg, NULL);
5391 	goto out;
5392 fail:
5393 	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
5394 out:
5395 	dbus_message_unref(msg);
5396 }
5397 
5398 #endif /* CONFIG_AP */
5399 
5400 
5401 DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
5402 						struct wpa_supplicant *wpa_s)
5403 {
5404 	u8 *ielems;
5405 	int len;
5406 	struct ieee802_11_elems elems;
5407 	dbus_int32_t frame_id;
5408 	DBusMessageIter	iter, array;
5409 
5410 	dbus_message_iter_init(message, &iter);
5411 	dbus_message_iter_get_basic(&iter, &frame_id);
5412 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5413 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5414 					      "Invalid ID");
5415 	}
5416 
5417 	dbus_message_iter_next(&iter);
5418 	dbus_message_iter_recurse(&iter, &array);
5419 	dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5420 	if (!ielems || len == 0) {
5421 		return dbus_message_new_error(
5422 			message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
5423 	}
5424 
5425 	if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5426 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5427 					      "Parse error");
5428 	}
5429 
5430 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5431 	if (!wpa_s->vendor_elem[frame_id]) {
5432 		wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
5433 		wpas_vendor_elem_update(wpa_s);
5434 		return NULL;
5435 	}
5436 
5437 	if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
5438 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5439 					      "Resize error");
5440 	}
5441 
5442 	wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
5443 	wpas_vendor_elem_update(wpa_s);
5444 	return NULL;
5445 }
5446 
5447 
5448 DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
5449 						struct wpa_supplicant *wpa_s)
5450 {
5451 	DBusMessage *reply;
5452 	DBusMessageIter	iter, array_iter;
5453 	dbus_int32_t frame_id;
5454 	const u8 *elem;
5455 	size_t elem_len;
5456 
5457 	dbus_message_iter_init(message, &iter);
5458 	dbus_message_iter_get_basic(&iter, &frame_id);
5459 
5460 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5461 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5462 					      "Invalid ID");
5463 	}
5464 
5465 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5466 	if (!wpa_s->vendor_elem[frame_id]) {
5467 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5468 					      "ID value does not exist");
5469 	}
5470 
5471 	reply = dbus_message_new_method_return(message);
5472 	if (!reply)
5473 		return wpas_dbus_error_no_memory(message);
5474 
5475 	dbus_message_iter_init_append(reply, &iter);
5476 
5477 	elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
5478 	elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
5479 
5480 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
5481 					      DBUS_TYPE_BYTE_AS_STRING,
5482 					      &array_iter) ||
5483 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
5484 						  &elem, elem_len) ||
5485 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
5486 		dbus_message_unref(reply);
5487 		reply = wpas_dbus_error_no_memory(message);
5488 	}
5489 
5490 	return reply;
5491 }
5492 
5493 
5494 DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
5495 						   struct wpa_supplicant *wpa_s)
5496 {
5497 	u8 *ielems;
5498 	int len;
5499 	struct ieee802_11_elems elems;
5500 	DBusMessageIter	iter, array;
5501 	dbus_int32_t frame_id;
5502 
5503 	dbus_message_iter_init(message, &iter);
5504 	dbus_message_iter_get_basic(&iter, &frame_id);
5505 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5506 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5507 					      "Invalid ID");
5508 	}
5509 
5510 	dbus_message_iter_next(&iter);
5511 	dbus_message_iter_recurse(&iter, &array);
5512 	dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5513 	if (!ielems || len == 0) {
5514 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5515 					      "Invalid value");
5516 	}
5517 
5518 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5519 
5520 	if (len == 1 && *ielems == '*') {
5521 		wpabuf_free(wpa_s->vendor_elem[frame_id]);
5522 		wpa_s->vendor_elem[frame_id] = NULL;
5523 		wpas_vendor_elem_update(wpa_s);
5524 		return NULL;
5525 	}
5526 
5527 	if (!wpa_s->vendor_elem[frame_id]) {
5528 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5529 					      "ID value does not exist");
5530 	}
5531 
5532 	if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5533 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5534 					      "Parse error");
5535 	}
5536 
5537 	if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
5538 		return NULL;
5539 
5540 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5541 				      "Not found");
5542 }
5543 
5544 
5545 #ifdef CONFIG_MESH
5546 
5547 /**
5548  * wpas_dbus_getter_mesh_peers - Get connected mesh peers
5549  * @iter: Pointer to incoming dbus message iter
5550  * @error: Location to store error on failure
5551  * @user_data: Function specific data
5552  * Returns: TRUE on success, FALSE on failure
5553  *
5554  * Getter for "MeshPeers" property.
5555  */
5556 dbus_bool_t wpas_dbus_getter_mesh_peers(
5557 	const struct wpa_dbus_property_desc *property_desc,
5558 	DBusMessageIter *iter, DBusError *error, void *user_data)
5559 {
5560 	struct wpa_supplicant *wpa_s = user_data;
5561 	struct hostapd_data *hapd;
5562 	struct sta_info *sta;
5563 	DBusMessageIter variant_iter, array_iter;
5564 	int i;
5565 	DBusMessageIter inner_array_iter;
5566 
5567 	if (!wpa_s->ifmsh)
5568 		return FALSE;
5569 	hapd = wpa_s->ifmsh->bss[0];
5570 
5571 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5572 					      DBUS_TYPE_ARRAY_AS_STRING
5573 					      DBUS_TYPE_ARRAY_AS_STRING
5574 					      DBUS_TYPE_BYTE_AS_STRING,
5575 					      &variant_iter) ||
5576 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
5577 					      DBUS_TYPE_ARRAY_AS_STRING
5578 					      DBUS_TYPE_BYTE_AS_STRING,
5579 					      &array_iter))
5580 		return FALSE;
5581 
5582 	for (sta = hapd->sta_list; sta; sta = sta->next) {
5583 		if (!dbus_message_iter_open_container(
5584 			    &array_iter, DBUS_TYPE_ARRAY,
5585 			    DBUS_TYPE_BYTE_AS_STRING,
5586 			    &inner_array_iter))
5587 			return FALSE;
5588 
5589 		for (i = 0; i < ETH_ALEN; i++) {
5590 			if (!dbus_message_iter_append_basic(&inner_array_iter,
5591 							    DBUS_TYPE_BYTE,
5592 							    &(sta->addr[i])))
5593 				return FALSE;
5594 		}
5595 
5596 		if (!dbus_message_iter_close_container(
5597 			    &array_iter, &inner_array_iter))
5598 			return FALSE;
5599 	}
5600 
5601 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
5602 	    !dbus_message_iter_close_container(iter, &variant_iter))
5603 		return FALSE;
5604 
5605 	return TRUE;
5606 }
5607 
5608 
5609 /**
5610  * wpas_dbus_getter_mesh_group - Get mesh group
5611  * @iter: Pointer to incoming dbus message iter
5612  * @error: Location to store error on failure
5613  * @user_data: Function specific data
5614  * Returns: TRUE on success, FALSE on failure
5615  *
5616  * Getter for "MeshGroup" property.
5617  */
5618 dbus_bool_t wpas_dbus_getter_mesh_group(
5619 	const struct wpa_dbus_property_desc *property_desc,
5620 	DBusMessageIter *iter, DBusError *error, void *user_data)
5621 {
5622 	struct wpa_supplicant *wpa_s = user_data;
5623 	struct wpa_ssid *ssid = wpa_s->current_ssid;
5624 
5625 	if (!wpa_s->ifmsh || !ssid)
5626 		return FALSE;
5627 
5628 	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5629 						    (char *) ssid->ssid,
5630 						    ssid->ssid_len, error)) {
5631 		dbus_set_error(error, DBUS_ERROR_FAILED,
5632 			       "%s: error constructing reply", __func__);
5633 		return FALSE;
5634 	}
5635 
5636 	return TRUE;
5637 }
5638 
5639 #endif /* CONFIG_MESH */
5640