D-Bus: Simplify message building error paths
[mech_eap.git] / wpa_supplicant / dbus / dbus_new_handlers.c
index cbe821a..e10b9fa 100644 (file)
 #include "../notify.h"
 #include "../bss.h"
 #include "../scan.h"
-#include "../ctrl_iface.h"
 #include "../autoscan.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
 #include "dbus_dict_helpers.h"
 #include "dbus_common_i.h"
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
+#include "drivers/driver.h"
 
 static const char *debug_strings[] = {
        "excessive", "msgdump", "debug", "info", "warning", "error", NULL
@@ -121,10 +117,27 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 }
 
 
+/**
+ * wpas_dbus_error_scan_error - Return a new ScanError error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @error: Optional string to be used as the error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return a scan error
+ */
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+                                               const char *error)
+{
+       return dbus_message_new_error(message,
+                                     WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+                                     error);
+}
+
+
 static const char *dont_quote[] = {
        "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
        "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-       "bssid", NULL
+       "bssid", "scan_freq", "freq_list", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
@@ -216,7 +229,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 
                                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);
@@ -230,7 +243,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 
                        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);
@@ -239,7 +252,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 
                        ret = os_snprintf(value, size, "%d",
                                          entry.int32_value);
-                       if (ret <= 0)
+                       if (os_snprintf_error(size, ret))
                                goto error;
                } else
                        goto error;
@@ -255,6 +268,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
                        wpa_config_update_prio_list(wpa_s->conf);
 
                os_free(value);
+               value = NULL;
                wpa_dbus_dict_entry_clear(&entry);
        }
 
@@ -294,21 +308,15 @@ dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
                                              wpa_dbus_type_as_string(type),
-                                             &variant_iter))
-               goto error;
-
-       if (!dbus_message_iter_append_basic(&variant_iter, type, val))
-               goto error;
-
-       if (!dbus_message_iter_close_container(iter, &variant_iter))
-               goto error;
+                                             &variant_iter) ||
+           !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: error constructing reply", __func__);
+               return FALSE;
+       }
 
        return TRUE;
-
-error:
-       dbus_set_error(error, DBUS_ERROR_FAILED,
-                      "%s: error constructing reply", __func__);
-       return FALSE;
 }
 
 
@@ -379,16 +387,11 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
        type_str[1] = sub_type_str[0];
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                             type_str, &variant_iter)) {
-               dbus_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to construct message 1", __func__);
-               return FALSE;
-       }
-
-       if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             type_str, &variant_iter) ||
+           !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
                                              sub_type_str, &array_iter)) {
                dbus_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to construct message 2", __func__);
+                              "%s: failed to construct message", __func__);
                return FALSE;
        }
 
@@ -423,22 +426,22 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
        }
 
        for (i = 0; i < array_len; i++) {
-               dbus_message_iter_append_basic(&array_iter, type,
-                                              array + i * element_size);
+               if (!dbus_message_iter_append_basic(&array_iter, type,
+                                                   array + i * element_size)) {
+                       dbus_set_error(error, DBUS_ERROR_FAILED,
+                                      "%s: failed to construct message 2.5",
+                                      __func__);
+                       return FALSE;
+               }
        }
 
-       if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
                dbus_set_error(error, DBUS_ERROR_FAILED,
                               "%s: failed to construct message 3", __func__);
                return FALSE;
        }
 
-       if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-               dbus_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to construct message 4", __func__);
-               return FALSE;
-       }
-
        return TRUE;
 }
 
@@ -478,34 +481,25 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
        inner_type_str[1] = sub_type_str[0];
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                             type_str, &variant_iter)) {
-               dbus_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to construct message 1", __func__);
-               return FALSE;
-       }
-       if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             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 2", __func__);
+                              "%s: failed to construct message", __func__);
                return FALSE;
        }
 
-       for (i = 0; i < array_len; i++) {
+       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_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to close message 2", __func__);
-               return FALSE;
-       }
-
-       if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+           !dbus_message_iter_close_container(iter, &variant_iter)) {
                dbus_set_error(error, DBUS_ERROR_FAILED,
-                              "%s: failed to close message 1", __func__);
+                              "%s: failed to close message", __func__);
                return FALSE;
        }
 
@@ -545,24 +539,28 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                        goto error;
                if (!os_strcmp(entry.key, "Driver") &&
                    (entry.type == DBUS_TYPE_STRING)) {
+                       os_free(driver);
                        driver = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (driver == NULL)
                                goto error;
                } else if (!os_strcmp(entry.key, "Ifname") &&
                           (entry.type == DBUS_TYPE_STRING)) {
+                       os_free(ifname);
                        ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (ifname == NULL)
                                goto error;
                } else if (!os_strcmp(entry.key, "ConfigFile") &&
                           (entry.type == DBUS_TYPE_STRING)) {
+                       os_free(confname);
                        confname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (confname == NULL)
                                goto error;
                } else if (!os_strcmp(entry.key, "BridgeIfname") &&
                           (entry.type == DBUS_TYPE_STRING)) {
+                       os_free(bridge_ifname);
                        bridge_ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (bridge_ifname == NULL)
@@ -871,7 +869,7 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
                num++;
 
-       paths = os_zalloc(num * sizeof(char*));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -924,6 +922,44 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
 }
 
 
+/**
+ * wpas_dbus_getter_global_capabilities - Request supported global capabilities
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property. Handles requests by dbus clients to
+ * return a list of strings with supported capabilities like AP, RSN IBSS,
+ * and P2P that are determined at compile time.
+ */
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data)
+{
+       const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+       size_t num_items = 0;
+
+#ifdef CONFIG_AP
+       capabilities[num_items++] = "ap";
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IBSS_RSN
+       capabilities[num_items++] = "ibss-rsn";
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+       capabilities[num_items++] = "p2p";
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+       capabilities[num_items++] = "interworking";
+#endif /* CONFIG_INTERWORKING */
+
+       return wpas_dbus_simple_array_property_getter(iter,
+                                                     DBUS_TYPE_STRING,
+                                                     capabilities,
+                                                     num_items, error);
+}
+
+
 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
                                   char **type, DBusMessage **reply)
 {
@@ -1159,8 +1195,9 @@ 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;
@@ -1180,8 +1217,7 @@ 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;
@@ -1199,6 +1235,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, "wpas_dbus_handler_scan[dbus]: "
+                          "Type must be a boolean");
+               *reply = wpas_dbus_error_invalid_args(
+                       message, "Wrong Type value type. Boolean required");
+               return -1;
+       }
+       dbus_message_iter_get_basic(var, allow);
+       return 0;
+}
+
+
 /**
  * wpas_dbus_handler_scan - Request a wireless scan on an interface
  * @message: Pointer to incoming dbus message
@@ -1217,6 +1270,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));
 
@@ -1247,6 +1301,12 @@ 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);
@@ -1273,9 +1333,12 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                "passive scan");
                        goto out;
                } else if (params.freqs && params.freqs[0]) {
-                       wpa_supplicant_trigger_scan(wpa_s, &params);
+                       if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+                               reply = wpas_dbus_error_scan_error(
+                                       message, "Scan request rejected");
+                       }
                } else {
-                       wpa_s->scan_req = 2;
+                       wpa_s->scan_req = MANUAL_SCAN_REQ;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                }
        } else if (!os_strcmp(type, "active")) {
@@ -1286,7 +1349,10 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 #ifdef CONFIG_AUTOSCAN
                autoscan_deinit(wpa_s);
 #endif /* CONFIG_AUTOSCAN */
-               wpa_supplicant_trigger_scan(wpa_s, &params);
+               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);
@@ -1295,6 +1361,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                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);
@@ -1304,6 +1373,73 @@ out:
 }
 
 
+/**
+ * wpas_dbus_handler_signal_poll - Request immediate signal properties
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "SignalPoll" method call of a network device. Requests
+ * that wpa_supplicant read signal properties like RSSI, noise, and link
+ * speed and return them.
+ */
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       struct wpa_signal_info si;
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter, iter_dict, variant_iter;
+       int ret;
+
+       ret = wpa_drv_signal_poll(wpa_s, &si);
+       if (ret) {
+               return dbus_message_new_error(message, DBUS_ERROR_FAILED,
+                                             "Failed to read signal");
+       }
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               goto nomem;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+                                       si.current_signal) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+                                       si.current_txrate / 1000) ||
+           !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+                                       si.current_noise) ||
+           !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+                                        si.frequency) ||
+           (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+            !wpa_dbus_dict_append_string(
+                    &iter_dict, "width",
+                    channel_width_to_string(si.chanwidth))) ||
+           (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+            (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+                                         si.center_frq1) ||
+             !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+                                         si.center_frq2))) ||
+           (si.avg_signal &&
+            !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+                                        si.avg_signal)) ||
+           !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(&iter, &variant_iter))
+               goto nomem;
+
+       return reply;
+
+nomem:
+       if (reply)
+               dbus_message_unref(reply);
+       reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+       return reply;
+}
+
+
 /*
  * wpas_dbus_handler_disconnect - Terminate the current connection
  * @message: Pointer to incoming dbus message
@@ -1405,10 +1541,10 @@ err:
 
 
 /**
- * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * wpas_dbus_handler_reassociate - Reassociate
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NotConnected DBus error message if not connected
+ * Returns: InterfaceDisabled DBus error message if disabled
  * or NULL otherwise.
  *
  * Handler function for "Reassociate" method call of network interface.
@@ -1416,13 +1552,31 @@ err:
 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s)
 {
-       if (wpa_s->current_ssid != NULL) {
-               wpa_s->normal_scans = 0;
-               wpa_supplicant_reinit_autoscan(wpa_s);
-               wpa_s->disconnected = 0;
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       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;
        }
 
@@ -1444,23 +1598,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, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1471,8 +1630,20 @@ 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]: "
@@ -1483,13 +1654,8 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
                goto out;
        }
 
-       if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-
 out:
        os_free(iface);
-       os_free(net_id);
        return reply;
 }
 
@@ -1509,7 +1675,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
        }
 
        if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
 }
 
 
@@ -1524,6 +1691,9 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
 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;
@@ -1543,7 +1713,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;
 
@@ -1552,14 +1722,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, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1575,7 +1749,6 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
 
 out:
        os_free(iface);
-       os_free(net_id);
        return reply;
 }
 
@@ -1594,7 +1767,7 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
 #ifdef IEEE8021X_EAPOL
        DBusMessage *reply = NULL;
        const char *op, *field, *value;
-       char *iface = NULL, *net_id = NULL;
+       char *iface, *net_id;
        int id;
        struct wpa_ssid *ssid;
 
@@ -1607,14 +1780,18 @@ DBusMessage * wpas_dbus_handler_network_reply(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, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       iface = wpas_dbus_new_decompose_object_path(op,
+                                                   WPAS_DBUS_NEW_NETWORKS_PART,
+                                                   &net_id);
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, net_id);
                goto out;
        }
@@ -1635,7 +1812,6 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
 
 out:
        os_free(iface);
-       os_free(net_id);
        return reply;
 #else /* IEEE8021X_EAPOL */
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
@@ -1644,6 +1820,8 @@ out:
 }
 
 
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
 /**
  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
  * @message: Pointer to incoming dbus message
@@ -1808,6 +1986,9 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
 
 }
 
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
 /*
  * wpas_dbus_handler_flush_bss - Flush the BSS cache
  * @message: Pointer to incoming dbus message
@@ -1881,6 +2062,259 @@ DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
 #endif /* CONFIG_AUTOSCAN */
 
 
+/*
+ * 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.");
+
+       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
@@ -1901,10 +2335,8 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
        const char *scans[] = { "active", "passive", "ssid" };
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                             "a{sv}", &variant_iter))
-               goto nomem;
-
-       if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
                goto nomem;
 
        res = wpa_drv_get_capa(wpa_s, &capa);
@@ -1914,34 +2346,32 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                const char *args[] = {"ccmp", "tkip", "none"};
                if (!wpa_dbus_dict_append_string_array(
                            &iter_dict, "Pairwise", args,
-                           sizeof(args) / sizeof(char*)))
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
                if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
                                                      &iter_dict_entry,
                                                      &iter_dict_val,
-                                                     &iter_array))
-                       goto nomem;
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "ccmp"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "tkip"))
-                               goto nomem;
-               }
-
-               if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "none"))
-                               goto nomem;
-               }
-
-               if (!wpa_dbus_dict_end_string_array(&iter_dict,
+                                                     &iter_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))
@@ -1955,40 +2385,35 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                };
                if (!wpa_dbus_dict_append_string_array(
                            &iter_dict, "Group", args,
-                           sizeof(args) / sizeof(char*)))
+                           ARRAY_SIZE(args)))
                        goto nomem;
        } else {
                if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
                                                      &iter_dict_entry,
                                                      &iter_dict_val,
-                                                     &iter_array))
-                       goto nomem;
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "ccmp"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "tkip"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wep104"))
-                               goto nomem;
-               }
-
-               if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "wep40"))
-                               goto nomem;
-               }
-
-               if (!wpa_dbus_dict_end_string_array(&iter_dict,
+                                                     &iter_array) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp-256")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "ccmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "gcmp")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "tkip")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "wep104")) ||
+                   ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+                    !wpa_dbus_dict_string_array_add_element(
+                            &iter_array, "wep40")) ||
+                   !wpa_dbus_dict_end_string_array(&iter_dict,
                                                    &iter_dict_entry,
                                                    &iter_dict_val,
                                                    &iter_array))
@@ -2006,34 +2431,28 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                };
                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(
@@ -2045,14 +2464,13 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                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(
@@ -2061,11 +2479,10 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
 #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
@@ -2086,30 +2503,22 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                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))
@@ -2121,7 +2530,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                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",
@@ -2130,25 +2539,16 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                                      &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))
@@ -2157,39 +2557,25 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
 
        /***** Scan */
        if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
-                                              sizeof(scans) / sizeof(char *)))
+                                              ARRAY_SIZE(scans)))
                goto nomem;
 
        /***** Modes */
        if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
                                              &iter_dict_entry,
                                              &iter_dict_val,
-                                             &iter_array))
-               goto nomem;
-
-       if (!wpa_dbus_dict_string_array_add_element(
-                           &iter_array, "infrastructure"))
-               goto nomem;
-
-       if (!wpa_dbus_dict_string_array_add_element(
-                           &iter_array, "ad-hoc"))
-               goto nomem;
-
-       if (res >= 0) {
-               if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "ap"))
-                               goto nomem;
-               }
-
-               if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
-                       if (!wpa_dbus_dict_string_array_add_element(
-                                   &iter_array, "p2p"))
-                               goto nomem;
-               }
-       }
-
-       if (!wpa_dbus_dict_end_string_array(&iter_dict,
+                                             &iter_array) ||
+           !wpa_dbus_dict_string_array_add_element(
+                   &iter_array, "infrastructure") ||
+           !wpa_dbus_dict_string_array_add_element(
+                   &iter_array, "ad-hoc") ||
+           (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+            !wpa_dbus_dict_string_array_add_element(
+                    &iter_array, "ap")) ||
+           (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+            !wpa_dbus_dict_string_array_add_element(
+                    &iter_array, "p2p")) ||
+           !wpa_dbus_dict_end_string_array(&iter_dict,
                                            &iter_dict_entry,
                                            &iter_dict_val,
                                            &iter_array))
@@ -2204,9 +2590,8 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                        goto nomem;
        }
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-               goto nomem;
-       if (!dbus_message_iter_close_container(iter, &variant_iter))
+       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
        return TRUE;
@@ -2787,7 +3172,7 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
        unsigned int i = 0;
        dbus_bool_t success = FALSE;
 
-       paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+       paths = os_calloc(wpa_s->num_bss, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -2838,19 +3223,11 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
        unsigned int i = 0, num = 0;
        dbus_bool_t success = FALSE;
 
-       if (wpa_s->conf == NULL) {
-               wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
-                          "networks list.", __func__);
-               dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
-                              "occurred getting the networks list", __func__);
-               return FALSE;
-       }
-
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
                if (!network_is_persistent_group(ssid))
                        num++;
 
-       paths = os_zalloc(num * sizeof(char *));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
                dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -2885,6 +3262,56 @@ out:
 
 
 /**
+ * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 engine path
+ *
+ * Getter for "PKCS11EnginePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *pkcs11_engine_path;
+
+       if (wpa_s->conf->pkcs11_engine_path == NULL)
+               pkcs11_engine_path = "";
+       else
+               pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &pkcs11_engine_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 module path
+ *
+ * Getter for "PKCS11ModulePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *pkcs11_module_path;
+
+       if (wpa_s->conf->pkcs11_module_path == NULL)
+               pkcs11_module_path = "";
+       else
+               pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &pkcs11_module_path, error);
+}
+
+
+/**
  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3058,11 +3485,22 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
        res = get_bss_helper(args, error, __func__);
        if (!res)
                return FALSE;
-
-       if (res->caps & IEEE80211_CAP_IBSS)
-               mode = "ad-hoc";
-       else
-               mode = "infrastructure";
+       if (bss_is_dmg(res)) {
+               switch (res->caps & IEEE80211_CAP_DMG_MASK) {
+               case IEEE80211_CAP_DMG_PBSS:
+               case IEEE80211_CAP_DMG_IBSS:
+                       mode = "ad-hoc";
+                       break;
+               case IEEE80211_CAP_DMG_AP:
+                       mode = "infrastructure";
+                       break;
+               }
+       } else {
+               if (res->caps & IEEE80211_CAP_IBSS)
+                       mode = "ad-hoc";
+               else
+                       mode = "infrastructure";
+       }
 
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
                                                &mode, error);
@@ -3182,8 +3620,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *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[8]; /* max 8 key managements may be supported */
        int n;
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3207,6 +3645,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
                key_mgmt[n++] = "wpa-ft-eap";
        if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
                key_mgmt[n++] = "wpa-eap-sha256";
+       if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+               key_mgmt[n++] = "wpa-eap-suite-b";
        if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
                key_mgmt[n++] = "wpa-none";
 
@@ -3225,9 +3665,18 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
        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;
@@ -3242,6 +3691,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
                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))
@@ -3265,9 +3720,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
                        goto nomem;
        }
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-               goto nomem;
-       if (!dbus_message_iter_close_container(iter, &variant_iter))
+       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
                goto nomem;
 
        return TRUE;
@@ -3301,12 +3755,10 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
 
        os_memset(&wpa_data, 0, sizeof(wpa_data));
        ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
-       if (ie) {
-               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-                       dbus_set_error_const(error, DBUS_ERROR_FAILED,
-                                            "failed to parse WPA IE");
-                       return FALSE;
-               }
+       if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "failed to parse WPA IE");
+               return FALSE;
        }
 
        return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3336,12 +3788,10 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
 
        os_memset(&wpa_data, 0, sizeof(wpa_data));
        ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
-       if (ie) {
-               if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-                       dbus_set_error_const(error, DBUS_ERROR_FAILED,
-                                            "failed to parse RSN IE");
-                       return FALSE;
-               }
+       if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "failed to parse RSN IE");
+               return FALSE;
        }
 
        return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3349,6 +3799,60 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+#ifdef CONFIG_WPS
+       struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+       DBusMessageIter iter_dict, variant_iter;
+       const char *type = "";
+
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter) ||
+           !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+               goto nomem;
+
+#ifdef CONFIG_WPS
+       wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+       if (wps_ie) {
+               if (wps_is_selected_pbc_registrar(wps_ie))
+                       type = "pbc";
+               else if (wps_is_selected_pin_registrar(wps_ie))
+                       type = "pin";
+
+               wpabuf_free(wps_ie);
+       }
+#endif /* CONFIG_WPS */
+
+       if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+           !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+           !dbus_message_iter_close_container(iter, &variant_iter))
+               goto nomem;
+
+       return TRUE;
+
+nomem:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
+}
+
+
+/**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3374,6 +3878,35 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for BSS age
+ */
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+       struct os_reltime now, diff = { 0, 0 };
+       u32 age;
+
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+
+       os_get_reltime(&now);
+       os_reltime_sub(&now, &res->last_update, &diff);
+       age = diff.sec > 0 ? diff.sec : 0;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
+                                               error);
+}
+
+
+/**
  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3611,28 +4144,22 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
 
        dbus_message_iter_init_append(msg, &iter);
 
-       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-               goto fail;
-       if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
-                                                    (const char *) addr,
-                                                    ETH_ALEN))
-               goto fail;
-       if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
-                                                   (const char *) dst,
-                                                   ETH_ALEN))
-               goto fail;
-       if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
-                                                     (const char *) bssid,
-                                                     ETH_ALEN))
-               goto fail;
-       if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
-                                                            (const char *) ie,
-                                                            ie_len))
-               goto fail;
-       if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
-                                                     ssi_signal))
-               goto fail;
-       if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+       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);