]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
Fix init2() driver_ops to get the correct global driver context
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index d03e9dac0ddd72d07b8e435be303644f6e47a907..5ea06f45b40c4282a57dae8a7b10e516f880f4ed 100644 (file)
@@ -29,7 +29,6 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "ctrl_iface.h"
-#include "ctrl_iface_dbus.h"
 #include "pcsc_funcs.h"
 #include "version.h"
 #include "preauth.h"
@@ -43,6 +42,8 @@
 #include "ibss_rsn.h"
 #include "sme.h"
 #include "ap.h"
+#include "notify.h"
+#include "bgscan.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -118,8 +119,7 @@ extern int wpa_debug_timestamp;
 extern struct wpa_driver_ops *wpa_drivers[];
 
 /* Configure default/group WEP keys for static WEP */
-static int wpa_set_wep_keys(struct wpa_supplicant *wpa_s,
-                           struct wpa_ssid *ssid)
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
        int i, set = 0;
 
@@ -361,6 +361,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
+       bgscan_deinit(wpa_s);
        scard_deinit(wpa_s->scard);
        wpa_s->scard = NULL;
        wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -405,6 +406,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        wpas_wps_deinit(wpa_s);
 
+       wpabuf_free(wpa_s->pending_eapol_rx);
+       wpa_s->pending_eapol_rx = NULL;
+
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
        wpa_s->ibss_rsn = NULL;
@@ -452,6 +456,10 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
        wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
        wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
        wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
        if (addr) {
                wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
                                0);
@@ -514,8 +522,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state)
        if (state != WPA_SCANNING)
                wpa_supplicant_notify_scanning(wpa_s, 0);
 
-       wpa_supplicant_dbus_notify_state_change(wpa_s, state,
-                                               wpa_s->wpa_state);
+       wpas_notify_state_changed(wpa_s, state, wpa_s->wpa_state);
 
        if (state == WPA_COMPLETED && wpa_s->new_connection) {
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
@@ -554,11 +561,13 @@ static void wpa_supplicant_terminate(int sig, void *eloop_ctx,
 
 static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 {
+       wpa_states old_state = wpa_s->wpa_state;
        wpa_s->pairwise_cipher = 0;
        wpa_s->group_cipher = 0;
        wpa_s->mgmt_group_cipher = 0;
        wpa_s->key_mgmt = 0;
        wpa_s->wpa_state = WPA_DISCONNECTED;
+       wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 }
 
 
@@ -576,7 +585,10 @@ static 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;
+
        if (wpa_s->confname == NULL)
                return -1;
        conf = wpa_config_read(wpa_s->confname);
@@ -597,7 +609,11 @@ 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);
+
        /*
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
         * pkcs11_engine_path, pkcs11_module_path.
@@ -613,8 +629,13 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        wpa_sm_set_config(wpa_s->wpa, NULL);
        wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
        rsn_preauth_deinit(wpa_s->wpa);
+
+       old_ap_scan = wpa_s->conf->ap_scan;
        wpa_config_free(wpa_s->conf);
        wpa_s->conf = conf;
+       if (old_ap_scan != wpa_s->conf->ap_scan)
+               wpas_notify_ap_scan_changed(wpa_s);
+
        if (reconf_ctrl)
                wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
 
@@ -942,13 +963,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 {
        u8 wpa_ie[80];
        size_t wpa_ie_len;
-       int use_crypt, ret, i;
+       int use_crypt, ret, i, bssid_changed;
        int algs = AUTH_ALG_OPEN_SYSTEM;
        wpa_cipher cipher_pairwise, cipher_group;
        struct wpa_driver_associate_params params;
        int wep_keys_set = 0;
        struct wpa_driver_capa capa;
        int assoc_failed = 0;
+       struct wpa_ssid *old_ssid;
 
        if (ssid->mode == 2) {
 #ifdef CONFIG_AP
@@ -979,8 +1001,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
                        " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
                        ie ? wpa_ssid_txt(ie + 2, ie[1]) : "", bss->freq);
+               bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
                os_memset(wpa_s->bssid, 0, ETH_ALEN);
                os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+               if (bssid_changed)
+                       wpas_notify_bssid_changed(wpa_s);
 #ifdef CONFIG_IEEE80211R
                ie = wpa_scan_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
                if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
@@ -1013,11 +1038,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
         * previous association. */
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
 
-       if (wpa_drv_set_mode(wpa_s, ssid->mode)) {
-               wpa_printf(MSG_WARNING, "Failed to set operating mode");
-               assoc_failed = 1;
-       }
-
 #ifdef IEEE8021X_EAPOL
        if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
                if (ssid->leap) {
@@ -1040,7 +1060,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
                           algs);
        }
-       wpa_drv_set_auth_alg(wpa_s, algs);
 
        if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
                    wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
@@ -1130,7 +1149,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
        }
 
-       wpa_drv_set_drop_unencrypted(wpa_s, use_crypt);
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
        os_memset(&params, 0, sizeof(params));
        if (bss) {
@@ -1254,9 +1272,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                 */
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
        }
+       old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = ssid;
        wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
        wpa_supplicant_initiate_eapol(wpa_s);
+       if (old_ssid != wpa_s->current_ssid)
+               wpas_notify_network_changed(wpa_s);
 }
 
 
@@ -1271,7 +1292,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code)
 {
+       struct wpa_ssid *old_ssid;
        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);
@@ -1281,9 +1304,12 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
        }
        wpa_clear_keys(wpa_s, addr);
        wpa_supplicant_mark_disassoc(wpa_s);
+       old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = NULL;
        wpa_sm_set_config(wpa_s->wpa, NULL);
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+       if (old_ssid != wpa_s->current_ssid)
+               wpas_notify_network_changed(wpa_s);
 }
 
 
@@ -1298,7 +1324,9 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
+       struct wpa_ssid *old_ssid;
        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);
@@ -1309,120 +1337,243 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
        }
        wpa_clear_keys(wpa_s, addr);
        wpa_supplicant_mark_disassoc(wpa_s);
+       old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = NULL;
        wpa_sm_set_config(wpa_s->wpa, NULL);
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+       if (old_ssid != wpa_s->current_ssid)
+               wpas_notify_network_changed(wpa_s);
 }
 
 
-static int wpa_supplicant_get_scan_results_old(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_supplicant_enable_network - Mark a configured network as enabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Enables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid)
 {
-#define SCAN_AP_LIMIT 128
-       struct wpa_scan_result *results;
-       int num, i;
-       struct wpa_scan_results *res;
-
-       results = os_malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result));
-       if (results == NULL) {
-               wpa_printf(MSG_WARNING, "Failed to allocate memory for scan "
-                          "results");
-               return -1;
-       }
+       struct wpa_ssid *other_ssid;
+       int was_disabled;
 
-       num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT);
-       wpa_printf(MSG_DEBUG, "Scan results: %d", num);
-       if (num < 0) {
-               wpa_printf(MSG_DEBUG, "Failed to get scan results");
-               os_free(results);
-               return -1;
+       if (ssid == NULL) {
+               other_ssid = wpa_s->conf->ssid;
+               while (other_ssid) {
+                       if (other_ssid == wpa_s->current_ssid &&
+                           other_ssid->disabled)
+                               wpa_s->reassociate = 1;
+
+                       was_disabled = other_ssid->disabled;
+
+                       other_ssid->disabled = 0;
+
+                       if (was_disabled != other_ssid->disabled)
+                               wpas_notify_network_enabled_changed(
+                                       wpa_s, other_ssid);
+
+                       other_ssid = other_ssid->next;
+               }
+               if (wpa_s->reassociate)
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       } else if (wpa_s->current_ssid == NULL && ssid->disabled) {
+               /*
+                * Try to reassociate since there is no current configuration
+                * and a new network was made available.
+                */
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+               was_disabled = ssid->disabled;
+
+               ssid->disabled = 0;
+
+               if (was_disabled != ssid->disabled)
+                       wpas_notify_network_enabled_changed(wpa_s, ssid);
        }
-       if (num > SCAN_AP_LIMIT) {
-               wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
-                          num, SCAN_AP_LIMIT);
-               num = SCAN_AP_LIMIT;
+}
+
+
+/**
+ * wpa_supplicant_disable_network - Mark a configured network as disabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Disables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+                                   struct wpa_ssid *ssid)
+{
+       struct wpa_ssid *other_ssid;
+       int was_disabled;
+
+       if (ssid == NULL) {
+               other_ssid = wpa_s->conf->ssid;
+               while (other_ssid) {
+                       was_disabled = other_ssid->disabled;
+
+                       other_ssid->disabled = 1;
+
+                       if (was_disabled != other_ssid->disabled)
+                               wpas_notify_network_enabled_changed(
+                                       wpa_s, other_ssid);
+
+                       other_ssid = other_ssid->next;
+               }
+               if (wpa_s->current_ssid)
+                       wpa_supplicant_disassociate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       } else {
+               if (ssid == wpa_s->current_ssid)
+                       wpa_supplicant_disassociate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+               was_disabled = ssid->disabled;
+
+               ssid->disabled = 1;
+
+               if (was_disabled != ssid->disabled)
+                       wpas_notify_network_enabled_changed(wpa_s, ssid);
        }
+}
 
-       wpa_scan_results_free(wpa_s->scan_res);
-       wpa_s->scan_res = NULL;
 
-       /* Convert old scan result data structure to the new one */
-       res = os_zalloc(sizeof(*res));
-       if (res == NULL) {
-               os_free(results);
-               return -1;
+/**
+ * wpa_supplicant_select_network - Attempt association with a network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL for any network
+ */
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid)
+{
+
+       struct wpa_ssid *other_ssid;
+
+       if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
+               wpa_supplicant_disassociate(
+                       wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+       /*
+        * Mark all other networks disabled or mark all networks enabled if no
+        * network specified.
+        */
+       other_ssid = wpa_s->conf->ssid;
+       while (other_ssid) {
+               int was_disabled = other_ssid->disabled;
+
+               other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+
+               if (was_disabled != other_ssid->disabled)
+                       wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+
+               other_ssid = other_ssid->next;
        }
-       res->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
-       if (res->res == NULL) {
-               os_free(results);
-               os_free(res);
+       wpa_s->disconnected = 0;
+       wpa_s->reassociate = 1;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+       if (ssid)
+               wpas_notify_network_selected(wpa_s, ssid);
+}
+
+
+/**
+ * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ap_scan: AP scan mode
+ * Returns: 0 if succeed or -1 if ap_scan has an invalid value
+ *
+ */
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
+{
+
+       int old_ap_scan;
+
+       if (ap_scan < 0 || ap_scan > 2)
                return -1;
-       }
 
-       for (i = 0; i < num; i++) {
-               struct wpa_scan_result *bss = &results[i];
-               struct wpa_scan_res *r;
-               size_t ie_len;
-               u8 *pos;
+       old_ap_scan = wpa_s->conf->ap_scan;
+       wpa_s->conf->ap_scan = ap_scan;
 
-               ie_len = 2 + bss->ssid_len + bss->rsn_ie_len + bss->wpa_ie_len;
-               if (bss->maxrate)
-                       ie_len += 3;
-               if (bss->mdie_present)
-                       ie_len += 5;
+       if (old_ap_scan != wpa_s->conf->ap_scan)
+               wpas_notify_ap_scan_changed(wpa_s);
 
-               r = os_zalloc(sizeof(*r) + ie_len);
-               if (r == NULL)
-                       break;
+       return 0;
+}
 
-               os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
-               r->freq = bss->freq;
-               r->caps = bss->caps;
-               r->qual = bss->qual;
-               r->noise = bss->noise;
-               r->level = bss->level;
-               r->tsf = bss->tsf;
-               r->ie_len = ie_len;
-
-               pos = (u8 *) (r + 1);
-
-               /* SSID IE */
-               *pos++ = WLAN_EID_SSID;
-               *pos++ = bss->ssid_len;
-               os_memcpy(pos, bss->ssid, bss->ssid_len);
-               pos += bss->ssid_len;
-
-               if (bss->maxrate) {
-                       /* Fake Supported Rate IE to include max rate */
-                       *pos++ = WLAN_EID_SUPP_RATES;
-                       *pos++ = 1;
-                       *pos++ = bss->maxrate;
-               }
 
-               if (bss->rsn_ie_len) {
-                       os_memcpy(pos, bss->rsn_ie, bss->rsn_ie_len);
-                       pos += bss->rsn_ie_len;
-               }
+/**
+ * wpa_supplicant_set_debug_params - Set global debug params
+ * @global: wpa_global structure
+ * @debug_level: debug level
+ * @debug_timestamp: determines if show timestamp in debug data
+ * @debug_show_keys: determines if show keys in debug data
+ * Returns: 0 if succeed or -1 if debug_level has wrong value
+ */
+int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
+                                   int debug_timestamp, int debug_show_keys)
+{
 
-               if (bss->mdie_present) {
-                       os_memcpy(pos, bss->mdie, 5);
-                       pos += 5;
-               }
+       int old_level, old_timestamp, old_show_keys;
 
-               if (bss->wpa_ie_len) {
-                       os_memcpy(pos, bss->wpa_ie, bss->wpa_ie_len);
-                       pos += bss->wpa_ie_len;
-               }
+       /* check for allowed debuglevels */
+       if (debug_level != MSG_MSGDUMP &&
+           debug_level != MSG_DEBUG &&
+           debug_level != MSG_INFO &&
+           debug_level != MSG_WARNING &&
+           debug_level != MSG_ERROR)
+               return -1;
 
-               res->res[res->num++] = r;
-       }
+       old_level = wpa_debug_level;
+       old_timestamp = wpa_debug_timestamp;
+       old_show_keys = wpa_debug_show_keys;
 
-       os_free(results);
-       wpa_s->scan_res = res;
+       wpa_debug_level = debug_level;
+       wpa_debug_timestamp = debug_timestamp ? 1 : 0;
+       wpa_debug_show_keys = debug_show_keys ? 1 : 0;
+
+       if (wpa_debug_level != old_level ||
+           wpa_debug_timestamp != old_timestamp ||
+           wpa_debug_show_keys != old_show_keys)
+               wpas_notify_debug_params_changed(global);
 
        return 0;
 }
 
 
+static void notify_bss_changes(struct wpa_supplicant *wpa_s,
+                              u8 (*prev_bssids)[ETH_ALEN], int prev_num,
+                              struct wpa_scan_results *new)
+{
+       int new_num, i, j;
+
+       new_num = new != NULL ? new->num : 0;
+       if (prev_bssids == NULL)
+               prev_num = 0;
+
+       for (i = 0; i < prev_num; i++) {
+               for (j = 0; j < new_num; j++) {
+                       if (!os_memcmp(prev_bssids[i], new->res[j]->bssid,
+                                      ETH_ALEN))
+                               break;
+               }
+               if (j == new_num)
+                       wpas_notify_bss_removed(wpa_s, prev_bssids[i]);
+       }
+       for (i = 0; i < new_num; i++) {
+               for (j = 0; j < prev_num; j++) {
+                       if (!os_memcmp(new->res[i]->bssid, prev_bssids[j],
+                                      ETH_ALEN))
+                               break;
+               }
+               if (j == prev_num)
+                       wpas_notify_bss_added(wpa_s, new->res[i]->bssid);
+       }
+}
+
+
 /**
  * wpa_supplicant_get_scan_results - Get scan results
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1433,30 +1584,39 @@ static int wpa_supplicant_get_scan_results_old(struct wpa_supplicant *wpa_s)
  */
 int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
 {
-       int ret;
+       int ret, i, prev_scan_res_num;
+       u8 (*prev_scan_bssids)[ETH_ALEN];
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-               wpa_scan_results_free(wpa_s->scan_res);
+       prev_scan_res_num = wpa_s->scan_res ? wpa_s->scan_res->num : 0;
+       prev_scan_bssids = os_malloc(prev_scan_res_num * ETH_ALEN);
+
+       if (prev_scan_bssids) {
+               for (i = 0; i < prev_scan_res_num; i++) {
+                       os_memcpy(prev_scan_bssids[i],
+                                 wpa_s->scan_res->res[i]->bssid, ETH_ALEN);
+               }
+       } else {
+               wpa_printf(MSG_WARNING, "Not enough memory for old scan "
+                          "results list");
+               prev_scan_res_num = 0;
+       }
+
+       wpa_scan_results_free(wpa_s->scan_res);
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                wpa_s->scan_res = ieee80211_sta_get_scan_results(wpa_s);
-               if (wpa_s->scan_res == NULL) {
-                       wpa_printf(MSG_DEBUG, "Failed to get scan results");
-                       ret = -1;
-               } else
-                       ret = 0;
-       } else if (wpa_s->driver->get_scan_results2 == NULL)
-               ret = wpa_supplicant_get_scan_results_old(wpa_s);
-       else {
-               wpa_scan_results_free(wpa_s->scan_res);
+       else
                wpa_s->scan_res = wpa_drv_get_scan_results2(wpa_s);
-               if (wpa_s->scan_res == NULL) {
-                       wpa_printf(MSG_DEBUG, "Failed to get scan results");
-                       ret = -1;
-               } else
-                       ret = 0;
+       if (wpa_s->scan_res == NULL) {
+               wpa_printf(MSG_DEBUG, "Failed to get scan results");
+               ret = -1;
+       } else {
+               ret = 0;
+               wpa_scan_sort_results(wpa_s->scan_res);
        }
 
-       if (wpa_s->scan_res)
-               wpa_scan_sort_results(wpa_s->scan_res);
+       notify_bss_changes(wpa_s, prev_scan_bssids, prev_scan_res_num,
+                          wpa_s->scan_res);
+       os_free(prev_scan_bssids);
 
        return ret;
 }
@@ -1544,6 +1704,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;
        }
 
@@ -1557,6 +1718,7 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                    os_strncmp(name, 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;
                }
        }
@@ -1574,6 +1736,27 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
        wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
+       if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+               /*
+                * There is possible race condition between receiving the
+                * association event and the EAPOL frame since they are coming
+                * through different paths from the driver. In order to avoid
+                * issues in trying to process the EAPOL frame before receiving
+                * association information, lets queue it for processing until
+                * the association event is received.
+                */
+               wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
+                          "received EAPOL frame");
+               wpabuf_free(wpa_s->pending_eapol_rx);
+               wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+               if (wpa_s->pending_eapol_rx) {
+                       os_get_time(&wpa_s->pending_eapol_rx_time);
+                       os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
+                                 ETH_ALEN);
+               }
+               return;
+       }
+
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface) {
                wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
@@ -1698,31 +1881,12 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                }
        }
 
-       /* Backwards compatibility call to set_wpa() handler. This is called
-        * only just after init and just before deinit, so these handler can be
-        * used to implement same functionality. */
-       if (wpa_drv_set_wpa(wpa_s, 1) < 0) {
-               struct wpa_driver_capa capa;
-               if (wpa_drv_get_capa(wpa_s, &capa) < 0 ||
-                   !(capa.flags & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-                                   WPA_DRIVER_CAPA_KEY_MGMT_WPA2))) {
-                       wpa_printf(MSG_DEBUG, "Driver does not support WPA.");
-                       /* Continue to allow non-WPA modes to be used. */
-               } else {
-                       wpa_printf(MSG_ERROR, "Failed to enable WPA in the "
-                               "driver.");
-                       return -1;
-               }
-       }
-
        wpa_clear_keys(wpa_s, NULL);
 
        /* Make sure that TKIP countermeasures are not left enabled (could
         * happen if wpa_supplicant is killed during countermeasures. */
        wpa_drv_set_countermeasures(wpa_s, 0);
 
-       wpa_drv_set_drop_unencrypted(wpa_s, 1);
-
        wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
        wpa_drv_flush_pmkid(wpa_s);
 
@@ -1964,20 +2128,11 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s)
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
 
-               /* Backwards compatibility call to set_wpa() handler. This is
-                * called only just after init and just before deinit, so these
-                * handler can be used to implement same functionality. */
-               if (wpa_drv_set_wpa(wpa_s, 0) < 0) {
-                       wpa_printf(MSG_ERROR, "Failed to disable WPA in the "
-                                  "driver.");
-               }
-
-               wpa_drv_set_drop_unencrypted(wpa_s, 0);
                wpa_drv_set_countermeasures(wpa_s, 0);
                wpa_clear_keys(wpa_s, NULL);
        }
 
-       wpas_dbus_unregister_iface(wpa_s);
+       wpas_notify_iface_removed(wpa_s);
 
        wpa_supplicant_cleanup(wpa_s);
 
@@ -2002,6 +2157,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                                                 struct wpa_interface *iface)
 {
        struct wpa_supplicant *wpa_s;
+       struct wpa_interface t_iface;
 
        if (global == NULL || iface == NULL)
                return NULL;
@@ -2010,7 +2166,22 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        if (wpa_s == NULL)
                return NULL;
 
-       if (wpa_supplicant_init_iface(wpa_s, iface)) {
+       t_iface = *iface;
+       if (global->params.override_driver) {
+               wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
+                          "('%s' -> '%s')",
+                          iface->driver, global->params.override_driver);
+               t_iface.driver = global->params.override_driver;
+       }
+       if (global->params.override_ctrl_interface) {
+               wpa_printf(MSG_DEBUG, "Override interface parameter: "
+                          "ctrl_interface ('%s' -> '%s')",
+                          iface->ctrl_interface,
+                          global->params.override_ctrl_interface);
+               t_iface.ctrl_interface =
+                       global->params.override_ctrl_interface;
+       }
+       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);
@@ -2020,13 +2191,13 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
 
        wpa_s->global = global;
 
-       /* Register the interface with the dbus control interface */
-       if (wpas_dbus_register_iface(wpa_s)) {
+       /* Notify the control interfaces about new iface */
+       if (wpas_notify_iface_added(wpa_s)) {
                wpa_supplicant_deinit_iface(wpa_s);
                os_free(wpa_s);
                return NULL;
        }
-               
+
        wpa_s->next = global->ifaces;
        global->ifaces = wpa_s;
 
@@ -2144,6 +2315,12 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params->ctrl_interface)
                global->params.ctrl_interface =
                        os_strdup(params->ctrl_interface);
+       if (params->override_driver)
+               global->params.override_driver =
+                       os_strdup(params->override_driver);
+       if (params->override_ctrl_interface)
+               global->params.override_ctrl_interface =
+                       os_strdup(params->override_ctrl_interface);
        wpa_debug_level = global->params.wpa_debug_level =
                params->wpa_debug_level;
        wpa_debug_show_keys = global->params.wpa_debug_show_keys =
@@ -2163,13 +2340,9 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
-       if (global->params.dbus_ctrl_interface) {
-               global->dbus_ctrl_iface =
-                       wpa_supplicant_dbus_ctrl_iface_init(global);
-               if (global->dbus_ctrl_iface == NULL) {
-                       wpa_supplicant_deinit(global);
-                       return NULL;
-               }
+       if (wpas_notify_supplicant_initialized(global)) {
+               wpa_supplicant_deinit(global);
+               return NULL;
        }
 
        for (i = 0; wpa_drivers[i]; i++)
@@ -2252,8 +2425,8 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
        if (global->ctrl_iface)
                wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
-       if (global->dbus_ctrl_iface)
-               wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface);
+
+       wpas_notify_supplicant_deinitialized(global);
 
        eap_peer_unregister_methods();
 #ifdef CONFIG_AP
@@ -2274,6 +2447,8 @@ void wpa_supplicant_deinit(struct wpa_global *global)
                os_free(global->params.pid_file);
        }
        os_free(global->params.ctrl_interface);
+       os_free(global->params.override_driver);
+       os_free(global->params.override_ctrl_interface);
 
        os_free(global);
        wpa_debug_close_syslog();