X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fdbus%2Fdbus_new_handlers.c;h=8ccace57973fcd2e94bfdba6d4584b8950fcb82c;hb=5f040be4ff78f26b84840fa31037831bdd886f5b;hp=e41fc162178e14450ac387d2da711492fbe8b2d2;hpb=5b49c9d5edf9006be0c4e19b8ffc7b257a18a054;p=mech_eap.git diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index e41fc16..8ccace5 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -2,16 +2,10 @@ * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2015, Jouni Malinen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -25,89 +19,23 @@ #include "../wpa_supplicant_i.h" #include "../driver_i.h" #include "../notify.h" -#include "../wpas_glue.h" #include "../bss.h" #include "../scan.h" +#include "../autoscan.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_dict_helpers.h" +#include "dbus_common_i.h" +#include "drivers/driver.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -static const char *debug_strings[] = { - "msgdump", "debug", "info", "warning", "error", NULL +static const char * const debug_strings[] = { + "excessive", "msgdump", "debug", "info", "warning", "error", NULL }; /** - * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts - * @path: The dbus object path - * @network: (out) the configured network this object path refers to, if any - * @bssid: (out) the scanned bssid this object path refers to, if any - * Returns: The object path of the network interface this path refers to - * - * For a given object path, decomposes the object path into object id, network, - * and BSSID parts, if those parts exist. - */ -static char * wpas_dbus_new_decompose_object_path(const char *path, - char **network, - char **bssid) -{ - const unsigned int dev_path_prefix_len = - strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/"); - char *obj_path_only; - char *next_sep; - - /* Be a bit paranoid about path */ - if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/", - dev_path_prefix_len)) - return NULL; - - /* Ensure there's something at the end of the path */ - if ((path + dev_path_prefix_len)[0] == '\0') - return NULL; - - obj_path_only = os_strdup(path); - if (obj_path_only == NULL) - return NULL; - - next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/'); - if (next_sep != NULL) { - const char *net_part = os_strstr( - next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/"); - const char *bssid_part = os_strstr( - next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/"); - - if (network && net_part) { - /* Deal with a request for a configured network */ - const char *net_name = net_part + - os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/"); - *network = NULL; - if (os_strlen(net_name)) - *network = os_strdup(net_name); - } else if (bssid && bssid_part) { - /* Deal with a request for a scanned BSSID */ - const char *bssid_name = bssid_part + - os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/"); - if (strlen(bssid_name)) - *bssid = os_strdup(bssid_name); - else - *bssid = NULL; - } - - /* Cut off interface object path before "/" */ - *next_sep = '\0'; - } - - return obj_path_only; -} - - -/** - * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message + * wpas_dbus_error_unknown_error - Return a new UnknownError error message * @message: Pointer to incoming dbus message this error refers to * @arg: Optional string appended to error message * Returns: a dbus error message @@ -117,20 +45,6 @@ static char * wpas_dbus_new_decompose_object_path(const char *path, DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, const char *arg) { - /* - * This function can be called as a result of a failure - * within internal getter calls, which will call this function - * with a NULL message parameter. However, dbus_message_new_error - * looks very unkindly (i.e, abort()) on a NULL message, so - * in this case, we should not call it. - */ - if (message == NULL) { - wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error " - "called with NULL message (arg=%s)", - arg ? arg : "N/A"); - return NULL; - } - return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR, arg); } @@ -145,9 +59,9 @@ DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, */ static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) { - return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, - "wpa_supplicant knows nothing about " - "this interface."); + return dbus_message_new_error( + message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, + "wpa_supplicant knows nothing about this interface."); } @@ -160,9 +74,9 @@ static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) */ static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message) { - return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, - "There is no such a network in this " - "interface."); + return dbus_message_new_error( + message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, + "There is no such a network in this interface."); } @@ -178,9 +92,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, { DBusMessage *reply; - reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS, - "Did not receive correct message " - "arguments."); + reply = dbus_message_new_error( + message, WPAS_DBUS_ERROR_INVALID_ARGS, + "Did not receive correct message arguments."); if (arg != NULL) dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); @@ -189,15 +103,40 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, } -static const char *dont_quote[] = { +/** + * wpas_dbus_error_scan_error - Return a new ScanError error message + * @message: Pointer to incoming dbus message this error refers to + * @error: Optional string to be used as the error message + * Returns: a dbus error message + * + * Convenience function to create and return a scan error + */ +static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message, + const char *error) +{ + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_IFACE_SCAN_ERROR, + error); +} + + +DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message) +{ + wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory"); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); +} + + +static const char * const dont_quote[] = { "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", - "bssid", NULL + "bssid", "scan_freq", "freq_list", NULL }; static dbus_bool_t should_quote_opt(const char *key) { int i = 0; + while (dont_quote[i] != NULL) { if (os_strcmp(key, dont_quote[i]) == 0) return FALSE; @@ -218,7 +157,8 @@ static struct wpa_supplicant * get_iface_by_dbus_path( struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { - if (os_strcmp(wpa_s->dbus_new_path, path) == 0) + if (wpa_s->dbus_new_path && + os_strcmp(wpa_s->dbus_new_path, path) == 0) return wpa_s; } return NULL; @@ -227,36 +167,35 @@ static struct wpa_supplicant * get_iface_by_dbus_path( /** * set_network_properties - Set properties of a configured network - * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network * @iter: DBus message iterator containing dictionary of network * properties to set. - * Returns: NULL when succeed or DBus error on failure + * @error: On failure, an error describing the failure + * Returns: TRUE if the request succeeds, FALSE if it failed * * Sets network configuration with parameters given id DBus dictionary */ -static DBusMessage * set_network_properties(DBusMessage *message, - struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, - DBusMessageIter *iter) +dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + DBusMessageIter *iter, + DBusError *error) { - struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; - DBusMessage *reply = NULL; DBusMessageIter iter_dict; + char *value = NULL; - if (!wpa_dbus_dict_open_read(iter, &iter_dict)) - return wpas_dbus_error_invalid_args(message, NULL); + if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) + return FALSE; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - char *value = NULL; size_t size = 50; int ret; - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { - reply = wpas_dbus_error_invalid_args(message, NULL); - break; - } + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + value = NULL; if (entry.type == DBUS_TYPE_ARRAY && entry.array_type == DBUS_TYPE_BYTE) { if (entry.array_len <= 0) @@ -275,7 +214,7 @@ static DBusMessage * set_network_properties(DBusMessage *message, } else if (entry.type == DBUS_TYPE_STRING) { if (should_quote_opt(entry.key)) { size = os_strlen(entry.str_value); - if (size <= 0) + if (size == 0) goto error; size += 3; @@ -285,7 +224,7 @@ static DBusMessage * set_network_properties(DBusMessage *message, ret = os_snprintf(value, size, "\"%s\"", entry.str_value); - if (ret < 0 || (size_t) ret != (size - 1)) + if (os_snprintf_error(size, ret)) goto error; } else { value = os_strdup(entry.str_value); @@ -299,7 +238,7 @@ static DBusMessage * set_network_properties(DBusMessage *message, ret = os_snprintf(value, size, "%u", entry.uint32_value); - if (ret <= 0) + if (os_snprintf_error(size, ret)) goto error; } else if (entry.type == DBUS_TYPE_INT32) { value = os_zalloc(size); @@ -308,7 +247,7 @@ static DBusMessage * set_network_properties(DBusMessage *message, ret = os_snprintf(value, size, "%d", entry.int32_value); - if (ret <= 0) + if (os_snprintf_error(size, ret)) goto error; } else goto error; @@ -316,80 +255,76 @@ static DBusMessage * set_network_properties(DBusMessage *message, if (wpa_config_set(ssid, entry.key, value, 0) < 0) goto error; + if (os_strcmp(entry.key, "bssid") != 0 && + os_strcmp(entry.key, "priority") != 0) + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); + + if (wpa_s->current_ssid == ssid || + wpa_s->current_ssid == NULL) { + /* + * Invalidate the EAP session cache if anything in the + * current or previously used configuration changes. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + if ((os_strcmp(entry.key, "psk") == 0 && value[0] == '"' && ssid->ssid_len) || - (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) wpa_config_update_psk(ssid); else if (os_strcmp(entry.key, "priority") == 0) wpa_config_update_prio_list(wpa_s->conf); os_free(value); + value = NULL; wpa_dbus_dict_entry_clear(&entry); - continue; - - error: - os_free(value); - reply = wpas_dbus_error_invalid_args(message, entry.key); - wpa_dbus_dict_entry_clear(&entry); - break; } - return reply; + return TRUE; + +error: + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; } /** * wpas_dbus_simple_property_getter - Get basic type property - * @message: Pointer to incoming dbus message + * @iter: Message iter to use when appending arguments * @type: DBus type of property (must be basic type) * @val: pointer to place holding property value - * Returns: The DBus message containing response for Properties.Get call - * or DBus error message if error occurred. + * @error: On failure an error describing the failure + * Returns: TRUE if the request was successful, FALSE if it failed * * Generic getter for basic type properties. Type is required to be basic. */ -DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message, - const int type, const void *val) +dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, + const int type, + const void *val, + DBusError *error) { - DBusMessage *reply = NULL; - DBusMessageIter iter, variant_iter; + DBusMessageIter variant_iter; if (!dbus_type_is_basic(type)) { - wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:" - " given type is not basic"); - return wpas_dbus_error_unknown_error(message, NULL); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; } - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); - else - reply = dbus_message_new_method_return(message); - - if (reply != NULL) { - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container( - &iter, DBUS_TYPE_VARIANT, - wpa_dbus_type_as_string(type), &variant_iter) || - !dbus_message_iter_append_basic(&variant_iter, type, - val) || - !dbus_message_iter_close_container(&iter, &variant_iter)) { - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_property_getter: out of " - "memory to put property value into " - "message"); - dbus_message_unref(reply); - reply = dbus_message_new_error(message, - DBUS_ERROR_NO_MEMORY, - NULL); - } - } else { - wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:" - " out of memory to return property value"); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + wpa_dbus_type_as_string(type), + &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, type, val) || + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: error constructing reply", __func__); + return FALSE; } - return reply; + return TRUE; } @@ -398,105 +333,77 @@ DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message, * @message: Pointer to incoming dbus message * @type: DBus type of property (must be basic type) * @val: pointer to place where value being set will be stored - * Returns: NULL or DBus error message if error occurred. + * Returns: TRUE if the request was successful, FALSE if it failed * * Generic setter for basic type properties. Type is required to be basic. */ -DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message, - const int type, void *val) +dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, + DBusError *error, + const int type, void *val) { - DBusMessageIter iter, variant_iter; + DBusMessageIter variant_iter; if (!dbus_type_is_basic(type)) { - wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:" - " given type is not basic"); - return wpas_dbus_error_unknown_error(message, NULL); - } - - if (!dbus_message_iter_init(message, &iter)) { - wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:" - " out of memory to return scanning state"); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; } - /* omit first and second argument and get value from third */ - dbus_message_iter_next(&iter); - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &variant_iter); - + /* Look at the new value */ + dbus_message_iter_recurse(iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != type) { - wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:" - " wrong property type"); - return wpas_dbus_error_invalid_args(message, - "wrong property type"); + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "wrong property type"); + return FALSE; } dbus_message_iter_get_basic(&variant_iter, val); - return NULL; + return TRUE; } /** * wpas_dbus_simple_array_property_getter - Get array type property - * @message: Pointer to incoming dbus message + * @iter: Pointer to incoming dbus message iterator * @type: DBus type of property array elements (must be basic type) * @array: pointer to array of elements to put into response message * @array_len: length of above array - * Returns: The DBus message containing response for Properties.Get call - * or DBus error message if error occurred. + * @error: a pointer to an error to fill on failure + * Returns: TRUE if the request succeeded, FALSE if it failed * * Generic getter for array type properties. Array elements type is * required to be basic. */ -DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message, - const int type, - const void *array, - size_t array_len) +dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, + const int type, + const void *array, + size_t array_len, + DBusError *error) { - DBusMessage *reply = NULL; - DBusMessageIter iter, variant_iter, array_iter; + DBusMessageIter variant_iter, array_iter; char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ const char *sub_type_str; size_t element_size, i; if (!dbus_type_is_basic(type)) { - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_array_property_getter: given " - "type is not basic"); - return wpas_dbus_error_unknown_error(message, NULL); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; } sub_type_str = wpa_dbus_type_as_string(type); type_str[1] = sub_type_str[0]; - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); - else - reply = dbus_message_new_method_return(message); - if (reply == NULL) { - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_array_property_getter: out of " - "memory to create return message"); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - } - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str, &variant_iter) || !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, sub_type_str, &array_iter)) { - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_array_property_getter: out of " - "memory to open container"); - dbus_message_unref(reply); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message", __func__); + return FALSE; } - switch(type) { + switch (type) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: element_size = 1; @@ -521,29 +428,91 @@ DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message, element_size = sizeof(char *); break; default: - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_array_property_getter: " - "fatal: unknown element type"); - element_size = 1; - break; + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: unknown element type %d", __func__, type); + return FALSE; } for (i = 0; i < array_len; i++) { - dbus_message_iter_append_basic(&array_iter, type, - array + i * element_size); + if (!dbus_message_iter_append_basic(&array_iter, type, + (const char *) array + + i * element_size)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 2.5", + __func__); + return FALSE; + } } if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || - !dbus_message_iter_close_container(&iter, &variant_iter)) { - wpa_printf(MSG_ERROR, "dbus: " - "wpas_dbus_simple_array_property_getter: out of " - "memory to close container"); - dbus_message_unref(reply); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 3", __func__); + return FALSE; } - return reply; + return TRUE; +} + + +/** + * wpas_dbus_simple_array_array_property_getter - Get array array type property + * @iter: Pointer to incoming dbus message iterator + * @type: DBus type of property array elements (must be basic type) + * @array: pointer to array of elements to put into response message + * @array_len: length of above array + * @error: a pointer to an error to fill on failure + * Returns: TRUE if the request succeeded, FALSE if it failed + * + * Generic getter for array type properties. Array elements type is + * required to be basic. + */ +dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, + const int type, + struct wpabuf **array, + size_t array_len, + DBusError *error) +{ + DBusMessageIter variant_iter, array_iter; + char type_str[] = "aa?"; + char inner_type_str[] = "a?"; + const char *sub_type_str; + size_t i; + + if (!dbus_type_is_basic(type)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; + } + + sub_type_str = wpa_dbus_type_as_string(type); + type_str[2] = sub_type_str[0]; + inner_type_str[1] = sub_type_str[0]; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + type_str, &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + inner_type_str, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message", __func__); + return FALSE; + } + + for (i = 0; i < array_len && array[i]; i++) { + wpa_dbus_dict_bin_array_add_element(&array_iter, + wpabuf_head(array[i]), + wpabuf_len(array[i])); + + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to close message", __func__); + return FALSE; + } + + return TRUE; } @@ -567,33 +536,44 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, struct wpa_dbus_dict_entry entry; char *driver = NULL; char *ifname = NULL; + char *confname = NULL; char *bridge_ifname = NULL; dbus_message_iter_init(message, &iter); - if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; - if (!strcmp(entry.key, "Driver") && - (entry.type == DBUS_TYPE_STRING)) { + if (os_strcmp(entry.key, "Driver") == 0 && + entry.type == DBUS_TYPE_STRING) { + os_free(driver); driver = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (driver == NULL) - goto error; - } else if (!strcmp(entry.key, "Ifname") && - (entry.type == DBUS_TYPE_STRING)) { + goto oom; + } else if (os_strcmp(entry.key, "Ifname") == 0 && + entry.type == DBUS_TYPE_STRING) { + os_free(ifname); ifname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (ifname == NULL) - goto error; - } else if (!strcmp(entry.key, "BridgeIfname") && - (entry.type == DBUS_TYPE_STRING)) { + goto oom; + } else if (os_strcmp(entry.key, "ConfigFile") == 0 && + entry.type == DBUS_TYPE_STRING) { + os_free(confname); + confname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (confname == NULL) + goto oom; + } else if (os_strcmp(entry.key, "BridgeIfname") == 0 && + entry.type == DBUS_TYPE_STRING) { + os_free(bridge_ifname); bridge_ifname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (bridge_ifname == NULL) - goto error; + goto oom; } else { wpa_dbus_dict_entry_clear(&entry); goto error; @@ -608,39 +588,46 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, * an error if we already control it. */ if (wpa_supplicant_get_iface(global, ifname) != NULL) { - reply = dbus_message_new_error(message, - WPAS_DBUS_ERROR_IFACE_EXISTS, - "wpa_supplicant already " - "controls this interface."); + reply = dbus_message_new_error( + message, WPAS_DBUS_ERROR_IFACE_EXISTS, + "wpa_supplicant already controls this interface."); } else { struct wpa_supplicant *wpa_s; struct wpa_interface iface; + os_memset(&iface, 0, sizeof(iface)); iface.driver = driver; iface.ifname = ifname; + iface.confname = confname; iface.bridge_ifname = bridge_ifname; /* Otherwise, have wpa_supplicant attach to it. */ - if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); + if (wpa_s && wpa_s->dbus_new_path) { const char *path = wpa_s->dbus_new_path; + reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, - &path, DBUS_TYPE_INVALID); + &path, DBUS_TYPE_INVALID); } else { reply = wpas_dbus_error_unknown_error( - message, "wpa_supplicant couldn't grab this " - "interface."); + message, + "wpa_supplicant couldn't grab this interface."); } } out: os_free(driver); os_free(ifname); + os_free(confname); os_free(bridge_ifname); return reply; error: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; +oom: + reply = wpas_dbus_error_no_memory(message); + goto out; } @@ -668,10 +655,10 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, wpa_s = get_iface_by_dbus_path(global, path); if (wpa_s == NULL) reply = wpas_dbus_error_iface_unknown(message); - else if (wpa_supplicant_remove_iface(global, wpa_s)) { + else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { reply = wpas_dbus_error_unknown_error( - message, "wpa_supplicant couldn't remove this " - "interface."); + message, + "wpa_supplicant couldn't remove this interface."); } return reply; @@ -699,19 +686,17 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, DBUS_TYPE_INVALID); wpa_s = wpa_supplicant_get_iface(global, ifname); - if (wpa_s == NULL) + if (wpa_s == NULL || wpa_s->dbus_new_path == NULL) return wpas_dbus_error_iface_unknown(message); path = wpa_s->dbus_new_path; reply = dbus_message_new_method_return(message); if (reply == NULL) - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + return wpas_dbus_error_no_memory(message); if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { dbus_message_unref(reply); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + return wpas_dbus_error_no_memory(message); } return reply; @@ -720,79 +705,87 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, /** * wpas_dbus_getter_debug_level - Get debug level - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: DBus message with value of debug level + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "DebugLevel" property. */ -DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_getter_debug_level( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { const char *str; int idx = wpa_debug_level; + if (idx < 0) idx = 0; - if (idx > 4) - idx = 4; + if (idx > 5) + idx = 5; str = debug_strings[idx]; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &str); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &str, error); } /** * wpas_dbus_getter_debug_timestamp - Get debug timestamp - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: DBus message with value of debug timestamp + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "DebugTimestamp" property. */ -DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_getter_debug_timestamp( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, - &wpa_debug_timestamp); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_timestamp, error); } /** * wpas_dbus_getter_debug_show_keys - Get debug show keys - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: DBus message with value of debug show_keys + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "DebugShowKeys" property. */ -DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_getter_debug_show_keys( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, - &wpa_debug_show_keys); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_show_keys, error); } /** * wpas_dbus_setter_debug_level - Set debug level - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: %NULL or DBus error message + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter for "DebugLevel" property. */ -DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_setter_debug_level( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_global *global = user_data; const char *str = NULL; int i, val = -1; - reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING, - &str); - if (reply) - return reply; + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &str)) + return FALSE; for (i = 0; debug_strings[i]; i++) if (os_strcmp(debug_strings[i], str) == 0) { @@ -803,137 +796,185 @@ DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message, if (val < 0 || wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, wpa_debug_show_keys)) { - return wpas_dbus_error_invalid_args( - message, "Wrong debug level value"); + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "wrong debug level value"); + return FALSE; } - return NULL; + return TRUE; } /** * wpas_dbus_setter_debug_timestamp - Set debug timestamp - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: %NULL or DBus error message + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter for "DebugTimestamp" property. */ -DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_setter_debug_timestamp( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_global *global = user_data; dbus_bool_t val; - reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, - &val); - if (reply) - return reply; + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &val)) + return FALSE; wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, wpa_debug_show_keys); - - return NULL; + return TRUE; } /** * wpas_dbus_setter_debug_show_keys - Set debug show keys - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: %NULL or DBus error message + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter for "DebugShowKeys" property. */ -DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_setter_debug_show_keys( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_global *global = user_data; dbus_bool_t val; - reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, - &val); - if (reply) - return reply; + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &val)) + return FALSE; wpa_supplicant_set_debug_params(global, wpa_debug_level, wpa_debug_timestamp, val ? 1 : 0); - - return NULL; + return TRUE; } /** * wpas_dbus_getter_interfaces - Request registered interfaces list - * @message: Pointer to incoming dbus message - * @global: %wpa_supplicant global data structure - * Returns: The object paths array containing registered interfaces - * objects paths or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Interfaces" property. Handles requests * by dbus clients to return list of registered interfaces objects * paths */ -DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message, - struct wpa_global *global) +dbus_bool_t wpas_dbus_getter_interfaces( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; + struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; const char **paths; unsigned int i = 0, num = 0; + dbus_bool_t success; - for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) - num++; + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_s->dbus_new_path) + num++; + } - paths = os_zalloc(num * sizeof(char*)); + paths = os_calloc(num, sizeof(char *)); if (!paths) { - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } - for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) - paths[i++] = wpa_s->dbus_new_path; + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_s->dbus_new_path) + paths[i++] = wpa_s->dbus_new_path; + } - reply = wpas_dbus_simple_array_property_getter(message, - DBUS_TYPE_OBJECT_PATH, - paths, num); + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, error); os_free(paths); - return reply; + return success; } /** * wpas_dbus_getter_eap_methods - Request supported EAP methods list - * @message: Pointer to incoming dbus message - * @nothing: not used argument. may be NULL or anything else - * Returns: The object paths array containing supported EAP methods - * represented by strings or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "EapMethods" property. Handles requests * by dbus clients to return list of strings with supported EAP methods */ -DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing) +dbus_bool_t wpas_dbus_getter_eap_methods( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; char **eap_methods; size_t num_items = 0; + dbus_bool_t success; eap_methods = eap_get_names_as_string_array(&num_items); if (!eap_methods) { - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } - reply = wpas_dbus_simple_array_property_getter(message, - DBUS_TYPE_STRING, - eap_methods, num_items); + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_STRING, + eap_methods, + num_items, error); while (num_items) os_free(eap_methods[--num_items]); os_free(eap_methods); - return reply; + return success; +} + + +/** + * wpas_dbus_getter_global_capabilities - Request supported global capabilities + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Capabilities" property. Handles requests by dbus clients to + * return a list of strings with supported capabilities like AP, RSN IBSS, + * and P2P that are determined at compile time. + */ +dbus_bool_t wpas_dbus_getter_global_capabilities( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL }; + size_t num_items = 0; + +#ifdef CONFIG_AP + capabilities[num_items++] = "ap"; +#endif /* CONFIG_AP */ +#ifdef CONFIG_IBSS_RSN + capabilities[num_items++] = "ibss-rsn"; +#endif /* CONFIG_IBSS_RSN */ +#ifdef CONFIG_P2P + capabilities[num_items++] = "p2p"; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + capabilities[num_items++] = "interworking"; +#endif /* CONFIG_INTERWORKING */ + + return wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_STRING, + capabilities, + num_items, error); } @@ -941,8 +982,8 @@ static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, char **type, DBusMessage **reply) { if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Type must be a string"); + wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string", + __func__); *reply = wpas_dbus_error_invalid_args( message, "Wrong Type value type. String required"); return -1; @@ -964,36 +1005,36 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, int len; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " - "must be an array of arrays of bytes"); + wpa_printf(MSG_DEBUG, + "%s[dbus]: ssids must be an array of arrays of bytes", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Wrong SSIDs value type. Array of arrays of " - "bytes required"); + message, + "Wrong SSIDs value type. Array of arrays of bytes required"); return -1; } dbus_message_iter_recurse(var, &array_iter); if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) - { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " - "must be an array of arrays of bytes"); + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: ssids must be an array of arrays of bytes", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Wrong SSIDs value type. Array of arrays of " - "bytes required"); + message, + "Wrong SSIDs value type. Array of arrays of bytes required"); return -1; } - while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) - { + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Too many ssids specified on scan dbus " - "call"); + wpa_printf(MSG_DEBUG, + "%s[dbus]: Too many ssids specified on scan dbus call", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Too many ssids specified. Specify " - "at most four"); + message, + "Too many ssids specified. Specify at most four"); return -1; } @@ -1001,15 +1042,19 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); + if (len > SSID_MAX_LEN) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: SSID too long (len=%d max_len=%d)", + __func__, len, SSID_MAX_LEN); + *reply = wpas_dbus_error_invalid_args( + message, "Invalid SSID: too long"); + return -1; + } + if (len != 0) { ssid = os_malloc(len); if (ssid == NULL) { - wpa_printf(MSG_DEBUG, - "wpas_dbus_handler_scan[dbus]: " - "out of memory. Cannot allocate " - "memory for SSID"); - *reply = dbus_message_new_error( - message, DBUS_ERROR_NO_MEMORY, NULL); + *reply = wpas_dbus_error_no_memory(message); return -1; } os_memcpy(ssid, val, len); @@ -1041,28 +1086,28 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, int len; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " - "be an array of arrays of bytes"); + wpa_printf(MSG_DEBUG, + "%s[dbus]: ies must be an array of arrays of bytes", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Wrong IEs value type. Array of arrays of " - "bytes required"); + message, + "Wrong IEs value type. Array of arrays of bytes required"); return -1; } dbus_message_iter_recurse(var, &array_iter); if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) - { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " - "be an array of arrays of bytes"); + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: ies must be an array of arrays of bytes", + __func__); *reply = wpas_dbus_error_invalid_args( message, "Wrong IEs value type. Array required"); return -1; } - while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) - { + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { dbus_message_iter_recurse(&array_iter, &sub_array_iter); dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); @@ -1073,12 +1118,8 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, nies = os_realloc(ies, ies_len + len); if (nies == NULL) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "out of memory. Cannot allocate memory for " - "IE"); os_free(ies); - *reply = dbus_message_new_error( - message, DBUS_ERROR_NO_MEMORY, NULL); + *reply = wpas_dbus_error_no_memory(message); return -1; } ies = nies; @@ -1104,11 +1145,12 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, int freqs_num = 0; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Channels must be an array of structs"); + wpa_printf(MSG_DEBUG, + "%s[dbus]: Channels must be an array of structs", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Wrong Channels value type. Array of structs " - "required"); + message, + "Wrong Channels value type. Array of structs required"); return -1; } @@ -1116,11 +1158,11 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { wpa_printf(MSG_DEBUG, - "wpas_dbus_handler_scan[dbus]: Channels must be an " - "array of structs"); + "%s[dbus]: Channels must be an array of structs", + __func__); *reply = wpas_dbus_error_invalid_args( - message, "Wrong Channels value type. Array of structs " - "required"); + message, + "Wrong Channels value type. Array of structs required"); return -1; } @@ -1132,14 +1174,14 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, if (dbus_message_iter_get_arg_type(&sub_array_iter) != DBUS_TYPE_UINT32) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Channel must by specified by struct of " - "two UINT32s %c", + wpa_printf(MSG_DEBUG, + "%s[dbus]: Channel must by specified by struct of two UINT32s %c", + __func__, dbus_message_iter_get_arg_type( &sub_array_iter)); *reply = wpas_dbus_error_invalid_args( - message, "Wrong Channel struct. Two UINT32s " - "required"); + message, + "Wrong Channel struct. Two UINT32s required"); os_free(freqs); return -1; } @@ -1148,9 +1190,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, if (!dbus_message_iter_next(&sub_array_iter) || dbus_message_iter_get_arg_type(&sub_array_iter) != DBUS_TYPE_UINT32) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Channel must by specified by struct of " - "two UINT32s"); + wpa_printf(MSG_DEBUG, + "%s[dbus]: Channel must by specified by struct of two UINT32s", + __func__); *reply = wpas_dbus_error_invalid_args( message, "Wrong Channel struct. Two UINT32s required"); @@ -1162,18 +1204,15 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, #define FREQS_ALLOC_CHUNK 32 if (freqs_num % FREQS_ALLOC_CHUNK == 0) { - nfreqs = os_realloc(freqs, sizeof(int) * - (freqs_num + FREQS_ALLOC_CHUNK)); + nfreqs = os_realloc_array( + freqs, freqs_num + FREQS_ALLOC_CHUNK, + sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; } if (freqs == NULL) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "out of memory. can't allocate memory for " - "freqs"); - *reply = dbus_message_new_error( - message, DBUS_ERROR_NO_MEMORY, NULL); + *reply = wpas_dbus_error_no_memory(message); return -1; } @@ -1183,16 +1222,12 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, dbus_message_iter_next(&array_iter); } - nfreqs = os_realloc(freqs, - sizeof(int) * (freqs_num + 1)); + nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; if (freqs == NULL) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "out of memory. Can't allocate memory for freqs"); - *reply = dbus_message_new_error( - message, DBUS_ERROR_NO_MEMORY, NULL); + *reply = wpas_dbus_error_no_memory(message); return -1; } freqs[freqs_num] = 0; @@ -1202,6 +1237,23 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, } +static int wpas_dbus_get_scan_allow_roam(DBusMessage *message, + DBusMessageIter *var, + dbus_bool_t *allow, + DBusMessage **reply) +{ + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) { + wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean", + __func__); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Type value type. Boolean required"); + return -1; + } + dbus_message_iter_get_basic(var, allow); + return 0; +} + + /** * wpas_dbus_handler_scan - Request a wireless scan on an interface * @message: Pointer to incoming dbus message @@ -1220,6 +1272,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, char *key = NULL, *type = NULL; struct wpa_driver_scan_params params; size_t i; + dbus_bool_t allow_roam = 1; os_memset(¶ms, 0, sizeof(params)); @@ -1228,7 +1281,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, dbus_message_iter_recurse(&iter, &dict_iter); while (dbus_message_iter_get_arg_type(&dict_iter) == - DBUS_TYPE_DICT_ENTRY) { + DBUS_TYPE_DICT_ENTRY) { dbus_message_iter_recurse(&dict_iter, &entry_iter); dbus_message_iter_get_basic(&entry_iter, &key); dbus_message_iter_next(&entry_iter); @@ -1250,9 +1303,15 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, if (wpas_dbus_get_scan_channels(message, &variant_iter, ¶ms, &reply) < 0) goto out; + } else if (os_strcmp(key, "AllowRoam") == 0) { + if (wpas_dbus_get_scan_allow_roam(message, + &variant_iter, + &allow_roam, + &reply) < 0) + goto out; } else { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Unknown argument %s", key); + wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s", + __func__, key); reply = wpas_dbus_error_invalid_args(message, key); goto out; } @@ -1261,40 +1320,73 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, } if (!type) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Scan type not specified"); + wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified", + __func__); reply = wpas_dbus_error_invalid_args(message, key); goto out; } - if (!os_strcmp(type, "passive")) { + if (os_strcmp(type, "passive") == 0) { if (params.num_ssids || params.extra_ies_len) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "SSIDs or IEs specified for passive scan."); + wpa_printf(MSG_DEBUG, + "%s[dbus]: SSIDs or IEs specified for passive scan.", + __func__); reply = wpas_dbus_error_invalid_args( - message, "You can specify only Channels in " - "passive scan"); + message, + "You can specify only Channels in passive scan"); goto out; - } else if (params.freqs && params.freqs[0]) { - wpa_supplicant_trigger_scan(wpa_s, ¶ms); } else { - wpa_s->scan_req = 2; - wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed", + __func__); + wpa_supplicant_cancel_sched_scan(wpa_s); + } + + if (params.freqs && params.freqs[0]) { + wpa_s->last_scan_req = MANUAL_SCAN_REQ; + if (wpa_supplicant_trigger_scan(wpa_s, + ¶ms)) { + reply = wpas_dbus_error_scan_error( + message, + "Scan request rejected"); + } + } else { + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } } - } else if (!os_strcmp(type, "active")) { + } else if (os_strcmp(type, "active") == 0) { if (!params.num_ssids) { /* Add wildcard ssid */ params.num_ssids++; } - wpa_supplicant_trigger_scan(wpa_s, ¶ms); +#ifdef CONFIG_AUTOSCAN + autoscan_deinit(wpa_s); +#endif /* CONFIG_AUTOSCAN */ + if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed", + __func__); + wpa_supplicant_cancel_sched_scan(wpa_s); + } + + wpa_s->last_scan_req = MANUAL_SCAN_REQ; + if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { + reply = wpas_dbus_error_scan_error( + message, "Scan request rejected"); + } } else { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " - "Unknown scan type: %s", type); + wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s", + __func__, type); reply = wpas_dbus_error_invalid_args(message, "Wrong scan type"); goto out; } + if (!allow_roam) + wpa_s->scan_res_handler = scan_only_handler; + out: for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++) os_free((u8 *) params.ssids[i].ssid); @@ -1304,30 +1396,93 @@ out: } -/* - * wpas_dbus_handler_disconnect - Terminate the current connection +/** + * wpas_dbus_handler_signal_poll - Request immediate signal properties * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface - * Returns: NotConnected DBus error message if already not connected - * or NULL otherwise. + * Returns: NULL indicating success or DBus error message on failure * - * Handler function for "Disconnect" method call of network interface. + * Handler function for "SignalPoll" method call of a network device. Requests + * that wpa_supplicant read signal properties like RSSI, noise, and link + * speed and return them. */ -DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, - struct wpa_supplicant *wpa_s) +DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message, + struct wpa_supplicant *wpa_s) { - if (wpa_s->current_ssid != NULL) { - wpa_s->disconnected = 1; - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); + struct wpa_signal_info si; + DBusMessage *reply = NULL; + DBusMessageIter iter, iter_dict, variant_iter; + int ret; - return NULL; + ret = wpa_drv_signal_poll(wpa_s, &si); + if (ret) { + return dbus_message_new_error(message, DBUS_ERROR_FAILED, + "Failed to read signal"); } - return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, - "This interface is not connected"); -} - + reply = dbus_message_new_method_return(message); + if (reply == NULL) + goto nomem; + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) || + !wpa_dbus_dict_append_int32(&iter_dict, "rssi", + si.current_signal) || + !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed", + si.current_txrate / 1000) || + !wpa_dbus_dict_append_int32(&iter_dict, "noise", + si.current_noise) || + !wpa_dbus_dict_append_uint32(&iter_dict, "frequency", + si.frequency) || + (si.chanwidth != CHAN_WIDTH_UNKNOWN && + !wpa_dbus_dict_append_string( + &iter_dict, "width", + channel_width_to_string(si.chanwidth))) || + (si.center_frq1 > 0 && si.center_frq2 > 0 && + (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1", + si.center_frq1) || + !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2", + si.center_frq2))) || + (si.avg_signal && + !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi", + si.avg_signal)) || + !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(&iter, &variant_iter)) + goto nomem; + + return reply; + +nomem: + if (reply) + dbus_message_unref(reply); + return wpas_dbus_error_no_memory(message); +} + + +/* + * wpas_dbus_handler_disconnect - Terminate the current connection + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NotConnected DBus error message if already not connected + * or NULL otherwise. + * + * Handler function for "Disconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->current_ssid != NULL) { + wpas_request_disconnection(wpa_s); + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, + "This interface is not connected"); +} + /** * wpas_dbus_new_iface_add_network - Add a new configured network @@ -1344,28 +1499,33 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, DBusMessageIter iter; struct wpa_ssid *ssid = NULL; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; + DBusError error; dbus_message_iter_init(message, &iter); - ssid = wpa_config_add_network(wpa_s->conf); + if (wpa_s->dbus_new_path) + ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { - wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: " - "can't add new interface."); + wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.", + __func__); reply = wpas_dbus_error_unknown_error( message, - "wpa_supplicant could not add " - "a network on this interface."); + "wpa_supplicant could not add a network on this interface."); goto err; } wpas_notify_network_added(wpa_s, ssid); ssid->disabled = 1; wpa_config_set_network_defaults(ssid); - reply = set_network_properties(message, wpa_s, ssid, &iter); - if (reply) { - wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:" - "control interface couldn't set network " - "properties"); + dbus_error_init(&error); + if (!set_network_properties(wpa_s, ssid, &iter, &error)) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: control interface couldn't set network properties", + __func__); + reply = wpas_dbus_reply_new_from_error(message, &error, + DBUS_ERROR_INVALID_ARGS, + "Failed to add network"); + dbus_error_free(&error); goto err; } @@ -1376,15 +1536,13 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, reply = dbus_message_new_method_return(message); if (reply == NULL) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + reply = wpas_dbus_error_no_memory(message); goto err; } if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + reply = wpas_dbus_error_no_memory(message); goto err; } @@ -1400,6 +1558,96 @@ err: /** + * wpas_dbus_handler_reassociate - Reassociate + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: InterfaceDisabled DBus error message if disabled + * or NULL otherwise. + * + * Handler function for "Reassociate" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + wpas_request_connection(wpa_s); + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED, + "This interface is disabled"); +} + + +/** + * wpas_dbus_handler_expect_disconnect - ExpectDisconnect + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: NULL + * + * Handler function for notifying system there will be a expected disconnect. + * This will prevent wpa_supplicant from adding blacklists upon next disconnect.. + */ +DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s = global->ifaces; + + for (; wpa_s; wpa_s = wpa_s->next) + if (wpa_s->wpa_state >= WPA_ASSOCIATED) + wpa_s->own_disconnect_req = 1; + return NULL; +} + + +/** + * wpas_dbus_handler_reattach - Reattach to current AP + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NotConnected DBus error message if not connected + * or NULL otherwise. + * + * Handler function for "Reattach" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->current_ssid != NULL) { + wpa_s->reattach = 1; + wpas_request_connection(wpa_s); + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, + "This interface is not connected"); +} + + +/** + * wpas_dbus_handler_reconnect - Reconnect if disconnected + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: InterfaceDisabled DBus error message if disabled + * or NULL otherwise. + * + * Handler function for "Reconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_IFACE_DISABLED, + "This interface is disabled"); + } + + if (wpa_s->disconnected) + wpas_request_connection(wpa_s); + return NULL; +} + + +/** * wpas_dbus_handler_remove_network - Remove a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface @@ -1412,23 +1660,28 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, { DBusMessage *reply = NULL; const char *op; - char *iface = NULL, *net_id = NULL; + char *iface, *net_id; int id; struct wpa_ssid *ssid; + int was_disabled; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID); /* Extract the network ID and ensure the network */ /* is actually a child of this interface */ - iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL); - if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + iface = wpas_dbus_new_decompose_object_path(op, + WPAS_DBUS_NEW_NETWORKS_PART, + &net_id); + if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } + errno = 0; id = strtoul(net_id, NULL, 10); - if (errno == EINVAL) { + if (errno != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } @@ -1439,26 +1692,72 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, goto out; } + was_disabled = ssid->disabled; + wpas_notify_network_removed(wpa_s, ssid); + if (ssid == wpa_s->current_ssid) + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + else if (!was_disabled && wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, + "Stop ongoing sched_scan to remove network from filters"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + if (wpa_config_remove_network(wpa_s->conf, id) < 0) { wpa_printf(MSG_ERROR, - "wpas_dbus_handler_remove_network[dbus]: " - "error occurred when removing network %d", id); + "%s[dbus]: error occurred when removing network %d", + __func__, id); reply = wpas_dbus_error_unknown_error( - message, "error removing the specified network on " - "this interface."); + message, + "error removing the specified network on is interface."); goto out; } +out: + os_free(iface); + return reply; +} + + +static void remove_network(void *arg, struct wpa_ssid *ssid) +{ + struct wpa_supplicant *wpa_s = arg; + + wpas_notify_network_removed(wpa_s, ssid); + + if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { + wpa_printf(MSG_ERROR, + "%s[dbus]: error occurred when removing network %d", + __func__, ssid->id); + return; + } + if (ssid == wpa_s->current_ssid) wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); +} -out: - os_free(iface); - os_free(net_id); - return reply; + +/** + * wpas_dbus_handler_remove_all_networks - Remove all configured networks + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "RemoveAllNetworks" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_all_networks( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + if (wpa_s->sched_scanning) + wpa_supplicant_cancel_sched_scan(wpa_s); + + /* NB: could check for failure and return an error */ + wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); + return NULL; } @@ -1475,7 +1774,7 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, { DBusMessage *reply = NULL; const char *op; - char *iface = NULL, *net_id = NULL; + char *iface, *net_id; int id; struct wpa_ssid *ssid; @@ -1484,14 +1783,18 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, /* Extract the network ID and ensure the network */ /* is actually a child of this interface */ - iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL); - if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + iface = wpas_dbus_new_decompose_object_path(op, + WPAS_DBUS_NEW_NETWORKS_PART, + &net_id); + if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } + errno = 0; id = strtoul(net_id, NULL, 10); - if (errno == EINVAL) { + if (errno != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } @@ -1507,12 +1810,80 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, out: os_free(iface); - os_free(net_id); return reply; } /** + * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "NetworkReply" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ +#ifdef IEEE8021X_EAPOL + DBusMessage *reply = NULL; + const char *op, *field, *value; + char *iface, *net_id; + int id; + struct wpa_ssid *ssid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_STRING, &field, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID)) + return wpas_dbus_error_invalid_args(message, NULL); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, + WPAS_DBUS_NEW_NETWORKS_PART, + &net_id); + if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + errno = 0; + id = strtoul(net_id, NULL, 10); + if (errno != 0) { + reply = wpas_dbus_error_invalid_args(message, net_id); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, + field, value) < 0) + reply = wpas_dbus_error_invalid_args(message, field); + else { + /* Tell EAP to retry immediately */ + eapol_sm_notify_ctrl_response(wpa_s->eapol); + } + +out: + os_free(iface); + return reply; +#else /* IEEE8021X_EAPOL */ + wpa_printf(MSG_DEBUG, "dbus: 802.1X not included"); + return wpas_dbus_error_unknown_error(message, "802.1X not included"); +#endif /* IEEE8021X_EAPOL */ +} + + +#ifndef CONFIG_NO_CONFIG_BLOBS + +/** * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates) * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure @@ -1547,26 +1918,18 @@ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, blob = os_zalloc(sizeof(*blob)); if (!blob) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + reply = wpas_dbus_error_no_memory(message); goto err; } blob->data = os_malloc(blob_len); - if (!blob->data) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + blob->name = os_strdup(blob_name); + if (!blob->data || !blob->name) { + reply = wpas_dbus_error_no_memory(message); goto err; } os_memcpy(blob->data, blob_data, blob_len); - blob->len = blob_len; - blob->name = os_strdup(blob_name); - if (!blob->name) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto err; - } wpa_config_set_blob(wpa_s->conf, blob); wpas_notify_blob_added(wpa_s, blob->name); @@ -1611,39 +1974,21 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, } reply = dbus_message_new_method_return(message); - if (!reply) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto out; - } + if (!reply) + return wpas_dbus_error_no_memory(message); dbus_message_iter_init_append(reply, &iter); if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, - &array_iter)) { - dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto out; - } - - if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, - &(blob->data), blob->len)) { - dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto out; - } - - if (!dbus_message_iter_close_container(&iter, &array_iter)) { + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, + &(blob->data), blob->len) || + !dbus_message_iter_close_container(&iter, &array_iter)) { dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto out; + reply = wpas_dbus_error_no_memory(message); } -out: return reply; } @@ -1676,41 +2021,387 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, } +#endif /* CONFIG_NO_CONFIG_BLOBS */ + +/* + * wpas_dbus_handler_flush_bss - Flush the BSS cache + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Handler function for "FlushBSS" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t age; + + dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age, + DBUS_TYPE_INVALID); + + if (age == 0) + wpa_bss_flush(wpa_s); + else + wpa_bss_flush_by_age(wpa_s, age); + + return NULL; +} + + +#ifdef CONFIG_AUTOSCAN /** - * wpas_dbus_getter_capabilities - Return interface capabilities + * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a dict of strings + * Returns: NULL * - * Getter for "Capabilities" property of an interface. + * Handler function for "AutoScan" method call of network interface. */ -DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, - struct wpa_supplicant *wpa_s) +DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message, + struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; + enum wpa_states state = wpa_s->wpa_state; + char *arg; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + if (arg != NULL && os_strlen(arg) > 0) { + char *tmp; + + tmp = os_strdup(arg); + if (tmp == NULL) { + reply = wpas_dbus_error_no_memory(message); + } else { + os_free(wpa_s->conf->autoscan); + wpa_s->conf->autoscan = tmp; + if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) + autoscan_init(wpa_s, 1); + else if (state == WPA_SCANNING) + wpa_supplicant_reinit_autoscan(wpa_s); + } + } else if (arg != NULL && os_strlen(arg) == 0) { + os_free(wpa_s->conf->autoscan); + wpa_s->conf->autoscan = NULL; + autoscan_deinit(wpa_s); + } else + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + NULL); + + return reply; +} +#endif /* CONFIG_AUTOSCAN */ + + +/* + * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Handler function for "EAPLogoff" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + eapol_sm_notify_logoff(wpa_s->eapol, TRUE); + return NULL; +} + + +/* + * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Handler function for "EAPLogin" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + eapol_sm_notify_logoff(wpa_s->eapol, FALSE); + return NULL; +} + + +#ifdef CONFIG_TDLS + +static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name, + u8 *peer_address, DBusMessage **error) +{ + const char *peer_string; + + *error = NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &peer_string, + DBUS_TYPE_INVALID)) { + *error = wpas_dbus_error_invalid_args(message, NULL); + return -1; + } + + if (hwaddr_aton(peer_string, peer_address)) { + wpa_printf(MSG_DEBUG, "%s: invalid address '%s'", + func_name, peer_string); + *error = wpas_dbus_error_invalid_args( + message, "Invalid hardware address format"); + return -1; + } + + return 0; +} + + +/* + * wpas_dbus_handler_tdls_discover - Discover TDLS peer + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "TDLSDiscover" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 peer[ETH_ALEN]; + DBusMessage *error_reply; + int ret; + + if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) + return error_reply; + + wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer)); + + if (wpa_tdls_is_external_setup(wpa_s->wpa)) + ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); + else + ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); + + if (ret) { + return wpas_dbus_error_unknown_error( + message, "error performing TDLS discovery"); + } + + return NULL; +} + + +/* + * wpas_dbus_handler_tdls_setup - Setup TDLS session + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "TDLSSetup" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 peer[ETH_ALEN]; + DBusMessage *error_reply; + int ret; + + if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) + return error_reply; + + wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer)); + + wpa_tdls_remove(wpa_s->wpa, peer); + if (wpa_tdls_is_external_setup(wpa_s->wpa)) + ret = wpa_tdls_start(wpa_s->wpa, peer); + else + ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); + + if (ret) { + return wpas_dbus_error_unknown_error( + message, "error performing TDLS setup"); + } + + return NULL; +} + + +/* + * wpas_dbus_handler_tdls_status - Return TDLS session status + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A string representing the state of the link to this TDLS peer + * + * Handler function for "TDLSStatus" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 peer[ETH_ALEN]; + DBusMessage *reply; + const char *tdls_status; + + if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0) + return reply; + + wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer)); + + tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_STRING, + &tdls_status, DBUS_TYPE_INVALID); + return reply; +} + + +/* + * wpas_dbus_handler_tdls_teardown - Teardown TDLS session + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "TDLSTeardown" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 peer[ETH_ALEN]; + DBusMessage *error_reply; + int ret; + + if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) + return error_reply; + + wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer)); + + if (wpa_tdls_is_external_setup(wpa_s->wpa)) + ret = wpa_tdls_teardown_link( + wpa_s->wpa, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + else + ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); + + if (ret) { + return wpas_dbus_error_unknown_error( + message, "error performing TDLS teardown"); + } + + return NULL; +} + +#endif /* CONFIG_TDLS */ + + +#ifndef CONFIG_NO_CONFIG_WRITE +/** + * wpas_dbus_handler_save_config - Save configuration to configuration file + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on Success, Otherwise errror message + * + * Handler function for "SaveConfig" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int ret; + + if (!wpa_s->conf->update_config) { + return wpas_dbus_error_unknown_error( + message, + "Not allowed to update configuration (update_config=0)"); + } + + ret = wpa_config_write(wpa_s->confname, wpa_s->conf); + if (ret) + return wpas_dbus_error_unknown_error( + message, "Failed to update configuration"); + return NULL; +} +#endif /* CONFIG_NO_CONFIG_WRITE */ + + +/** + * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing an error on failure or NULL on success + * + * Sets the PKCS #11 engine and module path. + */ +DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter; + char *value = NULL; + char *pkcs11_engine_path = NULL; + char *pkcs11_module_path = NULL; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &value); + if (value == NULL) { + return dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, + "Invalid pkcs11_engine_path argument"); + } + /* Empty path defaults to NULL */ + if (os_strlen(value)) + pkcs11_engine_path = value; + + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &value); + if (value == NULL) { + os_free(pkcs11_engine_path); + return dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, + "Invalid pkcs11_module_path argument"); + } + /* Empty path defaults to NULL */ + if (os_strlen(value)) + pkcs11_module_path = value; + + if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path, + pkcs11_module_path)) + return dbus_message_new_error( + message, DBUS_ERROR_FAILED, + "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed."); + + if (wpa_s->dbus_new_path) { + wpa_dbus_mark_property_changed( + wpa_s->global->dbus, wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath"); + wpa_dbus_mark_property_changed( + wpa_s->global->dbus, wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath"); + } + + return NULL; +} + + +/** + * wpas_dbus_getter_capabilities - Return interface capabilities + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Capabilities" property of an interface. + */ +dbus_bool_t wpas_dbus_getter_capabilities( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; struct wpa_driver_capa capa; int res; - DBusMessageIter iter, iter_dict; - DBusMessageIter iter_dict_entry, iter_dict_val, iter_array, + DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array, variant_iter; const char *scans[] = { "active", "passive", "ssid" }; - const char *modes[] = { "infrastructure", "ad-hoc", "ap" }; - int n = sizeof(modes) / sizeof(char *); - - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); - else - reply = dbus_message_new_method_return(message); - if (!reply) - goto nomem; - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - "a{sv}", &variant_iter)) - goto nomem; - - if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) goto nomem; res = wpa_drv_get_capa(wpa_s, &capa); @@ -1718,36 +2409,35 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, /***** pairwise cipher */ if (res < 0) { const char *args[] = {"ccmp", "tkip", "none"}; + if (!wpa_dbus_dict_append_string_array( &iter_dict, "Pairwise", args, - sizeof(args) / sizeof(char*))) + ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise", &iter_dict_entry, &iter_dict_val, - &iter_array)) - goto nomem; - - if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "ccmp")) - goto nomem; - } - - if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "tkip")) - goto nomem; - } - - if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "none")) - goto nomem; - } - - if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_array) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "tkip")) || + ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "none")) || + !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) @@ -1759,42 +2449,38 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, const char *args[] = { "ccmp", "tkip", "wep104", "wep40" }; + if (!wpa_dbus_dict_append_string_array( &iter_dict, "Group", args, - sizeof(args) / sizeof(char*))) + ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group", &iter_dict_entry, - &iter_dict_val, - &iter_array)) - goto nomem; - - if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "ccmp")) - goto nomem; - } - - if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "tkip")) - goto nomem; - } - - if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wep104")) - goto nomem; - } - - if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wep40")) - goto nomem; - } - - if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_val, + &iter_array) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "tkip")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "wep104")) || + ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "wep40")) || + !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) @@ -1812,34 +2498,28 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "KeyMgmt", args, - sizeof(args) / sizeof(char*))) + ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt", &iter_dict_entry, &iter_dict_val, - &iter_array)) - goto nomem; - - if (!wpa_dbus_dict_string_array_add_element(&iter_array, - "none")) - goto nomem; - - if (!wpa_dbus_dict_string_array_add_element(&iter_array, + &iter_array) || + !wpa_dbus_dict_string_array_add_element(&iter_array, + "none") || + !wpa_dbus_dict_string_array_add_element(&iter_array, "ieee8021x")) goto nomem; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-eap")) + &iter_array, "wpa-eap") || + ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-ft-eap"))) goto nomem; - if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-ft-eap")) - goto nomem; - /* TODO: Ensure that driver actually supports sha256 encryption. */ #ifdef CONFIG_IEEE80211W if (!wpa_dbus_dict_string_array_add_element( @@ -1851,14 +2531,13 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-psk")) + &iter_array, "wpa-psk") || + ((capa.key_mgmt & + WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-ft-psk"))) goto nomem; - if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-ft-psk")) - goto nomem; - /* TODO: Ensure that driver actually supports sha256 encryption. */ #ifdef CONFIG_IEEE80211W if (!wpa_dbus_dict_string_array_add_element( @@ -1867,11 +2546,10 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, #endif /* CONFIG_IEEE80211W */ } - if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-none")) - goto nomem; - } + if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && + !wpa_dbus_dict_string_array_add_element(&iter_array, + "wpa-none")) + goto nomem; #ifdef CONFIG_WPS @@ -1890,32 +2568,25 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, /***** WPA protocol */ if (res < 0) { const char *args[] = { "rsn", "wpa" }; + if (!wpa_dbus_dict_append_string_array( &iter_dict, "Protocol", args, - sizeof(args) / sizeof(char*))) + ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol", &iter_dict_entry, &iter_dict_val, - &iter_array)) - goto nomem; - - if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "rsn")) - goto nomem; - } - - if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa")) - goto nomem; - } - - if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_array) || + ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "rsn")) || + ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa")) || + !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) @@ -1925,9 +2596,10 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, /***** auth alg */ if (res < 0) { const char *args[] = { "open", "shared", "leap" }; + if (!wpa_dbus_dict_append_string_array( &iter_dict, "AuthAlg", args, - sizeof(args) / sizeof(char*))) + ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg", @@ -1936,25 +2608,16 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, &iter_array)) goto nomem; - if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "open")) - goto nomem; - } - - if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "shared")) - goto nomem; - } - - if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { - if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "leap")) - goto nomem; - } - - if (!wpa_dbus_dict_end_string_array(&iter_dict, + if (((capa.auth & WPA_DRIVER_AUTH_OPEN) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "open")) || + ((capa.auth & WPA_DRIVER_AUTH_SHARED) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "shared")) || + ((capa.auth & WPA_DRIVER_AUTH_LEAP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "leap")) || + !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) @@ -1963,45 +2626,70 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, /***** Scan */ if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans, - sizeof(scans) / sizeof(char *))) + ARRAY_SIZE(scans))) goto nomem; /***** Modes */ - if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP)) - n--; /* exclude ap mode if it is not supported by the driver */ - if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n)) + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes", + &iter_dict_entry, + &iter_dict_val, + &iter_array) || + !wpa_dbus_dict_string_array_add_element( + &iter_array, "infrastructure") || + (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ad-hoc")) || + (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "ap")) || + (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) && + !wpa_s->conf->p2p_disabled && + !wpa_dbus_dict_string_array_add_element( + &iter_array, "p2p")) || + !wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) goto nomem; + /***** Modes end */ - if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) - goto nomem; - if (!dbus_message_iter_close_container(&iter, &variant_iter)) + if (res >= 0) { + dbus_int32_t max_scan_ssid = capa.max_scan_ssids; + + if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID", + max_scan_ssid)) + goto nomem; + } + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(iter, &variant_iter)) goto nomem; - return reply; + return TRUE; nomem: - if (reply) - dbus_message_unref(reply); - - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } /** * wpas_dbus_getter_state - Get interface state - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a STRING representing the current - * interface state + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "State" property. */ -DBusMessage * wpas_dbus_getter_state(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_state( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; + struct wpa_supplicant *wpa_s = user_data; const char *str_state; char *state_ls, *tmp; + dbus_bool_t success = FALSE; str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); @@ -2009,201 +2697,521 @@ DBusMessage * wpas_dbus_getter_state(DBusMessage *message, */ state_ls = tmp = os_strdup(str_state); if (!tmp) { - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } while (*tmp) { *tmp = tolower(*tmp); tmp++; } - reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &state_ls); + success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &state_ls, error); os_free(state_ls); - return reply; + return success; } /** * wpas_dbus_new_iface_get_scanning - Get interface scanning state - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing whether the interface is scanning + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "scanning" property. */ -DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_scanning( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct wpa_supplicant *wpa_s = user_data; dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, - &scanning); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &scanning, error); } /** * wpas_dbus_getter_ap_scan - Control roaming mode - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A message containong value of ap_scan variable + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter function for "ApScan" property. */ -DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_ap_scan( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, - &ap_scan); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &ap_scan, error); } /** * wpas_dbus_setter_ap_scan - Control roaming mode - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: NULL + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter function for "ApScan" property. */ -DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_setter_ap_scan( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; + struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t ap_scan; - reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, - &ap_scan); - if (reply) - return reply; + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &ap_scan)) + return FALSE; if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { - return wpas_dbus_error_invalid_args( - message, "ap_scan must equal 0, 1 or 2"); + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "ap_scan must be 0, 1, or 2"); + return FALSE; } - return NULL; + return TRUE; +} + + +/** + * wpas_dbus_getter_fast_reauth - Control fast + * reauthentication (TLS session resumption) + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "FastReauth" property. + */ +dbus_bool_t wpas_dbus_getter_fast_reauth( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &fast_reauth, error); +} + + +/** + * wpas_dbus_setter_fast_reauth - Control fast + * reauthentication (TLS session resumption) + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "FastReauth" property. + */ +dbus_bool_t wpas_dbus_setter_fast_reauth( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t fast_reauth; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &fast_reauth)) + return FALSE; + + wpa_s->conf->fast_reauth = fast_reauth; + return TRUE; +} + + +/** + * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DisconnectReason" property. The reason is negative if it is + * locally generated. + */ +dbus_bool_t wpas_dbus_getter_disconnect_reason( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t reason = wpa_s->disconnect_reason; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &reason, error); +} + + +/** + * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "AssocStatusCode" property. + */ +dbus_bool_t wpas_dbus_getter_assoc_status_code( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t status_code = wpa_s->assoc_status_code; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &status_code, error); +} + + +/** + * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "BSSExpireAge" property. + */ +dbus_bool_t wpas_dbus_getter_bss_expire_age( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &expire_age, error); +} + + +/** + * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "BSSExpireAge" property. + */ +dbus_bool_t wpas_dbus_setter_bss_expire_age( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_age; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &expire_age)) + return FALSE; + + if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "BSSExpireAge must be >= 10"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "BSSExpireCount" property. + */ +dbus_bool_t wpas_dbus_getter_bss_expire_count( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &expire_count, error); +} + + +/** + * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "BSSExpireCount" property. + */ +dbus_bool_t wpas_dbus_setter_bss_expire_count( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_count; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &expire_count)) + return FALSE; + + if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "BSSExpireCount must be > 0"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_country - Control country code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "Country" property. + */ +dbus_bool_t wpas_dbus_getter_country( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char country[3]; + char *str = country; + + country[0] = wpa_s->conf->country[0]; + country[1] = wpa_s->conf->country[1]; + country[2] = '\0'; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &str, error); +} + + +/** + * wpas_dbus_setter_country - Control country code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "Country" property. + */ +dbus_bool_t wpas_dbus_setter_country( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *country; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &country)) + return FALSE; + + if (!country[0] || !country[1]) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "invalid country code"); + return FALSE; + } + + if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { + wpa_printf(MSG_DEBUG, "Failed to set country"); + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to set country code"); + return FALSE; + } + + wpa_s->conf->country[0] = country[0]; + wpa_s->conf->country[1] = country[1]; + return TRUE; +} + + +/** + * wpas_dbus_getter_scan_interval - Get scan interval + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "ScanInterval" property. + */ +dbus_bool_t wpas_dbus_getter_scan_interval( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t scan_interval = wpa_s->scan_interval; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &scan_interval, error); +} + + +/** + * wpas_dbus_setter_scan_interval - Control scan interval + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "ScanInterval" property. + */ +dbus_bool_t wpas_dbus_setter_scan_interval( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t scan_interval; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32, + &scan_interval)) + return FALSE; + + if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "scan_interval must be >= 0"); + return FALSE; + } + return TRUE; } /** * wpas_dbus_getter_ifname - Get interface name - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a name of network interface - * associated with with wpa_s + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Ifname" property. */ -DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_ifname( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct wpa_supplicant *wpa_s = user_data; const char *ifname = wpa_s->ifname; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &ifname); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &ifname, error); } /** * wpas_dbus_getter_driver - Get interface name - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a name of network interface - * driver associated with with wpa_s + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Driver" property. */ -DBusMessage * wpas_dbus_getter_driver(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_driver( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct wpa_supplicant *wpa_s = user_data; const char *driver; if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { - wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " - "wpa_s has no driver set"); - return wpas_dbus_error_unknown_error(message, NULL); + wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set", + __func__); + dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set", + __func__); + return FALSE; } driver = wpa_s->driver->name; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &driver); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &driver, error); } /** * wpas_dbus_getter_current_bss - Get current bss object path - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a DBus object path to - * current BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentBSS" property. */ -DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_current_bss( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; - if (wpa_s->current_bss) + if (wpa_s->current_bss && wpa_s->dbus_new_path) os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, wpa_s->current_bss->id); else os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); - reply = wpas_dbus_simple_property_getter(message, - DBUS_TYPE_OBJECT_PATH, - &bss_obj_path); - - return reply; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &bss_obj_path, error); } /** * wpas_dbus_getter_current_network - Get current network object path - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a DBus object path to - * current network + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentNetwork" property. */ -DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_current_network( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; - if (wpa_s->current_ssid) + if (wpa_s->current_ssid && wpa_s->dbus_new_path) os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, wpa_s->current_ssid->id); else os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); - reply = wpas_dbus_simple_property_getter(message, - DBUS_TYPE_OBJECT_PATH, - &net_obj_path); - - return reply; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &net_obj_path, error); } /** * wpas_dbus_getter_current_auth_mode - Get current authentication type - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a string indicating the current - * authentication type. + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentAuthMode" property. */ -DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_current_auth_mode( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; + struct wpa_supplicant *wpa_s = user_data; const char *eap_mode; const char *auth_mode; char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; @@ -2217,75 +3225,76 @@ DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message, "EAP-%s", eap_mode); auth_mode = eap_mode_buf; - } else { + } else if (wpa_s->current_ssid) { auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->current_ssid->proto); + } else { + auth_mode = "UNKNOWN"; } - reply = wpas_dbus_simple_property_getter(message, - DBUS_TYPE_STRING, - &auth_mode); - - return reply; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &auth_mode, error); } /** * wpas_dbus_getter_bridge_ifname - Get interface name - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: A dbus message containing a name of bridge network - * interface associated with with wpa_s + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "BridgeIfname" property. */ -DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_bridge_ifname( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *bridge_ifname = NULL; - - bridge_ifname = wpa_s->bridge_ifname; - if (bridge_ifname == NULL) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: " - "wpa_s has no bridge interface name set"); - return wpas_dbus_error_unknown_error(message, NULL); - } + struct wpa_supplicant *wpa_s = user_data; + const char *bridge_ifname = wpa_s->bridge_ifname; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &bridge_ifname); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &bridge_ifname, error); } /** * wpas_dbus_getter_bsss - Get array of BSSs objects - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: a dbus message containing an array of all known BSS objects - * dbus paths + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "BSSs" property. */ -DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_bsss( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; + struct wpa_supplicant *wpa_s = user_data; struct wpa_bss *bss; char **paths; unsigned int i = 0; + dbus_bool_t success = FALSE; + + if (!wpa_s->dbus_new_path) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: no D-Bus interface", __func__); + return FALSE; + } - paths = os_zalloc(wpa_s->num_bss * sizeof(char *)); + paths = os_calloc(wpa_s->num_bss, sizeof(char *)); if (!paths) { - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } /* Loop through scan results and append each result's object path */ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (paths[i] == NULL) { - reply = dbus_message_new_error(message, - DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); goto out; } /* Construct the object path for this BSS. */ @@ -2294,57 +3303,62 @@ DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message, wpa_s->dbus_new_path, bss->id); } - reply = wpas_dbus_simple_array_property_getter(message, - DBUS_TYPE_OBJECT_PATH, - paths, wpa_s->num_bss); + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, wpa_s->num_bss, + error); out: while (i) os_free(paths[--i]); os_free(paths); - return reply; + return success; } /** * wpas_dbus_getter_networks - Get array of networks objects - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: a dbus message containing an array of all configured - * networks dbus object paths. + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Networks" property. */ -DBusMessage * wpas_dbus_getter_networks(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_networks( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; + struct wpa_supplicant *wpa_s = user_data; struct wpa_ssid *ssid; char **paths; unsigned int i = 0, num = 0; + dbus_bool_t success = FALSE; - if (wpa_s->conf == NULL) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: " - "An error occurred getting networks list."); - return wpas_dbus_error_unknown_error(message, NULL); + if (!wpa_s->dbus_new_path) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: no D-Bus interface", __func__); + return FALSE; } for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) - num++; + if (!network_is_persistent_group(ssid)) + num++; - paths = os_zalloc(num * sizeof(char *)); + paths = os_calloc(num, sizeof(char *)); if (!paths) { - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } /* Loop through configured networks and append object path of each */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (network_is_persistent_group(ssid)) + continue; paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (paths[i] == NULL) { - reply = dbus_message_new_error(message, - DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error(error, DBUS_ERROR_NO_MEMORY, + "no memory"); goto out; } @@ -2354,50 +3368,91 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message, wpa_s->dbus_new_path, ssid->id); } - reply = wpas_dbus_simple_array_property_getter(message, - DBUS_TYPE_OBJECT_PATH, - paths, num); + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, error); out: while (i) os_free(paths[--i]); os_free(paths); - return reply; + return success; } /** - * wpas_dbus_getter_blobs - Get all blobs defined for this interface - * @message: Pointer to incoming dbus message - * @wpa_s: wpa_supplicant structure for a network interface - * Returns: a dbus message containing a dictionary of pairs (blob_name, blob) + * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: A dbus message containing the PKCS #11 engine path * - * Getter for "Blobs" property. + * Getter for "PKCS11EnginePath" property. */ -DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s) +dbus_bool_t wpas_dbus_getter_pkcs11_engine_path( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; - DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter; - struct wpa_config_blob *blob; + struct wpa_supplicant *wpa_s = user_data; + const char *pkcs11_engine_path; - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + if (wpa_s->conf->pkcs11_engine_path == NULL) + pkcs11_engine_path = ""; else - reply = dbus_message_new_method_return(message); - if (!reply) - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &pkcs11_engine_path, error); +} - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, +/** + * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: A dbus message containing the PKCS #11 module path + * + * Getter for "PKCS11ModulePath" property. + */ +dbus_bool_t wpas_dbus_getter_pkcs11_module_path( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *pkcs11_module_path; + + if (wpa_s->conf->pkcs11_module_path == NULL) + pkcs11_module_path = ""; + else + pkcs11_module_path = wpa_s->conf->pkcs11_module_path; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &pkcs11_module_path, error); +} + + +/** + * wpas_dbus_getter_blobs - Get all blobs defined for this interface + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Blobs" property. + */ +dbus_bool_t wpas_dbus_getter_blobs( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; + struct wpa_config_blob *blob; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter) || !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter)) { - dbus_message_unref(reply); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } blob = wpa_s->conf->blobs; @@ -2420,176 +3475,286 @@ DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message, &array_iter) || !dbus_message_iter_close_container(&dict_iter, &entry_iter)) { - dbus_message_unref(reply); - return dbus_message_new_error(message, - DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + return FALSE; } blob = blob->next; } if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || - !dbus_message_iter_close_container(&iter, &variant_iter)) { - dbus_message_unref(reply); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } - return reply; + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_iface_global( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + int ret; + char buf[250]; + char *p = buf; + + if (!property_desc->data) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Unhandled interface property %s", + property_desc->dbus_property); + return FALSE; + } + + ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf, + sizeof(buf)); + if (ret < 0) + *p = '\0'; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p, + error); +} + + +dbus_bool_t wpas_dbus_setter_iface_global( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *new_value = NULL; + char buf[250]; + size_t combined_len; + int ret; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &new_value)) + return FALSE; + + combined_len = os_strlen(property_desc->data) + os_strlen(new_value) + + 3; + if (combined_len >= sizeof(buf)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Interface property %s value too large", + property_desc->dbus_property); + return FALSE; + } + + if (!new_value[0]) + new_value = "NULL"; + + ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data, + new_value); + if (os_snprintf_error(combined_len, ret)) { + dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR, + "Failed to construct new interface property %s", + property_desc->dbus_property); + return FALSE; + } + + if (wpa_config_process_global(wpa_s->conf, buf, -1)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Failed to set interface property %s", + property_desc->dbus_property); + return FALSE; + } + + wpa_supplicant_update_config(wpa_s); + return TRUE; +} + + +static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, + DBusError *error, const char *func_name) +{ + struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id); + + if (!res) { + wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found", + func_name, args->id); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: BSS %d not found", + func_name, args->id); + } + + return res; } /** * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the bssid for the requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "BSSID" property. */ -DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_bssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; - return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, - res->bssid, ETH_ALEN); + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res->bssid, ETH_ALEN, + error); } /** * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the ssid for the requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "SSID" property. */ -DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_ssid( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; - return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, - res->ssid, - res->ssid_len); + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res->ssid, res->ssid_len, + error); } /** * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the privacy flag value of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Privacy" property. */ -DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_privacy( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; dbus_bool_t privacy; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, - &privacy); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &privacy, error); } /** * wpas_dbus_getter_bss_mode - Return the mode of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the mode of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Mode" property. */ -DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_mode( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; const char *mode; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no " - "bss with id %d found", bss->id); - return NULL; + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + if (bss_is_dmg(res)) { + switch (res->caps & IEEE80211_CAP_DMG_MASK) { + case IEEE80211_CAP_DMG_PBSS: + case IEEE80211_CAP_DMG_IBSS: + mode = "ad-hoc"; + break; + case IEEE80211_CAP_DMG_AP: + mode = "infrastructure"; + break; + } + } else { + if (res->caps & IEEE80211_CAP_IBSS) + mode = "ad-hoc"; + else + mode = "infrastructure"; } - if (res->caps & IEEE80211_CAP_IBSS) - mode = "ad-hoc"; - else - mode = "infrastructure"; - - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, - &mode); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &mode, error); } /** * wpas_dbus_getter_bss_level - Return the signal strength of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the signal strength of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Level" property. */ -DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_signal( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + s16 level; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16, - &res->level); + level = (s16) res->level; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16, + &level, error); } /** * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the frequency of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Frequency" property. */ -DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_frequency( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + u16 freq; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: " - "no bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16, - &res->freq); + freq = (u16) res->freq; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &freq, error); } @@ -2601,72 +3766,65 @@ static int cmp_u8s_desc(const void *a, const void *b) /** * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing sorted array of bit rates + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Rates" property. */ -DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_rates( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply; - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; u8 *ie_rates = NULL; u32 *real_rates; int rates_num, i; + dbus_bool_t success = FALSE; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: " - "no bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; rates_num = wpa_bss_get_bit_rates(res, &ie_rates); if (rates_num < 0) - return NULL; + return FALSE; qsort(ie_rates, rates_num, 1, cmp_u8s_desc); real_rates = os_malloc(sizeof(u32) * rates_num); if (!real_rates) { os_free(ie_rates); - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } for (i = 0; i < rates_num; i++) real_rates[i] = ie_rates[i] * 500000; - reply = wpas_dbus_simple_array_property_getter(message, - DBUS_TYPE_UINT32, - real_rates, rates_num); + success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32, + real_rates, rates_num, + error); os_free(ie_rates); os_free(real_rates); - return reply; + return success; } -static DBusMessage * wpas_dbus_get_bss_security_prop( - DBusMessage *message, struct wpa_ie_data *ie_data) +static dbus_bool_t wpas_dbus_get_bss_security_prop( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error) { - DBusMessage *reply; - DBusMessageIter iter, iter_dict, variant_iter; + DBusMessageIter iter_dict, variant_iter; const char *group; - const char *pairwise[2]; /* max 2 pairwise ciphers is supported */ - const char *key_mgmt[7]; /* max 7 key managements may be supported */ + const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ + const char *key_mgmt[9]; /* max 9 key managements may be supported */ int n; - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); - else - reply = dbus_message_new_method_return(message); - if (!reply) - goto nomem; - - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter)) goto nomem; @@ -2687,6 +3845,14 @@ static DBusMessage * wpas_dbus_get_bss_security_prop( key_mgmt[n++] = "wpa-ft-eap"; if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) key_mgmt[n++] = "wpa-eap-sha256"; +#ifdef CONFIG_SUITEB + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) + key_mgmt[n++] = "wpa-eap-suite-b"; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + key_mgmt[n++] = "wpa-eap-suite-b-192"; +#endif /* CONFIG_SUITEB192 */ if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) key_mgmt[n++] = "wpa-none"; @@ -2705,9 +3871,18 @@ static DBusMessage * wpas_dbus_get_bss_security_prop( case WPA_CIPHER_CCMP: group = "ccmp"; break; + case WPA_CIPHER_GCMP: + group = "gcmp"; + break; case WPA_CIPHER_WEP104: group = "wep104"; break; + case WPA_CIPHER_CCMP_256: + group = "ccmp-256"; + break; + case WPA_CIPHER_GCMP_256: + group = "gcmp-256"; + break; default: group = ""; break; @@ -2722,6 +3897,12 @@ static DBusMessage * wpas_dbus_get_bss_security_prop( pairwise[n++] = "tkip"; if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) pairwise[n++] = "ccmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) + pairwise[n++] = "gcmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256) + pairwise[n++] = "ccmp-256"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256) + pairwise[n++] = "gcmp-256"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", pairwise, n)) @@ -2745,154 +3926,241 @@ static DBusMessage * wpas_dbus_get_bss_security_prop( goto nomem; } - if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) - goto nomem; - if (!dbus_message_iter_close_container(&iter, &variant_iter)) + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(iter, &variant_iter)) goto nomem; - return reply; + return TRUE; nomem: - if (reply) - dbus_message_unref(reply); - - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } /** * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the WPA options of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "WPA" property. */ -DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_wpa( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; struct wpa_ie_data wpa_data; const u8 *ie; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; os_memset(&wpa_data, 0, sizeof(wpa_data)); ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); - if (ie) { - if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) - return wpas_dbus_error_unknown_error(message, - "invalid WPA IE"); + if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to parse WPA IE"); + return FALSE; } - return wpas_dbus_get_bss_security_prop(message, &wpa_data); + return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); } /** * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing the RSN options of requested bss + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "RSN" property. */ -DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_rsn( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; struct wpa_ie_data wpa_data; const u8 *ie; - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; os_memset(&wpa_data, 0, sizeof(wpa_data)); ie = wpa_bss_get_ie(res, WLAN_EID_RSN); - if (ie) { - if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) - return wpas_dbus_error_unknown_error(message, - "invalid RSN IE"); + if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to parse RSN IE"); + return FALSE; + } + + return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); +} + + +/** + * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "WPS" property. + */ +dbus_bool_t wpas_dbus_getter_bss_wps( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; +#ifdef CONFIG_WPS + struct wpabuf *wps_ie; +#endif /* CONFIG_WPS */ + DBusMessageIter iter_dict, variant_iter; + int wps_support = 0; + const char *type = ""; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + +#ifdef CONFIG_WPS + wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); + if (wps_ie) { + wps_support = 1; + if (wps_is_selected_pbc_registrar(wps_ie)) + type = "pbc"; + else if (wps_is_selected_pin_registrar(wps_ie)) + type = "pin"; + + wpabuf_free(wps_ie); } +#endif /* CONFIG_WPS */ + + if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) || + !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(iter, &variant_iter)) + goto nomem; + + return TRUE; - return wpas_dbus_get_bss_security_prop(message, &wpa_data); +nomem: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } /** * wpas_dbus_getter_bss_ies - Return all IEs of a BSS - * @message: Pointer to incoming dbus message - * @bss: a pair of interface describing structure and bss's id - * Returns: a dbus message containing IEs byte array + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "IEs" property. */ -DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message, - struct bss_handler_args *bss) +dbus_bool_t wpas_dbus_getter_bss_ies( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res + 1, res->ie_len, + error); +} - if (!res) { - wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no " - "bss with id %d found", bss->id); - return NULL; - } - return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, - res + 1, res->ie_len); +/** + * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for BSS age + */ +dbus_bool_t wpas_dbus_getter_bss_age( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + struct os_reltime now, diff = { 0, 0 }; + u32 age; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + os_get_reltime(&now); + os_reltime_sub(&now, &res->last_update, &diff); + age = diff.sec > 0 ? diff.sec : 0; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age, + error); } /** * wpas_dbus_getter_enabled - Check whether network is enabled or disabled - * @message: Pointer to incoming dbus message - * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface - * and wpa_ssid structure for a configured network - * Returns: DBus message with boolean indicating state of configured network - * or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "enabled" property of a configured network. */ -DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message, - struct network_handler_args *net) +dbus_bool_t wpas_dbus_getter_enabled( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct network_handler_args *net = user_data; dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; - return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, - &enabled); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &enabled, error); } /** * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled - * @message: Pointer to incoming dbus message - * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface - * and wpa_ssid structure for a configured network - * Returns: NULL indicating success or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter for "Enabled" property of a configured network. */ -DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message, - struct network_handler_args *net) +dbus_bool_t wpas_dbus_setter_enabled( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; - + struct network_handler_args *net = user_data; struct wpa_supplicant *wpa_s; struct wpa_ssid *ssid; - dbus_bool_t enable; - reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, - &enable); - - if (reply) - return reply; + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &enable)) + return FALSE; wpa_s = net->wpa_s; ssid = net->ssid; @@ -2902,48 +4170,38 @@ DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message, else wpa_supplicant_disable_network(wpa_s, ssid); - return NULL; + return TRUE; } /** * wpas_dbus_getter_network_properties - Get options for a configured network - * @message: Pointer to incoming dbus message - * @net: wpa_supplicant structure for a network interface and - * wpa_ssid structure for a configured network - * Returns: DBus message with network properties or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Getter for "Properties" property of a configured network. */ -DBusMessage * wpas_dbus_getter_network_properties( - DBusMessage *message, struct network_handler_args *net) +dbus_bool_t wpas_dbus_getter_network_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { - DBusMessage *reply = NULL; - DBusMessageIter iter, variant_iter, dict_iter; + struct network_handler_args *net = user_data; + DBusMessageIter variant_iter, dict_iter; char **iterator; char **props = wpa_config_get_all(net->ssid, 1); - if (!props) - return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_bool_t success = FALSE; - if (message == NULL) - reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); - else - reply = dbus_message_new_method_return(message); - if (!reply) { - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); - goto out; + if (!props) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; } - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - "a{sv}", &variant_iter) || + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", + &variant_iter) || !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { - dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } @@ -2951,10 +4209,8 @@ DBusMessage * wpas_dbus_getter_network_properties( while (*iterator) { if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, *(iterator + 1))) { - dbus_message_unref(reply); - reply = dbus_message_new_error(message, - DBUS_ERROR_NO_MEMORY, - NULL); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); goto out; } iterator += 2; @@ -2962,13 +4218,13 @@ DBusMessage * wpas_dbus_getter_network_properties( if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || - !dbus_message_iter_close_container(&iter, &variant_iter)) { - dbus_message_unref(reply); - reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, - NULL); + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } + success = TRUE; + out: iterator = props; while (*iterator) { @@ -2976,39 +4232,300 @@ out: iterator++; } os_free(props); - return reply; + return success; } /** * wpas_dbus_setter_network_properties - Set options for a configured network - * @message: Pointer to incoming dbus message - * @net: wpa_supplicant structure for a network interface and - * wpa_ssid structure for a configured network - * Returns: NULL indicating success or DBus error on failure + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure * * Setter for "Properties" property of a configured network. */ -DBusMessage * wpas_dbus_setter_network_properties( - DBusMessage *message, struct network_handler_args *net) +dbus_bool_t wpas_dbus_setter_network_properties( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) { + struct network_handler_args *net = user_data; struct wpa_ssid *ssid = net->ssid; + DBusMessageIter variant_iter; - DBusMessage *reply = NULL; - DBusMessageIter iter, variant_iter; + dbus_message_iter_recurse(iter, &variant_iter); + return set_network_properties(net->wpa_s, ssid, &variant_iter, error); +} + + +#ifdef CONFIG_AP + +DBusMessage * wpas_dbus_handler_subscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + char *name; + + if (wpa_s->preq_notify_peer != NULL) { + if (os_strcmp(dbus_message_get_sender(message), + wpa_s->preq_notify_peer) == 0) + return NULL; + + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE, + "Another application is already subscribed"); + } + + name = os_strdup(dbus_message_get_sender(message)); + if (!name) + return wpas_dbus_error_no_memory(message); + + wpa_s->preq_notify_peer = name; + + /* Subscribe to clean up if application closes socket */ + wpas_dbus_subscribe_noc(priv); + + /* + * Double-check it's still alive to make sure that we didn't + * miss the NameOwnerChanged signal, e.g. while strdup'ing. + */ + if (!dbus_bus_name_has_owner(priv->con, name, NULL)) { + /* + * Application no longer exists, clean up. + * The return value is irrelevant now. + * + * Need to check if the NameOwnerChanged handling + * already cleaned up because we have processed + * DBus messages while checking if the name still + * has an owner. + */ + if (!wpa_s->preq_notify_peer) + return NULL; + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + wpas_dbus_unsubscribe_noc(priv); + } + + return NULL; +} + + +DBusMessage * wpas_dbus_handler_unsubscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + + if (!wpa_s->preq_notify_peer) + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_NO_SUBSCRIPTION, + "Not subscribed"); + + if (os_strcmp(wpa_s->preq_notify_peer, + dbus_message_get_sender(message))) + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM, + "Can't unsubscribe others"); + + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + wpas_dbus_unsubscribe_noc(priv); + return NULL; +} + + +void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *dst, const u8 *bssid, + const u8 *ie, size_t ie_len, u32 ssi_signal) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (priv == NULL || !wpa_s->dbus_new_path) + return; + + if (wpa_s->preq_notify_peer == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "ProbeRequest"); + if (msg == NULL) + return; + + dbus_message_set_destination(msg, wpa_s->preq_notify_peer); + + dbus_message_iter_init_append(msg, &iter); + + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr", + (const char *) addr, + ETH_ALEN)) || + (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst", + (const char *) dst, + ETH_ALEN)) || + (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid", + (const char *) bssid, + ETH_ALEN)) || + (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies", + (const char *) ie, + ie_len)) || + (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal", + ssi_signal)) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto fail; + + dbus_connection_send(priv->con, msg, NULL); + goto out; +fail: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); +out: + dbus_message_unref(msg); +} + +#endif /* CONFIG_AP */ + + +DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + dbus_int32_t frame_id; + DBusMessageIter iter, array; dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } dbus_message_iter_next(&iter); - dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, "Invalid value"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } - dbus_message_iter_recurse(&iter, &variant_iter); + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; + } - reply = set_network_properties(message, net->wpa_s, ssid, - &variant_iter); - if (reply) - wpa_printf(MSG_DEBUG, "dbus control interface couldn't set " - "network properties"); + if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Resize error"); + } + + wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply; + DBusMessageIter iter, array_iter; + dbus_int32_t frame_id; + const u8 *elem; + size_t elem_len; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + reply = dbus_message_new_method_return(message); + if (!reply) + return wpas_dbus_error_no_memory(message); + + dbus_message_iter_init_append(reply, &iter); + + elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]); + elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, + &elem, elem_len) || + !dbus_message_iter_close_container(&iter, &array_iter)) { + dbus_message_unref(reply); + reply = wpas_dbus_error_no_memory(message); + } return reply; } + + +DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + DBusMessageIter iter, array; + dbus_int32_t frame_id; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid value"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + + if (len == 1 && *ielems == '*') { + wpabuf_free(wpa_s->vendor_elem[frame_id]); + wpa_s->vendor_elem[frame_id] = NULL; + wpas_vendor_elem_update(wpa_s); + return NULL; + } + + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } + + if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0) + return NULL; + + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Not found"); +}