Delay AP selection if all networks are temporarily disabled
[mech_eap.git] / wpa_supplicant / wpa_supplicant.c
index 0afc9ab..6f5fbad 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,6 +33,7 @@
 #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 "blacklist.h"
 #include "wpas_glue.h"
 #include "hs20_supplicant.h"
 #include "wnm_sta.h"
 #include "wpas_kay.h"
+#include "mesh.h"
 
 const char *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 =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -131,6 +133,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. */
@@ -174,7 +177,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;
 }
 
 
@@ -297,10 +302,28 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
                wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
                wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
        eapol_conf.external_sim = wpa_s->conf->external_sim;
+
+#ifdef CONFIG_WPS
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+               eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
+               if (wpa_s->current_bss) {
+                       struct wpabuf *ie;
+                       ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+                                                        WPS_IE_VENDOR_TYPE);
+                       if (ie) {
+                               if (wps_is_20(ie))
+                                       eapol_conf.wps |=
+                                               EAPOL_PEER_IS_WPS20_AP;
+                               wpabuf_free(ie);
+                       }
+               }
+       }
+#endif /* CONFIG_WPS */
+
        eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-#endif /* IEEE8021X_EAPOL */
 
        ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* IEEE8021X_EAPOL */
 }
 
 
@@ -375,6 +398,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
 
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
+       int i;
+
        bgscan_deinit(wpa_s);
        autoscan_deinit(wpa_s);
        scard_deinit(wpa_s->scard);
@@ -387,6 +412,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                l2_packet_deinit(wpa_s->l2_br);
                wpa_s->l2_br = NULL;
        }
+#ifdef CONFIG_TESTING_OPTIONS
+       l2_packet_deinit(wpa_s->l2_test);
+       wpa_s->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
                struct wpa_ssid *ssid;
@@ -400,11 +429,6 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        os_free(wpa_s->confanother);
        wpa_s->confanother = NULL;
 
-#ifdef CONFIG_P2P
-       os_free(wpa_s->conf_p2p_dev);
-       wpa_s->conf_p2p_dev = NULL;
-#endif /* CONFIG_P2P */
-
        wpa_sm_set_eapol(wpa_s->wpa, NULL);
        eapol_sm_deinit(wpa_s->eapol);
        wpa_s->eapol = NULL;
@@ -415,6 +439,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;
@@ -431,6 +456,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);
@@ -464,6 +491,8 @@ 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);
+
        gas_query_deinit(wpa_s->gas);
        wpa_s->gas = NULL;
 
@@ -498,6 +527,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_HS20
        hs20_deinit(wpa_s);
 #endif /* CONFIG_HS20 */
+
+       for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+               wpabuf_free(wpa_s->vendor_elem[i]);
+               wpa_s->vendor_elem[i] = NULL;
+       }
+
+       wmm_ac_notify_disassoc(wpa_s);
 }
 
 
@@ -730,6 +766,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);
 
@@ -833,13 +872,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 
        eapol_sm_invalidate_cached_session(wpa_s->eapol);
        if (wpa_s->current_ssid) {
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
        }
 
        /*
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
-        * pkcs11_engine_path, pkcs11_module_path.
+        * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
         */
        if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
                /*
@@ -925,9 +965,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");
@@ -976,7 +1014,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)) {
@@ -994,6 +1032,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)
@@ -1067,6 +1139,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;
@@ -1120,8 +1204,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) {
@@ -1147,8 +1230,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)) {
@@ -1157,7 +1239,7 @@ 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);
+               wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
 #ifndef CONFIG_NO_PBKDF2
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
@@ -1166,7 +1248,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                    4096, psk, PMK_LEN);
                        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                                        psk, PMK_LEN);
-                       wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                       wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                       os_memset(psk, 0, sizeof(psk));
                }
 #endif /* CONFIG_NO_PBKDF2 */
 #ifdef CONFIG_EXT_PASSWORD
@@ -1202,7 +1285,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
                                                "external passphrase)",
                                                psk, PMK_LEN);
-                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               os_memset(psk, 0, sizeof(psk));
                        } else
 #endif /* CONFIG_NO_PBKDF2 */
                        if (wpabuf_len(pw) == 2 * PMK_LEN) {
@@ -1213,7 +1297,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        ext_password_free(pw);
                                        return -1;
                                }
-                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               os_memset(psk, 0, sizeof(psk));
                        } else {
                                wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
                                        "PSK available");
@@ -1372,6 +1457,68 @@ void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
 }
 
 
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+{
+       struct os_reltime now;
+       u8 addr[ETH_ALEN];
+
+       os_get_reltime(&now);
+       if (wpa_s->last_mac_addr_style == style &&
+           wpa_s->last_mac_addr_change.sec != 0 &&
+           !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
+                               wpa_s->conf->rand_addr_lifetime)) {
+               wpa_msg(wpa_s, MSG_DEBUG,
+                       "Previously selected random MAC address has not yet expired");
+               return 0;
+       }
+
+       switch (style) {
+       case 1:
+               if (random_mac_addr(addr) < 0)
+                       return -1;
+               break;
+       case 2:
+               os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
+               if (random_mac_addr_keep_oui(addr) < 0)
+                       return -1;
+               break;
+       default:
+               return -1;
+       }
+
+       if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Failed to set random MAC address");
+               return -1;
+       }
+
+       os_get_reltime(&wpa_s->last_mac_addr_change);
+       wpa_s->mac_addr_changed = 1;
+       wpa_s->last_mac_addr_style = style;
+
+       if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Could not update MAC address information");
+               return -1;
+       }
+
+       wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+               MAC2STR(addr));
+
+       return 0;
+}
+
+
+int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
+           !wpa_s->conf->preassoc_mac_addr)
+               return 0;
+
+       return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
 
 /**
@@ -1386,6 +1533,41 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                              struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
        struct wpa_connect_work *cwork;
+       int rand_style;
+
+       if (ssid->mac_addr == -1)
+               rand_style = wpa_s->conf->mac_addr;
+       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;
+               wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+       } else if (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");
+                       return;
+               }
+               wpa_s->mac_addr_changed = 0;
+               if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "Could not update MAC address information");
+                       return;
+               }
+               wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+       }
+       wpa_s->last_ssid = ssid;
 
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1414,6 +1596,31 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (ssid->mode == WPAS_MODE_MESH) {
+#ifdef CONFIG_MESH
+               if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "Driver does not support mesh mode");
+                       return;
+               }
+               if (bss)
+                       ssid->frequency = bss->freq;
+               if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+                       wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
+                       return;
+               }
+               wpa_s->current_bss = bss;
+               wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
+                            "ssid=\"%s\" id=%d",
+                            wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                            ssid->id);
+#else /* CONFIG_MESH */
+               wpa_msg(wpa_s, MSG_ERROR,
+                       "mesh mode support not included in the build");
+#endif /* CONFIG_MESH */
+               return;
+       }
+
 #ifdef CONFIG_TDLS
        if (bss)
                wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1450,6 +1657,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;
@@ -1488,7 +1916,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        wpa_s->connect_work = work;
 
-       if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
+       if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, 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;
@@ -1497,7 +1925,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
        wpa_s->eap_expected_failure = 0;
-       if (bss && !wpas_driver_bss_selection(wpa_s)) {
+       if (bss &&
+           (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
 #ifdef CONFIG_IEEE80211R
                const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1525,6 +1954,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                /* Use ap_scan==1 style network selection to find the network
                 */
+               wpas_connect_work_done(wpa_s);
                wpa_s->scan_req = MANUAL_SCAN_REQ;
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1569,12 +1999,13 @@ 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)) {
                        wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
                                "key management and encryption suites");
+                       wpas_connect_work_done(wpa_s);
                        return;
                }
        } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
@@ -1594,6 +2025,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
                                "key management and encryption suites (no "
                                "scan results)");
+                       wpas_connect_work_done(wpa_s);
                        return;
                }
 #ifdef CONFIG_WPS
@@ -1694,6 +2126,18 @@ 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);
+               }
+       }
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = wpa_s->pairwise_cipher;
@@ -1742,7 +2186,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                                   MAC2STR(bss->bssid), bss->freq,
                                   ssid->bssid_set);
                        params.bssid = bss->bssid;
-                       params.freq = bss->freq;
+                       params.freq.freq = bss->freq;
                }
                params.bssid_hint = bss->bssid;
                params.freq_hint = bss->freq;
@@ -1757,11 +2201,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                params.fixed_bssid = 1;
        }
 
-       if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
-           params.freq == 0)
-               params.freq = ssid->frequency; /* Initial channel for IBSS */
+       /* Initial frequency for IBSS/mesh */
+       if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+           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
@@ -1792,12 +2238,28 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.psk = ssid->psk;
        }
 
+       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_192)
+                       params.req_key_mgmt_offload =
+                               ssid->proactive_key_caching < 0 ?
+                               wpa_s->conf->okc : ssid->proactive_key_caching;
+               else
+                       params.req_key_mgmt_offload = 1;
+
+               if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+                    params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+                    params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+                   ssid->psk_set)
+                       params.psk = ssid->psk;
+       }
+
        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;
@@ -1831,7 +2293,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
@@ -1843,14 +2305,15 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        if (wpa_s->num_multichan_concurrent < 2) {
                int freq, num;
                num = get_shared_radio_freqs(wpa_s, &freq, 1);
-               if (num > 0 && freq > 0 && freq != params.freq) {
+               if (num > 0 && freq > 0 && freq != params.freq.freq) {
                        wpa_printf(MSG_DEBUG,
                                   "Assoc conflicting freq found (%d != %d)",
-                                  freq, params.freq);
-                       if (wpas_p2p_handle_frequency_conflicts(wpa_s,
-                                                               params.freq,
-                                                               ssid) < 0)
+                                  freq, params.freq.freq);
+                       if (wpas_p2p_handle_frequency_conflicts(
+                                   wpa_s, params.freq.freq, ssid) < 0) {
+                               wpas_connect_work_done(wpa_s);
                                return;
+                       }
                }
        }
 #endif /* CONFIG_P2P */
@@ -1935,6 +2398,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ssid *old_ssid;
 
+       wpas_connect_work_done(wpa_s);
        wpa_clear_keys(wpa_s, addr);
        old_ssid = wpa_s->current_ssid;
        wpa_supplicant_mark_disassoc(wpa_s);
@@ -1987,6 +2451,14 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
        wpa_tdls_teardown_peers(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_MESH
+       if (wpa_s->ifmsh) {
+               wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+                            wpa_s->ifname);
+               wpa_supplicant_leave_mesh(wpa_s);
+       }
+#endif /* CONFIG_MESH */
+
        if (addr) {
                wpa_drv_deauthenticate(wpa_s, addr, reason_code);
                os_memset(&event, 0, sizeof(event));
@@ -2116,6 +2588,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        int disconnected = 0;
 
        if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+               wpa_s->own_disconnect_req = 1;
                wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                disconnected = 1;
@@ -2152,12 +2625,24 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        if (ssid) {
                wpa_s->current_ssid = ssid;
                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;
        }
-       wpa_s->connect_without_scan = NULL;
+
        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_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
 
        if (ssid)
@@ -2627,15 +3112,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),
@@ -2654,6 +3133,8 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
                return -1;
        }
 
+       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
        return 0;
 }
 
@@ -2701,16 +3182,15 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
                MAC2STR(wpa_s->own_addr));
+       os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
        wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
 
        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'",
@@ -2736,12 +3216,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);
@@ -2757,7 +3239,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;
 
@@ -2767,7 +3250,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;
@@ -2835,7 +3318,7 @@ static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
                                 struct ieee80211_ht_capabilities *htcaps_mask,
                                 int disabled)
 {
-       u16 msk;
+       le16 msk;
 
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
 
@@ -2908,8 +3391,8 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
                                int disabled)
 {
        /* Masking these out disables HT40 */
-       u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
-                              HT_CAP_INFO_SHORT_GI40MHZ);
+       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);
 
@@ -2930,8 +3413,8 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
                               int disabled)
 {
        /* Masking these out disables SGI */
-       u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
-                              HT_CAP_INFO_SHORT_GI40MHZ);
+       le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
+                               HT_CAP_INFO_SHORT_GI40MHZ);
 
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
 
@@ -2952,7 +3435,7 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
                               int disabled)
 {
        /* Masking these out disables LDPC */
-       u16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
+       le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
 
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
 
@@ -2993,7 +3476,7 @@ void wpa_supplicant_apply_ht_overrides(
        wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
 
        if (ssid->ht40_intolerant) {
-               u16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
+               le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
                htcaps->ht_capabilities_info |= bit;
                htcaps_mask->ht_capabilities_info |= bit;
        }
@@ -3009,10 +3492,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;
@@ -3030,9 +3509,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,
@@ -3142,75 +3624,20 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
 }
 
 
-static int wpas_check_wowlan_trigger(const char *start, const char *trigger,
-                                    int capa_trigger, u8 *param_trigger)
-{
-       if (os_strcmp(start, trigger) != 0)
-               return 0;
-       if (!capa_trigger)
-               return 0;
-
-       *param_trigger = 1;
-       return 1;
-}
-
-
-int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
-                            struct wpa_driver_capa *capa)
+static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
+                                   const struct wpa_driver_capa *capa)
 {
-       struct wowlan_triggers triggers;
-       char *start, *end, *buf;
-       int last, ret;
+       struct wowlan_triggers *triggers;
+       int ret = 0;
 
        if (!wpa_s->conf->wowlan_triggers)
                return 0;
 
-       buf = os_strdup(wpa_s->conf->wowlan_triggers);
-       if (buf == NULL)
-               return -1;
-
-       os_memset(&triggers, 0, sizeof(triggers));
-
-#define CHECK_TRIGGER(trigger) \
-       wpas_check_wowlan_trigger(start, #trigger,                      \
-                                 capa->wowlan_triggers.trigger,        \
-                                 &triggers.trigger)
-
-       start = buf;
-       while (*start != '\0') {
-               while (isblank(*start))
-                       start++;
-               if (*start == '\0')
-                       break;
-               end = start;
-               while (!isblank(*end) && *end != '\0')
-                       end++;
-               last = *end == '\0';
-               *end = '\0';
-
-               if (!CHECK_TRIGGER(any) &&
-                   !CHECK_TRIGGER(disconnect) &&
-                   !CHECK_TRIGGER(magic_pkt) &&
-                   !CHECK_TRIGGER(gtk_rekey_failure) &&
-                   !CHECK_TRIGGER(eap_identity_req) &&
-                   !CHECK_TRIGGER(four_way_handshake) &&
-                   !CHECK_TRIGGER(rfkill_release)) {
-                       wpa_printf(MSG_DEBUG,
-                                  "Unknown/unsupported wowlan trigger '%s'",
-                                  start);
-                       ret = -1;
-                       goto out;
-               }
-
-               if (last)
-                       break;
-               start = end + 1;
+       triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
+       if (triggers) {
+               ret = wpa_drv_wowlan(wpa_s, triggers);
+               os_free(triggers);
        }
-#undef CHECK_TRIGGER
-
-       ret = wpa_drv_wowlan(wpa_s, &triggers);
-out:
-       os_free(buf);
        return ret;
 }
 
@@ -3288,7 +3715,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;
        }
@@ -3367,6 +3794,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);
 }
@@ -3454,17 +3886,18 @@ void radio_work_done(struct wpa_radio_work *work)
 }
 
 
-int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
+struct wpa_radio_work *
+radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
 {
        struct wpa_radio_work *work;
        struct wpa_radio *radio = wpa_s->radio;
 
        dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
                if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
-                       return 1;
+                       return work;
        }
 
-       return 0;
+       return NULL;
 }
 
 
@@ -3521,6 +3954,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
        struct wpa_driver_capa capa;
+       int capa_res;
 
        wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
                   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -3552,11 +3986,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                wpa_s->confanother = os_rel2abs_path(iface->confanother);
                wpa_config_read(wpa_s->confanother, wpa_s->conf);
 
-#ifdef CONFIG_P2P
-               wpa_s->conf_p2p_dev = os_rel2abs_path(iface->conf_p2p_dev);
-               wpa_config_read(wpa_s->conf_p2p_dev, wpa_s->conf);
-#endif /* CONFIG_P2P */
-
                /*
                 * Override ctrl_interface and driver_param if set on command
                 * line.
@@ -3654,11 +4083,31 @@ 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_drv_get_capa(wpa_s, &capa) == 0) {
+                       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) {
                wpa_s->drv_capa_known = 1;
                wpa_s->drv_flags = capa.flags;
                wpa_s->drv_enc = capa.enc;
+               wpa_s->drv_smps_modes = capa.smps_modes;
+               wpa_s->drv_rrm_flags = capa.rrm_flags;
                wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
                wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -3671,6 +4120,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                wpa_s->extended_capa_len = capa.extended_capa_len;
                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;
@@ -3745,7 +4202,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
         * Note: We don't restore/remove the triggers on shutdown (it doesn't
         * have effect anyway when the interface is down).
         */
-       if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+       if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
                return -1;
 
 #ifdef CONFIG_EAP_PROXY
@@ -3769,6 +4226,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        if (wpas_init_ext_pw(wpa_s) < 0)
                return -1;
 
+       wpas_rrm_reset(wpa_s);
+
        return 0;
 }
 
@@ -3776,6 +4235,26 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
                                        int notify, int terminate)
 {
+       struct wpa_global *global = wpa_s->global;
+       struct wpa_supplicant *iface, *prev;
+
+       if (wpa_s == wpa_s->parent)
+               wpas_p2p_group_remove(wpa_s, "*");
+
+       iface = global->ifaces;
+       while (iface) {
+               if (iface == wpa_s || iface->parent != wpa_s) {
+                       iface = iface->next;
+                       continue;
+               }
+               wpa_printf(MSG_DEBUG,
+                          "Remove remaining child interface %s from parent %s",
+                          iface->ifname, wpa_s->ifname);
+               prev = iface;
+               iface = iface->next;
+               wpa_supplicant_remove_iface(global, prev, terminate);
+       }
+
        wpa_s->disconnected = 1;
        if (wpa_s->drv_priv) {
                wpa_supplicant_deauthenticate(wpa_s,
@@ -3805,6 +4284,13 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
                wpa_s->ctrl_iface = NULL;
        }
 
+#ifdef CONFIG_MESH
+       if (wpa_s->ifmsh) {
+               wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+               wpa_s->ifmsh = NULL;
+       }
+#endif /* CONFIG_MESH */
+
        if (wpa_s->conf != NULL) {
                wpa_config_free(wpa_s->conf);
                wpa_s->conf = NULL;
@@ -3818,6 +4304,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.
@@ -3827,7 +4314,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;
@@ -3836,7 +4324,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;
 
@@ -3864,14 +4352,16 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                return NULL;
        }
 
-       /* Notify the control interfaces about new iface */
-       if (wpas_notify_iface_added(wpa_s)) {
-               wpa_supplicant_deinit_iface(wpa_s, 1, 0);
-               return NULL;
-       }
+       if (iface->p2p_mgmt == 0) {
+               /* Notify the control interfaces about new iface */
+               if (wpas_notify_iface_added(wpa_s)) {
+                       wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+                       return NULL;
+               }
 
-       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-               wpas_notify_network_added(wpa_s, ssid);
+               for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+                       wpas_notify_network_added(wpa_s, ssid);
+       }
 
        wpa_s->next = global->ifaces;
        global->ifaces = wpa_s;
@@ -3879,6 +4369,16 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p == NULL &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+               wpa_printf(MSG_INFO,
+                          "P2P: Failed to enable P2P Device interface");
+               /* Try to continue without. P2P will be disabled. */
+       }
+#endif /* CONFIG_P2P */
+
        return wpa_s;
 }
 
@@ -3899,6 +4399,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;
@@ -3914,12 +4418,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;
 }
 
@@ -4004,7 +4526,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) {
@@ -4082,7 +4607,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;
@@ -4220,7 +4745,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 }
 
 
-static void add_freq(int *freqs, int *num_freqs, int freq)
+void add_freq(int *freqs, int *num_freqs, int freq)
 {
        int i;
 
@@ -4241,7 +4766,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;
 
@@ -4281,11 +4806,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");
@@ -4395,7 +4926,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_PASSWORD:
-               os_free(eap->password);
+               bin_clear_free(eap->password, eap->password_len);
                eap->password = (u8 *) os_strdup(value);
                eap->password_len = os_strlen(value);
                eap->pending_req_password = 0;
@@ -4403,7 +4934,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
-               os_free(eap->new_password);
+               bin_clear_free(eap->new_password, eap->new_password_len);
                eap->new_password = (u8 *) os_strdup(value);
                eap->new_password_len = os_strlen(value);
                eap->pending_req_new_password = 0;
@@ -4411,14 +4942,14 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_PIN:
-               os_free(eap->pin);
+               str_clear_free(eap->pin);
                eap->pin = os_strdup(value);
                eap->pending_req_pin = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_OTP:
-               os_free(eap->otp);
+               bin_clear_free(eap->otp, eap->otp_len);
                eap->otp = (u8 *) os_strdup(value);
                eap->otp_len = os_strlen(value);
                os_free(eap->pending_req_otp);
@@ -4426,14 +4957,14 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                eap->pending_req_otp_len = 0;
                break;
        case WPA_CTRL_REQ_EAP_PASSPHRASE:
-               os_free(eap->private_key_passwd);
-               eap->private_key_passwd = (u8 *) os_strdup(value);
+               str_clear_free(eap->private_key_passwd);
+               eap->private_key_passwd = os_strdup(value);
                eap->pending_req_passphrase = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_SIM:
-               os_free(eap->external_sim_resp);
+               str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
                break;
        default:
@@ -4455,13 +4986,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;
@@ -4487,6 +5021,30 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 }
 
 
+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)
@@ -4622,6 +5180,7 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
 void wpas_request_connection(struct wpa_supplicant *wpa_s)
 {
        wpa_s->normal_scans = 0;
+       wpa_s->scan_req = NORMAL_SCAN_REQ;
        wpa_supplicant_reinit_autoscan(wpa_s);
        wpa_s->extra_blacklist_count = 0;
        wpa_s->disconnected = 0;
@@ -4629,6 +5188,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;
 }
 
 
@@ -4726,3 +5287,268 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 
        return num;
 }
+
+
+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
+
+/**
+ * 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.
+ * @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 *ssid,
+                                      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));
+       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);
+       }
+
+       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;
+}
+
+
+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);
+}