* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
#include "../notify.h"
-#include "../wpas_glue.h"
#include "../bss.h"
#include "../scan.h"
+#include "../autoscan.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
+#include "dbus_common_i.h"
+#include "drivers/driver.h"
static const char *debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
}
+/**
+ * wpas_dbus_error_scan_error - Return a new ScanError error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @error: Optional string to be used as the error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return a scan error
+ */
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+ const char *error)
+{
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+ error);
+}
+
+
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", NULL
+ "bssid", "scan_freq", "freq_list", NULL
};
static dbus_bool_t should_quote_opt(const char *key)
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
- if (ret < 0 || (size_t) ret != (size - 1))
+ if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
ret = os_snprintf(value, size, "%d",
entry.int32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else
goto error;
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
- (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+ (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
wpa_config_update_psk(ssid);
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
os_free(value);
+ value = NULL;
wpa_dbus_dict_entry_clear(&entry);
}
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;
+ &variant_iter) ||
+ !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
return TRUE;
-
-error:
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: error constructing reply", __func__);
- return FALSE;
}
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,
+ type_str, &variant_iter) ||
+ !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__);
+ "%s: failed to construct message", __func__);
return FALSE;
}
}
for (i = 0; i < array_len; i++) {
- dbus_message_iter_append_basic(&array_iter, type,
- array + i * element_size);
+ if (!dbus_message_iter_append_basic(&array_iter, type,
+ array + i * element_size)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 2.5",
+ __func__);
+ return FALSE;
+ }
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 3", __func__);
return FALSE;
}
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_simple_array_array_property_getter - Get array array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+ const int type,
+ struct wpabuf **array,
+ size_t array_len,
+ DBusError *error)
+{
+ DBusMessageIter variant_iter, array_iter;
+ char type_str[] = "aa?";
+ char inner_type_str[] = "a?";
+ const char *sub_type_str;
+ size_t i;
+
+ if (!dbus_type_is_basic(type)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: given type is not basic", __func__);
+ return FALSE;
+ }
+
+ sub_type_str = wpa_dbus_type_as_string(type);
+ type_str[2] = sub_type_str[0];
+ inner_type_str[1] = sub_type_str[0];
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ type_str, &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ inner_type_str, &array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message", __func__);
+ return FALSE;
+ }
+
+ for (i = 0; i < array_len && array[i]; i++) {
+ wpa_dbus_dict_bin_array_add_element(&array_iter,
+ wpabuf_head(array[i]),
+ wpabuf_len(array[i]));
+
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 4", __func__);
+ "%s: failed to close message", __func__);
return FALSE;
}
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!strcmp(entry.key, "Driver") &&
+ if (!os_strcmp(entry.key, "Driver") &&
(entry.type == DBUS_TYPE_STRING)) {
+ os_free(driver);
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
goto error;
- } else if (!strcmp(entry.key, "Ifname") &&
+ } else if (!os_strcmp(entry.key, "Ifname") &&
(entry.type == DBUS_TYPE_STRING)) {
+ os_free(ifname);
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
goto error;
- } else if (!strcmp(entry.key, "ConfigFile") &&
+ } else if (!os_strcmp(entry.key, "ConfigFile") &&
(entry.type == DBUS_TYPE_STRING)) {
+ os_free(confname);
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
goto error;
- } else if (!strcmp(entry.key, "BridgeIfname") &&
+ } else if (!os_strcmp(entry.key, "BridgeIfname") &&
(entry.type == DBUS_TYPE_STRING)) {
+ os_free(bridge_ifname);
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (bridge_ifname == NULL)
out:
os_free(driver);
os_free(ifname);
+ os_free(confname);
os_free(bridge_ifname);
return reply;
wpa_s = get_iface_by_dbus_path(global, path);
if (wpa_s == NULL)
reply = wpas_dbus_error_iface_unknown(message);
- else if (wpa_supplicant_remove_iface(global, wpa_s)) {
+ else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_error_unknown_error(
message, "wpa_supplicant couldn't remove this "
"interface.");
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
num++;
- paths = os_zalloc(num * sizeof(char*));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
}
+/**
+ * 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)
{
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) {
#define FREQS_ALLOC_CHUNK 32
if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
- nfreqs = os_realloc(freqs, sizeof(int) *
- (freqs_num + FREQS_ALLOC_CHUNK));
+ nfreqs = os_realloc_array(
+ freqs, freqs_num + FREQS_ALLOC_CHUNK,
+ sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
dbus_message_iter_next(&array_iter);
}
- nfreqs = os_realloc(freqs,
- sizeof(int) * (freqs_num + 1));
+ nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
}
+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
char *key = NULL, *type = NULL;
struct wpa_driver_scan_params params;
size_t i;
+ dbus_bool_t allow_roam = 1;
os_memset(¶ms, 0, sizeof(params));
if (wpas_dbus_get_scan_channels(message, &variant_iter,
¶ms, &reply) < 0)
goto out;
+ } else if (os_strcmp(key, "AllowRoam") == 0) {
+ if (wpas_dbus_get_scan_allow_roam(message,
+ &variant_iter,
+ &allow_roam,
+ &reply) < 0)
+ goto out;
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Unknown argument %s", key);
"passive scan");
goto out;
} else if (params.freqs && params.freqs[0]) {
- wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
} else if (!os_strcmp(type, "active")) {
/* Add wildcard ssid */
params.num_ssids++;
}
- wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+#ifdef CONFIG_AUTOSCAN
+ autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
+ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Unknown scan type: %s", type);
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);
}
+/**
+ * wpas_dbus_handler_signal_poll - Request immediate signal properties
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "SignalPoll" method call of a network device. Requests
+ * that wpa_supplicant read signal properties like RSSI, noise, and link
+ * speed and return them.
+ */
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ struct wpa_signal_info si;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, iter_dict, variant_iter;
+ int ret;
+
+ ret = wpa_drv_signal_poll(wpa_s, &si);
+ if (ret) {
+ return dbus_message_new_error(message, DBUS_ERROR_FAILED,
+ "Failed to read signal");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ goto nomem;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+ si.current_signal) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+ si.current_txrate / 1000) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+ si.current_noise) ||
+ !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+ si.frequency) ||
+ (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+ !wpa_dbus_dict_append_string(
+ &iter_dict, "width",
+ channel_width_to_string(si.chanwidth))) ||
+ (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+ (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+ si.center_frq1) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+ si.center_frq2))) ||
+ (si.avg_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+ si.avg_signal)) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
+ goto nomem;
+
+ return reply;
+
+nomem:
+ if (reply)
+ dbus_message_unref(reply);
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+ return reply;
+}
+
+
/*
* wpas_dbus_handler_disconnect - Terminate the current connection
* @message: Pointer to incoming dbus message
/**
+ * 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
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
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]: "
goto out;
}
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
out:
os_free(iface);
- os_free(net_id);
return reply;
}
}
if (ssid == wpa_s->current_ssid)
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
}
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;
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
/* 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 || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
out:
os_free(iface);
- os_free(net_id);
return reply;
}
/**
+ * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "NetworkReply" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+ DBusMessage *reply = NULL;
+ const char *op, *field, *value;
+ char *iface, *net_id;
+ int id;
+ struct wpa_ssid *ssid;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_STRING, &field,
+ DBUS_TYPE_STRING, &value,
+ DBUS_TYPE_INVALID))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ /* Extract the network ID and ensure the network */
+ /* is actually a child of this interface */
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ reply = wpas_dbus_error_invalid_args(message, op);
+ goto out;
+ }
+
+ errno = 0;
+ id = strtoul(net_id, NULL, 10);
+ if (errno != 0) {
+ reply = wpas_dbus_error_invalid_args(message, net_id);
+ goto out;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ reply = wpas_dbus_error_network_unknown(message);
+ goto out;
+ }
+
+ if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
+ field, value) < 0)
+ reply = wpas_dbus_error_invalid_args(message, field);
+ else {
+ /* Tell EAP to retry immediately */
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ }
+
+out:
+ os_free(iface);
+ return reply;
+#else /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "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
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
/*
* wpas_dbus_handler_flush_bss - Flush the BSS cache
* @message: Pointer to incoming dbus message
}
+#ifdef CONFIG_AUTOSCAN
/**
- * 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
+ * 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
*
- * Getter for "Capabilities" property of an interface.
+ * Handler function for "AutoScan" method call of network interface.
*/
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
{
- 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" };
+ DBusMessage *reply = NULL;
+ enum wpa_states state = wpa_s->wpa_state;
+ char *arg;
- if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+ DBUS_TYPE_INVALID);
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
- goto nomem;
+ 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);
- res = wpa_drv_get_capa(wpa_s, &capa);
+ return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
- /***** pairwise cipher */
- if (res < 0) {
- const char *args[] = {"ccmp", "tkip", "none"};
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "Pairwise", args,
- sizeof(args) / sizeof(char*)))
- goto nomem;
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto nomem;
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
+/*
+ * 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;
+}
- 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;
- }
+/*
+ * 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;
+}
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+
+#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) ||
+ !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) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "tkip")) ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "none")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "tkip"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep104"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep40"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "tkip")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wep104")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wep40")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "KeyMgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "none"))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ &iter_array) ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "none") ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
"ieee8021x"))
goto nomem;
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-eap"))
+ &iter_array, "wpa-eap") ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-eap")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-eap"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-psk"))
+ &iter_array, "wpa-psk") ||
+ ((capa.key_mgmt &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-psk")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-psk"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
#endif /* CONFIG_IEEE80211W */
}
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-none"))
- goto nomem;
- }
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "wpa-none"))
+ goto nomem;
#ifdef CONFIG_WPS
const char *args[] = { "rsn", "wpa" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "rsn"))
- goto nomem;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "rsn")) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
const char *args[] = { "open", "shared", "leap" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
&iter_array))
goto nomem;
- if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "open"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "shared"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "leap"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "open")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "shared")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "leap")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
/***** Scan */
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
- sizeof(scans) / sizeof(char *)))
+ 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_array) ||
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "infrastructure") ||
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc") ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ap")) ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "p2p")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
goto nomem;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return 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
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
+ 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_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
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *bridge_ifname;
-
- bridge_ifname = wpa_s->bridge_ifname ? wpa_s->bridge_ifname : "";
+ const char *bridge_ifname = wpa_s->bridge_ifname;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&bridge_ifname, error);
}
unsigned int i = 0;
dbus_bool_t success = FALSE;
- paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+ paths = os_calloc(wpa_s->num_bss, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
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_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
/**
+ * 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->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->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
res = get_bss_helper(args, error, __func__);
if (!res)
return FALSE;
-
- if (res->caps & IEEE80211_CAP_IBSS)
- mode = "ad-hoc";
- else
- mode = "infrastructure";
+ 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);
{
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,
- &res->level, error);
+ &level, error);
}
{
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,
- &res->freq, error);
+ &freq, error);
}
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
- const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
- const char *key_mgmt[7]; /* max 7 key managements may be supported */
+ const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
+ const char *key_mgmt[8]; /* max 8 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
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_IEEE8021X_SUITE_B)
+ key_mgmt[n++] = "wpa-eap-suite-b";
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
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;
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;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
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;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse WPA IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
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;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse RSN IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(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) ||
+ !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";
+
+ wpabuf_free(wps_ie);
+ }
+#endif /* CONFIG_WPS */
+
+ if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
+ goto nomem;
+
+ return TRUE;
+
+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
/**
+ * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for BSS age
+ */
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+ void *user_data)
+{
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *res;
+ struct os_reltime now, diff = { 0, 0 };
+ u32 age;
+
+ res = get_bss_helper(args, error, __func__);
+ if (!res)
+ return FALSE;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &res->last_update, &diff);
+ age = diff.sec > 0 ? diff.sec : 0;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
+ error);
+}
+
+
+/**
* wpas_dbus_getter_enabled - Check whether network is enabled or disabled
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
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) ||
+ (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+ (const char *) addr,
+ ETH_ALEN)) ||
+ (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+ (const char *) dst,
+ ETH_ALEN)) ||
+ (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+ (const char *) bssid,
+ ETH_ALEN)) ||
+ (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+ (const char *) ie,
+ ie_len)) ||
+ (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+ ssi_signal)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto fail;
+
+ dbus_connection_send(priv->con, msg, NULL);
+ goto out;
+fail:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+ dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_AP */