]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - build-utilities/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
Select the BSD license terms as the only license alternative
[build-utilities/hostap.git] / wpa_supplicant / wpa_supplicant.c
index c4f07d3fdefdb394553402fb63e6e600f152e414..39b2147afbcaffea4071e5d5f376fafcfa626af9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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
@@ -20,6 +20,7 @@
 
 #include "common.h"
 #include "crypto/random.h"
+#include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
@@ -35,7 +36,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 "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
 #include "ap.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
 #include "bss.h"
 #include "scan.h"
+#include "offchannel.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"
@@ -69,22 +68,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"
@@ -368,6 +354,22 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
+static 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);
@@ -382,16 +384,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);
@@ -416,8 +412,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);
 
@@ -439,8 +438,19 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpas_p2p_deinit(wpa_s);
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_OFFCHANNEL
+       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);
 }
 
 
@@ -527,6 +537,8 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+       if (wpas_driver_bss_selection(wpa_s))
+               return;
        if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
                return;
 
@@ -645,11 +657,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);
 }
 
@@ -684,7 +691,6 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 {
        struct wpa_config *conf;
-       struct wpa_ssid *old_ssid;
        int reconf_ctrl;
        int old_ap_scan;
 
@@ -709,10 +715,10 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
 
        eapol_sm_invalidate_cached_session(wpa_s->eapol);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
+       if (wpa_s->current_ssid) {
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
 
        /*
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
@@ -727,6 +733,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        wpa_sm_set_config(wpa_s->wpa, NULL);
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
        wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
        rsn_preauth_deinit(wpa_s->wpa);
 
@@ -935,6 +942,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_IEEE80211W */
 
+       wpa_s->wpa_proto = proto;
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
                         !!(ssid->proto & WPA_PROTO_RSN));
@@ -1045,10 +1053,20 @@ 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);
-       else
+#ifndef CONFIG_NO_PBKDF2
+               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);
+                       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 */
+       } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
        return 0;
@@ -1076,6 +1094,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);
@@ -1113,7 +1135,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
-       if (bss) {
+       if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
                const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1151,6 +1173,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
@@ -1176,11 +1199,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);
@@ -1195,11 +1214,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)) {
@@ -1223,10 +1238,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        params.wps = WPS_MODE_PRIVACY;
                else
                        params.wps = WPS_MODE_OPEN;
+               wpa_s->wpa_proto = 0;
 #endif /* CONFIG_WPS */
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                wpa_ie_len = 0;
+               wpa_s->wpa_proto = 0;
        }
 
 #ifdef CONFIG_P2P
@@ -1259,6 +1276,22 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
+#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);
@@ -1298,14 +1331,23 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
        if (bss) {
-               params.bssid = bss->bssid;
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               params.freq = bss->freq;
+               if (!wpas_driver_bss_selection(wpa_s)) {
+                       params.bssid = bss->bssid;
+                       params.freq = bss->freq;
+               }
        } else {
                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 */
@@ -1314,6 +1356,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
        params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+       params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
        params.mode = ssid->mode;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -1349,21 +1392,22 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_IEEE80211W */
 
-#ifdef CONFIG_P2P
-       if (wpa_s->global->p2p &&
-           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
-               params.p2p = 1;
-#endif /* CONFIG_P2P */
+       params.p2p = ssid->p2p_group;
 
        if (wpa_s->parent->set_sta_uapsd)
                params.uapsd = wpa_s->parent->sta_uapsd;
        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");
@@ -1469,10 +1513,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
        u8 *addr = NULL;
 
        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;
        }
 
@@ -1494,11 +1535,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
        u8 *addr = NULL;
 
        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;
        }
 
@@ -1614,10 +1651,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
@@ -1634,9 +1674,20 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                if (was_disabled != other_ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
        }
+
+       if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+               /* We are already associated with the selected network */
+               wpa_printf(MSG_DEBUG, "Already associated with the "
+                          "selected network - do nothing");
+               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);
@@ -1658,6 +1709,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;
 
@@ -1770,25 +1831,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;
@@ -1813,6 +1864,12 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
 #endif /* CONFIG_WPS */
+
+               if (!entry->disabled && entry->bssid_set &&
+                   entry->ssid_len == 0 &&
+                   os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+                       return entry;
+
                entry = entry->next;
        }
 
@@ -1820,6 +1877,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)
 {
@@ -1838,9 +1915,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 {
@@ -1854,10 +1929,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;
                        }
                }
 
@@ -1980,25 +2054,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,
@@ -2018,6 +2082,27 @@ 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;
+}
+
+
+/**
+ * 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 "
@@ -2045,8 +2130,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;
+       wpa_s->prev_scan_wildcard = 0;
+
        if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-               wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+               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);
@@ -2073,11 +2163,189 @@ 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 wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
@@ -2230,13 +2498,18 @@ 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->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;
        }
@@ -2257,8 +2530,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;
 
@@ -2280,6 +2551,12 @@ next_driver:
                return -1;
        }
 
+       wpa_s->gas = gas_query_init(wpa_s);
+       if (wpa_s->gas == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
+               return -1;
+       }
+
 #ifdef CONFIG_P2P
        if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
@@ -2295,7 +2572,7 @@ next_driver:
 
 
 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,
@@ -2307,11 +2584,24 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_cleanup(wpa_s);
 
+       if (wpa_s->drv_priv)
+               wpa_drv_deinit(wpa_s);
+
        if (notify)
                wpas_notify_iface_removed(wpa_s);
 
-       if (wpa_s->drv_priv)
-               wpa_drv_deinit(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;
+       }
 }
 
 
@@ -2361,14 +2651,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;
        }
@@ -2397,7 +2687,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;
 
@@ -2417,7 +2708,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;
@@ -2493,6 +2784,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 */
@@ -2544,7 +2842,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
-       random_init();
+       random_init(params->entropy_file);
 
        global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
        if (global->ctrl_iface == NULL) {
@@ -2569,17 +2867,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;
 }
@@ -2637,7 +2924,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);
@@ -2676,6 +2963,18 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 {
+       if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+           wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+               char country[3];
+               country[0] = wpa_s->conf->country[0];
+               country[1] = wpa_s->conf->country[1];
+               country[2] = '\0';
+               if (wpa_drv_set_country(wpa_s, country) < 0) {
+                       wpa_printf(MSG_ERROR, "Failed to set country code "
+                                  "'%s'", country);
+               }
+       }
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -2688,23 +2987,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;
@@ -2759,6 +3041,11 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        int count;
        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.
@@ -2811,3 +3098,10 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        wpa_supplicant_req_scan(wpa_s, timeout / 1000,
                                1000 * (timeout % 1000));
 }
+
+
+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);
+}