TDLS: Declare tdls_testing as extern in a header file
[mech_eap.git] / wpa_supplicant / wps_supplicant.c
index 22083bd..74a420c 100644 (file)
 #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
 #endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
 
+/*
+ * The minimum time in seconds before trying to associate to a WPS PIN AP that
+ * does not have Selected Registrar TRUE.
+ */
+#ifndef WPS_PIN_TIME_IGNORE_SEL_REG
+#define WPS_PIN_TIME_IGNORE_SEL_REG 5
+#endif /* WPS_PIN_TIME_IGNORE_SEL_REG */
+
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
 
@@ -113,6 +121,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
                           "try to associate with the received credential "
                           "(freq=%u)", freq);
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                if (disabled) {
@@ -160,6 +169,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
                           "for external credential processing");
                wpas_clear_wps(wpa_s);
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                return 1;
@@ -537,6 +547,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
                        return -1;
                }
        }
+       ssid->priority = wpa_s->conf->wps_priority;
 
        wpas_wps_security_workaround(wpa_s, ssid, cred);
 
@@ -550,6 +561,9 @@ static int wpa_supplicant_wps_cred(void *ctx,
        }
 #endif /* CONFIG_NO_CONFIG_WRITE */
 
+       if (ssid->priority)
+               wpa_config_update_prio_list(wpa_s->conf);
+
        /*
         * Optimize the post-WPS scan based on the channel used during
         * the provisioning in case EAP-Failure is not received.
@@ -569,8 +583,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
                m2d->dev_password_id, m2d->config_error);
        wpas_notify_wps_event_m2d(wpa_s, m2d);
 #ifdef CONFIG_P2P
-       if (wpa_s->parent && wpa_s->parent != wpa_s) {
-               wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+       if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
+               wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
                        "dev_password_id=%d config_error=%d",
                        m2d->dev_password_id, m2d->config_error);
        }
@@ -603,8 +617,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
                        WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
                        fail->msg, fail->config_error, fail->error_indication,
                        wps_ei_str(fail->error_indication));
-               if (wpa_s->parent && wpa_s->parent != wpa_s)
-                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+               if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+                       wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
                                "msg=%d config_error=%d reason=%d (%s)",
                                fail->msg, fail->config_error,
                                fail->error_indication,
@@ -613,8 +627,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO,
                        WPS_EVENT_FAIL "msg=%d config_error=%d",
                        fail->msg, fail->config_error);
-               if (wpa_s->parent && wpa_s->parent != wpa_s)
-                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+               if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+                       wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
                                "msg=%d config_error=%d",
                                fail->msg, fail->config_error);
        }
@@ -669,6 +683,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+       return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
+                                          wpa_s, NULL);
+}
+
+
 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
 {
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
@@ -878,7 +899,8 @@ static int wpa_supplicant_wps_rf_band(void *ctx)
        if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
                return 0;
 
-       return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
+       return (wpa_s->assoc_freq > 50000) ? WPS_RF_60GHZ :
+               (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
 }
 
 
@@ -913,6 +935,7 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
        while (ssid) {
                if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
                        if (ssid == wpa_s->current_ssid) {
+                               wpa_s->own_disconnect_req = 1;
                                wpa_supplicant_deauthenticate(
                                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                        }
@@ -939,8 +962,20 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
+       union wps_event_data data;
+
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
                "out");
+       os_memset(&data, 0, sizeof(data));
+       data.fail.config_error = WPS_CFG_MSG_TIMEOUT;
+       data.fail.error_indication = WPS_EI_NO_ERROR;
+       /*
+        * Call wpas_notify_wps_event_fail() directly instead of through
+        * wpa_supplicant_wps_event() which would end up registering unnecessary
+        * timeouts (those are only for the case where the failure happens
+        * during an EAP-WSC exchange).
+        */
+       wpas_notify_wps_event_fail(wpa_s, &data.fail);
        wpas_clear_wps(wpa_s);
 }
 
@@ -1022,9 +1057,11 @@ static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ssid *ssid;
 
-       if (wpa_s->current_ssid)
+       if (wpa_s->current_ssid) {
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       }
 
        /* Mark all other networks disabled and trigger reassociation */
        ssid = wpa_s->conf->ssid;
@@ -1091,12 +1128,27 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       int p2p_group)
 {
        struct wpa_ssid *ssid;
+
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+               return -1;
+       }
+#endif /* CONFIG_AP */
        wpas_clear_wps(wpa_s);
        ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
        if (ssid == NULL)
                return -1;
        ssid->temporary = 1;
        ssid->p2p_group = p2p_group;
+       /*
+        * When starting a regular WPS process (not P2P group formation)
+        * the registrar/final station can be either AP or PCP
+        * so use a "don't care" value for the pbss flag.
+        */
+       if (!p2p_group)
+               ssid->pbss = 2;
 #ifdef CONFIG_P2P
        if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
                ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1104,6 +1156,10 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                        ssid->ssid_len = wpa_s->go_params->ssid_len;
                        os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
                                  ssid->ssid_len);
+                       if (wpa_s->go_params->freq > 56160) {
+                               /* P2P in 60 GHz uses PBSS */
+                               ssid->pbss = 1;
+                       }
                        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
                                          "SSID", ssid->ssid, ssid->ssid_len);
                }
@@ -1131,6 +1187,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
        unsigned int rpin = 0;
        char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
 
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+               return -1;
+       }
+#endif /* CONFIG_AP */
        wpas_clear_wps(wpa_s);
        if (bssid && is_zero_ether_addr(bssid))
                bssid = NULL;
@@ -1141,6 +1204,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
        }
        ssid->temporary = 1;
        ssid->p2p_group = p2p_group;
+       /*
+        * When starting a regular WPS process (not P2P group formation)
+        * the registrar/final station can be either AP or PCP
+        * so use a "don't care" value for the pbss flag.
+        */
+       if (!p2p_group)
+               ssid->pbss = 2;
        if (ssid_val) {
                ssid->ssid = os_malloc(ssid_len);
                if (ssid->ssid) {
@@ -1158,11 +1228,16 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
        }
 #ifdef CONFIG_P2P
        if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+               os_free(ssid->ssid);
                ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
                if (ssid->ssid) {
                        ssid->ssid_len = wpa_s->go_params->ssid_len;
                        os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
                                  ssid->ssid_len);
+                       if (wpa_s->go_params->freq > 56160) {
+                               /* P2P in 60 GHz uses PBSS */
+                               ssid->pbss = 1;
+                       }
                        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
                                          "SSID", ssid->ssid, ssid->ssid_len);
                }
@@ -1175,7 +1250,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
                os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
                            dev_pw_id, hash);
        } else {
-               rpin = wps_generate_pin();
+               if (wps_generate_pin(&rpin) < 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
+                       return -1;
+               }
                os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
                            rpin, dev_pw_id, hash);
        }
@@ -1196,11 +1274,28 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       const char *pin, int p2p_group, u16 dev_pw_id)
 {
+       os_get_reltime(&wpa_s->wps_pin_start_time);
        return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
                                     dev_pw_id, NULL, NULL, 0, 0);
 }
 
 
+void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+       union wps_event_data data;
+
+       os_memset(&data, 0, sizeof(data));
+       data.fail.config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+       data.fail.error_indication = WPS_EI_NO_ERROR;
+       /*
+        * Call wpas_notify_wps_event_fail() directly instead of through
+        * wpa_supplicant_wps_event() which would end up registering unnecessary
+        * timeouts (those are only for the case where the failure happens
+        * during an EAP-WSC exchange).
+        */
+       wpas_notify_wps_event_fail(wpa_s, &data.fail);
+}
+
 /* Cancel the wps pbc/pin requests */
 int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
 {
@@ -1219,6 +1314,7 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
        } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
                wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
                           "deauthenticate");
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                wpas_clear_wps(wpa_s);
@@ -1244,6 +1340,13 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
        char *pos, *end;
        int res;
 
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+               return -1;
+       }
+#endif /* CONFIG_AP */
        if (!pin)
                return -1;
        wpas_clear_wps(wpa_s);
@@ -1459,6 +1562,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
                                wps->dev.rf_bands |= WPS_RF_24GHZ;
                        else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
                                wps->dev.rf_bands |= WPS_RF_50GHZ;
+                       else if (modes[m].mode == HOSTAPD_MODE_IEEE80211AD)
+                               wps->dev.rf_bands |= WPS_RF_60GHZ;
                }
        }
        if (wps->dev.rf_bands == 0) {
@@ -1581,9 +1686,15 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                 * external Registrar.
                 */
                if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
-                       if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
-                               wpa_printf(MSG_DEBUG, "   skip - WPS AP "
-                                          "without active PIN Registrar");
+                       struct os_reltime age;
+
+                       os_reltime_age(&wpa_s->wps_pin_start_time, &age);
+
+                       if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG ||
+                           age.sec < WPS_PIN_TIME_IGNORE_SEL_REG) {
+                               wpa_printf(MSG_DEBUG,
+                                          "   skip - WPS AP without active PIN Registrar (scan_runs=%d age=%d)",
+                                          wpa_s->scan_runs, (int) age.sec);
                                wpabuf_free(wps_ie);
                                return 0;
                        }
@@ -1666,10 +1777,10 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
 int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
                              struct wpa_bss *selected, struct wpa_ssid *ssid)
 {
-       const u8 *sel_uuid, *uuid;
+       const u8 *sel_uuid;
        struct wpabuf *wps_ie;
        int ret = 0;
-       struct wpa_bss *bss;
+       size_t i;
 
        if (!eap_is_wps_pbc_enrollee(&ssid->eap))
                return 0;
@@ -1690,40 +1801,28 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
                sel_uuid = NULL;
        }
 
-       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-               struct wpabuf *ie;
-               if (bss == selected)
-                       continue;
-               ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-               if (!ie)
-                       continue;
-               if (!wps_is_selected_pbc_registrar(ie)) {
-                       wpabuf_free(ie);
+       for (i = 0; i < wpa_s->num_wps_ap; i++) {
+               struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+
+               if (!ap->pbc_active ||
+                   os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
                        continue;
-               }
+
                wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
-                          MACSTR, MAC2STR(bss->bssid));
-               uuid = wps_get_uuid_e(ie);
+                          MACSTR, MAC2STR(ap->bssid));
                wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
-                           uuid, UUID_LEN);
-               if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
-                       wpabuf_free(ie);
-                       continue;
-               }
-               if (sel_uuid == NULL || uuid == NULL ||
-                   os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
+                           ap->uuid, UUID_LEN);
+               if (sel_uuid == NULL ||
+                   os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
                        ret = 1; /* PBC overlap */
                        wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
                                MACSTR " and " MACSTR,
                                MAC2STR(selected->bssid),
-                               MAC2STR(bss->bssid));
-                       wpabuf_free(ie);
+                               MAC2STR(ap->bssid));
                        break;
                }
 
                /* TODO: verify that this is reasonable dual-band situation */
-
-               wpabuf_free(ie);
        }
 
        wpabuf_free(wps_ie);
@@ -1882,7 +1981,7 @@ static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
                                    struct wps_credential *cred)
 {
        os_memset(cred, 0, sizeof(*cred));
-       if (ssid->ssid_len > 32)
+       if (ssid->ssid_len > SSID_MAX_LEN)
                return -1;
        os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
        cred->ssid_len = ssid->ssid_len;
@@ -2554,6 +2653,10 @@ static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
                         (attr.rf_bands == NULL ||
                          *attr.rf_bands & WPS_RF_50GHZ))
                        freq = 5000 + 5 * chan;
+               else if (chan >= 1 && chan <= 4 &&
+                        (attr.rf_bands == NULL ||
+                         *attr.rf_bands & WPS_RF_60GHZ))
+                       freq = 56160 + 2160 * chan;
 
                if (freq) {
                        wpa_printf(MSG_DEBUG,
@@ -2743,7 +2846,8 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
        struct wpabuf *wps;
        enum wps_ap_info_type type;
        struct wps_ap_info *ap;
-       int r;
+       int r, pbc_active;
+       const u8 *uuid;
 
        if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
                return;
@@ -2760,7 +2864,8 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
        else
                type = WPS_AP_NOT_SEL_REG;
 
-       wpabuf_free(wps);
+       uuid = wps_get_uuid_e(wps);
+       pbc_active = wps_is_selected_pbc_registrar(wps);
 
        ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
        if (ap) {
@@ -2772,13 +2877,16 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
                        if (type != WPS_AP_NOT_SEL_REG)
                                wpa_blacklist_del(wpa_s, ap->bssid);
                }
-               return;
+               ap->pbc_active = pbc_active;
+               if (uuid)
+                       os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
+               goto out;
        }
 
        ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
                              sizeof(struct wps_ap_info));
        if (ap == NULL)
-               return;
+               goto out;
 
        wpa_s->wps_ap = ap;
        ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
@@ -2787,8 +2895,14 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
        os_memset(ap, 0, sizeof(*ap));
        os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
        ap->type = type;
+       ap->pbc_active = pbc_active;
+       if (uuid)
+               os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
        wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
                   MAC2STR(ap->bssid), ap->type);
+
+out:
+       wpabuf_free(wps);
 }