Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / wpa_supplicant / dbus / dbus_new_handlers.c
index 0ad51a0..67562a5 100644 (file)
@@ -2,16 +2,10 @@
  * 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>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "../wpa_supplicant_i.h"
 #include "../driver_i.h"
 #include "../notify.h"
-#include "../wpas_glue.h"
 #include "../bss.h"
 #include "../scan.h"
+#include "../autoscan.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
 #include "dbus_dict_helpers.h"
+#include "dbus_common_i.h"
+#include "drivers/driver.h"
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-static const char *debug_strings[] = {
-       "msgdump", "debug", "info", "warning", "error", NULL
+static const char * const debug_strings[] = {
+       "excessive", "msgdump", "debug", "info", "warning", "error", NULL
 };
 
 
 /**
- * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
-                                                 char **network,
-                                                 char **bssid)
-{
-       const unsigned int dev_path_prefix_len =
-               strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
-       char *obj_path_only;
-       char *next_sep;
-
-       /* Be a bit paranoid about path */
-       if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-                               dev_path_prefix_len))
-               return NULL;
-
-       /* Ensure there's something at the end of the path */
-       if ((path + dev_path_prefix_len)[0] == '\0')
-               return NULL;
-
-       obj_path_only = os_strdup(path);
-       if (obj_path_only == NULL)
-               return NULL;
-
-       next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-       if (next_sep != NULL) {
-               const char *net_part = os_strstr(
-                       next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
-               const char *bssid_part = os_strstr(
-                       next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
-               if (network && net_part) {
-                       /* Deal with a request for a configured network */
-                       const char *net_name = net_part +
-                               os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
-                       *network = NULL;
-                       if (os_strlen(net_name))
-                               *network = os_strdup(net_name);
-               } else if (bssid && bssid_part) {
-                       /* Deal with a request for a scanned BSSID */
-                       const char *bssid_name = bssid_part +
-                               os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-                       if (strlen(bssid_name))
-                               *bssid = os_strdup(bssid_name);
-                       else
-                               *bssid = NULL;
-               }
-
-               /* Cut off interface object path before "/" */
-               *next_sep = '\0';
-       }
-
-       return obj_path_only;
-}
-
-
-/**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * wpas_dbus_error_unknown_error - Return a new UnknownError error message
  * @message: Pointer to incoming dbus message this error refers to
  * @arg: Optional string appended to error message
  * Returns: a dbus error message
@@ -117,20 +45,6 @@ static char * wpas_dbus_new_decompose_object_path(const char *path,
 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);
 }
@@ -145,9 +59,9 @@ DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
  */
 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.");
+       return dbus_message_new_error(
+               message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+               "wpa_supplicant knows nothing about this interface.");
 }
 
 
@@ -160,9 +74,9 @@ static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
  */
 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.");
+       return dbus_message_new_error(
+               message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+               "There is no such a network in this interface.");
 }
 
 
@@ -178,9 +92,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 {
        DBusMessage *reply;
 
-       reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
-                                      "Did not receive correct message "
-                                      "arguments.");
+       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);
@@ -189,15 +103,40 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 }
 
 
-static const char *dont_quote[] = {
+/**
+ * wpas_dbus_error_scan_error - Return a new ScanError error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @error: Optional string to be used as the error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return a scan error
+ */
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+                                               const char *error)
+{
+       return dbus_message_new_error(message,
+                                     WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+                                     error);
+}
+
+
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
+{
+       wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
+       return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+
+static const char * const dont_quote[] = {
        "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
        "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-       "bssid", NULL
+       "bssid", "scan_freq", "freq_list", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
 {
        int i = 0;
+
        while (dont_quote[i] != NULL) {
                if (os_strcmp(key, dont_quote[i]) == 0)
                        return FALSE;
@@ -218,7 +157,8 @@ static struct wpa_supplicant * get_iface_by_dbus_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)
+               if (wpa_s->dbus_new_path &&
+                   os_strcmp(wpa_s->dbus_new_path, path) == 0)
                        return wpa_s;
        }
        return NULL;
@@ -227,36 +167,35 @@ static struct wpa_supplicant * get_iface_by_dbus_path(
 
 /**
  * set_network_properties - Set properties of a configured network
- * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ssid: wpa_ssid structure for a configured network
  * @iter: DBus message iterator containing dictionary of network
  * properties to set.
- * Returns: NULL when succeed or DBus error on failure
+ * @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
  */
-static DBusMessage * set_network_properties(DBusMessage *message,
-                                           struct wpa_supplicant *wpa_s,
-                                           struct wpa_ssid *ssid,
-                                           DBusMessageIter *iter)
+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 };
-       DBusMessage *reply = NULL;
        DBusMessageIter iter_dict;
+       char *value = NULL;
 
-       if (!wpa_dbus_dict_open_read(iter, &iter_dict))
-               return wpas_dbus_error_invalid_args(message, NULL);
+       if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+               return FALSE;
 
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-               char *value = NULL;
                size_t size = 50;
                int ret;
-               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-                       reply = wpas_dbus_error_invalid_args(message, NULL);
-                       break;
-               }
+
+               if (!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)
@@ -275,7 +214,7 @@ static DBusMessage * set_network_properties(DBusMessage *message,
                } else if (entry.type == DBUS_TYPE_STRING) {
                        if (should_quote_opt(entry.key)) {
                                size = os_strlen(entry.str_value);
-                               if (size <= 0)
+                               if (size == 0)
                                        goto error;
 
                                size += 3;
@@ -285,7 +224,7 @@ static DBusMessage * set_network_properties(DBusMessage *message,
 
                                ret = os_snprintf(value, size, "\"%s\"",
                                                  entry.str_value);
-                               if (ret < 0 || (size_t) ret != (size - 1))
+                               if (os_snprintf_error(size, ret))
                                        goto error;
                        } else {
                                value = os_strdup(entry.str_value);
@@ -299,7 +238,7 @@ static DBusMessage * set_network_properties(DBusMessage *message,
 
                        ret = os_snprintf(value, size, "%u",
                                          entry.uint32_value);
-                       if (ret <= 0)
+                       if (os_snprintf_error(size, ret))
                                goto error;
                } else if (entry.type == DBUS_TYPE_INT32) {
                        value = os_zalloc(size);
@@ -308,7 +247,7 @@ static DBusMessage * set_network_properties(DBusMessage *message,
 
                        ret = os_snprintf(value, size, "%d",
                                          entry.int32_value);
-                       if (ret <= 0)
+                       if (os_snprintf_error(size, ret))
                                goto error;
                } else
                        goto error;
@@ -316,80 +255,76 @@ static DBusMessage * set_network_properties(DBusMessage *message,
                if (wpa_config_set(ssid, entry.key, value, 0) < 0)
                        goto error;
 
+               if (os_strcmp(entry.key, "bssid") != 0 &&
+                   os_strcmp(entry.key, "priority") != 0)
+                       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+               if (wpa_s->current_ssid == ssid ||
+                   wpa_s->current_ssid == NULL) {
+                       /*
+                        * Invalidate the EAP session cache if anything in the
+                        * current or previously used configuration changes.
+                        */
+                       eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               }
+
                if ((os_strcmp(entry.key, "psk") == 0 &&
                     value[0] == '"' && ssid->ssid_len) ||
-                   (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+                   (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
                        wpa_config_update_psk(ssid);
                else if (os_strcmp(entry.key, "priority") == 0)
                        wpa_config_update_prio_list(wpa_s->conf);
 
                os_free(value);
+               value = NULL;
                wpa_dbus_dict_entry_clear(&entry);
-               continue;
-
-       error:
-               os_free(value);
-               reply = wpas_dbus_error_invalid_args(message, entry.key);
-               wpa_dbus_dict_entry_clear(&entry);
-               break;
        }
 
-       return reply;
+       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
- * @message: Pointer to incoming dbus message
+ * @iter: Message iter to use when appending arguments
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place holding property value
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @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.
  */
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-                                              const int type, const void *val)
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+                                            const int type,
+                                            const void *val,
+                                            DBusError *error)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter;
+       DBusMessageIter variant_iter;
 
        if (!dbus_type_is_basic(type)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-                          " given type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
        }
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-
-       if (reply != NULL) {
-               dbus_message_iter_init_append(reply, &iter);
-               if (!dbus_message_iter_open_container(
-                           &iter, DBUS_TYPE_VARIANT,
-                           wpa_dbus_type_as_string(type), &variant_iter) ||
-                   !dbus_message_iter_append_basic(&variant_iter, type,
-                                                   val) ||
-                   !dbus_message_iter_close_container(&iter, &variant_iter)) {
-                       wpa_printf(MSG_ERROR, "dbus: "
-                                  "wpas_dbus_simple_property_getter: out of "
-                                  "memory to put property value into "
-                                  "message");
-                       dbus_message_unref(reply);
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
-               }
-       } else {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-                          " out of memory to return property value");
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             wpa_dbus_type_as_string(type),
+                                             &variant_iter) ||
+           !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: error constructing reply", __func__);
+               return FALSE;
        }
 
-       return reply;
+       return TRUE;
 }
 
 
@@ -398,105 +333,77 @@ DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
  * @message: Pointer to incoming dbus message
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place where value being set will be stored
- * Returns: NULL or DBus error message if error occurred.
+ * Returns: TRUE if the request was successful, FALSE if it failed
  *
  * Generic setter for basic type properties. Type is required to be basic.
  */
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-                                              const int type, void *val)
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            const int type, void *val)
 {
-       DBusMessageIter iter, variant_iter;
+       DBusMessageIter variant_iter;
 
        if (!dbus_type_is_basic(type)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-                          " given type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
-       }
-
-       if (!dbus_message_iter_init(message, &iter)) {
-               wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-                          " out of memory to return scanning state");
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
        }
 
-       /* omit first and second argument and get value from third */
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &variant_iter);
-
+       /* Look at the new value */
+       dbus_message_iter_recurse(iter, &variant_iter);
        if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
-               wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:"
-                          " wrong property type");
-               return wpas_dbus_error_invalid_args(message,
-                                                   "wrong property type");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "wrong property type");
+               return FALSE;
        }
        dbus_message_iter_get_basic(&variant_iter, val);
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_simple_array_property_getter - Get array type property
- * @message: Pointer to incoming dbus message
+ * @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
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @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.
  */
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-                                                    const int type,
-                                                    const void *array,
-                                                    size_t array_len)
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+                                                  const int type,
+                                                  const void *array,
+                                                  size_t array_len,
+                                                  DBusError *error)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, array_iter;
+       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)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: given "
-                          "type is not basic");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               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 (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (reply == NULL) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to create return message");
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
-       }
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
                                              type_str, &variant_iter) ||
            !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
                                              sub_type_str, &array_iter)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to open container");
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message", __func__);
+               return FALSE;
        }
 
-       switch(type) {
+       switch (type) {
        case DBUS_TYPE_BYTE:
        case DBUS_TYPE_BOOLEAN:
                element_size = 1;
@@ -521,29 +428,90 @@ DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
                element_size = sizeof(char *);
                break;
        default:
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: "
-                          "fatal: unknown element type");
-               element_size = 1;
-               break;
+               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_append_basic(&array_iter, type,
+                                                   array + i * element_size)) {
+                       dbus_set_error(error, DBUS_ERROR_FAILED,
+                                      "%s: failed to construct message 2.5",
+                                      __func__);
+                       return FALSE;
+               }
        }
 
        if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
-           !dbus_message_iter_close_container(&iter, &variant_iter)) {
-               wpa_printf(MSG_ERROR, "dbus: "
-                          "wpas_dbus_simple_array_property_getter: out of "
-                          "memory to close container");
-               dbus_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 3", __func__);
+               return FALSE;
        }
 
-       return reply;
+       return TRUE;
+}
+
+
+/**
+ * wpas_dbus_simple_array_array_property_getter - Get array array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+                                                        const int type,
+                                                        struct wpabuf **array,
+                                                        size_t array_len,
+                                                        DBusError *error)
+{
+       DBusMessageIter variant_iter, array_iter;
+       char type_str[] = "aa?";
+       char inner_type_str[] = "a?";
+       const char *sub_type_str;
+       size_t i;
+
+       if (!dbus_type_is_basic(type)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
+       }
+
+       sub_type_str = wpa_dbus_type_as_string(type);
+       type_str[2] = sub_type_str[0];
+       inner_type_str[1] = sub_type_str[0];
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             type_str, &variant_iter) ||
+           !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             inner_type_str, &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message", __func__);
+               return FALSE;
+       }
+
+       for (i = 0; i < array_len && array[i]; i++) {
+               wpa_dbus_dict_bin_array_add_element(&array_iter,
+                                                   wpabuf_head(array[i]),
+                                                   wpabuf_len(array[i]));
+
+       }
+
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to close message", __func__);
+               return FALSE;
+       }
+
+       return TRUE;
 }
 
 
@@ -567,33 +535,44 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
        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))
+       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)) {
+               if (os_strcmp(entry.key, "Driver") == 0 &&
+                   entry.type == DBUS_TYPE_STRING) {
+                       os_free(driver);
                        driver = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (driver == NULL)
-                               goto error;
-               } else if (!strcmp(entry.key, "Ifname") &&
-                          (entry.type == DBUS_TYPE_STRING)) {
+                               goto oom;
+               } else if (os_strcmp(entry.key, "Ifname") == 0 &&
+                          entry.type == DBUS_TYPE_STRING) {
+                       os_free(ifname);
                        ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (ifname == NULL)
-                               goto error;
-               } else if (!strcmp(entry.key, "BridgeIfname") &&
-                          (entry.type == DBUS_TYPE_STRING)) {
+                               goto oom;
+               } else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
+                          entry.type == DBUS_TYPE_STRING) {
+                       os_free(confname);
+                       confname = os_strdup(entry.str_value);
+                       wpa_dbus_dict_entry_clear(&entry);
+                       if (confname == NULL)
+                               goto oom;
+               } else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
+                          entry.type == DBUS_TYPE_STRING) {
+                       os_free(bridge_ifname);
                        bridge_ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (bridge_ifname == NULL)
-                               goto error;
+                               goto oom;
                } else {
                        wpa_dbus_dict_entry_clear(&entry);
                        goto error;
@@ -608,39 +587,46 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
         * 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.");
+               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))) {
+               wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+               if (wpa_s && wpa_s->dbus_new_path) {
                        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);
+                                                &path, DBUS_TYPE_INVALID);
                } else {
                        reply = wpas_dbus_error_unknown_error(
-                               message, "wpa_supplicant couldn't grab this "
-                               "interface.");
+                               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;
+oom:
+       reply = wpas_dbus_error_no_memory(message);
+       goto out;
 }
 
 
@@ -668,10 +654,10 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
        wpa_s = get_iface_by_dbus_path(global, path);
        if (wpa_s == NULL)
                reply = wpas_dbus_error_iface_unknown(message);
-       else if (wpa_supplicant_remove_iface(global, wpa_s)) {
+       else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
                reply = wpas_dbus_error_unknown_error(
-                       message, "wpa_supplicant couldn't remove this "
-                       "interface.");
+                       message,
+                       "wpa_supplicant couldn't remove this interface.");
        }
 
        return reply;
@@ -699,19 +685,17 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
                              DBUS_TYPE_INVALID);
 
        wpa_s = wpa_supplicant_get_iface(global, ifname);
-       if (wpa_s == NULL)
+       if (wpa_s == NULL || wpa_s->dbus_new_path == 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);
+               return wpas_dbus_error_no_memory(message);
        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 wpas_dbus_error_no_memory(message);
        }
 
        return reply;
@@ -720,79 +704,86 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
 
 /**
  * wpas_dbus_getter_debug_level - Get debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug level
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global)
+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 > 4)
-               idx = 4;
+       if (idx > 5)
+               idx = 5;
        str = debug_strings[idx];
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &str);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &str, error);
 }
 
 
 /**
  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug timestamp
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &wpa_debug_timestamp);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &wpa_debug_timestamp, error);
 
 }
 
 
 /**
  * wpas_dbus_getter_debug_show_keys - Get debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug show_keys
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-                                               &wpa_debug_show_keys);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &wpa_debug_show_keys, error);
 
 }
 
 /**
  * wpas_dbus_setter_debug_level - Set debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @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.
  */
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-                                          struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        const char *str = NULL;
        int i, val = -1;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING,
-                                                &str);
-       if (reply)
-               return reply;
+       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) {
@@ -803,138 +794,184 @@ DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
        if (val < 0 ||
            wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
                                            wpa_debug_show_keys)) {
-               dbus_message_unref(reply);
-               return wpas_dbus_error_invalid_args(
-                       message, "Wrong debug level value");
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "wrong debug level value");
+               return FALSE;
        }
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @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.
  */
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        dbus_bool_t val;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &val);
-       if (reply)
-               return reply;
+       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 NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_show_keys - Set debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @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.
  */
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-                                              struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       struct wpa_global *global = user_data;
        dbus_bool_t val;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &val);
-       if (reply)
-               return reply;
+       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 NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_interfaces - Request registered interfaces list
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object paths array containing registered interfaces
- * objects paths or DBus error on failure
+ * @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
  */
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-                                         struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
+                                       DBusError *error,
+                                       void *user_data)
 {
-       DBusMessage *reply = NULL;
+       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++;
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s->dbus_new_path)
+                       num++;
+       }
 
-       paths = os_zalloc(num * sizeof(char*));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               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;
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s->dbus_new_path)
+                       paths[i++] = wpa_s->dbus_new_path;
+       }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, num);
+       success = wpas_dbus_simple_array_property_getter(iter,
+                                                        DBUS_TYPE_OBJECT_PATH,
+                                                        paths, num, error);
 
        os_free(paths);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
- * @message: Pointer to incoming dbus message
- * @nothing: not used argument. may be NULL or anything else
- * Returns: The object paths array containing supported EAP methods
- * represented by strings or DBus error on failure
+ * @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
  */
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing)
+dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       DBusMessage *reply = NULL;
        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) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_STRING,
-                                                      eap_methods, num_items);
+       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 reply;
+       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);
 }
 
 
@@ -942,8 +979,8 @@ 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");
+               wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
                        message, "Wrong Type value type. String required");
                return -1;
@@ -965,36 +1002,36 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
        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");
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: ssids must be an array of arrays of bytes",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
-                       message, "Wrong SSIDs value type. Array of arrays of "
-                       "bytes required");
+                       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");
+           dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: ssids must be an array of arrays of bytes",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
-                       message, "Wrong SSIDs value type. Array of arrays of "
-                       "bytes required");
+                       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)
-       {
+       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");
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: Too many ssids specified on scan dbus call",
+                                  __func__);
                        *reply = wpas_dbus_error_invalid_args(
-                               message, "Too many ssids specified. Specify "
-                               "at most four");
+                               message,
+                               "Too many ssids specified. Specify at most four");
                        return -1;
                }
 
@@ -1002,15 +1039,19 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
 
                dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
 
+               if (len > SSID_MAX_LEN) {
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: SSID too long (len=%d max_len=%d)",
+                                  __func__, len, SSID_MAX_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);
+                               *reply = wpas_dbus_error_no_memory(message);
                                return -1;
                        }
                        os_memcpy(ssid, val, len);
@@ -1042,28 +1083,28 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
        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");
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: ies must be an array of arrays of bytes",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
-                       message, "Wrong IEs value type. Array of arrays of "
-                       "bytes required");
+                       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");
+           dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: ies must be an array of arrays of bytes",
+                          __func__);
                *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)
-       {
+       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);
@@ -1074,12 +1115,8 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
 
                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);
+                       *reply = wpas_dbus_error_no_memory(message);
                        return -1;
                }
                ies = nies;
@@ -1105,11 +1142,12 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
        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");
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: Channels must be an array of structs",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
-                       message, "Wrong Channels value type. Array of structs "
-                       "required");
+                       message,
+                       "Wrong Channels value type. Array of structs required");
                return -1;
        }
 
@@ -1117,11 +1155,11 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
 
        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");
+                          "%s[dbus]: Channels must be an array of structs",
+                          __func__);
                *reply = wpas_dbus_error_invalid_args(
-                       message, "Wrong Channels value type. Array of structs "
-                       "required");
+                       message,
+                       "Wrong Channels value type. Array of structs required");
                return -1;
        }
 
@@ -1133,14 +1171,14 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
 
                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",
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
+                                  __func__,
                                   dbus_message_iter_get_arg_type(
                                           &sub_array_iter));
                        *reply = wpas_dbus_error_invalid_args(
-                               message, "Wrong Channel struct. Two UINT32s "
-                               "required");
+                               message,
+                               "Wrong Channel struct. Two UINT32s required");
                        os_free(freqs);
                        return -1;
                }
@@ -1149,9 +1187,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
                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");
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: Channel must by specified by struct of two UINT32s",
+                                  __func__);
                        *reply = wpas_dbus_error_invalid_args(
                                message,
                                "Wrong Channel struct. Two UINT32s required");
@@ -1163,18 +1201,15 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
 
 #define FREQS_ALLOC_CHUNK 32
                if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
-                       nfreqs = os_realloc(freqs, sizeof(int) *
-                                           (freqs_num + FREQS_ALLOC_CHUNK));
+                       nfreqs = os_realloc_array(
+                               freqs, freqs_num + FREQS_ALLOC_CHUNK,
+                               sizeof(int));
                        if (nfreqs == NULL)
                                os_free(freqs);
                        freqs = nfreqs;
                }
                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);
+                       *reply = wpas_dbus_error_no_memory(message);
                        return -1;
                }
 
@@ -1184,16 +1219,12 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
                dbus_message_iter_next(&array_iter);
        }
 
-       nfreqs = os_realloc(freqs,
-                           sizeof(int) * (freqs_num + 1));
+       nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
        if (nfreqs == NULL)
                os_free(freqs);
        freqs = nfreqs;
        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);
+               *reply = wpas_dbus_error_no_memory(message);
                return -1;
        }
        freqs[freqs_num] = 0;
@@ -1203,6 +1234,23 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
 }
 
 
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+                                        DBusMessageIter *var,
+                                        dbus_bool_t *allow,
+                                        DBusMessage **reply)
+{
+       if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+               wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
+                          __func__);
+               *reply = wpas_dbus_error_invalid_args(
+                       message, "Wrong Type value type. Boolean required");
+               return -1;
+       }
+       dbus_message_iter_get_basic(var, allow);
+       return 0;
+}
+
+
 /**
  * wpas_dbus_handler_scan - Request a wireless scan on an interface
  * @message: Pointer to incoming dbus message
@@ -1221,6 +1269,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
        char *key = NULL, *type = NULL;
        struct wpa_driver_scan_params params;
        size_t i;
+       dbus_bool_t allow_roam = 1;
 
        os_memset(&params, 0, sizeof(params));
 
@@ -1229,7 +1278,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
        dbus_message_iter_recurse(&iter, &dict_iter);
 
        while (dbus_message_iter_get_arg_type(&dict_iter) ==
-                       DBUS_TYPE_DICT_ENTRY) {
+              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);
@@ -1251,9 +1300,15 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                        if (wpas_dbus_get_scan_channels(message, &variant_iter,
                                                        &params, &reply) < 0)
                                goto out;
+               } else if (os_strcmp(key, "AllowRoam") == 0) {
+                       if (wpas_dbus_get_scan_allow_roam(message,
+                                                         &variant_iter,
+                                                         &allow_roam,
+                                                         &reply) < 0)
+                               goto out;
                } else {
-                       wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-                                  "Unknown argument %s", key);
+                       wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
+                                  __func__, key);
                        reply = wpas_dbus_error_invalid_args(message, key);
                        goto out;
                }
@@ -1262,40 +1317,73 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
        }
 
        if (!type) {
-               wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-                          "Scan type not specified");
+               wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
+                          __func__);
                reply = wpas_dbus_error_invalid_args(message, key);
                goto out;
        }
 
-       if (!os_strcmp(type, "passive")) {
+       if (os_strcmp(type, "passive") == 0) {
                if (params.num_ssids || params.extra_ies_len) {
-                       wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-                                  "SSIDs or IEs specified for passive scan.");
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: SSIDs or IEs specified for passive scan.",
+                                  __func__);
                        reply = wpas_dbus_error_invalid_args(
-                               message, "You can specify only Channels in "
-                               "passive scan");
+                               message,
+                               "You can specify only Channels in passive scan");
                        goto out;
-               } else if (params.freqs && params.freqs[0]) {
-                       wpa_supplicant_trigger_scan(wpa_s, &params);
                } else {
-                       wpa_s->scan_req = 2;
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       if (wpa_s->sched_scanning) {
+                               wpa_printf(MSG_DEBUG,
+                                          "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
+                                          __func__);
+                               wpa_supplicant_cancel_sched_scan(wpa_s);
+                       }
+
+                       if (params.freqs && params.freqs[0]) {
+                               wpa_s->last_scan_req = MANUAL_SCAN_REQ;
+                               if (wpa_supplicant_trigger_scan(wpa_s,
+                                                               &params)) {
+                                       reply = wpas_dbus_error_scan_error(
+                                               message,
+                                               "Scan request rejected");
+                               }
+                       } else {
+                               wpa_s->scan_req = MANUAL_SCAN_REQ;
+                               wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       }
                }
-       } else if (!os_strcmp(type, "active")) {
+       } else if (os_strcmp(type, "active") == 0) {
                if (!params.num_ssids) {
                        /* Add wildcard ssid */
                        params.num_ssids++;
                }
-               wpa_supplicant_trigger_scan(wpa_s, &params);
+#ifdef CONFIG_AUTOSCAN
+               autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
+               if (wpa_s->sched_scanning) {
+                       wpa_printf(MSG_DEBUG,
+                                  "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
+                                  __func__);
+                       wpa_supplicant_cancel_sched_scan(wpa_s);
+               }
+
+               wpa_s->last_scan_req = MANUAL_SCAN_REQ;
+               if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+                       reply = wpas_dbus_error_scan_error(
+                               message, "Scan request rejected");
+               }
        } else {
-               wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-                          "Unknown scan type: %s", type);
+               wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
+                          __func__, type);
                reply = wpas_dbus_error_invalid_args(message,
                                                     "Wrong scan type");
                goto out;
        }
 
+       if (!allow_roam)
+               wpa_s->scan_res_handler = scan_only_handler;
+
 out:
        for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
                os_free((u8 *) params.ssids[i].ssid);
@@ -1305,28 +1393,94 @@ out:
 }
 
 
-/*
- * wpas_dbus_handler_disconnect - Terminate the current connection
+/**
+ * wpas_dbus_handler_signal_poll - Request immediate signal properties
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NotConnected DBus error message if already not connected
- * or NULL otherwise.
+ * Returns: NULL indicating success or DBus error message on failure
  *
- * Handler function for "Disconnect" method call of network interface.
+ * Handler function for "SignalPoll" method call of a network device. Requests
+ * that wpa_supplicant read signal properties like RSSI, noise, and link
+ * speed and return them.
  */
-DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s)
+DBusMessage * wpas_dbus_handler_signal_poll(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);
+       struct wpa_signal_info si;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter, iter_dict, variant_iter;
+       int ret;
 
-               return NULL;
+       ret = wpa_drv_signal_poll(wpa_s, &si);
+       if (ret) {
+               return dbus_message_new_error(message, DBUS_ERROR_FAILED,
+                                             "Failed to read signal");
        }
 
-       return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
-                                     "This interface is not connected");
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               goto nomem;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+                                       si.current_signal) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+                                       si.current_txrate / 1000) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+                                       si.current_noise) ||
+           !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+                                        si.frequency) ||
+           (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+            !wpa_dbus_dict_append_string(
+                    &iter_dict, "width",
+                    channel_width_to_string(si.chanwidth))) ||
+           (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+            (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+                                         si.center_frq1) ||
+             !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+                                         si.center_frq2))) ||
+           (si.avg_signal &&
+            !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+                                        si.avg_signal)) ||
+           !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(&iter, &variant_iter))
+               goto nomem;
+
+       return reply;
+
+nomem:
+       if (reply)
+               dbus_message_unref(reply);
+       return wpas_dbus_error_no_memory(message);
+}
+
+
+/*
+ * 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");
 }
 
 
@@ -1345,28 +1499,33 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
        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 (wpa_s->dbus_new_path)
+               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.");
+               wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+                          __func__);
                reply = wpas_dbus_error_unknown_error(
                        message,
-                       "wpa_supplicant could not add "
-                       "a network on this interface.");
+                       "wpa_supplicant could not add a network on this interface.");
                goto err;
        }
        wpas_notify_network_added(wpa_s, ssid);
        ssid->disabled = 1;
        wpa_config_set_network_defaults(ssid);
 
-       reply = set_network_properties(message, wpa_s, ssid, &iter);
-       if (reply) {
-               wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
-                          "control interface couldn't set network "
-                          "properties");
+       dbus_error_init(&error);
+       if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: control interface couldn't set network properties",
+                          __func__);
+               reply = wpas_dbus_reply_new_from_error(message, &error,
+                                                      DBUS_ERROR_INVALID_ARGS,
+                                                      "Failed to add network");
+               dbus_error_free(&error);
                goto err;
        }
 
@@ -1377,15 +1536,13 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
 
        reply = dbus_message_new_method_return(message);
        if (reply == NULL) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+               reply = wpas_dbus_error_no_memory(message);
                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);
+               reply = wpas_dbus_error_no_memory(message);
                goto err;
        }
 
@@ -1401,6 +1558,75 @@ err:
 
 
 /**
+ * wpas_dbus_handler_reassociate - Reassociate
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: InterfaceDisabled DBus error message if disabled
+ * or NULL otherwise.
+ *
+ * Handler function for "Reassociate" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
+               wpas_request_connection(wpa_s);
+               return NULL;
+       }
+
+       return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
+                                     "This interface is disabled");
+}
+
+
+/**
+ * wpas_dbus_handler_reattach - Reattach to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reattach" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->current_ssid != NULL) {
+               wpa_s->reattach = 1;
+               wpas_request_connection(wpa_s);
+               return NULL;
+       }
+
+       return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+                                     "This interface is not connected");
+}
+
+
+/**
+ * wpas_dbus_handler_reconnect - Reconnect if disconnected
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: InterfaceDisabled DBus error message if disabled
+ * or NULL otherwise.
+ *
+ * Handler function for "Reconnect" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
+               struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+               return dbus_message_new_error(message,
+                                             WPAS_DBUS_ERROR_IFACE_DISABLED,
+                                             "This interface is disabled");
+       }
+
+       if (wpa_s->disconnected)
+               wpas_request_connection(wpa_s);
+       return NULL;
+}
+
+
+/**
  * wpas_dbus_handler_remove_network - Remove a configured network
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
@@ -1413,23 +1639,28 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
 {
        DBusMessage *reply = NULL;
        const char *op;
-       char *iface = NULL, *net_id = NULL;
+       char *iface, *net_id;
        int id;
        struct wpa_ssid *ssid;
+       int was_disabled;
 
        dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
                              DBUS_TYPE_INVALID);
 
        /* Extract the network ID and ensure the network */
        /* is actually a child of this interface */
-       iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1440,26 +1671,72 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
                goto out;
        }
 
+       was_disabled = ssid->disabled;
+
        wpas_notify_network_removed(wpa_s, ssid);
 
+       if (ssid == wpa_s->current_ssid)
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       else if (!was_disabled && wpa_s->sched_scanning) {
+               wpa_printf(MSG_DEBUG,
+                          "Stop ongoing sched_scan to remove network from filters");
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
+
        if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
                wpa_printf(MSG_ERROR,
-                          "wpas_dbus_handler_remove_network[dbus]: "
-                          "error occurred when removing network %d", id);
+                          "%s[dbus]: error occurred when removing network %d",
+                          __func__, id);
                reply = wpas_dbus_error_unknown_error(
-                       message, "error removing the specified network on "
-                       "this interface.");
+                       message,
+                       "error removing the specified network on is interface.");
                goto out;
        }
 
+out:
+       os_free(iface);
+       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,
+                          "%s[dbus]: error occurred when removing network %d",
+                          __func__, ssid->id);
+               return;
+       }
+
        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;
+
+/**
+ * wpas_dbus_handler_remove_all_networks - Remove all configured networks
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllNetworks" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_networks(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->sched_scanning)
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+
+       /* NB: could check for failure and return an error */
+       wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+       return NULL;
 }
 
 
@@ -1476,7 +1753,7 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
 {
        DBusMessage *reply = NULL;
        const char *op;
-       char *iface = NULL, *net_id = NULL;
+       char *iface, *net_id;
        int id;
        struct wpa_ssid *ssid;
 
@@ -1485,14 +1762,18 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
 
        /* Extract the network ID and ensure the network */
        /* is actually a child of this interface */
-       iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1508,12 +1789,80 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
 
 out:
        os_free(iface);
-       os_free(net_id);
        return reply;
 }
 
 
 /**
+ * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "NetworkReply" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+       DBusMessage *reply = NULL;
+       const char *op, *field, *value;
+       char *iface, *net_id;
+       int id;
+       struct wpa_ssid *ssid;
+
+       if (!dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_OBJECT_PATH, &op,
+                                  DBUS_TYPE_STRING, &field,
+                                  DBUS_TYPE_STRING, &value,
+                                  DBUS_TYPE_INVALID))
+               return wpas_dbus_error_invalid_args(message, NULL);
+
+       /* Extract the network ID and ensure the network */
+       /* is actually a child of this interface */
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       errno = 0;
+       id = strtoul(net_id, NULL, 10);
+       if (errno != 0) {
+               reply = wpas_dbus_error_invalid_args(message, net_id);
+               goto out;
+       }
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL) {
+               reply = wpas_dbus_error_network_unknown(message);
+               goto out;
+       }
+
+       if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
+                                                     field, value) < 0)
+               reply = wpas_dbus_error_invalid_args(message, field);
+       else {
+               /* Tell EAP to retry immediately */
+               eapol_sm_notify_ctrl_response(wpa_s->eapol);
+       }
+
+out:
+       os_free(iface);
+       return reply;
+#else /* IEEE8021X_EAPOL */
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+       return wpas_dbus_error_unknown_error(message, "802.1X not included");
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
+/**
  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
  * @message: Pointer to incoming dbus message
  * @wpa_s: %wpa_supplicant data structure
@@ -1548,26 +1897,18 @@ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
 
        blob = os_zalloc(sizeof(*blob));
        if (!blob) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+               reply = wpas_dbus_error_no_memory(message);
                goto err;
        }
 
        blob->data = os_malloc(blob_len);
-       if (!blob->data) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+       blob->name = os_strdup(blob_name);
+       if (!blob->data || !blob->name) {
+               reply = wpas_dbus_error_no_memory(message);
                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);
@@ -1612,39 +1953,21 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
        }
 
        reply = dbus_message_new_method_return(message);
-       if (!reply) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
-               goto out;
-       }
+       if (!reply)
+               return wpas_dbus_error_no_memory(message);
 
        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)) {
+                                             &array_iter) ||
+           !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+                                                 &(blob->data), blob->len) ||
+           !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;
+               reply = wpas_dbus_error_no_memory(message);
        }
 
-out:
        return reply;
 }
 
@@ -1677,125 +2000,436 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
 
 }
 
+#endif /* CONFIG_NO_CONFIG_BLOBS */
 
-/**
- * wpas_dbus_getter_capabilities - Return interface capabilities
+
+/*
+ * 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: A dbus message containing a dict of strings
+ * Returns: NULL
  *
- * Getter for "Capabilities" property of an interface.
+ * Handler function for "FlushBSS" method call of network interface.
  */
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-                                           struct wpa_supplicant *wpa_s)
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
 {
-       DBusMessage *reply = NULL;
-       struct wpa_driver_capa capa;
-       int res;
-       DBusMessageIter iter, iter_dict;
-       DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
-               variant_iter;
-       const char *scans[] = { "active", "passive", "ssid" };
-       const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
-       int n = sizeof(modes) / sizeof(char *);
+       dbus_uint32_t age;
+
+       dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
+                             DBUS_TYPE_INVALID);
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+       if (age == 0)
+               wpa_bss_flush(wpa_s);
        else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               goto nomem;
+               wpa_bss_flush_by_age(wpa_s, age);
 
-       dbus_message_iter_init_append(reply, &iter);
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                                             "a{sv}", &variant_iter))
-               goto nomem;
+       return NULL;
+}
 
-       if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
-               goto nomem;
 
-       res = wpa_drv_get_capa(wpa_s, &capa);
+#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;
 
-       /***** 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;
+       dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+                             DBUS_TYPE_INVALID);
 
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "ccmp"))
-                               goto nomem;
-               }
+       if (arg != NULL && os_strlen(arg) > 0) {
+               char *tmp;
 
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "tkip"))
-                               goto nomem;
+               tmp = os_strdup(arg);
+               if (tmp == NULL) {
+                       reply = wpas_dbus_error_no_memory(message);
+               } 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);
 
-               if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "none"))
-                               goto nomem;
-               }
+       return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
 
-               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"
-               };
+/*
+ * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogoff" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s)
+{
+       eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+       return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogin" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
+{
+       eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+       return NULL;
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
+                                 u8 *peer_address, DBusMessage **error)
+{
+       const char *peer_string;
+
+       *error = NULL;
+
+       if (!dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_STRING, &peer_string,
+                                  DBUS_TYPE_INVALID)) {
+               *error = wpas_dbus_error_invalid_args(message, NULL);
+               return -1;
+       }
+
+       if (hwaddr_aton(peer_string, peer_address)) {
+               wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
+                          func_name, peer_string);
+               *error = wpas_dbus_error_invalid_args(
+                       message, "Invalid hardware address format");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_discover - Discover TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSDiscover" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+       u8 peer[ETH_ALEN];
+       DBusMessage *error_reply;
+       int ret;
+
+       if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
+               return error_reply;
+
+       wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
+
+       if (wpa_tdls_is_external_setup(wpa_s->wpa))
+               ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+       else
+               ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+       if (ret) {
+               return wpas_dbus_error_unknown_error(
+                       message, "error performing TDLS discovery");
+       }
+
+       return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_setup - Setup TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSSetup" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s)
+{
+       u8 peer[ETH_ALEN];
+       DBusMessage *error_reply;
+       int ret;
+
+       if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
+               return error_reply;
+
+       wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
+
+       wpa_tdls_remove(wpa_s->wpa, peer);
+       if (wpa_tdls_is_external_setup(wpa_s->wpa))
+               ret = wpa_tdls_start(wpa_s->wpa, peer);
+       else
+               ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+       if (ret) {
+               return wpas_dbus_error_unknown_error(
+                       message, "error performing TDLS setup");
+       }
+
+       return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_status - Return TDLS session status
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A string representing the state of the link to this TDLS peer
+ *
+ * Handler function for "TDLSStatus" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       u8 peer[ETH_ALEN];
+       DBusMessage *reply;
+       const char *tdls_status;
+
+       if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
+               return reply;
+
+       wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
+
+       tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+
+       reply = dbus_message_new_method_return(message);
+       dbus_message_append_args(reply, DBUS_TYPE_STRING,
+                                &tdls_status, DBUS_TYPE_INVALID);
+       return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSTeardown" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s)
+{
+       u8 peer[ETH_ALEN];
+       DBusMessage *error_reply;
+       int ret;
+
+       if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
+               return error_reply;
+
+       wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
+
+       if (wpa_tdls_is_external_setup(wpa_s->wpa))
+               ret = wpa_tdls_teardown_link(
+                       wpa_s->wpa, peer,
+                       WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+       else
+               ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+       if (ret) {
+               return wpas_dbus_error_unknown_error(
+                       message, "error performing TDLS teardown");
+       }
+
+       return NULL;
+}
+
+#endif /* CONFIG_TDLS */
+
+
+/**
+ * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing an error on failure or NULL on success
+ *
+ * Sets the PKCS #11 engine and module path.
+ */
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       DBusMessageIter iter;
+       char *value = NULL;
+       char *pkcs11_engine_path = NULL;
+       char *pkcs11_module_path = NULL;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &value);
+       if (value == NULL) {
+               return dbus_message_new_error(
+                       message, DBUS_ERROR_INVALID_ARGS,
+                       "Invalid pkcs11_engine_path argument");
+       }
+       /* Empty path defaults to NULL */
+       if (os_strlen(value))
+               pkcs11_engine_path = value;
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_get_basic(&iter, &value);
+       if (value == NULL) {
+               os_free(pkcs11_engine_path);
+               return dbus_message_new_error(
+                       message, DBUS_ERROR_INVALID_ARGS,
+                       "Invalid pkcs11_module_path argument");
+       }
+       /* Empty path defaults to NULL */
+       if (os_strlen(value))
+               pkcs11_module_path = value;
+
+       if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
+                                                  pkcs11_module_path))
+               return dbus_message_new_error(
+                       message, DBUS_ERROR_FAILED,
+                       "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
+
+       if (wpa_s->dbus_new_path) {
+               wpa_dbus_mark_property_changed(
+                       wpa_s->global->dbus, wpa_s->dbus_new_path,
+                       WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
+               wpa_dbus_mark_property_changed(
+                       wpa_s->global->dbus, wpa_s->dbus_new_path,
+                       WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
+       }
+
+       return NULL;
+}
+
+
+/**
+ * wpas_dbus_getter_capabilities - Return interface capabilities
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property of an interface.
+ */
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+                                         DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       struct wpa_driver_capa capa;
+       int res;
+       DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
+               variant_iter;
+       const char *scans[] = { "active", "passive", "ssid" };
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+               goto nomem;
+
+       res = wpa_drv_get_capa(wpa_s, &capa);
+
+       /***** pairwise cipher */
+       if (res < 0) {
+               const char *args[] = {"ccmp", "tkip", "none"};
+
                if (!wpa_dbus_dict_append_string_array(
-                           &iter_dict, "Group", args,
-                           sizeof(args) / sizeof(char*)))
+                           &iter_dict, "Pairwise", args,
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
-               if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
+               if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
                                                      &iter_dict_entry,
                                                      &iter_dict_val,
-                                                     &iter_array))
+                                                     &iter_array) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "tkip")) ||
+                   ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "none")) ||
+                   !wpa_dbus_dict_end_string_array(&iter_dict,
+                                                   &iter_dict_entry,
+                                                   &iter_dict_val,
+                                                   &iter_array))
                        goto nomem;
+       }
 
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "ccmp"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "tkip"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wep104"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wep40"))
-                               goto nomem;
-               }
+       /***** group cipher */
+       if (res < 0) {
+               const char *args[] = {
+                       "ccmp", "tkip", "wep104", "wep40"
+               };
 
-               if (!wpa_dbus_dict_end_string_array(&iter_dict,
+               if (!wpa_dbus_dict_append_string_array(
+                           &iter_dict, "Group", args,
+                           ARRAY_SIZE(args)))
+                       goto nomem;
+       } else {
+               if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
+                                                     &iter_dict_entry,
+                                                     &iter_dict_val,
+                                                     &iter_array) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "tkip")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "wep104")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "wep40")) ||
+                   !wpa_dbus_dict_end_string_array(&iter_dict,
                                                    &iter_dict_entry,
                                                    &iter_dict_val,
                                                    &iter_array))
@@ -1813,34 +2447,28 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
                };
                if (!wpa_dbus_dict_append_string_array(
                            &iter_dict, "KeyMgmt", args,
-                           sizeof(args) / sizeof(char*)))
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
                if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
                                                      &iter_dict_entry,
                                                      &iter_dict_val,
-                                                     &iter_array))
-                       goto nomem;
-
-               if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-                                                           "none"))
-                       goto nomem;
-
-               if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+                                                     &iter_array) ||
+                   !wpa_dbus_dict_string_array_add_element(&iter_array,
+                                                           "none") ||
+                   !wpa_dbus_dict_string_array_add_element(&iter_array,
                                                            "ieee8021x"))
                        goto nomem;
 
                if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
                                     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
                        if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wpa-eap"))
+                                   &iter_array, "wpa-eap") ||
+                           ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+                            !wpa_dbus_dict_string_array_add_element(
+                                    &iter_array, "wpa-ft-eap")))
                                goto nomem;
 
-                       if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
-                               if (!wpa_dbus_dict_string_array_add_element(
-                                           &iter_array, "wpa-ft-eap"))
-                                       goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
                        if (!wpa_dbus_dict_string_array_add_element(
@@ -1852,14 +2480,13 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
                if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
                                     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
                        if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wpa-psk"))
+                                   &iter_array, "wpa-psk") ||
+                           ((capa.key_mgmt &
+                             WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+                            !wpa_dbus_dict_string_array_add_element(
+                                    &iter_array, "wpa-ft-psk")))
                                goto nomem;
 
-                       if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
-                               if (!wpa_dbus_dict_string_array_add_element(
-                                           &iter_array, "wpa-ft-psk"))
-                                       goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
                        if (!wpa_dbus_dict_string_array_add_element(
@@ -1868,11 +2495,10 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
 #endif /* CONFIG_IEEE80211W */
                }
 
-               if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wpa-none"))
-                               goto nomem;
-               }
+               if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+                   !wpa_dbus_dict_string_array_add_element(&iter_array,
+                                                           "wpa-none"))
+                       goto nomem;
 
 
 #ifdef CONFIG_WPS
@@ -1891,32 +2517,25 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
        /***** 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*)))
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
                if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
                                                      &iter_dict_entry,
                                                      &iter_dict_val,
-                                                     &iter_array))
-                       goto nomem;
-
-               if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-                                    WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "rsn"))
-                               goto nomem;
-               }
-
-               if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-                                    WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wpa"))
-                               goto nomem;
-               }
-
-               if (!wpa_dbus_dict_end_string_array(&iter_dict,
+                                                     &iter_array) ||
+                   ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "rsn")) ||
+                   ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "wpa")) ||
+                   !wpa_dbus_dict_end_string_array(&iter_dict,
                                                    &iter_dict_entry,
                                                    &iter_dict_val,
                                                    &iter_array))
@@ -1926,9 +2545,10 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
        /***** 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*)))
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
                if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -1937,25 +2557,16 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
                                                      &iter_array))
                        goto nomem;
 
-               if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "open"))
-                               goto nomem;
-               }
-
-               if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "shared"))
-                               goto nomem;
-               }
-
-               if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "leap"))
-                               goto nomem;
-               }
-
-               if (!wpa_dbus_dict_end_string_array(&iter_dict,
+               if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "open")) ||
+                   ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "shared")) ||
+                   ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "leap")) ||
+                   !wpa_dbus_dict_end_string_array(&iter_dict,
                                                    &iter_dict_entry,
                                                    &iter_dict_val,
                                                    &iter_array))
@@ -1964,45 +2575,67 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
 
        /***** Scan */
        if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
-                                              sizeof(scans) / sizeof(char *)))
+                                              ARRAY_SIZE(scans)))
                goto nomem;
 
        /***** Modes */
-       if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
-               n--; /* exclude ap mode if it is not supported by the driver */
-       if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
+       if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
+                                             &iter_dict_entry,
+                                             &iter_dict_val,
+                                             &iter_array) ||
+           !wpa_dbus_dict_string_array_add_element(
+                   &iter_array, "infrastructure") ||
+           !wpa_dbus_dict_string_array_add_element(
+                   &iter_array, "ad-hoc") ||
+           (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+            !wpa_dbus_dict_string_array_add_element(
+                    &iter_array, "ap")) ||
+           (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+            !wpa_dbus_dict_string_array_add_element(
+                    &iter_array, "p2p")) ||
+           !wpa_dbus_dict_end_string_array(&iter_dict,
+                                           &iter_dict_entry,
+                                           &iter_dict_val,
+                                           &iter_array))
                goto nomem;
+       /***** Modes end */
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-               goto nomem;
-       if (!dbus_message_iter_close_container(&iter, &variant_iter))
+       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) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
-       return reply;
+       return TRUE;
 
 nomem:
-       if (reply)
-               dbus_message_unref(reply);
-
-       return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- *          interface state
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-                                    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+                                  void *user_data)
 {
-       DBusMessage *reply = NULL;
+       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);
 
@@ -2010,244 +2643,573 @@ DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
         */
        state_ls = tmp = os_strdup(str_state);
        if (!tmp) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
        while (*tmp) {
                *tmp = tolower(*tmp);
                tmp++;
        }
 
-       reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                                &state_ls);
+       success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                                  &state_ls, error);
 
        os_free(state_ls);
 
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s)
+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(message, DBUS_TYPE_BOOLEAN,
-                                               &scanning);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &scanning, error);
 }
 
 
 /**
  * wpas_dbus_getter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containong value of ap_scan variable
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s)
+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(message, DBUS_TYPE_UINT32,
-                                               &ap_scan);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+                                               &ap_scan, error);
 }
 
 
 /**
  * wpas_dbus_setter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @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 "ApScan" property.
+ * Setter function for "ScanInterval" property.
  */
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-                                      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data)
 {
-       DBusMessage *reply = NULL;
-       dbus_uint32_t ap_scan;
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_int32_t scan_interval;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-                                                &ap_scan);
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
+                                             &scan_interval))
+               return FALSE;
 
-       if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
-               return wpas_dbus_error_invalid_args(
-                       message, "ap_scan must equal 0, 1 or 2");
+       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 NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * associated with with wpa_s
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s)
+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(message, DBUS_TYPE_STRING,
-                                               &ifname);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &ifname, error);
 }
 
 
 /**
  * wpas_dbus_getter_driver - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * driver associated with with wpa_s
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-                                     struct wpa_supplicant *wpa_s)
+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");
-               return wpas_dbus_error_unknown_error(message, NULL);
+               wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
+                          __func__);
+               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(message, DBUS_TYPE_STRING,
-                                               &driver);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &driver, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_bss - Get current bss object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current BSS
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
+                                        DBusError *error,
+                                        void *user_data)
 {
-       DBusMessage *reply;
+       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)
+       if (wpa_s->current_bss && wpa_s->dbus_new_path)
                os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
                            "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
                            wpa_s->dbus_new_path, wpa_s->current_bss->id);
        else
                os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-       reply = wpas_dbus_simple_property_getter(message,
-                                                DBUS_TYPE_OBJECT_PATH,
-                                                &bss_obj_path);
-
-       return reply;
+       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
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current network
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-                                              struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
-       DBusMessage *reply;
+       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)
+       if (wpa_s->current_ssid && wpa_s->dbus_new_path)
                os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
                            "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
                            wpa_s->dbus_new_path, wpa_s->current_ssid->id);
        else
                os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-       reply = wpas_dbus_simple_property_getter(message,
-                                                DBUS_TYPE_OBJECT_PATH,
-                                                &net_obj_path);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+                                               &net_obj_path, error);
+}
+
 
-       return reply;
+/**
+ * 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
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of bridge network
- * interface associated with with wpa_s
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-                                            struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data)
 {
-       const char *bridge_ifname = NULL;
-
-       bridge_ifname = wpa_s->bridge_ifname;
-       if (bridge_ifname == NULL) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: "
-                          "wpa_s has no bridge interface name set");
-               return wpas_dbus_error_unknown_error(message, NULL);
-       }
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *bridge_ifname = wpa_s->bridge_ifname;
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &bridge_ifname);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &bridge_ifname, error);
 }
 
 
 /**
  * wpas_dbus_getter_bsss - Get array of BSSs objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all known BSS objects
- * dbus paths
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-                                   struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+                                 void *user_data)
 {
-       DBusMessage *reply = NULL;
+       struct wpa_supplicant *wpa_s = user_data;
        struct wpa_bss *bss;
        char **paths;
        unsigned int i = 0;
+       dbus_bool_t success = FALSE;
+
+       if (!wpa_s->dbus_new_path) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: no D-Bus interface", __func__);
+               return FALSE;
+       }
 
-       paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+       paths = os_calloc(wpa_s->num_bss, sizeof(char *));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               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) {
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
                        goto out;
                }
                /* Construct the object path for this BSS. */
@@ -2256,57 +3218,61 @@ DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
                            wpa_s->dbus_new_path, bss->id);
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, wpa_s->num_bss);
+       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 reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_getter_networks - Get array of networks objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all configured
- * networks dbus object paths.
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-                                       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       DBusMessage *reply = NULL;
+       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, "wpas_dbus_getter_networks[dbus]: "
-                          "An error occurred getting networks list.");
-               return wpas_dbus_error_unknown_error(message, NULL);
+       if (!wpa_s->dbus_new_path) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: no D-Bus interface", __func__);
+               return FALSE;
        }
 
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-               num++;
+               if (!network_is_persistent_group(ssid))
+                       num++;
 
-       paths = os_zalloc(num * sizeof(char *));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               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) {
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
+                                      "no memory");
                        goto out;
                }
 
@@ -2316,50 +3282,90 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
                            wpa_s->dbus_new_path, ssid->id);
        }
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_OBJECT_PATH,
-                                                      paths, num);
+       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 reply;
+       return success;
 }
 
 
 /**
- * wpas_dbus_getter_blobs - Get all blobs defined for this interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dictionary of pairs (blob_name, blob)
+ * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 engine path
  *
- * Getter for "Blobs" property.
+ * Getter for "PKCS11EnginePath" property.
  */
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-                                    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter;
-       struct wpa_config_blob *blob;
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *pkcs11_engine_path;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+       if (wpa_s->conf->pkcs11_engine_path == NULL)
+               pkcs11_engine_path = "";
        else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &pkcs11_engine_path, error);
+}
 
-       dbus_message_iter_init_append(reply, &iter);
 
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+/**
+ * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 module path
+ *
+ * Getter for "PKCS11ModulePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *pkcs11_module_path;
+
+       if (wpa_s->conf->pkcs11_module_path == NULL)
+               pkcs11_module_path = "";
+       else
+               pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &pkcs11_module_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_blobs - Get all blobs defined for this interface
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @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_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
        blob = wpa_s->conf->blobs;
@@ -2382,176 +3388,207 @@ DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
                                                       &array_iter) ||
                    !dbus_message_iter_close_container(&dict_iter,
                                                       &entry_iter)) {
-                       dbus_message_unref(reply);
-                       return dbus_message_new_error(message,
-                                                     DBUS_ERROR_NO_MEMORY,
-                                                     NULL);
+                       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_message_unref(reply);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       return reply;
+       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
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the bssid for the requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-                                        struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res->bssid, ETH_ALEN);
+       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
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the ssid for the requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-                                             struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res->ssid,
-                                                     res->ssid_len);
+       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
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the privacy flag value of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-                                          struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+                                        DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        dbus_bool_t privacy;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       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(message, DBUS_TYPE_BOOLEAN,
-                                               &privacy);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &privacy, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the mode of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-                                       struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+                                     void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        const char *mode;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+       if (bss_is_dmg(res)) {
+               switch (res->caps & IEEE80211_CAP_DMG_MASK) {
+               case IEEE80211_CAP_DMG_PBSS:
+               case IEEE80211_CAP_DMG_IBSS:
+                       mode = "ad-hoc";
+                       break;
+               case IEEE80211_CAP_DMG_AP:
+                       mode = "infrastructure";
+                       break;
+               }
+       } else {
+               if (res->caps & IEEE80211_CAP_IBSS)
+                       mode = "ad-hoc";
+               else
+                       mode = "infrastructure";
        }
 
-       if (res->caps & IEEE80211_CAP_IBSS)
-               mode = "ad-hoc";
-       else
-               mode = "infrastructure";
-
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-                                               &mode);
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &mode, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the signal strength of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-                                         struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+                                       DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+       s16 level;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16,
-                                               &res->level);
+       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
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the frequency of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-                                            struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+                                          DBusError *error, void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+       u16 freq;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: "
-                          "no bss with id %d found", bss->id);
-               return NULL;
-       }
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
 
-       return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16,
-                                               &res->freq);
+       freq = (u16) res->freq;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+                                               &freq, error);
 }
 
 
@@ -2563,72 +3600,64 @@ static int cmp_u8s_desc(const void *a, const void *b)
 
 /**
  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing sorted array of bit rates
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-                                           struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+                                      DBusError *error, void *user_data)
 {
-       DBusMessage *reply;
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       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;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: "
-                          "no bss with id %d found", bss->id);
-               return NULL;
-       }
+       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 NULL;
+               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);
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+               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;
 
-       reply = wpas_dbus_simple_array_property_getter(message,
-                                                      DBUS_TYPE_UINT32,
-                                                      real_rates, rates_num);
+       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 reply;
+       return success;
 }
 
 
-static DBusMessage * wpas_dbus_get_bss_security_prop(
-       DBusMessage *message, struct wpa_ie_data *ie_data)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
+                                                  struct wpa_ie_data *ie_data,
+                                                  DBusError *error)
 {
-       DBusMessage *reply;
-       DBusMessageIter iter, iter_dict, variant_iter;
+       DBusMessageIter iter_dict, variant_iter;
        const char *group;
-       const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
-       const char *key_mgmt[7]; /* max 7 key managements may be supported */
+       const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
+       const char *key_mgmt[9]; /* max 9 key managements may be supported */
        int n;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply)
-               goto nomem;
-
-       dbus_message_iter_init_append(reply, &iter);
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
                                              "a{sv}", &variant_iter))
                goto nomem;
 
@@ -2649,6 +3678,14 @@ static DBusMessage * wpas_dbus_get_bss_security_prop(
                key_mgmt[n++] = "wpa-ft-eap";
        if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
                key_mgmt[n++] = "wpa-eap-sha256";
+#ifdef CONFIG_SUITEB
+       if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+               key_mgmt[n++] = "wpa-eap-suite-b";
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+       if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+               key_mgmt[n++] = "wpa-eap-suite-b-192";
+#endif /* CONFIG_SUITEB192 */
        if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
                key_mgmt[n++] = "wpa-none";
 
@@ -2667,9 +3704,18 @@ static DBusMessage * wpas_dbus_get_bss_security_prop(
        case WPA_CIPHER_CCMP:
                group = "ccmp";
                break;
+       case WPA_CIPHER_GCMP:
+               group = "gcmp";
+               break;
        case WPA_CIPHER_WEP104:
                group = "wep104";
                break;
+       case WPA_CIPHER_CCMP_256:
+               group = "ccmp-256";
+               break;
+       case WPA_CIPHER_GCMP_256:
+               group = "gcmp-256";
+               break;
        default:
                group = "";
                break;
@@ -2684,6 +3730,12 @@ static DBusMessage * wpas_dbus_get_bss_security_prop(
                pairwise[n++] = "tkip";
        if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
                pairwise[n++] = "ccmp";
+       if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
+               pairwise[n++] = "gcmp";
+       if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
+               pairwise[n++] = "ccmp-256";
+       if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
+               pairwise[n++] = "gcmp-256";
 
        if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
                                               pairwise, n))
@@ -2707,154 +3759,234 @@ static DBusMessage * wpas_dbus_get_bss_security_prop(
                        goto nomem;
        }
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-               goto nomem;
-       if (!dbus_message_iter_close_container(&iter, &variant_iter))
+       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
-       return reply;
+       return TRUE;
 
 nomem:
-       if (reply)
-               dbus_message_unref(reply);
-
-       return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+       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
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the WPA options of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        struct wpa_ie_data wpa_data;
        const u8 *ie;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       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)
-                       return wpas_dbus_error_unknown_error(message,
-                                                            "invalid WPA IE");
+       if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "failed to parse WPA IE");
+               return FALSE;
        }
 
-       return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+       return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the RSN options of requested bss
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
        struct wpa_ie_data wpa_data;
        const u8 *ie;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       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)
-                       return wpas_dbus_error_unknown_error(message,
-                                                            "invalid RSN IE");
+       if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "failed to parse RSN IE");
+               return FALSE;
        }
 
-       return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+       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;
+       int wps_support = 0;
+       const char *type = "";
+
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+               goto nomem;
+
+#ifdef CONFIG_WPS
+       wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+       if (wps_ie) {
+               wps_support = 1;
+               if (wps_is_selected_pbc_registrar(wps_ie))
+                       type = "pbc";
+               else if (wps_is_selected_pin_registrar(wps_ie))
+                       type = "pin";
+
+               wpabuf_free(wps_ie);
+       }
+#endif /* CONFIG_WPS */
+
+       if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
+           !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
+               goto nomem;
+
+       return TRUE;
+
+nomem:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing IEs byte array
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-                                      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
 
-       if (!res) {
-               wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no "
-                          "bss with id %d found", bss->id);
-               return NULL;
-       }
+       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);
+}
 
-       return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-                                                     res + 1, res->ie_len);
+
+/**
+ * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for BSS age
+ */
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+       struct os_reltime now, diff = { 0, 0 };
+       u32 age;
+
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+
+       os_get_reltime(&now);
+       os_reltime_sub(&now, &res->last_update, &diff);
+       age = diff.sec > 0 ? diff.sec : 0;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
+                                               error);
 }
 
 
 /**
  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: DBus message with boolean indicating state of configured network
- * or DBus error on failure
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net)
+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(message, DBUS_TYPE_BOOLEAN,
-                                               &enabled);
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+                                               &enabled, error);
 }
 
 
 /**
  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @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.
  */
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-                                      struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
 {
-       DBusMessage *reply = NULL;
-
+       struct network_handler_args *net = user_data;
        struct wpa_supplicant *wpa_s;
        struct wpa_ssid *ssid;
-
        dbus_bool_t enable;
 
-       reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-                                                &enable);
-
-       if (reply)
-               return reply;
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+                                             &enable))
+               return FALSE;
 
        wpa_s = net->wpa_s;
        ssid = net->ssid;
@@ -2864,48 +3996,38 @@ DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
        else
                wpa_supplicant_disable_network(wpa_s, ssid);
 
-       return NULL;
+       return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_network_properties - Get options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: DBus message with network properties or DBus error on failure
+ * @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.
  */
-DBusMessage * wpas_dbus_getter_network_properties(
-       DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter, dict_iter;
+       struct network_handler_args *net = user_data;
+       DBusMessageIter variant_iter, dict_iter;
        char **iterator;
-       char **props = wpa_config_get_all(net->ssid, 0);
-       if (!props)
-               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                             NULL);
+       char **props = wpa_config_get_all(net->ssid, 1);
+       dbus_bool_t success = FALSE;
 
-       if (message == NULL)
-               reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-       else
-               reply = dbus_message_new_method_return(message);
-       if (!reply) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
-               goto out;
+       if (!props) {
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+               return FALSE;
        }
 
-       dbus_message_iter_init_append(reply, &iter);
-
-       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                       "a{sv}", &variant_iter) ||
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
+                                             &variant_iter) ||
            !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
-               dbus_message_unref(reply);
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                goto out;
        }
 
@@ -2913,10 +4035,8 @@ DBusMessage * wpas_dbus_getter_network_properties(
        while (*iterator) {
                if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
                                                 *(iterator + 1))) {
-                       dbus_message_unref(reply);
-                       reply = dbus_message_new_error(message,
-                                                      DBUS_ERROR_NO_MEMORY,
-                                                      NULL);
+                       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+                                            "no memory");
                        goto out;
                }
                iterator += 2;
@@ -2924,13 +4044,13 @@ DBusMessage * wpas_dbus_getter_network_properties(
 
 
        if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-           !dbus_message_iter_close_container(&iter, &variant_iter)) {
-               dbus_message_unref(reply);
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
+           !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) {
@@ -2938,39 +4058,156 @@ out:
                iterator++;
        }
        os_free(props);
-       return reply;
+       return success;
 }
 
 
 /**
  * wpas_dbus_setter_network_properties - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @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.
  */
-DBusMessage * wpas_dbus_setter_network_properties(
-       DBusMessage *message, struct network_handler_args *net)
+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;
 
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter, variant_iter;
+       dbus_message_iter_recurse(iter, &variant_iter);
+       return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
+}
 
-       dbus_message_iter_init(message, &iter);
 
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_next(&iter);
+#ifdef CONFIG_AP
 
-       dbus_message_iter_recurse(&iter, &variant_iter);
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+       char *name;
 
-       reply = set_network_properties(message, net->wpa_s, ssid,
-                                      &variant_iter);
-       if (reply)
-               wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
-                          "network properties");
+       if (wpa_s->preq_notify_peer != NULL) {
+               if (os_strcmp(dbus_message_get_sender(message),
+                             wpa_s->preq_notify_peer) == 0)
+                       return NULL;
 
-       return reply;
+               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 wpas_dbus_error_no_memory(message);
+
+       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 || !wpa_s->dbus_new_path)
+               return;
+
+       if (wpa_s->preq_notify_peer == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "ProbeRequest");
+       if (msg == NULL)
+               return;
+
+       dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+           (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+                                                     (const char *) addr,
+                                                     ETH_ALEN)) ||
+           (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+                                                    (const char *) dst,
+                                                    ETH_ALEN)) ||
+           (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+                                                      (const char *) bssid,
+                                                      ETH_ALEN)) ||
+           (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+                                                             (const char *) ie,
+                                                             ie_len)) ||
+           (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+                                                      ssi_signal)) ||
+           !wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto fail;
+
+       dbus_connection_send(priv->con, msg, NULL);
+       goto out;
+fail:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+       dbus_message_unref(msg);
 }
+
+#endif /* CONFIG_AP */