From 8fc2fb56e456b4dfea4ea7c4afc34c20309560cd Mon Sep 17 00:00:00 2001 From: Witold Sowa Date: Mon, 9 Nov 2009 23:51:59 +0200 Subject: [PATCH] wpa_supplicant: new DBus API implementation This patch implements the new DBus API. Both, the new and the previous API may work concurrently and may be turned on or off separately in .config file. Some features of the new API are: - more wpa_supplicant's events are signaled with DBus signals, - introspection data (requires libxml2 and may be disabled), - CurrentBSS and CurrentNetwork properties, - PropertyChanged signal for most of properties, - Relatively easy to extend. .config options for the new API are: CONFIG_CTRL_IFACE_DBUS_NEW=y and CONFIG_CTRL_IFACE_DBUS_INTRO=y for introspection. This commit misses couple of parts from the full implementation (these are still under review): - fetching all configuration parameters for learning WPS information - scan result BSS add/remove notification (register_bss() and unregister_bss() notification callbacks) --- wpa_supplicant/Makefile | 31 +- wpa_supplicant/ctrl_iface_dbus_handlers.c | 102 +- wpa_supplicant/ctrl_iface_dbus_new.c | 2000 ++++++++++ wpa_supplicant/ctrl_iface_dbus_new.h | 142 + wpa_supplicant/ctrl_iface_dbus_new_handlers.c | 3312 +++++++++++++++++ wpa_supplicant/ctrl_iface_dbus_new_handlers.h | 142 + wpa_supplicant/ctrl_iface_dbus_new_helpers.c | 1900 ++++++++++ wpa_supplicant/ctrl_iface_dbus_new_helpers.h | 140 + wpa_supplicant/dbus-wpa_supplicant.conf | 10 + wpa_supplicant/defconfig | 10 +- wpa_supplicant/notify.c | 84 + wpa_supplicant/wpa_supplicant_i.h | 6 + 12 files changed, 7825 insertions(+), 54 deletions(-) create mode 100644 wpa_supplicant/ctrl_iface_dbus_new.c create mode 100644 wpa_supplicant/ctrl_iface_dbus_new.h create mode 100644 wpa_supplicant/ctrl_iface_dbus_new_handlers.c create mode 100644 wpa_supplicant/ctrl_iface_dbus_new_handlers.h create mode 100644 wpa_supplicant/ctrl_iface_dbus_new_helpers.c create mode 100644 wpa_supplicant/ctrl_iface_dbus_new_helpers.h diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 6436f3986..08797749a 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1025,12 +1025,12 @@ OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o endif ifdef CONFIG_CTRL_IFACE_DBUS -CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE -OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o dbus_dict_helpers.o +DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE +DBUS_OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o +DBUS_OBJS += dbus_dict_helpers.o ifndef DBUS_LIBS DBUS_LIBS := $(shell pkg-config --libs dbus-1) endif -LIBS += $(DBUS_LIBS) ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1) endif @@ -1045,9 +1045,32 @@ DBUS_VERSION_MINOR=0 endif DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR) DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR) -CFLAGS += $(DBUS_INCLUDE) +DBUS_CFLAGS += $(DBUS_INCLUDE) endif +ifdef CONFIG_CTRL_IFACE_DBUS_NEW +DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW +DBUS_OBJS ?= dbus_dict_helpers.o +DBUS_OBJS += ctrl_iface_dbus_new_helpers.o +DBUS_OBJS += ctrl_iface_dbus_new.o ctrl_iface_dbus_new_handlers.o +ifndef DBUS_LIBS +DBUS_LIBS := $(shell pkg-config --libs dbus-1) +endif +ifndef DBUS_INCLUDE +DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1) +endif +ifdef CONFIG_CTRL_IFACE_DBUS_INTRO +DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO +DBUS_INCLUDE += $(shell xml2-config --cflags) +DBUS_LIBS += $(shell xml2-config --libs) +endif +DBUS_CFLAGS += $(DBUS_INCLUDE) +endif + +OBJS += $(DBUS_OBJS) +CFLAGS += $(DBUS_CFLAGS) +LIBS += $(DBUS_LIBS) + ifdef CONFIG_READLINE CFLAGS += -DCONFIG_READLINE LIBS_c += -lncurses -lreadline diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.c b/wpa_supplicant/ctrl_iface_dbus_handlers.c index ea4d68241..2fd4e23b5 100644 --- a/wpa_supplicant/ctrl_iface_dbus_handlers.c +++ b/wpa_supplicant/ctrl_iface_dbus_handlers.c @@ -45,8 +45,8 @@ static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, DBusMessage *reply; reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, - "Did not receive correct message " - "arguments."); + "Did not receive correct message " + "arguments."); if (arg != NULL) dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); @@ -77,10 +77,10 @@ static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface) { - free((char *) iface->driver); - free((char *) iface->driver_param); - free((char *) iface->confname); - free((char *) iface->bridge_ifname); + os_free((char *) iface->driver); + os_free((char *) iface->driver_param); + os_free((char *) iface->confname); + os_free((char *) iface->bridge_ifname); } @@ -103,7 +103,7 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, DBusMessage *reply = NULL; DBusMessageIter iter; - memset(&iface, 0, sizeof(iface)); + os_memset(&iface, 0, sizeof(iface)); dbus_message_iter_init(message, &iter); @@ -113,7 +113,7 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) goto error; dbus_message_iter_get_basic(&iter, &ifname); - if (!strlen(ifname)) + if (!os_strlen(ifname)) goto error; iface.ifname = ifname; @@ -283,6 +283,7 @@ out: return reply; } + /** * wpas_dbus_global_set_debugparams- Set the debug params * @message: Pointer to incoming dbus message @@ -306,23 +307,21 @@ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, DBUS_TYPE_BOOLEAN, &debug_timestamp, DBUS_TYPE_BOOLEAN, &debug_show_keys, DBUS_TYPE_INVALID)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; + return wpas_dbus_new_invalid_opts_error(message, NULL); } if (wpa_supplicant_set_debug_params(global, debug_level, debug_timestamp ? 1 : 0, debug_show_keys ? 1 : 0)) { - reply = wpas_dbus_new_invalid_opts_error(message, NULL); - goto out; + return wpas_dbus_new_invalid_opts_error(message, NULL); } reply = wpas_dbus_new_success_reply(message); -out: return reply; } + /** * wpas_dbus_iface_scan - Request a wireless scan on an interface * @message: Pointer to incoming dbus message @@ -394,14 +393,14 @@ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, /* Construct the object path for this network. Note that ':' * is not a valid character in dbus object paths. */ - snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, - "%s/" WPAS_DBUS_BSSIDS_PART "/" - WPAS_DBUS_BSSID_FORMAT, - wpa_supplicant_get_dbus_path(wpa_s), - MAC2STR(res->bssid)); + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_BSSIDS_PART "/" + WPAS_DBUS_BSSID_FORMAT, + wpa_supplicant_get_dbus_path(wpa_s), + MAC2STR(res->bssid)); dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_OBJECT_PATH, &path); - free(path); + os_free(path); } dbus_message_iter_close_container(&iter, &sub_iter); @@ -551,8 +550,8 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, /* free returned method array */ while (eap_methods[i]) - free(eap_methods[i++]); - free(eap_methods); + os_free(eap_methods[i++]); + os_free(eap_methods); if (!success) goto error; @@ -834,17 +833,17 @@ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, wpa_config_set_network_defaults(ssid); /* Construct the object path for this network. */ - snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, - "%s/" WPAS_DBUS_NETWORKS_PART "/%d", - wpa_supplicant_get_dbus_path(wpa_s), - ssid->id); + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NETWORKS_PART "/%d", + wpa_supplicant_get_dbus_path(wpa_s), + ssid->id); reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); out: - free(path); + os_free(path); return reply; } @@ -880,6 +879,7 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, reply = wpas_dbus_new_invalid_network_error(message); goto out; } + /* Ensure the network is actually a child of this interface */ if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) { reply = wpas_dbus_new_invalid_network_error(message); @@ -908,8 +908,8 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, reply = wpas_dbus_new_success_reply(message); out: - free(iface); - free(net_id); + os_free(iface); + os_free(net_id); return reply; } @@ -920,6 +920,7 @@ static const char *dont_quote[] = { "bssid", NULL }; + static dbus_bool_t should_quote_opt(const char *key) { int i = 0; @@ -931,6 +932,7 @@ static dbus_bool_t should_quote_opt(const char *key) return TRUE; } + /** * wpas_dbus_iface_set_network - Set options for a configured network * @message: Pointer to incoming dbus message @@ -978,13 +980,13 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, if (value == NULL) goto error; ret = wpa_snprintf_hex(value, size, - (u8 *) entry.bytearray_value, - entry.array_len); + (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 = strlen(entry.str_value); + size = os_strlen(entry.str_value); /* Zero-length option check */ if (size <= 0) goto error; @@ -992,12 +994,12 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, value = os_zalloc(size); if (value == NULL) goto error; - ret = snprintf(value, size, "\"%s\"", - entry.str_value); + ret = os_snprintf(value, size, "\"%s\"", + entry.str_value); if (ret < 0 || (size_t) ret != (size - 1)) goto error; } else { - value = strdup(entry.str_value); + value = os_strdup(entry.str_value); if (value == NULL) goto error; } @@ -1005,14 +1007,16 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, value = os_zalloc(size); if (value == NULL) goto error; - ret = snprintf(value, size, "%u", entry.uint32_value); + 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 = snprintf(value, size, "%d", entry.int32_value); + ret = os_snprintf(value, size, "%d", + entry.int32_value); if (ret <= 0) goto error; } else @@ -1021,17 +1025,17 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, if (wpa_config_set(ssid, entry.key, value, 0) < 0) goto error; - if ((strcmp(entry.key, "psk") == 0 && + 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); - free(value); + os_free(value); wpa_dbus_dict_entry_clear(&entry); continue; error: - free(value); + os_free(value); reply = wpas_dbus_new_invalid_opts_error(message, entry.key); wpa_dbus_dict_entry_clear(&entry); break; @@ -1101,7 +1105,7 @@ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, char *iface_obj_path = NULL; char *network = NULL; - if (strlen(dbus_message_get_signature(message)) == 0) { + if (os_strlen(dbus_message_get_signature(message)) == 0) { /* Any network */ ssid = NULL; } else { @@ -1126,7 +1130,7 @@ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, } /* Ensure the object path really points to this interface */ obj_path = wpa_supplicant_get_dbus_path(wpa_s); - if (strcmp(iface_obj_path, obj_path) != 0) { + if (os_strcmp(iface_obj_path, obj_path) != 0) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } @@ -1150,8 +1154,8 @@ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, reply = wpas_dbus_new_success_reply(message); out: - free(iface_obj_path); - free(network); + os_free(iface_obj_path); + os_free(network); return reply; } @@ -1278,6 +1282,7 @@ error: return wpas_dbus_new_invalid_opts_error(message, NULL); } + /** * wpas_dbus_iface_get_state - Get interface state * @message: Pointer to incoming dbus message @@ -1429,7 +1434,7 @@ DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, * Asks wpa_supplicant to remove one or more previously stored binary blobs. */ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, - struct wpa_supplicant *wpa_s) + struct wpa_supplicant *wpa_s) { DBusMessageIter iter, array; char *err_msg = NULL; @@ -1445,7 +1450,7 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, const char *name; dbus_message_iter_get_basic(&array, &name); - if (!strlen(name)) + if (!os_strlen(name)) err_msg = "Invalid blob name."; if (wpa_config_remove_blob(wpa_s->conf, name) != 0) @@ -1455,10 +1460,9 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, dbus_message_iter_next(&array); } - if (err_msg) { + if (err_msg) return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, err_msg); - } return wpas_dbus_new_success_reply(message); } @@ -1557,7 +1561,7 @@ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, DBUS_TYPE_INVALID); } else { char npin[9]; - sprintf(npin, "%08d", ret); + os_snprintf(npin, sizeof(npin), "%08d", ret); dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin, DBUS_TYPE_INVALID); } diff --git a/wpa_supplicant/ctrl_iface_dbus_new.c b/wpa_supplicant/ctrl_iface_dbus_new.c new file mode 100644 index 000000000..aea0ce76e --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new.c @@ -0,0 +1,2000 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa + * + * 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. + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "drivers/driver.h" +#include "wps/wps.h" +#include "ctrl_iface_dbus_new_helpers.h" +#include "dbus_dict_helpers.h" +#include "ctrl_iface_dbus_new.h" +#include "ctrl_iface_dbus_new_handlers.h" + +/** + * wpas_dbus_set_path - Assign a dbus path to an interface + * @wpa_s: wpa_supplicant interface structure + * @path: dbus path to set on the interface + * Returns: 0 on succes, -1 on error + */ +static int wpas_dbus_set_path(struct wpa_supplicant *wpa_s, + const char *path) +{ + u32 len = os_strlen(path); + if (len >= WPAS_DBUS_OBJECT_PATH_MAX) + return -1; + if (wpa_s->dbus_new_path) + return -1; + wpa_s->dbus_new_path = os_strdup(path); + return 0; +} + + +/** + * wpas_dbus_signal_interface - Send a interface related event signal + * @wpa_s: %wpa_supplicant network interface data + * @sig_name: signal name - InterfaceAdded or InterfaceRemoved + * + * Notify listeners about event related with interface + */ +static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s, + const char *sig_name) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal; + const char *path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: " + "Interface doesn't have a dbus path. " + "Can't send signal."); + return; + } + _signal = dbus_message_new_signal(WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, sig_name); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: " + "enough memory to send scan results signal."); + return; + } + + if (dbus_message_append_args(_signal, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_interface[dbus]: " + "not enough memory to construct signal."); + } + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_interface_created - Send a interface created signal + * @wpa_s: %wpa_supplicant network interface data + * + * Notify listeners about creating new interface + */ +static void wpas_dbus_signal_interface_created(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_interface(wpa_s, "InterfaceCreated"); +} + + +/** + * wpas_dbus_signal_interface_removed - Send a interface removed signal + * @wpa_s: %wpa_supplicant network interface data + * + * Notify listeners about removing interface + */ +static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved"); + +} + + +/** + * wpas_dbus_signal_scan_done - send scan done signal + * @wpa_s: %wpa_supplicant network interface data + * @success: indicates if scanning succeed or failed + * + * Notify listeners about finishing a scan + */ +static void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, + int success) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal; + const char *path; + dbus_bool_t succ; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: " + "Interface doesn't have a dbus path. " + "Can't send signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE, + "ScanDone"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: " + "enough memory to send signal."); + return; + } + + succ = success ? TRUE : FALSE; + if (dbus_message_append_args(_signal, DBUS_TYPE_BOOLEAN, &succ, + DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_scan_done[dbus]: " + "not enough memory to construct signal."); + } + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_blob - Send a BSS related event signal + * @wpa_s: %wpa_supplicant network interface data + * @bss_obj_path: BSS object path + * @sig_name: signal name - BSSAdded or BSSRemoved + * + * Notify listeners about event related with BSS + */ +static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s, + const char *bss_obj_path, + const char *sig_name) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal; + const char *path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: " + "Interface doesn't have a dbus path. " + "Can't send signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: " + "enough memory to send signal."); + return; + } + + if (dbus_message_append_args(_signal, DBUS_TYPE_OBJECT_PATH, + &bss_obj_path, DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_bss[dbus]: " + "not enough memory to construct signal."); + } + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_bss_added - Send a BSS added signal + * @wpa_s: %wpa_supplicant network interface data + * @bss_obj_path: new BSS object path + * + * Notify listeners about adding new BSS + */ +static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s, + const char *bss_obj_path) +{ + wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded"); +} + + +/** + * wpas_dbus_signal_bss_removed - Send a BSS removed signal + * @wpa_s: %wpa_supplicant network interface data + * @bss_obj_path: BSS object path + * + * Notify listeners about removing BSS + */ +static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s, + const char *bss_obj_path) +{ + wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved"); +} + + +/** + * wpas_dbus_signal_blob - Send a blob related event signal + * @wpa_s: %wpa_supplicant network interface data + * @name: blob name + * @sig_name: signal name - BlobAdded or BlobRemoved + * + * Notify listeners about event related with blob + */ +static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s, + const char *name, const char *sig_name) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal; + const char *path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: " + "Interface doesn't have a dbus path. " + "Can't send signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: " + "enough memory to send signal."); + return; + } + + if (dbus_message_append_args(_signal, DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_blob[dbus]: " + "not enough memory to construct signal."); + } + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_blob_added - Send a blob added signal + * @wpa_s: %wpa_supplicant network interface data + * @name: blob name + * + * Notify listeners about adding a new blob + */ +static void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, + const char *name) +{ + wpas_dbus_signal_blob(wpa_s, name, "BlobAdded"); +} + + +/** + * wpas_dbus_signal_blob_removed - Send a blob removed signal + * @wpa_s: %wpa_supplicant network interface data + * @name: blob name + * + * Notify listeners about removing blob + */ +static void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, + const char *name) +{ + wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved"); +} + + +/** + * wpas_dbus_signal_network - Send a network related event signal + * @wpa_s: %wpa_supplicant network interface data + * @id: new network id + * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected + * + * Notify listeners about event related with configured network + */ +static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s, + int id, const char *sig_name) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal; + const char *path; + char *net_obj_path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: " + "Interface doesn't have a dbus path. " + "Can't send signal."); + return; + } + + net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (net_obj_path == NULL) + return; + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path, id); + + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: " + "enough memory to send signal."); + os_free(net_obj_path); + return; + } + + if (dbus_message_append_args(_signal, DBUS_TYPE_OBJECT_PATH, + &net_obj_path, DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_network[dbus]: " + "not enough memory to construct signal."); + } + + os_free(net_obj_path); + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_network_added - Send a network added signal + * @wpa_s: %wpa_supplicant network interface data + * @id: new network id + * + * Notify listeners about adding new network + */ +static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s, + int id) +{ + wpas_dbus_signal_network(wpa_s, id, "NetworkAdded"); +} + + +/** + * wpas_dbus_signal_network_added - Send a network removed signal + * @wpa_s: %wpa_supplicant network interface data + * @id: network id + * + * Notify listeners about removing a network + */ +static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s, + int id) +{ + wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved"); +} + + +/** + * wpas_dbus_signal_network_selected - Send a network selected signal + * @wpa_s: %wpa_supplicant network interface data + * @id: network id + * + * Notify listeners about selecting a network + */ +static void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, + int id) +{ + wpas_dbus_signal_network(wpa_s, id, "NetworkSelected"); +} + + +/** + * wpas_dbus_signal_state_changed - Send a state changed signal + * @wpa_s: %wpa_supplicant network interface data + * @new_state: new state wpa_supplicant is entering + * @old_state: old state wpa_supplicant is leaving + * + * Notify listeners that wpa_supplicant has changed state + */ +static void wpas_dbus_signal_state_changed(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusMessage *_signal = NULL; + const char *path; + char *new_state_str, *old_state_str; + char *tmp; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus_new_ctrl_iface; + if (iface == NULL) + return; + + /* Only send signal if state really changed */ + if (new_state == old_state) + return; + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + perror("wpas_dbus_signal_state_changed[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpas_dbus_signal_state_changed[dbus]: " + "interface didn't have a dbus path; can't send " + "signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_INTERFACE, + "StateChanged"); + if (_signal == NULL) { + perror("wpas_dbus_signal_state_changed[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, + "wpas_dbus_signal_state_changed[dbus]: " + "couldn't create dbus signal; likely out of " + "memory."); + return; + } + + new_state_str = os_strdup(wpa_supplicant_state_txt(new_state)); + old_state_str = os_strdup(wpa_supplicant_state_txt(old_state)); + if (new_state_str == NULL || old_state_str == NULL) { + perror("wpas_dbus_signal_state_changed[dbus]: " + "couldn't convert state strings"); + wpa_printf(MSG_ERROR, + "wpas_dbus_signal_state_changed[dbus]: " + "couldn't convert state strings."); + goto out; + } + + /* make state string lowercase to fit new DBus API convention */ + tmp = new_state_str; + while (*tmp) { + *tmp = tolower(*tmp); + tmp++; + } + tmp = old_state_str; + while (*tmp) { + *tmp = tolower(*tmp); + tmp++; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_STRING, &new_state_str, + DBUS_TYPE_STRING, &old_state_str, + DBUS_TYPE_INVALID)) { + perror("wpas_dbus_signal_state_changed[dbus]: " + "not enough memory to construct state change signal."); + wpa_printf(MSG_ERROR, + "wpas_dbus_signal_state_changed[dbus]: " + "not enough memory to construct state change " + "signal."); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); + os_free(new_state_str); + os_free(old_state_str); +} + + +/** + * wpas_dbus_signal_state_changed - Signals that Enabled property changed + * @wpa_s: %wpa_supplicant network interface data + * @ssid: configured network which Enabled property has changed + * + * Sends PropertyChanged signals containing new value of Enabled property + * for specified network + */ +static void wpas_dbus_signal_network_enabled_changed( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) +{ + + struct network_handler_args args = {wpa_s, ssid}; + + char path[WPAS_DBUS_OBJECT_PATH_MAX]; + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpas_dbus_get_path(wpa_s), ssid->id); + + wpa_dbus_signal_property_changed(wpa_s->global->dbus_new_ctrl_iface, + (WPADBusPropertyAccessor) + wpas_dbus_getter_enabled, &args, + path, WPAS_DBUS_NEW_IFACE_NETWORK, + "Enabled"); +} + + +#ifdef CONFIG_WPS + +/** + * wpas_dbus_signal_wps_event_success - Signals Success WPS event + * @wpa_s: %wpa_supplicant network interface data + * + * Sends Event dbus signal with name "success" and empty dict as arguments + */ +static void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s) +{ + + DBusMessage * _signal = NULL; + DBusMessageIter iter, dict_iter; + struct ctrl_iface_dbus_new_priv *iface; + char *key = "success"; + const char * path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (!path) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success" + "[dbus]: interface has no dbus path set"); + return; + } + + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS, + "Event"); + if (!_signal) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success" + "[dbus]: out of memory when creating a signal"); + return; + } + + dbus_message_iter_init_append(_signal, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || + !wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_success" + "[dbus]: out of memory"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); +out: + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event + * @wpa_s: %wpa_supplicant network interface data + * + * Sends Event dbus signal with name "fail" and dictionary containing + * "msg field with fail message number (int32) as arguments + */ +static void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail) +{ + + DBusMessage * _signal = NULL; + DBusMessageIter iter, dict_iter; + struct ctrl_iface_dbus_new_priv *iface; + char* key = "fail"; + const char * path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (!path) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: " + "interface has no dbus path set"); + return; + } + + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS, + "Event"); + if (!_signal) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: " + "out of memory when creating a signal"); + return; + } + + dbus_message_iter_init_append(_signal, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || + !wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_fail[dbus]: " + "out of memory"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); +out: + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event + * @wpa_s: %wpa_supplicant network interface data + * + * Sends Event dbus signal with name "m2d" and dictionary containing + * fields of wps_event_m2d structure. + */ +static void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d) +{ + + DBusMessage * _signal = NULL; + DBusMessageIter iter, dict_iter; + struct ctrl_iface_dbus_new_priv *iface; + char* key = "m2d"; + const char * path; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (!path) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: " + "interface has no dbus path set"); + return; + } + + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS, + "Event"); + if (!_signal) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: " + "out of memory when creating a signal"); + return; + } + + dbus_message_iter_init_append(_signal, &iter); + + if (!(dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) && + wpa_dbus_dict_open_write(&iter, &dict_iter) && + wpa_dbus_dict_append_uint16(&dict_iter, "config_methods", + m2d->config_methods) && + wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer", + (const char *) m2d->manufacturer, + m2d->manufacturer_len) && + wpa_dbus_dict_append_byte_array(&dict_iter, "model_name", + (const char *) m2d->model_name, + m2d->model_name_len) && + wpa_dbus_dict_append_byte_array(&dict_iter, "model_number", + (const char *) m2d->model_number, + m2d->model_number_len) && + wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number", + (const char *) + m2d->serial_number, + m2d->serial_number_len) && + wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name", + (const char *) m2d->dev_name, + m2d->dev_name_len) && + wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type", + (const char *) + m2d->primary_dev_type, 8) && + wpa_dbus_dict_append_uint16(&dict_iter, "config_error", + m2d->config_error) && + wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id", + m2d->dev_password_id) && + wpa_dbus_dict_close_write(&iter, &dict_iter))) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_event_m2d[dbus]: " + "out of memory"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); +out: + dbus_message_unref(_signal); +} + + +/** + * wpas_dbus_signal_wps_cred - Signals new credentials + * @wpa_s: %wpa_supplicant network interface data + * + * Sends signal with credentials in directory argument + */ +static void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ + DBusMessage *_signal = NULL; + DBusMessageIter iter, dict_iter; + struct ctrl_iface_dbus_new_priv *iface; + const char *path; + char *auth_type[6]; /* we have six possible authorization types */ + int at_num = 0; + char *encr_type[4]; /* we have four possible encryption types */ + int et_num = 0; + + iface = wpa_s->global->dbus_new_ctrl_iface; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpas_dbus_get_path(wpa_s); + if (!path) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_cred[dbus]: " + "interface has no dbus path set"); + return; + } + + _signal = dbus_message_new_signal(path, WPAS_DBUS_NEW_IFACE_WPS, + "Credentials"); + if (!_signal) { + wpa_printf(MSG_ERROR, "wpas_dbus_signal_wps_cred[dbus]: " + "out of memory when creating a signal"); + return; + } + + dbus_message_iter_init_append(_signal, &iter); + + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { + perror("wpas_dbus_signal_wps_cred[dbus]: out of memory " + "when opening a dictionary"); + goto nomem; + } + + if (cred->auth_type & WPS_AUTH_OPEN) + auth_type[at_num++] = "open"; + if (cred->auth_type & WPS_AUTH_WPAPSK) + auth_type[at_num++] = "wpa-psk"; + if (cred->auth_type & WPS_AUTH_SHARED) + auth_type[at_num++] = "shared"; + if (cred->auth_type & WPS_AUTH_WPA) + auth_type[at_num++] = "wpa-eap"; + if (cred->auth_type & WPS_AUTH_WPA2) + auth_type[at_num++] = "wpa2-eap"; + if (cred->auth_type & WPS_AUTH_WPA2PSK) + auth_type[at_num++] = + "wpa2-psk"; + + if (cred->encr_type & WPS_ENCR_NONE) + encr_type[et_num++] = "none"; + if (cred->encr_type & WPS_ENCR_WEP) + encr_type[et_num++] = "wep"; + if (cred->encr_type & WPS_ENCR_TKIP) + encr_type[et_num++] = "tkip"; + if (cred->encr_type & WPS_ENCR_AES) + encr_type[et_num++] = "aes"; + + if (wpa_s->current_ssid) { + if (!wpa_dbus_dict_append_byte_array( + &dict_iter, "BSSID", + (const char *) wpa_s->current_ssid->bssid, + ETH_ALEN)) { + perror("wpas_dbus_signal_wps_cred[dbus]: out of " + "memory when appending bssid to dictionary"); + goto nomem; + } + } + + if (!(wpa_dbus_dict_append_byte_array(&dict_iter, "SSID", + (const char *) cred->ssid, + cred->ssid_len) && + wpa_dbus_dict_append_string_array(&dict_iter, "AuthType", + (const char **) auth_type, + at_num) && + wpa_dbus_dict_append_string_array(&dict_iter, "EncrType", + (const char **) encr_type, + et_num) && + wpa_dbus_dict_append_byte_array(&dict_iter, "Key", + (const char *) cred->key, + cred->key_len) && + wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex", + cred->key_idx))) { + perror("wpas_dbus_signal_wps_cred[dbus]: out of memory " + "when appending to dictionary"); + goto nomem; + } + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { + perror("wpas_dbus_signal_wps_cred[dbus]: out of memory " + "when closing a dictionary"); + goto nomem; + } + + dbus_connection_send(iface->con, _signal, NULL); + +nomem: + dbus_message_unref(_signal); +} + +#endif /* CONFIG_WPS */ + + +/** + * wpas_dbus_signal_prop_changed - Signals change of property + * @wpa_s: %wpa_supplicant network interface data + * @property: indicates which property has changed + * + * Sends ProertyChanged signals with path, interface and arguments + * depending on which property has changed. + */ +static void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_prop property) +{ + WPADBusPropertyAccessor getter; + char *iface; + char *prop; + void *arg; + + switch (property) { + case WPAS_DBUS_PROP_AP_SCAN: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan; + arg = wpa_s; + iface = WPAS_DBUS_NEW_IFACE_INTERFACE; + prop = "ApScan"; + break; + case WPAS_DBUS_PROP_SCANNING: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning; + arg = wpa_s; + iface = WPAS_DBUS_NEW_IFACE_INTERFACE; + prop = "Scanning"; + break; + case WPAS_DBUS_PROP_CURRENT_BSS: + getter = (WPADBusPropertyAccessor) + wpas_dbus_getter_current_bss; + arg = wpa_s; + iface = WPAS_DBUS_NEW_IFACE_INTERFACE; + prop = "CurrentBSS"; + break; + case WPAS_DBUS_PROP_CURRENT_NETWORK: + getter = (WPADBusPropertyAccessor) + wpas_dbus_getter_current_network; + arg = wpa_s; + iface = WPAS_DBUS_NEW_IFACE_INTERFACE; + prop = "CurrentNetwork"; + break; + default: + wpa_printf(MSG_ERROR, "wpas_dbus_signal_prop_changed[dbus]: " + "Unknown Property enum value %d", property); + return; + } + + wpa_dbus_signal_property_changed(wpa_s->global->dbus_new_ctrl_iface, + getter, arg, + wpas_dbus_get_path(wpa_s), iface, + prop); +} + + +/** + * wpas_dbus_signal_debug_params_changed - Signals change of debug params + * @global: wpa_global structure + * + * Sends ProertyChanged signals informing that debug params has changed. + */ +static void wpas_dbus_signal_debug_params_changed(struct wpa_global *global) +{ + + wpa_dbus_signal_property_changed(global->dbus_new_ctrl_iface, + (WPADBusPropertyAccessor) + wpas_dbus_getter_debug_params, + global, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, + "DebugParams"); +} + + +/** + * wpas_dbus_ctrl_iface_init - Initialize dbus control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: Pointer to dbus_new_ctrl_iface date or %NULL on failure + * + * Initialize the dbus control interface for wpa_supplicantand and start + * receiving commands from external programs over the bus. + */ +static struct ctrl_iface_dbus_new_priv * wpas_dbus_ctrl_iface_init( + struct wpa_global *global) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + /* register methods */ + struct wpa_dbus_argument margs1[] = { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument margs2[] = { + { "path", "o", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument margs3[] = { + { "ifname", "s", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs1[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs2[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs3[] = { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + }; + + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create object description"); + return NULL; + } + + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "CreateInterface", + (WPADBusMethodHandler) + &wpas_dbus_handler_create_interface, + global, NULL, margs1)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus method %s" + "in interface %s", "CreateInterface", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "RemoveInterface", + (WPADBusMethodHandler) + &wpas_dbus_handler_remove_interface, + global, NULL, margs2)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus method %s" + "in interface %s", "RemoveInterface", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "GetInterface", + (WPADBusMethodHandler) + &wpas_dbus_handler_get_interface, + global, NULL, margs3)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus method %s" + "in interface %s", "global", + WPAS_DBUS_NEW_INTERFACE); + } + + /* register properties */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "DebugParams", "(ibb)", + (WPADBusPropertyAccessor) + &wpas_dbus_getter_debug_params, + (WPADBusPropertyAccessor) + &wpas_dbus_setter_debug_params, + global, NULL, RW)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "DebugParams", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "Interfaces", "ao", + (WPADBusPropertyAccessor) + &wpas_dbus_getter_interfaces, NULL, + global, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Interfaces", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "EapMethods", "as", + wpas_dbus_getter_eap_methods, NULL, + NULL, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "EapMethods", + WPAS_DBUS_NEW_INTERFACE); + } + + + /* register signals */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "InterfaceAdded", sargs1)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "InterfaceAdded", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "InterfaceRemoved", sargs2)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "InterfaceRemoved", + WPAS_DBUS_NEW_INTERFACE); + } + + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_INTERFACE, + "PropertiesChanged", sargs3)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "PropertiesChanged", + WPAS_DBUS_NEW_INTERFACE); + } + + ctrl_iface = wpa_dbus_ctrl_iface_init(global, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_SERVICE, + obj_desc); + + if (!ctrl_iface) + free_dbus_object_desc(obj_desc); + + return ctrl_iface; +} + + +/** + * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for + * wpa_supplicant + * @iface: Pointer to dbus private data from + * wpas_dbus_ctrl_iface_init() + * + * Deinitialize the dbus control interface that was initialized with + * wpas_dbus_ctrl_iface_init(). + */ +static void wpas_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_new_priv *iface) +{ + if (iface) { + dbus_connection_unregister_object_path(iface->con, + WPAS_DBUS_NEW_PATH); + wpa_dbus_ctrl_iface_deinit(iface); + } +} + + +/** + * wpas_dbus_register_network - Register a configured network with dbus + * @wpa_s: wpa_supplicant interface structure + * @ssid: network configuration data + * Returns: 0 on success, -1 on failure + * + * Registers network representing object with dbus + */ +static int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + + struct network_handler_args *arg1 = NULL; + struct network_handler_args *arg2 = NULL; + struct network_handler_args *arg3 = NULL; + + const char *path = wpas_dbus_get_path(wpa_s); + char *net_obj_path; + + struct wpa_dbus_argument sargs[] = { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + }; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_new_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (net_obj_path == NULL) + return -1; + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path, ssid->id); + + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create object description"); + goto err; + } + + /* allocate memory for handlers arguments */ + arg1 = os_zalloc(sizeof(struct network_handler_args)); + if (!arg1) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for method"); + goto err; + } + arg2 = os_zalloc(sizeof(struct network_handler_args)); + if (!arg2) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for method"); + goto err; + } + + arg1->wpa_s = wpa_s; + arg1->ssid = ssid; + arg2->wpa_s = wpa_s; + arg2->ssid = ssid; + + /* Enabled property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_NETWORK, + "Enabled", "b", + (WPADBusPropertyAccessor) + wpas_dbus_getter_enabled, + (WPADBusPropertyAccessor) + wpas_dbus_setter_enabled, + arg1, free, RW)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Enabled", + WPAS_DBUS_NEW_IFACE_NETWORK); + } + + /* Properties property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_NETWORK, + "Properties", "a{sv}", + (WPADBusPropertyAccessor) + wpas_dbus_getter_network_properties, + (WPADBusPropertyAccessor) + wpas_dbus_setter_network_properties, + arg2, free, RW)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Properties", + WPAS_DBUS_NEW_IFACE_NETWORK); + } + + /* PropertiesChanged signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_NETWORK, + "PropertiesChanged", sargs)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "PropertiesChanged", + WPAS_DBUS_NEW_IFACE_NETWORK); + } + + + if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path, + wpa_s->ifname, obj_desc)) + goto err; + + wpas_dbus_signal_network_added(wpa_s, ssid->id); + + os_free(net_obj_path); + return 0; + +err: + os_free(net_obj_path); + os_free(obj_desc); + os_free(arg1); + os_free(arg2); + os_free(arg3); + return -1; +} + + +/** + * wpas_dbus_unregister_network - Unregister a configured network from dbus + * @wpa_s: wpa_supplicant interface structure + * @nid: network id + * Returns: 0 on success, -1 on failure + * + * Unregisters network representing object from dbus + */ +static int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + const char *path = wpas_dbus_get_path(wpa_s); + char *net_obj_path; + int ret; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_new_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (net_obj_path == NULL) + return -1; + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path, nid); + + ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path); + + if (!ret) + wpas_dbus_signal_network_removed(wpa_s, nid); + + os_free(net_obj_path); + return ret; +} + + +/** + * wpas_dbus_register_bss - Register a scanned BSS with dbus + * @wpa_s: wpa_supplicant interface structure + * @bssid: scanned network bssid + * Returns: 0 on success, -1 on failure + * + * Registers BSS representing object with dbus + */ +static int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN]) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + const char *path = wpas_dbus_get_path(wpa_s); + char *bss_obj_path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_new_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (bss_obj_path == NULL) + return -1; + + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/" WPAS_DBUS_BSSID_FORMAT, + path, MAC2STR(bssid)); + + if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) { + wpa_printf(MSG_ERROR, + "Cannot unregister BSSID dbus object %s.", + bss_obj_path); + os_free(bss_obj_path); + return -1; + } + + wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path); + + os_free(bss_obj_path); + return 0; +} + + +static int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN]) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + const char *path = wpas_dbus_get_path(wpa_s); + char *bss_obj_path; + + struct bss_handler_args *arg = NULL; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_new_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (bss_obj_path == NULL) + return -1; + + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/" WPAS_DBUS_BSSID_FORMAT, + path, MAC2STR(bssid)); + + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create object description"); + goto err; + } + + arg = os_zalloc(sizeof(struct bss_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for handler"); + goto err; + } + arg->wpa_s = wpa_s; + os_memcpy(arg->bssid, bssid, ETH_ALEN); + + /* Properties property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_BSSID, + "Properties", "a{sv}", + (WPADBusPropertyAccessor) + wpas_dbus_getter_bss_properties, NULL, + arg, free, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Properties", + WPAS_DBUS_NEW_IFACE_BSSID); + } + + if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path, + wpa_s->ifname, obj_desc)) { + wpa_printf(MSG_ERROR, + "Cannot register BSSID dbus object %s.", + bss_obj_path); + goto err; + } + + wpas_dbus_signal_bss_added(wpa_s, bss_obj_path); + + os_free(bss_obj_path); + return 0; + +err: + os_free(bss_obj_path); + os_free(obj_desc); + os_free(arg); + return -1; +} + + +/** + * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus + * @wpa_s: wpa_supplicant interface structure + * @bssid: scanned network bssid + * Returns: 0 on success, -1 on failure + * + * Unregisters BSS representing object from dbus + */ +static int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) +{ + + struct wpa_dbus_object_desc *obj_desc = NULL; + char *path; + struct ctrl_iface_dbus_new_priv *ctrl_iface = + wpa_s->global->dbus_new_ctrl_iface; + int next; + + struct wpa_dbus_argument args1[] = { + { "args", "a{sv}", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument args3[] = { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument args4[] = { + { "path", "o", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument args5[] = { + { "path", "o", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument args6[] = { + { "name", "s", ARG_IN }, + { "data", "ay", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument args7[] = { + { "name", "s", ARG_IN }, + { "data", "ay", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument args8[] = { + { "name", "s", ARG_IN }, + END_ARGS + }; + struct wpa_dbus_argument sargs1[] = { + { "success", "b", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs2[] = { + { "newState", "s", ARG_OUT }, + { "oldState", "s", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs3[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs4[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs5[] = { + { "name", "s", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs6[] = { + { "name", "s", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs7[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs8[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs9[] = { + { "path", "o", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs10[] = { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + }; + +#ifdef CONFIG_WPS + struct wpa_dbus_argument args9[] = { + { "args", "a{sv}", ARG_IN }, + { "output", "a{sv}", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs11[] = { + { "name", "s", ARG_OUT }, + { "args", "a{sv}", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs12[] = { + { "credentials", "a{sv}", ARG_OUT }, + END_ARGS + }; + struct wpa_dbus_argument sargs13[] = { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + }; +#endif /* CONFIG_WPS */ + /* Do nothing if the control interface is not turned on */ + if (ctrl_iface == NULL) + return 0; + + /* Create and set the interface's object path */ + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) + return -1; + next = wpa_dbus_next_objid(ctrl_iface); + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + WPAS_DBUS_NEW_PATH_INTERFACES "/%u", + next); + if (wpas_dbus_set_path(wpa_s, path)) { + wpa_printf(MSG_DEBUG, + "Failed to set dbus path for interface %s", + wpa_s->ifname); + goto err; + } + + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create object description"); + goto err; + } + + /* Scan method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Scan", + (WPADBusMethodHandler) + &wpas_dbus_handler_scan, + wpa_s, NULL, args1)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "Scan", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Disconnect method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Disconnect", + (WPADBusMethodHandler) + &wpas_dbus_handler_disconnect, + wpa_s, NULL, NULL)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "Disconnect", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* AddNetwork method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "AddNetwork", + (WPADBusMethodHandler) + &wpas_dbus_handler_add_network, + wpa_s, NULL, args3)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "AddNetwork", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* RemoveNetwork method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "RemoveNetwork", + (WPADBusMethodHandler) + &wpas_dbus_handler_remove_network, + wpa_s, NULL, args4)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "RemoveNetwork", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* SelectNetwork method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "SelectNetwork", + (WPADBusMethodHandler) + &wpas_dbus_handler_select_network, + wpa_s, NULL, args5)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "SelectNetwork", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* AddBlob method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "AddBlob", + (WPADBusMethodHandler) + &wpas_dbus_handler_add_blob, + wpa_s, NULL, args6)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "AddBlob", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* GetBlob method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "GetBlob", + (WPADBusMethodHandler) + &wpas_dbus_handler_get_blob, + wpa_s, NULL, args7)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "GetBlob", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* RemoveBlob method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "RemoveBlob", + (WPADBusMethodHandler) + &wpas_dbus_handler_remove_blob, + wpa_s, NULL, args8)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "RemoveBlob", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Capabilities property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Capabilities", "a{sv}", + (WPADBusPropertyAccessor) + wpas_dbus_getter_capabilities, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Capabilities", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* State property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "State", "s", + (WPADBusPropertyAccessor) + wpas_dbus_getter_state, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "State", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Scanning property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Scanning", "b", + (WPADBusPropertyAccessor) + wpas_dbus_getter_scanning, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Scanning", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* ApScan property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "ApScan", "u", + (WPADBusPropertyAccessor) + wpas_dbus_getter_ap_scan, + (WPADBusPropertyAccessor) + wpas_dbus_setter_ap_scan, + wpa_s, NULL, RW)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "ApScan", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Ifname property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Ifname", "s", + (WPADBusPropertyAccessor) + wpas_dbus_getter_ifname, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Ifname", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Driver property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Driver", "s", + (WPADBusPropertyAccessor) + wpas_dbus_getter_driver, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Driver", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BridgeIfname property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BridgeIfname", "s", + (WPADBusPropertyAccessor) + wpas_dbus_getter_bridge_ifname, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "BridgeIfname", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* CurrentBSS property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "CurrentBSS", "o", + (WPADBusPropertyAccessor) + wpas_dbus_getter_current_bss, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "CurrentBSS", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* CurrentNetwork property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "CurrentNetwork", "o", + (WPADBusPropertyAccessor) + wpas_dbus_getter_current_network, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "CurrentNetwork", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Blobs property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Blobs", "a{say}", + (WPADBusPropertyAccessor) + wpas_dbus_getter_blobs, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Blobs", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BSSs property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BSSs", "ao", + (WPADBusPropertyAccessor) + wpas_dbus_getter_bsss, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "BSSs", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* Networks property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "Networks", "ao", + (WPADBusPropertyAccessor) + wpas_dbus_getter_networks, NULL, + wpa_s, NULL, R)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "Networks", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* ScanDone signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "ScanDone", sargs1)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "ScanDone", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* StateChanged signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "StateChanged", sargs2)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "StateChanged", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BSSAdded signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BSSAdded", sargs3)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "BSSAdded", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BSSRemoved signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BSSRemoved", sargs4)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "BSSRemoved", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BlobAdded signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BlobAdded", sargs5)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "BlobAdded", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* BlobRemoved signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "BlobRemoved", sargs6)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "BlobRemoved", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* NetworkAdded signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "NetworkAdded", sargs7)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "NetworkAdded", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* NetworkRemoved signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "NetworkRemoved", sargs8)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "NetworkRemoved", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* NetworkSelected signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "NetworkSelected", sargs9)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "NetworkSelected", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + + /* PropertiesChanged signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_INTERFACE, + "PropertiesChanged", sargs10)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "PropertiesChanged", + WPAS_DBUS_NEW_IFACE_INTERFACE); + } + +#ifdef CONFIG_WPS + /* Start method */ + if (wpa_dbus_method_register(obj_desc, WPAS_DBUS_NEW_IFACE_WPS, + "Start", + (WPADBusMethodHandler) + &wpas_dbus_handler_wps_start, + wpa_s, NULL, args9)) { + wpa_printf(MSG_DEBUG, + "Failed to register dbus method %s" + "in interface %s", "Start", + WPAS_DBUS_NEW_IFACE_WPS); + } + + /* ProcessCredentials property */ + if (wpa_dbus_property_register(obj_desc, WPAS_DBUS_NEW_IFACE_WPS, + "ProcessCredentials", "b", + (WPADBusPropertyAccessor) + wpas_dbus_getter_process_credentials, + (WPADBusPropertyAccessor) + wpas_dbus_setter_process_credentials, + wpa_s, NULL, RW)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus property %s" + "in interface %s", "ProcessCredentials", + WPAS_DBUS_NEW_IFACE_WPS); + } + + /* Event signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_WPS, + "Event", sargs11)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "Event", + WPAS_DBUS_NEW_IFACE_WPS); + } + + /* Credentials signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_WPS, + "Credentials", sargs12)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "Credentials", + WPAS_DBUS_NEW_IFACE_WPS); + } + + /* PropertiesChanged signal */ + if (wpa_dbus_signal_register(obj_desc, WPAS_DBUS_NEW_IFACE_WPS, + "PropertiesChanged", sargs13)) { + wpa_printf(MSG_ERROR, + "Failed to register dbus signal %s" + "in interface %s", "PropertiesChanged", + WPAS_DBUS_NEW_IFACE_WPS); + } +#endif /* CONFIG_WPS */ + + if (wpa_dbus_register_object_per_iface(ctrl_iface, path, wpa_s->ifname, + obj_desc)) + goto err; + + wpas_dbus_signal_interface_created(wpa_s); + + os_free(path); + return 0; + +err: + os_free(obj_desc); + os_free(path); + return -1; +} + + +static int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_new_priv *ctrl_iface; + struct wpa_ssid *ssid = wpa_s->conf->ssid; + size_t i; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_new_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + path = wpas_dbus_get_path(wpa_s); + + /* unregister all BSSs and networks from dbus */ + for (i = 0; i < wpa_s->scan_res->num; i++) { + wpas_dbus_unregister_bss(wpa_s, + wpa_s->scan_res->res[i]->bssid); + } + + while (ssid) { + wpas_dbus_unregister_network(wpa_s, ssid->id); + ssid = ssid->next; + } + + if (wpa_dbus_unregister_object_per_iface(ctrl_iface, path)) + return -1; + + wpas_dbus_signal_interface_removed(wpa_s); + + os_free(wpa_s->dbus_new_path); + wpa_s->dbus_new_path = NULL; + + return 0; +} + + +static struct wpas_dbus_callbacks callbacks = +{ + .dbus_ctrl_init = wpas_dbus_ctrl_iface_init, + .dbus_ctrl_deinit = wpas_dbus_ctrl_iface_deinit, + + .signal_interface_created = wpas_dbus_signal_interface_created, + .signal_interface_removed = wpas_dbus_signal_interface_removed, + + .register_interface = wpas_dbus_register_interface, + .unregister_interface = wpas_dbus_unregister_interface, + + .signal_scan_done = wpas_dbus_signal_scan_done, + + .signal_blob_added = wpas_dbus_signal_blob_added, + .signal_blob_removed = wpas_dbus_signal_blob_removed, + + .signal_network_selected = wpas_dbus_signal_network_selected, + + .signal_state_changed = wpas_dbus_signal_state_changed, + .register_network = wpas_dbus_register_network, + .unregister_network = wpas_dbus_unregister_network, + + .signal_network_enabled_changed = + wpas_dbus_signal_network_enabled_changed, + + .register_bss = wpas_dbus_register_bss, + .unregister_bss = wpas_dbus_unregister_bss, + + .signal_prop_changed = wpas_dbus_signal_prop_changed, + .signal_debug_params_changed = wpas_dbus_signal_debug_params_changed, + +#ifdef CONFIG_WPS + .signal_wps_event_success = wpas_dbus_signal_wps_event_success, + .signal_wps_event_fail = wpas_dbus_signal_wps_event_fail, + .signal_wps_event_m2d = wpas_dbus_signal_wps_event_m2d, + .signal_wps_credentials = wpas_dbus_signal_wps_cred, +#endif /* CONFIG_WPS */ +}; + + +struct wpas_dbus_callbacks * wpas_dbus_get_callbacks(void) +{ + return &callbacks; +} + + +/** + * wpas_dbus_get_path - Get an interface's dbus path + * @wpa_s: %wpa_supplicant interface structure + * Returns: Interface's dbus object path, or %NULL on error + */ +const char * wpas_dbus_get_path(struct wpa_supplicant *wpa_s) +{ + return wpa_s->dbus_new_path; +} diff --git a/wpa_supplicant/ctrl_iface_dbus_new.h b/wpa_supplicant/ctrl_iface_dbus_new.h new file mode 100644 index 000000000..5fe48eef9 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new.h @@ -0,0 +1,142 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa + * + * 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. + */ + +#ifndef CTRL_IFACE_DBUS_NEW_H +#define CTRL_IFACE_DBUS_NEW_H + +struct wpa_global; +struct wpa_supplicant; +struct wpa_ssid; +struct wps_event_m2d; +struct wps_event_fail; +struct wps_credential; + +enum wpas_dbus_prop { + WPAS_DBUS_PROP_AP_SCAN, + WPAS_DBUS_PROP_SCANNING, + WPAS_DBUS_PROP_CURRENT_BSS, + WPAS_DBUS_PROP_CURRENT_NETWORK, +}; + +struct wpas_dbus_callbacks { + struct ctrl_iface_dbus_new_priv * (*dbus_ctrl_init)( + struct wpa_global *global); + + void (*dbus_ctrl_deinit)(struct ctrl_iface_dbus_new_priv *iface); + + void (*signal_interface_created)(struct wpa_supplicant *wpa_s); + void (*signal_interface_removed)(struct wpa_supplicant *wpa_s); + + int (*register_interface)(struct wpa_supplicant *wpa_s); + int (*unregister_interface)(struct wpa_supplicant *wpa_s); + + void (*signal_scan_done)(struct wpa_supplicant *wpa_s, int success); + + void (*signal_blob_added)(struct wpa_supplicant *wpa_s, + const char *name); + void (*signal_blob_removed)(struct wpa_supplicant *wpa_s, + const char *name); + + void (*signal_network_selected)(struct wpa_supplicant *wpa_s, int id); + + void (*signal_state_changed)(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state); + + int (*register_network)(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + int (*unregister_network)(struct wpa_supplicant *wpa_s, + int nid); + + void (*signal_network_enabled_changed)(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + + int (*register_bss)(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN]); + int (*unregister_bss)(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN]); + + void (*signal_prop_changed)(struct wpa_supplicant *wpa_s, + enum wpas_dbus_prop property); + void (*signal_debug_params_changed)(struct wpa_global *global); + +#ifdef CONFIG_WPS + void (*signal_wps_event_success)(struct wpa_supplicant *wpa_s); + void (*signal_wps_event_fail)(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail); + void (*signal_wps_event_m2d)(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d); + void (*signal_wps_credentials)(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); +#endif /* CONFIG_WPS */ +}; + + +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + +#include + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 + +#define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1" +#define WPAS_DBUS_NEW_PATH "/fi/w1/wpa_supplicant1" +#define WPAS_DBUS_NEW_INTERFACE "fi.w1.wpa_supplicant1" + +#define WPAS_DBUS_NEW_PATH_INTERFACES WPAS_DBUS_NEW_PATH "/Interfaces" +#define WPAS_DBUS_NEW_IFACE_INTERFACE WPAS_DBUS_NEW_INTERFACE ".Interface" +#define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS" + +#define WPAS_DBUS_NEW_NETWORKS_PART "Networks" +#define WPAS_DBUS_NEW_IFACE_NETWORK WPAS_DBUS_NEW_IFACE_INTERFACE ".Network" + +#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" +#define WPAS_DBUS_NEW_IFACE_BSSID WPAS_DBUS_NEW_IFACE_INTERFACE ".BSS" + + +/* Errors */ +#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \ + WPAS_DBUS_NEW_INTERFACE ".UnknownError" +#define WPAS_DBUS_ERROR_INVALID_ARGS \ + WPAS_DBUS_NEW_INTERFACE ".InvalidArgs" + +#define WPAS_DBUS_ERROR_IFACE_EXISTS \ + WPAS_DBUS_NEW_INTERFACE ".InterfaceExists" +#define WPAS_DBUS_ERROR_IFACE_UNKNOWN \ + WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown" + +#define WPAS_DBUS_ERROR_NOT_CONNECTED \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".NotConnected" +#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".NetworkUnknown" + +#define WPAS_DBUS_ERROR_BLOB_EXISTS \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".BlobExists" +#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".BlobUnknown" + +#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" + +struct wpas_dbus_callbacks * wpas_dbus_get_callbacks(void); +const char * wpas_dbus_get_path(struct wpa_supplicant *wpa_s); + +#else /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +static inline struct wpas_dbus_callbacks * wpas_dbus_get_callbacks(void) +{ + return NULL; +} + +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant/ctrl_iface_dbus_new_handlers.c b/wpa_supplicant/ctrl_iface_dbus_new_handlers.c new file mode 100644 index 000000000..c1b0c63fb --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new_handlers.c @@ -0,0 +1,3312 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa + * + * 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. + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#include "ctrl_iface_dbus_new_helpers.h" +#include "ctrl_iface_dbus_new.h" +#include "ctrl_iface_dbus_new_handlers.h" +#include "notify.h" +#include "eap_peer/eap_methods.h" +#include "dbus_dict_helpers.h" +#include "ieee802_11_defs.h" +#include "wpas_glue.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wps_supplicant.h" + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + + +/** + * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts + * @path: The dbus object path + * @network: (out) the configured network this object path refers to, if any + * @bssid: (out) the scanned bssid this object path refers to, if any + * Returns: The object path of the network interface this path refers to + * + * For a given object path, decomposes the object path into object id, network, + * and BSSID parts, if those parts exist. + */ +static char * wpas_dbus_new_decompose_object_path(const char *path, + char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/"); + char *obj_path_only; + char *next_sep; + + /* Be a bit paranoid about path */ + if (!path || strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/", + dev_path_prefix_len)) + return NULL; + + /* Ensure there's something at the end of the path */ + if ((path + dev_path_prefix_len)[0] == '\0') + return NULL; + + obj_path_only = strdup(path); + if (obj_path_only == NULL) + return NULL; + + next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); + if (next_sep != NULL) { + const char *net_part = strstr(next_sep, + WPAS_DBUS_NEW_NETWORKS_PART "/"); + const char *bssid_part = strstr(next_sep, + WPAS_DBUS_NEW_BSSIDS_PART "/"); + + if (network && net_part) { + /* Deal with a request for a configured network */ + const char *net_name = net_part + + strlen(WPAS_DBUS_NEW_NETWORKS_PART "/"); + *network = NULL; + if (strlen(net_name)) + *network = strdup(net_name); + } else if (bssid && bssid_part) { + /* Deal with a request for a scanned BSSID */ + const char *bssid_name = bssid_part + + strlen(WPAS_DBUS_NEW_BSSIDS_PART "/"); + if (strlen(bssid_name)) + *bssid = strdup(bssid_name); + else + *bssid = NULL; + } + + /* Cut off interface object path before "/" */ + *next_sep = '\0'; + } + + return obj_path_only; +} + + +/** + * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message + * @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 + */ +static DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, + const char *arg) +{ + 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_invald_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 + */ +static DBusMessage * wpas_dbus_error_invald_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; +} + + +static void free_wpa_interface(struct wpa_interface *iface) +{ + os_free((char *) iface->driver); + os_free((char *) iface->driver_param); + os_free((char *) iface->confname); + os_free((char *) iface->bridge_ifname); +} + + +static const char *dont_quote[] = { + "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", + "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", + "bssid", NULL +}; + +static dbus_bool_t should_quote_opt(const char *key) +{ + int i = 0; + while (dont_quote[i] != NULL) { + if (strcmp(key, dont_quote[i]) == 0) + return FALSE; + i++; + } + return TRUE; +} + +static struct wpa_scan_res * find_scan_result(struct bss_handler_args *bss) +{ + struct wpa_scan_results *results = bss->wpa_s->scan_res; + size_t i; + for (i = 0; i < results->num; i++) { + if (!os_memcmp(results->res[i]->bssid, bss->bssid, ETH_ALEN)) { + return results->res[i]; + } + } + return NULL; +} + + +/** + * 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 (strcmp(wpa_s->dbus_new_path, path) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * set_network_properties - Set properties of a configured network + * @message: Pointer to incoming dbus message + * @ssid: wpa_ssid structure for a configured network + * @iter: DBus message iterator containing dictionary of network + * properties to set. + * Returns: NULL when succeed or DBus error on failure + * + * Sets network configuration with parameters given id DBus dictionary + */ +static DBusMessage * set_network_properties(DBusMessage *message, + struct wpa_ssid *ssid, DBusMessageIter *iter) +{ + + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessage *reply = NULL; + DBusMessageIter iter_dict; + + + if (!wpa_dbus_dict_open_read(iter, &iter_dict)) { + reply = wpas_dbus_error_invald_args(message, NULL); + goto out; + } + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + char *value = NULL; + size_t size = 50; + int ret; + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_error_invald_args(message, NULL); + goto out; + } + 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 = strlen(entry.str_value); + if (size <= 0) + goto error; + + size += 3; + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = snprintf(value, size, "\"%s\"", entry.str_value); + if (ret < 0 || (size_t)ret != (size - 1)) + goto error; + + } + else { + value = 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 = 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 = 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 ((strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + continue; + + error: + os_free(value); + reply = wpas_dbus_error_invald_args(message, entry.key); + wpa_dbus_dict_entry_clear(&entry); + break; + } + out: + return reply; +} + + +/** + * 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 "addInterface" 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) +{ + struct wpa_interface iface; + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + + os_memset(&iface, 0, sizeof(iface)); + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + goto error; + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "Driver") && + (entry.type == DBUS_TYPE_STRING)) { + iface.driver = strdup(entry.str_value); + if (iface.driver == NULL) + goto error; + } + else if (!strcmp(entry.key, "Ifname") && + (entry.type == DBUS_TYPE_STRING)) { + iface.ifname = strdup(entry.str_value); + if (iface.ifname == NULL) + goto error; + } + else if (!strcmp(entry.key, "BridgeIfname") && + (entry.type == DBUS_TYPE_STRING)) { + iface.bridge_ifname = strdup(entry.str_value); + if (iface.bridge_ifname == NULL) + goto error; + } + else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, iface.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; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpas_dbus_get_path(wpa_s); + 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."); + } + } + free_wpa_interface(&iface); + return reply; + +error: + free_wpa_interface(&iface); + return wpas_dbus_error_invald_args(message, NULL); +} + + +/** + * 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)) { + 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) { + reply = wpas_dbus_error_iface_unknown(message); + goto out; + } + + path = wpas_dbus_get_path(wpa_s); + if (path == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_handler_get_interface[dbus]: " + "interface has no dbus object path set"); + reply = wpas_dbus_error_unknown_error(message, "path not set"); + goto out; + } + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + perror("wpas_dbus_handler_get_interface[dbus]: out of memory " + "when creating reply"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + perror("wpas_dbus_handler_get_interface[dbus]: out of memory " + "when appending argument to reply"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_debug_params - Get the debug params + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: DBus message with struct containing debug params. + * + * Getter for "DebugParams" property. + */ +DBusMessage * wpas_dbus_getter_debug_params(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, struct_iter; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to initialize return message"); + 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_VARIANT, + "(ibb)", &variant_iter)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to open variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_STRUCT, + NULL, &struct_iter)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to open struct"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_INT32, + &wpa_debug_level)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to append value to struct"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_timestamp)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to append value to struct"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_show_keys)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to append value to struct"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&variant_iter, &struct_iter)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to close struct"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_debug_params[dbus] out of memory when " + "trying to close variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_setter_debugparams - Set the debug params + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: NULL indicating success or a dbus error message with more + * information + * + * Setter for "DebugParams" property. + */ +DBusMessage * wpas_dbus_setter_debug_params(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, struct_iter; + int debug_level; + dbus_bool_t debug_timestamp; + dbus_bool_t debug_show_keys; + + if (!dbus_message_iter_init(message, &iter)) { + perror("wpas_dbus_handler_add_blob[dbus] out of memory when " + "trying to initialize message iterator"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + + dbus_message_iter_recurse(&iter, &variant_iter); + + if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRUCT) { + reply = wpas_dbus_error_invald_args(message, + "Argument must by a structure"); + goto out; + } + + dbus_message_iter_recurse(&variant_iter, &struct_iter); + + + if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_INT32) { + reply = wpas_dbus_error_invald_args(message, + "First struct argument must by an INT32"); + goto out; + } + dbus_message_iter_get_basic(&struct_iter, &debug_level); + if (!dbus_message_iter_next(&struct_iter)) { + reply = wpas_dbus_error_invald_args(message, + "Not enough elements in struct"); + goto out; + } + + if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_BOOLEAN) { + reply = wpas_dbus_error_invald_args(message, + "Second struct argument must by a boolean"); + goto out; + } + dbus_message_iter_get_basic(&struct_iter, &debug_timestamp); + if (!dbus_message_iter_next(&struct_iter)) { + reply = wpas_dbus_error_invald_args(message, + "Not enough elements in struct"); + goto out; + } + + if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_BOOLEAN) { + reply = wpas_dbus_error_invald_args(message, + "Third struct argument must by an boolean"); + goto out; + } + dbus_message_iter_get_basic(&struct_iter, &debug_show_keys); + + if (wpa_supplicant_set_debug_params(global, debug_level, + debug_timestamp ? 1 : 0, debug_show_keys ? 1 : 0)) { + reply = wpas_dbus_error_invald_args(message, "Wrong debug level value"); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_interfaces - Request registered interfaces list + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object paths array containing registered interfaces + * objects paths or DBus error on failure + * + * Getter for "Interfaces" property. Handles requests + * by dbus clients to return list of registered interfaces objects + * paths + */ +DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, array_iter; + const char *path; + + struct wpa_supplicant *wpa_s; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to initialize return message"); + 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_VARIANT, + "ao", &variant_iter)) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to open variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + "o", &array_iter)) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to open array"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + path = wpas_dbus_get_path(wpa_s); + if (!dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_OBJECT_PATH, &path)) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to append interface path"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to close array"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_interfaces[dbus] out of memory " + "when trying to close variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_eap_methods - Request supported EAP methods list + * @message: Pointer to incoming dbus message + * @nothing: not used argument. may be NULL or anything else + * Returns: The object paths array containing supported EAP methods + * represented by strings or DBus error on failure + * + * Getter for "EapMethods" property. Handles requests + * by dbus clients to return list of strings with supported EAP methods + */ +DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, + void *nothing) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, array_iter; + char **eap_methods; + size_t num_items; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_eap_methods[dbus] out of memory " + "when trying to initialize return message"); + 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_VARIANT, + "as", &variant_iter)) { + perror("wpas_dbus_getter_eap_methods[dbus] out of memory " + "when trying to open variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + "s", &array_iter)) { + perror("wpas_dbus_getter_eap_methods[dbus] out of memory " + "when trying to open variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + eap_methods = eap_get_names_as_string_array(&num_items); + if (eap_methods) { + size_t i; + int err = 0; + for (i = 0; i < num_items; i++) { + if (!dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_STRING, &(eap_methods[i]))) + err = 1; + os_free(eap_methods[i]); + } + os_free(eap_methods); + + if (err) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_eap_methods[dbus] " + "out of memory when adding to array"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { + perror("wpas_dbus_getter_eap_methods[dbus] " + "out of memory when trying to close array"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_eap_methods[dbus] " + "out of memory when trying to close variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * 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, + array_iter, sub_array_iter; + char *key, *val, *type = NULL; + int len; + int freqs_num = 0; + int ssids_num = 0; + int ies_len = 0; + + struct wpa_driver_scan_params params; + + os_memset(¶ms, 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 (!strcmp(key, "Type")) { + + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Type must be a string"); + reply = wpas_dbus_error_invald_args(message, + "Wrong Type value type. String required"); + goto out; + } + + dbus_message_iter_get_basic(&variant_iter, &type); + + } + else if (!strcmp(key, "SSIDs")) { + + struct wpa_driver_scan_ssid *ssids = params.ssids; + + if (dbus_message_iter_get_arg_type(&variant_iter) != + 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_invald_args(message, + "Wrong SSIDs value type. " + "Array of arrays of bytes required"); + goto out; + } + + dbus_message_iter_recurse(&variant_iter, &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_invald_args(message, + "Wrong SSIDs value type. " + "Array of arrays of bytes required"); + goto out; + } + + 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]: " + "To many ssids specified on scan dbus call"); + reply = wpas_dbus_error_invald_args(message, + "To many ssids specified. " + "Specify at most four"); + goto out; + } + + 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; + } + + ssids[ssids_num].ssid = os_malloc(sizeof(u8) * len); + + if (! ssids[ssids_num].ssid) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. can't allocate memory for SSID"); + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + os_memcpy((void *) ssids[ssids_num].ssid, val, + sizeof(u8) * len); + ssids[ssids_num].ssid_len = len; + + dbus_message_iter_next(&array_iter); + ssids_num++;; + } + + params.num_ssids = ssids_num; + } + else if (!strcmp(key, "IEs")) { + u8 *ies = NULL; + + if (dbus_message_iter_get_arg_type(&variant_iter) != + 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_invald_args(message, + "Wrong IEs value type. " + "Array of arrays of bytes required"); + goto out; + } + + dbus_message_iter_recurse(&variant_iter, &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_invald_args(message, + "Wrong IEs value type. Array required"); + goto out; + } + + 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; + } + + ies = os_realloc(ies, ies_len+len); + + if (!ies) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. can't allocate memory for IE"); + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + os_memcpy(ies+ies_len, val, sizeof(u8) * len); + ies_len += len; + + dbus_message_iter_next(&array_iter); + } + + params.extra_ies = ies; + params.extra_ies_len = ies_len; + } + else if (!strcmp(key, "Channels")) { + int *freqs = NULL; + + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_ARRAY) { + + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channels must be an array of structs"); + reply = wpas_dbus_error_invald_args(message, + "Wrong Channels value type. " + "Array of structs required"); + goto out; + } + + dbus_message_iter_recurse(&variant_iter, &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_invald_args(message, + "Wrong Channels value type. " + "Array of structs required"); + goto out; + } + + 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_invald_args(message, + "Wrong Channel struct. Two UINT32s required"); + os_free(freqs); + goto out; + } + 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_invald_args(message, + "Wrong Channel struct. Two UINT32s required"); + os_free(freqs); + goto out; + } + + dbus_message_iter_get_basic(&sub_array_iter, &width); + + #define FREQS_ALLOC_CHUNK 32 + if (freqs_num % FREQS_ALLOC_CHUNK == 0) { + freqs = os_realloc(freqs, + sizeof(int) * (freqs_num + FREQS_ALLOC_CHUNK)); + } + if (!freqs) { + 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); + goto out; + } + + freqs[freqs_num] = freq; + + freqs_num++; + dbus_message_iter_next(&array_iter); + } + + freqs = os_realloc(freqs, sizeof(int) * (freqs_num + 1)); + if (!freqs) { + 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); + goto out; + } + freqs[freqs_num] = 0; + + params.freqs = freqs; + } + else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Unknown argument %s", key); + reply = wpas_dbus_error_invald_args(message, + "Wrong Channel struct. Two UINT32s required"); + 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_invald_args(message, key); + goto out; + } + + if (!strcmp(type, "passive")) { + if (ssids_num || ies_len) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "SSIDs or IEs specified for passive scan."); + reply = wpas_dbus_error_invald_args(message, + "You can specify only Channels in passive scan"); + goto out; + } + else if (freqs_num > 0) { + /* wildcard ssid */ + params.num_ssids++; + wpa_supplicant_trigger_scan(wpa_s, ¶ms); + } + else { + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + } + else if (!strcmp(type, "active")) { + wpa_supplicant_trigger_scan(wpa_s, ¶ms); + } + else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Unknown scan type: %s", type); + reply = wpas_dbus_error_invald_args(message, + "Wrong scan type"); + goto out; + } + +out: + 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_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + return NULL; + } + else { + 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 = NULL; + + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_handler_add_network[dbus]: out of " + "memory."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto err; + } + + 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); + + reply = set_network_properties(message, ssid, &iter); + if (reply) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:" + "control interface couldn't set network properties"); + goto err; + } + + /* Construct the object path for this network. */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpas_dbus_get_path(wpa_s), + ssid->id); + + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + perror("wpas_dbus_handler_add_network[dbus]: out of memory " + "when creating reply"); + 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)) { + perror("wpas_dbus_handler_add_network[dbus]: out of memory " + "when appending argument to reply"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto err; + } + + os_free(path); + return reply; + +err: + if (ssid) { + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + } + os_free(path); + return reply; +} + + +/** + * 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; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL); + if (iface == NULL || strcmp(iface, wpas_dbus_get_path(wpa_s)) != 0) { + reply = wpas_dbus_error_invald_args(message, op); + goto out; + } + + id = strtoul(net_id, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invald_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; + } + + wpas_notify_network_removed(wpa_s, ssid); + + 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; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + +out: + os_free(iface); + os_free(net_id); + return reply; +} + + +/** + * 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, &net_id, NULL); + if (iface == NULL || strcmp(iface, wpas_dbus_get_path(wpa_s)) != 0) { + reply = wpas_dbus_error_invald_args(message, op); + goto out; + } + + id = strtoul(net_id, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invald_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_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) { + perror("wpas_dbus_handler_add_blob[dbus] out of memory when " + "trying to allocate blob struct"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto err; + } + + blob->data = os_malloc(blob_len); + if (!blob->data) { + perror("wpas_dbus_handler_add_blob[dbus] out of memory when " + "trying to allocate 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 = strdup(blob_name); + if (!blob->name) { + perror("wpas_dbus_handler_add_blob[dbus] out of memory when " + "trying to copy 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) { + perror("wpas_dbus_handler_get_blob[dbus] out of memory when " + "trying to allocate return message"); + 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); + perror("wpas_dbus_handler_get_blob[dbus] out of memory when " + "trying to open array"); + 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); + perror("wpas_dbus_handler_get_blob[dbus] out of memory when " + "trying to append data to array"); + 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); + perror("wpas_dbus_handler_get_blob[dbus] out of memory when " + "trying to close array"); + 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; + +} + + + + +/** + * wpas_dbus_getter_capabilities - Return interface capabilities + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a dict of strings + * + * Getter for "Capabilities" property of an interface. + */ +DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_driver_capa capa; + int res; + DBusMessageIter iter, iter_dict; + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array, variant_iter; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) + goto nomem; + + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + 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, + 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; + } + + 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, + sizeof(args) / sizeof(char*))) + goto nomem; + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "tkip")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wep104")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wep40")) + goto nomem; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_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, + sizeof(args) / sizeof(char*))) + 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_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_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, + sizeof(args) / sizeof(char*))) + 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, + sizeof(args) / sizeof(char*))) + 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 */ + const char *scans[] = { "active", "passive", "ssid" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "Scan", scans, + sizeof(scans) / sizeof(char*))) + goto nomem; + + /***** Modes */ + const char *modes[] = { "infrastructure", "ad-hoc", "ap" }; + int n = sizeof(modes) / sizeof(char*); + if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP)) + n--; /* exclude ap mode if it is not supported by the driver */ + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "Modes", modes, n)) + 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 reply; + +nomem: + if (reply) { + dbus_message_unref(reply); + } + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); +} + + +/** + * wpas_dbus_getter_state - Get interface state + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a STRING representing the current + * interface state + * + * Getter for "State" property. + */ +DBusMessage * wpas_dbus_getter_state(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *str_state; + char *state_ls, *tmp; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (reply != NULL) { + + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "s", &variant_iter)) { + perror("wpas_dbus_getter_state[dbus] out of memory " + "when trying to open variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + + /* make state string lowercase to fit new DBus API convention */ + state_ls = tmp = strdup(str_state); + if (!tmp) { + perror("wpas_dbus_getter_state[dbus] out of memory " + "when trying read state"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + while (*tmp) { + *tmp = tolower(*tmp); + tmp++; + } + + if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, + &state_ls)) { + perror("wpas_dbus_getter_state[dbus] out of memory " + "when trying append state"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto err; + } + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_state[dbus] out of memory " + "when trying close variant"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto err; + } + err: + os_free(state_ls); + } +out: + return reply; +} + +/** + * wpas_dbus_new_iface_get_scanning - Get interface scanning state + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing whether the interface is scanning + * + * Getter for "scanning" property. + */ +DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "b", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_BOOLEAN, &scanning) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_scanning[dbus]: out of " + "memory to put scanning state into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_scanning[dbus]: out of " + "memory to return scanning state."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_ap_scan - Control roaming mode + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containong value of ap_scan variable + * + * Getter function for "ApScan" property. + */ +DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "u", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_UINT32, &ap_scan) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_ap_scan[dbus]: out of " + "memory to put scanning state into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_ap_scan[dbus]: out of " + "memory to return scanning state."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_setter_ap_scan - Control roaming mode + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "ApScan" property. + */ +DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + dbus_uint32_t ap_scan; + + if (!dbus_message_iter_init(message, &iter)) { + perror("wpas_dbus_getter_ap_scan[dbus]: out of " + "memory to return scanning state."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + /* omit first and second argument and get value from third*/ + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &variant_iter); + + if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_UINT32) { + reply = wpas_dbus_error_invald_args(message, "UINT32 required"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &ap_scan); + + if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { + reply = wpas_dbus_error_invald_args(message, + "ap_scan must equal 0, 1 or 2"); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_ifname - Get interface name + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a name of network interface + * associated with with wpa_s + * + * Getter for "Ifname" property. + */ +DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *ifname = NULL; + + ifname = wpa_s->ifname; + if (ifname == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_getter_ifname[dbus]: " + "wpa_s has no interface name set"");"); + return wpas_dbus_error_unknown_error(message, "ifname not set"); + } + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "s", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_STRING, &ifname) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_ifname[dbus]: out of " + "memory to put ifname into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_ifname[dbus]: out of " + "memory to return ifname state."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_driver - Get interface name + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a name of network interface + * driver associated with with wpa_s + * + * Getter for "Driver" property. + */ +DBusMessage * wpas_dbus_getter_driver(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *driver = NULL; + + if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " + "wpa_s has no driver set"");"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + driver = wpa_s->driver->name; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "s", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_STRING, &driver) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_driver[dbus]: out of " + "memory to put driver into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_driver[dbus]: out of " + "memory to return driver."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_current_bss - Get current bss object path + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a DBus object path to + * current BSS + * + * Getter for "CurrentBSS" property. + */ +DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *path = wpas_dbus_get_path(wpa_s); + char *bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + int is_bssid_known = 0; + + if (bss_obj_path == NULL) { + perror("wpas_dbus_getter_current_bss[dbus]: out of " + "memory to allocate result argument."); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + if (wpa_s->bssid && !is_zero_ether_addr(wpa_s->bssid)) { + size_t i; + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *res = wpa_s->scan_res->res[i]; + if (!os_memcmp(wpa_s->bssid, res->bssid, ETH_ALEN)) { + is_bssid_known = 1; + break; + } + } + } + + if (is_bssid_known) + snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/" WPAS_DBUS_BSSID_FORMAT, + path, MAC2STR(wpa_s->bssid)); + else + sprintf(bss_obj_path, "/"); + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "o", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_OBJECT_PATH, &bss_obj_path) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_current_bss[dbus]: out of " + "memory to put path into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_current_bss[dbus]: out of " + "memory when creating reply."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + os_free(bss_obj_path); + return reply; +} + + +/** + * wpas_dbus_getter_current_network - Get current network object path + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a DBus object path to + * current network + * + * Getter for "CurrentNetwork" property. + */ +DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *path = wpas_dbus_get_path(wpa_s); + char *net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + + if (net_obj_path == NULL) { + perror("wpas_dbus_getter_current_network[dbus]: out of " + "memory to allocate result argument."); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + if (wpa_s->current_ssid) + snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path, + wpa_s->current_ssid->id); + else + sprintf(net_obj_path, "/"); + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "o", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_OBJECT_PATH, &net_obj_path) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_current_network[dbus]: out of " + "memory to put path into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_current_network[dbus]: out of " + "memory when creating reply."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + os_free(net_obj_path); + return reply; +} + + +/** + * wpas_dbus_getter_bridge_ifname - Get interface name + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a name of bridge network + * interface associated with with wpa_s + * + * Getter for "BridgeIfname" property. + */ +DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + const char *bridge_ifname = NULL; + + bridge_ifname = wpa_s->bridge_ifname; + if (bridge_ifname == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: " + "wpa_s has no bridge interface name set"");"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "s", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_STRING, &bridge_ifname) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_bridge_ifname[dbus]: out of " + "memory to put bridge ifname into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_bridge_ifname[dbus]: out of " + "memory to return bridge ifname."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_bsss - Get array of BSSs objects + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing an array of all known BSS objects + * dbus paths + * + * Getter for "BSSs" property. + */ +DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, array_iter; + size_t i; + + /* Ensure we've actually got scan results to return */ + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bsss[dbus]: " + "An error occurred getting scan results."); + return wpas_dbus_error_unknown_error(message, NULL); + } + + /* Create and initialize the return message */ + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + perror("wpas_dbus_getter_bsss[dbus]: out of " + "memory to create return message."); + 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_VARIANT, + "ao", &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter)) { + perror("wpas_dbus_getter_bsss[dbus]: out of " + "memory to open container."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + /* Loop through scan results and append each result's object path */ + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *res = wpa_s->scan_res->res[i]; + char *path; + + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_getter_bsss[dbus]: out of " + "memory."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + /* Construct the object path for this BSS. Note that ':' + * is not a valid character in dbus object paths. + */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/" + WPAS_DBUS_BSSID_FORMAT, + wpas_dbus_get_path(wpa_s), + MAC2STR(res->bssid)); + dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_OBJECT_PATH, &path); + os_free(path); + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_bsss[dbus]: out of " + "memory to close container."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_networks - Get array of networks objects + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing an array of all configured + * networks dbus object paths. + * + * Getter for "Networks" property. + */ +DBusMessage * wpas_dbus_getter_networks(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, array_iter; + struct wpa_ssid *ssid; + + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: " + "An error occurred getting networks list."); + return wpas_dbus_error_unknown_error(message, NULL); + } + + /* Create and initialize the return message */ + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + perror("wpas_dbus_getter_networks[dbus]: out of " + "memory to create return message."); + 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_VARIANT, + "ao", &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter)) { + perror("wpas_dbus_getter_networks[dbus]: out of " + "memory to open container."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + /* Loop through configured networks and append object path if each */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + char *path; + + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_getter_networks[dbus]: out of " + "memory."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + /* Construct the object path for this network. */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpas_dbus_get_path(wpa_s), ssid->id); + dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_OBJECT_PATH, &path); + os_free(path); + } + + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_networks[dbus]: out of " + "memory to close container."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_blobs - Get all blobs defined for this interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a dictionary of pairs (blob_name, blob) + * + * Getter for "Blobs" property. + */ +DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter; + struct wpa_config_blob *blob; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to initialize return message"); + 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_VARIANT, + "a{say}", &variant_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to open variant"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + "{say}", &dict_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to open dictionary"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + blob = wpa_s->conf->blobs; + while (blob) { + if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to open entry"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING, + &(blob->name))) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to append blob name"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_open_container(&entry_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to open array"); + 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); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to append blob data"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&entry_iter, &array_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to close array"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&dict_iter, &entry_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to close entry"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + blob = blob->next; + } + + if (!dbus_message_iter_close_container(&variant_iter, &dict_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to close dictionary"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to close variant"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_bss_properties - Return the properties of a scanned bss + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss' bssid + * Returns: a dbus message containing the properties for the requested bss + * + * Getter for "Properties" property. + */ +DBusMessage * wpas_dbus_getter_bss_properties(DBusMessage *message, + struct bss_handler_args *bss) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, iter_dict, variant_iter; + const u8 *ie; + + struct wpa_scan_res *res = find_scan_result(bss); + + if (res == NULL) { + return NULL; + } + + /* Dump the properties into a dbus message */ + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (!reply) + goto error; + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto error; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto error; + + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "BSSID", + (const char *) res->bssid, + ETH_ALEN)) + goto error; + + ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "SSID", + (const char *) (ie + 2), + ie[1])) + goto error; + } + + ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "WPAIE", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + ie = wpa_scan_get_ie(res, WLAN_EID_RSN); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "RSNIE", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "WPSIE", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + if (res->freq) { + if (!wpa_dbus_dict_append_int32(&iter_dict, "Frequency", + res->freq)) + goto error; + } + if (!wpa_dbus_dict_append_uint16(&iter_dict, "Capabilities", + res->caps)) + goto error; + if (!(res->flags & WPA_SCAN_QUAL_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "Quality", res->qual)) + goto error; + if (!(res->flags & WPA_SCAN_NOISE_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "Noise", res->noise)) + goto error; + if (!(res->flags & WPA_SCAN_LEVEL_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "Level", res->level)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxRate", + wpa_scan_get_max_rate(res) * 500000)) + goto error; + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto error; + + return reply; + +error: + if (reply) + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); +} + + +/** + * wpas_dbus_getter_enabled - Check whether network is enabled or disabled + * @message: Pointer to incoming dbus message + * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface + * and wpa_ssid structure for a configured network + * Returns: DBus message with boolean indicating state of configured network + * or DBus error on failure + * + * Getter for "enabled" property of a configured network. + */ +DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message, + struct network_handler_args *net) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + + dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_enabled[dbus] out of memory when " + "trying to initialize return message"); + 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_VARIANT, + "b", &variant_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_enabled[dbus] out of memory when " + "trying to open variant"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_BOOLEAN, &enabled)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_enabled[dbus] out of memory when " + "trying to append value"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + dbus_message_unref(reply); + perror("wpas_dbus_getter_blobs[dbus] out of memory when " + "trying to close variant"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled + * @message: Pointer to incoming dbus message + * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface + * and wpa_ssid structure for a configured network + * Returns: NULL indicating success or DBus error on failure + * + * Setter for "Enabled" property of a configured network. + */ +DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message, + struct network_handler_args *net) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + + struct wpa_supplicant *wpa_s; + struct wpa_ssid *ssid; + + dbus_bool_t enable; + + if (!dbus_message_iter_init(message, &iter)) { + perror("wpas_dbus_setter_enabled[dbus] out of memory when " + "trying to init iterator"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + + dbus_message_iter_recurse(&iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_BOOLEAN) { + perror("wpas_dbus_setter_enabled[dbus] " + "variant content should be boolean"); + reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "value should be a boolean"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &enable); + + 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); + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_network_properties - Get options for a configured network + * @message: Pointer to incoming dbus message + * @net: wpa_supplicant structure for a network interface and + * wpa_ssid structure for a configured network + * Returns: DBus message with network properties or DBus error on failure + * + * Getter for "Properties" property of a configured network. + */ +DBusMessage * wpas_dbus_getter_network_properties(DBusMessage *message, + struct network_handler_args *net) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, dict_iter; + + char **iterator; + +#if 0 + /* FIX: decide what to do with wpa_config_get_all */ + char** props = wpa_config_get_all(net->ssid, 0); +#else + char **props = NULL; +#endif + if (!props) { + perror("wpas_dbus_getter_network_properties[dbus] couldn't " + "read network properties. out of memory."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to initialize return message"); + 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_VARIANT, + "a{sv}", &variant_iter)) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to open variant container"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to open dict"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + iterator = props; + while (*iterator) { + if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, + *(iterator+1))) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to add entry"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + iterator += 2; + } + + + if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter)) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to close dictionary"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&iter, &variant_iter)) { + perror("wpas_dbus_getter_network_properties[dbus] out of " + "memory when trying to close variant container"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + iterator = props; + while (*iterator) { + os_free(*iterator); + iterator++; + } + os_free(props); + return reply; +} + + +/** + * wpas_dbus_setter_network_properties - Set options for a configured network + * @message: Pointer to incoming dbus message + * @net: wpa_supplicant structure for a network interface and + * wpa_ssid structure for a configured network + * Returns: NULL indicating success or DBus error on failure + * + * Setter for "Properties" property of a configured network. + */ +DBusMessage * wpas_dbus_setter_network_properties(DBusMessage *message, + struct network_handler_args *net) +{ + struct wpa_ssid *ssid = net->ssid; + + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + + dbus_message_iter_init(message, &iter); + + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + + dbus_message_iter_recurse(&iter, &variant_iter); + + reply = set_network_properties(message, ssid, &variant_iter); + + if (reply) + wpa_printf(MSG_DEBUG, "dbus control interface couldn't set " + "network properties"); + + return reply; +} + + +#ifdef CONFIG_WPS +/** + * wpas_dbus_handler_wps_start - Start WPS configuration + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: DBus message dictionary on success or DBus error on failure + * + * Handler for "Start" method call. DBus dictionary argument contains + * information about role (enrollee or registrar), authorization method + * (pin or push button) and optionally pin and bssid. Returned message + * has a dictionary argument which may contain newly generated pin (optional). + */ +DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage * reply = NULL; + DBusMessageIter iter, dict_iter, entry_iter, variant_iter, array_iter; + + char *key, *val; + + int role = 0; /* 0 - not set, 1 - enrollee, 2 - registrar */ + int type = 0; /* 0 - not set, 1 - pin, 2 - pbc */ + u8 *bssid = NULL; + char *pin = NULL, npin[9] = { '\0' }; + int len, ret; + + 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); + + if (strcmp(key, "Role") == 0) { + dbus_message_iter_recurse(&entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wrong Role type. string required"); + reply = wpas_dbus_error_invald_args(message, + "Role must be a string"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &val); + if (strcmp(val, "enrollee") == 0) + role = 1; + else if (strcmp(val, "registrar") == 0) + role = 2; + else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "unknown role %s", val); + reply = wpas_dbus_error_invald_args(message, val); + goto out; + } + } + else if (strcmp(key, "Type") == 0) { + dbus_message_iter_recurse(&entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wrong Type type. string required"); + reply = wpas_dbus_error_invald_args(message, + "Type must be a string"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &val); + if (strcmp(val, "pin") == 0) + type = 1; + else if (strcmp(val, "pbc") == 0) + type = 2; + else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "unknown type %s", val); + reply = wpas_dbus_error_invald_args(message, val); + goto out; + } + } + else if (strcmp(key, "Bssid") == 0) { + dbus_message_iter_recurse(&entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&variant_iter) != + DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wrong Bssid type. byte array required"); + reply = wpas_dbus_error_invald_args(message, + "Bssid must be a byte array"); + goto out; + } + dbus_message_iter_recurse(&variant_iter, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, &bssid, &len); + if (len != ETH_ALEN) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wrong Bssid length %d", len); + reply = wpas_dbus_error_invald_args(message, + "Bssid is wrong length"); + goto out; + } + } + else if (strcmp(key, "Pin") == 0) { + dbus_message_iter_recurse(&entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wrong Pin type. string required"); + reply = wpas_dbus_error_invald_args(message, + "Pin must be a string"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &pin); + } + else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "unknown key %s", key); + reply = wpas_dbus_error_invald_args(message, key); + goto out; + } + + dbus_message_iter_next(&dict_iter); + } + + if (role == 0) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "Role not specified"); + reply = wpas_dbus_error_invald_args(message, "Role not specified"); + goto out; + } + else if (role == 1 && type == 0) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "Type not specified"); + reply = wpas_dbus_error_invald_args(message, "Type not specified"); + goto out; + } + else if (role == 2 && pin == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "Pin required for registrar role."); + reply = wpas_dbus_error_invald_args(message, + "Pin required for registrar role."); + goto out; + } + + if (role == 2) { + ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL); + } + else if (type == 1) { + ret = wpas_wps_start_pin(wpa_s, bssid, pin); + if (ret>0) + sprintf(npin, "%08d", ret); + } + else { + ret = wpas_wps_start_pbc(wpa_s, bssid); + } + + if (ret<0) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_wps_start[dbus]: " + "wpas_wps_failed in role %s and key %s.", + (role == 1 ? "enrollee" : "registrar"), + (type == 0 ? "" : (type == 1 ? "pin" : "pbc"))); + reply = wpas_dbus_error_unknown_error(message, "wps start failed"); + goto out; + } + + reply = dbus_message_new_method_return(message); + if (!reply) { + perror("wpas_dbus_handler_wps_start[dbus]: out of memory " + "when creating reply"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { + perror("wpas_dbus_handler_wps_start[dbus]: out of memory " + "when opening dictionary"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (strlen(npin) > 0) { + if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) { + perror("wpas_dbus_handler_wps_start[dbus]: out of memory " + "when appending pin"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + } + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { + perror("wpas_dbus_handler_wps_start[dbus]: out of memory " + "when closing dictionary"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_dbus_getter_process_credentials - Check if credentials are processed + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: DBus message with a boolean on success or DBus error on failure + * + * Getter for "ProcessCredentials" property. Returns returned boolean will be + * true if wps_cred_processing configuration field is not equal to 1 or false + * if otherwise. + */ +DBusMessage * wpas_dbus_getter_process_credentials(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "b", &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, + DBUS_TYPE_BOOLEAN, &process) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + + perror("wpas_dbus_getter_process_credentials[dbus]: out of " + "memory to put value into message."); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + } else { + perror("wpas_dbus_getter_process_credentials[dbus]: out of " + "memory to create reply message."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + } + + return reply; +} + + +/** + * wpas_dbus_setter_process_credentials - Set credentials_processed conf param + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: NULL on success or DBus error on failure + * + * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 + * if boolean argument is true or on 1 if otherwise. + */ +DBusMessage * wpas_dbus_setter_process_credentials(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + dbus_bool_t process_credentials, old_pc; + + if (!dbus_message_iter_init(message, &iter)) { + perror("wpas_dbus_getter_ap_scan[dbus]: out of " + "memory to return scanning state."); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + /* omit first and second argument and get value from third*/ + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &variant_iter); + + if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_BOOLEAN) { + reply = wpas_dbus_error_invald_args(message, "BOOLEAN required"); + goto out; + } + dbus_message_iter_get_basic(&variant_iter, &process_credentials); + + old_pc = (wpa_s->conf->wps_cred_processing != 1); + wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1); + + if ((wpa_s->conf->wps_cred_processing != 1) != old_pc) + wpa_dbus_signal_property_changed(wpa_s->global->dbus_new_ctrl_iface, + (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials, + wpa_s, wpas_dbus_get_path(wpa_s), WPAS_DBUS_NEW_IFACE_WPS, + "ProcessCredentials"); + +out: + return reply; +} +#endif /* CONFIG_WPS */ diff --git a/wpa_supplicant/ctrl_iface_dbus_new_handlers.h b/wpa_supplicant/ctrl_iface_dbus_new_handlers.h new file mode 100644 index 000000000..01f96dcd7 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new_handlers.h @@ -0,0 +1,142 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * + * 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. + */ + +#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H +#define CTRL_IFACE_DBUS_NEW_HANDLERS_H + +struct network_handler_args { + struct wpa_supplicant *wpa_s; + struct wpa_ssid *ssid; +}; + +struct bss_handler_args { + struct wpa_supplicant *wpa_s; + u8 bssid[ETH_ALEN]; +}; + +DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_getter_debug_params(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_setter_debug_params(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, + void *nothing); + +DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_state(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_driver(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_networks(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message, + struct wpa_supplicant *bss); + +DBusMessage * wpas_dbus_getter_bss_properties(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message, + struct network_handler_args *net); + +DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message, + struct network_handler_args *net); + +DBusMessage * wpas_dbus_getter_network_properties( + DBusMessage *message, struct network_handler_args *net); + +DBusMessage * wpas_dbus_setter_network_properties( + DBusMessage *message, struct network_handler_args *net); + + +#ifdef CONFIG_WPS +DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_process_credentials( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_process_credentials( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_credentials(DBusMessage *message, + struct wpa_supplicant *wpa_s); +#endif /* CONFIG_WPS */ + +#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */ diff --git a/wpa_supplicant/ctrl_iface_dbus_new_helpers.c b/wpa_supplicant/ctrl_iface_dbus_new_helpers.c new file mode 100644 index 000000000..9c5e28b67 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new_helpers.c @@ -0,0 +1,1900 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa + * + * 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. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "ctrl_iface_dbus_new_helpers.h" + +/** + * struct wpa_dbus_method_desc - DBus method description + */ +struct wpa_dbus_method_desc { + /* pointer to next description in list */ + struct wpa_dbus_method_desc *next; + + /* method interface */ + char *dbus_interface; + /* method name */ + char *dbus_method; + + /* method handling function */ + WPADBusMethodHandler method_handler; + /* handler function argument */ + void *handler_argument; + /* function used to free handler argument */ + WPADBusArgumentFreeFunction argument_free_func; + + /* number of method arguments */ + int args_num; + /* array of arguments */ + struct wpa_dbus_argument args[]; +}; + + +/** + * struct wpa_dbus_signal_desc - DBus signal description + */ +struct wpa_dbus_signal_desc { + /* pointer to next description in list */ + struct wpa_dbus_signal_desc *next; + + /* signal interface */ + char *dbus_interface; + /* signal name */ + char *dbus_signal; + + /* number of signal arguments */ + int args_num; + /* array of arguments */ + struct wpa_dbus_argument args[0]; +}; + + +/** + * struct wpa_dbus_property_desc - DBus property description + */ +struct wpa_dbus_property_desc { + /* pointer to next description in list */ + struct wpa_dbus_property_desc *next; + + /* property interface */ + char *dbus_interface; + /* property name */ + char *dbus_property; + /* property type signature in DBus type notation */ + char *type; + + /* property access permissions */ + enum dbus_prop_access access; + + /* property getter function */ + WPADBusPropertyAccessor getter; + /* property setter function */ + WPADBusPropertyAccessor setter; + /* argument for getter and setter functions */ + void *user_data; + /* function used to free accessors argument */ + WPADBusArgumentFreeFunction user_data_free_func; +}; + + +#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO +#include + +struct interfaces { + struct interfaces *next; + char *dbus_interface; + xmlNodePtr interface_node; +}; +#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */ + +static void process_watch(struct ctrl_iface_dbus_new_priv *iface, + DBusWatch *watch, eloop_event_type type) +{ + dbus_connection_ref(iface->con); + + iface->should_dispatch = 0; + + if (type == EVENT_TYPE_READ) + dbus_watch_handle(watch, DBUS_WATCH_READABLE); + else if (type == EVENT_TYPE_WRITE) + dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); + else if (type == EVENT_TYPE_EXCEPTION) + dbus_watch_handle(watch, DBUS_WATCH_ERROR); + + if (iface->should_dispatch) { + while (dbus_connection_get_dispatch_status(iface->con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(iface->con); + iface->should_dispatch = 0; + } + + dbus_connection_unref(iface->con); +} + + +static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); +} + + +static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); +} + + +static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); +} + + +static void connection_setup_add_watch(struct ctrl_iface_dbus_new_priv *iface, + DBusWatch *watch) +{ + unsigned int flags; + int fd; + + if (!dbus_watch_get_enabled(watch)) + return; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_unix_fd(watch); + + eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, + iface, watch); + + if (flags & DBUS_WATCH_READABLE) { + eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, + iface, watch); + } + if (flags & DBUS_WATCH_WRITABLE) { + eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, + iface, watch); + } + + dbus_watch_set_data(watch, iface, NULL); +} + + +static void connection_setup_remove_watch( + struct ctrl_iface_dbus_new_priv *iface, DBusWatch *watch) +{ + unsigned int flags; + int fd; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_unix_fd(watch); + + eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); + + if (flags & DBUS_WATCH_READABLE) + eloop_unregister_sock(fd, EVENT_TYPE_READ); + if (flags & DBUS_WATCH_WRITABLE) + eloop_unregister_sock(fd, EVENT_TYPE_WRITE); + + dbus_watch_set_data(watch, NULL, NULL); +} + + +static dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + connection_setup_add_watch(data, watch); + return TRUE; +} + + +static void remove_watch(DBusWatch *watch, void *data) +{ + connection_setup_remove_watch(data, watch); +} + + +static void watch_toggled(DBusWatch *watch, void *data) +{ + if (dbus_watch_get_enabled(watch)) + add_watch(watch, data); + else + remove_watch(watch, data); +} + + +static void process_timeout(void *eloop_ctx, void *sock_ctx) +{ + DBusTimeout *timeout = sock_ctx; + + dbus_timeout_handle(timeout); +} + + +static void connection_setup_add_timeout( + struct ctrl_iface_dbus_new_priv *iface, DBusTimeout *timeout) +{ + if (!dbus_timeout_get_enabled(timeout)) + return; + + eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, + process_timeout, iface, timeout); + + dbus_timeout_set_data(timeout, iface, NULL); +} + + +static void connection_setup_remove_timeout( + struct ctrl_iface_dbus_new_priv *iface, DBusTimeout *timeout) +{ + eloop_cancel_timeout(process_timeout, iface, timeout); + dbus_timeout_set_data(timeout, NULL, NULL); +} + + +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + connection_setup_add_timeout(data, timeout); + + return TRUE; +} + + +static void remove_timeout(DBusTimeout *timeout, void *data) +{ + connection_setup_remove_timeout(data, timeout); +} + + +static void timeout_toggled(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) + add_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + + +static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx) +{ + struct ctrl_iface_dbus_new_priv *iface = signal_ctx; + + if (sig != SIGPOLL || !iface->con) + return; + + if (dbus_connection_get_dispatch_status(iface->con) != + DBUS_DISPATCH_DATA_REMAINS) + return; + + /* Only dispatch once - we do not want to starve other events */ + dbus_connection_ref(iface->con); + dbus_connection_dispatch(iface->con); + dbus_connection_unref(iface->con); +} + + +/** + * wakeup_main - Attempt to wake our mainloop up + * @data: dbus control interface private data + * + * Try to wake up the main eloop so it will process + * dbus events that may have happened. + */ +static void wakeup_main(void *data) +{ + struct ctrl_iface_dbus_new_priv *iface = data; + + /* Use SIGPOLL to break out of the eloop select() */ + raise(SIGPOLL); + iface->should_dispatch = 1; +} + + +/** + * connection_setup_wakeup_main - Tell dbus about our wakeup_main function + * @iface: dbus control interface private data + * Returns: 0 on success, -1 on failure + * + * Register our wakeup_main handler with dbus + */ +static int connection_setup_wakeup_main(struct ctrl_iface_dbus_new_priv *iface) +{ + if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) + return -1; + + dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, + iface, NULL); + + return 0; +} + + +/** + * wpa_dbus_next_objid - Return next available object id + * @iface: dbus control interface private data + * Returns: Object id + */ +u32 wpa_dbus_next_objid(struct ctrl_iface_dbus_new_priv *iface) +{ + return iface->next_objid++; +} + + +/** + * integrate_with_eloop - Register our mainloop integration with dbus + * @connection: connection to the system message bus + * @iface: a dbus control interface data structure + * Returns: 0 on success, -1 on failure + * + * We register our mainloop integration functions with dbus here. + */ +static int integrate_with_eloop(DBusConnection *connection, + struct ctrl_iface_dbus_new_priv *iface) +{ + if (!dbus_connection_set_watch_functions(connection, add_watch, + remove_watch, watch_toggled, + iface, NULL)) { + perror("dbus_connection_set_watch_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (!dbus_connection_set_timeout_functions(connection, add_timeout, + remove_timeout, + timeout_toggled, iface, + NULL)) { + perror("dbus_connection_set_timeout_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (connection_setup_wakeup_main(iface) < 0) { + perror("connection_setup_wakeup_main[dbus]"); + wpa_printf(MSG_ERROR, "Could not setup main wakeup function."); + return -1; + } + + return 0; +} + + +/** + * dispatch_initial_dbus_messages - Dispatch initial dbus messages after + * claiming bus name + * @eloop_ctx: the DBusConnection to dispatch on + * @timeout_ctx: unused + * + * If clients are quick to notice that service claimed its bus name, + * there may have been messages that came in before initialization was + * all finished. Dispatch those here. + */ +static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) +{ + DBusConnection *con = eloop_ctx; + + while (dbus_connection_get_dispatch_status(con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(con); +} + + +#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO + +/** + * extract_interfaces - Extract interfaces from methods, signals and props + * @obj_dsc: Description of object from which interfaces will be extracted + * @root_node: root node of XML introspection document + * Returns: List of interfaces found in object description + * + * Iterates over all methods, signals and properties registered with + * object and collects all declared DBus interfaces and create interface's + * node in XML root node for each. Returned list elements contains interface + * name and XML node of corresponding interface. + */ +static struct interfaces * extract_interfaces( + struct wpa_dbus_object_desc *obj_dsc, xmlNodePtr root_node) +{ + struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; + struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals; + struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties; + struct interfaces *head = NULL; + struct interfaces *iface, *last; + int len; + + /* extract interfaces from methods */ + while (method_dsc) { + iface = head; + last = NULL; + + /* go to next method if its interface is already extracted */ + while (iface) { + if (!os_strcmp(iface->dbus_interface, + method_dsc->dbus_interface)) + break; + last = iface; + iface = iface->next; + } + if (iface) { + method_dsc = method_dsc->next; + continue; + } + + iface = os_zalloc(sizeof(struct interfaces)); + if (!iface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data"); + method_dsc = method_dsc->next; + continue; + } + + if (last) + last->next = iface; + else + head = iface; + + len = os_strlen(method_dsc->dbus_interface) + 1; + iface->dbus_interface = os_malloc(len); + if (!iface->dbus_interface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data (interface " + "name)"); + method_dsc = method_dsc->next; + continue; + } + os_strncpy(iface->dbus_interface, method_dsc->dbus_interface, + len); + + iface->interface_node = xmlNewChild(root_node, NULL, + BAD_CAST "interface", + NULL); + xmlNewProp(iface->interface_node, BAD_CAST "name", + BAD_CAST method_dsc->dbus_interface); + + method_dsc = method_dsc->next; + } + + /* extract interfaces from signals */ + while (signal_dsc) { + iface = head; + last = NULL; + + /* go to next signal if its interface is already extracted */ + while (iface) { + if (!os_strcmp(iface->dbus_interface, + signal_dsc->dbus_interface)) + break; + last = iface; + iface = iface->next; + } + if (iface) { + signal_dsc = signal_dsc->next; + continue; + } + + iface = os_zalloc(sizeof(struct interfaces)); + if (!iface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data"); + signal_dsc = signal_dsc->next; + continue; + } + + if (last) + last->next = iface; + else + head = iface; + + len = os_strlen(signal_dsc->dbus_interface) + 1; + iface->dbus_interface = os_malloc(len); + if (!iface->dbus_interface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data (interface " + "name)"); + signal_dsc = signal_dsc->next; + continue; + } + os_strncpy(iface->dbus_interface, signal_dsc->dbus_interface, + len); + + iface->interface_node = xmlNewChild(root_node, NULL, + BAD_CAST "interface", + NULL); + xmlNewProp(iface->interface_node, BAD_CAST "name", + BAD_CAST signal_dsc->dbus_interface); + + signal_dsc = signal_dsc->next; + } + + /* extract interfaces from properties */ + while (property_dsc) { + iface = head; + last = NULL; + + /* go to next property if its interface is already extracted */ + while (iface) { + if (!os_strcmp(iface->dbus_interface, + property_dsc->dbus_interface)) + break; + last = iface; + iface = iface->next; + } + if (iface) { + property_dsc = property_dsc->next; + continue; + } + + iface = os_zalloc(sizeof(struct interfaces)); + if (!iface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data"); + property_dsc = property_dsc->next; + continue; + } + + if (last) + last->next = iface; + else + head = iface; + + len = os_strlen(property_dsc->dbus_interface) + 1; + iface->dbus_interface = os_malloc(len); + if (!iface->dbus_interface) { + wpa_printf(MSG_ERROR, "Not enough memory to create " + "interface introspection data (interface " + "name)"); + property_dsc = property_dsc->next; + continue; + } + os_strncpy(iface->dbus_interface, property_dsc->dbus_interface, + len); + + iface->interface_node = xmlNewChild(root_node, NULL, + BAD_CAST "interface", + NULL); + xmlNewProp(iface->interface_node, BAD_CAST "name", + BAD_CAST property_dsc->dbus_interface); + + property_dsc = property_dsc->next; + } + + return head; +} + + +/** + * introspect - Responds for Introspect calls on object + * @message: Message with Introspect call + * @obj_dsc: Object description on which Introspect was called + * Returns: Message with introspection result XML string as only argument + * + * Iterates over all methods, signals and properties registered with + * object and generates introspection data for the object as XML string. + */ +static DBusMessage * introspect(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc) +{ + + DBusMessage *reply = NULL; + struct interfaces *ifaces, *tmp; + struct wpa_dbus_signal_desc *signal_dsc; + struct wpa_dbus_method_desc *method_dsc; + struct wpa_dbus_property_desc *property_dsc; + char *intro_str; + char **children; + int i, s; + + xmlDocPtr doc = NULL; + xmlNodePtr root_node = NULL, node = NULL, iface_node = NULL; + xmlNodePtr method_node = NULL, signal_node = NULL; + xmlNodePtr property_node = NULL, arg_node = NULL; + + /* Create and initialize the return message */ + reply = dbus_message_new_method_return(message); + + /* root node and dtd */ + doc = xmlNewDoc(BAD_CAST "1.0"); + root_node = xmlNewNode(NULL, BAD_CAST "node"); + xmlDocSetRootElement(doc, root_node); + xmlCreateIntSubset(doc, BAD_CAST "node", + BAD_CAST DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER, + BAD_CAST DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER); + + /* Add Introspectable interface */ + iface_node = xmlNewChild(root_node, NULL, BAD_CAST "interface", NULL); + xmlNewProp(iface_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_INTROSPECTION_INTERFACE); + + /* Add Introspect method */ + method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL); + xmlNewProp(method_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_INTROSPECTION_METHOD); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "data"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out"); + + + /* Add Properties interface */ + iface_node = xmlNewChild(root_node, NULL, + BAD_CAST "interface", NULL); + xmlNewProp(iface_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_PROPERTIES_INTERFACE); + + /* Add Get method */ + method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL); + xmlNewProp(method_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_PROPERTIES_GET); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out"); + method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL); + + /* Add GetAll method */ + xmlNewProp(method_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_PROPERTIES_GETALL); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "props"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "a{sv}"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out"); + method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL); + + /* Add Set method */ + xmlNewProp(method_node, BAD_CAST "name", + BAD_CAST WPA_DBUS_PROPERTIES_SET); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL); + xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value"); + xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v"); + xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in"); + + /* get all interfaces registered with object */ + ifaces = extract_interfaces(obj_dsc, root_node); + + /* create methods' nodes */ + method_dsc = obj_dsc->methods; + while (method_dsc) { + + struct interfaces *iface = ifaces; + while (iface) { + if (!os_strcmp(iface->dbus_interface, + method_dsc->dbus_interface)) + break; + iface = iface->next; + } + if (!iface) + continue; + + iface_node = iface->interface_node; + method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", + NULL); + xmlNewProp(method_node, BAD_CAST "name", + BAD_CAST method_dsc->dbus_method); + + /* create args' nodes */ + for (i = 0; i < method_dsc->args_num; i++) { + struct wpa_dbus_argument arg = method_dsc->args[i]; + arg_node = xmlNewChild(method_node, NULL, + BAD_CAST "arg", NULL); + if (arg.name && strlen(arg.name)) { + xmlNewProp(arg_node, BAD_CAST "name", + BAD_CAST arg.name); + } + xmlNewProp(arg_node, BAD_CAST "type", + BAD_CAST arg.type); + xmlNewProp(arg_node, BAD_CAST "direction", + BAD_CAST (arg.dir == ARG_IN ? + "in" : "out")); + } + method_dsc = method_dsc->next; + } + + /* create signals' nodes */ + signal_dsc = obj_dsc->signals; + while (signal_dsc) { + + struct interfaces *iface = ifaces; + while (iface) { + if (!os_strcmp(iface->dbus_interface, + signal_dsc->dbus_interface)) + break; + iface = iface->next; + } + if (!iface) + continue; + + iface_node = iface->interface_node; + signal_node = xmlNewChild(iface_node, NULL, BAD_CAST "signal", + NULL); + xmlNewProp(signal_node, BAD_CAST "name", + BAD_CAST signal_dsc->dbus_signal); + + /* create args' nodes */ + for (i = 0; i < signal_dsc->args_num; i++) { + struct wpa_dbus_argument arg = signal_dsc->args[i]; + arg_node = xmlNewChild(signal_node, NULL, + BAD_CAST "arg", NULL); + if (arg.name && strlen(arg.name)) { + xmlNewProp(arg_node, BAD_CAST "name", + BAD_CAST arg.name); + } + xmlNewProp(arg_node, BAD_CAST "type", + BAD_CAST arg.type); + } + signal_dsc = signal_dsc->next; + } + + /* create properties' nodes */ + property_dsc = obj_dsc->properties; + while (property_dsc) { + + struct interfaces *iface = ifaces; + while (iface) { + if (!os_strcmp(iface->dbus_interface, + property_dsc->dbus_interface)) + break; + iface = iface->next; + } + if (!iface) + continue; + + iface_node = iface->interface_node; + property_node = xmlNewChild(iface_node, NULL, + BAD_CAST "property", NULL); + xmlNewProp(property_node, BAD_CAST "name", + BAD_CAST property_dsc->dbus_property); + xmlNewProp(property_node, BAD_CAST "type", + BAD_CAST property_dsc->type); + xmlNewProp(property_node, BAD_CAST "access", BAD_CAST + (property_dsc->access == R ? "read" : + (property_dsc->access == W ? + "write" : "readwrite"))); + + property_dsc = property_dsc->next; + } + + /* add child nodes to introspection tree; */ + dbus_connection_list_registered(obj_dsc->connection, + dbus_message_get_path(message), + &children); + for (i = 0; children[i]; i++) { + node = xmlNewChild(root_node, NULL, BAD_CAST "node", NULL); + xmlNewProp(node, BAD_CAST "name", BAD_CAST children[i]); + } + dbus_free_string_array(children); + + + xmlDocDumpFormatMemory(doc, (xmlChar **) &intro_str, &s, 1); + + xmlFreeDoc(doc); + + while (ifaces) { + tmp = ifaces; + ifaces = ifaces->next; + os_free(tmp->dbus_interface); + os_free(tmp); + } + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str, + DBUS_TYPE_INVALID); + + xmlFree(intro_str); + + return reply; +} + +#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */ + +/** + * introspect - Responds for Introspect calls on object + * @message: Message with Introspect call + * @obj_dsc: Object description on which Introspect was called + * Returns: Message with introspection result XML string as only argument + * + * Returns error informing that introspection support was not compiled. + */ +static DBusMessage * introspect(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc) +{ + return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, + "wpa_supplicant was compiled without " + "introspection support."); +} + +#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */ + + +/** + * recursive_iter_copy - Reads arguments from one iterator and + * writes to another recursively + * @from: iterator to read from + * @to: iterator to write to + * + * Copies one iterator's elements to another. If any element in + * iterator is of container type, its content is copied recursively + */ +static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to) +{ + + char *subtype = NULL; + int type; + + /* iterate over iterator to copy */ + while ((type = dbus_message_iter_get_arg_type (from)) != + DBUS_TYPE_INVALID) { + + /* simply copy basic type entries */ + if (dbus_type_is_basic(type)) { + if (dbus_type_is_fixed(type)) { + /* + * According to DBus documentation all + * fixed-length types are guaranteed to fit + * 8 bytes + */ + dbus_uint64_t v; + dbus_message_iter_get_basic (from, &v); + dbus_message_iter_append_basic (to, type, &v); + } else { + char *v; + dbus_message_iter_get_basic (from, &v); + dbus_message_iter_append_basic (to, type, &v); + } + } else { + /* recursively copy container type entries */ + DBusMessageIter write_subiter, read_subiter; + + dbus_message_iter_recurse(from, &read_subiter); + + if (type == DBUS_TYPE_VARIANT || + type == DBUS_TYPE_ARRAY) { + subtype = dbus_message_iter_get_signature( + &read_subiter); + } + + dbus_message_iter_open_container(to, type, subtype, + &write_subiter); + + recursive_iter_copy(&read_subiter, &write_subiter); + + dbus_message_iter_close_container(to, &write_subiter); + if (subtype) + dbus_free(subtype); + } + + dbus_message_iter_next(from); + } +} + + +/** + * get_all_properties - Responds for GetAll properties calls on object + * @message: Message with GetAll call + * @interface: interface name which properties will be returned + * @property_dsc: list of object's properties + * Returns: Message with dict of variants as argument with properties values + * + * Iterates over all properties registered with object and execute getters + * of those, which are readable and which interface matches interface + * specified as argument. Returned message contains one dict argument + * with properties names as keys and theirs values as values. + */ +static DBusMessage * get_all_properties( + DBusMessage *message, char *interface, + struct wpa_dbus_property_desc *property_dsc) +{ + /* Create and initialize the return message */ + DBusMessage *reply = dbus_message_new_method_return(message); + DBusMessage *getterReply = NULL; + DBusMessageIter iter, dict_iter, entry_iter, ret_iter; + int counter = 0; + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict_iter); + + while (property_dsc) { + if (!os_strncmp(property_dsc->dbus_interface, interface, + WPAS_DBUS_INTERFACE_MAX) && + property_dsc->access != W && property_dsc->getter) { + + getterReply = property_dsc->getter( + message, property_dsc->user_data); + dbus_message_iter_init(getterReply, &ret_iter); + + dbus_message_iter_open_container(&dict_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter); + dbus_message_iter_append_basic( + &entry_iter, DBUS_TYPE_STRING, + &(property_dsc->dbus_property)); + + recursive_iter_copy(&ret_iter, &entry_iter); + + dbus_message_iter_close_container(&dict_iter, + &entry_iter); + dbus_message_unref(getterReply); + counter++; + } + property_dsc = property_dsc->next; + } + dbus_message_iter_close_container(&iter, &dict_iter); + + if (counter == 0) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + "No readable properties in " + "this interface"); + } + + return reply; +} + + +static int is_signature_correct(DBusMessage * message, + struct wpa_dbus_method_desc *method_dsc) +{ + /* According to DBus documentation max length of signature is 255 */ + #define MAX_SIG_LEN 256 + + char registered_sig[MAX_SIG_LEN]; + const char *sig = dbus_message_get_signature(message); + int i; + + registered_sig[0] = 0; + + for (i = 0; i < method_dsc->args_num; i++) { + struct wpa_dbus_argument arg = method_dsc->args[i]; + if (arg.dir == ARG_IN) + strcat(registered_sig, arg.type); + } + + return !os_strncmp(registered_sig, sig, MAX_SIG_LEN); +} + + +/** + * message_handler - Handles incoming DBus messages + * @connection: DBus connection on which message was received + * @message: Received message + * @user_data: pointer to description of object to which message was sent + * Returns: Returns information whether message was handled or not + * + * Reads message interface and method name, then checks if they matches one + * of the special cases i.e. introspection call or properties get/getall/set + * methods and handles it. Else it iterates over registered methods list + * and tries to match method's name and interface to those read from message + * If appropriate method was found it's handler function is called and + * response is sent. Otherwise the DBUS_ERROR_UNKNOWN_METHOD error message + * will be sent. + */ +static DBusHandlerResult message_handler(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct wpa_dbus_object_desc *obj_dsc = user_data; + const char *method; + const char *path; + const char *msg_interface; + +#define MESSAGE_UNHANDLED (DBusMessage *) 1 + + DBusMessage *reply = MESSAGE_UNHANDLED; + + /* get method, interface and path the message is addressed to */ + method = dbus_message_get_member(message); + path = dbus_message_get_path(message); + msg_interface = dbus_message_get_interface(message); + if (!method || !path || !msg_interface) + goto out; + + /* if message is introspection method call */ + if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && + !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface, + WPAS_DBUS_INTERFACE_MAX)) + reply = introspect(message, obj_dsc); + else if (!strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface, + WPAS_DBUS_INTERFACE_MAX)) { + /* if message is properties method call */ + DBusMessageIter iter; + char *interface; + char *property; + + dbus_message_iter_init(message, &iter); + + if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || + !os_strncmp(WPA_DBUS_PROPERTIES_SET, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || + !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { + /* First argument: interface name (DBUS_TYPE_STRING) */ + if (dbus_message_iter_get_arg_type(&iter) != + DBUS_TYPE_STRING) { + reply = dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, + NULL); + goto out; + } + + dbus_message_iter_get_basic(&iter, &interface); + + /* GetAll */ + if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { + if (os_strcmp(dbus_message_get_signature( + message), "s")) + reply = dbus_message_new_error( + message, + DBUS_ERROR_INVALID_ARGS, NULL); + else + reply = get_all_properties( + message, interface, + obj_dsc->properties); + } else { + /* Get or Set */ + struct wpa_dbus_property_desc *property_dsc; + property_dsc = obj_dsc->properties; + + /* Second argument: property name + * (DBUS_TYPE_STRING) */ + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != + DBUS_TYPE_STRING) { + reply = dbus_message_new_error( + message, + DBUS_ERROR_INVALID_ARGS, NULL); + goto out; + } + dbus_message_iter_get_basic(&iter, &property); + + while (property_dsc) { + /* compare property names and + * interfaces */ + if (!os_strncmp(property_dsc->dbus_property, + property, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && + !os_strncmp(property_dsc->dbus_interface, interface, + WPAS_DBUS_INTERFACE_MAX)) + break; + + property_dsc = property_dsc->next; + } + if (property_dsc) { + /* Get */ + if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { + if (os_strcmp(dbus_message_get_signature(message), "ss")) + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, NULL); + else if (property_dsc->access != W && + property_dsc->getter) + reply = property_dsc->getter(message, + property_dsc->user_data); + else + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + "Property is write-only"); + } else { + /* Set */ + if (os_strcmp(dbus_message_get_signature(message), "ssv")) + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, NULL); + else if (property_dsc->access != R && + property_dsc->setter) { + reply = property_dsc->setter + (message, property_dsc->user_data); + } else { + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + "Property is read-only"); + } + } + } else { + wpa_printf(MSG_DEBUG, "no property handler for %s.%s\n" + "on %s", interface, property, path); + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + "No such property"); + } + } + } else { + reply = dbus_message_new_error( + message, DBUS_ERROR_UNKNOWN_METHOD, NULL); + goto out; + } + } else { + struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; + + /* try match call to any registered method */ + while (method_dsc) { + /* compare method names and interfaces */ + if (!os_strncmp(method_dsc->dbus_method, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && + !os_strncmp(method_dsc->dbus_interface, + msg_interface, + WPAS_DBUS_INTERFACE_MAX)) + break; + + method_dsc = method_dsc->next; + } + if (method_dsc) { + if (is_signature_correct(message, method_dsc)) { + reply = method_dsc->method_handler( + message, method_dsc->handler_argument); + } else { + reply = dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, + NULL); + } + } else { + wpa_printf(MSG_DEBUG, "no method handler for %s.%s " + "on %s", msg_interface, method, path); + reply = dbus_message_new_error( + message, DBUS_ERROR_UNKNOWN_METHOD, NULL); + } + } + +out: + /* If the message was handled, send back the reply */ + if (reply != MESSAGE_UNHANDLED) { + /* If handler succeed returning NULL, reply empty message */ + if (!reply) + reply = dbus_message_new_method_return(message); + if (reply) { + if (!dbus_message_get_no_reply(message)) + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + return DBUS_HANDLER_RESULT_HANDLED; + } else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * free_dbus_object_desc - Frees object description data structure + * @connection: DBus connection + * @obj_dsc: Object description to free + * + * Frees each of properties, methods and signals description lists and + * the object description structure itself. + */ +void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc) +{ + struct wpa_dbus_method_desc *method_dsc, *tmp_met_dsc; + struct wpa_dbus_signal_desc *signal_dsc, *tmp_sig_dsc; + struct wpa_dbus_property_desc *property_dsc, *tmp_prop_dsc; + int i; + + if (!obj_dsc) + return; + + /* free methods */ + method_dsc = obj_dsc->methods; + + while (method_dsc) { + tmp_met_dsc = method_dsc; + method_dsc = method_dsc->next; + + os_free(tmp_met_dsc->dbus_interface); + os_free(tmp_met_dsc->dbus_method); + + for (i = 0; i < tmp_met_dsc->args_num; i++) { + os_free(tmp_met_dsc->args[i].name); + os_free(tmp_met_dsc->args[i].type); + } + + if (tmp_met_dsc->argument_free_func) + tmp_met_dsc->argument_free_func( + tmp_met_dsc->handler_argument); + + os_free(tmp_met_dsc); + } + + /* free signals */ + signal_dsc = obj_dsc->signals; + + while (signal_dsc) { + tmp_sig_dsc = signal_dsc; + signal_dsc = signal_dsc->next; + + os_free(tmp_sig_dsc->dbus_interface); + os_free(tmp_sig_dsc->dbus_signal); + + for (i = 0; i < tmp_sig_dsc->args_num; i++) { + os_free(tmp_sig_dsc->args[i].name); + os_free(tmp_sig_dsc->args[i].type); + } + + os_free(tmp_sig_dsc); + } + + /* free properties */ + property_dsc = obj_dsc->properties; + + while (property_dsc) { + tmp_prop_dsc = property_dsc; + property_dsc = property_dsc->next; + + os_free(tmp_prop_dsc->dbus_interface); + os_free(tmp_prop_dsc->dbus_property); + os_free(tmp_prop_dsc->type); + + if (tmp_prop_dsc->user_data_free_func) + tmp_prop_dsc->user_data_free_func( + tmp_prop_dsc->user_data); + + os_free(tmp_prop_dsc); + } + + os_free(obj_dsc); +} + + +static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc) +{ + free_dbus_object_desc(obj_dsc); +} + +/** + * wpa_dbus_ctrl_iface_init - Initialize dbus control interface + * @application_data: Pointer to application specific data structure + * @dbus_path: DBus path to interface object + * @dbus_service: DBus service name to register with + * @messageHandler: a pointer to function which will handle dbus messages + * coming on interface + * Returns: Pointer to dbus_new_ctrl_iface date or %NULL on failure + * + * Initialize the dbus control interface and start receiving commands from + * external programs over the bus. + */ +struct ctrl_iface_dbus_new_priv * +wpa_dbus_ctrl_iface_init(void *application_data, + char *dbus_path, char *dbus_service, + struct wpa_dbus_object_desc *obj_desc) +{ + struct ctrl_iface_dbus_new_priv *iface; + DBusError error; + int ret = -1; + DBusObjectPathVTable wpa_vtable = { + &free_dbus_object_desc_cb, &message_handler, + NULL, NULL, NULL, NULL + }; + + iface = os_zalloc(sizeof(struct ctrl_iface_dbus_new_priv)); + if (iface == NULL) + return NULL; + + iface->application_data = application_data; + + /* Get a reference to the system bus */ + dbus_error_init(&error); + iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + dbus_error_free(&error); + if (!iface->con) { + perror("dbus_bus_get[ctrl_iface_dbus]"); + wpa_printf(MSG_ERROR, "Could not acquire the system bus."); + goto fail; + } + + obj_desc->connection = iface->con; + + /* Tell dbus about our mainloop integration functions */ + if (integrate_with_eloop(iface->con, iface)) + goto fail; + + /* Register the message handler for the global dbus interface */ + if (!dbus_connection_register_object_path(iface->con, + dbus_path, &wpa_vtable, + obj_desc)) { + perror("dbus_connection_register_object_path[dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler."); + goto fail; + } + + /* Register our service with the message bus */ + dbus_error_init(&error); + switch (dbus_bus_request_name(iface->con, dbus_service, + 0, &error)) { + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: + ret = 0; + break; + case DBUS_REQUEST_NAME_REPLY_EXISTS: + case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "already registered."); + break; + default: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "%s %s.", error.name, error.message); + break; + } + dbus_error_free(&error); + + if (ret != 0) + goto fail; + + wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service); + + /* + * Dispatch initial DBus messages that may have come in since the bus + * name was claimed above. Happens when clients are quick to notice the + * service. + * + * FIXME: is there a better solution to this problem? + */ + eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, + iface->con, NULL); + + return iface; + +fail: + wpa_dbus_ctrl_iface_deinit(iface); + return NULL; +} + + +/** + * wpa_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface + * @iface: Pointer to dbus private data from wpa_dbus_ctrl_iface_init() + * + * Deinitialize the dbus control interface that was initialized with + * wpa_dbus_ctrl_iface_init(). + */ +void wpa_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_new_priv *iface) +{ + if (iface == NULL) + return; + + if (iface->con) { + eloop_cancel_timeout(dispatch_initial_dbus_messages, + iface->con, NULL); + dbus_connection_set_watch_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_set_timeout_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_unref(iface->con); + } + + os_memset(iface, 0, sizeof(struct ctrl_iface_dbus_new_priv)); + os_free(iface); +} + + +/** + * wpa_dbus_register_object_per_iface - Register a new object with dbus + * @ctrl_iface: pointer to dbus private data + * @path: DBus path to object + * @ifname: interface name + * @obj_desc: description of object's methods, signals and properties + * Returns: 0 on success, -1 on error + * + * Registers a new interface with dbus and assigns it a dbus object path. + */ +int wpa_dbus_register_object_per_iface( + struct ctrl_iface_dbus_new_priv *ctrl_iface, + const char *path, const char *ifname, + struct wpa_dbus_object_desc *obj_desc) +{ + DBusConnection *con; + + DBusObjectPathVTable vtable = { + &free_dbus_object_desc_cb, &message_handler, + NULL, NULL, NULL, NULL + }; + + /* Do nothing if the control interface is not turned on */ + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + obj_desc->connection = con; + + /* Register the message handler for the interface functions */ + if (!dbus_connection_register_object_path(con, path, &vtable, + obj_desc)) { + perror("wpa_dbus_register_iface [dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler for interface %s\n" + "and object %s.", ifname, path); + return -1; + } + + return 0; +} + + +/** + * wpa_dbus_unregister_object_per_iface - Unregisters DBus object + * @ctrl_iface: Pointer to dbus private data + * @path: DBus path to object which will be unregistered + * Returns: Zero on success and -1 on failure + * + * Unregisters DBus object given by its path + */ +int wpa_dbus_unregister_object_per_iface( + struct ctrl_iface_dbus_new_priv *ctrl_iface, const char *path) +{ + DBusConnection *con = ctrl_iface->con; + if (!dbus_connection_unregister_object_path(con, path)) + return -1; + + return 0; +} + + +/** + * wpa_dbus_method_register - Registers DBus method for given object + * @obj_dsc: Object description for which a method will be registered + * @dbus_interface: DBus interface under which method will be registered + * @dbus_method: a name the method will be registered with + * @method_handler: a function which will be called to handle this method call + * @handler_argument: an additional argument passed to handler function + * @argument_free_func: function used to free handler argument + * @args: method arguments list + * Returns: Zero on success and -1 on failure + * + * Registers DBus method under given name and interface for the object. + * Method calls will be handled with given handling function and optional + * argument passed to this function. Handler function is required to return + * a DBusMessage pointer which will be response to method call. Any method + * call before being handled must have registered appropriate handler by + * using this function. + */ +int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_method, + WPADBusMethodHandler method_handler, + void *handler_argument, + WPADBusArgumentFreeFunction argument_free_func, + struct wpa_dbus_argument args[]) +{ + struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; + struct wpa_dbus_method_desc *prev_desc; + int args_num = 0; + int interface_len, method_len, i, len, error; + + prev_desc = NULL; + while (method_dsc) { + prev_desc = method_dsc; + method_dsc = method_dsc->next; + } + + /* count args */ + + if (args) { + while (args[args_num].name && args[args_num].type) + args_num++; + } + + method_dsc = os_zalloc(sizeof(struct wpa_dbus_method_desc) + + args_num * sizeof(struct wpa_dbus_argument)); + if (!method_dsc) + return -1; + + if (prev_desc == NULL) + obj_dsc->methods = method_dsc; + else + prev_desc->next = method_dsc; + + /* copy interface name */ + interface_len = os_strlen(dbus_interface) + 1; + method_dsc->dbus_interface = os_malloc(interface_len); + if (!method_dsc->dbus_interface) + goto err; + os_strncpy(method_dsc->dbus_interface, dbus_interface, interface_len); + + /* copy method name */ + method_len = os_strlen(dbus_method) + 1; + method_dsc->dbus_method = os_malloc(method_len); + if (!method_dsc->dbus_method) + goto err; + os_strncpy(method_dsc->dbus_method, dbus_method, method_len); + + /* copy arguments */ + error = 0; + method_dsc->args_num = args_num; + for (i = 0; i < args_num; i++) { + len = os_strlen(args[i].name) + 1; + method_dsc->args[i].name = os_malloc(len); + if (!method_dsc->args[i].name) { + error = 1; + continue; + } + os_strncpy(method_dsc->args[i].name, args[i].name, len); + + len = os_strlen(args[i].type) + 1; + method_dsc->args[i].type = os_malloc(len); + if (!method_dsc->args[i].type) { + error = 1; + continue; + } + os_strncpy(method_dsc->args[i].type, args[i].type, len); + + method_dsc->args[i].dir = args[i].dir; + } + if (error) + goto err; + + method_dsc->method_handler = method_handler; + method_dsc->handler_argument = handler_argument; + method_dsc->argument_free_func = argument_free_func; + method_dsc->next = NULL; + + return 0; + +err: + if (method_dsc) { + os_free(method_dsc->dbus_interface); + os_free(method_dsc->dbus_method); + for (i = 0; i < method_dsc->args_num; i++) { + os_free(method_dsc->args[i].name); + os_free(method_dsc->args[i].type); + } + + if (prev_desc == NULL) + obj_dsc->methods = NULL; + else + prev_desc->next = NULL; + + os_free(method_dsc); + } + + return -1; +} + + +/** + * wpa_dbus_signal_register - Registers DBus signal for given object + * @obj_dsc: Object description for which a signal will be registered + * @dbus_interface: DBus interface under which signal will be registered + * @dbus_signal: a name the signal will be registered with + * @args: signal arguments list + * Returns: Zero on success and -1 on failure + * + * Registers DBus signal under given name and interface for the object. + * Signal registration is NOT required in order to send signals, but not + * registered signals will not be respected in introspection data + * therefore it is highly recommended to register every signal before + * using it. + */ +int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_signal, + struct wpa_dbus_argument args[]) +{ + + struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals; + struct wpa_dbus_signal_desc *prev_desc; + int args_num = 0; + int interface_len, signal_len, i, len, error = 0; + + prev_desc = NULL; + while (signal_dsc) { + prev_desc = signal_dsc; + signal_dsc = signal_dsc->next; + } + + /* count args */ + if (args) { + while (args[args_num].name && args[args_num].type) + args_num++; + } + + signal_dsc = os_zalloc(sizeof(struct wpa_dbus_signal_desc) + + args_num*sizeof(struct wpa_dbus_argument)); + if (!signal_dsc) + return -1; + + if (prev_desc == NULL) + obj_dsc->signals = signal_dsc; + else + prev_desc->next = signal_dsc; + + /* copy interface name */ + interface_len = strlen(dbus_interface) + 1; + signal_dsc->dbus_interface = os_malloc(interface_len); + if (!signal_dsc->dbus_interface) + goto err; + os_strncpy(signal_dsc->dbus_interface, dbus_interface, interface_len); + + /* copy signal name */ + signal_len = strlen(dbus_signal) + 1; + signal_dsc->dbus_signal = os_malloc(signal_len); + if (!signal_dsc->dbus_signal) + goto err; + os_strncpy(signal_dsc->dbus_signal, dbus_signal, signal_len); + + /* copy arguments */ + signal_dsc->args_num = args_num; + for (i = 0; i < args_num; i++) { + len = os_strlen(args[i].name) + 1; + signal_dsc->args[i].name = os_malloc(len); + if (!signal_dsc->args[i].name) { + error = 1; + continue; + } + os_strncpy(signal_dsc->args[i].name, args[i].name, len); + + len = strlen(args[i].type) + 1; + signal_dsc->args[i].type = os_malloc(len); + if (!signal_dsc->args[i].type) { + error = 1; + continue; + } + os_strncpy(signal_dsc->args[i].type, args[i].type, len); + } + if (error) + goto err; + + signal_dsc->next = NULL; + + return 0; + +err: + if (signal_dsc) { + os_free(signal_dsc->dbus_interface); + os_free(signal_dsc->dbus_signal); + for (i = 0; i < signal_dsc->args_num; i++) { + os_free(signal_dsc->args[i].name); + os_free(signal_dsc->args[i].type); + } + + if (prev_desc == NULL) + obj_dsc->signals = NULL; + else + prev_desc->next = NULL; + + os_free(signal_dsc); + } + + return -1; +} + + +/** + * wpa_dbus_property_register - Registers DBus property for given object + * @obj_dsc: Object description for which a property will be registered + * @dbus_interface: DBus interface under which method will be registered + * @dbus_property: a name the property will be registered with + * @type: a property type signature in form of DBus type description + * @getter: a function called in order to get property value + * @setter: a function called in order to set property value + * @user_data: additional argument passed to setter or getter + * @user_data_free_func: function used to free additional argument + * @access: property access permissions specifier (R, W or RW) + * Returns: Zero on success and -1 on failure + * + * Registers DBus property under given name and interface for the object. + * Property are set with giver setter function and get with getter. + * Additional argument is passed to getter or setter. Getter or setter + * are required to return DBusMessage which is response to Set/Get method + * calls. Every property must be registered by this function before being + * used. + */ +int wpa_dbus_property_register(struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_property, + char *type, + WPADBusPropertyAccessor getter, + WPADBusPropertyAccessor setter, + void *user_data, + WPADBusArgumentFreeFunction user_data_free_func, + enum dbus_prop_access _access) +{ + struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties; + struct wpa_dbus_property_desc *prev_desc; + int interface_len, property_len, type_len; + + prev_desc = NULL; + while (property_dsc) { + prev_desc = property_dsc; + property_dsc = property_dsc->next; + } + + property_dsc = os_zalloc(sizeof(struct wpa_dbus_property_desc)); + if (!property_dsc) + return -1; + + if (prev_desc == NULL) + obj_dsc->properties = property_dsc; + else + prev_desc->next = property_dsc; + + /* copy interface name */ + interface_len = os_strlen(dbus_interface) + 1; + property_dsc->dbus_interface = os_malloc(interface_len); + if (!property_dsc->dbus_interface) + goto err; + os_strncpy(property_dsc->dbus_interface, dbus_interface, + interface_len); + + /* copy property name */ + property_len = os_strlen(dbus_property) + 1; + property_dsc->dbus_property = os_malloc(property_len); + if (!property_dsc->dbus_property) + goto err; + os_strncpy(property_dsc->dbus_property, dbus_property, property_len); + + /* copy property type */ + type_len = os_strlen(type) + 1; + property_dsc->type = os_malloc(type_len); + if (!property_dsc->type) + goto err; + os_strncpy(property_dsc->type, type, type_len); + + property_dsc->getter = getter; + property_dsc->setter = setter; + property_dsc->user_data = user_data; + property_dsc->user_data_free_func = user_data_free_func; + property_dsc->access = _access; + property_dsc->next = NULL; + + return 0; + +err: + if (property_dsc) { + os_free(property_dsc->dbus_interface); + os_free(property_dsc->dbus_property); + os_free(property_dsc->type); + + if (prev_desc == NULL) + obj_dsc->properties = NULL; + else + prev_desc->next = NULL; + + os_free(property_dsc); + } + + return -1; +} + + +/** + * wpas_dbus_signal_network_added - Send a property changed signal + * @iface: dbus priv struct + * @property_getter: propperty getter used to fetch new property value + * @getter_arg: argument passed to property getter + * @path: path to object which property has changed + * @interface_name: signal and property interface + * @property_name: name of property which has changed + * + * Notify listeners about changing value of some property. Signal + * contains property name and its value fetched using given property + * getter. + */ +void wpa_dbus_signal_property_changed(struct ctrl_iface_dbus_new_priv *iface, + WPADBusPropertyAccessor property_getter, + void *getter_arg, + const char *path, + const char *interface_name, + const char *property_name) +{ + + DBusConnection *connection; + DBusMessage *_signal, *getter_reply; + DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter; + + if (!iface) + return; + connection = iface->con; + + if (!property_getter) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: property getter not specified"); + return; + } + + if (!path || !interface_name || !property_name) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: path interface of property not specified"); + return; + } + + getter_reply = property_getter(NULL, getter_arg); + if (!getter_reply || + dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: cannot get new value of property %s", + property_name); + return; + } + + _signal = dbus_message_new_signal(path, interface_name, + "PropertiesChanged"); + if (!_signal) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: cannot allocate signal"); + dbus_message_unref(getter_reply); + return; + } + + dbus_message_iter_init(getter_reply, &prop_iter); + dbus_message_iter_init_append(_signal, &signal_iter); + + if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, + "{sv}", &dict_iter)) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: out of memory. cannot open dictionary"); + goto err; + } + + if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter)) { + wpa_printf(MSG_ERROR, "iwpa_dbus_signal_property_changed" + "[dbus]: out of memory. cannot open dictionary " + "element"); + goto err; + } + + if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING, + &property_name)) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: out of memory. cannot open add property " + "name"); + goto err; + } + + recursive_iter_copy(&prop_iter, &entry_iter); + + if (!dbus_message_iter_close_container(&dict_iter, &entry_iter)) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: out of memory. cannot close dictionary " + "element"); + goto err; + } + + if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) { + wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed" + "[dbus]: out of memory. cannot close dictionary"); + goto err; + } + + dbus_connection_send(connection, _signal, NULL); + +err: + dbus_message_unref(getter_reply); + dbus_message_unref(_signal); + +} diff --git a/wpa_supplicant/ctrl_iface_dbus_new_helpers.h b/wpa_supplicant/ctrl_iface_dbus_new_helpers.h new file mode 100644 index 000000000..1da4e4b85 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_new_helpers.h @@ -0,0 +1,140 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa + * + * 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. + */ + +#ifndef WPA_DBUS_CTRL_H +#define WPA_DBUS_CTRL_H + +#include + +struct ctrl_iface_dbus_new_priv { + DBusConnection *con; + int should_dispatch; + void *application_data; + + u32 next_objid; +}; + +typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message, + void *user_data); +typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg); + +typedef DBusMessage * (* WPADBusPropertyAccessor)(DBusMessage *message, + void *user_data); + +struct wpa_dbus_object_desc { + DBusConnection *connection; + struct wpa_dbus_method_desc *methods; + struct wpa_dbus_signal_desc *signals; + struct wpa_dbus_property_desc *properties; +}; + +enum dbus_prop_access { R, W, RW }; + +enum dbus_arg_direction { ARG_IN, ARG_OUT }; + +struct wpa_dbus_argument { + char *name; + char *type; + enum dbus_arg_direction dir; +}; + +#define END_ARGS { NULL, NULL, ARG_IN } + +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + +#ifndef SIGPOLL +#ifdef SIGIO +/* + * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for + * FreeBSD. + */ +#define SIGPOLL SIGIO +#endif +#endif + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 +#define WPAS_DBUS_INTERFACE_MAX 150 +#define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50 + +#define WPA_DBUS_INTROSPECTION_INTERFACE "org.freedesktop.DBus.Introspectable" +#define WPA_DBUS_INTROSPECTION_METHOD "Introspect" +#define WPA_DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" +#define WPA_DBUS_PROPERTIES_GET "Get" +#define WPA_DBUS_PROPERTIES_SET "Set" +#define WPA_DBUS_PROPERTIES_GETALL "GetAll" + +void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc); + +struct ctrl_iface_dbus_new_priv * +wpa_dbus_ctrl_iface_init(void *application_data, char *dbus_path, + char *dbus_service, + struct wpa_dbus_object_desc *obj_desc); + +void wpa_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_new_priv *iface); + +int wpa_dbus_register_object_per_iface( + struct ctrl_iface_dbus_new_priv *ctrl_iface, + const char *path, const char *ifname, + struct wpa_dbus_object_desc *obj_desc); + +int wpa_dbus_unregister_object_per_iface( + struct ctrl_iface_dbus_new_priv *ctrl_iface, + const char *path); + +int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_method, + WPADBusMethodHandler method_handler, + void *handler_argument, + WPADBusArgumentFreeFunction argument_free_func, + struct wpa_dbus_argument args[]); + +int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_signal, + struct wpa_dbus_argument args[]); + +int wpa_dbus_property_register( + struct wpa_dbus_object_desc *obj_dsc, + char *dbus_interface, char *dbus_property, + char *type, + WPADBusPropertyAccessor getter, + WPADBusPropertyAccessor setter, + void *user_data, + WPADBusArgumentFreeFunction user_datat_free_func, + enum dbus_prop_access access); + +void wpa_dbus_signal_property_changed(struct ctrl_iface_dbus_new_priv *iface, + WPADBusPropertyAccessor property_getter, + void *getter_arg, + const char *path, + const char *interface_name, + const char *property_name); + +/* Methods internal to the dbus control interface */ +u32 wpa_dbus_next_objid(struct ctrl_iface_dbus_new_priv *iface); + + +#else /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +static inline void wpa_dbus_signal_property_changed( + struct ctrl_iface_dbus_new_priv *iface, + WPADBusPropertyAccessor property_getter, void *getter_arg, + const char *path, const char *interface_name, + const char *property_name) +{ +} + +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#endif /* WPA_DBUS_CTRL_H */ diff --git a/wpa_supplicant/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus-wpa_supplicant.conf index 51a29e3a8..1d4368e5a 100644 --- a/wpa_supplicant/dbus-wpa_supplicant.conf +++ b/wpa_supplicant/dbus-wpa_supplicant.conf @@ -7,10 +7,20 @@ + + + + + + + + + + diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index aaa921f27..453ffe8e2 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -337,9 +337,17 @@ CONFIG_PEERKEY=y #CONFIG_NDIS_EVENTS_INTEGRATED=y #PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" -# Add support for DBus control interface +# Add support for old DBus control interface +# (fi.epitest.hostap.WPASupplicant) #CONFIG_CTRL_IFACE_DBUS=y +# Add support for new DBus control interface +# (fi.w1.hostap.wpa_supplicant1) +#CONFIG_CTRL_IFACE_DBUS_NEW=y + +# Add introspection support for new DBus control interface (requires libxml2) +#CONFIG_CTRL_IFACE_DBUS_INTRO=y + # Add support for loading EAP methods dynamically as shared libraries. # When this option is enabled, each EAP method can be either included # statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 066f5a900..f3dcebcbf 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -19,15 +19,25 @@ #include "wpa_supplicant_i.h" #include "wps_supplicant.h" #include "ctrl_iface_dbus.h" +#include "ctrl_iface_dbus_new.h" #include "notify.h" int wpas_notify_supplicant_initialized(struct wpa_global *global) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (global->params.dbus_ctrl_interface) { global->dbus_ctrl_iface = wpa_supplicant_dbus_ctrl_iface_init(global); if (global->dbus_ctrl_iface == NULL) return -1; + + if (cbs) { + global->dbus_new_ctrl_iface = + cbs->dbus_ctrl_init(global); + if (global->dbus_new_ctrl_iface == NULL) + return -1; + } } return 0; @@ -36,16 +46,26 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global) void wpas_notify_supplicant_deinitialized(struct wpa_global *global) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (global->dbus_ctrl_iface) wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface); + + if (cbs && global->dbus_new_ctrl_iface) + cbs->dbus_ctrl_deinit(global->dbus_new_ctrl_iface); } int wpas_notify_iface_added(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (wpas_dbus_register_iface(wpa_s)) return -1; + if (cbs && cbs->register_interface(wpa_s)) + return -1; + return 0; } @@ -53,56 +73,91 @@ int wpas_notify_iface_added(struct wpa_supplicant *wpa_s) void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + /* unregister interface in old DBus ctrl iface */ wpas_dbus_unregister_iface(wpa_s); + + /* unregister interface in new DBus ctrl iface */ + if (cbs) + cbs->unregister_interface(wpa_s); } void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, wpa_states new_state, wpa_states old_state) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + /* notify the old DBus API */ wpa_supplicant_dbus_notify_state_change(wpa_s, new_state, old_state); + + /* notify the new DBus API */ + if (cbs) + cbs->signal_state_changed(wpa_s, new_state, old_state); } void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_prop_changed(wpa_s, + WPAS_DBUS_PROP_CURRENT_NETWORK); } void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN); } void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS); } void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_network_enabled_changed(wpa_s, ssid); } void wpas_notify_network_selected(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_network_selected(wpa_s, ssid->id); } void wpas_notify_scanning(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); /* notify the old DBus API */ wpa_supplicant_dbus_notify_scanning(wpa_s); + /* notify the new DBus API */ + if (cbs) + cbs->signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING); } void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_scan_done(wpa_s, success); } @@ -118,50 +173,79 @@ void wpas_notify_scan_results(struct wpa_supplicant *wpa_s) void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + /* notify the old DBus API */ wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred); + /* notify the new DBus API */ + if (cbs) + cbs->signal_wps_credentials(wpa_s, cred); } void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_wps_event_m2d(wpa_s, m2d); } void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_wps_event_fail(wpa_s, fail); } void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_wps_event_success(wpa_s); } void wpas_notify_network_added(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (wpa_s->global->dbus_new_ctrl_iface && cbs) + cbs->register_network(wpa_s, ssid); } void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (wpa_s->global->dbus_new_ctrl_iface && cbs) + cbs->unregister_network(wpa_s, ssid->id); } void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_blob_added(wpa_s, name); } void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_blob_removed(wpa_s, name); } void wpas_notify_debug_params_changed(struct wpa_global *global) { + struct wpas_dbus_callbacks *cbs = wpas_dbus_get_callbacks(); + if (cbs) + cbs->signal_debug_params_changed(global); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index e47ac74fa..193baa34c 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -190,7 +190,10 @@ struct wpa_global { struct wpa_supplicant *ifaces; struct wpa_params params; struct ctrl_iface_global_priv *ctrl_iface; + /* old DBus API data */ struct ctrl_iface_dbus_priv *dbus_ctrl_iface; + /* new DBus API data */ + struct ctrl_iface_dbus_new_priv *dbus_new_ctrl_iface; void **drv_priv; size_t drv_count; }; @@ -305,6 +308,9 @@ struct wpa_supplicant { #ifdef CONFIG_CTRL_IFACE_DBUS char *dbus_path; #endif /* CONFIG_CTRL_IFACE_DBUS */ +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + char *dbus_new_path; +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ char bridge_ifname[16]; char *confname;