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