D-Bus: Set last_scan_req to MANUAL_SCAN_REQ on Scan() trigger paths
[mech_eap.git] / wpa_supplicant / dbus / dbus_new_handlers.c
index 166db5d..67562a5 100644 (file)
@@ -2,7 +2,7 @@
  * 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 software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -157,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;
@@ -213,7 +214,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
                } 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;
@@ -254,6 +255,19 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
                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) ||
                    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
@@ -537,28 +551,28 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                        driver = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (driver == NULL)
-                               goto error;
+                               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;
+                               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 error;
+                               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;
@@ -586,8 +600,8 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                iface.confname = confname;
                iface.bridge_ifname = bridge_ifname;
                /* Otherwise, have wpa_supplicant attach to it. */
-               wpa_s = wpa_supplicant_add_iface(global, &iface);
-               if (wpa_s) {
+               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);
@@ -610,6 +624,9 @@ out:
 error:
        reply = wpas_dbus_error_invalid_args(message, NULL);
        goto out;
+oom:
+       reply = wpas_dbus_error_no_memory(message);
+       goto out;
 }
 
 
@@ -668,7 +685,7 @@ 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;
@@ -860,8 +877,10 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
        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_calloc(num, sizeof(char *));
        if (!paths) {
@@ -869,8 +888,10 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
                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;
+       }
 
        success = wpas_dbus_simple_array_property_getter(iter,
                                                         DBUS_TYPE_OBJECT_PATH,
@@ -1018,10 +1039,10 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
 
                dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
 
-               if (len > MAX_SSID_LEN) {
+               if (len > SSID_MAX_LEN) {
                        wpa_printf(MSG_DEBUG,
                                   "%s[dbus]: SSID too long (len=%d max_len=%d)",
-                                  __func__, len, MAX_SSID_LEN);
+                                  __func__, len, SSID_MAX_LEN);
                        *reply = wpas_dbus_error_invalid_args(
                                message, "Invalid SSID: too long");
                        return -1;
@@ -1311,14 +1332,26 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                message,
                                "You can specify only Channels in passive scan");
                        goto out;
-               } else if (params.freqs && params.freqs[0]) {
-                       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);
+                       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") == 0) {
                if (!params.num_ssids) {
@@ -1328,6 +1361,14 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 #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");
@@ -1462,7 +1503,8 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
 
        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, "%s[dbus]: can't add new interface.",
                           __func__);
@@ -1561,6 +1603,30 @@ DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
 
 
 /**
+ * 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
@@ -1586,7 +1652,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        iface = wpas_dbus_new_decompose_object_path(op,
                                                    WPAS_DBUS_NEW_NETWORKS_PART,
                                                    &net_id);
-       if (iface == NULL || net_id == NULL ||
+       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;
@@ -1699,7 +1765,7 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
        iface = wpas_dbus_new_decompose_object_path(op,
                                                    WPAS_DBUS_NEW_NETWORKS_PART,
                                                    &net_id);
-       if (iface == NULL || net_id == NULL ||
+       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;
@@ -1757,7 +1823,7 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
        iface = wpas_dbus_new_decompose_object_path(op,
                                                    WPAS_DBUS_NEW_NETWORKS_PART,
                                                    &net_id);
-       if (iface == NULL || net_id == NULL ||
+       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;
@@ -2250,12 +2316,14 @@ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
                        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");
+       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;
 }
@@ -3008,7 +3076,7 @@ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
        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);
@@ -3036,7 +3104,7 @@ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
        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);
@@ -3124,6 +3192,12 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
        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_calloc(wpa_s->num_bss, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
@@ -3175,6 +3249,12 @@ 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->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)
                if (!network_is_persistent_group(ssid))
                        num++;
@@ -3574,7 +3654,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
        DBusMessageIter iter_dict, variant_iter;
        const char *group;
        const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
-       const char *key_mgmt[8]; /* max 8 key managements may be supported */
+       const char *key_mgmt[9]; /* max 9 key managements may be supported */
        int n;
 
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3598,8 +3678,14 @@ 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";
+#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";
 
@@ -3769,6 +3855,7 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
        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__);
@@ -3783,6 +3870,7 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
 #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))
@@ -3792,7 +3880,7 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
        }
 #endif /* CONFIG_WPS */
 
-       if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+       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;
@@ -4080,7 +4168,7 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
        struct wpas_dbus_priv *priv = wpa_s->global->dbus;
 
        /* Do nothing if the control interface is not turned on */
-       if (priv == NULL)
+       if (priv == NULL || !wpa_s->dbus_new_path)
                return;
 
        if (wpa_s->preq_notify_peer == NULL)