]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
FILS: Track completion with FILS shared key authentication offload
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 1c02020ad5e7be4f42c53bbb013f757042b40b4c..498820a3d9b098b618b25f5018bf241ed5c6199c 100644 (file)
@@ -452,6 +452,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_TESTING_OPTIONS
        l2_packet_deinit(wpa_s->l2_test);
        wpa_s->l2_test = NULL;
+       os_free(wpa_s->get_pref_freq_list_override);
+       wpa_s->get_pref_freq_list_override = NULL;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
@@ -524,6 +526,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        os_free(wpa_s->manual_scan_freqs);
        wpa_s->manual_scan_freqs = NULL;
+       os_free(wpa_s->select_network_scan_freqs);
+       wpa_s->select_network_scan_freqs = NULL;
 
        os_free(wpa_s->manual_sched_scan_freqs);
        wpa_s->manual_sched_scan_freqs = NULL;
@@ -617,6 +621,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 
        wpas_flush_fils_hlp_req(wpa_s);
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = NULL;
 }
 
 
@@ -990,7 +997,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
         * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
         */
-       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
                /*
                 * Clear forced success to clear EAP state for next
                 * authentication.
@@ -1326,6 +1334,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
                wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_OWE
+       } else if (sel & WPA_KEY_MGMT_OWE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
+#endif /* CONFIG_OWE */
        } else {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
                        "authenticated key management type");
@@ -1868,11 +1881,6 @@ static int drv_supports_vht(struct wpa_supplicant *wpa_s,
        u8 channel;
        int i;
 
-#ifdef CONFIG_HT_OVERRIDES
-       if (ssid->disable_ht)
-               return 0;
-#endif /* CONFIG_HT_OVERRIDES */
-
        hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
        if (hw_mode == NUM_HOSTAPD_MODES)
                return 0;
@@ -2071,6 +2079,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        vht_freq = *freq;
 
+#ifdef CONFIG_VHT_OVERRIDES
+       if (ssid->disable_vht) {
+               freq->vht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        vht_freq.vht_enabled = vht_supported(mode);
        if (!vht_freq.vht_enabled)
                return;
@@ -2179,6 +2194,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        struct ieee80211_vht_capabilities vhtcaps;
        struct ieee80211_vht_capabilities vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_FILS
+       const u8 *realm, *username, *rrk;
+       size_t realm_len, username_len, rrk_len;
+       u16 next_seq_num;
+#endif /* CONFIG_FILS */
 
        if (deinit) {
                if (work->started) {
@@ -2266,7 +2286,28 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                                algs |= WPA_AUTH_ALG_LEAP;
                }
        }
+
+#ifdef CONFIG_FILS
+       /* Clear FILS association */
+       wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
+
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+           ssid->eap.erp && wpa_key_mgmt_fils(ssid->key_mgmt) &&
+           eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
+                                 &username_len, &realm, &realm_len,
+                                 &next_seq_num, &rrk, &rrk_len) == 0) {
+               algs = WPA_AUTH_ALG_FILS;
+               params.fils_erp_username = username;
+               params.fils_erp_username_len = username_len;
+               params.fils_erp_realm = realm;
+               params.fils_erp_realm_len = realm_len;
+               params.fils_erp_next_seq_num = next_seq_num;
+               params.fils_erp_rrk = rrk;
+               params.fils_erp_rrk_len = rrk_len;
+       }
+#endif /* CONFIG_FILS */
 #endif /* IEEE8021X_EAPOL */
+
        wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
        if (ssid->auth_alg) {
                algs = ssid->auth_alg;
@@ -2278,12 +2319,19 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
+               const u8 *cache_id = NULL;
+
                try_opportunistic = (ssid->proactive_key_caching < 0 ?
                                     wpa_s->conf->okc :
                                     ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
+#ifdef CONFIG_FILS
+               if (wpa_key_mgmt_fils(ssid->key_mgmt))
+                       cache_id = wpa_bss_get_fils_cache_id(bss);
+#endif /* CONFIG_FILS */
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-                                           ssid, try_opportunistic) == 0)
+                                           ssid, try_opportunistic,
+                                           cache_id) == 0)
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2548,6 +2596,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        params.key_mgmt_suite = wpa_s->key_mgmt;
        params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
+       wpa_s->auth_alg = params.auth_alg;
        params.mode = ssid->mode;
        params.bg_scan_period = ssid->bg_scan_period;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -3566,6 +3615,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 
        os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
        if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
            eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
                return;
        wpa_drv_poll(wpa_s);
@@ -3762,8 +3812,11 @@ static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
        wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
 
        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+               long v;
+
                errno = 0;
-               long v = strtol(tmp, &end, 16);
+               v = strtol(tmp, &end, 16);
+
                if (errno == 0) {
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "htcap value[%i]: %ld end: %p  tmp: %p",
@@ -4152,10 +4205,14 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+       if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+                          __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+               return -1;
+       }
        return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-                                         wpa_s->own_addr, wpa_s->bssid,
-                                         wpabuf_head(data), wpabuf_len(data),
+                                  wpa_s->own_addr, wpa_s->bssid,
+                                  wpabuf_head(data), wpabuf_len(data),
                                   0);
 }
 
@@ -4353,6 +4410,20 @@ static void radio_work_free(struct wpa_radio_work *work)
 }
 
 
+static int radio_work_is_connect(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "sme-connect") == 0 ||
+               os_strcmp(work->type, "connect") == 0;
+}
+
+
+static int radio_work_is_scan(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "scan") == 0 ||
+               os_strcmp(work->type, "p2p-scan") == 0;
+}
+
+
 static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
 {
        struct wpa_radio_work *active_work = NULL;
@@ -4382,8 +4453,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                return NULL;
        }
 
-       if (os_strcmp(active_work->type, "sme-connect") == 0 ||
-           os_strcmp(active_work->type, "connect") == 0) {
+       if (radio_work_is_connect(active_work)) {
                /*
                 * If the active work is either connect or sme-connect,
                 * do not parallelize them with other radio works.
@@ -4402,10 +4472,20 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                 * If connect or sme-connect are enqueued, parallelize only
                 * those operations ahead of them in the queue.
                 */
-               if (os_strcmp(tmp->type, "connect") == 0 ||
-                   os_strcmp(tmp->type, "sme-connect") == 0)
+               if (radio_work_is_connect(tmp))
                        break;
 
+               /* Serialize parallel scan and p2p_scan operations on the same
+                * interface since the driver_nl80211 mechanism for tracking
+                * scan cookies does not yet have support for this. */
+               if (active_work->wpa_s == tmp->wpa_s &&
+                   radio_work_is_scan(active_work) &&
+                   radio_work_is_scan(tmp)) {
+                       wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+                               "Do not start work '%s' when another work '%s' is already scheduled",
+                               tmp->type, active_work->type);
+                       continue;
+               }
                /*
                 * Check that the radio works are distinct and
                 * on different bands.
@@ -5308,6 +5388,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 #ifdef CONFIG_MESH
        unsigned int mesh_if_created = wpa_s->mesh_if_created;
        char *ifname = NULL;
+       struct wpa_supplicant *parent = wpa_s->parent;
 #endif /* CONFIG_MESH */
 
        /* Remove interface from the global list of interfaces */
@@ -5343,7 +5424,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
 #ifdef CONFIG_MESH
        if (mesh_if_created) {
-               wpa_drv_if_remove(wpa_s->parent, WPA_IF_MESH, ifname);
+               wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
                os_free(ifname);
        }
 #endif /* CONFIG_MESH */
@@ -5936,6 +6017,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
        case WPA_CTRL_REQ_SIM:
                str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
+               eap->pending_req_sim = 0;
                break;
        case WPA_CTRL_REQ_PSK_PASSPHRASE:
                if (wpa_config_set(ssid, "psk", value, 0) < 0)