diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2011-05-09 14:06:53 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2011-05-09 14:24:08 -0700 |
commit | 8d520ff1dc2da35cdca849e982051b86468016d8 (patch) | |
tree | 3e33700a20ffe9064c3de3e9efa3a9dfcebb7b03 /wpa_supplicant/dbus | |
parent | 7acd11a82b3521a1ec0ef3976af4786b02642e7e (diff) | |
download | external_wpa_supplicant_8-8d520ff1dc2da35cdca849e982051b86468016d8.zip external_wpa_supplicant_8-8d520ff1dc2da35cdca849e982051b86468016d8.tar.gz external_wpa_supplicant_8-8d520ff1dc2da35cdca849e982051b86468016d8.tar.bz2 |
wpa_supplicant: Initial Revision 0.8.X
Based on:
commit 0725cc7b7efc434910e89865c42eda7ce61bbf08
Author: Jouni Malinen <j@w1.fi>
Date: Thu Apr 21 20:41:01 2011 +0300
Enable CONFIG_DRIVER_NL80211=y in the default configuration
nl80211 should be preferred over WEXT with any recent Linux
kernel version.
Change-Id: I26aec5afbbd4f4a1f5fd900912545b6f5050de64
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'wpa_supplicant/dbus')
23 files changed, 11109 insertions, 0 deletions
diff --git a/wpa_supplicant/dbus/.gitignore b/wpa_supplicant/dbus/.gitignore new file mode 100644 index 0000000..6db2468 --- /dev/null +++ b/wpa_supplicant/dbus/.gitignore @@ -0,0 +1 @@ +libwpadbus.a diff --git a/wpa_supplicant/dbus/Makefile b/wpa_supplicant/dbus/Makefile new file mode 100644 index 0000000..cfaf58d --- /dev/null +++ b/wpa_supplicant/dbus/Makefile @@ -0,0 +1,84 @@ +all: libwpadbus.a + +clean: + rm -f *~ *.o *.d + rm -f libwpadbus.a + +install: + @echo Nothing to be made. + +ifndef CC +CC=gcc +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g +endif + +CFLAGS += -I../../src -I../../src/utils + + +Q=@ +E=echo +ifeq ($(V), 1) +Q= +E=true +endif + +%.o: %.c + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + @$(E) " CC " $< + + +ifdef CONFIG_WPS +CFLAGS += -DCONFIG_WPS +endif + +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS + +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 +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO +DBUS_INCLUDE += $(shell xml2-config --cflags) +DBUS_LIBS += $(shell xml2-config --libs) +endif + +dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1)) +DBUS_VERSION_MAJOR=$(word 1,$(dbus_version)) +DBUS_VERSION_MINOR=$(word 2,$(dbus_version)) +ifeq ($(DBUS_VERSION_MAJOR),) +DBUS_VERSION_MAJOR=0 +endif +ifeq ($(DBUS_VERSION_MINOR),) +DBUS_VERSION_MINOR=0 +endif +DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR) +DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR) + +CFLAGS += $(DBUS_INCLUDE) + +LIB_OBJS= \ + dbus_common.o \ + dbus_old.o \ + dbus_old_handlers.o \ + dbus_new.o \ + dbus_new_handlers.o \ + dbus_new_helpers.o \ + dbus_new_introspect.o \ + dbus_dict_helpers.o + +ifdef CONFIG_WPS +LIB_OBJS += dbus_old_handlers_wps.o +LIB_OBJS += dbus_new_handlers_wps.o +endif + +libwpadbus.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf new file mode 100644 index 0000000..c091234 --- /dev/null +++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf @@ -0,0 +1,27 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow own="fi.epitest.hostap.WPASupplicant"/> + + <allow send_destination="fi.epitest.hostap.WPASupplicant"/> + <allow send_interface="fi.epitest.hostap.WPASupplicant"/> + + <allow own="fi.w1.wpa_supplicant1"/> + + <allow send_destination="fi.w1.wpa_supplicant1"/> + <allow send_interface="fi.w1.wpa_supplicant1"/> + <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> + </policy> + <policy context="default"> + <deny own="fi.epitest.hostap.WPASupplicant"/> + <deny send_destination="fi.epitest.hostap.WPASupplicant"/> + <deny send_interface="fi.epitest.hostap.WPASupplicant"/> + + <deny own="fi.w1.wpa_supplicant1"/> + <deny send_destination="fi.w1.wpa_supplicant1"/> + <deny send_interface="fi.w1.wpa_supplicant1"/> + <deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> + </policy> +</busconfig> diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c new file mode 100644 index 0000000..5850636 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_common.c @@ -0,0 +1,371 @@ +/* + * wpa_supplicant D-Bus control interface - common functionality + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" +#include <dbus/dbus.h> + +#include "utils/common.h" +#include "utils/eloop.h" +#include "dbus_common.h" +#include "dbus_common_i.h" +#include "dbus_new.h" +#include "dbus_old.h" + + +#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 + + +static void dispatch_data(DBusConnection *con) +{ + while (dbus_connection_get_dispatch_status(con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(con); +} + + +/** + * 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; + dispatch_data(con); +} + + +static void process_watch(struct wpas_dbus_priv *priv, + DBusWatch *watch, eloop_event_type type) +{ + dbus_connection_ref(priv->con); + + priv->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 (priv->should_dispatch) { + dispatch_data(priv->con); + priv->should_dispatch = 0; + } + + dbus_connection_unref(priv->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 dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + struct wpas_dbus_priv *priv = data; + unsigned int flags; + int fd; + + if (!dbus_watch_get_enabled(watch)) + return TRUE; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_unix_fd(watch); + + eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, + priv, watch); + + if (flags & DBUS_WATCH_READABLE) { + eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, + priv, watch); + } + if (flags & DBUS_WATCH_WRITABLE) { + eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, + priv, watch); + } + + dbus_watch_set_data(watch, priv, NULL); + + return TRUE; +} + + +static void remove_watch(DBusWatch *watch, void *data) +{ + 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 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 dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + struct wpas_dbus_priv *priv = data; + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, + process_timeout, priv, timeout); + + dbus_timeout_set_data(timeout, priv, NULL); + + return TRUE; +} + + +static void remove_timeout(DBusTimeout *timeout, void *data) +{ + struct wpas_dbus_priv *priv = data; + eloop_cancel_timeout(process_timeout, priv, timeout); + dbus_timeout_set_data(timeout, NULL, NULL); +} + + +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 *signal_ctx) +{ + struct wpas_dbus_priv *priv = signal_ctx; + + if (sig != SIGPOLL || !priv->con) + return; + + if (dbus_connection_get_dispatch_status(priv->con) != + DBUS_DISPATCH_DATA_REMAINS) + return; + + /* Only dispatch once - we do not want to starve other events */ + dbus_connection_ref(priv->con); + dbus_connection_dispatch(priv->con); + dbus_connection_unref(priv->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 wpas_dbus_priv *priv = data; + + /* Use SIGPOLL to break out of the eloop select() */ + raise(SIGPOLL); + priv->should_dispatch = 1; +} + + +/** + * integrate_with_eloop - Register our mainloop integration with dbus + * @connection: connection to the system message bus + * @priv: a dbus control interface data structure + * Returns: 0 on success, -1 on failure + */ +static int integrate_with_eloop(struct wpas_dbus_priv *priv) +{ + if (!dbus_connection_set_watch_functions(priv->con, add_watch, + remove_watch, watch_toggled, + priv, NULL) || + !dbus_connection_set_timeout_functions(priv->con, add_timeout, + remove_timeout, + timeout_toggled, priv, + NULL)) { + wpa_printf(MSG_ERROR, "dbus: Failed to set callback " + "functions"); + return -1; + } + + if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv)) + return -1; + dbus_connection_set_wakeup_main_function(priv->con, wakeup_main, + priv, NULL); + + return 0; +} + + +static int wpas_dbus_init_common(struct wpas_dbus_priv *priv) +{ + DBusError error; + int ret = 0; + + /* Get a reference to the system bus */ + dbus_error_init(&error); + priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (!priv->con) { + wpa_printf(MSG_ERROR, "dbus: Could not acquire the system " + "bus: %s - %s", error.name, error.message); + ret = -1; + } + dbus_error_free(&error); + + return ret; +} + + +static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv) +{ + /* Tell dbus about our mainloop integration functions */ + integrate_with_eloop(priv); + + /* + * 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, + priv->con, NULL); + + return 0; +} + + +static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv) +{ + if (priv->con) { + eloop_cancel_timeout(dispatch_initial_dbus_messages, + priv->con, NULL); + dbus_connection_set_watch_functions(priv->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_set_timeout_functions(priv->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_unref(priv->con); + } + + os_free(priv); +} + + +struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global) +{ + struct wpas_dbus_priv *priv; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + + if (wpas_dbus_init_common(priv) < 0) { + wpas_dbus_deinit(priv); + return NULL; + } + +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + if (wpas_dbus_ctrl_iface_init(priv) < 0) { + wpas_dbus_deinit(priv); + return NULL; + } +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#ifdef CONFIG_CTRL_IFACE_DBUS + if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) { + wpas_dbus_deinit(priv); + return NULL; + } +#endif /* CONFIG_CTRL_IFACE_DBUS */ + + if (wpas_dbus_init_common_finish(priv) < 0) { + wpas_dbus_deinit(priv); + return NULL; + } + + return priv; +} + + +void wpas_dbus_deinit(struct wpas_dbus_priv *priv) +{ + if (priv == NULL) + return; + +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + wpas_dbus_ctrl_iface_deinit(priv); +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#ifdef CONFIG_CTRL_IFACE_DBUS + /* TODO: is any deinit needed? */ +#endif /* CONFIG_CTRL_IFACE_DBUS */ + + wpas_dbus_deinit_common(priv); +} diff --git a/wpa_supplicant/dbus/dbus_common.h b/wpa_supplicant/dbus/dbus_common.h new file mode 100644 index 0000000..50da09b --- /dev/null +++ b/wpa_supplicant/dbus/dbus_common.h @@ -0,0 +1,26 @@ +/* + * wpa_supplicant D-Bus control interface - common definitions + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DBUS_COMMON_H +#define DBUS_COMMON_H + +struct wpas_dbus_priv; +struct wpa_global; + +struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global); +void wpas_dbus_deinit(struct wpas_dbus_priv *priv); + +#endif /* DBUS_COMMON_H */ diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h new file mode 100644 index 0000000..9dab1ee --- /dev/null +++ b/wpa_supplicant/dbus/dbus_common_i.h @@ -0,0 +1,30 @@ +/* + * wpa_supplicant D-Bus control interface - internal definitions + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DBUS_COMMON_I_H +#define DBUS_COMMON_I_H + +#include <dbus/dbus.h> + +struct wpas_dbus_priv { + DBusConnection *con; + int should_dispatch; + struct wpa_global *global; + u32 next_objid; + int dbus_new_initialized; +}; + +#endif /* DBUS_COMMON_I_H */ diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c new file mode 100644 index 0000000..d900487 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_dict_helpers.c @@ -0,0 +1,923 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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. + */ + +#include "includes.h" +#include <dbus/dbus.h> + +#include "common.h" +#include "dbus_dict_helpers.h" + + +/** + * Start a dict in a dbus message. Should be paired with a call to + * wpa_dbus_dict_close_write(). + * + * @param iter A valid dbus message iterator + * @param iter_dict (out) A dict iterator to pass to further dict functions + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + dbus_bool_t result; + + if (!iter || !iter_dict) + return FALSE; + + result = 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, + iter_dict); + return result; +} + + +/** + * End a dict element in a dbus message. Should be paired with + * a call to wpa_dbus_dict_open_write(). + * + * @param iter valid dbus message iterator, same as passed to + * wpa_dbus_dict_open_write() + * @param iter_dict a dbus dict iterator returned from + * wpa_dbus_dict_open_write() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + return dbus_message_iter_close_container(iter, iter_dict); +} + + +const char * wpa_dbus_type_as_string(const int type) +{ + switch(type) { + case DBUS_TYPE_BYTE: + return DBUS_TYPE_BYTE_AS_STRING; + case DBUS_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN_AS_STRING; + case DBUS_TYPE_INT16: + return DBUS_TYPE_INT16_AS_STRING; + case DBUS_TYPE_UINT16: + return DBUS_TYPE_UINT16_AS_STRING; + case DBUS_TYPE_INT32: + return DBUS_TYPE_INT32_AS_STRING; + case DBUS_TYPE_UINT32: + return DBUS_TYPE_UINT32_AS_STRING; + case DBUS_TYPE_INT64: + return DBUS_TYPE_INT64_AS_STRING; + case DBUS_TYPE_UINT64: + return DBUS_TYPE_UINT64_AS_STRING; + case DBUS_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE_AS_STRING; + case DBUS_TYPE_STRING: + return DBUS_TYPE_STRING_AS_STRING; + case DBUS_TYPE_OBJECT_PATH: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + case DBUS_TYPE_ARRAY: + return DBUS_TYPE_ARRAY_AS_STRING; + default: + return NULL; + } +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_start( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + const char *key, const int value_type) +{ + if (!dbus_message_iter_open_container(iter_dict, + DBUS_TYPE_DICT_ENTRY, NULL, + iter_dict_entry)) + return FALSE; + + if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING, + &key)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_end( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val) +{ + if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val)) + return FALSE; + if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict, + const char *key, + const int value_type, + const void *value) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + const char *type_as_string = NULL; + + if (key == NULL) + return FALSE; + + type_as_string = wpa_dbus_type_as_string(value_type); + if (!type_as_string) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, value_type)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + type_as_string, &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array( + DBusMessageIter *iter_dict, const char *key, + const char *value, const dbus_uint32_t value_len) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &iter_array)) + return FALSE; + + for (i = 0; i < value_len; i++) { + if (!dbus_message_iter_append_basic(&iter_array, + DBUS_TYPE_BYTE, + &(value[i]))) + return FALSE; + } + + if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Add a string entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The string value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value) +{ + if (!value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING, + &value); +} + + +/** + * Add a byte entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The byte value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE, + &value); +} + + +/** + * Add a boolean entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The boolean value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, const dbus_bool_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_BOOLEAN, &value); +} + + +/** + * Add a 16-bit signed integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 16-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16, + &value); +} + + +/** + * Add a 16-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 16-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16, + &value); +} + + +/** + * Add a 32-bit signed integer to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 32-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32, + &value); +} + + +/** + * Add a 32-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 32-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32, + &value); +} + + +/** + * Add a 64-bit integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 64-bit integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64, + &value); +} + + +/** + * Add a 64-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 64-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, + &value); +} + + +/** + * Add a double-precision floating point entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The double-precision floating point value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, const double value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, + &value); +} + + +/** + * Add a DBus object path entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The DBus object path value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value) +{ + if (!value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_OBJECT_PATH, &value); +} + + +/** + * Add a byte array entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The byte array + * @param value_len The length of the byte array, in bytes + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len) +{ + if (!key) + return FALSE; + if (!value && (value_len != 0)) + return FALSE; + return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value, + value_len); +} + + +/** + * Begin a string array entry in the dict + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param iter_dict_entry A private DBusMessageIter provided by the caller to + * be passed to wpa_dbus_dict_end_string_array() + * @param iter_dict_val A private DBusMessageIter provided by the caller to + * be passed to wpa_dbus_dict_end_string_array() + * @param iter_array On return, the DBusMessageIter to be passed to + * wpa_dbus_dict_string_array_add_element() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_STRING_AS_STRING, + iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + iter_array)) + return FALSE; + + return TRUE; +} + + +/** + * Add a single string element to a string array dict entry + * + * @param iter_array A valid DBusMessageIter returned from + * wpa_dbus_dict_begin_string_array()'s + * iter_array parameter + * @param elem The string element to be added to the dict entry's string array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem) +{ + if (!iter_array || !elem) + return FALSE; + + return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING, + &elem); +} + + +/** + * End a string array dict entry + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param iter_dict_entry A private DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @param iter_dict_val A private DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @param iter_array A DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!dbus_message_iter_close_container(iter_dict_val, iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry, + iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Convenience function to add an entire string array to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param items The array of strings + * @param num_items The number of strings in the array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!key) + return FALSE; + if (!items && (num_items != 0)) + return FALSE; + + if (!wpa_dbus_dict_begin_string_array(iter_dict, key, + &iter_dict_entry, &iter_dict_val, + &iter_array)) + return FALSE; + + for (i = 0; i < num_items; i++) { + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + items[i])) + return FALSE; + } + + if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry, + &iter_dict_val, &iter_array)) + return FALSE; + + return TRUE; +} + + +/*****************************************************/ +/* Stuff for reading dicts */ +/*****************************************************/ + +/** + * Start reading from a dbus dict. + * + * @param iter A valid DBusMessageIter pointing to the start of the dict + * @param iter_dict (out) A DBusMessageIter to be passed to + * wpa_dbus_dict_read_next_entry() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) + return FALSE; + + dbus_message_iter_recurse(iter, iter_dict); + return TRUE; +} + + +#define BYTE_ARRAY_CHUNK_SIZE 34 +#define BYTE_ARRAY_ITEM_SIZE (sizeof(char)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( + DBusMessageIter *iter, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_bool_t success = FALSE; + char *buffer, *nbuffer;; + + entry->bytearray_value = NULL; + entry->array_type = DBUS_TYPE_BYTE; + + buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE); + if (!buffer) + return FALSE; + + entry->bytearray_value = buffer; + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) { + char byte; + + if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) { + nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE * + (count + BYTE_ARRAY_CHUNK_SIZE)); + if (nbuffer == NULL) { + os_free(buffer); + wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" + "entry_get_byte_array out of " + "memory trying to retrieve the " + "string array"); + goto done; + } + buffer = nbuffer; + } + entry->bytearray_value = buffer; + + dbus_message_iter_get_basic(iter, &byte); + entry->bytearray_value[count] = byte; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + + /* Zero-length arrays are valid. */ + if (entry->array_len == 0) { + os_free(entry->bytearray_value); + entry->bytearray_value = NULL; + } + + success = TRUE; + +done: + return success; +} + + +#define STR_ARRAY_CHUNK_SIZE 8 +#define STR_ARRAY_ITEM_SIZE (sizeof(char *)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( + DBusMessageIter *iter, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_bool_t success = FALSE; + char **buffer, **nbuffer; + + entry->strarray_value = NULL; + entry->array_type = DBUS_TYPE_STRING; + + buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE); + if (buffer == NULL) + return FALSE; + + entry->strarray_value = buffer; + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { + const char *value; + char *str; + + if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) { + nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE * + (count + STR_ARRAY_CHUNK_SIZE)); + if (nbuffer == NULL) { + os_free(buffer); + wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" + "entry_get_string_array out of " + "memory trying to retrieve the " + "string array"); + goto done; + } + buffer = nbuffer; + } + entry->strarray_value = buffer; + + dbus_message_iter_get_basic(iter, &value); + str = os_strdup(value); + if (str == NULL) { + wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_" + "string_array out of memory trying to " + "duplicate the string array"); + goto done; + } + entry->strarray_value[count] = str; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + + /* Zero-length arrays are valid. */ + if (entry->array_len == 0) { + os_free(entry->strarray_value); + entry->strarray_value = NULL; + } + + success = TRUE; + +done: + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_entry_get_array( + DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry) +{ + int array_type = dbus_message_iter_get_element_type(iter_dict_val); + dbus_bool_t success = FALSE; + DBusMessageIter iter_array; + + if (!entry) + return FALSE; + + dbus_message_iter_recurse(iter_dict_val, &iter_array); + + switch (array_type) { + case DBUS_TYPE_BYTE: + success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, + array_type, + entry); + break; + case DBUS_TYPE_STRING: + success = _wpa_dbus_dict_entry_get_string_array(&iter_array, + array_type, + entry); + break; + default: + break; + } + + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant( + struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter) +{ + const char *v; + + switch (entry->type) { + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: + dbus_message_iter_get_basic(iter, &v); + entry->str_value = os_strdup(v); + if (entry->str_value == NULL) + return FALSE; + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(iter, &entry->bool_value); + break; + case DBUS_TYPE_BYTE: + dbus_message_iter_get_basic(iter, &entry->byte_value); + break; + case DBUS_TYPE_INT16: + dbus_message_iter_get_basic(iter, &entry->int16_value); + break; + case DBUS_TYPE_UINT16: + dbus_message_iter_get_basic(iter, &entry->uint16_value); + break; + case DBUS_TYPE_INT32: + dbus_message_iter_get_basic(iter, &entry->int32_value); + break; + case DBUS_TYPE_UINT32: + dbus_message_iter_get_basic(iter, &entry->uint32_value); + break; + case DBUS_TYPE_INT64: + dbus_message_iter_get_basic(iter, &entry->int64_value); + break; + case DBUS_TYPE_UINT64: + dbus_message_iter_get_basic(iter, &entry->uint64_value); + break; + case DBUS_TYPE_DOUBLE: + dbus_message_iter_get_basic(iter, &entry->double_value); + break; + case DBUS_TYPE_ARRAY: + return _wpa_dbus_dict_entry_get_array(iter, entry); + default: + return FALSE; + } + + return TRUE; +} + + +/** + * Read the current key/value entry from the dict. Entries are dynamically + * allocated when needed and must be freed after use with the + * wpa_dbus_dict_entry_clear() function. + * + * The returned entry object will be filled with the type and value of the next + * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error + * occurred. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_read() + * @param entry A valid dict entry object into which the dict key and value + * will be placed + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, + struct wpa_dbus_dict_entry * entry) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + int type; + const char *key; + + if (!iter_dict || !entry) + goto error; + + if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) + goto error; + + dbus_message_iter_recurse(iter_dict, &iter_dict_entry); + dbus_message_iter_get_basic(&iter_dict_entry, &key); + entry->key = key; + + if (!dbus_message_iter_next(&iter_dict_entry)) + goto error; + type = dbus_message_iter_get_arg_type(&iter_dict_entry); + if (type != DBUS_TYPE_VARIANT) + goto error; + + dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val); + entry->type = dbus_message_iter_get_arg_type(&iter_dict_val); + if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) + goto error; + + dbus_message_iter_next(iter_dict); + return TRUE; + +error: + if (entry) { + wpa_dbus_dict_entry_clear(entry); + entry->type = DBUS_TYPE_INVALID; + entry->array_type = DBUS_TYPE_INVALID; + } + + return FALSE; +} + + +/** + * Return whether or not there are additional dictionary entries. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_read() + * @return TRUE if more dict entries exists, FALSE if no more dict entries + * exist + */ +dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict) +{ + if (!iter_dict) + return FALSE; + return dbus_message_iter_get_arg_type(iter_dict) == + DBUS_TYPE_DICT_ENTRY; +} + + +/** + * Free any memory used by the entry object. + * + * @param entry The entry object + */ +void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) +{ + unsigned int i; + + if (!entry) + return; + switch (entry->type) { + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: + os_free(entry->str_value); + break; + case DBUS_TYPE_ARRAY: + switch (entry->array_type) { + case DBUS_TYPE_BYTE: + os_free(entry->bytearray_value); + break; + case DBUS_TYPE_STRING: + for (i = 0; i < entry->array_len; i++) + os_free(entry->strarray_value[i]); + os_free(entry->strarray_value); + break; + } + break; + } + + memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); +} diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h new file mode 100644 index 0000000..eb31575 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_dict_helpers.h @@ -0,0 +1,137 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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 DBUS_DICT_HELPERS_H +#define DBUS_DICT_HELPERS_H + +/* + * Adding a dict to a DBusMessage + */ + +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +const char * wpa_dbus_type_as_string(const int type); + +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value); + +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, + const dbus_bool_t value); + +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value); + +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value); + +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value); + +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value); + +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value); + +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value); + +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, + const double value); + +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len); + +/* Manual construction and addition of string array elements */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem); + +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +/* Convenience function to add a whole string list */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items); + +/* + * Reading a dict from a DBusMessage + */ + +struct wpa_dbus_dict_entry { + int type; /** the dbus type of the dict entry's value */ + int array_type; /** the dbus type of the array elements if the dict + entry value contains an array */ + const char *key; /** key of the dict entry */ + + /** Possible values of the property */ + union { + char *str_value; + char byte_value; + dbus_bool_t bool_value; + dbus_int16_t int16_value; + dbus_uint16_t uint16_value; + dbus_int32_t int32_value; + dbus_uint32_t uint32_value; + dbus_int64_t int64_value; + dbus_uint64_t uint64_value; + double double_value; + char *bytearray_value; + char **strarray_value; + }; + dbus_uint32_t array_len; /** length of the array if the dict entry's + value contains an array */ +}; + +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, + struct wpa_dbus_dict_entry *entry); + +dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict); + +void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry); + +#endif /* DBUS_DICT_HELPERS_H */ diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c new file mode 100644 index 0000000..49a0895 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new.c @@ -0,0 +1,1605 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This 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 "wps/wps.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../bss.h" +#include "dbus_new_helpers.h" +#include "dbus_dict_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_common.h" +#include "dbus_common_i.h" + + +/** + * wpas_dbus_signal_interface - Send a interface related event signal + * @wpa_s: %wpa_supplicant network interface data + * @sig_name: signal name - InterfaceAdded or InterfaceRemoved + * @properties: Whether to add second argument with object properties + * + * Notify listeners about event related with interface + */ +static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s, + const char *sig_name, int properties) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, iter_dict; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, sig_name); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &wpa_s->dbus_new_path)) + goto err; + + if (properties) { + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto err; + + wpa_dbus_get_object_properties(iface, wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + &iter_dict); + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto err; + } + + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); + return; + +err: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_interface_added - Send a interface created signal + * @wpa_s: %wpa_supplicant network interface data + * + * Notify listeners about creating new interface + */ +static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE); +} + + +/** + * 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", FALSE); + +} + + +/** + * 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 + */ +void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + dbus_bool_t succ; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "ScanDone"); + if (msg == NULL) + return; + + succ = success ? TRUE : FALSE; + if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ, + DBUS_TYPE_INVALID)) + dbus_connection_send(iface->con, msg, NULL); + else + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * 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 + * @properties: Whether to add second argument with object properties + * + * 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, int properties) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, iter_dict; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &bss_obj_path)) + goto err; + + if (properties) { + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto err; + + wpa_dbus_get_object_properties(iface, bss_obj_path, + WPAS_DBUS_NEW_IFACE_BSS, + &iter_dict); + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto err; + } + + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); + return; + +err: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * 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", TRUE); +} + + +/** + * 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", FALSE); +} + + +/** + * 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 wpas_dbus_priv *iface; + DBusMessage *msg; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (msg == NULL) + return; + + if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + dbus_connection_send(iface->con, msg, NULL); + else + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * 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 + */ +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 + */ +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 + * @properties: determines if add second argument with object properties + * + * 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, + int properties) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, iter_dict; + char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, id); + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + sig_name); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + path = net_obj_path; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path)) + goto err; + + if (properties) { + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto err; + + wpa_dbus_get_object_properties(iface, net_obj_path, + WPAS_DBUS_NEW_IFACE_NETWORK, + &iter_dict); + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto err; + } + + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); + return; + +err: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * 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", TRUE); +} + + +/** + * wpas_dbus_signal_network_removed - 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", FALSE); +} + + +/** + * 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 + */ +void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id) +{ + wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE); +} + + +/** + * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes + * @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 + */ +void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + + char path[WPAS_DBUS_OBJECT_PATH_MAX]; + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + + wpa_dbus_mark_property_changed(wpa_s->global->dbus, 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 + */ +void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s) +{ + + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char *key = "success"; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_WPS, "Event"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &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, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + +/** + * 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 + */ +void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail) +{ + + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char *key = "fail"; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_WPS, "Event"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &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, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + +/** + * 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. + */ +void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d) +{ + + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char *key = "m2d"; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_WPS, "Event"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &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, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_wps_cred - Signals new credentials + * @wpa_s: %wpa_supplicant network interface data + * + * Sends signal with credentials in directory argument + */ +void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + 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; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_WPS, + "Credentials"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + 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)) + 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) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + +#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. + */ +void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_prop property) +{ + WPADBusPropertyAccessor getter; + char *prop; + + if (wpa_s->dbus_new_path == NULL) + return; /* Skip signal since D-Bus setup is not yet ready */ + + switch (property) { + case WPAS_DBUS_PROP_AP_SCAN: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan; + prop = "ApScan"; + break; + case WPAS_DBUS_PROP_SCANNING: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning; + prop = "Scanning"; + break; + case WPAS_DBUS_PROP_STATE: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_state; + prop = "State"; + break; + case WPAS_DBUS_PROP_CURRENT_BSS: + getter = (WPADBusPropertyAccessor) + wpas_dbus_getter_current_bss; + prop = "CurrentBSS"; + break; + case WPAS_DBUS_PROP_CURRENT_NETWORK: + getter = (WPADBusPropertyAccessor) + wpas_dbus_getter_current_network; + prop = "CurrentNetwork"; + break; + case WPAS_DBUS_PROP_BSSS: + getter = (WPADBusPropertyAccessor) wpas_dbus_getter_bsss; + prop = "BSSs"; + break; + case WPAS_DBUS_PROP_CURRENT_AUTH_MODE: + getter = (WPADBusPropertyAccessor) + wpas_dbus_getter_current_auth_mode; + prop = "CurrentAuthMode"; + break; + default: + wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", + __func__, property); + return; + } + + wpa_dbus_mark_property_changed(wpa_s->global->dbus, + wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, prop); +} + + +/** + * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property + * @wpa_s: %wpa_supplicant network interface data + * @property: indicates which property has changed + * @id: unique BSS identifier + * + * Sends PropertyChanged signals with path, interface, and arguments depending + * on which property has changed. + */ +void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_bss_prop property, + unsigned int id) +{ + char path[WPAS_DBUS_OBJECT_PATH_MAX]; + char *prop; + + switch (property) { + case WPAS_DBUS_BSS_PROP_SIGNAL: + prop = "Signal"; + break; + case WPAS_DBUS_BSS_PROP_FREQ: + prop = "Frequency"; + break; + case WPAS_DBUS_BSS_PROP_MODE: + prop = "Mode"; + break; + case WPAS_DBUS_BSS_PROP_PRIVACY: + prop = "Privacy"; + break; + case WPAS_DBUS_BSS_PROP_RATES: + prop = "Rates"; + break; + case WPAS_DBUS_BSS_PROP_WPA: + prop = "WPA"; + break; + case WPAS_DBUS_BSS_PROP_RSN: + prop = "RSN"; + break; + case WPAS_DBUS_BSS_PROP_IES: + prop = "IEs"; + break; + default: + wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", + __func__, property); + return; + } + + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, id); + + wpa_dbus_mark_property_changed(wpa_s->global->dbus, path, + WPAS_DBUS_NEW_IFACE_BSS, prop); +} + + +/** + * wpas_dbus_signal_debug_level_changed - Signals change of debug param + * @global: wpa_global structure + * + * Sends ProertyChanged signals informing that debug level has changed. + */ +void wpas_dbus_signal_debug_level_changed(struct wpa_global *global) +{ + wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, + "DebugLevel"); +} + + +/** + * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param + * @global: wpa_global structure + * + * Sends ProertyChanged signals informing that debug timestamp has changed. + */ +void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global) +{ + wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, + "DebugTimestamp"); +} + + +/** + * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param + * @global: wpa_global structure + * + * Sends ProertyChanged signals informing that debug show_keys has changed. + */ +void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global) +{ + wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_INTERFACE, + "DebugShowKeys"); +} + + +static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc, + void *priv, + WPADBusArgumentFreeFunction priv_free, + const struct wpa_dbus_method_desc *methods, + const struct wpa_dbus_property_desc *properties, + const struct wpa_dbus_signal_desc *signals) +{ + int n; + + obj_desc->user_data = priv; + obj_desc->user_data_free_func = priv_free; + obj_desc->methods = methods; + obj_desc->properties = properties; + obj_desc->signals = signals; + + for (n = 0; properties && properties->dbus_property; properties++) + n++; + + obj_desc->prop_changed_flags = os_zalloc(n); + if (!obj_desc->prop_changed_flags) + wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers", + __func__); +} + + +static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = { + { "CreateInterface", WPAS_DBUS_NEW_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_create_interface, + { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "RemoveInterface", WPAS_DBUS_NEW_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface, + { + { "path", "o", ARG_IN }, + END_ARGS + } + }, + { "GetInterface", WPAS_DBUS_NEW_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_get_interface, + { + { "ifname", "s", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, NULL, { END_ARGS } } +}; + +static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = { + { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level, + (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level, + RW + }, + { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp, + (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp, + RW + }, + { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys, + (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys, + RW + }, + { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao", + (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces, + NULL, + R + }, + { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as", + (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods, + NULL, + R + }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; + +static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = { + { "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, { END_ARGS } } +}; + + +/** + * wpas_dbus_ctrl_iface_init - Initialize dbus control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: 0 on success or -1 on failure + * + * Initialize the dbus control interface for wpa_supplicantand and start + * receiving commands from external programs over the bus. + */ +int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv) +{ + struct wpa_dbus_object_desc *obj_desc; + int ret; + + 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 -1; + } + + wpas_dbus_register(obj_desc, priv->global, NULL, + wpas_dbus_global_methods, + wpas_dbus_global_properties, + wpas_dbus_global_signals); + + wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'", + WPAS_DBUS_NEW_PATH); + ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH, + WPAS_DBUS_NEW_SERVICE, + obj_desc); + if (ret < 0) + free_dbus_object_desc(obj_desc); + else + priv->dbus_new_initialized = 1; + + return ret; +} + + +/** + * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for + * wpa_supplicant + * @iface: Pointer to dbus private data from wpas_dbus_init() + * + * Deinitialize the dbus control interface that was initialized with + * wpas_dbus_ctrl_iface_init(). + */ +void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface) +{ + if (!iface->dbus_new_initialized) + return; + wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'", + WPAS_DBUS_NEW_PATH); + dbus_connection_unregister_object_path(iface->con, + WPAS_DBUS_NEW_PATH); +} + + +static void wpa_dbus_free(void *ptr) +{ + os_free(ptr); +} + + +static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = { + { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}", + (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties, + (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties, + RW + }, + { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_enabled, + (WPADBusPropertyAccessor) wpas_dbus_setter_enabled, + RW + }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; + + +static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = { + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, { END_ARGS } } +}; + + +/** + * 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 + */ +int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + struct network_handler_args *arg; + char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + + /* 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; + if (ctrl_iface == NULL) + return 0; + + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, ssid->id); + + wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'", + net_obj_path); + 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 */ + arg = os_zalloc(sizeof(struct network_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for method"); + goto err; + } + + arg->wpa_s = wpa_s; + arg->ssid = ssid; + + wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, + wpas_dbus_network_properties, + wpas_dbus_network_signals); + + 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); + + return 0; + +err: + free_dbus_object_desc(obj_desc); + 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 + */ +int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid) +{ + struct wpas_dbus_priv *ctrl_iface; + char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + int ret; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL || + wpa_s->dbus_new_path == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return 0; + + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, nid); + + wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'", + net_obj_path); + ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path); + + if (!ret) + wpas_dbus_signal_network_removed(wpa_s, nid); + + return ret; +} + + +static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = { + { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid, + NULL, + R + }, + { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid, + NULL, + R + }, + { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy, + NULL, + R + }, + { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode, + NULL, + R + }, + { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal, + NULL, + R + }, + { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency, + NULL, + R + }, + { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rates, + NULL, + R + }, + { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpa, + NULL, + R + }, + { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsn, + NULL, + R + }, + { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ies, + NULL, + R + }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; + + +static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = { + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, { END_ARGS } } +}; + + +/** + * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus + * @wpa_s: wpa_supplicant interface structure + * @bssid: scanned network bssid + * @id: unique BSS identifier + * Returns: 0 on success, -1 on failure + * + * Unregisters BSS representing object from dbus + */ +int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id) +{ + struct wpas_dbus_priv *ctrl_iface; + char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + + /* 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; + if (ctrl_iface == NULL) + return 0; + + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, id); + + wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'", + bss_obj_path); + if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) { + wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s", + bss_obj_path); + return -1; + } + + wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path); + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS); + + return 0; +} + + +/** + * wpas_dbus_register_bss - Register a scanned BSS with dbus + * @wpa_s: wpa_supplicant interface structure + * @bssid: scanned network bssid + * @id: unique BSS identifier + * Returns: 0 on success, -1 on failure + * + * Registers BSS representing object with dbus + */ +int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + struct bss_handler_args *arg; + + /* 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; + if (ctrl_iface == NULL) + return 0; + + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, 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; + } + + 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; + arg->id = id; + + wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, + wpas_dbus_bss_properties, + wpas_dbus_bss_signals); + + wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'", + bss_obj_path); + 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); + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS); + + return 0; + +err: + free_dbus_object_desc(obj_desc); + return -1; +} + + +static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { + { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_scan, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_disconnect, + { + END_ARGS + } + }, + { "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_add_network, + { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_remove_network, + { + { "path", "o", ARG_IN }, + END_ARGS + } + }, + { "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks, + { + END_ARGS + } + }, + { "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_select_network, + { + { "path", "o", ARG_IN }, + END_ARGS + } + }, + { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_add_blob, + { + { "name", "s", ARG_IN }, + { "data", "ay", ARG_IN }, + END_ARGS + } + }, + { "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_get_blob, + { + { "name", "s", ARG_IN }, + { "data", "ay", ARG_OUT }, + END_ARGS + } + }, + { "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob, + { + { "name", "s", ARG_IN }, + END_ARGS + } + }, +#ifdef CONFIG_WPS + { "Start", WPAS_DBUS_NEW_IFACE_WPS, + (WPADBusMethodHandler) &wpas_dbus_handler_wps_start, + { + { "args", "a{sv}", ARG_IN }, + { "output", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_WPS */ + { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss, + { + { "age", "u", ARG_IN }, + END_ARGS + } + }, + { NULL, NULL, NULL, { END_ARGS } } +}; + +static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { + { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}", + (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities, + NULL, R + }, + { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_state, + NULL, R + }, + { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_scanning, + NULL, R + }, + { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan, + (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan, + RW + }, + { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_age, + (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_age, + RW + }, + { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_count, + (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_count, + RW + }, + { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_country, + (WPADBusPropertyAccessor) wpas_dbus_setter_country, + RW + }, + { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_ifname, + NULL, R + }, + { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_driver, + NULL, R + }, + { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname, + NULL, R + }, + { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", + (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss, + NULL, R + }, + { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", + (WPADBusPropertyAccessor) wpas_dbus_getter_current_network, + NULL, R + }, + { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + (WPADBusPropertyAccessor) wpas_dbus_getter_current_auth_mode, + NULL, R + }, + { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}", + (WPADBusPropertyAccessor) wpas_dbus_getter_blobs, + NULL, R + }, + { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", + (WPADBusPropertyAccessor) wpas_dbus_getter_bsss, + NULL, R + }, + { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", + (WPADBusPropertyAccessor) wpas_dbus_getter_networks, + NULL, R + }, +#ifdef CONFIG_WPS + { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b", + (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials, + (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials, + RW + }, +#endif /* CONFIG_WPS */ + { NULL, NULL, NULL, NULL, NULL, 0 } +}; + +static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { + { "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "success", "b", ARG_OUT }, + END_ARGS + } + }, + { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "name", "s", ARG_OUT }, + END_ARGS + } + }, + { "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "name", "s", ARG_OUT }, + END_ARGS + } + }, + { "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#ifdef CONFIG_WPS + { "Event", WPAS_DBUS_NEW_IFACE_WPS, + { + { "name", "s", ARG_OUT }, + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "Credentials", WPAS_DBUS_NEW_IFACE_WPS, + { + { "credentials", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_WPS */ + { NULL, NULL, { END_ARGS } } +}; + + +int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) +{ + + struct wpa_dbus_object_desc *obj_desc = NULL; + struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; + int next; + + /* Do nothing if the control interface is not turned on */ + if (ctrl_iface == NULL) + return 0; + + /* Create and set the interface's object path */ + wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (wpa_s->dbus_new_path == NULL) + return -1; + next = ctrl_iface->next_objid++; + os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX, + WPAS_DBUS_NEW_PATH_INTERFACES "/%u", + next); + + 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; + } + + wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods, + wpas_dbus_interface_properties, + wpas_dbus_interface_signals); + + wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'", + wpa_s->dbus_new_path); + if (wpa_dbus_register_object_per_iface(ctrl_iface, + wpa_s->dbus_new_path, + wpa_s->ifname, obj_desc)) + goto err; + + wpas_dbus_signal_interface_added(wpa_s); + + return 0; + +err: + os_free(wpa_s->dbus_new_path); + wpa_s->dbus_new_path = NULL; + free_dbus_object_desc(obj_desc); + return -1; +} + + +int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *ctrl_iface; + + /* 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; + if (ctrl_iface == NULL) + return 0; + + wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'", + wpa_s->dbus_new_path); + if (wpa_dbus_unregister_object_per_iface(ctrl_iface, + wpa_s->dbus_new_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; +} diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h new file mode 100644 index 0000000..377e381 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new.h @@ -0,0 +1,236 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * + * 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 wpa_states; + +enum wpas_dbus_prop { + WPAS_DBUS_PROP_AP_SCAN, + WPAS_DBUS_PROP_SCANNING, + WPAS_DBUS_PROP_STATE, + WPAS_DBUS_PROP_CURRENT_BSS, + WPAS_DBUS_PROP_CURRENT_NETWORK, + WPAS_DBUS_PROP_CURRENT_AUTH_MODE, + WPAS_DBUS_PROP_BSSS, +}; + +enum wpas_dbus_bss_prop { + WPAS_DBUS_BSS_PROP_SIGNAL, + WPAS_DBUS_BSS_PROP_FREQ, + WPAS_DBUS_BSS_PROP_MODE, + WPAS_DBUS_BSS_PROP_PRIVACY, + WPAS_DBUS_BSS_PROP_RATES, + WPAS_DBUS_BSS_PROP_WPA, + WPAS_DBUS_BSS_PROP_RSN, + WPAS_DBUS_BSS_PROP_IES, +}; + +#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_INTERFACE ".Network" + +#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" +#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_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_INTERFACE ".NotConnected" +#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \ + WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown" + +#define WPAS_DBUS_ERROR_BLOB_EXISTS \ + WPAS_DBUS_NEW_INTERFACE ".BlobExists" +#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \ + WPAS_DBUS_NEW_INTERFACE ".BlobUnknown" + + +#ifdef CONFIG_CTRL_IFACE_DBUS_NEW + +int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv); +void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface); + +int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s); +int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s); +void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_prop property); +void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_bss_prop property, + unsigned int id); +void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id); +void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success); +void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); +void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d); +void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail); +void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s); +int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid); +int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id); +int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id); +void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, + const char *name); +void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, + const char *name); +void wpas_dbus_signal_debug_level_changed(struct wpa_global *global); +void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global); +void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global); + +#else /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#define wpas_dbus_signal_state_changed(w, n, o) do { } while (0) + +static inline void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, + enum wpas_dbus_prop property) +{ +} + +static inline void wpas_dbus_bss_signal_prop_changed( + struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property, + unsigned int id) +{ +} + +static inline void wpas_dbus_signal_network_enabled_changed( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) +{ +} + +static inline void wpas_dbus_signal_network_selected( + struct wpa_supplicant *wpa_s, int id) +{ +} + +static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, + int success) +{ +} + +static inline void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ +} + +static inline void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d) +{ +} + +static inline void wpas_dbus_signal_wps_event_fail( + struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) +{ +} + +static inline void wpas_dbus_signal_wps_event_success( + struct wpa_supplicant *wpa_s) +{ +} + +static inline int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + return 0; +} + +static inline int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, + int nid) +{ + return 0; +} + +static inline int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id) +{ + return 0; +} + +static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, + u8 bssid[ETH_ALEN], unsigned int id) +{ + return 0; +} + +static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, + const char *name) +{ +} + +static inline void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, + const char *name) +{ +} + +static inline void wpas_dbus_signal_debug_level_changed( + struct wpa_global *global) +{ +} + +static inline void wpas_dbus_signal_debug_timestamp_changed( + struct wpa_global *global) +{ +} + +static inline void wpas_dbus_signal_debug_show_keys_changed( + struct wpa_global *global) +{ +} + +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c new file mode 100644 index 0000000..68e5465 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -0,0 +1,3228 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This 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 "common/ieee802_11_defs.h" +#include "eap_peer/eap_methods.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "rsn_supp/wpa.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../driver_i.h" +#include "../notify.h" +#include "../wpas_glue.h" +#include "../bss.h" +#include "../scan.h" +#include "dbus_new_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_dict_helpers.h" + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + +static const char *debug_strings[] = { + "excessive", "msgdump", "debug", "info", "warning", "error", NULL +}; + + +/** + * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts + * @path: The dbus object path + * @network: (out) the configured network this object path refers to, if any + * @bssid: (out) the scanned bssid this object path refers to, if any + * Returns: The object path of the network interface this path refers to + * + * For a given object path, decomposes the object path into object id, network, + * and BSSID parts, if those parts exist. + */ +static char * wpas_dbus_new_decompose_object_path(const char *path, + char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/"); + char *obj_path_only; + char *next_sep; + + /* Be a bit paranoid about path */ + if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/", + dev_path_prefix_len)) + return NULL; + + /* Ensure there's something at the end of the path */ + if ((path + dev_path_prefix_len)[0] == '\0') + return NULL; + + obj_path_only = os_strdup(path); + if (obj_path_only == NULL) + return NULL; + + next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/'); + if (next_sep != NULL) { + const char *net_part = os_strstr( + next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/"); + const char *bssid_part = os_strstr( + next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/"); + + if (network && net_part) { + /* Deal with a request for a configured network */ + const char *net_name = net_part + + os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/"); + *network = NULL; + if (os_strlen(net_name)) + *network = os_strdup(net_name); + } else if (bssid && bssid_part) { + /* Deal with a request for a scanned BSSID */ + const char *bssid_name = bssid_part + + os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/"); + if (strlen(bssid_name)) + *bssid = os_strdup(bssid_name); + else + *bssid = NULL; + } + + /* Cut off interface object path before "/" */ + *next_sep = '\0'; + } + + return obj_path_only; +} + + +/** + * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message + * @message: Pointer to incoming dbus message this error refers to + * @arg: Optional string appended to error message + * Returns: a dbus error message + * + * Convenience function to create and return an UnknownError + */ +DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, + const char *arg) +{ + /* + * This function can be called as a result of a failure + * within internal getter calls, which will call this function + * with a NULL message parameter. However, dbus_message_new_error + * looks very unkindly (i.e, abort()) on a NULL message, so + * in this case, we should not call it. + */ + if (message == NULL) { + wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error " + "called with NULL message (arg=%s)", + arg ? arg : "N/A"); + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR, + arg); +} + + +/** + * wpas_dbus_error_iface_unknown - Return a new invalid interface error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: A dbus error message + * + * Convenience function to create and return an invalid interface error + */ +static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, + "wpa_supplicant knows nothing about " + "this interface."); +} + + +/** + * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid network error + */ +static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, + "There is no such a network in this " + "interface."); +} + + +/** + * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid options error + */ +DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, + const char *arg) +{ + DBusMessage *reply; + + reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS, + "Did not receive correct message " + "arguments."); + if (arg != NULL) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + return reply; +} + + +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 (os_strcmp(key, dont_quote[i]) == 0) + return FALSE; + i++; + } + return TRUE; +} + +/** + * get_iface_by_dbus_path - Get a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @path: Pointer to a dbus object path representing an interface + * Returns: Pointer to the interface or %NULL if not found + */ +static struct wpa_supplicant * get_iface_by_dbus_path( + struct wpa_global *global, const char *path) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (os_strcmp(wpa_s->dbus_new_path, path) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * set_network_properties - Set properties of a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * @iter: DBus message iterator containing dictionary of network + * properties to set. + * Returns: NULL when succeed or DBus error on failure + * + * Sets network configuration with parameters given id DBus dictionary + */ +static DBusMessage * set_network_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + DBusMessageIter *iter) +{ + + 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)) + return wpas_dbus_error_invalid_args(message, NULL); + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + char *value = NULL; + size_t size = 50; + int ret; + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_error_invalid_args(message, NULL); + break; + } + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = os_strlen(entry.str_value); + if (size <= 0) + goto error; + + size += 3; + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "\"%s\"", + entry.str_value); + if (ret < 0 || (size_t) ret != (size - 1)) + goto error; + } else { + value = os_strdup(entry.str_value); + if (value == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "%u", + entry.uint32_value); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "%d", + entry.int32_value); + if (ret <= 0) + goto error; + } else + goto error; + + if (wpa_config_set(ssid, entry.key, value, 0) < 0) + goto error; + + if ((os_strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + else if (os_strcmp(entry.key, "priority") == 0) + wpa_config_update_prio_list(wpa_s->conf); + + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + continue; + + error: + os_free(value); + reply = wpas_dbus_error_invalid_args(message, entry.key); + wpa_dbus_dict_entry_clear(&entry); + break; + } + + return reply; +} + + +/** + * wpas_dbus_simple_property_getter - Get basic type property + * @message: Pointer to incoming dbus message + * @type: DBus type of property (must be basic type) + * @val: pointer to place holding property value + * Returns: The DBus message containing response for Properties.Get call + * or DBus error message if error occurred. + * + * Generic getter for basic type properties. Type is required to be basic. + */ +DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message, + const int type, const void *val) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter; + + if (!dbus_type_is_basic(type)) { + wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:" + " given type is not basic"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + + if (reply != NULL) { + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container( + &iter, DBUS_TYPE_VARIANT, + wpa_dbus_type_as_string(type), &variant_iter) || + !dbus_message_iter_append_basic(&variant_iter, type, + val) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_property_getter: out of " + "memory to put property value into " + "message"); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + } + } else { + wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:" + " out of memory to return property value"); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + return reply; +} + + +/** + * wpas_dbus_simple_property_setter - Set basic type property + * @message: Pointer to incoming dbus message + * @type: DBus type of property (must be basic type) + * @val: pointer to place where value being set will be stored + * Returns: NULL or DBus error message if error occurred. + * + * Generic setter for basic type properties. Type is required to be basic. + */ +DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message, + const int type, void *val) +{ + DBusMessageIter iter, variant_iter; + + if (!dbus_type_is_basic(type)) { + wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:" + " given type is not basic"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + if (!dbus_message_iter_init(message, &iter)) { + wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:" + " out of memory to return scanning state"); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + /* 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) != type) { + wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:" + " wrong property type"); + return wpas_dbus_error_invalid_args(message, + "wrong property type"); + } + dbus_message_iter_get_basic(&variant_iter, val); + + return NULL; +} + + +/** + * wpas_dbus_simple_array_property_getter - Get array type property + * @message: Pointer to incoming dbus message + * @type: DBus type of property array elements (must be basic type) + * @array: pointer to array of elements to put into response message + * @array_len: length of above array + * Returns: The DBus message containing response for Properties.Get call + * or DBus error message if error occurred. + * + * Generic getter for array type properties. Array elements type is + * required to be basic. + */ +DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message, + const int type, + const void *array, + size_t array_len) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, variant_iter, array_iter; + char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ + const char *sub_type_str; + size_t element_size, i; + + if (!dbus_type_is_basic(type)) { + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_array_property_getter: given " + "type is not basic"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + sub_type_str = wpa_dbus_type_as_string(type); + type_str[1] = sub_type_str[0]; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_array_property_getter: out of " + "memory to create return message"); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + type_str, &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + sub_type_str, &array_iter)) { + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_array_property_getter: out of " + "memory to open container"); + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + switch(type) { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + element_size = 1; + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + element_size = sizeof(uint16_t); + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + element_size = sizeof(uint32_t); + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + element_size = sizeof(uint64_t); + break; + case DBUS_TYPE_DOUBLE: + element_size = sizeof(double); + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + element_size = sizeof(char *); + break; + default: + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_array_property_getter: " + "fatal: unknown element type"); + element_size = 1; + break; + } + + for (i = 0; i < array_len; i++) { + dbus_message_iter_append_basic(&array_iter, type, + array + i * element_size); + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + wpa_printf(MSG_ERROR, "dbus: " + "wpas_dbus_simple_array_property_getter: out of " + "memory to close container"); + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + 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 "CreateInterface" method call. Handles requests + * by dbus clients to register a network interface that wpa_supplicant + * will manage. + */ +DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *driver = NULL; + char *ifname = NULL; + char *confname = NULL; + char *bridge_ifname = NULL; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + 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)) { + driver = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (driver == NULL) + goto error; + } else if (!strcmp(entry.key, "Ifname") && + (entry.type == DBUS_TYPE_STRING)) { + ifname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (ifname == NULL) + goto error; + } else if (!strcmp(entry.key, "ConfigFile") && + (entry.type == DBUS_TYPE_STRING)) { + confname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (confname == NULL) + goto error; + } else if (!strcmp(entry.key, "BridgeIfname") && + (entry.type == DBUS_TYPE_STRING)) { + bridge_ifname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (bridge_ifname == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + } + + if (ifname == NULL) + goto error; /* Required Ifname argument missing */ + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, ifname) != NULL) { + reply = dbus_message_new_error(message, + WPAS_DBUS_ERROR_IFACE_EXISTS, + "wpa_supplicant already " + "controls this interface."); + } else { + struct wpa_supplicant *wpa_s; + struct wpa_interface iface; + os_memset(&iface, 0, sizeof(iface)); + iface.driver = driver; + iface.ifname = ifname; + iface.confname = confname; + iface.bridge_ifname = bridge_ifname; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpa_s->dbus_new_path; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + } else { + reply = wpas_dbus_error_unknown_error( + message, "wpa_supplicant couldn't grab this " + "interface."); + } + } + +out: + os_free(driver); + os_free(ifname); + os_free(bridge_ifname); + return reply; + +error: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +/** + * wpas_dbus_handler_remove_interface - Request deregistration of an interface + * @message: Pointer to incoming dbus message + * @global: wpa_supplicant global data structure + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0), or returns a dbus error message with more information + * + * Handler function for "removeInterface" method call. Handles requests + * by dbus clients to deregister a network interface that wpa_supplicant + * currently manages. + */ +DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + char *path; + DBusMessage *reply = NULL; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + wpa_s = get_iface_by_dbus_path(global, path); + if (wpa_s == NULL) + reply = wpas_dbus_error_iface_unknown(message); + else if (wpa_supplicant_remove_iface(global, wpa_s)) { + reply = wpas_dbus_error_unknown_error( + message, "wpa_supplicant couldn't remove this " + "interface."); + } + + return reply; +} + + +/** + * wpas_dbus_handler_get_interface - Get the object path for an interface name + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the interface object, + * or a dbus error message with more information + * + * Handler function for "getInterface" method call. + */ +DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + const char *ifname; + const char *path; + struct wpa_supplicant *wpa_s; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID); + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) + return wpas_dbus_error_iface_unknown(message); + + path = wpa_s->dbus_new_path; + reply = dbus_message_new_method_return(message); + if (reply == NULL) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_debug_level - Get debug level + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: DBus message with value of debug level + * + * Getter for "DebugLevel" property. + */ +DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message, + struct wpa_global *global) +{ + const char *str; + int idx = wpa_debug_level; + if (idx < 0) + idx = 0; + if (idx > 5) + idx = 5; + str = debug_strings[idx]; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &str); +} + + +/** + * wpas_dbus_getter_debug_timestamp - Get debug timestamp + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: DBus message with value of debug timestamp + * + * Getter for "DebugTimestamp" property. + */ +DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message, + struct wpa_global *global) +{ + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &wpa_debug_timestamp); + +} + + +/** + * wpas_dbus_getter_debug_show_keys - Get debug show keys + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: DBus message with value of debug show_keys + * + * Getter for "DebugShowKeys" property. + */ +DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message, + struct wpa_global *global) +{ + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &wpa_debug_show_keys); + +} + +/** + * wpas_dbus_setter_debug_level - Set debug level + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: %NULL or DBus error message + * + * Setter for "DebugLevel" property. + */ +DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply; + const char *str = NULL; + int i, val = -1; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING, + &str); + if (reply) + return reply; + + for (i = 0; debug_strings[i]; i++) + if (os_strcmp(debug_strings[i], str) == 0) { + val = i; + break; + } + + if (val < 0 || + wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, + wpa_debug_show_keys)) { + return wpas_dbus_error_invalid_args( + message, "Wrong debug level value"); + } + + return NULL; +} + + +/** + * wpas_dbus_setter_debug_timestamp - Set debug timestamp + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: %NULL or DBus error message + * + * Setter for "DebugTimestamp" property. + */ +DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply; + dbus_bool_t val; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, + &val); + if (reply) + return reply; + + wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, + wpa_debug_show_keys); + + return NULL; +} + + +/** + * wpas_dbus_setter_debug_show_keys - Set debug show keys + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: %NULL or DBus error message + * + * Setter for "DebugShowKeys" property. + */ +DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply; + dbus_bool_t val; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, + &val); + if (reply) + return reply; + + wpa_supplicant_set_debug_params(global, wpa_debug_level, + wpa_debug_timestamp, + val ? 1 : 0); + + return NULL; +} + + +/** + * 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; + struct wpa_supplicant *wpa_s; + const char **paths; + unsigned int i = 0, num = 0; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) + num++; + + paths = os_zalloc(num * sizeof(char*)); + if (!paths) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) + paths[i++] = wpa_s->dbus_new_path; + + reply = wpas_dbus_simple_array_property_getter(message, + DBUS_TYPE_OBJECT_PATH, + paths, num); + + os_free(paths); + 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; + char **eap_methods; + size_t num_items = 0; + + eap_methods = eap_get_names_as_string_array(&num_items); + if (!eap_methods) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + reply = wpas_dbus_simple_array_property_getter(message, + DBUS_TYPE_STRING, + eap_methods, num_items); + + while (num_items) + os_free(eap_methods[--num_items]); + os_free(eap_methods); + return reply; +} + + +static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, + char **type, DBusMessage **reply) +{ + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Type must be a string"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Type value type. String required"); + return -1; + } + dbus_message_iter_get_basic(var, type); + return 0; +} + + +static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + struct wpa_driver_scan_ssid *ssids = params->ssids; + size_t ssids_num = 0; + u8 *ssid; + DBusMessageIter array_iter, sub_array_iter; + char *val; + int len; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " + "must be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong SSIDs value type. Array of arrays of " + "bytes required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) + { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " + "must be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong SSIDs value type. Array of arrays of " + "bytes required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) + { + if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Too many ssids specified on scan dbus " + "call"); + *reply = wpas_dbus_error_invalid_args( + message, "Too many ssids specified. Specify " + "at most four"); + return -1; + } + + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); + + if (len != 0) { + ssid = os_malloc(len); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, + "wpas_dbus_handler_scan[dbus]: " + "out of memory. Cannot allocate " + "memory for SSID"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + os_memcpy(ssid, val, len); + } else { + /* Allow zero-length SSIDs */ + ssid = NULL; + } + + ssids[ssids_num].ssid = ssid; + ssids[ssids_num].ssid_len = len; + + dbus_message_iter_next(&array_iter); + ssids_num++; + } + + params->num_ssids = ssids_num; + return 0; +} + + +static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + u8 *ies = NULL, *nies; + int ies_len = 0; + DBusMessageIter array_iter, sub_array_iter; + char *val; + int len; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " + "be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong IEs value type. Array of arrays of " + "bytes required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) + { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " + "be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong IEs value type. Array required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) + { + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); + if (len == 0) { + dbus_message_iter_next(&array_iter); + continue; + } + + nies = os_realloc(ies, ies_len + len); + if (nies == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. Cannot allocate memory for " + "IE"); + os_free(ies); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + ies = nies; + os_memcpy(ies + ies_len, val, len); + ies_len += len; + + dbus_message_iter_next(&array_iter); + } + + params->extra_ies = ies; + params->extra_ies_len = ies_len; + return 0; +} + + +static int wpas_dbus_get_scan_channels(DBusMessage *message, + DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + DBusMessageIter array_iter, sub_array_iter; + int *freqs = NULL, *nfreqs; + int freqs_num = 0; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channels must be an array of structs"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channels value type. Array of structs " + "required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_DEBUG, + "wpas_dbus_handler_scan[dbus]: Channels must be an " + "array of structs"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channels value type. Array of structs " + "required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT) + { + int freq, width; + + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + if (dbus_message_iter_get_arg_type(&sub_array_iter) != + DBUS_TYPE_UINT32) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channel must by specified by struct of " + "two UINT32s %c", + dbus_message_iter_get_arg_type( + &sub_array_iter)); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channel struct. Two UINT32s " + "required"); + os_free(freqs); + return -1; + } + dbus_message_iter_get_basic(&sub_array_iter, &freq); + + if (!dbus_message_iter_next(&sub_array_iter) || + dbus_message_iter_get_arg_type(&sub_array_iter) != + DBUS_TYPE_UINT32) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channel must by specified by struct of " + "two UINT32s"); + *reply = wpas_dbus_error_invalid_args( + message, + "Wrong Channel struct. Two UINT32s required"); + os_free(freqs); + return -1; + } + + dbus_message_iter_get_basic(&sub_array_iter, &width); + +#define FREQS_ALLOC_CHUNK 32 + if (freqs_num % FREQS_ALLOC_CHUNK == 0) { + nfreqs = os_realloc(freqs, sizeof(int) * + (freqs_num + FREQS_ALLOC_CHUNK)); + if (nfreqs == NULL) + os_free(freqs); + freqs = nfreqs; + } + if (freqs == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. can't allocate memory for " + "freqs"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + + freqs[freqs_num] = freq; + + freqs_num++; + dbus_message_iter_next(&array_iter); + } + + nfreqs = os_realloc(freqs, + sizeof(int) * (freqs_num + 1)); + if (nfreqs == NULL) + os_free(freqs); + freqs = nfreqs; + if (freqs == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. Can't allocate memory for freqs"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + freqs[freqs_num] = 0; + + params->freqs = freqs; + return 0; +} + + +/** + * wpas_dbus_handler_scan - Request a wireless scan on an interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "Scan" method call of a network device. Requests + * that wpa_supplicant perform a wireless scan as soon as possible + * on a particular wireless interface. + */ +DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, dict_iter, entry_iter, variant_iter; + char *key = NULL, *type = NULL; + struct wpa_driver_scan_params params; + size_t i; + + 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 (os_strcmp(key, "Type") == 0) { + if (wpas_dbus_get_scan_type(message, &variant_iter, + &type, &reply) < 0) + goto out; + } else if (os_strcmp(key, "SSIDs") == 0) { + if (wpas_dbus_get_scan_ssids(message, &variant_iter, + ¶ms, &reply) < 0) + goto out; + } else if (os_strcmp(key, "IEs") == 0) { + if (wpas_dbus_get_scan_ies(message, &variant_iter, + ¶ms, &reply) < 0) + goto out; + } else if (os_strcmp(key, "Channels") == 0) { + if (wpas_dbus_get_scan_channels(message, &variant_iter, + ¶ms, &reply) < 0) + goto out; + } else { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Unknown argument %s", key); + reply = wpas_dbus_error_invalid_args(message, key); + goto out; + } + + dbus_message_iter_next(&dict_iter); + } + + if (!type) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Scan type not specified"); + reply = wpas_dbus_error_invalid_args(message, key); + goto out; + } + + if (!os_strcmp(type, "passive")) { + if (params.num_ssids || params.extra_ies_len) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "SSIDs or IEs specified for passive scan."); + reply = wpas_dbus_error_invalid_args( + message, "You can specify only Channels in " + "passive scan"); + goto out; + } else if (params.freqs && params.freqs[0]) { + wpa_supplicant_trigger_scan(wpa_s, ¶ms); + } else { + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + } else if (!os_strcmp(type, "active")) { + if (!params.num_ssids) { + /* Add wildcard ssid */ + params.num_ssids++; + } + 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_invalid_args(message, + "Wrong scan type"); + goto out; + } + +out: + for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++) + os_free((u8 *) params.ssids[i].ssid); + os_free((u8 *) params.extra_ies); + os_free(params.freqs); + return reply; +} + + +/* + * wpas_dbus_handler_disconnect - Terminate the current connection + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NotConnected DBus error message if already not connected + * or NULL otherwise. + * + * Handler function for "Disconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->current_ssid != NULL) { + wpa_s->disconnected = 1; + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, + "This interface is not connected"); +} + + +/** + * wpas_dbus_new_iface_add_network - Add a new configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing the object path of the new network + * + * Handler function for "AddNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_ssid *ssid = NULL; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; + + 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, wpa_s, 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. */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + + return reply; + +err: + if (ssid) { + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + } + return reply; +} + + +/** + * wpas_dbus_handler_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 || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + id = strtoul(net_id, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + 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_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + +out: + os_free(iface); + os_free(net_id); + return reply; +} + + +static void remove_network(void *arg, struct wpa_ssid *ssid) +{ + struct wpa_supplicant *wpa_s = arg; + + wpas_notify_network_removed(wpa_s, ssid); + + if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { + wpa_printf(MSG_ERROR, + "wpas_dbus_handler_remove_all_networks[dbus]: " + "error occurred when removing network %d", + ssid->id); + return; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); +} + + +/** + * wpas_dbus_handler_remove_all_networks - Remove all configured networks + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "RemoveAllNetworks" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_all_networks( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + /* NB: could check for failure and return an error */ + wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); + return NULL; +} + + +/** + * wpas_dbus_handler_select_network - Attempt association with a network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "SelectNetwork" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL); + if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + id = strtoul(net_id, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + /* Finally, associate with the network */ + wpa_supplicant_select_network(wpa_s, ssid); + +out: + os_free(iface); + os_free(net_id); + return reply; +} + + +/** + * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates) + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing an error on failure or NULL on success + * + * Asks wpa_supplicant to internally store a binary blobs. + */ +DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, array_iter; + + char *blob_name; + u8 *blob_data; + int blob_len; + struct wpa_config_blob *blob = NULL; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &blob_name); + + if (wpa_config_get_blob(wpa_s->conf, blob_name)) { + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_BLOB_EXISTS, + NULL); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array_iter); + + dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len); + + blob = os_zalloc(sizeof(*blob)); + if (!blob) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + + blob->data = os_malloc(blob_len); + if (!blob->data) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + os_memcpy(blob->data, blob_data, blob_len); + + blob->len = blob_len; + blob->name = os_strdup(blob_name); + if (!blob->name) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + + wpa_config_set_blob(wpa_s->conf, blob); + wpas_notify_blob_added(wpa_s, blob->name); + + return reply; + +err: + if (blob) { + os_free(blob->name); + os_free(blob->data); + os_free(blob); + } + return reply; +} + + +/** + * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates) + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing array of bytes (blob) + * + * Gets one wpa_supplicant's binary blobs. + */ +DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, array_iter; + + char *blob_name; + const struct wpa_config_blob *blob; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, + DBUS_TYPE_INVALID); + + blob = wpa_config_get_blob(wpa_s->conf, blob_name); + if (!blob) { + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_BLOB_UNKNOWN, + "Blob id not set"); + } + + reply = dbus_message_new_method_return(message); + if (!reply) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter)) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + + if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, + &(blob->data), blob->len)) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + + if (!dbus_message_iter_close_container(&iter, &array_iter)) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + +out: + return reply; +} + + +/** + * wpas_remove_handler_remove_blob - Remove named binary blob + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: NULL on success or dbus error + * + * Asks wpa_supplicant to internally remove a binary blobs. + */ +DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + char *blob_name; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, + DBUS_TYPE_INVALID); + + if (wpa_config_remove_blob(wpa_s->conf, blob_name)) { + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_BLOB_UNKNOWN, + "Blob id not set"); + } + wpas_notify_blob_removed(wpa_s, blob_name); + + return reply; + +} + +/* + * wpas_dbus_handler_flush_bss - Flush the BSS cache + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Handler function for "FlushBSS" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t age; + + dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age, + DBUS_TYPE_INVALID); + + if (age == 0) + wpa_bss_flush(wpa_s); + else + wpa_bss_flush_by_age(wpa_s, age); + + return NULL; +} + + +/** + * 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; + const char *scans[] = { "active", "passive", "ssid" }; + const char *modes[] = { "infrastructure", "ad-hoc", "ap" }; + int n = sizeof(modes) / sizeof(char *); + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) + goto nomem; + + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + 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_FT) + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-ft-eap")) + goto nomem; + +/* TODO: Ensure that driver actually supports sha256 encryption. */ +#ifdef CONFIG_IEEE80211W + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-eap-sha256")) + goto nomem; +#endif /* CONFIG_IEEE80211W */ + } + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-psk")) + goto nomem; + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-ft-psk")) + goto nomem; + +/* TODO: Ensure that driver actually supports sha256 encryption. */ +#ifdef CONFIG_IEEE80211W + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-psk-sha256")) + goto nomem; +#endif /* CONFIG_IEEE80211W */ + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wpa-none")) + goto nomem; + } + + +#ifdef CONFIG_WPS + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "wps")) + goto nomem; +#endif /* CONFIG_WPS */ + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + } + + /***** WPA protocol */ + if (res < 0) { + const char *args[] = { "rsn", "wpa" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "Protocol", args, + 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 */ + if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans, + sizeof(scans) / sizeof(char *))) + goto nomem; + + /***** Modes */ + if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP)) + n--; /* exclude ap mode if it is not supported by the driver */ + if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n)) + 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; + const char *str_state; + char *state_ls, *tmp; + + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + + /* make state string lowercase to fit new DBus API convention + */ + state_ls = tmp = os_strdup(str_state); + if (!tmp) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + while (*tmp) { + *tmp = tolower(*tmp); + tmp++; + } + + reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &state_ls); + + os_free(state_ls); + + 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) +{ + dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &scanning); +} + + +/** + * 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) +{ + dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, + &ap_scan); +} + + +/** + * 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; + dbus_uint32_t ap_scan; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, + &ap_scan); + if (reply) + return reply; + + if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { + return wpas_dbus_error_invalid_args( + message, "ap_scan must equal 0, 1 or 2"); + } + return NULL; +} + + +/** + * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containing value of bss_expiration_age variable + * + * Getter function for "BSSExpireAge" property. + */ +DBusMessage * wpas_dbus_getter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, + &expire_age); +} + + +/** + * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "BSSExpireAge" property. + */ +DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t expire_age; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, + &expire_age); + if (reply) + return reply; + + if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { + return wpas_dbus_error_invalid_args( + message, "BSSExpireAge must be >=10"); + } + return NULL; +} + + +/** + * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containing value of bss_expire_count variable + * + * Getter function for "BSSExpireCount" property. + */ +DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, + &expire_count); +} + + +/** + * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "BSSExpireCount" property. + */ +DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t expire_count; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, + &expire_count); + if (reply) + return reply; + + if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { + return wpas_dbus_error_invalid_args( + message, "BSSExpireCount must be >0"); + } + return NULL; +} + + +/** + * wpas_dbus_getter_country - Control country code + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containong value of country variable + * + * Getter function for "Country" property. + */ +DBusMessage * wpas_dbus_getter_country(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + char country[3]; + char *str = country; + + country[0] = wpa_s->conf->country[0]; + country[1] = wpa_s->conf->country[1]; + country[2] = '\0'; + + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &str); +} + + +/** + * wpas_dbus_setter_country - Control country code + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "Country" property. + */ +DBusMessage * wpas_dbus_setter_country(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *country; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING, + &country); + if (reply) + return reply; + + if (!country[0] || !country[1]) + return wpas_dbus_error_invalid_args(message, + "invalid country code"); + + if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { + wpa_printf(MSG_DEBUG, "Failed to set country"); + return wpas_dbus_error_invalid_args( + message, "failed to set country code"); + } + + wpa_s->conf->country[0] = country[0]; + wpa_s->conf->country[1] = country[1]; + return NULL; +} + + +/** + * 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) +{ + const char *ifname = wpa_s->ifname; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &ifname); +} + + +/** + * 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) +{ + const char *driver; + + if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " + "wpa_s has no driver set"); + return wpas_dbus_error_unknown_error(message, NULL); + } + + driver = wpa_s->driver->name; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &driver); +} + + +/** + * 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; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; + + if (wpa_s->current_bss) + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, wpa_s->current_bss->id); + else + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); + + reply = wpas_dbus_simple_property_getter(message, + DBUS_TYPE_OBJECT_PATH, + &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; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; + + if (wpa_s->current_ssid) + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, wpa_s->current_ssid->id); + else + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); + + reply = wpas_dbus_simple_property_getter(message, + DBUS_TYPE_OBJECT_PATH, + &net_obj_path); + + return reply; +} + + +/** + * wpas_dbus_getter_current_auth_mode - Get current authentication type + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a string indicating the current + * authentication type. + * + * Getter for "CurrentAuthMode" property. + */ +DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply; + const char *eap_mode; + const char *auth_mode; + char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; + + if (wpa_s->wpa_state != WPA_COMPLETED) { + auth_mode = "INACTIVE"; + } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + eap_mode = wpa_supplicant_get_eap_mode(wpa_s); + os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX, + "EAP-%s", eap_mode); + auth_mode = eap_mode_buf; + + } else { + auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, + wpa_s->current_ssid->proto); + } + + reply = wpas_dbus_simple_property_getter(message, + DBUS_TYPE_STRING, + &auth_mode); + + 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) +{ + 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); + } + + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &bridge_ifname); +} + + +/** + * 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; + struct wpa_bss *bss; + char **paths; + unsigned int i = 0; + + paths = os_zalloc(wpa_s->num_bss * sizeof(char *)); + if (!paths) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + /* Loop through scan results and append each result's object path */ + dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (paths[i] == NULL) { + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + /* Construct the object path for this BSS. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, bss->id); + } + + reply = wpas_dbus_simple_array_property_getter(message, + DBUS_TYPE_OBJECT_PATH, + paths, wpa_s->num_bss); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + 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; + struct wpa_ssid *ssid; + char **paths; + unsigned int i = 0, num = 0; + + 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); + } + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) + num++; + + paths = os_zalloc(num * sizeof(char *)); + if (!paths) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + /* Loop through configured networks and append object path of each */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (paths[i] == NULL) { + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + + /* Construct the object path for this network. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + } + + reply = wpas_dbus_simple_array_property_getter(message, + DBUS_TYPE_OBJECT_PATH, + paths, num); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + 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) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{say}", &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + "{say}", &dict_iter)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + blob = wpa_s->conf->blobs; + while (blob) { + if (!dbus_message_iter_open_container(&dict_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter) || + !dbus_message_iter_append_basic(&entry_iter, + DBUS_TYPE_STRING, + &(blob->name)) || + !dbus_message_iter_open_container(&entry_iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, + DBUS_TYPE_BYTE, + &(blob->data), + blob->len) || + !dbus_message_iter_close_container(&entry_iter, + &array_iter) || + !dbus_message_iter_close_container(&dict_iter, + &entry_iter)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + } + + blob = blob->next; + } + + if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the bssid for the requested bss + * + * Getter for "BSSID" property. + */ +DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, + res->bssid, ETH_ALEN); +} + + +/** + * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the ssid for the requested bss + * + * Getter for "SSID" property. + */ +DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, + res->ssid, + res->ssid_len); +} + + +/** + * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the privacy flag value of requested bss + * + * Getter for "Privacy" property. + */ +DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + dbus_bool_t privacy; + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &privacy); +} + + +/** + * wpas_dbus_getter_bss_mode - Return the mode of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the mode of requested bss + * + * Getter for "Mode" property. + */ +DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + const char *mode; + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + if (res->caps & IEEE80211_CAP_IBSS) + mode = "ad-hoc"; + else + mode = "infrastructure"; + + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, + &mode); +} + + +/** + * wpas_dbus_getter_bss_level - Return the signal strength of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the signal strength of requested bss + * + * Getter for "Level" property. + */ +DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16, + &res->level); +} + + +/** + * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the frequency of requested bss + * + * Getter for "Frequency" property. + */ +DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: " + "no bss with id %d found", bss->id); + return NULL; + } + + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16, + &res->freq); +} + + +static int cmp_u8s_desc(const void *a, const void *b) +{ + return (*(u8 *) b - *(u8 *) a); +} + + +/** + * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing sorted array of bit rates + * + * Getter for "Rates" property. + */ +DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message, + struct bss_handler_args *bss) +{ + DBusMessage *reply; + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + u8 *ie_rates = NULL; + u32 *real_rates; + int rates_num, i; + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: " + "no bss with id %d found", bss->id); + return NULL; + } + + rates_num = wpa_bss_get_bit_rates(res, &ie_rates); + if (rates_num < 0) + return NULL; + + qsort(ie_rates, rates_num, 1, cmp_u8s_desc); + + real_rates = os_malloc(sizeof(u32) * rates_num); + if (!real_rates) { + os_free(ie_rates); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + for (i = 0; i < rates_num; i++) + real_rates[i] = ie_rates[i] * 500000; + + reply = wpas_dbus_simple_array_property_getter(message, + DBUS_TYPE_UINT32, + real_rates, rates_num); + + os_free(ie_rates); + os_free(real_rates); + return reply; +} + + +static DBusMessage * wpas_dbus_get_bss_security_prop( + DBusMessage *message, struct wpa_ie_data *ie_data) +{ + DBusMessage *reply; + DBusMessageIter iter, iter_dict, variant_iter; + const char *group; + const char *pairwise[2]; /* max 2 pairwise ciphers is supported */ + const char *key_mgmt[7]; /* max 7 key managements may be supported */ + int n; + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) + goto nomem; + + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + + /* KeyMgmt */ + n = 0; + if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) + key_mgmt[n++] = "wpa-psk"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK) + key_mgmt[n++] = "wpa-ft-psk"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + key_mgmt[n++] = "wpa-psk-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X) + key_mgmt[n++] = "wpa-eap"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) + key_mgmt[n++] = "wpa-ft-eap"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) + key_mgmt[n++] = "wpa-eap-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) + key_mgmt[n++] = "wpa-none"; + + if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", + key_mgmt, n)) + goto nomem; + + /* Group */ + switch (ie_data->group_cipher) { + case WPA_CIPHER_WEP40: + group = "wep40"; + break; + case WPA_CIPHER_TKIP: + group = "tkip"; + break; + case WPA_CIPHER_CCMP: + group = "ccmp"; + break; + case WPA_CIPHER_WEP104: + group = "wep104"; + break; + default: + group = ""; + break; + } + + if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group)) + goto nomem; + + /* Pairwise */ + n = 0; + if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP) + pairwise[n++] = "tkip"; + if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) + pairwise[n++] = "ccmp"; + + if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", + pairwise, n)) + goto nomem; + + /* Management group (RSN only) */ + if (ie_data->proto == WPA_PROTO_RSN) { + switch (ie_data->mgmt_group_cipher) { +#ifdef CONFIG_IEEE80211W + case WPA_CIPHER_AES_128_CMAC: + group = "aes128cmac"; + break; +#endif /* CONFIG_IEEE80211W */ + default: + group = ""; + break; + } + + if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup", + group)) + goto nomem; + } + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) + goto nomem; + if (!dbus_message_iter_close_container(&iter, &variant_iter)) + goto nomem; + + return reply; + +nomem: + if (reply) + dbus_message_unref(reply); + + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); +} + + +/** + * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the WPA options of requested bss + * + * Getter for "WPA" property. + */ +DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct wpa_ie_data wpa_data; + const u8 *ie; + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + os_memset(&wpa_data, 0, sizeof(wpa_data)); + ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); + if (ie) { + if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) + return wpas_dbus_error_unknown_error(message, + "invalid WPA IE"); + } + + return wpas_dbus_get_bss_security_prop(message, &wpa_data); +} + + +/** + * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing the RSN options of requested bss + * + * Getter for "RSN" property. + */ +DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + struct wpa_ie_data wpa_data; + const u8 *ie; + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + os_memset(&wpa_data, 0, sizeof(wpa_data)); + ie = wpa_bss_get_ie(res, WLAN_EID_RSN); + if (ie) { + if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) + return wpas_dbus_error_unknown_error(message, + "invalid RSN IE"); + } + + return wpas_dbus_get_bss_security_prop(message, &wpa_data); +} + + +/** + * wpas_dbus_getter_bss_ies - Return all IEs of a BSS + * @message: Pointer to incoming dbus message + * @bss: a pair of interface describing structure and bss's id + * Returns: a dbus message containing IEs byte array + * + * Getter for "IEs" property. + */ +DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message, + struct bss_handler_args *bss) +{ + struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id); + + if (!res) { + wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no " + "bss with id %d found", bss->id); + return NULL; + } + + return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE, + res + 1, res->ie_len); +} + + +/** + * wpas_dbus_getter_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) +{ + dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &enabled); +} + + +/** + * 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; + + struct wpa_supplicant *wpa_s; + struct wpa_ssid *ssid; + + dbus_bool_t enable; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, + &enable); + + if (reply) + return reply; + + wpa_s = net->wpa_s; + ssid = net->ssid; + + if (enable) + wpa_supplicant_enable_network(wpa_s, ssid); + else + wpa_supplicant_disable_network(wpa_s, ssid); + + return NULL; +} + + +/** + * 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; + char **props = wpa_config_get_all(net->ssid, 1); + if (!props) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + + if (message == NULL) + reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + else + reply = dbus_message_new_method_return(message); + if (!reply) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto out; + } + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { + 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))) { + 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) || + !dbus_message_iter_close_container(&iter, &variant_iter)) { + 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, net->wpa_s, ssid, + &variant_iter); + if (reply) + wpa_printf(MSG_DEBUG, "dbus control interface couldn't set " + "network properties"); + + return reply; +} diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h new file mode 100644 index 0000000..742d33c --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -0,0 +1,223 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * + * 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; + unsigned int id; +}; + +DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message, + const int type, + const void *val); + +DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message, + const int type, void *val); + +DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message, + const int type, + const void *array, + size_t array_len); + +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_level(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_setter_debug_show_keys(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_remove_all_networks( + 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_handler_flush_bss(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_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_country(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_country(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_current_auth_mode(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_bssid(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message, + struct bss_handler_args *bss); + +DBusMessage * wpas_dbus_getter_bss_ies(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); + +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); + +DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, + const char *arg); +DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, + const char *arg); + +#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */ diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c new file mode 100644 index 0000000..c118d73 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c @@ -0,0 +1,332 @@ +/* + * WPA Supplicant / dbus-based control interface (WPS) + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * + * 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 "../wps_supplicant.h" +#include "dbus_new_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_dict_helpers.h" + + +struct wps_start_params { + int role; /* 0 - not set, 1 - enrollee, 2 - registrar */ + int type; /* 0 - not set, 1 - pin, 2 - pbc */ + u8 *bssid; + char *pin; +}; + + +static int wpas_dbus_handler_wps_role(DBusMessage *message, + DBusMessageIter *entry_iter, + struct wps_start_params *params, + DBusMessage **reply) +{ + DBusMessageIter variant_iter; + char *val; + + dbus_message_iter_recurse(entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, " + "string required"); + *reply = wpas_dbus_error_invalid_args(message, + "Role must be a string"); + return -1; + } + dbus_message_iter_get_basic(&variant_iter, &val); + if (os_strcmp(val, "enrollee") == 0) + params->role = 1; + else if (os_strcmp(val, "registrar") == 0) + params->role = 2; + else { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val); + *reply = wpas_dbus_error_invalid_args(message, val); + return -1; + } + return 0; +} + + +static int wpas_dbus_handler_wps_type(DBusMessage *message, + DBusMessageIter *entry_iter, + struct wps_start_params *params, + DBusMessage **reply) +{ + DBusMessageIter variant_iter; + char *val; + + dbus_message_iter_recurse(entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, " + "string required"); + *reply = wpas_dbus_error_invalid_args(message, + "Type must be a string"); + return -1; + } + dbus_message_iter_get_basic(&variant_iter, &val); + if (os_strcmp(val, "pin") == 0) + params->type = 1; + else if (os_strcmp(val, "pbc") == 0) + params->type = 2; + else { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s", + val); + *reply = wpas_dbus_error_invalid_args(message, val); + return -1; + } + return 0; +} + + +static int wpas_dbus_handler_wps_bssid(DBusMessage *message, + DBusMessageIter *entry_iter, + struct wps_start_params *params, + DBusMessage **reply) +{ + DBusMessageIter variant_iter, array_iter; + int len; + + 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_BYTE) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, " + "byte array required"); + *reply = wpas_dbus_error_invalid_args( + message, "Bssid must be a byte array"); + return -1; + } + dbus_message_iter_recurse(&variant_iter, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, ¶ms->bssid, &len); + if (len != ETH_ALEN) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length " + "%d", len); + *reply = wpas_dbus_error_invalid_args(message, + "Bssid is wrong length"); + return -1; + } + return 0; +} + + +static int wpas_dbus_handler_wps_pin(DBusMessage *message, + DBusMessageIter *entry_iter, + struct wps_start_params *params, + DBusMessage **reply) +{ + DBusMessageIter variant_iter; + + dbus_message_iter_recurse(entry_iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != + DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, " + "string required"); + *reply = wpas_dbus_error_invalid_args(message, + "Pin must be a string"); + return -1; + } + dbus_message_iter_get_basic(&variant_iter, ¶ms->pin); + return 0; +} + + +static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key, + DBusMessageIter *entry_iter, + struct wps_start_params *params, + DBusMessage **reply) +{ + if (os_strcmp(key, "Role") == 0) + return wpas_dbus_handler_wps_role(message, entry_iter, + params, reply); + else if (os_strcmp(key, "Type") == 0) + return wpas_dbus_handler_wps_type(message, entry_iter, + params, reply); + else if (os_strcmp(key, "Bssid") == 0) + return wpas_dbus_handler_wps_bssid(message, entry_iter, + params, reply); + else if (os_strcmp(key, "Pin") == 0) + return wpas_dbus_handler_wps_pin(message, entry_iter, + params, reply); + + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key); + *reply = wpas_dbus_error_invalid_args(message, key); + return -1; +} + + +/** + * 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; + struct wps_start_params params; + char *key; + char npin[9] = { '\0' }; + int ret; + + 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); + + if (wpas_dbus_handler_wps_start_entry(message, key, + &entry_iter, + ¶ms, &reply)) + return reply; + + dbus_message_iter_next(&dict_iter); + } + + if (params.role == 0) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified"); + return wpas_dbus_error_invalid_args(message, + "Role not specified"); + } else if (params.role == 1 && params.type == 0) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified"); + return wpas_dbus_error_invalid_args(message, + "Type not specified"); + } else if (params.role == 2 && params.pin == NULL) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for " + "registrar role"); + return wpas_dbus_error_invalid_args( + message, "Pin required for registrar role."); + } + + if (params.role == 2) + ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin, + NULL); + else if (params.type == 1) { + ret = wpas_wps_start_pin(wpa_s, params.bssid, params.pin, 0, + DEV_PW_DEFAULT); + if (ret > 0) + os_snprintf(npin, sizeof(npin), "%08d", ret); + } else + ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); + + if (ret < 0) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in " + "role %s and key %s", + (params.role == 1 ? "enrollee" : "registrar"), + (params.type == 0 ? "" : + (params.type == 1 ? "pin" : "pbc"))); + return wpas_dbus_error_unknown_error(message, + "WPS start failed"); + } + + reply = dbus_message_new_method_return(message); + if (!reply) { + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + if (os_strlen(npin) > 0) { + if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + } + } + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + 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) +{ + dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN, + &process); +} + + +/** + * 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; + dbus_bool_t process_credentials, old_pc; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN, + &process_credentials); + if (reply) + return reply; + + 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_mark_property_changed(wpa_s->global->dbus, + wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_WPS, + "ProcessCredentials"); + + return NULL; +} diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c new file mode 100644 index 0000000..6e6e842 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_helpers.c @@ -0,0 +1,886 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "dbus_common.h" +#include "dbus_common_i.h" +#include "dbus_new.h" +#include "dbus_new_helpers.h" + + +/** + * 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); + } +} + + +static unsigned int fill_dict_with_properties( + DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props, + const char *interface, const void *user_data) +{ + DBusMessage *reply; + DBusMessageIter entry_iter, ret_iter; + unsigned int counter = 0; + const struct wpa_dbus_property_desc *dsc; + + for (dsc = props; dsc && dsc->dbus_property; dsc++) { + if (!os_strncmp(dsc->dbus_interface, interface, + WPAS_DBUS_INTERFACE_MAX) && + dsc->access != W && dsc->getter) { + reply = dsc->getter(NULL, user_data); + if (!reply) + continue; + + if (dbus_message_get_type(reply) == + DBUS_MESSAGE_TYPE_ERROR) { + dbus_message_unref(reply); + continue; + } + + dbus_message_iter_init(reply, &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, + &dsc->dbus_property); + + recursive_iter_copy(&ret_iter, &entry_iter); + + dbus_message_iter_close_container(dict_iter, + &entry_iter); + dbus_message_unref(reply); + counter++; + } + } + + return counter; +} + + +/** + * 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_object_desc *obj_dsc) +{ + /* Create and initialize the return message */ + DBusMessage *reply = dbus_message_new_method_return(message); + DBusMessageIter iter, dict_iter; + int props_num; + + 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); + + props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties, + interface, obj_dsc->user_data); + + dbus_message_iter_close_container(&iter, &dict_iter); + + if (props_num == 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, + const 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], *pos; + const char *sig = dbus_message_get_signature(message); + int ret; + const struct wpa_dbus_argument *arg; + + pos = registered_sig; + *pos = '\0'; + + for (arg = method_dsc->args; arg && arg->name; arg++) { + if (arg->dir == ARG_IN) { + size_t blen = registered_sig + MAX_SIG_LEN - pos; + ret = os_snprintf(pos, blen, "%s", arg->type); + if (ret < 0 || (size_t) ret >= blen) + return 0; + pos += ret; + } + } + + return !os_strncmp(registered_sig, sig, MAX_SIG_LEN); +} + + +static DBusMessage * properties_get_all(DBusMessage *message, char *interface, + struct wpa_dbus_object_desc *obj_dsc) +{ + if (os_strcmp(dbus_message_get_signature(message), "s") != 0) + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + + return get_all_properties(message, interface, obj_dsc); +} + + +static DBusMessage * properties_get(DBusMessage *message, + const struct wpa_dbus_property_desc *dsc, + void *user_data) +{ + if (os_strcmp(dbus_message_get_signature(message), "ss")) + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + + if (dsc->access != W && dsc->getter) + return dsc->getter(message, user_data); + + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Property is write-only"); +} + + +static DBusMessage * properties_set(DBusMessage *message, + const struct wpa_dbus_property_desc *dsc, + void *user_data) +{ + if (os_strcmp(dbus_message_get_signature(message), "ssv")) + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + + if (dsc->access != R && dsc->setter) + return dsc->setter(message, user_data); + + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Property is read-only"); +} + + +static DBusMessage * +properties_get_or_set(DBusMessage *message, DBusMessageIter *iter, + char *interface, + struct wpa_dbus_object_desc *obj_dsc) +{ + const struct wpa_dbus_property_desc *property_dsc; + char *property; + const char *method; + + method = dbus_message_get_member(message); + 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) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + } + dbus_message_iter_get_basic(iter, &property); + + while (property_dsc && property_dsc->dbus_property) { + /* 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++; + } + if (property_dsc == NULL || property_dsc->dbus_property == NULL) { + wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s", + interface, property, + dbus_message_get_path(message)); + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "No such property"); + } + + if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) + return properties_get(message, property_dsc, + obj_dsc->user_data); + + return properties_set(message, property_dsc, obj_dsc->user_data); +} + + +static DBusMessage * properties_handler(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc) +{ + DBusMessageIter iter; + char *interface; + const char *method; + + method = dbus_message_get_member(message); + 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) + { + return dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + NULL); + } + + dbus_message_iter_get_basic(&iter, &interface); + + if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, + WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { + /* GetAll */ + return properties_get_all(message, interface, obj_dsc); + } + /* Get or Set */ + return properties_get_or_set(message, &iter, interface, + obj_dsc); + } + return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, + NULL); +} + + +static DBusMessage * msg_method_handler(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc) +{ + const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; + const char *method; + const char *msg_interface; + + method = dbus_message_get_member(message); + msg_interface = dbus_message_get_interface(message); + + /* try match call to any registered method */ + while (method_dsc && method_dsc->dbus_method) { + /* 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++; + } + if (method_dsc == NULL || method_dsc->dbus_method == NULL) { + wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s", + msg_interface, method, + dbus_message_get_path(message)); + return dbus_message_new_error(message, + DBUS_ERROR_UNKNOWN_METHOD, NULL); + } + + if (!is_signature_correct(message, method_dsc)) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + } + + return method_dsc->method_handler(message, + obj_dsc->user_data); +} + + +/** + * 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 its 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; + DBusMessage *reply; + + /* 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) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)", + msg_interface, method, path); + + /* 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)) { +#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO + reply = wpa_dbus_introspect(message, obj_dsc); +#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */ + reply = dbus_message_new_error( + message, DBUS_ERROR_UNKNOWN_METHOD, + "wpa_supplicant was compiled without " + "introspection support."); +#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */ + } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface, + WPAS_DBUS_INTERFACE_MAX)) { + /* if message is properties method call */ + reply = properties_handler(message, obj_dsc); + } else { + reply = msg_method_handler(message, obj_dsc); + } + + /* 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); + } + + wpa_dbus_flush_all_changed_properties(connection); + + return DBUS_HANDLER_RESULT_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) +{ + if (!obj_dsc) + return; + + /* free handler's argument */ + if (obj_dsc->user_data_free_func) + obj_dsc->user_data_free_func(obj_dsc->user_data); + + os_free(obj_dsc->path); + os_free(obj_dsc->prop_changed_flags); + 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: 0 on success, -1 on failure + * + * Initialize the dbus control interface and start receiving commands from + * external programs over the bus. + */ +int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, + char *dbus_path, char *dbus_service, + struct wpa_dbus_object_desc *obj_desc) +{ + DBusError error; + int ret = -1; + DBusObjectPathVTable wpa_vtable = { + &free_dbus_object_desc_cb, &message_handler, + NULL, NULL, NULL, NULL + }; + + obj_desc->connection = iface->con; + obj_desc->path = os_strdup(dbus_path); + + /* Register the message handler for the global dbus interface */ + if (!dbus_connection_register_object_path(iface->con, + dbus_path, &wpa_vtable, + obj_desc)) { + wpa_printf(MSG_ERROR, "dbus: Could not set up message " + "handler"); + return -1; + } + + /* 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: + wpa_printf(MSG_ERROR, "dbus: Could not request service name: " + "already registered"); + break; + default: + wpa_printf(MSG_ERROR, "dbus: Could not request service name: " + "%s %s", error.name, error.message); + break; + } + dbus_error_free(&error); + + if (ret != 0) + return -1; + + wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service); + + return 0; +} + + +/** + * 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 wpas_dbus_priv *ctrl_iface, + const char *path, const char *ifname, + struct wpa_dbus_object_desc *obj_desc) +{ + DBusConnection *con; + DBusError error; + + 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; + obj_desc->path = os_strdup(path); + + dbus_error_init(&error); + /* Register the message handler for the interface functions */ + if (!dbus_connection_try_register_object_path(con, path, &vtable, + obj_desc, &error)) { + if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) { + wpa_printf(MSG_DEBUG, "dbus: %s", error.message); + } else { + wpa_printf(MSG_ERROR, "dbus: Could not set up message " + "handler for interface %s object %s", + ifname, path); + wpa_printf(MSG_ERROR, "dbus error: %s", error.name); + wpa_printf(MSG_ERROR, "dbus: %s", error.message); + } + dbus_error_free(&error); + return -1; + } + + dbus_error_free(&error); + return 0; +} + + +static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx); + + +/** + * 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 wpas_dbus_priv *ctrl_iface, const char *path) +{ + DBusConnection *con = ctrl_iface->con; + struct wpa_dbus_object_desc *obj_desc = NULL; + + dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's " + "private data: %s", __func__, path); + } else { + eloop_cancel_timeout(flush_object_timeout_handler, con, + obj_desc); + } + + if (!dbus_connection_unregister_object_path(con, path)) + return -1; + + return 0; +} + + +static void put_changed_properties(const struct wpa_dbus_object_desc *obj_dsc, + const char *interface, + DBusMessageIter *dict_iter) +{ + DBusMessage *getter_reply; + DBusMessageIter prop_iter, entry_iter; + const struct wpa_dbus_property_desc *dsc; + int i; + + for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property; + dsc++, i++) { + if (obj_dsc->prop_changed_flags == NULL || + !obj_dsc->prop_changed_flags[i]) + continue; + if (os_strcmp(dsc->dbus_interface, interface) != 0) + continue; + obj_dsc->prop_changed_flags[i] = 0; + + getter_reply = dsc->getter(NULL, obj_dsc->user_data); + if (!getter_reply || + dbus_message_get_type(getter_reply) == + DBUS_MESSAGE_TYPE_ERROR) { + wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value " + "of property %s", __func__, + dsc->dbus_property); + continue; + } + + if (!dbus_message_iter_init(getter_reply, &prop_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, + &dsc->dbus_property)) + goto err; + + recursive_iter_copy(&prop_iter, &entry_iter); + + if (!dbus_message_iter_close_container(dict_iter, &entry_iter)) + goto err; + + dbus_message_unref(getter_reply); + } + + return; + +err: + wpa_printf(MSG_ERROR, "dbus: %s: Cannot construct signal", __func__); +} + + +static void send_prop_changed_signal( + DBusConnection *con, const char *path, const char *interface, + const struct wpa_dbus_object_desc *obj_dsc) +{ + DBusMessage *msg; + DBusMessageIter signal_iter, dict_iter; + + msg = dbus_message_new_signal(path, interface, "PropertiesChanged"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &signal_iter); + + if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, + "{sv}", &dict_iter)) + goto err; + + put_changed_properties(obj_dsc, interface, &dict_iter); + + if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) + goto err; + + dbus_connection_send(con, msg, NULL); + +out: + dbus_message_unref(msg); + return; + +err: + wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", + __func__); + goto out; +} + + +static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx) +{ + DBusConnection *con = eloop_ctx; + struct wpa_dbus_object_desc *obj_desc = timeout_ctx; + + wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties " + "of object %s", __func__, obj_desc->path); + wpa_dbus_flush_object_changed_properties(con, obj_desc->path); +} + + +static void recursive_flush_changed_properties(DBusConnection *con, + const char *path) +{ + char **objects = NULL; + char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + int i; + + wpa_dbus_flush_object_changed_properties(con, path); + + if (!dbus_connection_list_registered(con, path, &objects)) + goto out; + + for (i = 0; objects[i]; i++) { + os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/%s", path, objects[i]); + recursive_flush_changed_properties(con, subobj_path); + } + +out: + dbus_free_string_array(objects); +} + + +/** + * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals + * @con: DBus connection + * + * Traverses through all registered objects and sends PropertiesChanged for + * each properties. + */ +void wpa_dbus_flush_all_changed_properties(DBusConnection *con) +{ + recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH); +} + + +/** + * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object + * @con: DBus connection + * @path: path to a DBus object for which PropertiesChanged will be sent. + * + * Iterates over all properties registered with object and for each interface + * containing properties marked as changed, sends a PropertiesChanged signal + * containing names and new values of properties that have changed. + * + * You need to call this function after wpa_dbus_mark_property_changed() + * if you want to send PropertiesChanged signal immediately (i.e., without + * waiting timeout to expire). PropertiesChanged signal for an object is sent + * automatically short time after first marking property as changed. All + * PropertiesChanged signals are sent automatically after responding on DBus + * message, so if you marked a property changed as a result of DBus call + * (e.g., param setter), you usually do not need to call this function. + */ +void wpa_dbus_flush_object_changed_properties(DBusConnection *con, + const char *path) +{ + struct wpa_dbus_object_desc *obj_desc = NULL; + const struct wpa_dbus_property_desc *dsc; + int i; + + dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); + if (!obj_desc) + return; + eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc); + + dsc = obj_desc->properties; + for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property; + dsc++, i++) { + if (obj_desc->prop_changed_flags == NULL || + !obj_desc->prop_changed_flags[i]) + continue; + send_prop_changed_signal(con, path, dsc->dbus_interface, + obj_desc); + } +} + + +#define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000 + + +/** + * wpa_dbus_mark_property_changed - Mark a property as changed and + * @iface: dbus priv struct + * @path: path to DBus object which property has changed + * @interface: interface containing changed property + * @property: property name which has changed + * + * Iterates over all properties registered with an object and marks the one + * given in parameters as changed. All parameters registered for an object + * within a single interface will be aggregated together and sent in one + * PropertiesChanged signal when function + * wpa_dbus_flush_object_changed_properties() is called. + */ +void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface, + const char *path, const char *interface, + const char *property) +{ + struct wpa_dbus_object_desc *obj_desc = NULL; + const struct wpa_dbus_property_desc *dsc; + int i = 0; + + if (iface == NULL) + return; + + dbus_connection_get_object_path_data(iface->con, path, + (void **) &obj_desc); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " + "could not obtain object's private data: %s", path); + return; + } + + for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++) + if (os_strcmp(property, dsc->dbus_property) == 0 && + os_strcmp(interface, dsc->dbus_interface) == 0) { + if (obj_desc->prop_changed_flags) + obj_desc->prop_changed_flags[i] = 1; + break; + } + + if (!dsc || !dsc->dbus_property) { + wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " + "no property %s in object %s", property, path); + return; + } + + if (!eloop_is_timeout_registered(flush_object_timeout_handler, + iface->con, obj_desc->path)) { + eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT, + flush_object_timeout_handler, + iface->con, obj_desc); + } +} + + +/** + * wpa_dbus_get_object_properties - Put object's properties into dictionary + * @iface: dbus priv struct + * @path: path to DBus object which properties will be obtained + * @interface: interface name which properties will be obtained + * @dict_iter: correct, open DBus dictionary iterator. + * + * Iterates over all properties registered with object and execute getters + * of those, which are readable and which interface matches interface + * specified as argument. Obtained properties values are stored in + * dict_iter dictionary. + */ +void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, + const char *path, const char *interface, + DBusMessageIter *dict_iter) +{ + struct wpa_dbus_object_desc *obj_desc = NULL; + + dbus_connection_get_object_path_data(iface->con, path, + (void **) &obj_desc); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: " + "could not obtain object's private data: %s", path); + return; + } + + fill_dict_with_properties(dict_iter, obj_desc->properties, + interface, obj_desc->user_data); +} diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h new file mode 100644 index 0000000..7038b63 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_helpers.h @@ -0,0 +1,148 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * + * 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 <dbus/dbus.h> + +typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message, + void *user_data); +typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg); + +typedef DBusMessage * (* WPADBusPropertyAccessor)(DBusMessage *message, + const void *user_data); + +struct wpa_dbus_object_desc { + DBusConnection *connection; + char *path; + + /* list of methods, properties and signals registered with object */ + const struct wpa_dbus_method_desc *methods; + const struct wpa_dbus_signal_desc *signals; + const struct wpa_dbus_property_desc *properties; + + /* property changed flags */ + u8 *prop_changed_flags; + + /* argument for method handlers and properties + * getter and setter functions */ + void *user_data; + /* function used to free above argument */ + WPADBusArgumentFreeFunction user_data_free_func; +}; + +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 } + +/** + * struct wpa_dbus_method_desc - DBus method description + */ +struct wpa_dbus_method_desc { + /* method name */ + const char *dbus_method; + /* method interface */ + const char *dbus_interface; + /* method handling function */ + WPADBusMethodHandler method_handler; + /* array of arguments */ + struct wpa_dbus_argument args[3]; +}; + +/** + * struct wpa_dbus_signal_desc - DBus signal description + */ +struct wpa_dbus_signal_desc { + /* signal name */ + const char *dbus_signal; + /* signal interface */ + const char *dbus_interface; + /* array of arguments */ + struct wpa_dbus_argument args[3]; +}; + +/** + * struct wpa_dbus_property_desc - DBus property description + */ +struct wpa_dbus_property_desc { + /* property name */ + const char *dbus_property; + /* property interface */ + const char *dbus_interface; + /* property type signature in DBus type notation */ + const char *type; + /* property getter function */ + WPADBusPropertyAccessor getter; + /* property setter function */ + WPADBusPropertyAccessor setter; + /* property access permissions */ + enum dbus_prop_access access; +}; + + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 +#define WPAS_DBUS_INTERFACE_MAX 150 +#define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50 +#define WPAS_DBUS_AUTH_MODE_MAX 64 + +#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); + +int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path, + char *dbus_service, + struct wpa_dbus_object_desc *obj_desc); + +int wpa_dbus_register_object_per_iface( + struct wpas_dbus_priv *ctrl_iface, + const char *path, const char *ifname, + struct wpa_dbus_object_desc *obj_desc); + +int wpa_dbus_unregister_object_per_iface( + struct wpas_dbus_priv *ctrl_iface, + const char *path); + +void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, + const char *path, const char *interface, + DBusMessageIter *dict_iter); + + +void wpa_dbus_flush_all_changed_properties(DBusConnection *con); + +void wpa_dbus_flush_object_changed_properties(DBusConnection *con, + const char *path); + +void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface, + const char *path, const char *interface, + const char *property); + +DBusMessage * wpa_dbus_introspect(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc); + +#endif /* WPA_DBUS_CTRL_H */ diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c new file mode 100644 index 0000000..fd433df --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_introspect.c @@ -0,0 +1,278 @@ +/* + * wpa_supplicant - D-Bus introspection + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/list.h" +#include "utils/wpabuf.h" +#include "dbus_common_i.h" +#include "dbus_new_helpers.h" + + +struct interfaces { + struct dl_list list; + char *dbus_interface; + struct wpabuf *xml; +}; + + +static struct interfaces * add_interface(struct dl_list *list, + const char *dbus_interface) +{ + struct interfaces *iface; + + dl_list_for_each(iface, list, struct interfaces, list) { + if (os_strcmp(iface->dbus_interface, dbus_interface) == 0) + return iface; /* already in the list */ + } + + iface = os_zalloc(sizeof(struct interfaces)); + if (!iface) + return NULL; + iface->xml = wpabuf_alloc(6000); + if (iface->xml == NULL) { + os_free(iface); + return NULL; + } + wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface); + dl_list_add_tail(list, &iface->list); + iface->dbus_interface = os_strdup(dbus_interface); + return iface; +} + + +static void add_arg(struct wpabuf *xml, const char *name, const char *type, + const char *direction) +{ + wpabuf_printf(xml, "<arg name=\"%s\"", name); + if (type) + wpabuf_printf(xml, " type=\"%s\"", type); + if (direction) + wpabuf_printf(xml, " direction=\"%s\"", direction); + wpabuf_put_str(xml, "/>"); +} + + +static void add_entry(struct wpabuf *xml, const char *type, const char *name, + const struct wpa_dbus_argument *args, int include_dir) +{ + const struct wpa_dbus_argument *arg; + + if (args == NULL || args->name == NULL) { + wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name); + return; + } + wpabuf_printf(xml, "<%s name=\"%s\">", type, name); + for (arg = args; arg && arg->name; arg++) { + add_arg(xml, arg->name, arg->type, + include_dir ? (arg->dir == ARG_IN ? "in" : "out") : + NULL); + } + wpabuf_printf(xml, "</%s>", type); +} + + +static void add_property(struct wpabuf *xml, + const struct wpa_dbus_property_desc *dsc) +{ + wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>", + dsc->dbus_property, dsc->type, + (dsc->access == R ? "read" : + (dsc->access == W ? "write" : "readwrite"))); +} + + +static void extract_interfaces_methods( + struct dl_list *list, const struct wpa_dbus_method_desc *methods) +{ + const struct wpa_dbus_method_desc *dsc; + struct interfaces *iface; + for (dsc = methods; dsc && dsc->dbus_method; dsc++) { + iface = add_interface(list, dsc->dbus_interface); + if (iface) + add_entry(iface->xml, "method", dsc->dbus_method, + dsc->args, 1); + } +} + + +static void extract_interfaces_signals( + struct dl_list *list, const struct wpa_dbus_signal_desc *signals) +{ + const struct wpa_dbus_signal_desc *dsc; + struct interfaces *iface; + for (dsc = signals; dsc && dsc->dbus_signal; dsc++) { + iface = add_interface(list, dsc->dbus_interface); + if (iface) + add_entry(iface->xml, "signal", dsc->dbus_signal, + dsc->args, 0); + } +} + + +static void extract_interfaces_properties( + struct dl_list *list, const struct wpa_dbus_property_desc *properties) +{ + const struct wpa_dbus_property_desc *dsc; + struct interfaces *iface; + for (dsc = properties; dsc && dsc->dbus_property; dsc++) { + iface = add_interface(list, dsc->dbus_interface); + if (iface) + add_property(iface->xml, dsc); + } +} + + +/** + * extract_interfaces - Extract interfaces from methods, signals and props + * @list: Interface list to be filled + * @obj_dsc: Description of object from which interfaces will be extracted + * + * Iterates over all methods, signals, and properties registered with an + * object and collects all declared DBus interfaces and create interfaces' + * node in XML root node for each. Returned list elements contain interface + * name and XML node of corresponding interface. + */ +static void extract_interfaces(struct dl_list *list, + struct wpa_dbus_object_desc *obj_dsc) +{ + extract_interfaces_methods(list, obj_dsc->methods); + extract_interfaces_signals(list, obj_dsc->signals); + extract_interfaces_properties(list, obj_dsc->properties); +} + + +static void add_interfaces(struct dl_list *list, struct wpabuf *xml) +{ + struct interfaces *iface, *n; + dl_list_for_each_safe(iface, n, list, struct interfaces, list) { + if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) { + wpabuf_put_buf(xml, iface->xml); + wpabuf_put_str(xml, "</interface>"); + } + dl_list_del(&iface->list); + wpabuf_free(iface->xml); + os_free(iface->dbus_interface); + os_free(iface); + } +} + + +static void add_child_nodes(struct wpabuf *xml, DBusConnection *con, + const char *path) +{ + char **children; + int i; + + /* add child nodes to introspection tree */ + dbus_connection_list_registered(con, path, &children); + for (i = 0; children[i]; i++) + wpabuf_printf(xml, "<node name=\"%s\"/>", children[i]); + dbus_free_string_array(children); +} + + +static void add_introspectable_interface(struct wpabuf *xml) +{ + wpabuf_printf(xml, "<interface name=\"%s\">" + "<method name=\"%s\">" + "<arg name=\"data\" type=\"s\" direction=\"out\"/>" + "</method>" + "</interface>", + WPA_DBUS_INTROSPECTION_INTERFACE, + WPA_DBUS_INTROSPECTION_METHOD); +} + + +static void add_properties_interface(struct wpabuf *xml) +{ + wpabuf_printf(xml, "<interface name=\"%s\">", + WPA_DBUS_PROPERTIES_INTERFACE); + + wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GET); + add_arg(xml, "interface", "s", "in"); + add_arg(xml, "propname", "s", "in"); + add_arg(xml, "value", "v", "out"); + wpabuf_put_str(xml, "</method>"); + + wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GETALL); + add_arg(xml, "interface", "s", "in"); + add_arg(xml, "props", "a{sv}", "out"); + wpabuf_put_str(xml, "</method>"); + + wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_SET); + add_arg(xml, "interface", "s", "in"); + add_arg(xml, "propname", "s", "in"); + add_arg(xml, "value", "v", "in"); + wpabuf_put_str(xml, "</method>"); + + wpabuf_put_str(xml, "</interface>"); +} + + +static void add_wpas_interfaces(struct wpabuf *xml, + struct wpa_dbus_object_desc *obj_dsc) +{ + struct dl_list ifaces; + dl_list_init(&ifaces); + extract_interfaces(&ifaces, obj_dsc); + add_interfaces(&ifaces, xml); +} + + +/** + * wpa_dbus_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. + */ +DBusMessage * wpa_dbus_introspect(DBusMessage *message, + struct wpa_dbus_object_desc *obj_dsc) +{ + + DBusMessage *reply; + struct wpabuf *xml; + + xml = wpabuf_alloc(8000); + if (xml == NULL) + return NULL; + + wpabuf_put_str(xml, "<?xml version=\"1.0\"?>\n"); + wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); + wpabuf_put_str(xml, "<node>"); + + add_introspectable_interface(xml); + add_properties_interface(xml); + add_wpas_interfaces(xml, obj_dsc); + add_child_nodes(xml, obj_dsc->connection, + dbus_message_get_path(message)); + + wpabuf_put_str(xml, "</node>\n"); + + reply = dbus_message_new_method_return(message); + if (reply) { + const char *intro_str = wpabuf_head(xml); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str, + DBUS_TYPE_INVALID); + } + wpabuf_free(xml); + + return reply; +} diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c new file mode 100644 index 0000000..6a00f3e --- /dev/null +++ b/wpa_supplicant/dbus/dbus_old.c @@ -0,0 +1,697 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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. + */ + +#include "includes.h" +#include <dbus/dbus.h> + +#include "common.h" +#include "eloop.h" +#include "wps/wps.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../bss.h" +#include "dbus_old.h" +#include "dbus_old_handlers.h" +#include "dbus_common.h" +#include "dbus_common_i.h" + + +/** + * wpas_dbus_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. + */ +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + strlen(WPAS_DBUS_PATH_INTERFACES "/"); + char *obj_path_only; + char *next_sep; + + /* Be a bit paranoid about path */ + if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", + dev_path_prefix_len)) + return NULL; + + /* Ensure there's something at the end of the path */ + if ((path + dev_path_prefix_len)[0] == '\0') + return NULL; + + obj_path_only = os_strdup(path); + if (obj_path_only == NULL) + return NULL; + + next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); + if (next_sep != NULL) { + const char *net_part = strstr(next_sep, + WPAS_DBUS_NETWORKS_PART "/"); + const char *bssid_part = strstr(next_sep, + WPAS_DBUS_BSSIDS_PART "/"); + + if (network && net_part) { + /* Deal with a request for a configured network */ + const char *net_name = net_part + + strlen(WPAS_DBUS_NETWORKS_PART "/"); + *network = NULL; + if (strlen(net_name)) + *network = os_strdup(net_name); + } else if (bssid && bssid_part) { + /* Deal with a request for a scanned BSSID */ + const char *bssid_name = bssid_part + + strlen(WPAS_DBUS_BSSIDS_PART "/"); + if (strlen(bssid_name)) + *bssid = os_strdup(bssid_name); + else + *bssid = NULL; + } + + /* Cut off interface object path before "/" */ + *next_sep = '\0'; + } + + return obj_path_only; +} + + +/** + * wpas_dbus_new_invalid_iface_error - 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 + */ +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, + "wpa_supplicant knows nothing about " + "this interface."); +} + + +/** + * wpas_dbus_new_invalid_network_error - Return a new invalid network 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 + */ +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, + "The requested network does not exist."); +} + + +/** + * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid 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 bssid error + */ +static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, + "The BSSID requested was invalid."); +} + + +/** + * wpas_dispatch_network_method - dispatch messages for configured networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @network_id: id of the configured network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for configured networks. + */ +static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + int network_id) +{ + DBusMessage *reply = NULL; + const char *method = dbus_message_get_member(message); + struct wpa_ssid *ssid; + + ssid = wpa_config_get_network(wpa_s->conf, network_id); + if (ssid == NULL) + return wpas_dbus_new_invalid_network_error(message); + + if (!strcmp(method, "set")) + reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); + else if (!strcmp(method, "enable")) + reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); + else if (!strcmp(method, "disable")) + reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); + + return reply; +} + + +/** + * wpas_dispatch_bssid_method - dispatch messages for scanned networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @bssid: bssid of the scanned network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for scanned networks. + */ +static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + const char *bssid_txt) +{ + u8 bssid[ETH_ALEN]; + struct wpa_bss *bss; + + if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) + return wpas_dbus_new_invalid_bssid_error(message); + + bss = wpa_bss_get_bssid(wpa_s, bssid); + if (bss == NULL) + return wpas_dbus_new_invalid_bssid_error(message); + + /* Dispatch the method call against the scanned bssid */ + if (os_strcmp(dbus_message_get_member(message), "properties") == 0) + return wpas_dbus_bssid_properties(message, wpa_s, bss); + + return NULL; +} + + +/** + * wpas_iface_message_handler - Dispatch messages for interfaces or networks + * @connection: Connection to the system message bus + * @message: An incoming dbus message + * @user_data: A pointer to a dbus control interface data structure + * Returns: Whether or not the message was handled + * + * This function dispatches all incoming dbus messages for network interfaces, + * or objects owned by them, such as scanned BSSIDs and configured networks. + */ +static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *method = dbus_message_get_member(message); + const char *path = dbus_message_get_path(message); + const char *msg_interface = dbus_message_get_interface(message); + char *iface_obj_path = NULL; + char *network = NULL; + char *bssid = NULL; + DBusMessage *reply = NULL; + + /* Caller must specify a message interface */ + if (!msg_interface) + goto out; + + iface_obj_path = wpas_dbus_decompose_object_path(path, &network, + &bssid); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + /* Make sure the message's object path actually refers to the + * wpa_supplicant structure it's supposed to (which is wpa_s) + */ + if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, + iface_obj_path) != wpa_s) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { + /* A method for one of this interface's configured networks */ + int nid = strtoul(network, NULL, 10); + if (errno != EINVAL) + reply = wpas_dispatch_network_method(message, wpa_s, + nid); + else + reply = wpas_dbus_new_invalid_network_error(message); + } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { + /* A method for one of this interface's scanned BSSIDs */ + reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); + } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { + /* A method for an interface only. */ + if (!strcmp(method, "scan")) + reply = wpas_dbus_iface_scan(message, wpa_s); + else if (!strcmp(method, "scanResults")) + reply = wpas_dbus_iface_scan_results(message, wpa_s); + else if (!strcmp(method, "addNetwork")) + reply = wpas_dbus_iface_add_network(message, wpa_s); + else if (!strcmp(method, "removeNetwork")) + reply = wpas_dbus_iface_remove_network(message, wpa_s); + else if (!strcmp(method, "selectNetwork")) + reply = wpas_dbus_iface_select_network(message, wpa_s); + else if (!strcmp(method, "capabilities")) + reply = wpas_dbus_iface_capabilities(message, wpa_s); + else if (!strcmp(method, "disconnect")) + reply = wpas_dbus_iface_disconnect(message, wpa_s); + else if (!strcmp(method, "setAPScan")) + reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); + else if (!strcmp(method, "setSmartcardModules")) + reply = wpas_dbus_iface_set_smartcard_modules(message, + wpa_s); + else if (!strcmp(method, "state")) + reply = wpas_dbus_iface_get_state(message, wpa_s); + else if (!strcmp(method, "scanning")) + reply = wpas_dbus_iface_get_scanning(message, wpa_s); + else if (!strcmp(method, "setBlobs")) + reply = wpas_dbus_iface_set_blobs(message, wpa_s); + else if (!strcmp(method, "removeBlobs")) + reply = wpas_dbus_iface_remove_blobs(message, wpa_s); +#ifdef CONFIG_WPS + else if (!os_strcmp(method, "wpsPbc")) + reply = wpas_dbus_iface_wps_pbc(message, wpa_s); + else if (!os_strcmp(method, "wpsPin")) + reply = wpas_dbus_iface_wps_pin(message, wpa_s); + else if (!os_strcmp(method, "wpsReg")) + reply = wpas_dbus_iface_wps_reg(message, wpa_s); +#endif /* CONFIG_WPS */ + else if (!os_strcmp(method, "flush")) + reply = wpas_dbus_iface_flush(message, wpa_s); + } + + /* If the message was handled, send back the reply */ + if (reply) { + if (!dbus_message_get_no_reply(message)) + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + +out: + os_free(iface_obj_path); + os_free(network); + os_free(bssid); + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpas_message_handler - dispatch incoming dbus messages + * @connection: connection to the system message bus + * @message: an incoming dbus message + * @user_data: a pointer to a dbus control interface data structure + * Returns: whether or not the message was handled + * + * This function dispatches all incoming dbus messages to the correct + * handlers, depending on what the message's target object path is, + * and what the method call is. + */ +static DBusHandlerResult wpas_message_handler(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct wpas_dbus_priv *ctrl_iface = user_data; + const char *method; + const char *path; + const char *msg_interface; + DBusMessage *reply = NULL; + + method = dbus_message_get_member(message); + path = dbus_message_get_path(message); + msg_interface = dbus_message_get_interface(message); + if (!method || !path || !ctrl_iface || !msg_interface) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the method interface */ + if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!strcmp(path, WPAS_DBUS_PATH)) { + /* dispatch methods against our global dbus interface here */ + if (!strcmp(method, "addInterface")) { + reply = wpas_dbus_global_add_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "removeInterface")) { + reply = wpas_dbus_global_remove_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "getInterface")) { + reply = wpas_dbus_global_get_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "setDebugParams")) { + reply = wpas_dbus_global_set_debugparams( + message, ctrl_iface->global); + } + } + + /* If the message was handled, send back the reply */ + if (reply) { + if (!dbus_message_get_no_reply(message)) + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal + * @wpa_s: %wpa_supplicant network interface data + * Returns: 0 on success, -1 on failure + * + * Notify listeners that this interface has updated scan results. + */ +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *iface = wpa_s->global->dbus; + DBusMessage *_signal; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + _signal = dbus_message_new_signal(wpa_s->dbus_path, + WPAS_DBUS_IFACE_INTERFACE, + "ScanResultsAvailable"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " + "results signal"); + return; + } + dbus_connection_send(iface->con, _signal, NULL); + dbus_message_unref(_signal); +} + + +/** + * wpa_supplicant_dbus_notify_state_change - Send a state change signal + * @wpa_s: %wpa_supplicant network interface data + * @new_state: new state wpa_supplicant is entering + * @old_state: old state wpa_supplicant is leaving + * Returns: 0 on success, -1 on failure + * + * Notify listeners that wpa_supplicant has changed state + */ +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + enum wpa_states new_state, + enum wpa_states old_state) +{ + struct wpas_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *new_state_str, *old_state_str; + + if (wpa_s->dbus_path == NULL) + return; /* Skip signal since D-Bus setup is not yet ready */ + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus; + if (iface == NULL) + return; + + /* Only send signal if state really changed */ + if (new_state == old_state) + return; + + _signal = dbus_message_new_signal(wpa_s->dbus_path, + WPAS_DBUS_IFACE_INTERFACE, + "StateChange"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_state_change: " + "could not create dbus signal; likely out of " + "memory"); + return; + } + + new_state_str = wpa_supplicant_state_txt(new_state); + old_state_str = wpa_supplicant_state_txt(old_state); + if (new_state_str == NULL || old_state_str == NULL) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_state_change: " + "Could not convert state strings"); + goto out; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_STRING, &new_state_str, + DBUS_TYPE_STRING, &old_state_str, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_state_change: " + "Not enough memory to construct state change " + "signal"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); +} + + +/** + * wpa_supplicant_dbus_notify_scanning - send scanning status + * @wpa_s: %wpa_supplicant network interface data + * Returns: 0 on success, -1 on failure + * + * Notify listeners of interface scanning state changes + */ +void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *iface = wpa_s->global->dbus; + DBusMessage *_signal; + dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + _signal = dbus_message_new_signal(wpa_s->dbus_path, + WPAS_DBUS_IFACE_INTERFACE, + "Scanning"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " + "results signal"); + return; + } + + if (dbus_message_append_args(_signal, + DBUS_TYPE_BOOLEAN, &scanning, + DBUS_TYPE_INVALID)) { + dbus_connection_send(iface->con, _signal, NULL); + } else { + wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct " + "signal"); + } + dbus_message_unref(_signal); +} + + +#ifdef CONFIG_WPS +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ + struct wpas_dbus_priv *iface; + DBusMessage *_signal = NULL; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus; + if (iface == NULL) + return; + + _signal = dbus_message_new_signal(wpa_s->dbus_path, + WPAS_DBUS_IFACE_INTERFACE, + "WpsCred"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_wps_cred: " + "Could not create dbus signal; likely out of " + "memory"); + return; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &cred->cred_attr, cred->cred_attr_len, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_wps_cred: " + "Not enough memory to construct signal"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); +} +#else /* CONFIG_WPS */ +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ +} +#endif /* CONFIG_WPS */ + + +/** + * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: 0 on success, -1 on failure + * + * Initialize the dbus control interface and start receiving commands from + * external programs over the bus. + */ +int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) +{ + DBusError error; + int ret = -1; + DBusObjectPathVTable wpas_vtable = { + NULL, &wpas_message_handler, NULL, NULL, NULL, NULL + }; + + /* Register the message handler for the global dbus interface */ + if (!dbus_connection_register_object_path(iface->con, + WPAS_DBUS_PATH, &wpas_vtable, + iface)) { + wpa_printf(MSG_ERROR, "dbus: Could not set up message " + "handler"); + return -1; + } + + /* Register our service with the message bus */ + dbus_error_init(&error); + switch (dbus_bus_request_name(iface->con, WPAS_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: + wpa_printf(MSG_ERROR, "dbus: Could not request service name: " + "already registered"); + break; + default: + wpa_printf(MSG_ERROR, "dbus: Could not request service name: " + "%s %s", error.name, error.message); + break; + } + dbus_error_free(&error); + + if (ret != 0) + return -1; + + wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE + "'."); + + return 0; +} + + +/** + * wpas_dbus_register_new_iface - Register a new interface with dbus + * @wpa_s: %wpa_supplicant interface description structure to register + * Returns: 0 on success, -1 on error + * + * Registers a new interface with dbus and assigns it a dbus object path. + */ +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; + DBusConnection * con; + u32 next; + DBusObjectPathVTable vtable = { + NULL, &wpas_iface_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; + next = ctrl_iface->next_objid++; + + /* Create and set the interface's object path */ + wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (wpa_s->dbus_path == NULL) + return -1; + os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, + WPAS_DBUS_PATH_INTERFACES "/%u", + next); + + /* Register the message handler for the interface functions */ + if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, + wpa_s)) { + wpa_printf(MSG_ERROR, "dbus: Could not set up message " + "handler for interface %s", wpa_s->ifname); + return -1; + } + + return 0; +} + + +/** + * wpas_dbus_unregister_iface - Unregister an interface from dbus + * @wpa_s: wpa_supplicant interface structure + * Returns: 0 on success, -1 on failure + * + * Unregisters the interface with dbus + */ +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *ctrl_iface; + DBusConnection *con; + + /* 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; + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) + return -1; + + os_free(wpa_s->dbus_path); + wpa_s->dbus_path = NULL; + + return 0; +} + + +/** + * wpa_supplicant_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 + */ +struct wpa_supplicant * 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_path, path) == 0) + return wpa_s; + } + return NULL; +} diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h new file mode 100644 index 0000000..a9840c2 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_old.h @@ -0,0 +1,131 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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_H +#define CTRL_IFACE_DBUS_H + +struct wps_credential; + +#ifdef CONFIG_CTRL_IFACE_DBUS + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 + +#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" +#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" +#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" + +#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" + +#define WPAS_DBUS_NETWORKS_PART "Networks" +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" + +#define WPAS_DBUS_BSSIDS_PART "BSSIDs" +#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" + + +/* Errors */ +#define WPAS_ERROR_INVALID_NETWORK \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" +#define WPAS_ERROR_INVALID_BSSID \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" + +#define WPAS_ERROR_INVALID_OPTS \ + WPAS_DBUS_INTERFACE ".InvalidOptions" +#define WPAS_ERROR_INVALID_IFACE \ + WPAS_DBUS_INTERFACE ".InvalidInterface" + +#define WPAS_ERROR_ADD_ERROR \ + WPAS_DBUS_INTERFACE ".AddError" +#define WPAS_ERROR_EXISTS_ERROR \ + WPAS_DBUS_INTERFACE ".ExistsError" +#define WPAS_ERROR_REMOVE_ERROR \ + WPAS_DBUS_INTERFACE ".RemoveError" + +#define WPAS_ERROR_SCAN_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".ScanError" +#define WPAS_ERROR_ADD_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" +#define WPAS_ERROR_INTERNAL_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".InternalError" +#define WPAS_ERROR_REMOVE_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" + +#define WPAS_ERROR_WPS_PBC_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError" +#define WPAS_ERROR_WPS_PIN_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".WpsPinError" +#define WPAS_ERROR_WPS_REG_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".WpsRegError" + +#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" + +struct wpa_global; +struct wpa_supplicant; + +int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface); +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); +void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s); +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + enum wpa_states new_state, + enum wpa_states old_state); +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); + +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid); + +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s); +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s); + + +/* Methods internal to the dbus control interface */ +struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( + struct wpa_global *global, const char *path); + +#else /* CONFIG_CTRL_IFACE_DBUS */ + +static inline void +wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ +} + +static inline void +wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) +{ +} + +#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0) + +static inline void +wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ +} + +static inline int +wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline int +wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#endif /* CONFIG_CTRL_IFACE_DBUS */ + +#endif /* CTRL_IFACE_DBUS_H */ diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c new file mode 100644 index 0000000..de66140 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_old_handlers.c @@ -0,0 +1,1468 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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. + */ + +#include "includes.h" +#include <dbus/dbus.h> + +#include "common.h" +#include "eap_peer/eap_methods.h" +#include "common/ieee802_11_defs.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "rsn_supp/wpa.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../driver_i.h" +#include "../notify.h" +#include "../wpas_glue.h" +#include "../bss.h" +#include "../scan.h" +#include "dbus_old.h" +#include "dbus_old_handlers.h" +#include "dbus_dict_helpers.h" + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + +/** + * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid options error + */ +DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, + const char *arg) +{ + DBusMessage *reply; + + reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, + "Did not receive correct message " + "arguments."); + if (arg != NULL) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + return reply; +} + + +/** + * wpas_dbus_new_success_reply - Return a new success reply message + * @message: Pointer to incoming dbus message this reply refers to + * Returns: a dbus message containing a single UINT32 that indicates + * success (ie, a value of 1) + * + * Convenience function to create and return a success reply message + */ +DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) +{ + DBusMessage *reply; + unsigned int success = 1; + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, + DBUS_TYPE_INVALID); + return reply; +} + + +/** + * wpas_dbus_global_add_interface - Request registration of a network interface + * @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_global_add_interface(DBusMessage *message, + struct wpa_global *global) +{ + char *ifname = NULL; + char *driver = NULL; + char *driver_param = NULL; + char *confname = NULL; + char *bridge_ifname = NULL; + DBusMessage *reply = NULL; + DBusMessageIter iter; + + dbus_message_iter_init(message, &iter); + + /* First argument: interface name (DBUS_TYPE_STRING) + * Required; must be non-zero length + */ + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto error; + dbus_message_iter_get_basic(&iter, &ifname); + if (!os_strlen(ifname)) + goto error; + + /* Second argument: dict of options */ + if (dbus_message_iter_next(&iter)) { + DBusMessageIter iter_dict; + struct wpa_dbus_dict_entry entry; + + 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)) { + driver = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (driver == NULL) + goto error; + } else if (!strcmp(entry.key, "driver-params") && + (entry.type == DBUS_TYPE_STRING)) { + driver_param = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (driver_param == NULL) + goto error; + } else if (!strcmp(entry.key, "config-file") && + (entry.type == DBUS_TYPE_STRING)) { + confname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (confname == NULL) + goto error; + } else if (!strcmp(entry.key, "bridge-ifname") && + (entry.type == DBUS_TYPE_STRING)) { + bridge_ifname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (bridge_ifname == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + } + } + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, ifname) != NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_EXISTS_ERROR, + "wpa_supplicant already " + "controls this interface."); + } else { + struct wpa_supplicant *wpa_s; + struct wpa_interface iface; + os_memset(&iface, 0, sizeof(iface)); + iface.ifname = ifname; + iface.driver = driver; + iface.driver_param = driver_param; + iface.confname = confname; + iface.bridge_ifname = bridge_ifname; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpa_s->dbus_path; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_ERROR, + "wpa_supplicant " + "couldn't grab this " + "interface."); + } + } + +out: + os_free(driver); + os_free(driver_param); + os_free(confname); + os_free(bridge_ifname); + return reply; + +error: + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; +} + + +/** + * wpas_dbus_global_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_global_remove_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + char *path; + DBusMessage *reply = NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (!wpa_supplicant_remove_iface(global, wpa_s)) { + reply = wpas_dbus_new_success_reply(message); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_ERROR, + "wpa_supplicant couldn't " + "remove this interface."); + } + +out: + return reply; +} + + +/** + * wpas_dbus_global_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. Handles requests + * by dbus clients for the object path of an specific network interface. + */ +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + const char *ifname; + const char *path; + struct wpa_supplicant *wpa_s; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + path = wpa_s->dbus_path; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + +out: + return reply; +} + + +/** + * wpas_dbus_global_set_debugparams- Set the debug params + * @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 "setDebugParams" method call. Handles requests + * by dbus clients for the object path of an specific network interface. + */ +DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + int debug_level; + dbus_bool_t debug_timestamp; + dbus_bool_t debug_show_keys; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_INT32, &debug_level, + DBUS_TYPE_BOOLEAN, &debug_timestamp, + DBUS_TYPE_BOOLEAN, &debug_show_keys, + DBUS_TYPE_INVALID)) { + 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)) { + return wpas_dbus_new_invalid_opts_error(message, NULL); + } + + reply = wpas_dbus_new_success_reply(message); + + return reply; +} + + +/** + * wpas_dbus_iface_scan - Request a wireless scan on an interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * 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_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_scan_results - Get the results of a recent scan request + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a dbus array of objects paths, or returns + * a dbus error message if not scan results could be found + * + * Handler function for "scanResults" method call of a network device. Returns + * a dbus message containing the object paths of wireless networks found. + */ +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter sub_iter; + struct wpa_bss *bss; + + /* Create and initialize the return message */ + reply = dbus_message_new_method_return(message); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &sub_iter); + + /* Loop through scan results and append each result's object path */ + dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; + char *path = path_buf; + + /* Construct the object path for this network. Note that ':' + * is not a valid character in dbus object paths. + */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_BSSIDS_PART "/" + WPAS_DBUS_BSSID_FORMAT, + wpa_s->dbus_path, MAC2STR(bss->bssid)); + dbus_message_iter_append_basic(&sub_iter, + DBUS_TYPE_OBJECT_PATH, &path); + } + + dbus_message_iter_close_container(&iter, &sub_iter); + + return reply; +} + + +/** + * wpas_dbus_bssid_properties - Return the properties of a scanned network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @res: wpa_supplicant scan result for which to get properties + * Returns: a dbus message containing the properties for the requested network + * + * Handler function for "properties" method call of a scanned network. + * Returns a dbus message containing the the properties. + */ +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + DBusMessage *reply; + DBusMessageIter iter, iter_dict; + const u8 *ie; + + /* Dump the properties into a dbus message */ + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", + (const char *) bss->bssid, + ETH_ALEN)) + goto error; + + ie = wpa_bss_get_ie(bss, 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_bss_get_vendor_ie(bss, 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_bss_get_ie(bss, 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_bss_get_vendor_ie(bss, 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 (bss->freq) { + if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", + bss->freq)) + goto error; + } + if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", + bss->caps)) + goto error; + if (!(bss->flags & WPA_BSS_QUAL_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) + goto error; + if (!(bss->flags & WPA_BSS_NOISE_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) + goto error; + if (!(bss->flags & WPA_BSS_LEVEL_INVALID) && + !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", + wpa_bss_get_max_rate(bss) * 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, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "BSSID properties."); +} + + +/** + * wpas_dbus_iface_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 + * + * Handler function for "capabilities" method call of an interface. + */ +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_driver_capa capa; + int res; + DBusMessageIter iter, iter_dict; + char **eap_methods; + size_t num_items; + dbus_bool_t strict = FALSE; + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_BOOLEAN, &strict, + DBUS_TYPE_INVALID)) + strict = FALSE; + + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + /* EAP methods */ + eap_methods = eap_get_names_as_string_array(&num_items); + if (eap_methods) { + dbus_bool_t success = FALSE; + size_t i = 0; + + success = wpa_dbus_dict_append_string_array( + &iter_dict, "eap", (const char **) eap_methods, + num_items); + + /* free returned method array */ + while (eap_methods[i]) + os_free(eap_methods[i++]); + os_free(eap_methods); + + if (!success) + goto error; + } + + res = wpa_drv_get_capa(wpa_s, &capa); + + /***** pairwise cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = {"CCMP", "TKIP", "NONE"}; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "pairwise", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** group cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "CCMP", "TKIP", "WEP104", "WEP40" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "group", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP104")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP40")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** key management */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", + "NONE" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "key_mgmt", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "NONE")) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "IEEE8021X")) + goto error; + + 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 error; + } + + 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 error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** WPA protocol */ + if (res < 0) { + if (!strict) { + const char *args[] = { "RSN", "WPA" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "proto", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + 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 error; + } + + 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 error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** auth alg */ + if (res < 0) { + if (!strict) { + const char *args[] = { "OPEN", "SHARED", "LEAP" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "auth_alg", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "OPEN")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "SHARED")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "LEAP")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + 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, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "interface capabilities."); +} + + +/** + * wpas_dbus_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_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_ssid *ssid; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_NETWORK_ERROR, + "wpa_supplicant could not add " + "a network on this interface."); + goto out; + } + wpas_notify_network_added(wpa_s, ssid); + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + /* Construct the object path for this network. */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NETWORKS_PART "/%d", + wpa_s->dbus_path, ssid->id); + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_remove_network - Remove a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "removeNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_iface_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; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + /* Extract the network ID */ + iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); + if (iface == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + /* Ensure the network is actually a child of this interface */ + if (os_strcmp(iface, wpa_s->dbus_path) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + id = strtoul(net_id, NULL, 10); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + wpas_notify_network_removed(wpa_s, ssid); + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_NETWORK_ERROR, + "error removing the specified " + "on this interface."); + goto out; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + reply = wpas_dbus_new_success_reply(message); + +out: + os_free(iface); + os_free(net_id); + return reply; +} + + +static const char *dont_quote[] = { + "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", + "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", + "bssid", 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; +} + + +/** + * wpas_dbus_iface_set_network - Set options for a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "set" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + DBusMessage *reply = NULL; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter, iter_dict; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) { + reply = wpas_dbus_new_invalid_opts_error(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_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Type conversions, since wpa_supplicant wants strings */ + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = os_strlen(entry.str_value); + /* Zero-length option check */ + if (size <= 0) + goto error; + size += 3; /* For quotes and terminator */ + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = os_snprintf(value, size, "\"%s\"", + entry.str_value); + if (ret < 0 || (size_t) ret != (size - 1)) + goto error; + } else { + value = os_strdup(entry.str_value); + if (value == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = os_snprintf(value, size, "%u", + entry.uint32_value); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = os_snprintf(value, size, "%d", + entry.int32_value); + if (ret <= 0) + goto error; + } else + goto error; + + if (wpa_config_set(ssid, entry.key, value, 0) < 0) + goto error; + + if ((os_strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + else if (os_strcmp(entry.key, "priority") == 0) + wpa_config_update_prio_list(wpa_s->conf); + + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + continue; + + error: + os_free(value); + reply = wpas_dbus_new_invalid_opts_error(message, entry.key); + wpa_dbus_dict_entry_clear(&entry); + break; + } + + if (!reply) + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_enable_network - Mark a configured network as enabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "enable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + wpa_supplicant_enable_network(wpa_s, ssid); + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_disable_network - Mark a configured network as disabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + wpa_supplicant_disable_network(wpa_s, ssid); + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_select_network - Attempt association with a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "selectNetwork" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + struct wpa_ssid *ssid; + char *iface_obj_path = NULL; + char *network = NULL; + + if (os_strlen(dbus_message_get_signature(message)) == 0) { + /* Any network */ + ssid = NULL; + } else { + int nid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Extract the network number */ + iface_obj_path = wpas_dbus_decompose_object_path(op, + &network, + NULL); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + /* Ensure the object path really points to this interface */ + if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + nid = strtoul(network, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, nid); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + } + + /* Finally, associate with the network */ + wpa_supplicant_select_network(wpa_s, ssid); + + reply = wpas_dbus_new_success_reply(message); + +out: + os_free(iface_obj_path); + os_free(network); + return reply; +} + + +/** + * wpas_dbus_iface_disconnect - Terminate the current connection + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->disconnected = 1; + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_set_ap_scan - Control roaming mode + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "setAPScan" method call. + */ +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t ap_scan = 1; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "setSmartcardModules" method call. + */ +DBusMessage * wpas_dbus_iface_set_smartcard_modules( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter, iter_dict; + char *opensc_engine_path = NULL; + char *pkcs11_engine_path = NULL; + char *pkcs11_module_path = NULL; + struct wpa_dbus_dict_entry entry; + + if (!dbus_message_iter_init(message, &iter)) + goto error; + + 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, "opensc_engine_path") && + (entry.type == DBUS_TYPE_STRING)) { + opensc_engine_path = os_strdup(entry.str_value); + if (opensc_engine_path == NULL) + goto error; + } else if (!strcmp(entry.key, "pkcs11_engine_path") && + (entry.type == DBUS_TYPE_STRING)) { + pkcs11_engine_path = os_strdup(entry.str_value); + if (pkcs11_engine_path == NULL) + goto error; + } else if (!strcmp(entry.key, "pkcs11_module_path") && + (entry.type == DBUS_TYPE_STRING)) { + pkcs11_module_path = os_strdup(entry.str_value); + if (pkcs11_module_path == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } + + os_free(wpa_s->conf->opensc_engine_path); + wpa_s->conf->opensc_engine_path = opensc_engine_path; + os_free(wpa_s->conf->pkcs11_engine_path); + wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; + os_free(wpa_s->conf->pkcs11_module_path); + wpa_s->conf->pkcs11_module_path = pkcs11_module_path; + + wpa_sm_set_eapol(wpa_s->wpa, NULL); + eapol_sm_deinit(wpa_s->eapol); + wpa_s->eapol = NULL; + wpa_supplicant_init_eapol(wpa_s); + wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); + + return wpas_dbus_new_success_reply(message); + +error: + os_free(opensc_engine_path); + os_free(pkcs11_engine_path); + os_free(pkcs11_module_path); + return wpas_dbus_new_invalid_opts_error(message, NULL); +} + + +/** + * wpas_dbus_iface_get_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 + * + * Handler function for "state" method call. + */ +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *str_state; + + reply = dbus_message_new_method_return(message); + if (reply != NULL) { + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, + DBUS_TYPE_INVALID); + } + + return reply; +} + + +/** + * wpas_dbus_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 + * + * Handler function for "scanning" method call. + */ +DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; + + reply = dbus_message_new_method_return(message); + if (reply != NULL) { + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning, + DBUS_TYPE_INVALID); + } else { + wpa_printf(MSG_ERROR, "dbus: Not enough memory to return " + "scanning state"); + } + + return reply; +} + + +/** + * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Asks wpa_supplicant to internally store a one or more binary blobs. + */ +DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter, iter_dict; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + struct wpa_config_blob *blob; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + break; + } + + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE) { + reply = wpas_dbus_new_invalid_opts_error( + message, "Byte array expected."); + break; + } + + if ((entry.array_len <= 0) || (entry.array_len > 65536) || + !strlen(entry.key)) { + reply = wpas_dbus_new_invalid_opts_error( + message, "Invalid array size."); + break; + } + + blob = os_zalloc(sizeof(*blob)); + if (blob == NULL) { + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Not enough memory to add blob."); + break; + } + blob->data = os_zalloc(entry.array_len); + if (blob->data == NULL) { + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Not enough memory to add blob data."); + os_free(blob); + break; + } + + blob->name = os_strdup(entry.key); + blob->len = entry.array_len; + os_memcpy(blob->data, (u8 *) entry.bytearray_value, + entry.array_len); + if (blob->name == NULL || blob->data == NULL) { + wpa_config_free_blob(blob); + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Error adding blob."); + break; + } + + /* Success */ + if (!wpa_config_remove_blob(wpa_s->conf, blob->name)) + wpas_notify_blob_removed(wpa_s, blob->name); + wpa_config_set_blob(wpa_s->conf, blob); + wpas_notify_blob_added(wpa_s, blob->name); + + wpa_dbus_dict_entry_clear(&entry); + } + wpa_dbus_dict_entry_clear(&entry); + + return reply ? reply : wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_remove_blob - Remove named binary blobs + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * 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) +{ + DBusMessageIter iter, array; + char *err_msg = NULL; + + dbus_message_iter_init(message, &iter); + + if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) || + (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + dbus_message_iter_recurse(&iter, &array); + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { + const char *name; + + dbus_message_iter_get_basic(&array, &name); + if (!os_strlen(name)) + err_msg = "Invalid blob name."; + + if (wpa_config_remove_blob(wpa_s->conf, name) != 0) + err_msg = "Error removing blob."; + else + wpas_notify_blob_removed(wpa_s, name); + dbus_message_iter_next(&array); + } + + if (err_msg) + return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, + err_msg); + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant 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 "flush" method call. Handles requests for an + * interface with an optional "age" parameter that specifies the minimum + * age of a BSS to be flushed. + */ +DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int flush_age = 0; + + if (os_strlen(dbus_message_get_signature(message)) != 0 && + !dbus_message_get_args(message, NULL, + DBUS_TYPE_INT32, &flush_age, + DBUS_TYPE_INVALID)) { + return wpas_dbus_new_invalid_opts_error(message, NULL); + } + + if (flush_age == 0) + wpa_bss_flush(wpa_s); + else + wpa_bss_flush_by_age(wpa_s, flush_age); + + return wpas_dbus_new_success_reply(message); +} diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h new file mode 100644 index 0000000..009e807 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_old_handlers.h @@ -0,0 +1,107 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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_HANDLERS_H +#define CTRL_IFACE_DBUS_HANDLERS_H + +struct wpa_bss; + +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message); + +DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); + +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_smartcard_modules( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message); +DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, + const char *arg); + +#endif /* CTRL_IFACE_DBUS_HANDLERS_H */ + diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c new file mode 100644 index 0000000..c04b844 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c @@ -0,0 +1,163 @@ +/* + * WPA Supplicant / dbus-based control interface (WPS) + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> 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. + */ + +#include "includes.h" +#include <dbus/dbus.h> + +#include "common.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../wps_supplicant.h" +#include "dbus_old.h" +#include "dbus_old_handlers.h" + +/** + * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "wpsPbc" method call + */ +DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + char *arg_bssid = NULL; + u8 bssid[ETH_ALEN]; + int ret = 0; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, + DBUS_TYPE_INVALID)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + if (!os_strcmp(arg_bssid, "any")) + ret = wpas_wps_start_pbc(wpa_s, NULL, 0); + else if (!hwaddr_aton(arg_bssid, bssid)) + ret = wpas_wps_start_pbc(wpa_s, bssid, 0); + else { + return wpas_dbus_new_invalid_opts_error(message, + "Invalid BSSID"); + } + + if (ret < 0) { + return dbus_message_new_error(message, + WPAS_ERROR_WPS_PBC_ERROR, + "Could not start PBC " + "negotiation"); + } + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "wpsPin" method call + */ +DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + char *arg_bssid; + char *pin = NULL; + u8 bssid[ETH_ALEN], *_bssid = NULL; + int ret = 0; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, + DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + if (!os_strcmp(arg_bssid, "any")) + _bssid = NULL; + else if (!hwaddr_aton(arg_bssid, bssid)) + _bssid = bssid; + else { + return wpas_dbus_new_invalid_opts_error(message, + "Invalid BSSID"); + } + + if (os_strlen(pin) > 0) + ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, + DEV_PW_DEFAULT); + else + ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, + DEV_PW_DEFAULT); + + if (ret < 0) { + return dbus_message_new_error(message, + WPAS_ERROR_WPS_PIN_ERROR, + "Could not init PIN"); + } + + reply = dbus_message_new_method_return(message); + if (reply == NULL) + return NULL; + + if (ret == 0) { + dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin, + DBUS_TYPE_INVALID); + } else { + char npin[9]; + os_snprintf(npin, sizeof(npin), "%08d", ret); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin, + DBUS_TYPE_INVALID); + } + return reply; +} + + +/** + * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "wpsReg" method call + */ +DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + char *arg_bssid; + char *pin = NULL; + u8 bssid[ETH_ALEN]; + int ret = 0; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, + DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + if (!os_strcmp(arg_bssid, "any")) + ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL); + else if (!hwaddr_aton(arg_bssid, bssid)) + ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL); + else { + return wpas_dbus_new_invalid_opts_error(message, + "Invalid BSSID"); + } + + if (ret < 0) { + return dbus_message_new_error(message, + WPAS_ERROR_WPS_PBC_ERROR, + "Could not request credentials"); + } + + return wpas_dbus_new_success_reply(message); +} diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service new file mode 100644 index 0000000..a9ce1ec --- /dev/null +++ b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=fi.epitest.hostap.WPASupplicant +Exec=/sbin/wpa_supplicant -u +User=root diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service new file mode 100644 index 0000000..df78471 --- /dev/null +++ b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=fi.w1.wpa_supplicant1 +Exec=/sbin/wpa_supplicant -u +User=root |