hostapd/wpa_supplicant/dbus/dbus_new_handlers.c
Jouni Malinen ceb4cd89c9 dbus: Fix a potential double-free in on error path (CID 62880)
It would have been at least theoretically possible to hit the first
error in the loop and end up jumping to error handling which would call
os_free(value) without the value having been cleared after the os_free()
call at the end of the previous loop iteration.

Signed-off-by: Jouni Malinen <j@w1.fi>
2014-06-12 19:45:02 +03:00

4218 lines
113 KiB
C

/*
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
#include "../notify.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"
static const char *debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
};
/**
* wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
* @message: Pointer to incoming dbus message this error refers to
* @arg: Optional string appended to error message
* Returns: a dbus error message
*
* Convenience function to create and return an UnknownError
*/
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);
}
/**
* wpas_dbus_error_iface_unknown - Return a new invalid interface error message
* @message: Pointer to incoming dbus message this error refers to
* Returns: A dbus error message
*
* Convenience function to create and return an invalid interface error
*/
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.");
}
/**
* wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
* @message: Pointer to incoming dbus message this error refers to
* Returns: a dbus error message
*
* Convenience function to create and return an invalid network error
*/
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.");
}
/**
* wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
* @message: Pointer to incoming dbus message this error refers to
* Returns: a dbus error message
*
* Convenience function to create and return an invalid options error
*/
DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
const char *arg)
{
DBusMessage *reply;
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);
return reply;
}
/**
* 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
*/
DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
const char *error)
{
DBusMessage *reply;
reply = dbus_message_new_error(message,
WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
error);
return reply;
}
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
"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;
i++;
}
return TRUE;
}
/**
* get_iface_by_dbus_path - Get a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
* @path: Pointer to a dbus object path representing an interface
* Returns: Pointer to the interface or %NULL if not found
*/
static struct wpa_supplicant * get_iface_by_dbus_path(
struct wpa_global *global, const char *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)
return wpa_s;
}
return NULL;
}
/**
* set_network_properties - Set properties of a configured network
* @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.
* @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
*/
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 };
DBusMessageIter iter_dict;
char *value = NULL;
if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
return FALSE;
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
size_t size = 50;
int ret;
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)
goto error;
size = entry.array_len * 2 + 1;
value = os_zalloc(size);
if (value == NULL)
goto error;
ret = wpa_snprintf_hex(value, size,
(u8 *) entry.bytearray_value,
entry.array_len);
if (ret <= 0)
goto error;
} else if (entry.type == DBUS_TYPE_STRING) {
if (should_quote_opt(entry.key)) {
size = os_strlen(entry.str_value);
if (size <= 0)
goto error;
size += 3;
value = os_zalloc(size);
if (value == NULL)
goto error;
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
if (ret < 0 || (size_t) ret != (size - 1))
goto error;
} else {
value = os_strdup(entry.str_value);
if (value == NULL)
goto error;
}
} else if (entry.type == DBUS_TYPE_UINT32) {
value = os_zalloc(size);
if (value == NULL)
goto error;
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
if (ret <= 0)
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
if (value == NULL)
goto error;
ret = os_snprintf(value, size, "%d",
entry.int32_value);
if (ret <= 0)
goto error;
} else
goto error;
if (wpa_config_set(ssid, entry.key, value, 0) < 0)
goto error;
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
(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);
}
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
* @iter: Message iter to use when appending arguments
* @type: DBus type of property (must be basic type)
* @val: pointer to place holding property value
* @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.
*/
dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
const int type,
const void *val,
DBusError *error)
{
DBusMessageIter variant_iter;
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: given type is not basic", __func__);
return FALSE;
}
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
wpa_dbus_type_as_string(type),
&variant_iter))
goto error;
if (!dbus_message_iter_append_basic(&variant_iter, type, val))
goto error;
if (!dbus_message_iter_close_container(iter, &variant_iter))
goto error;
return TRUE;
error:
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: error constructing reply", __func__);
return FALSE;
}
/**
* wpas_dbus_simple_property_setter - Set basic type property
* @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: TRUE if the request was successful, FALSE if it failed
*
* Generic setter for basic type properties. Type is required to be basic.
*/
dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
DBusError *error,
const int type, void *val)
{
DBusMessageIter variant_iter;
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: given type is not basic", __func__);
return FALSE;
}
/* Look at the new value */
dbus_message_iter_recurse(iter, &variant_iter);
if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"wrong property type");
return FALSE;
}
dbus_message_iter_get_basic(&variant_iter, val);
return TRUE;
}
/**
* wpas_dbus_simple_array_property_getter - Get 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_property_getter(DBusMessageIter *iter,
const int type,
const void *array,
size_t array_len,
DBusError *error)
{
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)) {
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 (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
type_str, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 1", __func__);
return FALSE;
}
if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
sub_type_str, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 2", __func__);
return FALSE;
}
switch(type) {
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
element_size = 1;
break;
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
element_size = sizeof(uint16_t);
break;
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
element_size = sizeof(uint32_t);
break;
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
element_size = sizeof(uint64_t);
break;
case DBUS_TYPE_DOUBLE:
element_size = sizeof(double);
break;
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
element_size = sizeof(char *);
break;
default:
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_close_container(&variant_iter, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 3", __func__);
return FALSE;
}
if (!dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 4", __func__);
return FALSE;
}
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_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 1", __func__);
return FALSE;
}
if (!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 2", __func__);
return FALSE;
}
for (i = 0; i < array_len; 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_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to close message 2", __func__);
return FALSE;
}
if (!dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to close message 1", __func__);
return FALSE;
}
return TRUE;
}
/**
* wpas_dbus_handler_create_interface - Request registration of a network iface
* @message: Pointer to incoming dbus message
* @global: %wpa_supplicant global data structure
* Returns: The object path of the new interface object,
* or a dbus error message with more information
*
* Handler function for "CreateInterface" method call. Handles requests
* by dbus clients to register a network interface that wpa_supplicant
* will manage.
*/
DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
struct wpa_global *global)
{
DBusMessageIter iter_dict;
DBusMessage *reply = NULL;
DBusMessageIter iter;
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, NULL))
goto error;
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
if (!os_strcmp(entry.key, "Driver") &&
(entry.type == DBUS_TYPE_STRING)) {
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
goto error;
} else if (!os_strcmp(entry.key, "Ifname") &&
(entry.type == DBUS_TYPE_STRING)) {
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
goto error;
} else if (!os_strcmp(entry.key, "ConfigFile") &&
(entry.type == DBUS_TYPE_STRING)) {
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
goto error;
} else if (!os_strcmp(entry.key, "BridgeIfname") &&
(entry.type == DBUS_TYPE_STRING)) {
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (bridge_ifname == NULL)
goto error;
} else {
wpa_dbus_dict_entry_clear(&entry);
goto error;
}
}
if (ifname == NULL)
goto error; /* Required Ifname argument missing */
/*
* Try to get the wpa_supplicant record for this iface, return
* 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.");
} 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))) {
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);
} else {
reply = wpas_dbus_error_unknown_error(
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;
}
/**
* wpas_dbus_handler_remove_interface - Request deregistration of an interface
* @message: Pointer to incoming dbus message
* @global: wpa_supplicant global data structure
* Returns: a dbus message containing a UINT32 indicating success (1) or
* failure (0), or returns a dbus error message with more information
*
* Handler function for "removeInterface" method call. Handles requests
* by dbus clients to deregister a network interface that wpa_supplicant
* currently manages.
*/
DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
struct wpa_global *global)
{
struct wpa_supplicant *wpa_s;
char *path;
DBusMessage *reply = NULL;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
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, 0)) {
reply = wpas_dbus_error_unknown_error(
message, "wpa_supplicant couldn't remove this "
"interface.");
}
return reply;
}
/**
* wpas_dbus_handler_get_interface - Get the object path for an interface name
* @message: Pointer to incoming dbus message
* @global: %wpa_supplicant global data structure
* Returns: The object path of the interface object,
* or a dbus error message with more information
*
* Handler function for "getInterface" method call.
*/
DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
struct wpa_global *global)
{
DBusMessage *reply = NULL;
const char *ifname;
const char *path;
struct wpa_supplicant *wpa_s;
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
DBUS_TYPE_INVALID);
wpa_s = wpa_supplicant_get_iface(global, ifname);
if (wpa_s == 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);
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 reply;
}
/**
* wpas_dbus_getter_debug_level - Get 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.
*/
dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
const char *str;
int idx = wpa_debug_level;
if (idx < 0)
idx = 0;
if (idx > 5)
idx = 5;
str = debug_strings[idx];
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&str, error);
}
/**
* wpas_dbus_getter_debug_timestamp - Get 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.
*/
dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_timestamp, error);
}
/**
* wpas_dbus_getter_debug_show_keys - Get 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.
*/
dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_show_keys, error);
}
/**
* wpas_dbus_setter_debug_level - Set 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
*
* Setter for "DebugLevel" property.
*/
dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
const char *str = NULL;
int i, val = -1;
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) {
val = i;
break;
}
if (val < 0 ||
wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
wpa_debug_show_keys)) {
dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
"level value");
return FALSE;
}
return TRUE;
}
/**
* wpas_dbus_setter_debug_timestamp - Set 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
*
* Setter for "DebugTimestamp" property.
*/
dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
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 TRUE;
}
/**
* wpas_dbus_setter_debug_show_keys - Set 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
*
* Setter for "DebugShowKeys" property.
*/
dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
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 TRUE;
}
/**
* wpas_dbus_getter_interfaces - Request registered interfaces list
* @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
*/
dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
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++;
paths = os_calloc(num, sizeof(char *));
if (!paths) {
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;
success = wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_OBJECT_PATH,
paths, num, error);
os_free(paths);
return success;
}
/**
* wpas_dbus_getter_eap_methods - Request supported EAP methods list
* @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
*/
dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
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) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
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 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(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);
}
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");
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Type value type. String required");
return -1;
}
dbus_message_iter_get_basic(var, type);
return 0;
}
static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
struct wpa_driver_scan_params *params,
DBusMessage **reply)
{
struct wpa_driver_scan_ssid *ssids = params->ssids;
size_t ssids_num = 0;
u8 *ssid;
DBusMessageIter array_iter, sub_array_iter;
char *val;
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");
*reply = wpas_dbus_error_invalid_args(
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");
*reply = wpas_dbus_error_invalid_args(
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)
{
if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Too many ssids specified on scan dbus "
"call");
*reply = wpas_dbus_error_invalid_args(
message, "Too many ssids specified. Specify "
"at most four");
return -1;
}
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
if (len > MAX_SSID_LEN) {
wpa_printf(MSG_DEBUG,
"wpas_dbus_handler_scan[dbus]: "
"SSID too long (len=%d max_len=%d)",
len, MAX_SSID_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);
return -1;
}
os_memcpy(ssid, val, len);
} else {
/* Allow zero-length SSIDs */
ssid = NULL;
}
ssids[ssids_num].ssid = ssid;
ssids[ssids_num].ssid_len = len;
dbus_message_iter_next(&array_iter);
ssids_num++;
}
params->num_ssids = ssids_num;
return 0;
}
static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
struct wpa_driver_scan_params *params,
DBusMessage **reply)
{
u8 *ies = NULL, *nies;
int ies_len = 0;
DBusMessageIter array_iter, sub_array_iter;
char *val;
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");
*reply = wpas_dbus_error_invalid_args(
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");
*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)
{
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
if (len == 0) {
dbus_message_iter_next(&array_iter);
continue;
}
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);
return -1;
}
ies = nies;
os_memcpy(ies + ies_len, val, len);
ies_len += len;
dbus_message_iter_next(&array_iter);
}
params->extra_ies = ies;
params->extra_ies_len = ies_len;
return 0;
}
static int wpas_dbus_get_scan_channels(DBusMessage *message,
DBusMessageIter *var,
struct wpa_driver_scan_params *params,
DBusMessage **reply)
{
DBusMessageIter array_iter, sub_array_iter;
int *freqs = NULL, *nfreqs;
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");
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Channels value type. Array of structs "
"required");
return -1;
}
dbus_message_iter_recurse(var, &array_iter);
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");
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Channels value type. Array of structs "
"required");
return -1;
}
while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
{
int freq, width;
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
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",
dbus_message_iter_get_arg_type(
&sub_array_iter));
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Channel struct. Two UINT32s "
"required");
os_free(freqs);
return -1;
}
dbus_message_iter_get_basic(&sub_array_iter, &freq);
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");
*reply = wpas_dbus_error_invalid_args(
message,
"Wrong Channel struct. Two UINT32s required");
os_free(freqs);
return -1;
}
dbus_message_iter_get_basic(&sub_array_iter, &width);
#define FREQS_ALLOC_CHUNK 32
if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
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);
return -1;
}
freqs[freqs_num] = freq;
freqs_num++;
dbus_message_iter_next(&array_iter);
}
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);
return -1;
}
freqs[freqs_num] = 0;
params->freqs = freqs;
return 0;
}
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, "wpas_dbus_handler_scan[dbus]: "
"Type must be a boolean");
*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
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: NULL indicating success or DBus error message on failure
*
* Handler function for "Scan" method call of a network device. Requests
* that wpa_supplicant perform a wireless scan as soon as possible
* on a particular wireless interface.
*/
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
char *key = NULL, *type = NULL;
struct wpa_driver_scan_params params;
size_t i;
dbus_bool_t allow_roam = 1;
os_memset(&params, 0, sizeof(params));
dbus_message_iter_init(message, &iter);
dbus_message_iter_recurse(&iter, &dict_iter);
while (dbus_message_iter_get_arg_type(&dict_iter) ==
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);
dbus_message_iter_recurse(&entry_iter, &variant_iter);
if (os_strcmp(key, "Type") == 0) {
if (wpas_dbus_get_scan_type(message, &variant_iter,
&type, &reply) < 0)
goto out;
} else if (os_strcmp(key, "SSIDs") == 0) {
if (wpas_dbus_get_scan_ssids(message, &variant_iter,
&params, &reply) < 0)
goto out;
} else if (os_strcmp(key, "IEs") == 0) {
if (wpas_dbus_get_scan_ies(message, &variant_iter,
&params, &reply) < 0)
goto out;
} else if (os_strcmp(key, "Channels") == 0) {
if (wpas_dbus_get_scan_channels(message, &variant_iter,
&params, &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);
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
dbus_message_iter_next(&dict_iter);
}
if (!type) {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Scan type not specified");
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
if (!os_strcmp(type, "passive")) {
if (params.num_ssids || params.extra_ies_len) {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"SSIDs or IEs specified for passive scan.");
reply = wpas_dbus_error_invalid_args(
message, "You can specify only Channels in "
"passive scan");
goto out;
} else if (params.freqs && params.freqs[0]) {
if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
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")) {
if (!params.num_ssids) {
/* Add wildcard ssid */
params.num_ssids++;
}
#ifdef CONFIG_AUTOSCAN
autoscan_deinit(wpa_s);
#endif /* CONFIG_AUTOSCAN */
if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
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);
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);
os_free((u8 *) params.extra_ies);
os_free(params.freqs);
return reply;
}
/*
* 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) {
wpa_s->disconnected = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
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
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: A dbus message containing the object path of the new network
*
* Handler function for "AddNetwork" method call of a network interface.
*/
DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
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 (ssid == NULL) {
wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
"can't add new interface.");
reply = wpas_dbus_error_unknown_error(
message,
"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);
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
"control interface couldn't set network "
"properties");
reply = wpas_dbus_reply_new_from_error(message, &error,
DBUS_ERROR_INVALID_ARGS,
"Failed to add network");
dbus_error_free(&error);
goto err;
}
/* Construct the object path for this network. */
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
wpa_s->dbus_new_path, ssid->id);
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
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);
goto err;
}
return reply;
err:
if (ssid) {
wpas_notify_network_removed(wpa_s, ssid);
wpa_config_remove_network(wpa_s->conf, ssid->id);
}
return reply;
}
/**
* 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_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_remove_network - Remove a configured network
* @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 "RemoveNetwork" method call of a network interface.
*/
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
const char *op;
char *iface = NULL, *net_id = NULL;
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, 0, &net_id, NULL);
if (iface == NULL || net_id == NULL ||
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, op);
goto out;
}
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
reply = wpas_dbus_error_network_unknown(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);
reply = wpas_dbus_error_unknown_error(
message, "error removing the specified network on "
"this interface.");
goto out;
}
out:
os_free(iface);
os_free(net_id);
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,
"wpas_dbus_handler_remove_all_networks[dbus]: "
"error occurred when removing network %d",
ssid->id);
return;
}
if (ssid == wpa_s->current_ssid)
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
/**
* 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;
}
/**
* wpas_dbus_handler_select_network - Attempt association with a network
* @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 "SelectNetwork" method call of network interface.
*/
DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
const char *op;
char *iface = NULL, *net_id = NULL;
int id;
struct wpa_ssid *ssid;
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, 0, &net_id, NULL);
if (iface == NULL || net_id == NULL ||
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, op);
goto out;
}
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
reply = wpas_dbus_error_network_unknown(message);
goto out;
}
/* Finally, associate with the network */
wpa_supplicant_select_network(wpa_s, ssid);
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 = NULL, *net_id = NULL;
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, 0, &net_id, NULL);
if (iface == NULL || net_id == NULL ||
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);
os_free(net_id);
return reply;
#else /* IEEE8021X_EAPOL */
wpa_printf(MSG_DEBUG, "CTRL_IFACE: 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
* Returns: A dbus message containing an error on failure or NULL on success
*
* Asks wpa_supplicant to internally store a binary blobs.
*/
DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
DBusMessageIter iter, array_iter;
char *blob_name;
u8 *blob_data;
int blob_len;
struct wpa_config_blob *blob = NULL;
dbus_message_iter_init(message, &iter);
dbus_message_iter_get_basic(&iter, &blob_name);
if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
return dbus_message_new_error(message,
WPAS_DBUS_ERROR_BLOB_EXISTS,
NULL);
}
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
blob = os_zalloc(sizeof(*blob));
if (!blob) {
reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
goto err;
}
blob->data = os_malloc(blob_len);
if (!blob->data) {
reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
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);
return reply;
err:
if (blob) {
os_free(blob->name);
os_free(blob->data);
os_free(blob);
}
return reply;
}
/**
* wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
* @message: Pointer to incoming dbus message
* @wpa_s: %wpa_supplicant data structure
* Returns: A dbus message containing array of bytes (blob)
*
* Gets one wpa_supplicant's binary blobs.
*/
DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
DBusMessageIter iter, array_iter;
char *blob_name;
const struct wpa_config_blob *blob;
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
DBUS_TYPE_INVALID);
blob = wpa_config_get_blob(wpa_s->conf, blob_name);
if (!blob) {
return dbus_message_new_error(message,
WPAS_DBUS_ERROR_BLOB_UNKNOWN,
"Blob id not set");
}
reply = dbus_message_new_method_return(message);
if (!reply) {
reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
goto out;
}
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)) {
dbus_message_unref(reply);
reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
NULL);
goto out;
}
out:
return reply;
}
/**
* wpas_remove_handler_remove_blob - Remove named binary blob
* @message: Pointer to incoming dbus message
* @wpa_s: %wpa_supplicant data structure
* Returns: NULL on success or dbus error
*
* Asks wpa_supplicant to internally remove a binary blobs.
*/
DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
char *blob_name;
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
DBUS_TYPE_INVALID);
if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
return dbus_message_new_error(message,
WPAS_DBUS_ERROR_BLOB_UNKNOWN,
"Blob id not set");
}
wpas_notify_blob_removed(wpa_s, blob_name);
return reply;
}
#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_handler_autoscan - Set autoscan parameters for the interface
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: NULL
*
* Handler function for "AutoScan" method call of network interface.
*/
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 = dbus_message_new_error(message,
DBUS_ERROR_NO_MEMORY,
NULL);
} 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 */
/**
* 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.");
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(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_driver_capa capa;
int res;
DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
variant_iter;
const char *scans[] = { "active", "passive", "ssid" };
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))
goto nomem;
res = wpa_drv_get_capa(wpa_s, &capa);
/***** pairwise cipher */
if (res < 0) {
const char *args[] = {"ccmp", "tkip", "none"};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
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_256) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ccmp-256"))
goto nomem;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp-256"))
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_GCMP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp"))
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_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
/***** group cipher */
if (res < 0) {
const char *args[] = {
"ccmp", "tkip", "wep104", "wep40"
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
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_256) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ccmp-256"))
goto nomem;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp-256"))
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_GCMP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp"))
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_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
/***** key management */
if (res < 0) {
const char *args[] = {
"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
#ifdef CONFIG_WPS
"wps",
#endif /* CONFIG_WPS */
"none"
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "KeyMgmt", args,
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,
"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"))
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(
&iter_array, "wpa-eap-sha256"))
goto nomem;
#endif /* CONFIG_IEEE80211W */
}
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"))
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(
&iter_array, "wpa-psk-sha256"))
goto nomem;
#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;
}
#ifdef CONFIG_WPS
if (!wpa_dbus_dict_string_array_add_element(&iter_array,
"wps"))
goto nomem;
#endif /* CONFIG_WPS */
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
/***** WPA protocol */
if (res < 0) {
const char *args[] = { "rsn", "wpa" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
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_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
/***** auth alg */
if (res < 0) {
const char *args[] = { "open", "shared", "leap" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
&iter_dict_entry,
&iter_dict_val,
&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,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
/***** Scan */
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
ARRAY_SIZE(scans)))
goto nomem;
/***** Modes */
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
&iter_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "infrastructure"))
goto nomem;
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ad-hoc"))
goto nomem;
if (res >= 0) {
if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "ap"))
goto nomem;
}
if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "p2p"))
goto nomem;
}
}
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
/***** Modes end */
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))
goto nomem;
if (!dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
nomem:
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
/**
* wpas_dbus_getter_state - Get 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.
*/
dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
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);
/* make state string lowercase to fit new DBus API convention
*/
state_ls = tmp = os_strdup(str_state);
if (!tmp) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
while (*tmp) {
*tmp = tolower(*tmp);
tmp++;
}
success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&state_ls, error);
os_free(state_ls);
return success;
}
/**
* wpas_dbus_new_iface_get_scanning - Get interface scanning 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 "scanning" property.
*/
dbus_bool_t wpas_dbus_getter_scanning(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(iter, DBUS_TYPE_BOOLEAN,
&scanning, error);
}
/**
* wpas_dbus_getter_ap_scan - Control roaming mode
* @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.
*/
dbus_bool_t wpas_dbus_getter_ap_scan(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(iter, DBUS_TYPE_UINT32,
&ap_scan, error);
}
/**
* wpas_dbus_setter_ap_scan - Control roaming mode
* @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.
*/
dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t ap_scan;
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)) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"ap_scan must be 0, 1, or 2");
return FALSE;
}
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(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(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(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_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(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(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(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(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(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(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(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(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
* @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.
*/
dbus_bool_t wpas_dbus_getter_ifname(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(iter, DBUS_TYPE_STRING,
&ifname, error);
}
/**
* wpas_dbus_getter_driver - Get interface name
* @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.
*/
dbus_bool_t wpas_dbus_getter_driver(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");
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(iter, DBUS_TYPE_STRING,
&driver, error);
}
/**
* wpas_dbus_getter_current_bss - Get current bss object path
* @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.
*/
dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
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)
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, "/");
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
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)
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, "/");
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *eap_mode;
const char *auth_mode;
char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
if (wpa_s->wpa_state != WPA_COMPLETED) {
auth_mode = "INACTIVE";
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
"EAP-%s", eap_mode);
auth_mode = eap_mode_buf;
} else {
auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
wpa_s->current_ssid->proto);
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&auth_mode, error);
}
/**
* wpas_dbus_getter_bridge_ifname - Get interface name
* @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.
*/
dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *bridge_ifname = wpa_s->bridge_ifname;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&bridge_ifname, error);
}
/**
* wpas_dbus_getter_bsss - Get array of BSSs objects
* @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.
*/
dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_bss *bss;
char **paths;
unsigned int i = 0;
dbus_bool_t success = FALSE;
paths = os_calloc(wpa_s->num_bss, sizeof(char *));
if (!paths) {
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) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
"no memory");
goto out;
}
/* Construct the object path for this BSS. */
os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
wpa_s->dbus_new_path, bss->id);
}
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 success;
}
/**
* wpas_dbus_getter_networks - Get array of networks objects
* @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.
*/
dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
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, "%s[dbus]: An error occurred getting "
"networks list.", __func__);
dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
"occurred getting the networks list", __func__);
return FALSE;
}
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (!network_is_persistent_group(ssid))
num++;
paths = os_calloc(num, sizeof(char *));
if (!paths) {
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) {
dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
goto out;
}
/* Construct the object path for this network. */
os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
wpa_s->dbus_new_path, ssid->id);
}
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 success;
}
/**
* 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 "PKCS11EnginePath" property.
*/
dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_engine_path;
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR,
"wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
"error occurred getting the PKCS #11 engine path.");
dbus_set_error_const(
error, DBUS_ERROR_FAILED,
"An error occured getting the PKCS #11 engine path.");
return FALSE;
}
if (wpa_s->conf->pkcs11_engine_path == NULL)
pkcs11_engine_path = "";
else
pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&pkcs11_engine_path, error);
}
/**
* 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(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_module_path;
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR,
"wpas_dbus_getter_pkcs11_module_path[dbus]: An "
"error occurred getting the PKCS #11 module path.");
dbus_set_error_const(
error, DBUS_ERROR_FAILED,
"An error occured getting the PKCS #11 module path.");
return FALSE;
}
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(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_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
blob = wpa_s->conf->blobs;
while (blob) {
if (!dbus_message_iter_open_container(&dict_iter,
DBUS_TYPE_DICT_ENTRY,
NULL, &entry_iter) ||
!dbus_message_iter_append_basic(&entry_iter,
DBUS_TYPE_STRING,
&(blob->name)) ||
!dbus_message_iter_open_container(&entry_iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&array_iter) ||
!dbus_message_iter_append_fixed_array(&array_iter,
DBUS_TYPE_BYTE,
&(blob->data),
blob->len) ||
!dbus_message_iter_close_container(&entry_iter,
&array_iter) ||
!dbus_message_iter_close_container(&dict_iter,
&entry_iter)) {
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_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
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->bssid, ETH_ALEN,
error);
}
/**
* wpas_dbus_getter_bss_ssid - Return the SSID 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 "SSID" property.
*/
dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
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->ssid, res->ssid_len,
error);
}
/**
* wpas_dbus_getter_bss_privacy - Return the privacy flag 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 "Privacy" property.
*/
dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
dbus_bool_t privacy;
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(iter, DBUS_TYPE_BOOLEAN,
&privacy, error);
}
/**
* wpas_dbus_getter_bss_mode - Return the mode 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 "Mode" property.
*/
dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
const char *mode;
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";
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&mode, error);
}
/**
* wpas_dbus_getter_bss_level - Return the signal strength 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 "Level" property.
*/
dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
s16 level;
res = get_bss_helper(args, error, __func__);
if (!res)
return FALSE;
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
u16 freq;
res = get_bss_helper(args, error, __func__);
if (!res)
return FALSE;
freq = (u16) res->freq;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
&freq, error);
}
static int cmp_u8s_desc(const void *a, const void *b)
{
return (*(u8 *) b - *(u8 *) a);
}
/**
* wpas_dbus_getter_bss_rates - Return available bit rates 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 "Rates" property.
*/
dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
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;
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 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);
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;
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 success;
}
static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
struct wpa_ie_data *ie_data,
DBusError *error)
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
const char *key_mgmt[7]; /* max 7 key managements may be supported */
int n;
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))
goto nomem;
/* KeyMgmt */
n = 0;
if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
key_mgmt[n++] = "wpa-psk";
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
key_mgmt[n++] = "wpa-ft-psk";
if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
key_mgmt[n++] = "wpa-psk-sha256";
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
key_mgmt[n++] = "wpa-eap";
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
key_mgmt[n++] = "wpa-ft-eap";
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
key_mgmt[n++] = "wpa-eap-sha256";
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
key_mgmt, n))
goto nomem;
/* Group */
switch (ie_data->group_cipher) {
case WPA_CIPHER_WEP40:
group = "wep40";
break;
case WPA_CIPHER_TKIP:
group = "tkip";
break;
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;
}
if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
goto nomem;
/* Pairwise */
n = 0;
if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
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))
goto nomem;
/* Management group (RSN only) */
if (ie_data->proto == WPA_PROTO_RSN) {
switch (ie_data->mgmt_group_cipher) {
#ifdef CONFIG_IEEE80211W
case WPA_CIPHER_AES_128_CMAC:
group = "aes128cmac";
break;
#endif /* CONFIG_IEEE80211W */
default:
group = "";
break;
}
if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
group))
goto nomem;
}
if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
goto nomem;
if (!dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
nomem:
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
struct wpa_ie_data wpa_data;
const u8 *ie;
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) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"failed to parse WPA IE");
return FALSE;
}
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
}
/**
* wpas_dbus_getter_bss_rsn - Return the RSN 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 "RSN" property.
*/
dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
struct wpa_ie_data wpa_data;
const u8 *ie;
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) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"failed to parse RSN IE");
return FALSE;
}
}
return wpas_dbus_get_bss_security_prop(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(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;
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))
goto nomem;
if (!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) {
if (wps_is_selected_pbc_registrar(wps_ie))
type = "pbc";
else if (wps_is_selected_pin_registrar(wps_ie))
type = "pin";
}
#endif /* CONFIG_WPS */
if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
goto nomem;
if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
goto nomem;
if (!dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
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
* @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.
*/
dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
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);
}
/**
* wpas_dbus_getter_enabled - Check whether network is enabled or disabled
* @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.
*/
dbus_bool_t wpas_dbus_getter_enabled(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(iter, DBUS_TYPE_BOOLEAN,
&enabled, error);
}
/**
* wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
* @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.
*/
dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_supplicant *wpa_s;
struct wpa_ssid *ssid;
dbus_bool_t enable;
if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
&enable))
return FALSE;
wpa_s = net->wpa_s;
ssid = net->ssid;
if (enable)
wpa_supplicant_enable_network(wpa_s, ssid);
else
wpa_supplicant_disable_network(wpa_s, ssid);
return TRUE;
}
/**
* wpas_dbus_getter_network_properties - Get options for a configured 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 "Properties" property of a configured network.
*/
dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct network_handler_args *net = user_data;
DBusMessageIter variant_iter, dict_iter;
char **iterator;
char **props = wpa_config_get_all(net->ssid, 1);
dbus_bool_t success = FALSE;
if (!props) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
&variant_iter) ||
!wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
goto out;
}
iterator = props;
while (*iterator) {
if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
*(iterator + 1))) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
"no memory");
goto out;
}
iterator += 2;
}
if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
!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) {
os_free(*iterator);
iterator++;
}
os_free(props);
return success;
}
/**
* wpas_dbus_setter_network_properties - Set options for a configured 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
*
* Setter for "Properties" property of a configured network.
*/
dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_ssid *ssid = net->ssid;
DBusMessageIter 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 dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
"out of memory");
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)
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))
goto fail;
if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
(const char *) addr,
ETH_ALEN))
goto fail;
if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
(const char *) dst,
ETH_ALEN))
goto fail;
if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
(const char *) bssid,
ETH_ALEN))
goto fail;
if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
(const char *) ie,
ie_len))
goto fail;
if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
ssi_signal))
goto fail;
if (!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 */