]> 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 d3848cb97c9b6580fe29614e758c1c80c8d26a0e..498820a3d9b098b618b25f5018bf241ed5c6199c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -62,7 +62,7 @@
 
 const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -192,7 +192,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        const u8 *bssid = wpa_s->bssid;
-       if (is_zero_ether_addr(bssid))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                bssid = wpa_s->pending_bssid;
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
@@ -327,7 +329,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 
        eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 
-       ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+               ieee802_1x_create_preshared_mka(wpa_s, ssid);
+       else
+               ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
 #endif /* IEEE8021X_EAPOL */
 }
 
@@ -413,6 +420,19 @@ static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+       struct fils_hlp_req *req;
+
+       while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+                                   list)) != NULL) {
+               dl_list_del(&req->list);
+               wpabuf_free(req->pkt);
+               os_free(req);
+       }
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -432,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) {
@@ -504,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;
@@ -578,6 +602,28 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        wpabuf_free(wpa_s->lci);
        wpa_s->lci = NULL;
+       wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       {
+               struct external_pmksa_cache *entry;
+
+               while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+                                            struct external_pmksa_cache,
+                                            list)) != NULL) {
+                       dl_list_del(&entry->list);
+                       os_free(entry->pmksa_cache);
+                       os_free(entry);
+               }
+       }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+       wpas_flush_fils_hlp_req(wpa_s);
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = NULL;
 }
 
 
@@ -951,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.
@@ -1231,6 +1278,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT 802.1X with Suite B");
 #endif /* CONFIG_SUITEB */
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R
+       } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
+       } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
+       } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+       } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
+#endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1271,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");
@@ -1456,6 +1524,19 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
                break;
        case 6: /* Bits 48-55 */
                break;
+       case 7: /* Bits 56-63 */
+               break;
+       case 8: /* Bits 64-71 */
+               if (wpa_s->conf->ftm_responder)
+                       *pos |= 0x40; /* Bit 70 - FTM responder */
+               if (wpa_s->conf->ftm_initiator)
+                       *pos |= 0x80; /* Bit 71 - FTM initiator */
+               break;
+       case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+               *pos |= 0x01;
+#endif /* CONFIG_FILS */
+               break;
        }
 }
 
@@ -1463,7 +1544,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
 {
        u8 *pos = buf;
-       u8 len = 6, i;
+       u8 len = 10, i;
 
        if (len < wpa_s->extended_capa_len)
                len = wpa_s->extended_capa_len;
@@ -1660,11 +1741,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wmm_ac_save_tspecs(wpa_s);
                        wpa_s->reassoc_same_bss = 1;
                }
-       } else if (rand_style > 0) {
+       }
+
+       if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
                if (wpas_update_random_addr(wpa_s, rand_style) < 0)
                        return;
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
-       } else if (wpa_s->mac_addr_changed) {
+       } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
                if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
                        wpa_msg(wpa_s, MSG_INFO,
                                "Could not restore permanent MAC address");
@@ -1683,6 +1766,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
        wpa_s->ibss_rsn = NULL;
+#else /* CONFIG_IBSS_RSN */
+       if (ssid->mode == WPAS_MODE_IBSS &&
+           !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "IBSS RSN not supported in the build");
+               return;
+       }
 #endif /* CONFIG_IBSS_RSN */
 
        if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
@@ -1753,6 +1843,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+#ifdef CONFIG_SME
+       if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+               /* Clear possibly set auth_alg, if any, from last attempt. */
+               wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+       }
+#endif /* CONFIG_SME */
+
        wpas_abort_ongoing_scan(wpa_s);
 
        cwork = os_zalloc(sizeof(*cwork));
@@ -1784,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;
@@ -1873,6 +1965,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!mode)
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht) {
+               freq->ht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_HT_OVERRIDES */
+
        freq->ht_enabled = ht_supported(mode);
        if (!freq->ht_enabled)
                return;
@@ -1894,6 +1993,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht40)
+               return;
+#endif /* CONFIG_HT_OVERRIDES */
+
        /* Check/setup HT40+/HT40- */
        for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
                if (ht40plus[j] == channel) {
@@ -1918,22 +2022,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        freq->channel = pri_chan->chan;
 
-       switch (ht40) {
-       case -1:
+       if (ht40 == -1) {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
                        return;
-               freq->sec_channel_offset = -1;
-               break;
-       case 1:
+       } else {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
                        return;
-               freq->sec_channel_offset = 1;
-               break;
-       default:
-               break;
        }
+       freq->sec_channel_offset = ht40;
 
-       if (freq->sec_channel_offset && obss_scan) {
+       if (obss_scan) {
                struct wpa_scan_results *scan_res;
 
                scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1981,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;
@@ -2089,9 +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_MBO
-       const u8 *mbo = NULL;
-#endif /* CONFIG_MBO */
+#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) {
@@ -2156,7 +2263,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        } else {
                wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-               os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+               if (bss)
+                       os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+               else
+                       os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
        if (!wpa_s->pno)
                wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -2176,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;
@@ -2188,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,
@@ -2277,21 +2415,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_MBO
        if (bss) {
-               mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
-               if (mbo) {
-                       int len;
-
-                       len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
-                                                       wpa_ie + wpa_ie_len,
-                                                       sizeof(wpa_ie) -
-                                                       wpa_ie_len);
-                       if (len > 0)
-                               wpa_ie_len += len;
-               }
+               wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+                                                   wpa_ie + wpa_ie_len,
+                                                   sizeof(wpa_ie) -
+                                                   wpa_ie_len);
        }
-#endif /* CONFIG_MBO */
 
        /*
         * Workaround: Add Extended Capabilities element only if the AP
@@ -2370,7 +2499,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_MBO
-       if (mbo) {
+       if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
                int len;
 
                len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2421,12 +2550,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        if (bss) {
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
+                   wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
                        wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
                                   MACSTR " freq=%u MHz based on scan results "
-                                  "(bssid_set=%d)",
+                                  "(bssid_set=%d wps=%d)",
                                   MAC2STR(bss->bssid), bss->freq,
-                                  ssid->bssid_set);
+                                  ssid->bssid_set,
+                                  wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
                        params.bssid = bss->bssid;
                        params.freq.freq = bss->freq;
                }
@@ -2465,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++) {
@@ -2685,12 +2817,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
                reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
 
-       if (!is_zero_ether_addr(wpa_s->bssid))
-               addr = wpa_s->bssid;
-       else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
-                (wpa_s->wpa_state == WPA_AUTHENTICATING ||
-                 wpa_s->wpa_state == WPA_ASSOCIATING))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                addr = wpa_s->pending_bssid;
+       else if (!is_zero_ether_addr(wpa_s->bssid))
+               addr = wpa_s->bssid;
        else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
                /*
                 * When using driver-based BSS selection, we may not know the
@@ -2746,6 +2878,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
 }
 
 
+/**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (!ssid)
+               return NULL;
+       wpas_notify_network_added(wpa_s, ssid);
+       ssid->disabled = 1;
+       wpa_config_set_network_defaults(ssid);
+
+       return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+       struct wpa_ssid *ssid;
+       int was_disabled;
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (!ssid)
+               return -1;
+       wpas_notify_network_removed(wpa_s, ssid);
+
+       if (wpa_s->last_ssid == ssid)
+               wpa_s->last_ssid = NULL;
+
+       if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+               wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+               /*
+                * Invalidate the EAP session cache if the current or
+                * previously used network is removed.
+                */
+               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+       }
+
+       if (ssid == wpa_s->current_ssid) {
+               wpa_sm_set_config(wpa_s->wpa, NULL);
+               eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+               if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                       wpa_s->own_disconnect_req = 1;
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
+
+       was_disabled = ssid->disabled;
+
+       if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+               return -2;
+
+       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);
+       }
+
+       return 0;
+}
+
+
 /**
  * wpa_supplicant_enable_network - Mark a configured network as enabled
  * @wpa_s: wpa_supplicant structure for a network interface
@@ -2906,6 +3127,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        if (wpa_s->connect_without_scan ||
            wpa_supplicant_fast_associate(wpa_s) != 1) {
                wpa_s->scan_req = NORMAL_SCAN_REQ;
+               wpas_scan_reset_sched_scan(wpa_s);
                wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
        }
 
@@ -3266,6 +3488,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
        wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->ignore_auth_resp) {
+               wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
+               return;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
 #ifdef CONFIG_PEERKEY
        if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
            wpa_s->current_ssid->peerkey &&
@@ -3386,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);
@@ -3554,6 +3784,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
        wpa_s->sched_scanning = 0;
 
        dl_list_init(&wpa_s->bss_tmp_disallowed);
+       dl_list_init(&wpa_s->fils_hlp_req);
 
        return wpa_s;
 }
@@ -3581,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",
@@ -3692,18 +3926,10 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
                                struct ieee80211_ht_capabilities *htcaps_mask,
                                int disabled)
 {
-       /* Masking these out disables HT40 */
-       le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
-                               HT_CAP_INFO_SHORT_GI40MHZ);
-
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
 
-       if (disabled)
-               htcaps->ht_capabilities_info &= ~msk;
-       else
-               htcaps->ht_capabilities_info |= msk;
-
-       htcaps_mask->ht_capabilities_info |= msk;
+       set_disable_ht40(htcaps, disabled);
+       set_disable_ht40(htcaps_mask, 0);
 
        return 0;
 }
@@ -3806,8 +4032,8 @@ void wpa_supplicant_apply_vht_overrides(
        if (!vhtcaps || !vhtcaps_mask)
                return;
 
-       vhtcaps->vht_capabilities_info = ssid->vht_capa;
-       vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+       vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+       vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
 
 #ifdef CONFIG_HT_OVERRIDES
        /* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -3829,15 +4055,17 @@ void wpa_supplicant_apply_vht_overrides(
 #define OVERRIDE_MCS(i)                                                        \
        if (ssid->vht_tx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.tx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.tx_map |=                \
-                       ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_tx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }                                                               \
        if (ssid->vht_rx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.rx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.rx_map |=                \
-                       ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_rx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }
 
        OVERRIDE_MCS(1);
@@ -3977,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);
 }
 
@@ -4009,8 +4241,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
 }
 
 
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                  Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+                                         struct fst_get_peer_ctx **get_ctx,
+                                         Boolean mb_only)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
@@ -4022,8 +4255,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
 }
 
 
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                 Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+                                        struct fst_get_peer_ctx **get_ctx,
+                                        Boolean mb_only)
 {
        return NULL;
 }
@@ -4176,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;
@@ -4205,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.
@@ -4225,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.
@@ -4824,6 +5081,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
        /*
         * Set Wake-on-WLAN triggers, if configured.
         * Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -4864,6 +5127,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
 #endif /* CONFIG_MBO */
 
+       wpa_supplicant_set_default_scan_ies(wpa_s);
+
        return 0;
 }
 
@@ -5123,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 */
@@ -5158,7 +5424,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
 #ifdef CONFIG_MESH
        if (mesh_if_created) {
-               wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+               wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
                os_free(ifname);
        }
 #endif /* CONFIG_MESH */
@@ -5751,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)
@@ -6011,6 +6278,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
 }
 
 
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+       wpa_s->reassociate = 0;
+       wpa_s->disconnected = 1;
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+       wpa_supplicant_cancel_scan(wpa_s);
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+}
+
+
 void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
                    struct wpa_used_freq_data *freqs_data,
                    unsigned int len)
@@ -6108,489 +6396,6 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
-{
-       struct rrm_data *rrm = data;
-
-       if (!rrm->notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Unexpected neighbor report timeout");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
-       rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
-       rrm->notify_neighbor_rep = NULL;
-       rrm->neighbor_rep_cb_ctx = NULL;
-}
-
-
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->rrm.rrm_used = 0;
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-       if (wpa_s->rrm.notify_neighbor_rep)
-               wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
-       wpa_s->rrm.next_neighbor_rep_token = 1;
-}
-
-
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
-                                  const u8 *report, size_t report_len)
-{
-       struct wpabuf *neighbor_rep;
-
-       wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
-       if (report_len < 1)
-               return;
-
-       if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Discarding neighbor report with token %d (expected %d)",
-                          report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
-               return;
-       }
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-
-       if (!wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
-               return;
-       }
-
-       /* skipping the first byte, which is only an id (dialog token) */
-       neighbor_rep = wpabuf_alloc(report_len - 1);
-       if (neighbor_rep == NULL)
-               return;
-       wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
-                  report[0]);
-       wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
-                                      neighbor_rep);
-       wpa_s->rrm.notify_neighbor_rep = NULL;
-       wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
-
-
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#define ECANCELED -1
-#endif
-
-/* Measurement Request element + Location Subject + Maximum Age subelement */
-#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
-/* Measurement Request element + Location Civic Request */
-#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
-
-
-/**
- * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
- * @wpa_s: Pointer to wpa_supplicant
- * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
- *       is sent in the request.
- * @lci: if set, neighbor request will include LCI request
- * @civic: if set, neighbor request will include civic location request
- * @cb: Callback function to be called once the requested report arrives, or
- *     timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
- *     In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
- *     the requester's responsibility to free it.
- *     In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid_value *ssid,
-                                      int lci, int civic,
-                                      void (*cb)(void *ctx,
-                                                 struct wpabuf *neighbor_rep),
-                                      void *cb_ctx)
-{
-       struct wpabuf *buf;
-       const u8 *rrm_ie;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
-               return -ENOTCONN;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
-               return -EOPNOTSUPP;
-       }
-
-       rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
-                               WLAN_EID_RRM_ENABLED_CAPABILITIES);
-       if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
-           !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: No network support for Neighbor Report.");
-               return -EOPNOTSUPP;
-       }
-
-       if (!cb) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Neighbor Report request must provide a callback.");
-               return -EINVAL;
-       }
-
-       /* Refuse if there's a live request */
-       if (wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Currently handling previous Neighbor Report.");
-               return -EBUSY;
-       }
-
-       /* 3 = action category + action code + dialog token */
-       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
-                          (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
-                          (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Failed to allocate Neighbor Report Request");
-               return -ENOMEM;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
-                  (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
-                  wpa_s->rrm.next_neighbor_rep_token);
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
-       wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
-       if (ssid) {
-               wpabuf_put_u8(buf, WLAN_EID_SSID);
-               wpabuf_put_u8(buf, ssid->ssid_len);
-               wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
-       }
-
-       if (lci) {
-               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
-               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
-               wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
-
-               /*
-                * Measurement token; nonzero number that is unique among the
-                * Measurement Request elements in a particular frame.
-                */
-               wpabuf_put_u8(buf, 1); /* Measurement Token */
-
-               /*
-                * Parallel, Enable, Request, and Report bits are 0, Duration is
-                * reserved.
-                */
-               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
-               wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
-
-               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
-               /* Location Subject */
-               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
-
-               /* Optional Subelements */
-               /*
-                * IEEE P802.11-REVmc/D5.0 Figure 9-170
-                * The Maximum Age subelement is required, otherwise the AP can
-                * send only data that was determined after receiving the
-                * request. Setting it here to unlimited age.
-                */
-               wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
-               wpabuf_put_u8(buf, 2);
-               wpabuf_put_le16(buf, 0xffff);
-       }
-
-       if (civic) {
-               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
-               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
-               wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
-
-               /*
-                * Measurement token; nonzero number that is unique among the
-                * Measurement Request elements in a particular frame.
-                */
-               wpabuf_put_u8(buf, 2); /* Measurement Token */
-
-               /*
-                * Parallel, Enable, Request, and Report bits are 0, Duration is
-                * reserved.
-                */
-               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
-               /* Measurement Type */
-               wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
-
-               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
-                * Location Civic request */
-               /* Location Subject */
-               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
-               wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
-               /* Location Service Interval Units: Seconds */
-               wpabuf_put_u8(buf, 0);
-               /* Location Service Interval: 0 - Only one report is requested
-                */
-               wpabuf_put_le16(buf, 0);
-               /* No optional subelements */
-       }
-
-       wpa_s->rrm.next_neighbor_rep_token++;
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Failed to send Neighbor Report Request");
-               wpabuf_free(buf);
-               return -ECANCELED;
-       }
-
-       wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
-       wpa_s->rrm.notify_neighbor_rep = cb;
-       eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
-                              wpas_rrm_neighbor_rep_timeout_handler,
-                              &wpa_s->rrm, NULL);
-
-       wpabuf_free(buf);
-       return 0;
-}
-
-
-static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
-                                                const u8 *request, size_t len,
-                                                struct wpabuf *report)
-{
-       u8 token, type, subject;
-       u16 max_age = 0;
-       struct os_reltime t, diff;
-       unsigned long diff_l;
-       u8 *ptoken;
-       const u8 *subelem;
-
-       if (!wpa_s->lci || len < 3 + 4)
-               return report;
-
-       token = *request++;
-       /* Measurement request mode isn't used */
-       request++;
-       type = *request++;
-       subject = *request++;
-
-       wpa_printf(MSG_DEBUG,
-                  "Measurement request token %u type %u location subject %u",
-                  token, type, subject);
-
-       if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
-               wpa_printf(MSG_INFO,
-                          "Not building LCI report - bad type or location subject");
-               return report;
-       }
-
-       /* Subelements are formatted exactly like elements */
-       subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
-       if (subelem && subelem[1] == 2)
-               max_age = WPA_GET_LE16(subelem + 2);
-
-       if (os_get_reltime(&t))
-               return report;
-
-       os_reltime_sub(&t, &wpa_s->lci_time, &diff);
-       /* LCI age is calculated in 10th of a second units. */
-       diff_l = diff.sec * 10 + diff.usec / 100000;
-
-       if (max_age != 0xffff && max_age < diff_l)
-               return report;
-
-       if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
-               return report;
-
-       wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
-       wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
-       /* We'll override user's measurement token */
-       ptoken = wpabuf_put(report, 0);
-       wpabuf_put_buf(report, wpa_s->lci);
-       *ptoken = token;
-
-       return report;
-}
-
-
-void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
-                                              const u8 *src,
-                                              const u8 *frame, size_t len)
-{
-       struct wpabuf *buf, *report;
-       u8 token;
-       const u8 *ie, *end;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring radio measurement request: Not associated");
-               return;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring radio measurement request: Not RRM network");
-               return;
-       }
-
-       if (len < 3) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring too short radio measurement request");
-               return;
-       }
-
-       end = frame + len;
-
-       token = *frame++;
-
-       /* Ignore number of repetitions because it's not used in LCI request */
-       frame += 2;
-
-       report = NULL;
-       while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
-              ie[1] >= 3) {
-               u8 msmt_type;
-
-               msmt_type = ie[4];
-               wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type);
-
-               switch (msmt_type) {
-               case MEASURE_TYPE_LCI:
-                       report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
-                                                          report);
-                       break;
-               default:
-                       wpa_printf(MSG_INFO,
-                                  "RRM: Unsupported radio measurement request %d",
-                                  msmt_type);
-                       break;
-               }
-
-               frame = ie + ie[1] + 2;
-       }
-
-       if (!report)
-               return;
-
-       buf = wpabuf_alloc(3 + wpabuf_len(report));
-       if (!buf) {
-               wpabuf_free(report);
-               return;
-       }
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
-       wpabuf_put_u8(buf, token);
-
-       wpabuf_put_buf(buf, report);
-       wpabuf_free(report);
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Radio measurement report failed: Sending Action frame failed");
-       }
-       wpabuf_free(buf);
-}
-
-
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
-                                             const u8 *src,
-                                             const u8 *frame, size_t len,
-                                             int rssi)
-{
-       struct wpabuf *buf;
-       const struct rrm_link_measurement_request *req;
-       struct rrm_link_measurement_report report;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not associated");
-               return;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not RRM network");
-               return;
-       }
-
-       if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Measurement report failed. TX power insertion not supported");
-               return;
-       }
-
-       req = (const struct rrm_link_measurement_request *) frame;
-       if (len < sizeof(*req)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Link measurement report failed. Request too short");
-               return;
-       }
-
-       os_memset(&report, 0, sizeof(report));
-       report.tpc.eid = WLAN_EID_TPC_REPORT;
-       report.tpc.len = 2;
-       report.rsni = 255; /* 255 indicates that RSNI is not available */
-       report.dialog_token = req->dialog_token;
-
-       /*
-        * It's possible to estimate RCPI based on RSSI in dBm. This
-        * calculation will not reflect the correct value for high rates,
-        * but it's good enough for Action frames which are transmitted
-        * with up to 24 Mbps rates.
-        */
-       if (!rssi)
-               report.rcpi = 255; /* not available */
-       else if (rssi < -110)
-               report.rcpi = 0;
-       else if (rssi > 0)
-               report.rcpi = 220;
-       else
-               report.rcpi = (rssi + 110) * 2;
-
-       /* action_category + action_code */
-       buf = wpabuf_alloc(2 + sizeof(report));
-       if (buf == NULL) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Buffer allocation failed");
-               return;
-       }
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
-       wpabuf_put_data(buf, &report, sizeof(report));
-       wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
-                   wpabuf_head(buf), wpabuf_len(buf));
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Send action failed");
-       }
-       wpabuf_free(buf);
-}
-
-
 struct wpa_supplicant *
 wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
 {