]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
Document wpa_s->scan_req
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 09b164022afcfee5a9c37b266c7ec4026fd1a854..a5bd58ae5a18dd272ae4d21ef77a4ea8b5762334 100644 (file)
@@ -21,6 +21,7 @@
 #include "rsn_supp/wpa.h"
 #include "eloop.h"
 #include "config.h"
+#include "utils/ext_password.h"
 #include "l2_packet/l2_packet.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "gas_query.h"
 #include "ap.h"
 #include "p2p_supplicant.h"
+#include "wifi_display.h"
 #include "notify.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "bss.h"
 #include "scan.h"
 #include "offchannel.h"
@@ -152,6 +155,11 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
                keylen = 16;
                alg = WPA_ALG_CCMP;
                break;
+       case WPA_CIPHER_GCMP:
+               os_memcpy(key, ssid->psk, 16);
+               keylen = 16;
+               alg = WPA_ALG_GCMP;
+               break;
        case WPA_CIPHER_TKIP:
                /* WPA-None uses the same Michael MIC key for both TX and RX */
                os_memcpy(key, ssid->psk, 16 + 8);
@@ -182,7 +190,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
                MAC2STR(bssid));
        wpa_blacklist_add(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        wpa_s->reassociate = 1;
 
        /*
@@ -190,6 +198,17 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
         * So, wait a second until scanning again.
         */
        wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+           wpa_s->global->p2p != NULL) {
+               wpa_s->global->p2p_cb_on_scan_complete = 0;
+               if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+                               "continued after timed out authentication");
+               }
+       }
+#endif /* CONFIG_P2P */
 }
 
 
@@ -368,6 +387,7 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        bgscan_deinit(wpa_s);
+       autoscan_deinit(wpa_s);
        scard_deinit(wpa_s->scard);
        wpa_s->scard = NULL;
        wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -449,6 +469,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        os_free(wpa_s->bssid_filter);
        wpa_s->bssid_filter = NULL;
+
+       os_free(wpa_s->disallow_aps_bssid);
+       wpa_s->disallow_aps_bssid = NULL;
+       os_free(wpa_s->disallow_aps_ssid);
+       wpa_s->disallow_aps_ssid = NULL;
+
+       wnm_bss_keep_alive_deinit(wpa_s);
+
+       ext_password_deinit(wpa_s->ext_pw);
+       wpa_s->ext_pw = NULL;
+
+       wpabuf_free(wpa_s->last_gas_resp);
+
+       os_free(wpa_s->last_scan_res);
+       wpa_s->last_scan_res = NULL;
 }
 
 
@@ -550,8 +585,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
                         * optimization, so the initial connection is not
                         * affected.
                         */
-               } else
+               } else {
+                       struct wpa_scan_results *scan_res;
                        wpa_s->bgscan_ssid = wpa_s->current_ssid;
+                       scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+                                                                  0);
+                       if (scan_res) {
+                               bgscan_notify_scan(wpa_s, scan_res);
+                               wpa_scan_results_free(scan_res);
+                       }
+               }
        } else
                wpa_s->bgscan_ssid = NULL;
 }
@@ -568,6 +611,29 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_BGSCAN */
 
 
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+       if (autoscan_init(wpa_s, 0))
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+       autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+           wpa_s->wpa_state == WPA_SCANNING) {
+               autoscan_deinit(wpa_s);
+               wpa_supplicant_start_autoscan(wpa_s);
+       }
+}
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -598,6 +664,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                        ssid ? ssid->id : -1,
                        ssid && ssid->id_str ? ssid->id_str : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+               wpas_clear_temp_disabled(wpa_s, ssid, 1);
                wpa_s->new_connection = 0;
                wpa_s->reassociated_connection = 1;
                wpa_drv_set_operstate(wpa_s, 1);
@@ -628,6 +695,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
 
+       if (state == WPA_AUTHENTICATING)
+               wpa_supplicant_stop_autoscan(wpa_s);
+
+       if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+               wpa_supplicant_start_autoscan(wpa_s);
+
        if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
@@ -671,7 +744,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
        wpa_s->mgmt_group_cipher = 0;
        wpa_s->key_mgmt = 0;
        if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
-               wpa_s->wpa_state = WPA_DISCONNECTED;
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
        if (wpa_s->wpa_state != old_state)
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -784,6 +857,8 @@ enum wpa_cipher cipher_suite2driver(int cipher)
                return CIPHER_WEP104;
        case WPA_CIPHER_CCMP:
                return CIPHER_CCMP;
+       case WPA_CIPHER_GCMP:
+               return CIPHER_GCMP;
        case WPA_CIPHER_TKIP:
        default:
                return CIPHER_TKIP;
@@ -855,7 +930,9 @@ 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_REQUIRED) {
+           (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+            wpa_s->conf->pmf : ssid->ieee80211w) ==
+           MGMT_FRAME_PROTECTION_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
                        "that does not support management frame protection - "
                        "reject");
@@ -960,6 +1037,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        if (sel & WPA_CIPHER_CCMP) {
                wpa_s->group_cipher = WPA_CIPHER_CCMP;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+       } else if (sel & WPA_CIPHER_GCMP) {
+               wpa_s->group_cipher = WPA_CIPHER_GCMP;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
        } else if (sel & WPA_CIPHER_TKIP) {
                wpa_s->group_cipher = WPA_CIPHER_TKIP;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
@@ -979,6 +1059,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        if (sel & WPA_CIPHER_CCMP) {
                wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+       } else if (sel & WPA_CIPHER_GCMP) {
+               wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
        } else if (sel & WPA_CIPHER_TKIP) {
                wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
@@ -992,6 +1075,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+               sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        if (0) {
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1001,6 +1088,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       } else if (sel & WPA_KEY_MGMT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+       } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_IEEE80211W
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1033,7 +1128,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        sel = ie.mgmt_group_cipher;
-       if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+       if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+            wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
            !(ie.capabilities & WPA_CAPABILITY_MFPC))
                sel = 0;
        if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1046,7 +1142,9 @@ 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);
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+                        (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+                         wpa_s->conf->pmf : ssid->ieee80211w));
 #endif /* CONFIG_IEEE80211W */
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1060,13 +1158,70 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
                        u8 psk[PMK_LEN];
-                       pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
-                                   bss->ssid_len, 4096, psk, PMK_LEN);
+                       pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+                                   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);
                }
 #endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+               if (ssid->ext_psk) {
+                       struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+                                                            ssid->ext_psk);
+                       char pw_str[64 + 1];
+                       u8 psk[PMK_LEN];
+
+                       if (pw == NULL) {
+                               wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+                                       "found from external storage");
+                               return -1;
+                       }
+
+                       if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+                               wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+                                       "PSK length %d in external storage",
+                                       (int) wpabuf_len(pw));
+                               ext_password_free(pw);
+                               return -1;
+                       }
+
+                       os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+                       pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+                       if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+                       {
+                               pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+                                           4096, psk, PMK_LEN);
+                               os_memset(pw_str, 0, sizeof(pw_str));
+                               wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+                                               "external passphrase)",
+                                               psk, PMK_LEN);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                       } else
+#endif /* CONFIG_NO_PBKDF2 */
+                       if (wpabuf_len(pw) == 2 * PMK_LEN) {
+                               if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+                                       wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+                                               "Invalid PSK hex string");
+                                       os_memset(pw_str, 0, sizeof(pw_str));
+                                       ext_password_free(pw);
+                                       return -1;
+                               }
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+                       } else {
+                               wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+                                       "PSK available");
+                               os_memset(pw_str, 0, sizeof(pw_str));
+                               ext_password_free(pw);
+                               return -1;
+                       }
+
+                       os_memset(pw_str, 0, sizeof(pw_str));
+                       ext_password_free(pw);
+               }
+#endif /* CONFIG_EXT_PASSWORD */
        } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
@@ -1113,7 +1268,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                "mode");
                        return;
                }
-               wpa_supplicant_create_ap(wpa_s, ssid);
+               if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+                       return;
+               }
                wpa_s->current_bss = bss;
 #else /* CONFIG_AP */
                wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
@@ -1164,7 +1322,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                /* Use ap_scan==1 style network selection to find the network
                 */
-               wpa_s->scan_req = 2;
+               wpa_s->scan_req = MANUAL_SCAN_REQ;
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
                return;
@@ -1202,7 +1360,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
-               try_opportunistic = ssid->proactive_key_caching &&
+               try_opportunistic = (ssid->proactive_key_caching < 0 ?
+                                    wpa_s->conf->okc :
+                                    ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            wpa_s->current_ssid,
@@ -1215,6 +1375,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                "key management and encryption suites");
                        return;
                }
+       } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+                  wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+               /*
+                * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+                * use non-WPA since the scan results did not indicate that the
+                * AP is using WPA or WPA2.
+                */
+               wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+               wpa_ie_len = 0;
+               wpa_s->wpa_proto = 0;
        } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -1397,8 +1567,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-       params.mgmt_frame_protection = ssid->ieee80211w;
-       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+       params.mgmt_frame_protection =
+               ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+               wpa_s->conf->pmf : ssid->ieee80211w;
+       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;
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
@@ -1438,6 +1610,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                         * succeed.
                         */
                        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                        return;
                }
@@ -1507,10 +1680,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
        struct wpa_ssid *old_ssid;
 
        wpa_clear_keys(wpa_s, addr);
-       wpa_supplicant_mark_disassoc(wpa_s);
        old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       wpa_s->current_bss = NULL;
+       wpa_supplicant_mark_disassoc(wpa_s);
        wpa_sm_set_config(wpa_s->wpa, NULL);
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        if (old_ssid != wpa_s->current_ssid)
@@ -1519,33 +1690,6 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
 }
 
 
-/**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-                                int reason_code)
-{
-       u8 *addr = NULL;
-       union wpa_event_data event;
-
-       if (!is_zero_ether_addr(wpa_s->bssid)) {
-               wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
-               addr = wpa_s->bssid;
-               os_memset(&event, 0, sizeof(event));
-               event.disassoc_info.reason_code = (u16) reason_code;
-               event.disassoc_info.locally_generated = 1;
-               wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
-       }
-
-       wpa_supplicant_clear_connection(wpa_s, addr);
-}
-
-
 /**
  * wpa_supplicant_deauthenticate - Deauthenticate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1559,14 +1703,38 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 {
        u8 *addr = NULL;
        union wpa_event_data event;
+       int zero_addr = 0;
 
-       if (!is_zero_ether_addr(wpa_s->bssid)) {
-               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+               " pending_bssid=" MACSTR " reason=%d state=%s",
+               MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+               reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+
+       if (!is_zero_ether_addr(wpa_s->bssid))
                addr = wpa_s->bssid;
+       else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+                (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+                 wpa_s->wpa_state == WPA_ASSOCIATING))
+               addr = wpa_s->pending_bssid;
+       else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+               /*
+                * When using driver-based BSS selection, we may not know the
+                * BSSID with which we are currently trying to associate. We
+                * need to notify the driver of this disconnection even in such
+                * a case, so use the all zeros address here.
+                */
+               addr = wpa_s->bssid;
+               zero_addr = 1;
+       }
+
+       if (addr) {
+               wpa_drv_deauthenticate(wpa_s, addr, reason_code);
                os_memset(&event, 0, sizeof(event));
                event.deauth_info.reason_code = (u16) reason_code;
                event.deauth_info.locally_generated = 1;
                wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+               if (zero_addr)
+                       addr = NULL;
        }
 
        wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1599,6 +1767,8 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                        was_disabled = other_ssid->disabled;
 
                        other_ssid->disabled = 0;
+                       if (was_disabled)
+                               wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
 
                        if (was_disabled != other_ssid->disabled)
                                wpas_notify_network_enabled_changed(
@@ -1619,6 +1789,7 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                was_disabled = ssid->disabled;
 
                ssid->disabled = 0;
+               wpas_clear_temp_disabled(wpa_s, ssid, 1);
 
                if (was_disabled != ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, ssid);
@@ -1654,11 +1825,11 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
                                        wpa_s, other_ssid);
                }
                if (wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        } else if (ssid->disabled != 2) {
                if (ssid == wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
                was_disabled = ssid->disabled;
@@ -1684,11 +1855,14 @@ 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_supplicant_disassociate(
+               wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                disconnected = 1;
        }
 
+       if (ssid)
+               wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
        /*
         * Mark all other networks disabled or mark all networks enabled if no
         * network specified.
@@ -1700,6 +1874,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                        continue; /* do not change persistent P2P group data */
 
                other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+               if (was_disabled && !other_ssid->disabled)
+                       wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
 
                if (was_disabled != other_ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
@@ -2237,7 +2413,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s = os_zalloc(sizeof(*wpa_s));
        if (wpa_s == NULL)
                return NULL;
-       wpa_s->scan_req = 1;
+       wpa_s->scan_req = INITIAL_SCAN_REQ;
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = wpa_s;
@@ -2466,6 +2642,38 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
 }
 
 
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+       char *val, *pos;
+
+       ext_password_deinit(wpa_s->ext_pw);
+       wpa_s->ext_pw = NULL;
+       eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+       if (!wpa_s->conf->ext_password_backend)
+               return 0;
+
+       val = os_strdup(wpa_s->conf->ext_password_backend);
+       if (val == NULL)
+               return -1;
+       pos = os_strchr(val, ':');
+       if (pos)
+               *pos++ = '\0';
+
+       wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+       wpa_s->ext_pw = ext_password_init(val, pos);
+       os_free(val);
+       if (wpa_s->ext_pw == NULL) {
+               wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+               return -1;
+       }
+       eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+       return 0;
+}
+
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
@@ -2691,6 +2899,9 @@ next_driver:
        if (pcsc_reader_init(wpa_s) < 0)
                return -1;
 
+       if (wpas_init_ext_pw(wpa_s) < 0)
+               return -1;
+
        return 0;
 }
 
@@ -2802,6 +3013,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        global->ifaces = wpa_s;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
        return wpa_s;
 }
@@ -3008,6 +3220,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wifi_display_init(global) < 0) {
+               wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return global;
 }
 
@@ -3059,6 +3279,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        if (global == NULL)
                return;
 
+#ifdef CONFIG_WIFI_DISPLAY
+       wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
 #ifdef CONFIG_P2P
        wpas_p2p_deinit_global(global);
 #endif /* CONFIG_P2P */
@@ -3118,6 +3341,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
                }
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+               wpas_init_ext_pw(wpa_s);
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -3240,6 +3466,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
         */
        wpa_supplicant_req_scan(wpa_s, timeout / 1000,
                                1000 * (timeout % 1000));
+
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+           wpa_s->global->p2p != NULL) {
+               wpa_s->global->p2p_cb_on_scan_complete = 0;
+               if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+                               "continued after failed association");
+               }
+       }
+#endif /* CONFIG_P2P */
 }
 
 
@@ -3353,5 +3590,115 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
                return 1; /* invalid WEP key */
        }
 
+       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+           !ssid->ext_psk)
+               return 1;
+
+       return 0;
+}
+
+
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
+               return 1;
+       if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
+               return 0;
+       return -1;
+}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       int dur;
+       struct os_time now;
+
+       if (ssid == NULL) {
+               wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+                          "SSID block");
+               return;
+       }
+
+       if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+               return;
+
+       ssid->auth_failures++;
+       if (ssid->auth_failures > 50)
+               dur = 300;
+       else if (ssid->auth_failures > 20)
+               dur = 120;
+       else if (ssid->auth_failures > 10)
+               dur = 60;
+       else if (ssid->auth_failures > 5)
+               dur = 30;
+       else if (ssid->auth_failures > 1)
+               dur = 20;
+       else
+               dur = 10;
+
+       os_get_time(&now);
+       if (now.sec + dur <= ssid->disabled_until.sec)
+               return;
+
+       ssid->disabled_until.sec = now.sec + dur;
+
+       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+               "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+               ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+               ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+                             struct wpa_ssid *ssid, int clear_failures)
+{
+       if (ssid == NULL)
+               return;
+
+       if (ssid->disabled_until.sec) {
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+                       "id=%d ssid=\"%s\"",
+                       ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+       }
+       ssid->disabled_until.sec = 0;
+       ssid->disabled_until.usec = 0;
+       if (clear_failures)
+               ssid->auth_failures = 0;
+}
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       size_t i;
+
+       if (wpa_s->disallow_aps_bssid == NULL)
+               return 0;
+
+       for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+               if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+                             bssid, ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+                   size_t ssid_len)
+{
+       size_t i;
+
+       if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+               return 0;
+
+       for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+               struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+               if (ssid_len == s->ssid_len &&
+                   os_memcmp(ssid, s->ssid, ssid_len) == 0)
+                       return 1;
+       }
+
        return 0;
 }