diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2013-07-04 23:01:24 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2013-07-04 23:01:24 +0000 |
commit | 41a13be5c85dbdca536871231d280abef16b624f (patch) | |
tree | f45428f717037c3a3ecece29f7da1c3b6f43e112 /contrib/wpa/wpa_supplicant | |
parent | ddbb7a25f4e44f700d8e8363f0f2fc686cfd43be (diff) | |
parent | 5e9e13ee49049544adc4f40a42b737418896a338 (diff) | |
download | FreeBSD-src-41a13be5c85dbdca536871231d280abef16b624f.zip FreeBSD-src-41a13be5c85dbdca536871231d280abef16b624f.tar.gz |
Restore the dbus directory that was not meant to be deleted in r252729.
Diffstat (limited to 'contrib/wpa/wpa_supplicant')
25 files changed, 17173 insertions, 0 deletions
diff --git a/contrib/wpa/wpa_supplicant/dbus/.gitignore b/contrib/wpa/wpa_supplicant/dbus/.gitignore new file mode 100644 index 0000000..6db2468 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/.gitignore @@ -0,0 +1 @@ +libwpadbus.a diff --git a/contrib/wpa/wpa_supplicant/dbus/Makefile b/contrib/wpa/wpa_supplicant/dbus/Makefile new file mode 100644 index 0000000..d64c65c --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/Makefile @@ -0,0 +1,73 @@ +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 + +PKG_CONFIG ?= pkg-config +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 + +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/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf new file mode 100644 index 0000000..c091234 --- /dev/null +++ b/contrib/wpa/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/contrib/wpa/wpa_supplicant/dbus/dbus_common.c b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c new file mode 100644 index 0000000..5d0e31e --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c @@ -0,0 +1,365 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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/contrib/wpa/wpa_supplicant/dbus/dbus_common.h b/contrib/wpa/wpa_supplicant/dbus/dbus_common.h new file mode 100644 index 0000000..aea7db7 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.h @@ -0,0 +1,20 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h b/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h new file mode 100644 index 0000000..a551ccd --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h @@ -0,0 +1,28 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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; + +#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP) + int dbus_noc_refcnt; +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */ +}; + +#endif /* DBUS_COMMON_I_H */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c new file mode 100644 index 0000000..61a9430 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c @@ -0,0 +1,1104 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" +#include <dbus/dbus.h> + +#include "common.h" +#include "wpabuf.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 an 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 type The type of the contained data + * @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_array(DBusMessageIter *iter_dict, + const char *key, const char *type, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + char array_type[10]; + int err; + + err = os_snprintf(array_type, sizeof(array_type), + DBUS_TYPE_ARRAY_AS_STRING "%s", + type); + if (err < 0 || err > (int) sizeof(array_type)) + return FALSE; + + 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, + array_type, + iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, + type, iter_array)) + return FALSE; + + return TRUE; +} + + +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) +{ + return wpa_dbus_dict_begin_array( + iter_dict, key, + DBUS_TYPE_STRING_AS_STRING, + iter_dict_entry, iter_dict_val, iter_array); +} + + +/** + * 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); +} + + +/** + * Add a single byte array element to a string array dict entry + * + * @param iter_array A valid DBusMessageIter returned from + * wpa_dbus_dict_begin_array()'s iter_array + * parameter -- note that wpa_dbus_dict_begin_array() + * must have been called with "ay" as the type + * @param value The data to be added to the dict entry's array + * @param value_len The length of the data + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array, + const u8 *value, + size_t value_len) +{ + DBusMessageIter iter_bytes; + size_t i; + + if (!iter_array || !value) + return FALSE; + + if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &iter_bytes)) + return FALSE; + + for (i = 0; i < value_len; i++) { + if (!dbus_message_iter_append_basic(&iter_bytes, + DBUS_TYPE_BYTE, + &(value[i]))) + return FALSE; + } + + if (!dbus_message_iter_close_container(iter_array, &iter_bytes)) + return FALSE; + + return TRUE; +} + + +/** + * End an 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_begin_string_array() or + * wpa_dbus_dict_begin_array() + * @param iter_dict_val A private DBusMessageIter returned from + * wpa_dbus_dict_begin_string_array() or + * wpa_dbus_dict_begin_array() + * @param iter_array A DBusMessageIter returned from + * wpa_dbus_dict_begin_string_array() or + * wpa_dbus_dict_begin_array() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_end_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; +} + + +/** + * Convenience function to add an wpabuf binary 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 wpabuf structures + * @param num_items The number of strings in the array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict, + const char *key, + const struct wpabuf **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_array(iter_dict, key, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &iter_dict_entry, &iter_dict_val, + &iter_array)) + return FALSE; + + for (i = 0; i < num_items; i++) { + if (!wpa_dbus_dict_bin_array_add_element(&iter_array, + wpabuf_head(items[i]), + wpabuf_len(items[i]))) + return FALSE; + } + + if (!wpa_dbus_dict_end_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() + * @error on failure a descriptive error + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict, + DBusError *error) +{ + if (!iter || !iter_dict) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "[internal] missing message iterators"); + return FALSE; + } + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) { + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "unexpected message argument types"); + 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, 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_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_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_array( + buffer, count + BYTE_ARRAY_CHUNK_SIZE, + BYTE_ARRAY_ITEM_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_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_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_array( + buffer, count + STR_ARRAY_CHUNK_SIZE, + STR_ARRAY_ITEM_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; +} + + +#define BIN_ARRAY_CHUNK_SIZE 10 +#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_binarray( + DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) +{ + struct wpa_dbus_dict_entry tmpentry; + size_t buflen = 0; + int i; + + if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE) + return FALSE; + + entry->array_type = WPAS_DBUS_TYPE_BINARRAY; + entry->array_len = 0; + entry->binarray_value = NULL; + + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) { + DBusMessageIter iter_array; + + if (entry->array_len == buflen) { + struct wpabuf **newbuf; + + buflen += BIN_ARRAY_CHUNK_SIZE; + + newbuf = os_realloc_array(entry->binarray_value, + buflen, BIN_ARRAY_ITEM_SIZE); + if (!newbuf) + goto cleanup; + entry->binarray_value = newbuf; + } + + dbus_message_iter_recurse(iter, &iter_array); + if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry) + == FALSE) + goto cleanup; + + entry->binarray_value[entry->array_len] = + wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value, + tmpentry.array_len); + if (entry->binarray_value[entry->array_len] == NULL) { + wpa_dbus_dict_entry_clear(&tmpentry); + goto cleanup; + } + entry->array_len++; + dbus_message_iter_next(iter); + } + + return TRUE; + + cleanup: + for (i = 0; i < (int) entry->array_len; i++) + wpabuf_free(entry->binarray_value[i]); + os_free(entry->binarray_value); + entry->array_len = 0; + entry->binarray_value = NULL; + return FALSE; +} + + +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, + entry); + break; + case DBUS_TYPE_STRING: + success = _wpa_dbus_dict_entry_get_string_array(&iter_array, + array_type, + entry); + break; + case DBUS_TYPE_ARRAY: + success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry); + 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; + case WPAS_DBUS_TYPE_BINARRAY: + for (i = 0; i < entry->array_len; i++) + wpabuf_free(entry->binarray_value[i]); + os_free(entry->binarray_value); + break; + } + break; + } + + os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); +} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h new file mode 100644 index 0000000..9666349 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h @@ -0,0 +1,163 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DBUS_DICT_HELPERS_H +#define DBUS_DICT_HELPERS_H + +#include "wpabuf.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 array elements */ +dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict, + const char *key, const char *type, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +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_bin_array_add_element(DBusMessageIter *iter_array, + const u8 *value, + size_t value_len); + +dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +static inline dbus_bool_t +wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry, + iter_dict_val, 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); + +dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict, + const char *key, + const struct wpabuf **items, + const dbus_uint32_t num_items); + +/* + * Reading a dict from a DBusMessage + */ + +#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100) + +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, or the special + WPAS_DBUS_TYPE_BINARRAY */ + 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; + struct wpabuf **binarray_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, + DBusError *error); + +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/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c new file mode 100644 index 0000000..8bc6618 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c @@ -0,0 +1,3710 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "common/ieee802_11_defs.h" +#include "wps/wps.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../bss.h" +#include "../wpas_glue.h" +#include "dbus_new_helpers.h" +#include "dbus_dict_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_common_i.h" +#include "dbus_new_handlers_p2p.h" +#include "p2p/p2p.h" + +#ifdef CONFIG_AP /* until needed by something else */ + +/* + * NameOwnerChanged handling + * + * Some services we provide allow an application to register for + * a signal that it needs. While it can also unregister, we must + * be prepared for the case where the application simply crashes + * and thus doesn't clean up properly. The way to handle this in + * DBus is to register for the NameOwnerChanged signal which will + * signal an owner change to NULL if the peer closes the socket + * for whatever reason. + * + * Handle this signal via a filter function whenever necessary. + * The code below also handles refcounting in case in the future + * there will be multiple instances of this subscription scheme. + */ +static const char wpas_dbus_noc_filter_str[] = + "interface=org.freedesktop.DBus,member=NameOwnerChanged"; + + +static DBusHandlerResult noc_filter(DBusConnection *conn, + DBusMessage *message, void *data) +{ + struct wpas_dbus_priv *priv = data; + + if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) { + const char *name; + const char *prev_owner; + const char *new_owner; + DBusError derr; + struct wpa_supplicant *wpa_s; + + dbus_error_init(&derr); + + if (!dbus_message_get_args(message, &derr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &prev_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { + /* Ignore this error */ + dbus_error_free(&derr); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) + { + if (wpa_s->preq_notify_peer != NULL && + os_strcmp(name, wpa_s->preq_notify_peer) == 0 && + (new_owner == NULL || os_strlen(new_owner) == 0)) { + /* probe request owner disconnected */ + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + wpas_dbus_unsubscribe_noc(priv); + } + } + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv) +{ + priv->dbus_noc_refcnt++; + if (priv->dbus_noc_refcnt > 1) + return; + + if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) { + wpa_printf(MSG_ERROR, "dbus: failed to add filter"); + return; + } + + dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL); +} + + +void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv) +{ + priv->dbus_noc_refcnt--; + if (priv->dbus_noc_refcnt > 0) + return; + + dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL); + dbus_connection_remove_filter(priv->con, noc_filter, priv); +} + +#endif /* CONFIG_AP */ + + +/** + * 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; + + 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_get_object_properties( + iface, wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)) + 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; + + 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_get_object_properties(iface, bss_obj_path, + WPAS_DBUS_NEW_IFACE_BSS, + &iter)) + 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; + 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_get_object_properties( + iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK, + &iter)) + 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_request - Indicate that additional information + * (EAP password, etc.) is required to complete the association to this SSID + * @wpa_s: %wpa_supplicant network interface data + * @rtype: The specific additional information required + * @default_text: Optional description of required information + * + * Request additional information or passwords to complete an association + * request. + */ +void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + enum wpa_ctrl_req_type rtype, + const char *default_txt) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + const char *field, *txt = NULL, *net_ptr; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt); + if (field == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NetworkRequest"); + if (msg == NULL) + return; + + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, ssid->id); + net_ptr = &net_obj_path[0]; + + dbus_message_iter_init_append(msg, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &net_ptr)) + goto err; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field)) + goto err; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt)) + 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_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 */ + +void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + + 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, + "Certification"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto nomem; + + if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) || + !wpa_dbus_dict_append_string(&dict_iter, "subject", subject)) + goto nomem; + + if (cert_hash && + !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash)) + goto nomem; + + if (cert && + !wpa_dbus_dict_append_byte_array(&dict_iter, "cert", + wpabuf_head(cert), + wpabuf_len(cert))) + goto nomem; + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, const char *parameter) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + + 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, + "EAP"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) + || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + ¶meter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + + +#ifdef CONFIG_P2P + +/** + * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed + * @wpa_s: %wpa_supplicant network interface data + * @role: role of this device (client or GO) + * Sends signal with i/f name and role as string arguments + */ +void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, + const char *role) +{ + + DBusMessage *msg; + DBusMessageIter iter; + struct wpas_dbus_priv *iface = wpa_s->global->dbus; + char *ifname = wpa_s->ifname; + + /* 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_P2PDEVICE, + "GroupFinished"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) { + wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished" + "signal -not enough memory for ifname "); + goto err; + } + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished" + "signal -not enough memory for role "); + else + dbus_connection_send(iface->con, msg, NULL); + +err: + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events + * + * @dev_addr - who sent the request or responded to our request. + * @request - Will be 1 if request, 0 for response. + * @status - valid only in case of response + * @config_methods - wps config methods + * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method + * + * Sends following provision discovery related events: + * ProvisionDiscoveryRequestDisplayPin + * ProvisionDiscoveryResponseDisplayPin + * ProvisionDiscoveryRequestEnterPin + * ProvisionDiscoveryResponseEnterPin + * ProvisionDiscoveryPBCRequest + * ProvisionDiscoveryPBCResponse + * + * TODO:: + * ProvisionDiscoveryFailure (timeout case) + */ +void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, + const u8 *dev_addr, int request, + enum p2p_prov_disc_status status, + u16 config_methods, + unsigned int generated_pin) +{ + DBusMessage *msg; + DBusMessageIter iter; + struct wpas_dbus_priv *iface; + char *_signal; + int add_pin = 0; + char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + int error_ret = 1; + char pin[9], *p_pin = NULL; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + if (request || !status) { + if (config_methods & WPS_CONFIG_DISPLAY) + _signal = request ? + "ProvisionDiscoveryRequestDisplayPin" : + "ProvisionDiscoveryResponseEnterPin"; + else if (config_methods & WPS_CONFIG_KEYPAD) + _signal = request ? + "ProvisionDiscoveryRequestEnterPin" : + "ProvisionDiscoveryResponseDisplayPin"; + else if (config_methods & WPS_CONFIG_PUSHBUTTON) + _signal = request ? "ProvisionDiscoveryPBCRequest" : + "ProvisionDiscoveryPBCResponse"; + else + return; /* Unknown or un-supported method */ + } else if (!request && status) + /* Explicit check for failure response */ + _signal = "ProvisionDiscoveryFailure"; + + add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) || + (!request && !status && + (config_methods & WPS_CONFIG_KEYPAD))); + + if (add_pin) { + os_snprintf(pin, sizeof(pin), "%08d", generated_pin); + p_pin = pin; + } + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal); + if (msg == NULL) + return; + + /* Check if this is a known peer */ + if (!p2p_peer_known(wpa_s->global->p2p, dev_addr)) + goto error; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" + COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(dev_addr)); + + path = peer_obj_path; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, + DBUS_TYPE_OBJECT_PATH, + &path)) + goto error; + + if (!request && status) + /* Attach status to ProvisionDiscoveryFailure */ + error_ret = !dbus_message_iter_append_basic(&iter, + DBUS_TYPE_INT32, + &status); + else + error_ret = (add_pin && + !dbus_message_iter_append_basic(&iter, + DBUS_TYPE_STRING, + &p_pin)); + +error: + if (!error_ret) + dbus_connection_send(iface->con, msg, NULL); + else + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 dev_passwd_id) +{ + DBusMessage *msg; + DBusMessageIter iter; + struct wpas_dbus_priv *iface; + char peer_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(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(src)); + path = peer_obj_path; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "GONegotiationRequest"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16, + &dev_passwd_id)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + +static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + char *group_obj_path) +{ + char group_name[3]; + + if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)) + return -1; + + os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2); + group_name[2] = '\0'; + + os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s", + wpa_s->dbus_new_path, group_name); + + return 0; +} + + +/** + * wpas_dbus_signal_p2p_group_started - Signals P2P group has + * started. Emitted when a group is successfully started + * irrespective of the role (client/GO) of the current device + * + * @wpa_s: %wpa_supplicant network interface data + * @ssid: SSID object + * @client: this device is P2P client + * @network_id: network id of the group started, use instead of ssid->id + * to account for persistent groups + */ +void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + int client, int network_id) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; + + iface = wpa_s->parent->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0) + return; + + /* New interface has been created for this group */ + msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "GroupStarted"); + + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto nomem; + + /* + * In case the device supports creating a separate interface the + * DBus client will need to know the object path for the interface + * object this group was created on, so include it here. + */ + if (!wpa_dbus_dict_append_object_path(&dict_iter, + "interface_object", + wpa_s->dbus_new_path)) + goto nomem; + + if (!wpa_dbus_dict_append_string(&dict_iter, "role", + client ? "client" : "GO")) + goto nomem; + + if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object", + group_obj_path) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + + +/** + * + * Method to emit GONeogtiation Success or Failure signals based + * on status. + * @status: Status of the GO neg request. 0 for success, other for errors. + */ +void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, + struct p2p_go_neg_results *res) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array; + struct wpas_dbus_priv *iface; + char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + dbus_int32_t freqs[P2P_MAX_CHANNELS]; + dbus_int32_t *f_array = freqs; + + + iface = wpa_s->global->dbus; + + os_memset(freqs, 0, sizeof(freqs)); + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr)); + path = peer_obj_path; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + res->status ? "GONegotiationFailure" : + "GONegotiationSuccess"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto err; + if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", + path) || + !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status)) + goto err; + + if (!res->status) { + int i = 0; + int freq_list_num = 0; + + if (res->role_go) { + if (!wpa_dbus_dict_append_byte_array( + &dict_iter, "passphrase", + (const char *) res->passphrase, + sizeof(res->passphrase))) + goto err; + } + + if (!wpa_dbus_dict_append_string(&dict_iter, "role_go", + res->role_go ? "GO" : + "client") || + !wpa_dbus_dict_append_int32(&dict_iter, "frequency", + res->freq) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid", + (const char *) res->ssid, + res->ssid_len) || + !wpa_dbus_dict_append_byte_array(&dict_iter, + "peer_device_addr", + (const char *) + res->peer_device_addr, + ETH_ALEN) || + !wpa_dbus_dict_append_byte_array(&dict_iter, + "peer_interface_addr", + (const char *) + res->peer_interface_addr, + ETH_ALEN) || + !wpa_dbus_dict_append_string(&dict_iter, "wps_method", + p2p_wps_method_text( + res->wps_method))) + goto err; + + for (i = 0; i < P2P_MAX_CHANNELS; i++) { + if (res->freq_list[i]) { + freqs[i] = res->freq_list[i]; + freq_list_num++; + } + } + + if (!wpa_dbus_dict_begin_array(&dict_iter, + "frequency_list", + DBUS_TYPE_INT32_AS_STRING, + &iter_dict_entry, + &iter_dict_val, + &iter_dict_array)) + goto err; + + if (!dbus_message_iter_append_fixed_array(&iter_dict_array, + DBUS_TYPE_INT32, + &f_array, + freq_list_num)) + goto err; + + if (!wpa_dbus_dict_end_array(&dict_iter, + &iter_dict_entry, + &iter_dict_val, + &iter_dict_array)) + goto err; + + if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group", + res->persistent_group) || + !wpa_dbus_dict_append_uint32(&dict_iter, + "peer_config_timeout", + res->peer_config_timeout)) + goto err; + } + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto err; + + dbus_connection_send(iface->con, msg, NULL); +err: + dbus_message_unref(msg); +} + + +/** + * + * Method to emit Invitation Result signal based on status and + * bssid + * @status: Status of the Invite request. 0 for success, other + * for errors + * @bssid : Basic Service Set Identifier + */ +void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s, + int status, const u8 *bssid) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + + wpa_printf(MSG_INFO, "%s\n", __func__); + + 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_P2PDEVICE, + "InvitationResult"); + + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto nomem; + + if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status)) + goto nomem; + if (bssid) { + if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID", + (const char *) bssid, + ETH_ALEN)) + goto nomem; + } + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + + +/** + * + * Method to emit a signal for a peer joining the group. + * The signal will carry path to the group member object + * constructed using p2p i/f addr used for connecting. + * + * @wpa_s: %wpa_supplicant network interface data + * @member_addr: addr (p2p i/f) of the peer joining the group + */ +void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, + const u8 *member) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char groupmember_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; + + if (!wpa_s->dbus_groupobj_path) + return; + + os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" + COMPACT_MACSTR, + wpa_s->dbus_groupobj_path, MAC2STR(member)); + + msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path, + WPAS_DBUS_NEW_IFACE_P2P_GROUP, + "PeerJoined"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + path = groupmember_obj_path; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path)) + 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); +} + + +/** + * + * Method to emit a signal for a peer disconnecting the group. + * The signal will carry path to the group member object + * constructed using p2p i/f addr used for connecting. + * + * @wpa_s: %wpa_supplicant network interface data + * @member_addr: addr (p2p i/f) of the peer joining the group + */ +void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *member) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char groupmember_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; + + if (!wpa_s->dbus_groupobj_path) + return; + + os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" + COMPACT_MACSTR, + wpa_s->dbus_groupobj_path, MAC2STR(member)); + + msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path, + WPAS_DBUS_NEW_IFACE_P2P_GROUP, + "PeerDisconnected"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + path = groupmember_obj_path; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path)) + goto err; + + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); + return; + +err: + wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected " + "signal"); + dbus_message_unref(msg); +} + + +/** + * + * Method to emit a signal for a service discovery request. + * The signal will carry station address, frequency, dialog token, + * update indicator and it tlvs + * + * @wpa_s: %wpa_supplicant network interface data + * @sa: station addr (p2p i/f) of the peer + * @dialog_token: service discovery request dialog token + * @update_indic: service discovery request update indicator + * @tlvs: service discovery request genrated byte array of tlvs + * @tlvs_len: service discovery request tlvs length + */ +void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, + int freq, const u8 *sa, u8 dialog_token, + u16 update_indic, const u8 *tlvs, + size_t tlvs_len) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char peer_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; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "ServiceDiscoveryRequest"); + if (msg == NULL) + return; + + /* Check if this is a known peer */ + if (!p2p_peer_known(wpa_s->global->p2p, sa)) + goto error; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" + COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa)); + + path = peer_obj_path; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto error; + + + if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", + path) || + !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) || + !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token", + dialog_token) || + !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator", + update_indic) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs", + (const char *) tlvs, + tlvs_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto error; + + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); + return; +error: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + + +/** + * + * Method to emit a signal for a service discovery response. + * The signal will carry station address, update indicator and it + * tlvs + * + * @wpa_s: %wpa_supplicant network interface data + * @sa: station addr (p2p i/f) of the peer + * @update_indic: service discovery request update indicator + * @tlvs: service discovery request genrated byte array of tlvs + * @tlvs_len: service discovery request tlvs length + */ +void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, + const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *iface; + char peer_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; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "ServiceDiscoveryResponse"); + if (msg == NULL) + return; + + /* Check if this is a known peer */ + if (!p2p_peer_known(wpa_s->global->p2p, sa)) + goto error; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" + COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa)); + + path = peer_obj_path; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto error; + + if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", + path) || + !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator", + update_indic) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs", + (const char *) tlvs, + tlvs_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto error; + + + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); + return; +error: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} + +/** + * wpas_dbus_signal_persistent_group - Send a persistent group related + * event signal + * @wpa_s: %wpa_supplicant network interface data + * @id: new persistent group id + * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved + * @properties: determines if add second argument with object properties + * + * Notify listeners about an event related to persistent groups. + */ +static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s, + int id, const char *sig_name, + int properties) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char pgrp_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(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", + wpa_s->dbus_new_path, id); + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + sig_name); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + path = pgrp_obj_path; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path)) + goto err; + + if (properties) { + if (!wpa_dbus_get_object_properties( + iface, pgrp_obj_path, + WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)) + 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_persistent_group_added - Send a persistent_group + * added signal + * @wpa_s: %wpa_supplicant network interface data + * @id: new persistent group id + * + * Notify listeners about addition of a new persistent group. + */ +static void wpas_dbus_signal_persistent_group_added( + struct wpa_supplicant *wpa_s, int id) +{ + wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded", + TRUE); +} + + +/** + * wpas_dbus_signal_persistent_group_removed - Send a persistent_group + * removed signal + * @wpa_s: %wpa_supplicant network interface data + * @id: persistent group id + * + * Notify listeners about removal of a persistent group. + */ +static void wpas_dbus_signal_persistent_group_removed( + struct wpa_supplicant *wpa_s, int id) +{ + wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved", + FALSE); +} + + +/** + * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed 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_p2p_wps_failed(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_P2PDEVICE, + "WpsFailed"); + 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_append_int16(&dict_iter, "config_error", + fail->config_error) || + !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); +} + +#endif /*CONFIG_P2P*/ + + +/** + * wpas_dbus_signal_prop_changed - Signals change of property + * @wpa_s: %wpa_supplicant network interface data + * @property: indicates which property has changed + * + * Sends PropertyChanged 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) +{ + char *prop; + dbus_bool_t flush; + + if (wpa_s->dbus_new_path == NULL) + return; /* Skip signal since D-Bus setup is not yet ready */ + + flush = FALSE; + switch (property) { + case WPAS_DBUS_PROP_AP_SCAN: + prop = "ApScan"; + break; + case WPAS_DBUS_PROP_SCANNING: + prop = "Scanning"; + break; + case WPAS_DBUS_PROP_STATE: + prop = "State"; + break; + case WPAS_DBUS_PROP_CURRENT_BSS: + prop = "CurrentBSS"; + break; + case WPAS_DBUS_PROP_CURRENT_NETWORK: + prop = "CurrentNetwork"; + break; + case WPAS_DBUS_PROP_BSSS: + prop = "BSSs"; + break; + case WPAS_DBUS_PROP_CURRENT_AUTH_MODE: + prop = "CurrentAuthMode"; + break; + case WPAS_DBUS_PROP_DISCONNECT_REASON: + prop = "DisconnectReason"; + flush = TRUE; + 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); + if (flush) { + wpa_dbus_flush_object_changed_properties( + wpa_s->global->dbus->con, wpa_s->dbus_new_path); + } +} + + +/** + * 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 PropertyChanged 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 PropertyChanged 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 PropertyChanged 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 + } + }, +#ifdef CONFIG_AUTOSCAN + { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_autoscan, + { + { "arg", "s", ARG_IN }, + END_ARGS + } + }, +#endif /* CONFIG_AUTOSCAN */ + { NULL, NULL, NULL, { END_ARGS } } +}; + +static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = { + { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s", + wpas_dbus_getter_debug_level, + wpas_dbus_setter_debug_level + }, + { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b", + wpas_dbus_getter_debug_timestamp, + wpas_dbus_setter_debug_timestamp + }, + { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b", + wpas_dbus_getter_debug_show_keys, + wpas_dbus_setter_debug_show_keys + }, + { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao", + wpas_dbus_getter_interfaces, + NULL + }, + { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as", + wpas_dbus_getter_eap_methods, + NULL + }, + { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as", + wpas_dbus_getter_global_capabilities, + NULL + }, + { NULL, NULL, NULL, NULL, NULL } +}; + +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 + } + }, + { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "path", "o", ARG_OUT }, + { "field", "s", ARG_OUT }, + { "text", "s", ARG_OUT }, + END_ARGS + } + }, + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "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}", + wpas_dbus_getter_network_properties, + wpas_dbus_setter_network_properties + }, + { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b", + wpas_dbus_getter_enabled, + wpas_dbus_setter_enabled + }, + { NULL, NULL, NULL, NULL, NULL } +}; + + +static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = { + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "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]; + +#ifdef CONFIG_P2P + /* + * If it is a persistent group register it as such. + * This is to handle cases where an interface is being initialized + * with a list of networks read from config. + */ + if (network_is_persistent_group(ssid)) + return wpas_dbus_register_persistent_group(wpa_s, ssid); +#endif /* CONFIG_P2P */ + + /* 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; +#ifdef CONFIG_P2P + struct wpa_ssid *ssid; + + ssid = wpa_config_get_network(wpa_s->conf, nid); + + /* If it is a persistent group unregister it as such */ + if (ssid && network_is_persistent_group(ssid)) + return wpas_dbus_unregister_persistent_group(wpa_s, nid); +#endif /* CONFIG_P2P */ + + /* Do nothing if the control interface is not turned on */ + if (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", + wpas_dbus_getter_bss_ssid, + NULL + }, + { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", + wpas_dbus_getter_bss_bssid, + NULL + }, + { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b", + wpas_dbus_getter_bss_privacy, + NULL + }, + { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s", + wpas_dbus_getter_bss_mode, + NULL + }, + { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n", + wpas_dbus_getter_bss_signal, + NULL + }, + { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q", + wpas_dbus_getter_bss_frequency, + NULL + }, + { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au", + wpas_dbus_getter_bss_rates, + NULL + }, + { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + wpas_dbus_getter_bss_wpa, + NULL + }, + { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + wpas_dbus_getter_bss_rsn, + NULL + }, + { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + wpas_dbus_getter_bss_wps, + NULL + }, + { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay", + wpas_dbus_getter_bss_ies, + NULL + }, + { NULL, NULL, NULL, NULL, NULL } +}; + + +static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = { + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "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 + } + }, + { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_reassociate, + { + 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 + } + }, + { "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_network_reply, + { + { "path", "o", ARG_IN }, + { "field", "s", ARG_IN }, + { "value", "s", 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 */ +#ifdef CONFIG_P2P + { "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_find, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find, + { + END_ARGS + } + }, + { "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen, + { + { "timeout", "i", ARG_IN }, + END_ARGS + } + }, + { "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req, + { + { "peer", "o", ARG_IN }, + { "config_method", "s", ARG_IN }, + END_ARGS + } + }, + { "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect, + { + { "args", "a{sv}", ARG_IN }, + { "generated_pin", "s", ARG_OUT }, + END_ARGS + } + }, + { "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect, + { + END_ARGS + } + }, + { "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer, + { + { "peer", "o", ARG_IN }, + END_ARGS + } + }, + { "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush, + { + END_ARGS + } + }, + { "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service, + { + END_ARGS + } + }, + { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + } + }, + { "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req, + { + { "args", "t", ARG_IN }, + END_ARGS + } + }, + { "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update, + { + END_ARGS + } + }, + { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external, + { + { "arg", "i", ARG_IN }, + END_ARGS + } + }, + { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external, + { + { "arg", "i", ARG_IN }, + END_ARGS + } + }, + { "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group, + { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group, + { + { "path", "o", ARG_IN }, + END_ARGS + } + }, + { "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + (WPADBusMethodHandler) + wpas_dbus_handler_remove_all_persistent_groups, + { + END_ARGS + } + }, +#endif /* CONFIG_P2P */ + { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss, + { + { "age", "u", ARG_IN }, + END_ARGS + } + }, +#ifdef CONFIG_AP + { "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq, + { + END_ARGS + } + }, + { "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq, + { + END_ARGS + } + }, +#endif /* CONFIG_AP */ + { NULL, NULL, NULL, { END_ARGS } } +}; + +static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { + { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}", + wpas_dbus_getter_capabilities, + NULL + }, + { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_state, + NULL + }, + { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", + wpas_dbus_getter_scanning, + NULL + }, + { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + wpas_dbus_getter_ap_scan, + wpas_dbus_setter_ap_scan + }, + { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + wpas_dbus_getter_bss_expire_age, + wpas_dbus_setter_bss_expire_age + }, + { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + wpas_dbus_getter_bss_expire_count, + wpas_dbus_setter_bss_expire_count + }, + { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_country, + wpas_dbus_setter_country + }, + { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_ifname, + NULL + }, + { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_driver, + NULL + }, + { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_bridge_ifname, + NULL + }, + { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", + wpas_dbus_getter_current_bss, + NULL + }, + { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", + wpas_dbus_getter_current_network, + NULL + }, + { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", + wpas_dbus_getter_current_auth_mode, + NULL + }, + { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}", + wpas_dbus_getter_blobs, + NULL + }, + { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", + wpas_dbus_getter_bsss, + NULL + }, + { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", + wpas_dbus_getter_networks, + NULL + }, + { "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", + wpas_dbus_getter_fast_reauth, + wpas_dbus_setter_fast_reauth + }, + { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", + wpas_dbus_getter_scan_interval, + wpas_dbus_setter_scan_interval + }, +#ifdef CONFIG_WPS + { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b", + wpas_dbus_getter_process_credentials, + wpas_dbus_setter_process_credentials + }, +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}", + wpas_dbus_getter_p2p_device_config, + wpas_dbus_setter_p2p_device_config + }, + { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", + wpas_dbus_getter_p2p_peers, + NULL + }, + { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s", + wpas_dbus_getter_p2p_role, + NULL + }, + { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", + wpas_dbus_getter_p2p_group, + NULL + }, + { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", + wpas_dbus_getter_p2p_peergo, + NULL + }, + { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", + wpas_dbus_getter_persistent_groups, + NULL + }, +#endif /* CONFIG_P2P */ + { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", + wpas_dbus_getter_disconnect_reason, + NULL + }, + { NULL, NULL, NULL, NULL, NULL } +}; + +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 + } + }, + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "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 + } + }, + /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ + { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "states", "a{ss}", ARG_OUT }, + END_ARGS + } + }, + { "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + { "pin", "s", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + { "pin", "s", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + END_ARGS + } + }, + { "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "peer_object", "o", ARG_OUT }, + { "status", "i", ARG_OUT }, + END_ARGS + } + }, + { "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + END_ARGS + } + }, + { "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "status", "i", ARG_OUT }, + END_ARGS + } + }, + { "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + { "dev_passwd_id", "i", ARG_OUT }, + END_ARGS + } + }, + { "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "invite_result", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "ifname", "s", ARG_OUT }, + { "role", "s", ARG_OUT }, + END_ARGS + } + }, + { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "sd_request", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "sd_response", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE, + { + { "name", "s", ARG_OUT }, + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_P2P */ +#ifdef CONFIG_AP + { "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "args", "a{sv}", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_AP */ + { "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "certification", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "status", "s", ARG_OUT }, + { "parameter", "s", ARG_OUT }, + END_ARGS + } + }, + { 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); + +#ifdef CONFIG_AP + if (wpa_s->preq_notify_peer) { + wpas_dbus_unsubscribe_noc(ctrl_iface); + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + } +#endif /* CONFIG_AP */ + + 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; +} + +#ifdef CONFIG_P2P + +static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = { + { "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", + wpas_dbus_getter_p2p_peer_device_name, + NULL + }, + { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", + wpas_dbus_getter_p2p_peer_primary_device_type, + NULL + }, + { "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q", + wpas_dbus_getter_p2p_peer_config_method, + NULL + }, + { "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i", + wpas_dbus_getter_p2p_peer_level, + NULL + }, + { "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", + wpas_dbus_getter_p2p_peer_device_capability, + NULL + }, + { "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", + wpas_dbus_getter_p2p_peer_group_capability, + NULL + }, + { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", + wpas_dbus_getter_p2p_peer_secondary_device_types, + NULL + }, + { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", + wpas_dbus_getter_p2p_peer_vendor_extension, + NULL + }, + { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", + wpas_dbus_getter_p2p_peer_ies, + NULL + }, + { NULL, NULL, NULL, NULL, NULL } +}; + +static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = { + + { NULL, NULL, { END_ARGS } } +}; + +/** + * wpas_dbus_signal_peer - Send a peer related event signal + * @wpa_s: %wpa_supplicant network interface data + * @dev: peer device object + * @interface: name of the interface emitting this signal. + * In case of peer objects, it would be emitted by either + * the "interface object" or by "peer objects" + * @sig_name: signal name - DeviceFound + * + * Notify listeners about event related with newly found p2p peer device + */ +static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr, const char *interface, + const char *sig_name) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char peer_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(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(dev_addr)); + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface, + sig_name); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + path = peer_obj_path; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path)) + 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_peer_found - Send a peer found signal + * @wpa_s: %wpa_supplicant network interface data + * @dev: peer device object + * + * Notify listeners about find a p2p peer device found + */ +void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ + wpas_dbus_signal_peer(wpa_s, dev_addr, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "DeviceFound"); +} + +/** + * wpas_dbus_signal_peer_lost - Send a peer lost signal + * @wpa_s: %wpa_supplicant network interface data + * @dev: peer device object + * + * Notify listeners about lost a p2p peer device + */ +void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ + wpas_dbus_signal_peer(wpa_s, dev_addr, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "DeviceLost"); +} + +/** + * wpas_dbus_register_peer - Register a discovered peer object 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_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + struct peer_handler_args *arg; + char peer_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(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(dev_addr)); + + wpa_printf(MSG_INFO, "dbus: Register peer object '%s'", + peer_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 peer_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for method"); + goto err; + } + + arg->wpa_s = wpa_s; + os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN); + + wpas_dbus_register(obj_desc, arg, wpa_dbus_free, + NULL, + wpas_dbus_p2p_peer_properties, + wpas_dbus_p2p_peer_signals); + + if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path, + wpa_s->ifname, obj_desc)) + goto err; + + return 0; + +err: + free_dbus_object_desc(obj_desc); + return -1; +} + +/** + * wpas_dbus_unregister_peer - Unregister a peer object with dbus + * @wpa_s: wpa_supplicant interface structure + * @dev_addr: p2p device addr + * Returns: 0 on success, -1 on failure + * + * Registers network representing object with dbus + */ +int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ + struct wpas_dbus_priv *ctrl_iface; + char peer_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(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(dev_addr)); + + wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'", + peer_obj_path); + ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path); + + return ret; +} + + +static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = { + { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao", + wpas_dbus_getter_p2p_group_members, + NULL + }, + { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o", + wpas_dbus_getter_p2p_group, + NULL + }, + { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", + wpas_dbus_getter_p2p_role, + NULL + }, + { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", + wpas_dbus_getter_p2p_group_ssid, + NULL + }, + { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", + wpas_dbus_getter_p2p_group_bssid, + NULL + }, + { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q", + wpas_dbus_getter_p2p_group_frequency, + NULL + }, + { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", + wpas_dbus_getter_p2p_group_passphrase, + NULL + }, + { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", + wpas_dbus_getter_p2p_group_psk, + NULL + }, + { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay", + wpas_dbus_getter_p2p_group_vendor_ext, + wpas_dbus_setter_p2p_group_vendor_ext + }, + { NULL, NULL, NULL, NULL, NULL } +}; + +static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = { + { "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP, + { + { "peer", "o", ARG_OUT }, + END_ARGS + } + }, + { "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP, + { + { "peer", "o", ARG_OUT }, + END_ARGS + } + }, + { NULL, NULL, { END_ARGS } } +}; + +/** + * wpas_dbus_register_p2p_group - Register a p2p group object with dbus + * @wpa_s: wpa_supplicant interface structure + * @ssid: SSID struct + * Returns: 0 on success, -1 on failure + * + * Registers p2p group representing object with dbus + */ +void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc; + char group_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; + + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return; + + if (wpa_s->dbus_groupobj_path) { + wpa_printf(MSG_INFO, "%s: Group object '%s' already exists", + __func__, wpa_s->dbus_groupobj_path); + return; + } + + if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0) + return; + + wpa_s->dbus_groupobj_path = os_strdup(group_obj_path); + if (wpa_s->dbus_groupobj_path == NULL) + return; + + wpa_printf(MSG_INFO, "dbus: Register group object '%s'", + group_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; + } + + wpas_dbus_register(obj_desc, wpa_s, NULL, NULL, + wpas_dbus_p2p_group_properties, + wpas_dbus_p2p_group_signals); + + if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path, + wpa_s->ifname, obj_desc)) + goto err; + + return; + +err: + if (wpa_s->dbus_groupobj_path) { + os_free(wpa_s->dbus_groupobj_path); + wpa_s->dbus_groupobj_path = NULL; + } + + free_dbus_object_desc(obj_desc); +} + +/** + * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus + * @wpa_s: wpa_supplicant interface structure + * @ssid: network name of the p2p group started + */ +void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid) +{ + 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; + + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return; + + if (!wpa_s->dbus_groupobj_path) { + wpa_printf(MSG_DEBUG, + "%s: Group object '%s' already unregistered", + __func__, wpa_s->dbus_groupobj_path); + return; + } + + wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'", + wpa_s->dbus_groupobj_path); + + wpa_dbus_unregister_object_per_iface(ctrl_iface, + wpa_s->dbus_groupobj_path); + + os_free(wpa_s->dbus_groupobj_path); + wpa_s->dbus_groupobj_path = NULL; +} + +static const struct wpa_dbus_property_desc +wpas_dbus_p2p_groupmember_properties[] = { + { NULL, NULL, NULL, NULL, NULL } +}; + +/** + * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember + * object with dbus + * @wpa_s: wpa_supplicant interface structure + * @p2p_if_addr: i/f addr of the device joining this group + * + * Registers p2p groupmember representing object with dbus + */ +void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr) +{ + struct wpas_dbus_priv *ctrl_iface; + struct wpa_dbus_object_desc *obj_desc = NULL; + struct groupmember_handler_args *arg; + char groupmember_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; + + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return; + + if (!wpa_s->dbus_groupobj_path) + return; + + os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr)); + + 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 groupmember_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, "Not enough memory " + "to create arguments for method"); + goto err; + } + + arg->wpa_s = wpa_s; + os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN); + + wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, + wpas_dbus_p2p_groupmember_properties, NULL); + + if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path, + wpa_s->ifname, obj_desc)) + goto err; + + wpa_printf(MSG_INFO, + "dbus: Registered group member object '%s' successfully", + groupmember_obj_path); + return; + +err: + free_dbus_object_desc(obj_desc); +} + +/** + * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember + * object with dbus + * @wpa_s: wpa_supplicant interface structure + * @p2p_if_addr: i/f addr of the device joining this group + * + * Unregisters p2p groupmember representing object with dbus + */ +void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr) +{ + struct wpas_dbus_priv *ctrl_iface; + char groupmember_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; + + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return; + + if (!wpa_s->dbus_groupobj_path) + return; + + os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr)); + + wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path); +} + + +static const struct wpa_dbus_property_desc + wpas_dbus_persistent_group_properties[] = { + { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}", + wpas_dbus_getter_persistent_group_properties, + wpas_dbus_setter_persistent_group_properties + }, + { NULL, NULL, NULL, NULL, NULL } +}; + +/* No signals intended for persistent group objects */ + +/** + * wpas_dbus_register_persistent_group - Register a configured(saved) + * persistent group with dbus + * @wpa_s: wpa_supplicant interface structure + * @ssid: persistent group (still represented as a network within wpa) + * configuration data + * Returns: 0 on success, -1 on failure + * + * Registers a persistent group representing object with dbus. + */ +int wpas_dbus_register_persistent_group(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 pgrp_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; + + /* Make sure ssid is a persistent group */ + if (ssid->disabled != 2 && !ssid->p2p_persistent_group) + return -1; /* should we return w/o complaining? */ + + ctrl_iface = wpa_s->global->dbus; + if (ctrl_iface == NULL) + return 0; + + /* + * Intentionally not coming up with different numbering scheme + * for persistent groups. + */ + os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", + wpa_s->dbus_new_path, ssid->id); + + wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'", + pgrp_obj_path); + obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "dbus: Not enough memory to create " + "object description"); + goto err; + } + + /* + * Reusing the same context structure as that for networks + * since these are represented using same data structure. + */ + /* allocate memory for handlers arguments */ + arg = os_zalloc(sizeof(struct network_handler_args)); + if (!arg) { + wpa_printf(MSG_ERROR, "dbus: 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_persistent_group_properties, + NULL); + + if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path, + wpa_s->ifname, obj_desc)) + goto err; + + wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id); + + return 0; + +err: + free_dbus_object_desc(obj_desc); + return -1; +} + + +/** + * wpas_dbus_unregister_persistent_group - Unregister a persistent_group + * from dbus + * @wpa_s: wpa_supplicant interface structure + * @nid: network id + * Returns: 0 on success, -1 on failure + * + * Unregisters persistent group representing object from dbus + * + * NOTE: There is a slight issue with the semantics here. While the + * implementation simply means the persistent group is unloaded from memory, + * it should not get interpreted as the group is actually being erased/removed + * from persistent storage as well. + */ +int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s, + int nid) +{ + struct wpas_dbus_priv *ctrl_iface; + char pgrp_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(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", + wpa_s->dbus_new_path, nid); + + wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'", + pgrp_obj_path); + ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path); + + if (!ret) + wpas_dbus_signal_persistent_group_removed(wpa_s, nid); + + return ret; +} + +#endif /* CONFIG_P2P */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h new file mode 100644 index 0000000..363a7e5 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h @@ -0,0 +1,498 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef CTRL_IFACE_DBUS_NEW_H +#define CTRL_IFACE_DBUS_NEW_H + +#include "common/defs.h" +#include "p2p/p2p.h" + +struct wpa_global; +struct wpa_supplicant; +struct wpa_ssid; +struct wps_event_m2d; +struct wps_event_fail; +struct wps_credential; + +enum wpas_dbus_prop { + WPAS_DBUS_PROP_AP_SCAN, + WPAS_DBUS_PROP_SCANNING, + WPAS_DBUS_PROP_STATE, + WPAS_DBUS_PROP_CURRENT_BSS, + WPAS_DBUS_PROP_CURRENT_NETWORK, + WPAS_DBUS_PROP_CURRENT_AUTH_MODE, + WPAS_DBUS_PROP_BSSS, + WPAS_DBUS_PROP_DISCONNECT_REASON, +}; + +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_WPS, + 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" + +#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \ + WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice" + +/* + * Groups correspond to P2P groups where this device is a GO (owner) + */ +#define WPAS_DBUS_NEW_P2P_GROUPS_PART "Groups" +#define WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group" + +/* + * Different dbus object for persistent groups so they do not get confused + * with regular (configured) network objects. + */ +#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups" +#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \ + WPAS_DBUS_NEW_INTERFACE ".PersistentGroup" + +#define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers" +#define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer" + +#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "Members" +#define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \ + WPAS_DBUS_NEW_INTERFACE ".GroupMember" + +/* 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_CONNECT_CHANNEL_UNAVAILABLE \ + WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable" +#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \ + WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported" +#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \ + WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError" + +#define WPAS_DBUS_ERROR_BLOB_EXISTS \ + WPAS_DBUS_NEW_INTERFACE ".BlobExists" +#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \ + WPAS_DBUS_NEW_INTERFACE ".BlobUnknown" + +#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \ + WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse" +#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \ + WPAS_DBUS_NEW_INTERFACE ".NoSubscription" +#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \ + WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou" + + +void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv); +void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv); + + +#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_network_request(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + enum wpa_ctrl_req_type rtype, + const char *default_text); +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); + +int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr); +void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, + const u8 *dev_addr); +int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr); +void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, + const u8 *dev_addr); +void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, + const char *role); +void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, + const u8 *dev_addr, int request, + enum p2p_prov_disc_status status, + u16 config_methods, + unsigned int generated_pin); +void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 dev_passwd_id); +void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + int client, int network_id); +void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, + struct p2p_go_neg_results *res); +void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid); +int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s, + int nid); +void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s, + int status, const u8 *bssid); +void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr); +void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr); +void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *member); +void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, + int freq, const u8 *sa, u8 dialog_token, + u16 update_indic, const u8 *tlvs, + size_t tlvs_len); +void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, + const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len); +void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, + const u8 *member); +void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail); +void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert); +void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *dst, const u8 *bssid, + const u8 *ie, size_t ie_len, u32 ssi_signal); +void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, const char *parameter); + +#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_network_request( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + enum wpa_ctrl_req_type rtype, const char *default_txt) +{ +} + +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) +{ +} + +static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ + return 0; +} + +static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ + return 0; +} + +static inline void +wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, + const char *role) +{ +} + +static inline void +wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, + const u8 *dev_addr, int request, + enum p2p_prov_disc_status status, + u16 config_methods, + unsigned int generated_pin) +{ +} + +static inline void wpas_dbus_signal_p2p_go_neg_req( + struct wpa_supplicant *wpa_s, + const u8 *src, + u16 dev_passwd_id) +{ +} + +static inline void +wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + int client, int network_id) +{ +} + +static inline void +wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ +} + +static inline int wpas_dbus_register_persistent_group( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) +{ + return 0; +} + +static inline int wpas_dbus_unregister_persistent_group( + struct wpa_supplicant *wpa_s, int nid) +{ + return 0; +} + +static inline void +wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, + struct p2p_go_neg_results *res) +{ +} + +static inline void +wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid) +{ +} + +static inline void wpas_dbus_signal_p2p_invitation_result( + struct wpa_supplicant *wpa_s, int status, + const u8 *bssid) +{ +} + +static inline void +wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr) +{ +} + +static inline void +wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, + const u8 *sa, u8 dialog_token, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) +{ +} + +static inline void +wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, + const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) +{ +} + +static inline void +wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, + const u8 *p2p_if_addr) +{ +} + +static inline void +wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, + const u8 *member) +{ +} + +static inline void +wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ +} + +static inline void +wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, + const u8 *dev_addr) +{ +} + +static inline void +wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, + const u8 *member) +{ +} + +static inline void +wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail) +{ +} + +static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, + const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ +} + +static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *dst, + const u8 *bssid, + const u8 *ie, size_t ie_len, + u32 ssi_signal) +{ +} + +static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, + const char *parameter) +{ +} + +#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ + +#endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c new file mode 100644 index 0000000..5e06932 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c @@ -0,0 +1,3759 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "common/ieee802_11_defs.h" +#include "eap_peer/eap_methods.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "rsn_supp/wpa.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../driver_i.h" +#include "../notify.h" +#include "../bss.h" +#include "../scan.h" +#include "../autoscan.h" +#include "dbus_new_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_dict_helpers.h" +#include "dbus_common_i.h" + +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_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", "scan_freq", "freq_list", NULL +}; + +static dbus_bool_t should_quote_opt(const char *key) +{ + int i = 0; + while (dont_quote[i] != NULL) { + if (os_strcmp(key, dont_quote[i]) == 0) + return FALSE; + i++; + } + return TRUE; +} + +/** + * get_iface_by_dbus_path - Get a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @path: Pointer to a dbus object path representing an interface + * Returns: Pointer to the interface or %NULL if not found + */ +static struct wpa_supplicant * get_iface_by_dbus_path( + struct wpa_global *global, const char *path) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (os_strcmp(wpa_s->dbus_new_path, path) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * set_network_properties - Set properties of a configured network + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * @iter: DBus message iterator containing dictionary of network + * properties to set. + * @error: On failure, an error describing the failure + * Returns: TRUE if the request succeeds, FALSE if it failed + * + * Sets network configuration with parameters given id DBus dictionary + */ +dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + DBusMessageIter *iter, + DBusError *error) +{ + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter_dict; + char *value = NULL; + + if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) + return FALSE; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + size_t size = 50; + int ret; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + value = NULL; + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = os_strlen(entry.str_value); + if (size <= 0) + goto error; + + size += 3; + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "\"%s\"", + entry.str_value); + if (ret < 0 || (size_t) ret != (size - 1)) + goto error; + } else { + value = os_strdup(entry.str_value); + if (value == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "%u", + entry.uint32_value); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + + ret = os_snprintf(value, size, "%d", + entry.int32_value); + if (ret <= 0) + goto error; + } else + goto error; + + if (wpa_config_set(ssid, entry.key, value, 0) < 0) + goto error; + + if ((os_strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + else if (os_strcmp(entry.key, "priority") == 0) + wpa_config_update_prio_list(wpa_s->conf); + + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + } + + return TRUE; + +error: + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; +} + + +/** + * wpas_dbus_simple_property_getter - Get basic type property + * @iter: Message iter to use when appending arguments + * @type: DBus type of property (must be basic type) + * @val: pointer to place holding property value + * @error: On failure an error describing the failure + * Returns: TRUE if the request was successful, FALSE if it failed + * + * Generic getter for basic type properties. Type is required to be basic. + */ +dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, + const int type, + const void *val, + DBusError *error) +{ + DBusMessageIter variant_iter; + + if (!dbus_type_is_basic(type)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; + } + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + wpa_dbus_type_as_string(type), + &variant_iter)) + goto error; + + if (!dbus_message_iter_append_basic(&variant_iter, type, val)) + goto error; + + if (!dbus_message_iter_close_container(iter, &variant_iter)) + goto error; + + return TRUE; + +error: + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: error constructing reply", __func__); + return FALSE; +} + + +/** + * wpas_dbus_simple_property_setter - Set basic type property + * @message: Pointer to incoming dbus message + * @type: DBus type of property (must be basic type) + * @val: pointer to place where value being set will be stored + * Returns: TRUE if the request was successful, FALSE if it failed + * + * Generic setter for basic type properties. Type is required to be basic. + */ +dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, + DBusError *error, + const int type, void *val) +{ + DBusMessageIter variant_iter; + + if (!dbus_type_is_basic(type)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; + } + + /* Look at the new value */ + dbus_message_iter_recurse(iter, &variant_iter); + if (dbus_message_iter_get_arg_type(&variant_iter) != type) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "wrong property type"); + return FALSE; + } + dbus_message_iter_get_basic(&variant_iter, val); + + return TRUE; +} + + +/** + * wpas_dbus_simple_array_property_getter - Get array type property + * @iter: Pointer to incoming dbus message iterator + * @type: DBus type of property array elements (must be basic type) + * @array: pointer to array of elements to put into response message + * @array_len: length of above array + * @error: a pointer to an error to fill on failure + * Returns: TRUE if the request succeeded, FALSE if it failed + * + * Generic getter for array type properties. Array elements type is + * required to be basic. + */ +dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, + const int type, + const void *array, + size_t array_len, + DBusError *error) +{ + DBusMessageIter variant_iter, array_iter; + char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ + const char *sub_type_str; + size_t element_size, i; + + if (!dbus_type_is_basic(type)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; + } + + sub_type_str = wpa_dbus_type_as_string(type); + type_str[1] = sub_type_str[0]; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + type_str, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 1", __func__); + return FALSE; + } + + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + sub_type_str, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 2", __func__); + return FALSE; + } + + switch(type) { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + element_size = 1; + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + element_size = sizeof(uint16_t); + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + element_size = sizeof(uint32_t); + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + element_size = sizeof(uint64_t); + break; + case DBUS_TYPE_DOUBLE: + element_size = sizeof(double); + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + element_size = sizeof(char *); + break; + default: + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: unknown element type %d", __func__, type); + return FALSE; + } + + for (i = 0; i < array_len; i++) { + dbus_message_iter_append_basic(&array_iter, type, + array + i * element_size); + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 3", __func__); + return FALSE; + } + + if (!dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 4", __func__); + return FALSE; + } + + return TRUE; +} + + +/** + * wpas_dbus_simple_array_array_property_getter - Get array array type property + * @iter: Pointer to incoming dbus message iterator + * @type: DBus type of property array elements (must be basic type) + * @array: pointer to array of elements to put into response message + * @array_len: length of above array + * @error: a pointer to an error to fill on failure + * Returns: TRUE if the request succeeded, FALSE if it failed + * + * Generic getter for array type properties. Array elements type is + * required to be basic. + */ +dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, + const int type, + struct wpabuf **array, + size_t array_len, + DBusError *error) +{ + DBusMessageIter variant_iter, array_iter; + char type_str[] = "aa?"; + char inner_type_str[] = "a?"; + const char *sub_type_str; + size_t i; + + if (!dbus_type_is_basic(type)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: given type is not basic", __func__); + return FALSE; + } + + sub_type_str = wpa_dbus_type_as_string(type); + type_str[2] = sub_type_str[0]; + inner_type_str[1] = sub_type_str[0]; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + type_str, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 1", __func__); + return FALSE; + } + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + inner_type_str, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 2", __func__); + return FALSE; + } + + for (i = 0; i < array_len; i++) { + wpa_dbus_dict_bin_array_add_element(&array_iter, + wpabuf_head(array[i]), + wpabuf_len(array[i])); + + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to close message 2", __func__); + return FALSE; + } + + if (!dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to close message 1", __func__); + return FALSE; + } + + return TRUE; +} + + +/** + * wpas_dbus_handler_create_interface - Request registration of a network iface + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the new interface object, + * or a dbus error message with more information + * + * Handler function for "CreateInterface" method call. Handles requests + * by dbus clients to register a network interface that wpa_supplicant + * will manage. + */ +DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *driver = NULL; + char *ifname = NULL; + char *confname = NULL; + char *bridge_ifname = NULL; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!os_strcmp(entry.key, "Driver") && + (entry.type == DBUS_TYPE_STRING)) { + driver = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (driver == NULL) + goto error; + } else if (!os_strcmp(entry.key, "Ifname") && + (entry.type == DBUS_TYPE_STRING)) { + ifname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (ifname == NULL) + goto error; + } else if (!os_strcmp(entry.key, "ConfigFile") && + (entry.type == DBUS_TYPE_STRING)) { + confname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (confname == NULL) + goto error; + } else if (!os_strcmp(entry.key, "BridgeIfname") && + (entry.type == DBUS_TYPE_STRING)) { + bridge_ifname = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + if (bridge_ifname == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + } + + if (ifname == NULL) + goto error; /* Required Ifname argument missing */ + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, ifname) != NULL) { + reply = dbus_message_new_error(message, + WPAS_DBUS_ERROR_IFACE_EXISTS, + "wpa_supplicant already " + "controls this interface."); + } else { + struct wpa_supplicant *wpa_s; + struct wpa_interface iface; + os_memset(&iface, 0, sizeof(iface)); + iface.driver = driver; + iface.ifname = ifname; + iface.confname = confname; + iface.bridge_ifname = bridge_ifname; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpa_s->dbus_new_path; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + } else { + reply = wpas_dbus_error_unknown_error( + message, "wpa_supplicant couldn't grab this " + "interface."); + } + } + +out: + os_free(driver); + os_free(ifname); + os_free(confname); + os_free(bridge_ifname); + return reply; + +error: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +/** + * wpas_dbus_handler_remove_interface - Request deregistration of an interface + * @message: Pointer to incoming dbus message + * @global: wpa_supplicant global data structure + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0), or returns a dbus error message with more information + * + * Handler function for "removeInterface" method call. Handles requests + * by dbus clients to deregister a network interface that wpa_supplicant + * currently manages. + */ +DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + char *path; + DBusMessage *reply = NULL; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + wpa_s = get_iface_by_dbus_path(global, path); + if (wpa_s == NULL) + reply = wpas_dbus_error_iface_unknown(message); + else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { + reply = wpas_dbus_error_unknown_error( + message, "wpa_supplicant couldn't remove this " + "interface."); + } + + return reply; +} + + +/** + * wpas_dbus_handler_get_interface - Get the object path for an interface name + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the interface object, + * or a dbus error message with more information + * + * Handler function for "getInterface" method call. + */ +DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + const char *ifname; + const char *path; + struct wpa_supplicant *wpa_s; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID); + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) + return wpas_dbus_error_iface_unknown(message); + + path = wpa_s->dbus_new_path; + reply = dbus_message_new_method_return(message); + if (reply == NULL) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + } + + return reply; +} + + +/** + * wpas_dbus_getter_debug_level - Get debug level + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DebugLevel" property. + */ +dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + const char *str; + int idx = wpa_debug_level; + + if (idx < 0) + idx = 0; + if (idx > 5) + idx = 5; + str = debug_strings[idx]; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &str, error); +} + + +/** + * wpas_dbus_getter_debug_timestamp - Get debug timestamp + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DebugTimestamp" property. + */ +dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_timestamp, error); + +} + + +/** + * wpas_dbus_getter_debug_show_keys - Get debug show keys + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DebugShowKeys" property. + */ +dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &wpa_debug_show_keys, error); + +} + +/** + * wpas_dbus_setter_debug_level - Set debug level + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "DebugLevel" property. + */ +dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct wpa_global *global = user_data; + const char *str = NULL; + int i, val = -1; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &str)) + return FALSE; + + for (i = 0; debug_strings[i]; i++) + if (os_strcmp(debug_strings[i], str) == 0) { + val = i; + break; + } + + if (val < 0 || + wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, + wpa_debug_show_keys)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug " + "level value"); + return FALSE; + } + + return TRUE; +} + + +/** + * wpas_dbus_setter_debug_timestamp - Set debug timestamp + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "DebugTimestamp" property. + */ +dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_global *global = user_data; + dbus_bool_t val; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &val)) + return FALSE; + + wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, + wpa_debug_show_keys); + return TRUE; +} + + +/** + * wpas_dbus_setter_debug_show_keys - Set debug show keys + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "DebugShowKeys" property. + */ +dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_global *global = user_data; + dbus_bool_t val; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &val)) + return FALSE; + + wpa_supplicant_set_debug_params(global, wpa_debug_level, + wpa_debug_timestamp, + val ? 1 : 0); + return TRUE; +} + + +/** + * wpas_dbus_getter_interfaces - Request registered interfaces list + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Interfaces" property. Handles requests + * by dbus clients to return list of registered interfaces objects + * paths + */ +dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_global *global = user_data; + struct wpa_supplicant *wpa_s; + const char **paths; + unsigned int i = 0, num = 0; + dbus_bool_t success; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) + num++; + + paths = os_calloc(num, sizeof(char *)); + if (!paths) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) + paths[i++] = wpa_s->dbus_new_path; + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, error); + + os_free(paths); + return success; +} + + +/** + * wpas_dbus_getter_eap_methods - Request supported EAP methods list + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "EapMethods" property. Handles requests + * by dbus clients to return list of strings with supported EAP methods + */ +dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + char **eap_methods; + size_t num_items = 0; + dbus_bool_t success; + + eap_methods = eap_get_names_as_string_array(&num_items); + if (!eap_methods) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_STRING, + eap_methods, + num_items, error); + + while (num_items) + os_free(eap_methods[--num_items]); + os_free(eap_methods); + return success; +} + + +/** + * wpas_dbus_getter_global_capabilities - Request supported global capabilities + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Capabilities" property. Handles requests by dbus clients to + * return a list of strings with supported capabilities like AP, RSN IBSS, + * and P2P that are determined at compile time. + */ +dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL }; + size_t num_items = 0; + +#ifdef CONFIG_AP + capabilities[num_items++] = "ap"; +#endif /* CONFIG_AP */ +#ifdef CONFIG_IBSS_RSN + capabilities[num_items++] = "ibss-rsn"; +#endif /* CONFIG_IBSS_RSN */ +#ifdef CONFIG_P2P + capabilities[num_items++] = "p2p"; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + capabilities[num_items++] = "interworking"; +#endif /* CONFIG_INTERWORKING */ + + return wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_STRING, + capabilities, + num_items, error); +} + + +static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, + char **type, DBusMessage **reply) +{ + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Type must be a string"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Type value type. String required"); + return -1; + } + dbus_message_iter_get_basic(var, type); + return 0; +} + + +static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + struct wpa_driver_scan_ssid *ssids = params->ssids; + size_t ssids_num = 0; + u8 *ssid; + DBusMessageIter array_iter, sub_array_iter; + char *val; + int len; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " + "must be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong SSIDs value type. Array of arrays of " + "bytes required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) + { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " + "must be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong SSIDs value type. Array of arrays of " + "bytes required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) + { + if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Too many ssids specified on scan dbus " + "call"); + *reply = wpas_dbus_error_invalid_args( + message, "Too many ssids specified. Specify " + "at most four"); + return -1; + } + + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); + + if (len > MAX_SSID_LEN) { + wpa_printf(MSG_DEBUG, + "wpas_dbus_handler_scan[dbus]: " + "SSID too long (len=%d max_len=%d)", + len, MAX_SSID_LEN); + *reply = wpas_dbus_error_invalid_args( + message, "Invalid SSID: too long"); + return -1; + } + + if (len != 0) { + ssid = os_malloc(len); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, + "wpas_dbus_handler_scan[dbus]: " + "out of memory. Cannot allocate " + "memory for SSID"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + os_memcpy(ssid, val, len); + } else { + /* Allow zero-length SSIDs */ + ssid = NULL; + } + + ssids[ssids_num].ssid = ssid; + ssids[ssids_num].ssid_len = len; + + dbus_message_iter_next(&array_iter); + ssids_num++; + } + + params->num_ssids = ssids_num; + return 0; +} + + +static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + u8 *ies = NULL, *nies; + int ies_len = 0; + DBusMessageIter array_iter, sub_array_iter; + char *val; + int len; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " + "be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong IEs value type. Array of arrays of " + "bytes required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) + { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " + "be an array of arrays of bytes"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong IEs value type. Array required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) + { + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); + if (len == 0) { + dbus_message_iter_next(&array_iter); + continue; + } + + nies = os_realloc(ies, ies_len + len); + if (nies == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. Cannot allocate memory for " + "IE"); + os_free(ies); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + ies = nies; + os_memcpy(ies + ies_len, val, len); + ies_len += len; + + dbus_message_iter_next(&array_iter); + } + + params->extra_ies = ies; + params->extra_ies_len = ies_len; + return 0; +} + + +static int wpas_dbus_get_scan_channels(DBusMessage *message, + DBusMessageIter *var, + struct wpa_driver_scan_params *params, + DBusMessage **reply) +{ + DBusMessageIter array_iter, sub_array_iter; + int *freqs = NULL, *nfreqs; + int freqs_num = 0; + + if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channels must be an array of structs"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channels value type. Array of structs " + "required"); + return -1; + } + + dbus_message_iter_recurse(var, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_DEBUG, + "wpas_dbus_handler_scan[dbus]: Channels must be an " + "array of structs"); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channels value type. Array of structs " + "required"); + return -1; + } + + while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT) + { + int freq, width; + + dbus_message_iter_recurse(&array_iter, &sub_array_iter); + + if (dbus_message_iter_get_arg_type(&sub_array_iter) != + DBUS_TYPE_UINT32) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channel must by specified by struct of " + "two UINT32s %c", + dbus_message_iter_get_arg_type( + &sub_array_iter)); + *reply = wpas_dbus_error_invalid_args( + message, "Wrong Channel struct. Two UINT32s " + "required"); + os_free(freqs); + return -1; + } + dbus_message_iter_get_basic(&sub_array_iter, &freq); + + if (!dbus_message_iter_next(&sub_array_iter) || + dbus_message_iter_get_arg_type(&sub_array_iter) != + DBUS_TYPE_UINT32) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "Channel must by specified by struct of " + "two UINT32s"); + *reply = wpas_dbus_error_invalid_args( + message, + "Wrong Channel struct. Two UINT32s required"); + os_free(freqs); + return -1; + } + + dbus_message_iter_get_basic(&sub_array_iter, &width); + +#define FREQS_ALLOC_CHUNK 32 + if (freqs_num % FREQS_ALLOC_CHUNK == 0) { + nfreqs = os_realloc_array( + freqs, freqs_num + FREQS_ALLOC_CHUNK, + sizeof(int)); + if (nfreqs == NULL) + os_free(freqs); + freqs = nfreqs; + } + if (freqs == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. can't allocate memory for " + "freqs"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + + freqs[freqs_num] = freq; + + freqs_num++; + dbus_message_iter_next(&array_iter); + } + + nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int)); + if (nfreqs == NULL) + os_free(freqs); + freqs = nfreqs; + if (freqs == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " + "out of memory. Can't allocate memory for freqs"); + *reply = dbus_message_new_error( + message, DBUS_ERROR_NO_MEMORY, NULL); + return -1; + } + freqs[freqs_num] = 0; + + params->freqs = freqs; + return 0; +} + + +/** + * 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 = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + } else if (!os_strcmp(type, "active")) { + if (!params.num_ssids) { + /* Add wildcard ssid */ + params.num_ssids++; + } +#ifdef CONFIG_AUTOSCAN + autoscan_deinit(wpa_s); +#endif /* CONFIG_AUTOSCAN */ + 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; + DBusError error; + + dbus_message_iter_init(message, &iter); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: " + "can't add new interface."); + reply = wpas_dbus_error_unknown_error( + message, + "wpa_supplicant could not add " + "a network on this interface."); + goto err; + } + wpas_notify_network_added(wpa_s, ssid); + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + dbus_error_init(&error); + if (!set_network_properties(wpa_s, ssid, &iter, &error)) { + wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:" + "control interface couldn't set network " + "properties"); + reply = wpas_dbus_reply_new_from_error(message, &error, + DBUS_ERROR_INVALID_ARGS, + "Failed to add network"); + dbus_error_free(&error); + goto err; + } + + /* Construct the object path for this network. */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + goto err; + } + + return reply; + +err: + if (ssid) { + wpas_notify_network_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + } + return reply; +} + + +/** + * wpas_dbus_handler_reassociate - Reassociate to current AP + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NotConnected DBus error message if not connected + * or NULL otherwise. + * + * Handler function for "Reassociate" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->current_ssid != NULL) { + wpas_request_connection(wpa_s); + return NULL; + } + + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, + "This interface is not connected"); +} + + +/** + * wpas_dbus_handler_remove_network - Remove a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "RemoveNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); + if (iface == NULL || net_id == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + errno = 0; + id = strtoul(net_id, NULL, 10); + if (errno != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + 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_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); +} + + +/** + * wpas_dbus_handler_remove_all_networks - Remove all configured networks + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "RemoveAllNetworks" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_all_networks( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + /* NB: could check for failure and return an error */ + wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); + return NULL; +} + + +/** + * wpas_dbus_handler_select_network - Attempt association with a network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "SelectNetwork" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); + if (iface == NULL || net_id == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + errno = 0; + id = strtoul(net_id, NULL, 10); + if (errno != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + /* Finally, associate with the network */ + wpa_supplicant_select_network(wpa_s, ssid); + +out: + os_free(iface); + os_free(net_id); + return reply; +} + + +/** + * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "NetworkReply" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ +#ifdef IEEE8021X_EAPOL + DBusMessage *reply = NULL; + const char *op, *field, *value; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_STRING, &field, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID)) + return wpas_dbus_error_invalid_args(message, NULL); + + /* Extract the network ID and ensure the network */ + /* is actually a child of this interface */ + iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); + if (iface == NULL || net_id == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + errno = 0; + id = strtoul(net_id, NULL, 10); + if (errno != 0) { + reply = wpas_dbus_error_invalid_args(message, net_id); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_error_network_unknown(message); + goto out; + } + + if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, + field, value) < 0) + reply = wpas_dbus_error_invalid_args(message, field); + else { + /* Tell EAP to retry immediately */ + eapol_sm_notify_ctrl_response(wpa_s->eapol); + } + +out: + os_free(iface); + os_free(net_id); + return reply; +#else /* IEEE8021X_EAPOL */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); + return wpas_dbus_error_unknown_error(message, "802.1X not included"); +#endif /* IEEE8021X_EAPOL */ +} + + +/** + * 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; +} + + +#ifdef CONFIG_AUTOSCAN +/** + * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Handler function for "AutoScan" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + enum wpa_states state = wpa_s->wpa_state; + char *arg; + + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + if (arg != NULL && os_strlen(arg) > 0) { + char *tmp; + tmp = os_strdup(arg); + if (tmp == NULL) { + reply = dbus_message_new_error(message, + DBUS_ERROR_NO_MEMORY, + NULL); + } else { + os_free(wpa_s->conf->autoscan); + wpa_s->conf->autoscan = tmp; + if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) + autoscan_init(wpa_s, 1); + else if (state == WPA_SCANNING) + wpa_supplicant_reinit_autoscan(wpa_s); + } + } else if (arg != NULL && os_strlen(arg) == 0) { + os_free(wpa_s->conf->autoscan); + wpa_s->conf->autoscan = NULL; + autoscan_deinit(wpa_s); + } else + reply = dbus_message_new_error(message, + DBUS_ERROR_INVALID_ARGS, + NULL); + + return reply; +} +#endif /* CONFIG_AUTOSCAN */ + + +/** + * wpas_dbus_getter_capabilities - Return interface capabilities + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Capabilities" property of an interface. + */ +dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_driver_capa capa; + int res; + DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array, + variant_iter; + const char *scans[] = { "active", "passive", "ssid" }; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + + res = wpa_drv_get_capa(wpa_s, &capa); + + /***** pairwise cipher */ + if (res < 0) { + const char *args[] = {"ccmp", "tkip", "none"}; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "Pairwise", args, + 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_GCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "tkip")) + goto nomem; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "none")) + goto nomem; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + } + + /***** group cipher */ + if (res < 0) { + const char *args[] = { + "ccmp", "tkip", "wep104", "wep40" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "Group", args, + 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_GCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "tkip")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wep104")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "wep40")) + goto nomem; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + } + + /***** key management */ + if (res < 0) { + const char *args[] = { + "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none", +#ifdef CONFIG_WPS + "wps", +#endif /* CONFIG_WPS */ + "none" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "KeyMgmt", args, + 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 (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "infrastructure")) + goto nomem; + + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ad-hoc")) + goto nomem; + + if (res >= 0) { + if (capa.flags & (WPA_DRIVER_FLAGS_AP)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ap")) + goto nomem; + } + + if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "p2p")) + goto nomem; + } + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto nomem; + /***** Modes end */ + + if (res >= 0) { + dbus_int32_t max_scan_ssid = capa.max_scan_ssids; + + if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID", + max_scan_ssid)) + goto nomem; + } + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) + goto nomem; + if (!dbus_message_iter_close_container(iter, &variant_iter)) + goto nomem; + + return TRUE; + +nomem: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; +} + + +/** + * wpas_dbus_getter_state - Get interface state + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "State" property. + */ +dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *str_state; + char *state_ls, *tmp; + dbus_bool_t success = FALSE; + + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + + /* make state string lowercase to fit new DBus API convention + */ + state_ls = tmp = os_strdup(str_state); + if (!tmp) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + while (*tmp) { + *tmp = tolower(*tmp); + tmp++; + } + + success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &state_ls, error); + + os_free(state_ls); + + return success; +} + + +/** + * wpas_dbus_new_iface_get_scanning - Get interface scanning state + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "scanning" property. + */ +dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &scanning, error); +} + + +/** + * wpas_dbus_getter_ap_scan - Control roaming mode + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "ApScan" property. + */ +dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &ap_scan, error); +} + + +/** + * wpas_dbus_setter_ap_scan - Control roaming mode + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "ApScan" property. + */ +dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t ap_scan; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &ap_scan)) + return FALSE; + + if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "ap_scan must be 0, 1, or 2"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_fast_reauth - Control fast + * reauthentication (TLS session resumption) + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "FastReauth" property. + */ +dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &fast_reauth, error); +} + + +/** + * wpas_dbus_setter_fast_reauth - Control fast + * reauthentication (TLS session resumption) + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "FastReauth" property. + */ +dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t fast_reauth; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &fast_reauth)) + return FALSE; + + wpa_s->conf->fast_reauth = fast_reauth; + return TRUE; +} + + +/** + * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "DisconnectReason" property. The reason is negative if it is + * locally generated. + */ +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t reason = wpa_s->disconnect_reason; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &reason, error); +} + + +/** + * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "BSSExpireAge" property. + */ +dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &expire_age, error); +} + + +/** + * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "BSSExpireAge" property. + */ +dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_age; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &expire_age)) + return FALSE; + + if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "BSSExpireAge must be >= 10"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "BSSExpireCount" property. + */ +dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, + &expire_count, error); +} + + +/** + * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "BSSExpireCount" property. + */ +dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_uint32_t expire_count; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, + &expire_count)) + return FALSE; + + if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "BSSExpireCount must be > 0"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_country - Control country code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "Country" property. + */ +dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char country[3]; + char *str = country; + + country[0] = wpa_s->conf->country[0]; + country[1] = wpa_s->conf->country[1]; + country[2] = '\0'; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &str, error); +} + + +/** + * wpas_dbus_setter_country - Control country code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "Country" property. + */ +dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *country; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, + &country)) + return FALSE; + + if (!country[0] || !country[1]) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "invalid country code"); + return FALSE; + } + + if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { + wpa_printf(MSG_DEBUG, "Failed to set country"); + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to set country code"); + return FALSE; + } + + wpa_s->conf->country[0] = country[0]; + wpa_s->conf->country[1] = country[1]; + return TRUE; +} + + +/** + * wpas_dbus_getter_scan_interval - Get scan interval + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter function for "ScanInterval" property. + */ +dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t scan_interval = wpa_s->scan_interval; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &scan_interval, error); +} + + +/** + * wpas_dbus_setter_scan_interval - Control scan interval + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter function for "ScanInterval" property. + */ +dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t scan_interval; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32, + &scan_interval)) + return FALSE; + + if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "scan_interval must be >= 0"); + return FALSE; + } + return TRUE; +} + + +/** + * wpas_dbus_getter_ifname - Get interface name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Ifname" property. + */ +dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *ifname = wpa_s->ifname; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &ifname, error); +} + + +/** + * wpas_dbus_getter_driver - Get interface name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Driver" property. + */ +dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *driver; + + if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { + wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " + "wpa_s has no driver set"); + dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set", + __func__); + return FALSE; + } + + driver = wpa_s->driver->name; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &driver, error); +} + + +/** + * wpas_dbus_getter_current_bss - Get current bss object path + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "CurrentBSS" property. + */ +dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; + + if (wpa_s->current_bss) + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, wpa_s->current_bss->id); + else + os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &bss_obj_path, error); +} + + +/** + * wpas_dbus_getter_current_network - Get current network object path + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "CurrentNetwork" property. + */ +dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; + + if (wpa_s->current_ssid) + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", + wpa_s->dbus_new_path, wpa_s->current_ssid->id); + else + os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &net_obj_path, error); +} + + +/** + * wpas_dbus_getter_current_auth_mode - Get current authentication type + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "CurrentAuthMode" property. + */ +dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *eap_mode; + const char *auth_mode; + char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; + + if (wpa_s->wpa_state != WPA_COMPLETED) { + auth_mode = "INACTIVE"; + } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + eap_mode = wpa_supplicant_get_eap_mode(wpa_s); + os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX, + "EAP-%s", eap_mode); + auth_mode = eap_mode_buf; + + } else { + auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, + wpa_s->current_ssid->proto); + } + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &auth_mode, error); +} + + +/** + * wpas_dbus_getter_bridge_ifname - Get interface name + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "BridgeIfname" property. + */ +dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *bridge_ifname = wpa_s->bridge_ifname; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &bridge_ifname, error); +} + + +/** + * wpas_dbus_getter_bsss - Get array of BSSs objects + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "BSSs" property. + */ +dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_bss *bss; + char **paths; + unsigned int i = 0; + dbus_bool_t success = FALSE; + + paths = os_calloc(wpa_s->num_bss, sizeof(char *)); + if (!paths) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + /* Loop through scan results and append each result's object path */ + dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (paths[i] == NULL) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + goto out; + } + /* Construct the object path for this BSS. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, bss->id); + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, wpa_s->num_bss, + error); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + return success; +} + + +/** + * wpas_dbus_getter_networks - Get array of networks objects + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Networks" property. + */ +dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_ssid *ssid; + char **paths; + unsigned int i = 0, num = 0; + dbus_bool_t success = FALSE; + + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting " + "networks list.", __func__); + dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error " + "occurred getting the networks list", __func__); + return FALSE; + } + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) + if (!network_is_persistent_group(ssid)) + num++; + + paths = os_calloc(num, sizeof(char *)); + if (!paths) { + dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + /* Loop through configured networks and append object path of each */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (network_is_persistent_group(ssid)) + continue; + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (paths[i] == NULL) { + dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); + goto out; + } + + /* Construct the object path for this network. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, error); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + return success; +} + + +/** + * wpas_dbus_getter_blobs - Get all blobs defined for this interface + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Blobs" property. + */ +dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; + struct wpa_config_blob *blob; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{say}", &variant_iter) || + !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + "{say}", &dict_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + blob = wpa_s->conf->blobs; + while (blob) { + if (!dbus_message_iter_open_container(&dict_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter) || + !dbus_message_iter_append_basic(&entry_iter, + DBUS_TYPE_STRING, + &(blob->name)) || + !dbus_message_iter_open_container(&entry_iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, + DBUS_TYPE_BYTE, + &(blob->data), + blob->len) || + !dbus_message_iter_close_container(&entry_iter, + &array_iter) || + !dbus_message_iter_close_container(&dict_iter, + &entry_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + return FALSE; + } + + blob = blob->next; + } + + if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, + DBusError *error, const char *func_name) +{ + struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id); + + if (!res) { + wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found", + func_name, args->id); + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: BSS %d not found", + func_name, args->id); + } + + return res; +} + + +/** + * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "BSSID" property. + */ +dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res->bssid, ETH_ALEN, + error); +} + + +/** + * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "SSID" property. + */ +dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res->ssid, res->ssid_len, + error); +} + + +/** + * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Privacy" property. + */ +dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + dbus_bool_t privacy; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &privacy, error); +} + + +/** + * wpas_dbus_getter_bss_mode - Return the mode of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Mode" property. + */ +dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + const char *mode; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + if (res->caps & IEEE80211_CAP_IBSS) + mode = "ad-hoc"; + else + mode = "infrastructure"; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &mode, error); +} + + +/** + * wpas_dbus_getter_bss_level - Return the signal strength of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Level" property. + */ +dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + s16 level; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + level = (s16) res->level; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16, + &level, error); +} + + +/** + * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Frequency" property. + */ +dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + u16 freq; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + freq = (u16) res->freq; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &freq, error); +} + + +static int cmp_u8s_desc(const void *a, const void *b) +{ + return (*(u8 *) b - *(u8 *) a); +} + + +/** + * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Rates" property. + */ +dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + u8 *ie_rates = NULL; + u32 *real_rates; + int rates_num, i; + dbus_bool_t success = FALSE; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + rates_num = wpa_bss_get_bit_rates(res, &ie_rates); + if (rates_num < 0) + return FALSE; + + qsort(ie_rates, rates_num, 1, cmp_u8s_desc); + + real_rates = os_malloc(sizeof(u32) * rates_num); + if (!real_rates) { + os_free(ie_rates); + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + for (i = 0; i < rates_num; i++) + real_rates[i] = ie_rates[i] * 500000; + + success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32, + real_rates, rates_num, + error); + + os_free(ie_rates); + os_free(real_rates); + return success; +} + + +static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, + struct wpa_ie_data *ie_data, + DBusError *error) +{ + DBusMessageIter iter_dict, variant_iter; + const char *group; + const char *pairwise[3]; /* max 3 pairwise ciphers is supported */ + const char *key_mgmt[7]; /* max 7 key managements may be supported */ + int n; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + + /* KeyMgmt */ + n = 0; + if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) + key_mgmt[n++] = "wpa-psk"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK) + key_mgmt[n++] = "wpa-ft-psk"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + key_mgmt[n++] = "wpa-psk-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X) + key_mgmt[n++] = "wpa-eap"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) + key_mgmt[n++] = "wpa-ft-eap"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) + key_mgmt[n++] = "wpa-eap-sha256"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) + key_mgmt[n++] = "wpa-none"; + + if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", + key_mgmt, n)) + goto nomem; + + /* Group */ + switch (ie_data->group_cipher) { + case WPA_CIPHER_WEP40: + group = "wep40"; + break; + case WPA_CIPHER_TKIP: + group = "tkip"; + break; + case WPA_CIPHER_CCMP: + group = "ccmp"; + break; + case WPA_CIPHER_GCMP: + group = "gcmp"; + break; + case WPA_CIPHER_WEP104: + group = "wep104"; + break; + default: + group = ""; + break; + } + + if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group)) + goto nomem; + + /* Pairwise */ + n = 0; + if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP) + pairwise[n++] = "tkip"; + if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) + pairwise[n++] = "ccmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) + pairwise[n++] = "gcmp"; + + if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", + pairwise, n)) + goto nomem; + + /* Management group (RSN only) */ + if (ie_data->proto == WPA_PROTO_RSN) { + switch (ie_data->mgmt_group_cipher) { +#ifdef CONFIG_IEEE80211W + case WPA_CIPHER_AES_128_CMAC: + group = "aes128cmac"; + break; +#endif /* CONFIG_IEEE80211W */ + default: + group = ""; + break; + } + + if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup", + group)) + goto nomem; + } + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) + goto nomem; + if (!dbus_message_iter_close_container(iter, &variant_iter)) + goto nomem; + + return TRUE; + +nomem: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; +} + + +/** + * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "WPA" property. + */ +dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + struct wpa_ie_data wpa_data; + const u8 *ie; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + os_memset(&wpa_data, 0, sizeof(wpa_data)); + ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); + if (ie) { + if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to parse WPA IE"); + return FALSE; + } + } + + return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); +} + + +/** + * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "RSN" property. + */ +dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + struct wpa_ie_data wpa_data; + const u8 *ie; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + os_memset(&wpa_data, 0, sizeof(wpa_data)); + ie = wpa_bss_get_ie(res, WLAN_EID_RSN); + if (ie) { + if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "failed to parse RSN IE"); + return FALSE; + } + } + + return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); +} + + +/** + * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "WPS" property. + */ +dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; +#ifdef CONFIG_WPS + struct wpabuf *wps_ie; +#endif /* CONFIG_WPS */ + DBusMessageIter iter_dict, variant_iter; + const char *type = ""; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter)) + goto nomem; + + if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + +#ifdef CONFIG_WPS + wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); + if (wps_ie) { + if (wps_is_selected_pbc_registrar(wps_ie)) + type = "pbc"; + else if (wps_is_selected_pin_registrar(wps_ie)) + type = "pin"; + } +#endif /* CONFIG_WPS */ + + if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type)) + goto nomem; + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) + goto nomem; + if (!dbus_message_iter_close_container(iter, &variant_iter)) + goto nomem; + + return TRUE; + +nomem: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; +} + + +/** + * wpas_dbus_getter_bss_ies - Return all IEs of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "IEs" property. + */ +dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct bss_handler_args *args = user_data; + struct wpa_bss *res; + + res = get_bss_helper(args, error, __func__); + if (!res) + return FALSE; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + res + 1, res->ie_len, + error); +} + + +/** + * wpas_dbus_getter_enabled - Check whether network is enabled or disabled + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "enabled" property of a configured network. + */ +dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &enabled, error); +} + + +/** + * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "Enabled" property of a configured network. + */ +dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + struct wpa_supplicant *wpa_s; + struct wpa_ssid *ssid; + dbus_bool_t enable; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &enable)) + return FALSE; + + wpa_s = net->wpa_s; + ssid = net->ssid; + + if (enable) + wpa_supplicant_enable_network(wpa_s, ssid); + else + wpa_supplicant_disable_network(wpa_s, ssid); + + return TRUE; +} + + +/** + * wpas_dbus_getter_network_properties - Get options for a configured network + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Properties" property of a configured network. + */ +dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + DBusMessageIter variant_iter, dict_iter; + char **iterator; + char **props = wpa_config_get_all(net->ssid, 1); + dbus_bool_t success = FALSE; + + if (!props) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", + &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + goto out; + } + + iterator = props; + while (*iterator) { + if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, + *(iterator + 1))) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + goto out; + } + iterator += 2; + } + + + if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || + !dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + goto out; + } + + success = TRUE; + +out: + iterator = props; + while (*iterator) { + os_free(*iterator); + iterator++; + } + os_free(props); + return success; +} + + +/** + * wpas_dbus_setter_network_properties - Set options for a configured network + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "Properties" property of a configured network. + */ +dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + struct wpa_ssid *ssid = net->ssid; + DBusMessageIter variant_iter; + + dbus_message_iter_recurse(iter, &variant_iter); + return set_network_properties(net->wpa_s, ssid, &variant_iter, error); +} + + +#ifdef CONFIG_AP + +DBusMessage * wpas_dbus_handler_subscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + char *name; + + if (wpa_s->preq_notify_peer != NULL) { + if (os_strcmp(dbus_message_get_sender(message), + wpa_s->preq_notify_peer) == 0) + return NULL; + + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE, + "Another application is already subscribed"); + } + + name = os_strdup(dbus_message_get_sender(message)); + if (!name) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + "out of memory"); + + wpa_s->preq_notify_peer = name; + + /* Subscribe to clean up if application closes socket */ + wpas_dbus_subscribe_noc(priv); + + /* + * Double-check it's still alive to make sure that we didn't + * miss the NameOwnerChanged signal, e.g. while strdup'ing. + */ + if (!dbus_bus_name_has_owner(priv->con, name, NULL)) { + /* + * Application no longer exists, clean up. + * The return value is irrelevant now. + * + * Need to check if the NameOwnerChanged handling + * already cleaned up because we have processed + * DBus messages while checking if the name still + * has an owner. + */ + if (!wpa_s->preq_notify_peer) + return NULL; + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + wpas_dbus_unsubscribe_noc(priv); + } + + return NULL; +} + + +DBusMessage * wpas_dbus_handler_unsubscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + + if (!wpa_s->preq_notify_peer) + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_NO_SUBSCRIPTION, + "Not subscribed"); + + if (os_strcmp(wpa_s->preq_notify_peer, + dbus_message_get_sender(message))) + return dbus_message_new_error(message, + WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM, + "Can't unsubscribe others"); + + os_free(wpa_s->preq_notify_peer); + wpa_s->preq_notify_peer = NULL; + wpas_dbus_unsubscribe_noc(priv); + return NULL; +} + + +void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *dst, const u8 *bssid, + const u8 *ie, size_t ie_len, u32 ssi_signal) +{ + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpas_dbus_priv *priv = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (priv == NULL) + return; + + if (wpa_s->preq_notify_peer == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "ProbeRequest"); + if (msg == NULL) + return; + + dbus_message_set_destination(msg, wpa_s->preq_notify_peer); + + dbus_message_iter_init_append(msg, &iter); + + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto fail; + if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr", + (const char *) addr, + ETH_ALEN)) + goto fail; + if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst", + (const char *) dst, + ETH_ALEN)) + goto fail; + if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid", + (const char *) bssid, + ETH_ALEN)) + goto fail; + if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies", + (const char *) ie, + ie_len)) + goto fail; + if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal", + ssi_signal)) + goto fail; + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto fail; + + dbus_connection_send(priv->con, msg, NULL); + goto out; +fail: + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); +out: + dbus_message_unref(msg); +} + +#endif /* CONFIG_AP */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h new file mode 100644 index 0000000..aa56550 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h @@ -0,0 +1,285 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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; +}; + +dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, + const int type, + const void *val, + DBusError *error); + +dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, + DBusError *error, + const int type, void *val); + +dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, + const int type, + const void *array, + size_t array_len, + DBusError *error); + +dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, + const int type, + struct wpabuf **array, + size_t array_len, + DBusError *error); + +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); + +dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + DBusMessageIter *iter, + DBusError *error); + +DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_reassociate(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_network_reply(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_handler_autoscan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, + const char *arg); +DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, + const char *arg); + +DBusMessage * wpas_dbus_handler_subscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_unsubscribe_preq( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c new file mode 100644 index 0000000..30e0eb3 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -0,0 +1,2438 @@ +/* + * WPA Supplicant / dbus-based control interface (P2P) + * Copyright (c) 2011-2012, Intel Corporation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "utils/includes.h" +#include "common.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../wps_supplicant.h" +#include "../notify.h" +#include "dbus_new_helpers.h" +#include "dbus_new.h" +#include "dbus_new_handlers.h" +#include "dbus_new_handlers_p2p.h" +#include "dbus_dict_helpers.h" +#include "p2p/p2p.h" +#include "common/ieee802_11_defs.h" +#include "ap/hostapd.h" +#include "ap/ap_config.h" +#include "ap/wps_hostapd.h" + +#include "../p2p_supplicant.h" + +/** + * Parses out the mac address from the peer object path. + * @peer_path - object path of the form + * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons) + * @addr - out param must be of ETH_ALEN size + * Returns 0 if valid (including MAC), -1 otherwise + */ +static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN]) +{ + char *p; + + if (!peer_path) + return -1; + p = os_strrchr(peer_path, '/'); + if (!p) + return -1; + p++; + return hwaddr_compact_aton(p, addr); +} + + +/** + * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown + * 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 persistent group error. + */ +static DBusMessage * wpas_dbus_error_persistent_group_unknown( + DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, + "There is no such persistent group in " + "this P2P device."); +} + + +DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + struct wpa_dbus_dict_entry entry; + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter iter_dict; + unsigned int timeout = 0; + enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL; + int num_req_dev_types = 0; + unsigned int i; + u8 *req_dev_types = NULL; + + dbus_message_iter_init(message, &iter); + entry.key = NULL; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "Timeout") && + (entry.type == DBUS_TYPE_INT32)) { + timeout = entry.uint32_value; + } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) { + if ((entry.type != DBUS_TYPE_ARRAY) || + (entry.array_type != WPAS_DBUS_TYPE_BINARRAY)) + goto error_clear; + + os_free(req_dev_types); + req_dev_types = + os_malloc(WPS_DEV_TYPE_LEN * entry.array_len); + if (!req_dev_types) + goto error_clear; + + for (i = 0; i < entry.array_len; i++) { + if (wpabuf_len(entry.binarray_value[i]) != + WPS_DEV_TYPE_LEN) + goto error_clear; + os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN, + wpabuf_head(entry.binarray_value[i]), + WPS_DEV_TYPE_LEN); + } + num_req_dev_types = entry.array_len; + } else if (!os_strcmp(entry.key, "DiscoveryType") && + (entry.type == DBUS_TYPE_STRING)) { + if (!os_strcmp(entry.str_value, "start_with_full")) + type = P2P_FIND_START_WITH_FULL; + else if (!os_strcmp(entry.str_value, "social")) + type = P2P_FIND_ONLY_SOCIAL; + else if (!os_strcmp(entry.str_value, "progressive")) + type = P2P_FIND_PROGRESSIVE; + else + goto error_clear; + } else + goto error_clear; + wpa_dbus_dict_entry_clear(&entry); + } + + wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types, + NULL, 0); + os_free(req_dev_types); + return reply; + +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + os_free(req_dev_types); + reply = wpas_dbus_error_invalid_args(message, entry.key); + return reply; +} + + +DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpas_p2p_stop_find(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter; + char *peer_object_path = NULL; + u8 peer_addr[ETH_ALEN]; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &peer_object_path); + + if (parse_peer_object_path(peer_object_path, peer_addr) < 0) + return wpas_dbus_error_invalid_args(message, NULL); + + if (wpas_p2p_reject(wpa_s, peer_addr) < 0) + return wpas_dbus_error_unknown_error(message, + "Failed to call wpas_p2p_reject method."); + + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_int32_t timeout = 0; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout, + DBUS_TYPE_INVALID)) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + + if (wpas_p2p_listen(wpa_s, (unsigned int)timeout)) + return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + NULL); + + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_extendedlisten( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + unsigned int period = 0, interval = 0; + struct wpa_dbus_dict_entry entry; + DBusMessageIter iter; + DBusMessageIter iter_dict; + + dbus_message_iter_init(message, &iter); + entry.key = NULL; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "period") && + (entry.type == DBUS_TYPE_INT32)) + period = entry.uint32_value; + else if (!os_strcmp(entry.key, "interval") && + (entry.type == DBUS_TYPE_INT32)) + interval = entry.uint32_value; + else + goto error_clear; + wpa_dbus_dict_entry_clear(&entry); + } + + if (wpas_p2p_ext_listen(wpa_s, period, interval)) + return wpas_dbus_error_unknown_error( + message, "failed to initiate a p2p_ext_listen."); + + return NULL; + +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + return wpas_dbus_error_invalid_args(message, entry.key); +} + + +DBusMessage * wpas_dbus_handler_p2p_presence_request( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; + struct wpa_dbus_dict_entry entry; + DBusMessageIter iter; + DBusMessageIter iter_dict; + + dbus_message_iter_init(message, &iter); + entry.key = NULL; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "duration1") && + (entry.type == DBUS_TYPE_INT32)) + dur1 = entry.uint32_value; + else if (!os_strcmp(entry.key, "interval1") && + entry.type == DBUS_TYPE_INT32) + int1 = entry.uint32_value; + else if (!os_strcmp(entry.key, "duration2") && + entry.type == DBUS_TYPE_INT32) + dur2 = entry.uint32_value; + else if (!os_strcmp(entry.key, "interval2") && + entry.type == DBUS_TYPE_INT32) + int2 = entry.uint32_value; + else + goto error_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0) + return wpas_dbus_error_unknown_error(message, + "Failed to invoke presence request."); + + return NULL; + +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + return wpas_dbus_error_invalid_args(message, entry.key); +} + + +DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *pg_object_path = NULL; + int persistent_group = 0; + int freq = 0; + char *iface = NULL; + char *net_id_str = NULL; + unsigned int group_id = 0; + struct wpa_ssid *ssid; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto inv_args; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto inv_args; + + if (!os_strcmp(entry.key, "persistent") && + (entry.type == DBUS_TYPE_BOOLEAN)) { + persistent_group = (entry.bool_value == TRUE) ? 1 : 0; + } else if (!os_strcmp(entry.key, "frequency") && + (entry.type == DBUS_TYPE_INT32)) { + freq = entry.int32_value; + if (freq <= 0) + goto inv_args_clear; + } else if (!os_strcmp(entry.key, "persistent_group_object") && + entry.type == DBUS_TYPE_OBJECT_PATH) + pg_object_path = os_strdup(entry.str_value); + else + goto inv_args_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (pg_object_path != NULL) { + /* + * A persistent group Object Path is defined meaning we want + * to re-invoke a persistent group. + */ + + iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, + &net_id_str, NULL); + if (iface == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = + wpas_dbus_error_invalid_args(message, + pg_object_path); + goto out; + } + + group_id = strtoul(net_id_str, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args( + message, pg_object_path); + goto out; + } + + /* Get the SSID structure from the persistent group id */ + ssid = wpa_config_get_network(wpa_s->conf, group_id); + if (ssid == NULL || ssid->disabled != 2) + goto inv_args; + + if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) { + reply = wpas_dbus_error_unknown_error( + message, + "Failed to reinvoke a persistent group"); + goto out; + } + } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0)) + goto inv_args; + +out: + os_free(pg_object_path); + os_free(net_id_str); + os_free(iface); + return reply; +inv_args_clear: + wpa_dbus_dict_entry_clear(&entry); +inv_args: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + if (wpas_p2p_disconnect(wpa_s)) + return wpas_dbus_error_unknown_error(message, + "failed to disconnect"); + + return NULL; +} + + +static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s, + DBusMessage *message, + DBusMessage **out_reply, + DBusError *error) +{ + /* Return an error message or an error if P2P isn't available */ + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) { + if (out_reply) { + *out_reply = dbus_message_new_error( + message, DBUS_ERROR_FAILED, + "P2P is not available for this interface"); + } + dbus_set_error_const(error, DBUS_ERROR_FAILED, + "P2P is not available for this " + "interface"); + return FALSE; + } + return TRUE; +} + + +DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) + return reply; + + os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); + wpa_s->force_long_sd = 0; + p2p_flush(wpa_s->global->p2p); + + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *peer_object_path = NULL; + int persistent_group = 0; + int join = 0; + int authorize_only = 0; + int go_intent = -1; + int freq = 0; + u8 addr[ETH_ALEN]; + char *pin = NULL; + enum p2p_wps_method wps_method = WPS_NOT_READY; + int new_pin; + char *err_msg = NULL; + char *iface = NULL; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) + return reply; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto inv_args; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto inv_args; + + if (!os_strcmp(entry.key, "peer") && + (entry.type == DBUS_TYPE_OBJECT_PATH)) { + peer_object_path = os_strdup(entry.str_value); + } else if (!os_strcmp(entry.key, "persistent") && + (entry.type == DBUS_TYPE_BOOLEAN)) { + persistent_group = (entry.bool_value == TRUE) ? 1 : 0; + } else if (!os_strcmp(entry.key, "join") && + (entry.type == DBUS_TYPE_BOOLEAN)) { + join = (entry.bool_value == TRUE) ? 1 : 0; + } else if (!os_strcmp(entry.key, "authorize_only") && + (entry.type == DBUS_TYPE_BOOLEAN)) { + authorize_only = (entry.bool_value == TRUE) ? 1 : 0; + } else if (!os_strcmp(entry.key, "frequency") && + (entry.type == DBUS_TYPE_INT32)) { + freq = entry.int32_value; + if (freq <= 0) + goto inv_args_clear; + } else if (!os_strcmp(entry.key, "go_intent") && + (entry.type == DBUS_TYPE_INT32)) { + go_intent = entry.int32_value; + if ((go_intent < 0) || (go_intent > 15)) + goto inv_args_clear; + } else if (!os_strcmp(entry.key, "wps_method") && + (entry.type == DBUS_TYPE_STRING)) { + if (!os_strcmp(entry.str_value, "pbc")) + wps_method = WPS_PBC; + else if (!os_strcmp(entry.str_value, "pin")) + wps_method = WPS_PIN_DISPLAY; + else if (!os_strcmp(entry.str_value, "display")) + wps_method = WPS_PIN_DISPLAY; + else if (!os_strcmp(entry.str_value, "keypad")) + wps_method = WPS_PIN_KEYPAD; + else + goto inv_args_clear; + } else if (!os_strcmp(entry.key, "pin") && + (entry.type == DBUS_TYPE_STRING)) { + pin = os_strdup(entry.str_value); + } else + goto inv_args_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (!peer_object_path || (wps_method == WPS_NOT_READY) || + (parse_peer_object_path(peer_object_path, addr) < 0) || + !p2p_peer_known(wpa_s->global->p2p, addr)) + goto inv_args; + + /* + * Validate the wps_method specified and the pin value. + */ + if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD)) + goto inv_args; + + new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, + persistent_group, 0, join, authorize_only, + go_intent, freq, -1, 0, 0); + + if (new_pin >= 0) { + char npin[9]; + char *generated_pin; + os_snprintf(npin, sizeof(npin), "%08d", new_pin); + generated_pin = npin; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_STRING, + &generated_pin, DBUS_TYPE_INVALID); + } else { + switch (new_pin) { + case -2: + err_msg = "connect failed due to channel " + "unavailability."; + iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE; + break; + + case -3: + err_msg = "connect failed due to unsupported channel."; + iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED; + break; + + default: + err_msg = "connect failed due to unspecified error."; + iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR; + break; + } + + /* + * TODO: + * Do we need specialized errors corresponding to above + * error conditions as against just returning a different + * error message? + */ + reply = dbus_message_new_error(message, iface, err_msg); + } + +out: + os_free(peer_object_path); + os_free(pin); + return reply; +inv_args_clear: + wpa_dbus_dict_entry_clear(&entry); +inv_args: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *peer_object_path = NULL; + char *pg_object_path = NULL; + char *iface = NULL; + char *net_id_str = NULL; + u8 peer_addr[ETH_ALEN]; + unsigned int group_id = 0; + int persistent = 0; + struct wpa_ssid *ssid; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) + return reply; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto err; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto err; + + if (!os_strcmp(entry.key, "peer") && + (entry.type == DBUS_TYPE_OBJECT_PATH)) { + peer_object_path = os_strdup(entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + } else if (!os_strcmp(entry.key, "persistent_group_object") && + (entry.type == DBUS_TYPE_OBJECT_PATH)) { + pg_object_path = os_strdup(entry.str_value); + persistent = 1; + wpa_dbus_dict_entry_clear(&entry); + } else { + wpa_dbus_dict_entry_clear(&entry); + goto err; + } + } + + if (!peer_object_path || + (parse_peer_object_path(peer_object_path, peer_addr) < 0) || + !p2p_peer_known(wpa_s->global->p2p, peer_addr)) { + goto err; + } + + if (persistent) { + /* + * A group ID is defined meaning we want to re-invoke a + * persistent group + */ + + iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, + &net_id_str, NULL); + if (iface == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, + pg_object_path); + goto out; + } + + group_id = strtoul(net_id_str, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args( + message, pg_object_path); + goto out; + } + + /* Get the SSID structure from the persistent group id */ + ssid = wpa_config_get_network(wpa_s->conf, group_id); + if (ssid == NULL || ssid->disabled != 2) + goto err; + + if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) { + reply = wpas_dbus_error_unknown_error( + message, + "Failed to reinvoke a persistent group"); + goto out; + } + } else { + /* + * No group ID means propose to a peer to join my active group + */ + if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, + peer_addr, NULL)) { + reply = wpas_dbus_error_unknown_error( + message, "Failed to join to an active group"); + goto out; + } + } + +out: + os_free(pg_object_path); + os_free(peer_object_path); + return reply; + +err: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter; + char *peer_object_path = NULL; + char *config_method = NULL; + u8 peer_addr[ETH_ALEN]; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &peer_object_path); + + if (parse_peer_object_path(peer_object_path, peer_addr) < 0) + return wpas_dbus_error_invalid_args(message, NULL); + + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &config_method); + + /* + * Validation checks on config_method are being duplicated here + * to be able to return invalid args reply since the error code + * from p2p module are not granular enough (yet). + */ + if (os_strcmp(config_method, "display") && + os_strcmp(config_method, "keypad") && + os_strcmp(config_method, "pbc") && + os_strcmp(config_method, "pushbutton")) + return wpas_dbus_error_invalid_args(message, NULL); + + if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, + WPAS_P2P_PD_FOR_GO_NEG) < 0) + return wpas_dbus_error_unknown_error(message, + "Failed to send provision discovery request"); + + return NULL; +} + + +/* + * P2P Device property accessor methods. + */ + +dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + DBusMessageIter variant_iter, dict_iter; + DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val, + iter_secdev_dict_array; + const char *dev_name; + int num_vendor_extensions = 0; + int i; + const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) + return FALSE; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) + goto err_no_mem; + + /* DeviceName */ + dev_name = wpa_s->conf->device_name; + if (dev_name && + !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name)) + goto err_no_mem; + + /* Primary device type */ + if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType", + (char *)wpa_s->conf->device_type, + WPS_DEV_TYPE_LEN)) + goto err_no_mem; + + /* Secondary device types */ + if (wpa_s->conf->num_sec_device_types) { + if (!wpa_dbus_dict_begin_array(&dict_iter, + "SecondaryDeviceTypes", + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &iter_secdev_dict_entry, + &iter_secdev_dict_val, + &iter_secdev_dict_array)) + goto err_no_mem; + + for (i = 0; i < wpa_s->conf->num_sec_device_types; i++) + wpa_dbus_dict_bin_array_add_element( + &iter_secdev_dict_array, + wpa_s->conf->sec_device_type[i], + WPS_DEV_TYPE_LEN); + + if (!wpa_dbus_dict_end_array(&dict_iter, + &iter_secdev_dict_entry, + &iter_secdev_dict_val, + &iter_secdev_dict_array)) + goto err_no_mem; + } + + /* Vendor Extensions */ + for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { + if (wpa_s->conf->wps_vendor_ext[i] == NULL) + continue; + vendor_ext[num_vendor_extensions++] = + wpa_s->conf->wps_vendor_ext[i]; + } + + if (num_vendor_extensions && + !wpa_dbus_dict_append_wpabuf_array(&dict_iter, + "VendorExtension", + vendor_ext, + num_vendor_extensions)) + goto err_no_mem; + + /* GO Intent */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent", + wpa_s->conf->p2p_go_intent)) + goto err_no_mem; + + /* Persistent Reconnect */ + if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect", + wpa_s->conf->persistent_reconnect)) + goto err_no_mem; + + /* Listen Reg Class */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass", + wpa_s->conf->p2p_listen_reg_class)) + goto err_no_mem; + + /* Listen Channel */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel", + wpa_s->conf->p2p_listen_channel)) + goto err_no_mem; + + /* Oper Reg Class */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass", + wpa_s->conf->p2p_oper_reg_class)) + goto err_no_mem; + + /* Oper Channel */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel", + wpa_s->conf->p2p_oper_channel)) + goto err_no_mem; + + /* SSID Postfix */ + if (wpa_s->conf->p2p_ssid_postfix && + !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix", + wpa_s->conf->p2p_ssid_postfix)) + goto err_no_mem; + + /* Intra Bss */ + if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss", + wpa_s->conf->p2p_intra_bss)) + goto err_no_mem; + + /* Group Idle */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle", + wpa_s->conf->p2p_group_idle)) + goto err_no_mem; + + /* Dissasociation low ack */ + if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack", + wpa_s->conf->disassoc_low_ack)) + goto err_no_mem; + + if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || + !dbus_message_iter_close_container(iter, &variant_iter)) + goto err_no_mem; + + return TRUE; + +err_no_mem: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; +} + + +dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + DBusMessageIter variant_iter, iter_dict; + struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING }; + unsigned int i; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) + return FALSE; + + dbus_message_iter_recurse(iter, &variant_iter); + if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) + return FALSE; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; + } + + if (os_strcmp(entry.key, "DeviceName") == 0) { + char *devname; + + if (entry.type != DBUS_TYPE_STRING) + goto error; + + devname = os_strdup(entry.str_value); + if (devname == NULL) + goto err_no_mem_clear; + + os_free(wpa_s->conf->device_name); + wpa_s->conf->device_name = devname; + + wpa_s->conf->changed_parameters |= + CFG_CHANGED_DEVICE_NAME; + } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE || + entry.array_len != WPS_DEV_TYPE_LEN) + goto error; + + os_memcpy(wpa_s->conf->device_type, + entry.bytearray_value, + WPS_DEV_TYPE_LEN); + wpa_s->conf->changed_parameters |= + CFG_CHANGED_DEVICE_TYPE; + } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != WPAS_DBUS_TYPE_BINARRAY || + entry.array_len > MAX_SEC_DEVICE_TYPES) + goto error; + + for (i = 0; i < entry.array_len; i++) + if (wpabuf_len(entry.binarray_value[i]) != + WPS_DEV_TYPE_LEN) + goto err_no_mem_clear; + for (i = 0; i < entry.array_len; i++) + os_memcpy(wpa_s->conf->sec_device_type[i], + wpabuf_head(entry.binarray_value[i]), + WPS_DEV_TYPE_LEN); + wpa_s->conf->num_sec_device_types = entry.array_len; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_SEC_DEVICE_TYPE; + } else if (os_strcmp(entry.key, "VendorExtension") == 0) { + if ((entry.type != DBUS_TYPE_ARRAY) || + (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) || + (entry.array_len > P2P_MAX_WPS_VENDOR_EXT)) + goto error; + + wpa_s->conf->changed_parameters |= + CFG_CHANGED_VENDOR_EXTENSION; + + for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { + wpabuf_free(wpa_s->conf->wps_vendor_ext[i]); + if (i < entry.array_len) { + wpa_s->conf->wps_vendor_ext[i] = + entry.binarray_value[i]; + entry.binarray_value[i] = NULL; + } else + wpa_s->conf->wps_vendor_ext[i] = NULL; + } + } else if ((os_strcmp(entry.key, "GOIntent") == 0) && + (entry.type == DBUS_TYPE_UINT32) && + (entry.uint32_value <= 15)) + wpa_s->conf->p2p_go_intent = entry.uint32_value; + else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) && + (entry.type == DBUS_TYPE_BOOLEAN)) + wpa_s->conf->persistent_reconnect = entry.bool_value; + else if ((os_strcmp(entry.key, "ListenRegClass") == 0) && + (entry.type == DBUS_TYPE_UINT32)) { + wpa_s->conf->p2p_listen_reg_class = entry.uint32_value; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_LISTEN_CHANNEL; + } else if ((os_strcmp(entry.key, "ListenChannel") == 0) && + (entry.type == DBUS_TYPE_UINT32)) { + wpa_s->conf->p2p_listen_channel = entry.uint32_value; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_LISTEN_CHANNEL; + } else if ((os_strcmp(entry.key, "OperRegClass") == 0) && + (entry.type == DBUS_TYPE_UINT32)) { + wpa_s->conf->p2p_oper_reg_class = entry.uint32_value; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_OPER_CHANNEL; + } else if ((os_strcmp(entry.key, "OperChannel") == 0) && + (entry.type == DBUS_TYPE_UINT32)) { + wpa_s->conf->p2p_oper_channel = entry.uint32_value; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_OPER_CHANNEL; + } else if (os_strcmp(entry.key, "SsidPostfix") == 0) { + char *postfix; + + if (entry.type != DBUS_TYPE_STRING) + goto error; + + postfix = os_strdup(entry.str_value); + if (!postfix) + goto err_no_mem_clear; + + os_free(wpa_s->conf->p2p_ssid_postfix); + wpa_s->conf->p2p_ssid_postfix = postfix; + + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_SSID_POSTFIX; + } else if ((os_strcmp(entry.key, "IntraBss") == 0) && + (entry.type == DBUS_TYPE_BOOLEAN)) { + wpa_s->conf->p2p_intra_bss = entry.bool_value; + wpa_s->conf->changed_parameters |= + CFG_CHANGED_P2P_INTRA_BSS; + } else if ((os_strcmp(entry.key, "GroupIdle") == 0) && + (entry.type == DBUS_TYPE_UINT32)) + wpa_s->conf->p2p_group_idle = entry.uint32_value; + else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 && + entry.type == DBUS_TYPE_UINT32) + wpa_s->conf->disassoc_low_ack = entry.uint32_value; + else + goto error; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (wpa_s->conf->changed_parameters) { + /* Some changed parameters requires to update config*/ + wpa_supplicant_update_config(wpa_s); + } + + return TRUE; + + error: + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + wpa_dbus_dict_entry_clear(&entry); + return FALSE; + + err_no_mem_clear: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + wpa_dbus_dict_entry_clear(&entry); + return FALSE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct p2p_data *p2p = wpa_s->global->p2p; + int next = 0, i = 0; + int num = 0, out_of_mem = 0; + const u8 *addr; + const struct p2p_peer_info *peer_info = NULL; + dbus_bool_t success = FALSE; + + struct dl_list peer_objpath_list; + struct peer_objpath_node { + struct dl_list list; + char path[WPAS_DBUS_OBJECT_PATH_MAX]; + } *node, *tmp; + + char **peer_obj_paths = NULL; + + if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) + return FALSE; + + dl_list_init(&peer_objpath_list); + + /* Get the first peer info */ + peer_info = p2p_get_peer_found(p2p, NULL, next); + + /* Get next and accumulate them */ + next = 1; + while (peer_info != NULL) { + node = os_zalloc(sizeof(struct peer_objpath_node)); + if (!node) { + out_of_mem = 1; + goto error; + } + + addr = peer_info->p2p_device_addr; + os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART + "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(addr)); + dl_list_add_tail(&peer_objpath_list, &node->list); + num++; + + peer_info = p2p_get_peer_found(p2p, addr, next); + } + + /* + * Now construct the peer object paths in a form suitable for + * array_property_getter helper below. + */ + peer_obj_paths = os_calloc(num, sizeof(char *)); + + if (!peer_obj_paths) { + out_of_mem = 1; + goto error; + } + + dl_list_for_each_safe(node, tmp, &peer_objpath_list, + struct peer_objpath_node, list) + peer_obj_paths[i++] = node->path; + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + peer_obj_paths, num, + error); + +error: + if (peer_obj_paths) + os_free(peer_obj_paths); + + dl_list_for_each_safe(node, tmp, &peer_objpath_list, + struct peer_objpath_node, list) { + dl_list_del(&node->list); + os_free(node); + } + if (out_of_mem) + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + + return success; +} + + +enum wpas_p2p_role { + WPAS_P2P_ROLE_DEVICE, + WPAS_P2P_ROLE_GO, + WPAS_P2P_ROLE_CLIENT, +}; + +static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (!ssid) + return WPAS_P2P_ROLE_DEVICE; + if (wpa_s->wpa_state != WPA_COMPLETED) + return WPAS_P2P_ROLE_DEVICE; + + switch (ssid->mode) { + case WPAS_MODE_P2P_GO: + case WPAS_MODE_P2P_GROUP_FORMATION: + return WPAS_P2P_ROLE_GO; + case WPAS_MODE_INFRA: + if (ssid->p2p_group) + return WPAS_P2P_ROLE_CLIENT; + return WPAS_P2P_ROLE_DEVICE; + default: + return WPAS_P2P_ROLE_DEVICE; + } +} + + +dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char *str; + + switch (wpas_get_p2p_role(wpa_s)) { + case WPAS_P2P_ROLE_GO: + str = "GO"; + break; + case WPAS_P2P_ROLE_CLIENT: + str = "client"; + break; + default: + str = "device"; + } + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str, + error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; + char *dbus_groupobj_path = path_buf; + + if (wpa_s->dbus_groupobj_path == NULL) + os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "/"); + else + os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s", wpa_s->dbus_groupobj_path); + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &dbus_groupobj_path, error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + + if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT) + os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); + else + os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" + COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr)); + + path = go_peer_obj_path; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, + &path, error); +} + + +/* + * Peer object properties accessor methods + */ + +dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + char *tmp; + + if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error)) + return FALSE; + + /* get the peer info */ + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + tmp = os_strdup(info->device_name); + if (!tmp) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp, + error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + os_free(tmp); + return FALSE; + } + + os_free(tmp); + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + (char *) + info->pri_dev_type, + WPS_DEV_TYPE_LEN, error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &info->config_methods, error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &info->level, error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, + &info->dev_capab, error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, + &info->group_capab, error)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + DBusMessageIter variant_iter, array_iter; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 1", __func__); + return FALSE; + } + + if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 2", __func__); + return FALSE; + } + + if (info->wps_sec_dev_type_list_len) { + const u8 *sec_dev_type_list = info->wps_sec_dev_type_list; + int num_sec_device_types = + info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; + int i; + DBusMessageIter inner_array_iter; + + for (i = 0; i < num_sec_device_types; i++) { + if (!dbus_message_iter_open_container( + &array_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &inner_array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct " + "message 3 (%d)", + __func__, i); + return FALSE; + } + + if (!dbus_message_iter_append_fixed_array( + &inner_array_iter, DBUS_TYPE_BYTE, + &sec_dev_type_list, WPS_DEV_TYPE_LEN)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct " + "message 4 (%d)", + __func__, i); + return FALSE; + } + + if (!dbus_message_iter_close_container( + &array_iter, &inner_array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct " + "message 5 (%d)", + __func__, i); + return FALSE; + } + + sec_dev_type_list += WPS_DEV_TYPE_LEN; + } + } + + if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 6", __func__); + return FALSE; + } + + if (!dbus_message_iter_close_container(iter, &variant_iter)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: failed to construct message 7", __func__); + return FALSE; + } + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT]; + int i, num; + struct peer_handler_args *peer_args = user_data; + const struct p2p_peer_info *info; + + info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, + peer_args->p2p_device_addr, 0); + if (info == NULL) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "failed to find peer"); + return FALSE; + } + + /* Add WPS vendor extensions attribute */ + for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { + if (info->wps_vendor_ext[i] == NULL) + continue; + vendor_extension[num] = info->wps_vendor_ext[i]; + num++; + } + + if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE, + vendor_extension, + num, error)) + return FALSE; + + return TRUE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + dbus_bool_t success; + /* struct peer_handler_args *peer_args = user_data; */ + + success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + NULL, 0, error); + return success; +} + + +/** + * wpas_dbus_getter_persistent_groups - Get array of persistent group objects + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "PersistentGroups" property. + */ +dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_ssid *ssid; + char **paths; + unsigned int i = 0, num = 0; + dbus_bool_t success = FALSE; + + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "dbus: %s: " + "An error occurred getting persistent groups list", + __func__); + dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error " + "occurred getting persistent groups list"); + return FALSE; + } + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) + if (network_is_persistent_group(ssid)) + num++; + + paths = os_calloc(num, sizeof(char *)); + if (!paths) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; + } + + /* Loop through configured networks and append object path of each */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (!network_is_persistent_group(ssid)) + continue; + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (paths[i] == NULL) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + goto out; + } + /* Construct the object path for this network. */ + os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", + wpa_s->dbus_new_path, ssid->id); + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num, error); + +out: + while (i) + os_free(paths[--i]); + os_free(paths); + return success; +} + + +/** + * wpas_dbus_getter_persistent_group_properties - Get options for a persistent + * group + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "Properties" property of a persistent group. + */ +dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + + /* Leveraging the fact that persistent group object is still + * represented in same manner as network within. + */ + return wpas_dbus_getter_network_properties(iter, error, net); +} + + +/** + * wpas_dbus_setter_persistent_group_properties - Get options for a persistent + * group + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "Properties" property of a persistent group. + */ +dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct network_handler_args *net = user_data; + struct wpa_ssid *ssid = net->ssid; + DBusMessageIter variant_iter; + + /* + * Leveraging the fact that persistent group object is still + * represented in same manner as network within. + */ + dbus_message_iter_recurse(iter, &variant_iter); + return set_network_properties(net->wpa_s, ssid, &variant_iter, error); +} + + +/** + * wpas_dbus_new_iface_add_persistent_group - Add a new configured + * persistent_group + * @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 + * persistent group + * + * Handler function for "AddPersistentGroup" method call of a P2P Device + * interface. + */ +DBusMessage * wpas_dbus_handler_add_persistent_group( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_ssid *ssid = NULL; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; + DBusError error; + + dbus_message_iter_init(message, &iter); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "dbus: %s: " + "Cannot add new persistent group", __func__); + reply = wpas_dbus_error_unknown_error( + message, + "wpa_supplicant could not add " + "a persistent group on this interface."); + goto err; + } + + /* Mark the ssid as being a persistent group before the notification */ + ssid->disabled = 2; + ssid->p2p_persistent_group = 1; + wpas_notify_persistent_group_added(wpa_s, ssid); + + wpa_config_set_network_defaults(ssid); + + dbus_error_init(&error); + if (!set_network_properties(wpa_s, ssid, &iter, &error)) { + wpa_printf(MSG_DEBUG, "dbus: %s: " + "Control interface could not set persistent group " + "properties", __func__); + reply = wpas_dbus_reply_new_from_error(message, &error, + DBUS_ERROR_INVALID_ARGS, + "Failed to set network " + "properties"); + dbus_error_free(&error); + goto err; + } + + /* Construct the object path for this network. */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_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_persistent_group_removed(wpa_s, ssid); + wpa_config_remove_network(wpa_s->conf, ssid->id); + } + return reply; +} + + +/** + * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent + * group + * @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 "RemovePersistentGroup" method call of a P2P Device + * interface. + */ +DBusMessage * wpas_dbus_handler_remove_persistent_group( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *persistent_group_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, 1, + &persistent_group_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(persistent_group_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_persistent_group_unknown(message); + goto out; + } + + wpas_notify_persistent_group_removed(wpa_s, ssid); + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + wpa_printf(MSG_ERROR, "dbus: %s: " + "error occurred when removing persistent group %d", + __func__, id); + reply = wpas_dbus_error_unknown_error( + message, + "error removing the specified persistent group on " + "this interface."); + goto out; + } + +out: + os_free(iface); + os_free(persistent_group_id); + return reply; +} + + +static void remove_persistent_group(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + wpas_notify_persistent_group_removed(wpa_s, ssid); + + if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { + wpa_printf(MSG_ERROR, "dbus: %s: " + "error occurred when removing persistent group %d", + __func__, ssid->id); + return; + } +} + + +/** + * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured + * persistent groups + * @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 "RemoveAllPersistentGroups" method call of a + * P2P Device interface. + */ +DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid, *next; + struct wpa_config *config; + + config = wpa_s->conf; + ssid = config->ssid; + while (ssid) { + next = ssid->next; + if (network_is_persistent_group(ssid)) + remove_persistent_group(wpa_s, ssid); + ssid = next; + } + return NULL; +} + + +/* + * Group object properties accessor methods + */ + +dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_ssid *ssid; + unsigned int num_members; + char **paths; + unsigned int i; + void *next = NULL; + const u8 *addr; + dbus_bool_t success = FALSE; + + /* Verify correct role for this property */ + if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) { + return wpas_dbus_simple_array_property_getter( + iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error); + } + + ssid = wpa_s->conf->ssid; + /* At present WPAS P2P_GO mode only applicable for p2p_go */ + if (ssid->mode != WPAS_MODE_P2P_GO && + ssid->mode != WPAS_MODE_AP && + ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) + return FALSE; + + num_members = p2p_get_group_num_members(wpa_s->p2p_group); + + paths = os_calloc(num_members, sizeof(char *)); + if (!paths) + goto out_of_memory; + + i = 0; + while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) { + paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (!paths[i]) + goto out_of_memory; + os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART + "/" COMPACT_MACSTR, + wpa_s->dbus_groupobj_path, MAC2STR(addr)); + i++; + } + + success = wpas_dbus_simple_array_property_getter(iter, + DBUS_TYPE_OBJECT_PATH, + paths, num_members, + error); + + for (i = 0; i < num_members; i++) + os_free(paths[i]); + os_free(paths); + return success; + +out_of_memory: + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); + if (paths) { + for (i = 0; i < num_members; i++) + os_free(paths[i]); + os_free(paths); + } + return FALSE; +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + if (wpa_s->current_ssid == NULL) + return FALSE; + return wpas_dbus_simple_array_property_getter( + iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid, + wpa_s->current_ssid->ssid_len, error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + u8 role = wpas_get_p2p_role(wpa_s); + u8 *p_bssid; + + if (role == WPAS_P2P_ROLE_CLIENT) { + if (wpa_s->current_ssid == NULL) + return FALSE; + p_bssid = wpa_s->current_ssid->bssid; + } else { + if (wpa_s->ap_iface == NULL) + return FALSE; + p_bssid = wpa_s->ap_iface->bss[0]->own_addr; + } + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + p_bssid, ETH_ALEN, + error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + u16 op_freq; + u8 role = wpas_get_p2p_role(wpa_s); + + if (role == WPAS_P2P_ROLE_CLIENT) { + if (wpa_s->go_params == NULL) + return FALSE; + op_freq = wpa_s->go_params->freq; + } else { + if (wpa_s->ap_iface == NULL) + return FALSE; + op_freq = wpa_s->ap_iface->freq; + } + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, + &op_freq, error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + u8 role = wpas_get_p2p_role(wpa_s); + char *p_pass = NULL; + + /* Verify correct role for this property */ + if (role == WPAS_P2P_ROLE_GO) { + if (wpa_s->current_ssid == NULL) + return FALSE; + p_pass = wpa_s->current_ssid->passphrase; + } else + p_pass = ""; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, + &p_pass, error); + +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, + DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + u8 role = wpas_get_p2p_role(wpa_s); + u8 *p_psk = NULL; + u8 psk_len = 0; + + /* Verify correct role for this property */ + if (role == WPAS_P2P_ROLE_CLIENT) { + if (wpa_s->current_ssid == NULL) + return FALSE; + p_psk = wpa_s->current_ssid->psk; + psk_len = 32; + } + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + &p_psk, psk_len, error); +} + + +dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct hostapd_data *hapd; + struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + int num_vendor_ext = 0; + int i; + + /* Verify correct role for this property */ + if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) { + if (wpa_s->ap_iface == NULL) + return FALSE; + hapd = wpa_s->ap_iface->bss[0]; + + /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */ + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (hapd->conf->wps_vendor_ext[i] == NULL) + vendor_ext[i] = NULL; + else { + vendor_ext[num_vendor_ext++] = + hapd->conf->wps_vendor_ext[i]; + } + } + } + + /* Return vendor extensions or no data */ + return wpas_dbus_simple_array_array_property_getter(iter, + DBUS_TYPE_BYTE, + vendor_ext, + num_vendor_ext, + error); +} + + +dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + DBusMessageIter variant_iter, iter_dict; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + unsigned int i; + struct hostapd_data *hapd = NULL; + + if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO && + wpa_s->ap_iface != NULL) + hapd = wpa_s->ap_iface->bss[0]; + else + return FALSE; + + dbus_message_iter_recurse(iter, &variant_iter); + if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) + return FALSE; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; + } + + if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != WPAS_DBUS_TYPE_BINARRAY || + entry.array_len > MAX_WPS_VENDOR_EXTENSIONS) + goto error; + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (i < entry.array_len) { + hapd->conf->wps_vendor_ext[i] = + entry.binarray_value[i]; + entry.binarray_value[i] = NULL; + } else + hapd->conf->wps_vendor_ext[i] = NULL; + } + + hostapd_update_wps(hapd); + } else + goto error; + + wpa_dbus_dict_entry_clear(&entry); + } + + return TRUE; + +error: + wpa_dbus_dict_entry_clear(&entry); + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; +} + + +DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + int upnp = 0; + int bonjour = 0; + char *service = NULL; + struct wpabuf *query = NULL; + struct wpabuf *resp = NULL; + u8 version = 0; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "service_type") && + (entry.type == DBUS_TYPE_STRING)) { + if (!os_strcmp(entry.str_value, "upnp")) + upnp = 1; + else if (!os_strcmp(entry.str_value, "bonjour")) + bonjour = 1; + else + goto error_clear; + } else if (!os_strcmp(entry.key, "version") && + entry.type == DBUS_TYPE_INT32) { + version = entry.uint32_value; + } else if (!os_strcmp(entry.key, "service") && + (entry.type == DBUS_TYPE_STRING)) { + service = os_strdup(entry.str_value); + } else if (!os_strcmp(entry.key, "query")) { + if ((entry.type != DBUS_TYPE_ARRAY) || + (entry.array_type != DBUS_TYPE_BYTE)) + goto error_clear; + query = wpabuf_alloc_copy( + entry.bytearray_value, + entry.array_len); + } else if (!os_strcmp(entry.key, "response")) { + if ((entry.type != DBUS_TYPE_ARRAY) || + (entry.array_type != DBUS_TYPE_BYTE)) + goto error_clear; + resp = wpabuf_alloc_copy(entry.bytearray_value, + entry.array_len); + } + wpa_dbus_dict_entry_clear(&entry); + } + + if (upnp == 1) { + if (version <= 0 || service == NULL) + goto error; + + if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0) + goto error; + + os_free(service); + service = NULL; + } else if (bonjour == 1) { + if (query == NULL || resp == NULL) + goto error; + + if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) + goto error; + query = NULL; + resp = NULL; + } else + goto error; + + return reply; +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + os_free(service); + wpabuf_free(query); + wpabuf_free(resp); + return wpas_dbus_error_invalid_args(message, NULL); +} + + +DBusMessage * wpas_dbus_handler_p2p_delete_service( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + int upnp = 0; + int bonjour = 0; + int ret = 0; + char *service = NULL; + struct wpabuf *query = NULL; + u8 version = 0; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "service_type") && + (entry.type == DBUS_TYPE_STRING)) { + if (!os_strcmp(entry.str_value, "upnp")) + upnp = 1; + else if (!os_strcmp(entry.str_value, "bonjour")) + bonjour = 1; + else + goto error_clear; + wpa_dbus_dict_entry_clear(&entry); + } + } + if (upnp == 1) { + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!os_strcmp(entry.key, "version") && + entry.type == DBUS_TYPE_INT32) + version = entry.uint32_value; + else if (!os_strcmp(entry.key, "service") && + entry.type == DBUS_TYPE_STRING) + service = os_strdup(entry.str_value); + else + goto error_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (version <= 0 || service == NULL) + goto error; + + ret = wpas_p2p_service_del_upnp(wpa_s, version, service); + os_free(service); + if (ret != 0) + goto error; + } else if (bonjour == 1) { + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "query")) { + if ((entry.type != DBUS_TYPE_ARRAY) || + (entry.array_type != DBUS_TYPE_BYTE)) + goto error_clear; + query = wpabuf_alloc_copy( + entry.bytearray_value, + entry.array_len); + } else + goto error_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (query == NULL) + goto error; + + ret = wpas_p2p_service_del_bonjour(wpa_s, query); + if (ret != 0) + goto error; + wpabuf_free(query); + } else + goto error; + + return reply; +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + return wpas_dbus_error_invalid_args(message, NULL); +} + + +DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpas_p2p_service_flush(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_service_sd_req( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + int upnp = 0; + char *service = NULL; + char *peer_object_path = NULL; + struct wpabuf *tlv = NULL; + u8 version = 0; + u64 ref = 0; + u8 addr_buf[ETH_ALEN], *addr; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!os_strcmp(entry.key, "peer_object") && + entry.type == DBUS_TYPE_OBJECT_PATH) { + peer_object_path = os_strdup(entry.str_value); + } else if (!os_strcmp(entry.key, "service_type") && + entry.type == DBUS_TYPE_STRING) { + if (!os_strcmp(entry.str_value, "upnp")) + upnp = 1; + else + goto error_clear; + } else if (!os_strcmp(entry.key, "version") && + entry.type == DBUS_TYPE_INT32) { + version = entry.uint32_value; + } else if (!os_strcmp(entry.key, "service") && + entry.type == DBUS_TYPE_STRING) { + service = os_strdup(entry.str_value); + } else if (!os_strcmp(entry.key, "tlv")) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE) + goto error_clear; + tlv = wpabuf_alloc_copy(entry.bytearray_value, + entry.array_len); + } else + goto error_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (!peer_object_path) { + addr = NULL; + } else { + if (parse_peer_object_path(peer_object_path, addr_buf) < 0 || + !p2p_peer_known(wpa_s->global->p2p, addr_buf)) + goto error; + + addr = addr_buf; + } + + if (upnp == 1) { + if (version <= 0 || service == NULL) + goto error; + + ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service); + } else { + if (tlv == NULL) + goto error; + ref = wpas_p2p_sd_request(wpa_s, addr, tlv); + wpabuf_free(tlv); + } + + if (ref != 0) { + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_UINT64, + &ref, DBUS_TYPE_INVALID); + } else { + reply = wpas_dbus_error_unknown_error( + message, "Unable to send SD request"); + } +out: + os_free(service); + os_free(peer_object_path); + return reply; +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + if (tlv) + wpabuf_free(tlv); + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +DBusMessage * wpas_dbus_handler_p2p_service_sd_res( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter_dict; + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_dbus_dict_entry entry; + char *peer_object_path = NULL; + struct wpabuf *tlv = NULL; + int freq = 0; + int dlg_tok = 0; + u8 addr[ETH_ALEN]; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + if (!os_strcmp(entry.key, "peer_object") && + entry.type == DBUS_TYPE_OBJECT_PATH) { + peer_object_path = os_strdup(entry.str_value); + } else if (!os_strcmp(entry.key, "frequency") && + entry.type == DBUS_TYPE_INT32) { + freq = entry.uint32_value; + } else if (!os_strcmp(entry.key, "dialog_token") && + entry.type == DBUS_TYPE_UINT32) { + dlg_tok = entry.uint32_value; + } else if (!os_strcmp(entry.key, "tlvs")) { + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE) + goto error_clear; + tlv = wpabuf_alloc_copy(entry.bytearray_value, + entry.array_len); + } else + goto error_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + if (!peer_object_path || + (parse_peer_object_path(peer_object_path, addr) < 0) || + !p2p_peer_known(wpa_s->global->p2p, addr)) + goto error; + + if (tlv == NULL) + goto error; + + wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv); + wpabuf_free(tlv); +out: + os_free(peer_object_path); + return reply; +error_clear: + wpa_dbus_dict_entry_clear(&entry); +error: + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; +} + + +DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter; + u64 req = 0; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &req); + + if (req == 0) + goto error; + + if (!wpas_p2p_sd_cancel_request(wpa_s, req)) + goto error; + + return NULL; +error: + return wpas_dbus_error_invalid_args(message, NULL); +} + + +DBusMessage * wpas_dbus_handler_p2p_service_update( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + wpas_p2p_sd_service_update(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_p2p_serv_disc_external( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter; + int ext = 0; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &ext); + + wpa_s->p2p_sd_over_ctrl_iface = ext; + + return NULL; + +} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h new file mode 100644 index 0000000..a11b3c8 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h @@ -0,0 +1,211 @@ +/* + * WPA Supplicant / dbus-based control interface for p2p + * Copyright (c) 2011-2012, Intel Corporation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DBUS_NEW_HANDLERS_P2P_H +#define DBUS_NEW_HANDLERS_P2P_H + +struct peer_handler_args { + struct wpa_supplicant *wpa_s; + u8 p2p_device_addr[ETH_ALEN]; +}; + +struct groupmember_handler_args { + struct wpa_supplicant *wpa_s; + u8 member_addr[ETH_ALEN]; +}; + +/* + * P2P Device methods + */ + +DBusMessage *wpas_dbus_handler_p2p_find( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_stop_find( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_rejectpeer( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_listen( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_extendedlisten( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_presence_request( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_prov_disc_req( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_group_add( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_connect( + DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_invite( + DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_disconnect( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_flush( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_add_service( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_delete_service( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_flush_service( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_service_sd_req( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_service_sd_res( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_service_update( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage *wpas_dbus_handler_p2p_serv_disc_external( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +/* + * P2P Device property accessor methods. + */ +dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +/* + * P2P Peer properties. + */ + +dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( + DBusMessageIter *iter, DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( + DBusMessageIter *iter, DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +/* + * P2P Group properties + */ + +dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +/* + * P2P Persistent Groups and properties + */ + +dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, + DBusError *error, void *user_data); + +dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, + DBusError *error, + void *user_data); + +DBusMessage * wpas_dbus_handler_add_persistent_group( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_persistent_group( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( + DBusMessage *message, struct wpa_supplicant *wpa_s); + + +#endif /* DBUS_NEW_HANDLERS_P2P_H */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c new file mode 100644 index 0000000..4ad5e7e --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c @@ -0,0 +1,391 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "../config.h" +#include "../wpa_supplicant_i.h" +#include "../wps_supplicant.h" +#include "../driver_i.h" +#include "../ap.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; + u8 *p2p_dev_addr; +}; + + +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; +} + + +#ifdef CONFIG_P2P +static int wpas_dbus_handler_wps_p2p_dev_addr(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 " + "P2PDeviceAddress type, byte array required"); + *reply = wpas_dbus_error_invalid_args( + message, "P2PDeviceAddress must be a byte array"); + return -1; + } + dbus_message_iter_recurse(&variant_iter, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, ¶ms->p2p_dev_addr, + &len); + if (len != ETH_ALEN) { + wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " + "P2PDeviceAddress length %d", len); + *reply = wpas_dbus_error_invalid_args(message, + "P2PDeviceAddress " + "has wrong length"); + return -1; + } + return 0; +} +#endif /* CONFIG_P2P */ + + +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); +#ifdef CONFIG_P2P + else if (os_strcmp(key, "P2PDeviceAddress") == 0) + return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter, + params, reply); +#endif /* CONFIG_P2P */ + + 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) { +#ifdef CONFIG_AP + if (wpa_s->ap_iface) + ret = wpa_supplicant_ap_wps_pin(wpa_s, + params.bssid, + params.pin, + npin, sizeof(npin), 0); + else +#endif /* CONFIG_AP */ + { + 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 { +#ifdef CONFIG_AP + if (wpa_s->ap_iface) + ret = wpa_supplicant_ap_wps_pbc(wpa_s, + params.bssid, + params.p2p_dev_addr); + else +#endif /* CONFIG_AP */ + 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: TRUE on success, FALSE 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. + */ +dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, + &process, error); +} + + +/** + * wpas_dbus_setter_process_credentials - Set credentials_processed conf param + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 + * if boolean argument is true or on 1 if otherwise. + */ +dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, + DBusError *error, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_bool_t process_credentials, old_pc; + + if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, + &process_credentials)) + return FALSE; + + 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 TRUE; +} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c new file mode 100644 index 0000000..cfa6a15 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c @@ -0,0 +1,1061 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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" +#include "dbus_dict_helpers.h" + + +static dbus_bool_t fill_dict_with_properties( + DBusMessageIter *dict_iter, + const struct wpa_dbus_property_desc *props, + const char *interface, void *user_data, DBusError *error) +{ + DBusMessageIter entry_iter; + const struct wpa_dbus_property_desc *dsc; + + for (dsc = props; dsc && dsc->dbus_property; dsc++) { + /* Only return properties for the requested D-Bus interface */ + if (os_strncmp(dsc->dbus_interface, interface, + WPAS_DBUS_INTERFACE_MAX) != 0) + continue; + + /* Skip write-only properties */ + if (dsc->getter == NULL) + continue; + + if (!dbus_message_iter_open_container(dict_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + return FALSE; + } + if (!dbus_message_iter_append_basic(&entry_iter, + DBUS_TYPE_STRING, + &dsc->dbus_property)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, + "no memory"); + return FALSE; + } + + /* An error getting a property fails the request entirely */ + if (!dsc->getter(&entry_iter, error, user_data)) + return FALSE; + + dbus_message_iter_close_container(dict_iter, &entry_iter); + } + + return TRUE; +} + + +/** + * 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) +{ + DBusMessage *reply; + DBusMessageIter iter, dict_iter; + DBusError error; + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply", + __func__); + return NULL; + } + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { + wpa_printf(MSG_ERROR, "%s: out of memory creating reply", + __func__); + dbus_message_unref(reply); + reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, + "out of memory"); + return reply; + } + + dbus_error_init(&error); + if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties, + interface, obj_dsc->user_data, &error)) + { + dbus_message_unref(reply); + reply = wpas_dbus_reply_new_from_error(message, &error, + DBUS_ERROR_INVALID_ARGS, + "No readable properties" + " in this interface"); + dbus_error_free(&error); + return reply; + } + + wpa_dbus_dict_close_write(&iter, &dict_iter); + 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) +{ + DBusMessage *reply; + DBusMessageIter iter; + DBusError error; + + if (os_strcmp(dbus_message_get_signature(message), "ss")) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + } + + if (dsc->getter == NULL) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Property is write-only"); + } + + reply = dbus_message_new_method_return(message); + dbus_message_iter_init_append(reply, &iter); + + dbus_error_init(&error); + if (dsc->getter(&iter, &error, user_data) == FALSE) { + dbus_message_unref(reply); + reply = wpas_dbus_reply_new_from_error( + message, &error, DBUS_ERROR_FAILED, + "Failed to read property"); + dbus_error_free(&error); + } + + return reply; +} + + +static DBusMessage * properties_set(DBusMessage *message, + const struct wpa_dbus_property_desc *dsc, + void *user_data) +{ + DBusMessage *reply; + DBusMessageIter iter; + DBusError error; + + if (os_strcmp(dbus_message_get_signature(message), "ssv")) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + NULL); + } + + if (dsc->setter == NULL) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Property is read-only"); + } + + dbus_message_iter_init(message, &iter); + /* Skip the interface name and the property name */ + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + + /* Iter will now point to the property's new value */ + dbus_error_init(&error); + if (dsc->setter(&iter, &error, user_data) == TRUE) { + /* Success */ + reply = dbus_message_new_method_return(message); + } else { + reply = wpas_dbus_reply_new_from_error( + message, &error, DBUS_ERROR_FAILED, + "Failed to set property"); + dbus_error_free(&error); + } + + return reply; +} + + +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 dbus_bool_t put_changed_properties( + const struct wpa_dbus_object_desc *obj_dsc, const char *interface, + DBusMessageIter *dict_iter, int clear_changed) +{ + DBusMessageIter entry_iter; + const struct wpa_dbus_property_desc *dsc; + int i; + DBusError error; + + 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; + if (clear_changed) + obj_dsc->prop_changed_flags[i] = 0; + + if (!dbus_message_iter_open_container(dict_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &entry_iter)) + return FALSE; + + if (!dbus_message_iter_append_basic(&entry_iter, + DBUS_TYPE_STRING, + &dsc->dbus_property)) + return FALSE; + + dbus_error_init(&error); + if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) { + if (dbus_error_is_set (&error)) { + wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " + "new value of property %s: (%s) %s", + __func__, dsc->dbus_property, + error.name, error.message); + } else { + wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " + "new value of property %s", + __func__, dsc->dbus_property); + } + dbus_error_free(&error); + return FALSE; + } + + if (!dbus_message_iter_close_container(dict_iter, &entry_iter)) + return FALSE; + } + + return TRUE; +} + + +static void do_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, DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &signal_iter); + + if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING, + &interface)) + goto err; + + /* Changed properties dict */ + if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, + "{sv}", &dict_iter)) + goto err; + + if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0)) + goto err; + + if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) + goto err; + + /* Invalidated properties array (empty) */ + if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, + "s", &dict_iter)) + goto err; + + 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 do_send_deprecated_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; + + if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1)) + goto err; + + 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 send_prop_changed_signal( + DBusConnection *con, const char *path, const char *interface, + const struct wpa_dbus_object_desc *obj_dsc) +{ + /* + * First, send property change notification on the standardized + * org.freedesktop.DBus.Properties interface. This call will not + * clear the property change bits, so that they are preserved for + * the call that follows. + */ + do_send_prop_changed_signal(con, path, interface, obj_dsc); + + /* + * Now send PropertiesChanged on our own interface for backwards + * compatibility. This is deprecated and will be removed in a future + * release. + */ + do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc); + + /* Property change bits have now been cleared. */ +} + + +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 + * @iter: DBus message iter at which to append property dictionary. + * + * 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. + */ +dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, + const char *path, + const char *interface, + DBusMessageIter *iter) +{ + struct wpa_dbus_object_desc *obj_desc = NULL; + DBusMessageIter dict_iter; + DBusError error; + + dbus_connection_get_object_path_data(iface->con, path, + (void **) &obj_desc); + if (!obj_desc) { + wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's " + "private data: %s", __func__, path); + return FALSE; + } + + if (!wpa_dbus_dict_open_write(iter, &dict_iter)) { + wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict", + __func__); + return FALSE; + } + + dbus_error_init(&error); + if (!fill_dict_with_properties(&dict_iter, obj_desc->properties, + interface, obj_desc->user_data, + &error)) { + wpa_printf(MSG_ERROR, "dbus: %s: failed to get object" + " properties: (%s) %s", __func__, + dbus_error_is_set(&error) ? error.name : "none", + dbus_error_is_set(&error) ? error.message : "none"); + dbus_error_free(&error); + return FALSE; + } + + return wpa_dbus_dict_close_write(iter, &dict_iter); +} + +/** + * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts + * @path: The dbus object path + * @p2p_persistent_group: indicates whether to parse the path as a P2P + * persistent group object + * @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_new_decompose_object_path(const char *path, + int p2p_persistent_group, + char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + os_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, p2p_persistent_group ? + WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" : + 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(p2p_persistent_group ? + WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART + "/" : + 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 (os_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_reply_new_from_error - Create a new D-Bus error message from a + * dbus error structure + * @message: The original request message for which the error is a reply + * @error: The error containing a name and a descriptive error cause + * @fallback_name: A generic error name if @error was not set + * @fallback_string: A generic error string if @error was not set + * Returns: A new D-Bus error message + * + * Given a DBusMessage structure, creates a new D-Bus error message using + * the error name and string contained in that structure. + */ +DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message, + DBusError *error, + const char *fallback_name, + const char *fallback_string) +{ + if (error && error->name && error->message) { + return dbus_message_new_error(message, error->name, + error->message); + } + if (fallback_name && fallback_string) { + return dbus_message_new_error(message, fallback_name, + fallback_string); + } + return NULL; +} diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h new file mode 100644 index 0000000..6d31ad5 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h @@ -0,0 +1,150 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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 dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter, + DBusError *error, + 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_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[4]; +}; + +/** + * 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[4]; +}; + +/** + * 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; +}; + + +#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); + +dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, + const char *path, + const char *interface, + DBusMessageIter *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); + +char *wpas_dbus_new_decompose_object_path(const char *path, + int p2p_persistent_group, + char **network, + char **bssid); + +DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message, + DBusError *error, + const char *fallback_name, + const char *fallback_string); + +#endif /* WPA_DBUS_CTRL_H */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c new file mode 100644 index 0000000..3b090c0 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c @@ -0,0 +1,279 @@ +/* + * 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 software may be distributed under the terms of the BSD license. + * See README 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%s\"/>", + dsc->dbus_property, dsc->type, + dsc->getter ? "read" : "", + dsc->setter ? "write" : ""); +} + + +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>"); + } else { + wpa_printf(MSG_DEBUG, "dbus: Not enough room for " + "add_interfaces inspect data: tailroom %u, " + "add %u", + (unsigned int) wpabuf_tailroom(xml), + (unsigned int) wpabuf_len(iface->xml)); + } + 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(10000); + 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/contrib/wpa/wpa_supplicant/dbus/dbus_old.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c new file mode 100644 index 0000000..5f298e7 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c @@ -0,0 +1,743 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README 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_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 */ + +void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct wpas_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *hash; + const char *cert_hex; + int cert_hex_len; + + /* 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, + "Certification"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_certification: " + "Could not create dbus signal; likely out of " + "memory"); + return; + } + + hash = cert_hash ? cert_hash : ""; + cert_hex = cert ? wpabuf_head(cert) : ""; + cert_hex_len = cert ? wpabuf_len(cert) : 0; + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_INT32,&depth, + DBUS_TYPE_STRING, &subject, + DBUS_TYPE_STRING, &hash, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &cert_hex, cert_hex_len, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_certification: " + "Not enough memory to construct signal"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); + +} + + +/** + * 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/contrib/wpa/wpa_supplicant/dbus/dbus_old.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h new file mode 100644 index 0000000..e668231 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h @@ -0,0 +1,137 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README 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); +void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert); + +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 void +wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ +} + +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/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c new file mode 100644 index 0000000..68e5515 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c @@ -0,0 +1,1462 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README 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, NULL)) + goto error; + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "driver") && + (entry.type == DBUS_TYPE_STRING)) { + 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, 0)) { + 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 = MANUAL_SCAN_REQ; + 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, NULL)) { + 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, NULL)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "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, NULL)) + 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/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h new file mode 100644 index 0000000..825bc6d --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h @@ -0,0 +1,101 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README 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/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c new file mode 100644 index 0000000..bb79382 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c @@ -0,0 +1,157 @@ +/* + * WPA Supplicant / dbus-based control interface (WPS) + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README 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/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in new file mode 100644 index 0000000..a75918f --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=fi.epitest.hostap.WPASupplicant +Exec=@BINDIR@/wpa_supplicant -u +User=root +SystemdService=wpa_supplicant.service diff --git a/contrib/wpa/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in b/contrib/wpa/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in new file mode 100644 index 0000000..d97ff39 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=fi.w1.wpa_supplicant1 +Exec=@BINDIR@/wpa_supplicant -u +User=root +SystemdService=wpa_supplicant.service |