mesh: Add support for scanning only the current frequency
[mech_eap.git] / wpa_supplicant / wpa_supplicant.c
index 140e0e2..4805f83 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -33,7 +33,9 @@
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "p2p/p2p.h"
+#include "fst/fst.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
 #include "wps_supplicant.h"
 #include "wpas_kay.h"
 #include "mesh.h"
 
-const char *wpa_supplicant_version =
+const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
 
-const char *wpa_supplicant_license =
+const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
 "See README for more details.\n"
 #ifdef EAP_TLS_OPENSSL
@@ -69,16 +71,16 @@ const char *wpa_supplicant_license =
 
 #ifndef CONFIG_NO_STDOUT_DEBUG
 /* Long text divided into parts in order to fit in C89 strings size limits. */
-const char *wpa_supplicant_full_license1 =
+const char *const wpa_supplicant_full_license1 =
 "";
-const char *wpa_supplicant_full_license2 =
+const char *const wpa_supplicant_full_license2 =
 "This software may be distributed under the terms of the BSD license.\n"
 "\n"
 "Redistribution and use in source and binary forms, with or without\n"
 "modification, are permitted provided that the following conditions are\n"
 "met:\n"
 "\n";
-const char *wpa_supplicant_full_license3 =
+const char *const wpa_supplicant_full_license3 =
 "1. Redistributions of source code must retain the above copyright\n"
 "   notice, this list of conditions and the following disclaimer.\n"
 "\n"
@@ -86,7 +88,7 @@ const char *wpa_supplicant_full_license3 =
 "   notice, this list of conditions and the following disclaimer in the\n"
 "   documentation and/or other materials provided with the distribution.\n"
 "\n";
-const char *wpa_supplicant_full_license4 =
+const char *const wpa_supplicant_full_license4 =
 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
 "   names of its contributors may be used to endorse or promote products\n"
 "   derived from this software without specific prior written permission.\n"
@@ -95,7 +97,7 @@ const char *wpa_supplicant_full_license4 =
 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
-const char *wpa_supplicant_full_license5 =
+const char *const wpa_supplicant_full_license5 =
 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
@@ -132,6 +134,7 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
        size_t keylen;
        enum wpa_alg alg;
        u8 seq[6] = { 0 };
+       int ret;
 
        /* IBSS/WPA-None uses only one key (Group) for both receiving and
         * sending unicast and multicast packets. */
@@ -175,7 +178,9 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
        /* TODO: should actually remember the previously used seq#, both for TX
         * and RX from each STA.. */
 
-       return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+       ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+       os_memset(key, 0, sizeof(key));
+       return ret;
 }
 
 
@@ -435,6 +440,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_tdls_deinit(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
 
+       wmm_ac_clear_saved_tspecs(wpa_s);
        pmksa_candidate_free(wpa_s->wpa);
        wpa_sm_deinit(wpa_s->wpa);
        wpa_s->wpa = NULL;
@@ -451,6 +457,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                             wpa_s, NULL);
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
+       eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+
        wpas_wps_deinit(wpa_s);
 
        wpabuf_free(wpa_s->pending_eapol_rx);
@@ -484,6 +492,18 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        os_free(wpa_s->manual_sched_scan_freqs);
        wpa_s->manual_sched_scan_freqs = NULL;
 
+       wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
+
+       /*
+        * Need to remove any pending gas-query radio work before the
+        * gas_query_deinit() call because gas_query::work has not yet been set
+        * for works that have not been started. gas_query_free() will be unable
+        * to cancel such pending radio works and once the pending gas-query
+        * radio work eventually gets removed, the deinit notification call to
+        * gas_query_start_cb() would result in dereferencing freed memory.
+        */
+       if (wpa_s->radio)
+               radio_remove_works(wpa_s, "gas-query", 0);
        gas_query_deinit(wpa_s->gas);
        wpa_s->gas = NULL;
 
@@ -523,6 +543,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                wpabuf_free(wpa_s->vendor_elem[i]);
                wpa_s->vendor_elem[i] = NULL;
        }
+
+       wmm_ac_notify_disassoc(wpa_s);
 }
 
 
@@ -707,6 +729,30 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_s->normal_scans = 0;
        }
 
+#ifdef CONFIG_P2P
+       /*
+        * P2PS client has to reply to Probe Request frames received on the
+        * group operating channel. Enable Probe Request frame reporting for
+        * P2P connected client in case p2p_cli_probe configuration property is
+        * set to 1.
+        */
+       if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
+           wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+           wpa_s->current_ssid->p2p_group) {
+               if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "P2P: Enable CLI Probe Request RX reporting");
+                       wpa_s->p2p_cli_probe =
+                               wpa_drv_probe_req_report(wpa_s, 1) >= 0;
+               } else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "P2P: Disable CLI Probe Request RX reporting");
+                       wpa_s->p2p_cli_probe = 0;
+                       wpa_drv_probe_req_report(wpa_s, 0);
+               }
+       }
+#endif /* CONFIG_P2P */
+
        if (state != WPA_SCANNING)
                wpa_supplicant_notify_scanning(wpa_s, 0);
 
@@ -720,6 +766,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                        ssid && ssid->id_str ? ssid->id_str : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
                wpas_clear_temp_disabled(wpa_s, ssid, 1);
+               wpa_blacklist_clear(wpa_s);
                wpa_s->extra_blacklist_count = 0;
                wpa_s->new_connection = 0;
                wpa_drv_set_operstate(wpa_s, 1);
@@ -755,6 +802,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
        if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
                wpa_supplicant_start_autoscan(wpa_s);
 
+       if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
+               wmm_ac_notify_disassoc(wpa_s);
+
        if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
@@ -858,6 +908,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 
        eapol_sm_invalidate_cached_session(wpa_s->eapol);
        if (wpa_s->current_ssid) {
+               if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                       wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
        }
@@ -950,9 +1002,7 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-           (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-            wpa_s->conf->pmf : ssid->ieee80211w) ==
-           MGMT_FRAME_PROTECTION_REQUIRED) {
+           wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
                        "that does not support management frame protection - "
                        "reject");
@@ -1001,7 +1051,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
                proto = WPA_PROTO_RSN;
        } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
-                  wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+                  wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
                   (ie.group_cipher & ssid->group_cipher) &&
                   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
                   (ie.key_mgmt & ssid->key_mgmt)) {
@@ -1019,6 +1069,40 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_HS20 */
        } else if (bss) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+                       ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
+                       ssid->key_mgmt);
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
+                       MAC2STR(bss->bssid),
+                       wpa_ssid_txt(bss->ssid, bss->ssid_len),
+                       bss_wpa ? " WPA" : "",
+                       bss_rsn ? " RSN" : "",
+                       bss_osen ? " OSEN" : "");
+               if (bss_rsn) {
+                       wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
+                       if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "Could not parse RSN element");
+                       } else {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+                                       ie.pairwise_cipher, ie.group_cipher,
+                                       ie.key_mgmt);
+                       }
+               }
+               if (bss_wpa) {
+                       wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
+                       if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "Could not parse WPA element");
+                       } else {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+                                       ie.pairwise_cipher, ie.group_cipher,
+                                       ie.key_mgmt);
+                       }
+               }
                return -1;
        } else {
                if (ssid->proto & WPA_PROTO_OSEN)
@@ -1092,10 +1176,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
        if (0) {
+#ifdef CONFIG_SUITEB192
+       } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_SUITEB
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT 802.1X with Suite B");
+#endif /* CONFIG_SUITEB */
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1149,8 +1241,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        sel = ie.mgmt_group_cipher;
-       if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-            wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+       if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
            !(ie.capabilities & WPA_CAPABILITY_MFPC))
                sel = 0;
        if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1176,8 +1267,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
                         wpa_s->mgmt_group_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
-                        (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-                         wpa_s->conf->pmf : ssid->ieee80211w));
+                        wpas_get_ssid_pmf(wpa_s, ssid));
 #endif /* CONFIG_IEEE80211W */
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1186,7 +1276,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
-               wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+               int psk_set = 0;
+
+               if (ssid->psk_set) {
+                       wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+                       psk_set = 1;
+               }
 #ifndef CONFIG_NO_PBKDF2
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
@@ -1196,6 +1291,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                                        psk, PMK_LEN);
                        wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                       psk_set = 1;
+                       os_memset(psk, 0, sizeof(psk));
                }
 #endif /* CONFIG_NO_PBKDF2 */
 #ifdef CONFIG_EXT_PASSWORD
@@ -1232,6 +1329,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                                "external passphrase)",
                                                psk, PMK_LEN);
                                wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               psk_set = 1;
+                               os_memset(psk, 0, sizeof(psk));
                        } else
 #endif /* CONFIG_NO_PBKDF2 */
                        if (wpabuf_len(pw) == 2 * PMK_LEN) {
@@ -1243,6 +1342,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        return -1;
                                }
                                wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               psk_set = 1;
+                               os_memset(psk, 0, sizeof(psk));
                        } else {
                                wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
                                        "PSK available");
@@ -1255,6 +1356,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        ext_password_free(pw);
                }
 #endif /* CONFIG_EXT_PASSWORD */
+
+               if (!psk_set) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "No PSK available for association");
+                       return -1;
+               }
        } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
@@ -1484,8 +1591,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        else
                rand_style = ssid->mac_addr;
 
+       wmm_ac_clear_saved_tspecs(wpa_s);
+       wpa_s->reassoc_same_bss = 0;
+
        if (wpa_s->last_ssid == ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+               if (wpa_s->current_bss && wpa_s->current_bss == bss) {
+                       wmm_ac_save_tspecs(wpa_s);
+                       wpa_s->reassoc_same_bss = 1;
+               }
        } else if (rand_style > 0) {
                if (wpas_update_random_addr(wpa_s, rand_style) < 0)
                        return;
@@ -1594,6 +1708,227 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 }
 
 
+static int bss_is_ibss(struct wpa_bss *bss)
+{
+       return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+               IEEE80211_CAP_IBSS;
+}
+
+
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+                         const struct wpa_ssid *ssid,
+                         struct hostapd_freq_params *freq)
+{
+       enum hostapd_hw_mode hw_mode;
+       struct hostapd_hw_modes *mode = NULL;
+       int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+                          184, 192 };
+       int vht80[] = { 36, 52, 100, 116, 132, 149 };
+       struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+       u8 channel;
+       int i, chan_idx, ht40 = -1, res, obss_scan = 1;
+       unsigned int j;
+       struct hostapd_freq_params vht_freq;
+
+       freq->freq = ssid->frequency;
+
+       for (j = 0; j < wpa_s->last_scan_res_used; j++) {
+               struct wpa_bss *bss = wpa_s->last_scan_res[j];
+
+               if (ssid->mode != WPAS_MODE_IBSS)
+                       break;
+
+               /* Don't adjust control freq in case of fixed_freq */
+               if (ssid->fixed_freq)
+                       break;
+
+               if (!bss_is_ibss(bss))
+                       continue;
+
+               if (ssid->ssid_len == bss->ssid_len &&
+                   os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "IBSS already found in scan results, adjust control freq: %d",
+                                  bss->freq);
+                       freq->freq = bss->freq;
+                       obss_scan = 0;
+                       break;
+               }
+       }
+
+       /* For IBSS check HT_IBSS flag */
+       if (ssid->mode == WPAS_MODE_IBSS &&
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
+               return;
+
+       if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
+           wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
+           wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
+               wpa_printf(MSG_DEBUG,
+                          "IBSS: WEP/TKIP detected, do not try to enable HT");
+               return;
+       }
+
+       hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+       for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+               if (wpa_s->hw.modes[i].mode == hw_mode) {
+                       mode = &wpa_s->hw.modes[i];
+                       break;
+               }
+       }
+
+       if (!mode)
+               return;
+
+       freq->ht_enabled = ht_supported(mode);
+       if (!freq->ht_enabled)
+               return;
+
+       /* Setup higher BW only for 5 GHz */
+       if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+               return;
+
+       for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
+               pri_chan = &mode->channels[chan_idx];
+               if (pri_chan->chan == channel)
+                       break;
+               pri_chan = NULL;
+       }
+       if (!pri_chan)
+               return;
+
+       /* Check primary channel flags */
+       if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+               return;
+
+       /* Check/setup HT40+/HT40- */
+       for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
+               if (ht40plus[j] == channel) {
+                       ht40 = 1;
+                       break;
+               }
+       }
+
+       /* Find secondary channel */
+       for (i = 0; i < mode->num_channels; i++) {
+               sec_chan = &mode->channels[i];
+               if (sec_chan->chan == channel + ht40 * 4)
+                       break;
+               sec_chan = NULL;
+       }
+       if (!sec_chan)
+               return;
+
+       /* Check secondary channel flags */
+       if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+               return;
+
+       freq->channel = pri_chan->chan;
+
+       switch (ht40) {
+       case -1:
+               if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
+                       return;
+               freq->sec_channel_offset = -1;
+               break;
+       case 1:
+               if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
+                       return;
+               freq->sec_channel_offset = 1;
+               break;
+       default:
+               break;
+       }
+
+       if (freq->sec_channel_offset && obss_scan) {
+               struct wpa_scan_results *scan_res;
+
+               scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+               if (scan_res == NULL) {
+                       /* Back to HT20 */
+                       freq->sec_channel_offset = 0;
+                       return;
+               }
+
+               res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
+                                    sec_chan->chan);
+               switch (res) {
+               case 0:
+                       /* Back to HT20 */
+                       freq->sec_channel_offset = 0;
+                       break;
+               case 1:
+                       /* Configuration allowed */
+                       break;
+               case 2:
+                       /* Switch pri/sec channels */
+                       freq->freq = hw_get_freq(mode, sec_chan->chan);
+                       freq->sec_channel_offset = -freq->sec_channel_offset;
+                       freq->channel = sec_chan->chan;
+                       break;
+               default:
+                       freq->sec_channel_offset = 0;
+                       break;
+               }
+
+               wpa_scan_results_free(scan_res);
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
+                  freq->channel, freq->sec_channel_offset);
+
+       /* Not sure if mesh is ready for VHT */
+       if (ssid->mode != WPAS_MODE_IBSS)
+               return;
+
+       /* For IBSS check VHT_IBSS flag */
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+               return;
+
+       vht_freq = *freq;
+
+       vht_freq.vht_enabled = vht_supported(mode);
+       if (!vht_freq.vht_enabled)
+               return;
+
+       /* setup center_freq1, bandwidth */
+       for (j = 0; j < ARRAY_SIZE(vht80); j++) {
+               if (freq->channel >= vht80[j] &&
+                   freq->channel < vht80[j] + 16)
+                       break;
+       }
+
+       if (j == ARRAY_SIZE(vht80))
+               return;
+
+       for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
+               struct hostapd_channel_data *chan;
+
+               chan = hw_get_channel_chan(mode, i, NULL);
+               if (!chan)
+                       return;
+
+               /* Back to HT configuration if channel not usable */
+               if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+                       return;
+       }
+
+       if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
+                                   freq->channel, freq->ht_enabled,
+                                   vht_freq.vht_enabled,
+                                   freq->sec_channel_offset,
+                                   VHT_CHANWIDTH_80MHZ,
+                                   vht80[j] + 6, 0, 0) != 0)
+               return;
+
+       *freq = vht_freq;
+
+       wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
+                  freq->center_freq1, freq->center_freq2, freq->bandwidth);
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 {
        struct wpa_connect_work *cwork = work->ctx;
@@ -1632,7 +1967,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        wpa_s->connect_work = work;
 
-       if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
+       if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
+           wpas_network_disabled(wpa_s, ssid)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
                wpas_connect_work_done(wpa_s);
                return;
@@ -1681,7 +2017,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
-       wpa_supplicant_cancel_sched_scan(wpa_s);
+       if (!wpa_s->pno)
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+
        wpa_supplicant_cancel_scan(wpa_s);
 
        /* Starting new association, so clear the possibly used WPA IE from the
@@ -1715,7 +2053,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        (ssid->proto & WPA_PROTO_RSN);
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            ssid, try_opportunistic) == 0)
-                       eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+                       eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_ie, &wpa_ie_len)) {
@@ -1842,6 +2180,30 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                }
        }
 
+       if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+               struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+               size_t len;
+
+               len = sizeof(wpa_ie) - wpa_ie_len;
+               if (wpabuf_len(buf) <= len) {
+                       os_memcpy(wpa_ie + wpa_ie_len,
+                                 wpabuf_head(buf), wpabuf_len(buf));
+                       wpa_ie_len += wpabuf_len(buf);
+               }
+       }
+
+#ifdef CONFIG_FST
+       if (wpa_s->fst_ies) {
+               int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
+
+               if (wpa_ie_len + fst_ies_len <= sizeof(wpa_ie)) {
+                       os_memcpy(wpa_ie + wpa_ie_len,
+                                 wpabuf_head(wpa_s->fst_ies), fst_ies_len);
+                       wpa_ie_len += fst_ies_len;
+               }
+       }
+#endif /* CONFIG_FST */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = wpa_s->pairwise_cipher;
@@ -1907,25 +2269,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        /* Initial frequency for IBSS/mesh */
        if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
-           ssid->frequency > 0 && params.freq.freq == 0) {
-               enum hostapd_hw_mode hw_mode;
-               u8 channel;
-
-               params.freq.freq = ssid->frequency;
-
-               hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
-               for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
-                       if (wpa_s->hw.modes[i].mode == hw_mode) {
-                               struct hostapd_hw_modes *mode;
-
-                               mode = &wpa_s->hw.modes[i];
-                               params.freq.ht_enabled = ht_supported(mode);
-                               break;
-                       }
-               }
-       }
+           ssid->frequency > 0 && params.freq.freq == 0)
+               ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
 
        if (ssid->mode == WPAS_MODE_IBSS) {
+               params.fixed_freq = ssid->fixed_freq;
                if (ssid->beacon_int)
                        params.beacon_int = ssid->beacon_int;
                else
@@ -1959,7 +2307,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        if (wpa_s->conf->key_mgmt_offload) {
                if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
                    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
-                   params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+                   params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+                   params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
                        params.req_key_mgmt_offload =
                                ssid->proactive_key_caching < 0 ?
                                wpa_s->conf->okc : ssid->proactive_key_caching;
@@ -1976,9 +2325,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-       params.mgmt_frame_protection =
-               ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-               wpa_s->conf->pmf : ssid->ieee80211w;
+       params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
        if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
                const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
                struct wpa_ie_data ie;
@@ -2012,7 +2359,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
        params.vhtcaps = &vhtcaps;
        params.vhtcaps_mask = &vhtcaps_mask;
-       wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+       wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_VHT_OVERRIDES */
 
 #ifdef CONFIG_P2P
@@ -2104,7 +2451,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
        old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = ssid;
-       wpa_s->current_bss = bss;
+       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+               wpa_s->current_bss = bss;
        wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
        wpa_supplicant_initiate_eapol(wpa_s);
        if (old_ssid != wpa_s->current_ssid)
@@ -2226,15 +2574,20 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
        } else
                wpa_supplicant_enable_one_network(wpa_s, ssid);
 
-       if (wpa_s->reassociate && !wpa_s->disconnected) {
+       if (wpa_s->reassociate && !wpa_s->disconnected &&
+           (!wpa_s->current_ssid ||
+            wpa_s->wpa_state == WPA_DISCONNECTED ||
+            wpa_s->wpa_state == WPA_SCANNING)) {
                if (wpa_s->sched_scanning) {
                        wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
                                   "new network to scan filters");
                        wpa_supplicant_cancel_sched_scan(wpa_s);
                }
 
-               if (wpa_supplicant_fast_associate(wpa_s) != 1)
+               if (wpa_supplicant_fast_associate(wpa_s) != 1) {
+                       wpa_s->scan_req = NORMAL_SCAN_REQ;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
+               }
        }
 }
 
@@ -2307,6 +2660,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        int disconnected = 0;
 
        if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+               if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                       wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                disconnected = 1;
@@ -2345,6 +2700,13 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
                wpa_s->connect_without_scan =
                        (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+
+               /*
+                * Don't optimize next scan freqs since a new ESS has been
+                * selected.
+                */
+               os_free(wpa_s->next_scan_freqs);
+               wpa_s->next_scan_freqs = NULL;
        } else {
                wpa_s->connect_without_scan = NULL;
        }
@@ -2352,8 +2714,11 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
 
-       if (wpa_supplicant_fast_associate(wpa_s) != 1)
+       if (wpa_s->connect_without_scan ||
+           wpa_supplicant_fast_associate(wpa_s) != 1) {
+               wpa_s->scan_req = NORMAL_SCAN_REQ;
                wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+       }
 
        if (ssid)
                wpas_notify_network_selected(wpa_s, ssid);
@@ -2428,6 +2793,11 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
        if (ap_scan < 0 || ap_scan > 2)
                return -1;
 
+       if (ap_scan == 2 && os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
+               wpa_printf(MSG_INFO,
+                          "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
+       }
+
 #ifdef ANDROID
        if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
            wpa_s->wpa_state >= WPA_ASSOCIATING &&
@@ -2567,7 +2937,7 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
 struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 {
        struct wpa_ssid *entry;
-       u8 ssid[MAX_SSID_LEN];
+       u8 ssid[SSID_MAX_LEN];
        int res;
        size_t ssid_len;
        u8 bssid[ETH_ALEN];
@@ -2772,12 +3142,36 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
            (wpa_s->current_ssid == NULL ||
             wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
                /* Timeout for completing IEEE 802.1X and WPA authentication */
-               wpa_supplicant_req_auth_timeout(
-                       wpa_s,
-                       (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-                        wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
-                        wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
-                       70 : 10, 0);
+               int timeout = 10;
+
+               if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+                   wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
+                   wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+                       /* Use longer timeout for IEEE 802.1X/EAP */
+                       timeout = 70;
+               }
+
+#ifdef CONFIG_WPS
+               if (wpa_s->current_ssid && wpa_s->current_bss &&
+                   (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+                   eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
+                       /*
+                        * Use shorter timeout if going through WPS AP iteration
+                        * for PIN config method with an AP that does not
+                        * advertise Selected Registrar.
+                        */
+                       struct wpabuf *wps_ie;
+
+                       wps_ie = wpa_bss_get_vendor_ie_multi(
+                               wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
+                       if (wps_ie &&
+                           !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
+                               timeout = 10;
+                       wpabuf_free(wps_ie);
+               }
+#endif /* CONFIG_WPS */
+
+               wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
        }
        wpa_s->eapol_received++;
 
@@ -2822,15 +3216,9 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 
 int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 {
-       if (wpa_s->driver->send_eapol) {
-               const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
-               if (addr)
-                       os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-       } else if ((!wpa_s->p2p_mgmt ||
-                   !(wpa_s->drv_flags &
-                     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
-                  !(wpa_s->drv_flags &
-                    WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+       if ((!wpa_s->p2p_mgmt ||
+            !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
                l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = l2_packet_init(wpa_s->ifname,
                                           wpa_drv_get_mac_addr(wpa_s),
@@ -2904,11 +3292,9 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        if (wpa_s->bridge_ifname[0]) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
                        "interface '%s'", wpa_s->bridge_ifname);
-               wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
-                                             wpa_s->own_addr,
-                                             ETH_P_EAPOL,
-                                             wpa_supplicant_rx_eapol_bridge,
-                                             wpa_s, 1);
+               wpa_s->l2_br = l2_packet_init_bridge(
+                       wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+                       ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
                if (wpa_s->l2_br == NULL) {
                        wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
                                "connection for the bridge interface '%s'",
@@ -2917,6 +3303,12 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                }
        }
 
+       if (wpa_s->conf->ap_scan == 2 &&
+           os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
+               wpa_printf(MSG_INFO,
+                          "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
+       }
+
        wpa_clear_keys(wpa_s, NULL);
 
        /* Make sure that TKIP countermeasures are not left enabled (could
@@ -2934,12 +3326,14 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        interface_count = 0;
                }
+#ifndef ANDROID
                if (!wpa_s->p2p_mgmt &&
                    wpa_supplicant_delayed_sched_scan(wpa_s,
                                                      interface_count % 3,
                                                      100000))
                        wpa_supplicant_req_scan(wpa_s, interface_count % 3,
                                                100000);
+#endif /* ANDROID */
                interface_count++;
        } else
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -2955,7 +3349,8 @@ static int wpa_supplicant_daemon(const char *pid_file)
 }
 
 
-static struct wpa_supplicant * wpa_supplicant_alloc(void)
+static struct wpa_supplicant *
+wpa_supplicant_alloc(struct wpa_supplicant *parent)
 {
        struct wpa_supplicant *wpa_s;
 
@@ -2965,7 +3360,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s->scan_req = INITIAL_SCAN_REQ;
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
-       wpa_s->parent = wpa_s;
+       wpa_s->parent = parent ? parent : wpa_s;
        wpa_s->sched_scanning = 0;
 
        return wpa_s;
@@ -3207,10 +3602,6 @@ void wpa_supplicant_apply_vht_overrides(
 {
        struct ieee80211_vht_capabilities *vhtcaps;
        struct ieee80211_vht_capabilities *vhtcaps_mask;
-#ifdef CONFIG_HT_OVERRIDES
-       int max_ampdu;
-       const u32 max_ampdu_mask = VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
-#endif /* CONFIG_HT_OVERRIDES */
 
        if (!ssid)
                return;
@@ -3228,9 +3619,12 @@ void wpa_supplicant_apply_vht_overrides(
 
 #ifdef CONFIG_HT_OVERRIDES
        /* if max ampdu is <= 3, we have to make the HT cap the same */
-       if (ssid->vht_capa_mask & max_ampdu_mask) {
-               max_ampdu = (ssid->vht_capa & max_ampdu_mask) >>
-                       find_first_bit(max_ampdu_mask);
+       if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
+               int max_ampdu;
+
+               max_ampdu = (ssid->vht_capa &
+                            VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
+                       VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
 
                max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
                wpa_set_ampdu_factor(wpa_s,
@@ -3340,6 +3734,124 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifdef CONFIG_FST
+
+static const u8 * wpas_fst_get_bssid_cb(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       return (is_zero_ether_addr(wpa_s->bssid) ||
+               wpa_s->wpa_state != WPA_COMPLETED) ? NULL : wpa_s->bssid;
+}
+
+
+static void wpas_fst_get_channel_info_cb(void *ctx,
+                                        enum hostapd_hw_mode *hw_mode,
+                                        u8 *channel)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (wpa_s->current_bss) {
+               *hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq,
+                                                 channel);
+       } else if (wpa_s->hw.num_modes) {
+               *hw_mode = wpa_s->hw.modes[0].mode;
+       } else {
+               WPA_ASSERT(0);
+               *hw_mode = 0;
+       }
+}
+
+
+static int wpas_fst_get_hw_modes(void *ctx, struct hostapd_hw_modes **modes)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       *modes = wpa_s->hw.modes;
+       return wpa_s->hw.num_modes;
+}
+
+
+static void wpas_fst_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpa_hexdump_buf(MSG_DEBUG, "FST: Set IEs", fst_ies);
+       wpa_s->fst_ies = fst_ies;
+}
+
+
+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);
+       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),
+                                  0);
+}
+
+
+static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
+       return wpa_s->received_mb_ies;
+}
+
+
+static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
+                                    const u8 *buf, size_t size)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       struct mb_ies_info info;
+
+       WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
+
+       if (!mb_ies_info_by_ies(&info, buf, size)) {
+               wpabuf_free(wpa_s->received_mb_ies);
+               wpa_s->received_mb_ies = mb_ies_by_info(&info);
+       }
+}
+
+
+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;
+
+       *get_ctx = NULL;
+       if (!is_zero_ether_addr(wpa_s->bssid))
+               return (wpa_s->received_mb_ies || !mb_only) ?
+                       wpa_s->bssid : NULL;
+       return NULL;
+}
+
+
+const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
+                                 Boolean mb_only)
+{
+       return NULL;
+}
+
+void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
+                                      struct fst_wpa_obj *iface_obj)
+{
+       iface_obj->ctx              = wpa_s;
+       iface_obj->get_bssid        = wpas_fst_get_bssid_cb;
+       iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
+       iface_obj->get_hw_modes     = wpas_fst_get_hw_modes;
+       iface_obj->set_ies          = wpas_fst_set_ies_cb;
+       iface_obj->send_action      = wpas_fst_send_action_cb;
+       iface_obj->get_mb_ie        = wpas_fst_get_mb_ie_cb;
+       iface_obj->update_mb_ie     = wpas_fst_update_mb_ie_cb;
+       iface_obj->get_peer_first   = wpas_fst_get_peer_first;
+       iface_obj->get_peer_next    = wpas_fst_get_peer_next;
+}
+#endif /* CONFIG_FST */
+
 static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
                                    const struct wpa_driver_capa *capa)
 {
@@ -3431,7 +3943,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
 
        wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
                              radio_list);
-       if (wpa_s && wpa_s->external_scan_running) {
+       if (wpa_s && wpa_s->radio->external_scan_running) {
                wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
                return;
        }
@@ -3510,6 +4022,11 @@ void radio_work_check_next(struct wpa_supplicant *wpa_s)
 
        if (dl_list_empty(&radio->work))
                return;
+       if (wpa_s->ext_work_in_progress) {
+               wpa_printf(MSG_DEBUG,
+                          "External radio work in progress - delay start of pending item");
+               return;
+       }
        eloop_cancel_timeout(radio_start_next_work, radio, NULL);
        eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
 }
@@ -3794,6 +4311,23 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
                                                      &wpa_s->hw.num_modes,
                                                      &wpa_s->hw.flags);
+       if (wpa_s->hw.modes) {
+               u16 i;
+
+               for (i = 0; i < wpa_s->hw.num_modes; i++) {
+                       if (wpa_s->hw.modes[i].vht_capab) {
+                               wpa_s->hw_capab = CAPAB_VHT;
+                               break;
+                       }
+
+                       if (wpa_s->hw.modes[i].ht_capab &
+                           HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+                               wpa_s->hw_capab = CAPAB_HT40;
+                       else if (wpa_s->hw.modes[i].ht_capab &&
+                                wpa_s->hw_capab == CAPAB_NO_HT_VHT)
+                               wpa_s->hw_capab = CAPAB_HT;
+               }
+       }
 
        capa_res = wpa_drv_get_capa(wpa_s, &capa);
        if (capa_res == 0) {
@@ -3815,6 +4349,13 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                wpa_s->num_multichan_concurrent =
                        capa.num_multichan_concurrent;
                wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+
+               if (capa.mac_addr_rand_scan_supported)
+                       wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
+               if (wpa_s->sched_scan_supported &&
+                   capa.mac_addr_rand_sched_scan_supported)
+                       wpa_s->mac_addr_rand_supported |=
+                               (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
        }
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
@@ -3849,6 +4390,28 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+#ifdef CONFIG_FST
+       if (wpa_s->conf->fst_group_id) {
+               struct fst_iface_cfg cfg;
+               struct fst_wpa_obj iface_obj;
+
+               fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
+               os_strlcpy(cfg.group_id, wpa_s->conf->fst_group_id,
+                          sizeof(cfg.group_id));
+               cfg.priority = wpa_s->conf->fst_priority;
+               cfg.llt = wpa_s->conf->fst_llt;
+
+               wpa_s->fst = fst_attach(wpa_s->ifname, wpa_s->own_addr,
+                                       &iface_obj, &cfg);
+               if (!wpa_s->fst) {
+                       wpa_msg(wpa_s, MSG_ERROR,
+                               "FST: Cannot attach iface %s to group %s",
+                               wpa_s->ifname, cfg.group_id);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_FST */
+
        if (wpas_wps_init(wpa_s))
                return -1;
 
@@ -3957,6 +4520,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
        wpas_ctrl_radio_work_flush(wpa_s);
        radio_remove_interface(wpa_s);
 
+#ifdef CONFIG_FST
+       if (wpa_s->fst) {
+               fst_detach(wpa_s->fst);
+               wpa_s->fst = NULL;
+       }
+       if (wpa_s->received_mb_ies) {
+               wpabuf_free(wpa_s->received_mb_ies);
+               wpa_s->received_mb_ies = NULL;
+       }
+#endif /* CONFIG_FST */
+
        if (wpa_s->drv_priv)
                wpa_drv_deinit(wpa_s);
 
@@ -3983,6 +4557,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
                wpa_s->conf = NULL;
        }
 
+       os_free(wpa_s->ssids_from_scan_req);
+
        os_free(wpa_s);
 }
 
@@ -3991,6 +4567,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
  * wpa_supplicant_add_iface - Add a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * @iface: Interface configuration options
+ * @parent: Parent interface or %NULL to assign new interface as parent
  * Returns: Pointer to the created interface or %NULL on failure
  *
  * This function is used to add new network interfaces for %wpa_supplicant.
@@ -4000,7 +4577,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
  * e.g., when a hotplug network adapter is inserted.
  */
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
-                                                struct wpa_interface *iface)
+                                                struct wpa_interface *iface,
+                                                struct wpa_supplicant *parent)
 {
        struct wpa_supplicant *wpa_s;
        struct wpa_interface t_iface;
@@ -4009,7 +4587,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        if (global == NULL || iface == NULL)
                return NULL;
 
-       wpa_s = wpa_supplicant_alloc();
+       wpa_s = wpa_supplicant_alloc(parent);
        if (wpa_s == NULL)
                return NULL;
 
@@ -4056,8 +4634,10 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
 
 #ifdef CONFIG_P2P
        if (wpa_s->global->p2p == NULL &&
+           !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
            (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
-           wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+           wpas_p2p_add_p2pdev_interface(
+                   wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
                wpa_printf(MSG_INFO,
                           "P2P: Failed to enable P2P Device interface");
                /* Try to continue without. P2P will be disabled. */
@@ -4084,6 +4664,10 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
                                int terminate)
 {
        struct wpa_supplicant *prev;
+#ifdef CONFIG_MESH
+       unsigned int mesh_if_created = wpa_s->mesh_if_created;
+       char *ifname = NULL;
+#endif /* CONFIG_MESH */
 
        /* Remove interface from the global list of interfaces */
        prev = global->ifaces;
@@ -4099,12 +4683,30 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
 
+#ifdef CONFIG_MESH
+       if (mesh_if_created) {
+               ifname = os_strdup(wpa_s->ifname);
+               if (ifname == NULL) {
+                       wpa_dbg(wpa_s, MSG_ERROR,
+                               "mesh: Failed to malloc ifname");
+                       return -1;
+               }
+       }
+#endif /* CONFIG_MESH */
+
        if (global->p2p_group_formation == wpa_s)
                global->p2p_group_formation = NULL;
        if (global->p2p_invite_group == wpa_s)
                global->p2p_invite_group = NULL;
        wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
 
+#ifdef CONFIG_MESH
+       if (mesh_if_created) {
+               wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+               os_free(ifname);
+       }
+#endif /* CONFIG_MESH */
+
        return 0;
 }
 
@@ -4161,6 +4763,33 @@ static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
 #endif /* CONFIG_NO_WPA_MSG */
 
 
+#ifndef WPA_SUPPLICANT_CLEANUP_INTERVAL
+#define WPA_SUPPLICANT_CLEANUP_INTERVAL 10
+#endif /* WPA_SUPPLICANT_CLEANUP_INTERVAL */
+
+/* Periodic cleanup tasks */
+static void wpas_periodic(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_global *global = eloop_ctx;
+       struct wpa_supplicant *wpa_s;
+
+       eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+                              wpas_periodic, global, NULL);
+
+#ifdef CONFIG_P2P
+       if (global->p2p)
+               p2p_expire_peers(global->p2p);
+#endif /* CONFIG_P2P */
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
+#ifdef CONFIG_AP
+               ap_periodic(wpa_s);
+#endif /* CONFIG_AP */
+       }
+}
+
+
 /**
  * wpa_supplicant_init - Initialize %wpa_supplicant
  * @params: Parameters for %wpa_supplicant
@@ -4189,7 +4818,10 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
 #endif /* CONFIG_NO_WPA_MSG */
 
-       wpa_debug_open_file(params->wpa_debug_file_path);
+       if (params->wpa_debug_file_path)
+               wpa_debug_open_file(params->wpa_debug_file_path);
+       else
+               wpa_debug_setup_stdout();
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
        if (params->wpa_debug_tracing) {
@@ -4232,6 +4864,11 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params->override_ctrl_interface)
                global->params.override_ctrl_interface =
                        os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_P2P
+       if (params->conf_p2p_dev)
+               global->params.conf_p2p_dev =
+                       os_strdup(params->conf_p2p_dev);
+#endif /* CONFIG_P2P */
        wpa_debug_level = global->params.wpa_debug_level =
                params->wpa_debug_level;
        wpa_debug_show_keys = global->params.wpa_debug_show_keys =
@@ -4267,7 +4904,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                wpa_supplicant_deinit(global);
                return NULL;
        }
-       global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+       global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
        if (global->drv_priv == NULL) {
                wpa_supplicant_deinit(global);
                return NULL;
@@ -4281,6 +4918,9 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        }
 #endif /* CONFIG_WIFI_DISPLAY */
 
+       eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+                              wpas_periodic, global, NULL);
+
        return global;
 }
 
@@ -4332,6 +4972,8 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        if (global == NULL)
                return;
 
+       eloop_cancel_timeout(wpas_periodic, global, NULL);
+
 #ifdef CONFIG_WIFI_DISPLAY
        wifi_display_deinit(global);
 #endif /* CONFIG_WIFI_DISPLAY */
@@ -4368,6 +5010,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.ctrl_interface_group);
        os_free(global->params.override_driver);
        os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_P2P
+       os_free(global->params.conf_p2p_dev);
+#endif /* CONFIG_P2P */
 
        os_free(global->p2p_disallow_freq.range);
        os_free(global->p2p_go_avoid_freq.range);
@@ -4426,7 +5071,7 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
        int *freqs;
        int num_freqs = 0;
 
-       freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+       freqs = os_calloc(max_freqs + 1, sizeof(int));
        if (freqs == NULL)
                return NULL;
 
@@ -4466,11 +5111,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
         */
        eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
 
+       /*
+        * There is no point in blacklisting the AP if this event is
+        * generated based on local request to disconnect.
+        */
+       if (wpa_s->own_disconnect_req) {
+               wpa_s->own_disconnect_req = 0;
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Ignore connection failure due to local request to disconnect");
+               return;
+       }
        if (wpa_s->disconnected) {
-               /*
-                * There is no point in blacklisting the AP if this event is
-                * generated based on local request to disconnect.
-                */
                wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
                        "indication since interface has been put into "
                        "disconnected state");
@@ -4621,6 +5272,15 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
                break;
+       case WPA_CTRL_REQ_PSK_PASSPHRASE:
+               if (wpa_config_set(ssid, "psk", value, 0) < 0)
+                       return -1;
+               ssid->mem_only_psk = 1;
+               if (ssid->passphrase)
+                       wpa_config_update_psk(ssid);
+               if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
                return -1;
@@ -4640,13 +5300,16 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        int i;
        unsigned int drv_enc;
 
+       if (wpa_s->p2p_mgmt)
+               return 1; /* no normal network profiles on p2p_mgmt interface */
+
        if (ssid == NULL)
                return 1;
 
        if (ssid->disabled)
                return 1;
 
-       if (wpa_s && wpa_s->drv_capa_known)
+       if (wpa_s->drv_capa_known)
                drv_enc = wpa_s->drv_enc;
        else
                drv_enc = (unsigned int) -1;
@@ -4665,13 +5328,38 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        }
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
-           (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
+           (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
+           !ssid->mem_only_psk)
                return 1;
 
        return 0;
 }
 
 
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_IEEE80211W
+       if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+               if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
+                   !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
+                       /*
+                        * Driver does not support BIP -- ignore pmf=1 default
+                        * since the connection with PMF would fail and the
+                        * configuration does not require PMF to be enabled.
+                        */
+                       return NO_MGMT_FRAME_PROTECTION;
+               }
+
+               return wpa_s->conf->pmf;
+       }
+
+       return ssid->ieee80211w;
+#else /* CONFIG_IEEE80211W */
+       return NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
@@ -4815,6 +5503,8 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
 
        if (wpa_supplicant_fast_associate(wpa_s) != 1)
                wpa_supplicant_req_scan(wpa_s, 0, 0);
+       else
+               wpa_s->reattach = 0;
 }
 
 
@@ -4861,7 +5551,8 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
                        continue;
 
                if (ifs->current_ssid->mode == WPAS_MODE_AP ||
-                   ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+                   ifs->current_ssid->mode == WPAS_MODE_P2P_GO ||
+                   ifs->current_ssid->mode == WPAS_MODE_MESH)
                        freq = ifs->current_ssid->frequency;
                else if (wpa_drv_get_bssid(ifs, bssid) == 0)
                        freq = ifs->assoc_freq;
@@ -4992,6 +5683,13 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 }
 
 
+#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
+
 /**
  * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
  * @wpa_s: Pointer to wpa_supplicant