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