Add automatic scanning support
[mech_eap.git] / wpa_supplicant / wpa_supplicant.c
index 3cf62e8..a043208 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  *
  * This file implements functions for registering and unregistering
  * %wpa_supplicant interfaces. In addition, this file contains number of
@@ -36,7 +30,6 @@
 #include "rsn_supp/preauth.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
-#include "mlme.h"
 #include "common/ieee802_11_defs.h"
 #include "p2p/p2p.h"
 #include "blacklist.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "bss.h"
 #include "scan.h"
 #include "offchannel.h"
+#include "hs20_supplicant.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *wpa_supplicant_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n"
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n"
 #ifdef EAP_TLS_OPENSSL
 "\nThis product includes software developed by the OpenSSL Project\n"
 "for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
@@ -72,22 +64,9 @@ const char *wpa_supplicant_license =
 #ifndef CONFIG_NO_STDOUT_DEBUG
 /* Long text divided into parts in order to fit in C89 strings size limits. */
 const char *wpa_supplicant_full_license1 =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-"GNU General Public License for more details.\n"
-"\n";
+"";
 const char *wpa_supplicant_full_license2 =
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license.\n"
+"This software may be distributed under the terms of the BSD license.\n"
 "\n"
 "Redistribution and use in source and binary forms, with or without\n"
 "modification, are permitted provided that the following conditions are\n"
@@ -371,9 +350,26 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
+void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+       int i;
+       if (wpa_s->hw.modes == NULL)
+               return;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               os_free(wpa_s->hw.modes[i].channels);
+               os_free(wpa_s->hw.modes[i].rates);
+       }
+
+       os_free(wpa_s->hw.modes);
+       wpa_s->hw.modes = NULL;
+}
+
+
 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);
@@ -385,16 +381,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                wpa_s->l2_br = NULL;
        }
 
-       if (wpa_s->ctrl_iface) {
-               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-               wpa_s->ctrl_iface = NULL;
-       }
        if (wpa_s->conf != NULL) {
                struct wpa_ssid *ssid;
                for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
                        wpas_notify_network_removed(wpa_s, ssid);
-               wpa_config_free(wpa_s->conf);
-               wpa_s->conf = NULL;
        }
 
        os_free(wpa_s->confname);
@@ -419,8 +409,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        wpa_supplicant_cancel_scan(wpa_s);
        wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-       ieee80211_sta_deinit(wpa_s);
+       eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+       eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+                            wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
        wpas_wps_deinit(wpa_s);
 
@@ -446,11 +439,20 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        offchannel_deinit(wpa_s);
 #endif /* CONFIG_OFFCHANNEL */
 
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+
        os_free(wpa_s->next_scan_freqs);
        wpa_s->next_scan_freqs = NULL;
 
        gas_query_deinit(wpa_s->gas);
        wpa_s->gas = NULL;
+
+       free_hw_features(wpa_s);
+
+       os_free(wpa_s->bssid_filter);
+       wpa_s->bssid_filter = NULL;
+
+       wnm_bss_keep_alive_deinit(wpa_s);
 }
 
 
@@ -570,6 +572,19 @@ 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))
+               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);
+}
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -610,6 +625,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_P2P
                wpas_p2p_completed(wpa_s);
 #endif /* CONFIG_P2P */
+
+               sme_sched_obss_scan(wpa_s, 1);
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -617,6 +634,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #ifndef IEEE8021X_EAPOL
                wpa_drv_set_supp_port(wpa_s, 0);
 #endif /* IEEE8021X_EAPOL */
+               sme_sched_obss_scan(wpa_s, 0);
        }
        wpa_s->wpa_state = state;
 
@@ -627,6 +645,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);
 
@@ -657,11 +681,6 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global)
 static void wpa_supplicant_terminate(int sig, void *signal_ctx)
 {
        struct wpa_global *global = signal_ctx;
-       struct wpa_supplicant *wpa_s;
-       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
-                       "received", sig);
-       }
        wpa_supplicant_terminate_proc(global);
 }
 
@@ -754,7 +773,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        wpa_supplicant_update_config(wpa_s);
 
        wpa_supplicant_clear_status(wpa_s);
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       if (wpa_supplicant_enabled_networks(wpa_s)) {
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
        }
@@ -1058,9 +1077,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       if (ssid->key_mgmt &
-           (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
-       {
+       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
                wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
 #ifndef CONFIG_NO_PBKDF2
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
@@ -1101,6 +1118,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        struct wpa_driver_capa capa;
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
+#ifdef CONFIG_HT_OVERRIDES
+       struct ieee80211_ht_capabilities htcaps;
+       struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
 
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1176,6 +1197,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
        /* Starting new association, so clear the possibly used WPA IE from the
@@ -1201,11 +1223,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-           (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-                              WPA_KEY_MGMT_FT_IEEE8021X |
-                              WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                              WPA_KEY_MGMT_PSK_SHA256))) {
+           wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
                try_opportunistic = ssid->proactive_key_caching &&
                        (ssid->proto & WPA_PROTO_RSN);
@@ -1220,11 +1238,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                "key management and encryption suites");
                        return;
                }
-       } else if (ssid->key_mgmt &
-                  (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-                   WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-                   WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-                   WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+       } 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,
                                              wpa_ie, &wpa_ie_len)) {
@@ -1261,11 +1275,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                u8 *pos;
                size_t len;
                int res;
-               int p2p_group;
-               p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
                pos = wpa_ie + wpa_ie_len;
                len = sizeof(wpa_ie) - wpa_ie_len;
-               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+                                           ssid->p2p_group);
                if (res >= 0)
                        wpa_ie_len += res;
        }
@@ -1286,6 +1299,36 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_HS20
+       if (wpa_s->conf->hs20) {
+               struct wpabuf *hs20;
+               hs20 = wpabuf_alloc(20);
+               if (hs20) {
+                       wpas_hs20_add_indication(hs20);
+                       os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+                                 wpabuf_len(hs20));
+                       wpa_ie_len += wpabuf_len(hs20);
+                       wpabuf_free(hs20);
+               }
+       }
+#endif /* CONFIG_HS20 */
+
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking) {
+               u8 *pos = wpa_ie;
+               if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+                       pos += 2 + pos[1];
+               os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
+               wpa_ie_len += 6;
+               *pos++ = WLAN_EID_EXT_CAPAB;
+               *pos++ = 4;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x80; /* Bit 31 - Interworking */
+       }
+#endif /* CONFIG_INTERWORKING */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
@@ -1327,7 +1370,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        if (bss) {
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               if (!wpas_driver_bss_selection(wpa_s)) {
+               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+                       wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+                                  MACSTR " freq=%u MHz based on scan results "
+                                  "(bssid_set=%d)",
+                                  MAC2STR(bss->bssid), bss->freq,
+                                  ssid->bssid_set);
                        params.bssid = bss->bssid;
                        params.freq = bss->freq;
                }
@@ -1335,6 +1383,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
        }
+
+       if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+           wpa_s->conf->ap_scan == 2) {
+               params.bssid = ssid->bssid;
+               params.fixed_bssid = 1;
+       }
+
        if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
            params.freq == 0)
                params.freq = ssid->frequency; /* Initial channel for IBSS */
@@ -1346,6 +1401,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
        params.mode = ssid->mode;
+       params.bg_scan_period = ssid->bg_scan_period;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
                if (ssid->wep_key_len[i])
                        params.wep_key[i] = ssid->wep_key[i];
@@ -1386,10 +1442,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        else
                params.uapsd = -1;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               ret = ieee80211_sta_associate(wpa_s, &params);
-       else
-               ret = wpa_drv_associate(wpa_s, &params);
+#ifdef CONFIG_HT_OVERRIDES
+       os_memset(&htcaps, 0, sizeof(htcaps));
+       os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+       params.htcaps = (u8 *) &htcaps;
+       params.htcaps_mask = (u8 *) &htcaps_mask;
+       wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+
+       ret = wpa_drv_associate(wpa_s, &params);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
                        "failed");
@@ -1400,6 +1461,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;
                }
@@ -1493,13 +1555,15 @@ 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)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_disassociate(wpa_s, reason_code);
-               else
-                       wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+               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);
@@ -1518,14 +1582,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
        u8 *addr = NULL;
+       union wpa_event_data event;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_deauthenticate(wpa_s, reason_code);
-               else
-                       wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-                                              reason_code);
+               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
+               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);
        }
 
        wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1640,10 +1705,13 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 {
 
        struct wpa_ssid *other_ssid;
+       int disconnected = 0;
 
-       if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
+       if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
                wpa_supplicant_disassociate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               disconnected = 1;
+       }
 
        /*
         * Mark all other networks disabled or mark all networks enabled if no
@@ -1668,10 +1736,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (ssid)
+               wpa_s->current_ssid = ssid;
        wpa_s->connect_without_scan = NULL;
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
 
        if (ssid)
                wpas_notify_network_selected(wpa_s, ssid);
@@ -1693,6 +1763,16 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
        if (ap_scan < 0 || ap_scan > 2)
                return -1;
 
+#ifdef ANDROID
+       if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+           wpa_s->wpa_state >= WPA_ASSOCIATING &&
+           wpa_s->wpa_state < WPA_COMPLETED) {
+               wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+                          "associating", wpa_s->conf->ap_scan, ap_scan);
+               return 0;
+       }
+#endif /* ANDROID */
+
        old_ap_scan = wpa_s->conf->ap_scan;
        wpa_s->conf->ap_scan = ap_scan;
 
@@ -1750,6 +1830,29 @@ int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
 
 
 /**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+                                    int scan_interval)
+{
+       if (scan_interval < 0) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+                       scan_interval);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+               scan_interval);
+       wpa_s->scan_interval = scan_interval;
+
+       return 0;
+}
+
+
+/**
  * wpa_supplicant_set_debug_params - Set global debug params
  * @global: wpa_global structure
  * @debug_level: debug level
@@ -1805,25 +1908,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        u8 bssid[ETH_ALEN];
        int wired;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-               if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
-                       wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-                               "MLME");
-                       return NULL;
-               }
-       } else {
-               res = wpa_drv_get_ssid(wpa_s, ssid);
-               if (res < 0) {
-                       wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-                               "driver");
-                       return NULL;
-               }
-               ssid_len = res;
+       res = wpa_drv_get_ssid(wpa_s, ssid);
+       if (res < 0) {
+               wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+                       "driver");
+               return NULL;
        }
+       ssid_len = res;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-       else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+       if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
                        "driver");
                return NULL;
@@ -1834,14 +1927,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 
        entry = wpa_s->conf->ssid;
        while (entry) {
-               if (!entry->disabled &&
+               if (!wpas_network_disabled(wpa_s, entry) &&
                    ((ssid_len == entry->ssid_len &&
                      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
                    (!entry->bssid_set ||
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
 #ifdef CONFIG_WPS
-               if (!entry->disabled &&
+               if (!wpas_network_disabled(wpa_s, entry) &&
                    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
                    (entry->ssid == NULL || entry->ssid_len == 0) &&
                    (!entry->bssid_set ||
@@ -1849,7 +1942,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                        return entry;
 #endif /* CONFIG_WPS */
 
-               if (!entry->disabled && entry->bssid_set &&
+               if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
                    entry->ssid_len == 0 &&
                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
                        return entry;
@@ -1861,6 +1954,26 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 }
 
 
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+       struct wpa_global *global = wpa_s->global;
+
+       if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+               global->drv_priv[i] = wpa_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_drivers[i]->name);
+                       return -1;
+               }
+       }
+
+       wpa_s->driver = wpa_drivers[i];
+       wpa_s->global_drv_priv = global->drv_priv[i];
+
+       return 0;
+}
+
+
 static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                                     const char *name)
 {
@@ -1879,9 +1992,7 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
 
        if (name == NULL) {
                /* default to first driver in the list */
-               wpa_s->driver = wpa_drivers[0];
-               wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
-               return 0;
+               return select_driver(wpa_s, 0);
        }
 
        do {
@@ -1895,10 +2006,9 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                        if (os_strlen(wpa_drivers[i]->name) == len &&
                            os_strncmp(driver, wpa_drivers[i]->name, len) ==
                            0) {
-                               wpa_s->driver = wpa_drivers[i];
-                               wpa_s->global_drv_priv =
-                                       wpa_s->global->drv_priv[i];
-                               return 0;
+                               /* First driver that succeeds wins */
+                               if (select_driver(wpa_s, i) == 0)
+                                       return 0;
                        }
                }
 
@@ -2021,25 +2131,15 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 }
 
 
-/**
- * wpa_supplicant_driver_init - Initialize driver interface parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to initialize driver interface parameters.
- * wpa_drv_init() must have been called before this function to initialize the
- * driver interface.
- */
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 {
-       static int interface_count = 0;
-
        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->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),
                                           ETH_P_EAPOL,
@@ -2059,6 +2159,52 @@ 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));
+       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+       return 0;
+}
+
+
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+                                          const u8 *buf, size_t len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct l2_ethhdr *eth;
+
+       if (len < sizeof(*eth))
+               return;
+       eth = (const struct l2_ethhdr *) buf;
+
+       if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+           !(eth->h_dest[0] & 0x01)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+                       " (bridge - not for this interface - ignore)",
+                       MAC2STR(src_addr), MAC2STR(eth->h_dest));
+               return;
+       }
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+               " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+       wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+                               len - sizeof(*eth));
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+       static int interface_count = 0;
+
+       if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+               return -1;
 
        if (wpa_s->bridge_ifname[0]) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
@@ -2066,8 +2212,8 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
                                              wpa_s->own_addr,
                                              ETH_P_EAPOL,
-                                             wpa_supplicant_rx_eapol, wpa_s,
-                                             0);
+                                             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'",
@@ -2086,8 +2232,13 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        wpa_drv_flush_pmkid(wpa_s);
 
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-               wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+       wpa_s->prev_scan_wildcard = 0;
+
+       if (wpa_supplicant_enabled_networks(wpa_s)) {
+               if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+                                                     100000))
+                       wpa_supplicant_req_scan(wpa_s, interface_count,
+                                               100000);
                interface_count++;
        } else
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -2114,11 +2265,231 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = wpa_s;
+       wpa_s->sched_scanning = 0;
 
        return wpa_s;
 }
 
 
+#ifdef CONFIG_HT_OVERRIDES
+
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+                            struct ieee80211_ht_capabilities *htcaps,
+                            struct ieee80211_ht_capabilities *htcaps_mask,
+                            const char *ht_mcs)
+{
+       /* parse ht_mcs into hex array */
+       int i;
+       const char *tmp = ht_mcs;
+       char *end = NULL;
+
+       /* If ht_mcs is null, do not set anything */
+       if (!ht_mcs)
+               return 0;
+
+       /* This is what we are setting in the kernel */
+       os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+       wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
+
+       for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+               errno = 0;
+               long v = strtol(tmp, &end, 16);
+               if (errno == 0) {
+                       wpa_msg(wpa_s, MSG_DEBUG,
+                               "htcap value[%i]: %ld end: %p  tmp: %p",
+                               i, v, end, tmp);
+                       if (end == tmp)
+                               break;
+
+                       htcaps->supported_mcs_set[i] = v;
+                       tmp = end;
+               } else {
+                       wpa_msg(wpa_s, MSG_ERROR,
+                               "Failed to parse ht-mcs: %s, error: %s\n",
+                               ht_mcs, strerror(errno));
+                       return -1;
+               }
+       }
+
+       /*
+        * If we were able to parse any values, then set mask for the MCS set.
+        */
+       if (i) {
+               os_memset(&htcaps_mask->supported_mcs_set, 0xff,
+                         IEEE80211_HT_MCS_MASK_LEN - 1);
+               /* skip the 3 reserved bits */
+               htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
+                       0x1f;
+       }
+
+       return 0;
+}
+
+
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+                                struct ieee80211_ht_capabilities *htcaps,
+                                struct ieee80211_ht_capabilities *htcaps_mask,
+                                int disabled)
+{
+       u16 msk;
+
+       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
+       if (disabled == -1)
+               return 0;
+
+       msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+       htcaps_mask->ht_capabilities_info |= msk;
+       if (disabled)
+               htcaps->ht_capabilities_info &= msk;
+       else
+               htcaps->ht_capabilities_info |= msk;
+
+       return 0;
+}
+
+
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+                               struct ieee80211_ht_capabilities *htcaps,
+                               struct ieee80211_ht_capabilities *htcaps_mask,
+                               int factor)
+{
+       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
+       if (factor == -1)
+               return 0;
+
+       if (factor < 0 || factor > 3) {
+               wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
+                       "Must be 0-3 or -1", factor);
+               return -EINVAL;
+       }
+
+       htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
+       htcaps->a_mpdu_params &= ~0x3;
+       htcaps->a_mpdu_params |= factor & 0x3;
+
+       return 0;
+}
+
+
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+                                struct ieee80211_ht_capabilities *htcaps,
+                                struct ieee80211_ht_capabilities *htcaps_mask,
+                                int density)
+{
+       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
+       if (density == -1)
+               return 0;
+
+       if (density < 0 || density > 7) {
+               wpa_msg(wpa_s, MSG_ERROR,
+                       "ampdu_density: %d out of range. Must be 0-7 or -1.",
+                       density);
+               return -EINVAL;
+       }
+
+       htcaps_mask->a_mpdu_params |= 0x1C;
+       htcaps->a_mpdu_params &= ~(0x1C);
+       htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+
+       return 0;
+}
+
+
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+                               struct ieee80211_ht_capabilities *htcaps,
+                               struct ieee80211_ht_capabilities *htcaps_mask,
+                               int disabled)
+{
+       /* Masking these out disables HT40 */
+       u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+                              HT_CAP_INFO_SHORT_GI40MHZ);
+
+       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+
+       if (disabled)
+               htcaps->ht_capabilities_info &= ~msk;
+       else
+               htcaps->ht_capabilities_info |= msk;
+
+       htcaps_mask->ht_capabilities_info |= msk;
+
+       return 0;
+}
+
+
+void wpa_supplicant_apply_ht_overrides(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+       struct wpa_driver_associate_params *params)
+{
+       struct ieee80211_ht_capabilities *htcaps;
+       struct ieee80211_ht_capabilities *htcaps_mask;
+
+       if (!ssid)
+               return;
+
+       params->disable_ht = ssid->disable_ht;
+       if (!params->htcaps || !params->htcaps_mask)
+               return;
+
+       htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
+       htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
+       wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
+       wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
+                             ssid->disable_max_amsdu);
+       wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
+       wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
+       wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+}
+
+#endif /* CONFIG_HT_OVERRIDES */
+
+
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+       size_t len;
+
+       if (!wpa_s->conf->pcsc_reader)
+               return 0;
+
+       wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+       if (!wpa_s->scard)
+               return 1;
+
+       if (wpa_s->conf->pcsc_pin &&
+           scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+               scard_deinit(wpa_s->scard);
+               wpa_s->scard = NULL;
+               wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+               return -1;
+       }
+
+       len = sizeof(wpa_s->imsi) - 1;
+       if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+               scard_deinit(wpa_s->scard);
+               wpa_s->scard = NULL;
+               wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+               return -1;
+       }
+       wpa_s->imsi[len] = '\0';
+
+       wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+       wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+                  wpa_s->imsi, wpa_s->mnc_len);
+
+       wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+       eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+       return 0;
+}
+
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
@@ -2271,13 +2642,19 @@ next_driver:
                return -1;
        }
 
+       wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+                                                     &wpa_s->hw.num_modes,
+                                                     &wpa_s->hw.flags);
+
        if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+               wpa_s->drv_capa_known = 1;
                wpa_s->drv_flags = capa.flags;
-               if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-                       if (ieee80211_sta_init(wpa_s))
-                               return -1;
-               }
+               wpa_s->drv_enc = capa.enc;
+               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;
+               wpa_s->sched_scan_supported = capa.sched_scan_supported;
+               wpa_s->max_match_sets = capa.max_match_sets;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
                wpa_s->max_stations = capa.max_stations;
        }
@@ -2298,8 +2675,6 @@ next_driver:
                return -1;
        }
 
-       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
        if (wpas_wps_init(wpa_s))
                return -1;
 
@@ -2337,12 +2712,15 @@ next_driver:
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+       if (pcsc_reader_init(wpa_s) < 0)
+               return -1;
+
        return 0;
 }
 
 
 static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
-                                       int notify)
+                                       int notify, int terminate)
 {
        if (wpa_s->drv_priv) {
                wpa_supplicant_deauthenticate(wpa_s,
@@ -2354,11 +2732,32 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_cleanup(wpa_s);
 
-       if (notify)
-               wpas_notify_iface_removed(wpa_s);
+#ifdef CONFIG_P2P
+       if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+                       "the management interface is being removed");
+               wpas_p2p_deinit_global(wpa_s->global);
+       }
+#endif /* CONFIG_P2P */
 
        if (wpa_s->drv_priv)
                wpa_drv_deinit(wpa_s);
+
+       if (notify)
+               wpas_notify_iface_removed(wpa_s);
+
+       if (terminate)
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+
+       if (wpa_s->ctrl_iface) {
+               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+               wpa_s->ctrl_iface = NULL;
+       }
+
+       if (wpa_s->conf != NULL) {
+               wpa_config_free(wpa_s->conf);
+               wpa_s->conf = NULL;
+       }
 }
 
 
@@ -2408,14 +2807,14 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
                wpa_printf(MSG_DEBUG, "Failed to add interface %s",
                           iface->ifname);
-               wpa_supplicant_deinit_iface(wpa_s, 0);
+               wpa_supplicant_deinit_iface(wpa_s, 0, 0);
                os_free(wpa_s);
                return NULL;
        }
 
        /* Notify the control interfaces about new iface */
        if (wpas_notify_iface_added(wpa_s)) {
-               wpa_supplicant_deinit_iface(wpa_s, 1);
+               wpa_supplicant_deinit_iface(wpa_s, 1, 0);
                os_free(wpa_s);
                return NULL;
        }
@@ -2444,7 +2843,8 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
  * %wpa_supplicant is terminated.
  */
 int wpa_supplicant_remove_iface(struct wpa_global *global,
-                               struct wpa_supplicant *wpa_s)
+                               struct wpa_supplicant *wpa_s,
+                               int terminate)
 {
        struct wpa_supplicant *prev;
 
@@ -2464,7 +2864,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
        if (global->p2p_group_formation == wpa_s)
                global->p2p_group_formation = NULL;
-       wpa_supplicant_deinit_iface(wpa_s, 1);
+       wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
        os_free(wpa_s);
 
        return 0;
@@ -2540,6 +2940,13 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params == NULL)
                return NULL;
 
+#ifdef CONFIG_DRIVER_NDIS
+       {
+               void driver_ndis_init_ops(void);
+               driver_ndis_init_ops();
+       }
+#endif /* CONFIG_DRIVER_NDIS */
+
 #ifndef CONFIG_NO_WPA_MSG
        wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
 #endif /* CONFIG_NO_WPA_MSG */
@@ -2547,6 +2954,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        wpa_debug_open_file(params->wpa_debug_file_path);
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
+       if (params->wpa_debug_tracing) {
+               ret = wpa_debug_open_linux_tracing();
+               if (ret) {
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to enable trace logging");
+                       return NULL;
+               }
+       }
 
        ret = eap_register_methods();
        if (ret) {
@@ -2616,17 +3031,6 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                wpa_supplicant_deinit(global);
                return NULL;
        }
-       for (i = 0; wpa_drivers[i]; i++) {
-               if (!wpa_drivers[i]->global_init)
-                       continue;
-               global->drv_priv[i] = wpa_drivers[i]->global_init();
-               if (global->drv_priv[i] == NULL) {
-                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
-                                  "'%s'", wpa_drivers[i]->name);
-                       wpa_supplicant_deinit(global);
-                       return NULL;
-               }
-       }
 
        return global;
 }
@@ -2684,7 +3088,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 #endif /* CONFIG_P2P */
 
        while (global->ifaces)
-               wpa_supplicant_remove_iface(global, global->ifaces);
+               wpa_supplicant_remove_iface(global, global->ifaces, 1);
 
        if (global->ctrl_iface)
                wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
@@ -2715,9 +3119,12 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.override_driver);
        os_free(global->params.override_ctrl_interface);
 
+       os_free(global->p2p_disallow_freq);
+
        os_free(global);
        wpa_debug_close_syslog();
        wpa_debug_close_file();
+       wpa_debug_close_linux_tracing();
 }
 
 
@@ -2747,23 +3154,6 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 }
 
 
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-                                   size_t num_hw_features)
-{
-       size_t i;
-
-       if (hw_features == NULL)
-               return;
-
-       for (i = 0; i < num_hw_features; i++) {
-               os_free(hw_features[i].channels);
-               os_free(hw_features[i].rates);
-       }
-
-       os_free(hw_features);
-}
-
-
 static void add_freq(int *freqs, int *num_freqs, int freq)
 {
        int i;
@@ -2819,6 +3209,11 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        int *freqs = NULL;
 
        /*
+        * Remove possible authentication timeout since the connection failed.
+        */
+       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       /*
         * Add the failed BSSID into the blacklist and speed up next scan
         * attempt if there could be other APs that could accept association.
         * The current blacklist count indicates how many times we have tried
@@ -2877,3 +3272,120 @@ int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
        return wpa_s->conf->ap_scan == 2 ||
                (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
 }
+
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+                                             struct wpa_ssid *ssid,
+                                             const char *field,
+                                             const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+       struct eap_peer_config *eap = &ssid->eap;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+       wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+                             (const u8 *) value, os_strlen(value));
+
+       switch (wpa_supplicant_ctrl_req_from_string(field)) {
+       case WPA_CTRL_REQ_EAP_IDENTITY:
+               os_free(eap->identity);
+               eap->identity = (u8 *) os_strdup(value);
+               eap->identity_len = os_strlen(value);
+               eap->pending_req_identity = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_PASSWORD:
+               os_free(eap->password);
+               eap->password = (u8 *) os_strdup(value);
+               eap->password_len = os_strlen(value);
+               eap->pending_req_password = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+               os_free(eap->new_password);
+               eap->new_password = (u8 *) os_strdup(value);
+               eap->new_password_len = os_strlen(value);
+               eap->pending_req_new_password = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_PIN:
+               os_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);
+               eap->otp = (u8 *) os_strdup(value);
+               eap->otp_len = os_strlen(value);
+               os_free(eap->pending_req_otp);
+               eap->pending_req_otp = NULL;
+               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);
+               eap->pending_req_passphrase = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+               return -1;
+       }
+
+       return 0;
+#else /* IEEE8021X_EAPOL */
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+       return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+       int i;
+       unsigned int drv_enc;
+
+       if (ssid == NULL)
+               return 1;
+
+       if (ssid->disabled)
+               return 1;
+
+       if (wpa_s && wpa_s->drv_capa_known)
+               drv_enc = wpa_s->drv_enc;
+       else
+               drv_enc = (unsigned int) -1;
+
+       for (i = 0; i < NUM_WEP_KEYS; i++) {
+               size_t len = ssid->wep_key_len[i];
+               if (len == 0)
+                       continue;
+               if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+                       continue;
+               if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+                       continue;
+               if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+                       continue;
+               return 1; /* invalid WEP key */
+       }
+
+       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;
+}