]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - build-utilities/hostap.git/blobdiff - wpa_supplicant/events.c
Fix crash when a local deauth occurs (squash)
[build-utilities/hostap.git] / wpa_supplicant / events.c
index 40b3026f5736b995fc62b8a01fa6b04c1d291629..191748a8afe89bf3bc561e8b8d9e8eb85d40bd36 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - Driver event processing
- * 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.
  */
 
 #include "includes.h"
@@ -104,6 +98,24 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
        }
 }
 
+void wpa_supplicant_mark_roaming(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->roaming_in_progress = 1;
+       os_memcpy(wpa_s->prev_bssid, wpa_s->bssid, ETH_ALEN);
+       wpa_s->prev_ssid = wpa_s->current_ssid;
+       wpa_dbg(wpa_s, MSG_DEBUG, "Saving prev AP info for roaming recovery - "
+               "SSID ID: %d BSSID: " MACSTR,
+               wpa_s->prev_ssid->id, MAC2STR(wpa_s->prev_bssid));
+}
+
+void wpa_supplicant_clear_roaming(struct wpa_supplicant *wpa_s,
+                                 int ignore_deauth_event)
+{
+       wpa_s->roaming_in_progress = 0;
+       wpa_s->ignore_deauth_event = ignore_deauth_event;
+       wpa_s->prev_ssid = NULL;
+       os_memset(wpa_s->prev_bssid, 0, ETH_ALEN);
+}
 
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 {
@@ -122,9 +134,13 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
                return;
 
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+       wpa_s->conf->ap_scan = DEFAULT_AP_SCAN;
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_P2P
+       os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+#endif /* CONFIG_P2P */
        wpa_s->current_bss = NULL;
        wpa_s->assoc_freq = 0;
 #ifdef CONFIG_IEEE80211R
@@ -269,7 +285,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
        else
                type = SCARD_GSM_SIM_ONLY;
 
-       wpa_s->scard = scard_init(type);
+       wpa_s->scard = scard_init(type, NULL);
        if (wpa_s->scard == NULL) {
                wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
                        "(pcsc-lite)");
@@ -630,11 +646,25 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                }
        }
 
+       if (wpa_s->roaming &&
+           os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN) == 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - current bssid (roaming)");
+               return NULL;
+       }
+
        if (ssid_len == 0) {
                wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
                return NULL;
        }
 
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+           wpa_s->current_ssid &&
+           os_memcmp(wpa_s->current_ssid->ssid, ssid_, ssid_len) != 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - block roaming to "
+                       "a different SSID while connected");
+               return NULL;
+       }
+
        wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
 
        for (ssid = group; ssid; ssid = ssid->pnext) {
@@ -788,7 +818,8 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
                                break;
                }
 
-               if (selected == NULL && wpa_s->blacklist) {
+               if (selected == NULL && wpa_s->blacklist &&
+                   !wpa_s->countermeasures) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
                                "blacklist and try again");
                        wpa_blacklist_clear(wpa_s);
@@ -825,13 +856,16 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
                        "PBC session overlap");
 #ifdef CONFIG_P2P
-               if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
+               if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1) {
+                       wpa_supplicant_clear_roaming(wpa_s, 0);
                        return -1;
+               }
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS
                wpas_wps_cancel(wpa_s);
 #endif /* CONFIG_WPS */
+               wpa_supplicant_clear_roaming(wpa_s, 0);
                return -1;
        }
 
@@ -848,7 +882,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
              0))) {
                if (wpa_supplicant_scard_init(wpa_s, ssid)) {
                        wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-                       return 0;
+                       wpa_supplicant_clear_roaming(wpa_s, 0);
                }
                wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
                        "reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
@@ -860,6 +894,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
        } else {
                wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
                        "selected AP");
+               wpa_supplicant_clear_roaming(wpa_s, 0);
        }
 
        return 0;
@@ -924,10 +959,17 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
 
        if (wpa_s->reassociate)
                return 1; /* explicit request to reassociate */
+       if (wpa_s->roaming)
+               return 1; /* explicit request to roam */
        if (wpa_s->wpa_state < WPA_ASSOCIATED)
                return 1; /* we are not associated; continue */
        if (wpa_s->current_ssid == NULL)
                return 1; /* unknown current SSID */
+       if (wpa_s->roaming_disabled) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - "
+                       "driver doesn't allow roaming now");
+               return 0;
+       }
        if (wpa_s->current_ssid != ssid)
                return 1; /* different network block */
 
@@ -953,6 +995,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        if (!current_bss)
                return 1; /* current BSS not seen in scan results */
 
+#ifndef CONFIG_NO_ROAMING
        wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
        wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
                MAC2STR(current_bss->bssid), current_bss->level);
@@ -986,9 +1029,14 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
+       wpa_supplicant_mark_roaming(wpa_s);
        return 1;
+#else /* CONFIG_NO_ROAMING */
+       return 0;
+#endif /* CONFIG_NO_ROAMING */
 }
 
+
 /* Return < 0 if no scan results could be fetched. */
 static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                                              union wpa_event_data *data)
@@ -1132,9 +1180,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                                return 0;
                        }
 #endif /* CONFIG_P2P */
-                       if (wpa_supplicant_req_sched_scan(wpa_s))
-                               wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
-                                                           timeout_usec);
+                       wpa_supplicant_req_sched_scan(wpa_s);
+                       wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+                                                   timeout_usec);
                }
        }
        return 0;
@@ -1355,6 +1403,45 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 }
 
 
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+       struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wpa_bss *bss = NULL;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (ssid->ssid_len > 0)
+               bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+       if (!bss)
+               bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+       return bss;
+}
+
+
+static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+{
+       const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+
+       if (!wpa_s->current_bss || !wpa_s->current_ssid)
+               return -1;
+
+       if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
+               return 0;
+
+       bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+                                       WPA_IE_VENDOR_TYPE);
+       bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+
+       if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+                                bss_wpa ? 2 + bss_wpa[1] : 0) ||
+           wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+                                bss_rsn ? 2 + bss_rsn[1] : 0))
+               return -1;
+
+       return 0;
+}
+
+
 static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                                       union wpa_event_data *data)
 {
@@ -1400,15 +1487,25 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                }
                if (wpa_s->current_ssid) {
                        struct wpa_bss *bss = NULL;
-                       struct wpa_ssid *ssid = wpa_s->current_ssid;
-                       if (ssid->ssid_len > 0)
-                               bss = wpa_bss_get(wpa_s, bssid,
-                                                 ssid->ssid, ssid->ssid_len);
-                       if (!bss)
-                               bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+                       bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+                       if (!bss) {
+                               wpa_supplicant_update_scan_results(wpa_s);
+
+                               /* Get the BSS from the new scan results */
+                               bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+                       }
+
                        if (bss)
                                wpa_s->current_bss = bss;
                }
+
+               if (wpa_s->conf->ap_scan == 1 &&
+                   wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
+                       if (wpa_supplicant_assoc_update_ie(wpa_s) < 0)
+                               wpa_msg(wpa_s, MSG_WARNING,
+                                       "WPA/RSN IEs not updated");
+               }
        }
 
 #ifdef CONFIG_SME
@@ -1455,6 +1552,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                /* Timeout for receiving the first EAPOL packet */
                wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
        }
+
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
        if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
@@ -1490,7 +1589,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                struct os_time now, age;
                os_get_time(&now);
                os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
-               if (age.sec == 0 && age.usec < 100000 &&
+               if (age.sec == 0 && age.usec < 500000 &&
                    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
                    0) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
@@ -1542,7 +1641,9 @@ static int disconnect_reason_recoverable(u16 reason_code)
 
 
 static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
-                                         u16 reason_code)
+                                         u16 reason_code,
+                                         int locally_generated,
+                                         const u8 *addr)
 {
        const u8 *bssid;
        int authenticating;
@@ -1564,6 +1665,13 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (addr && wpa_s->bssid && os_memcmp(wpa_s->bssid, addr, ETH_ALEN)) {
+               /* This may occur during roaming */
+               wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disconnect from"
+                       " a BSS which is not the current one");
+               return;
+       }
+
        if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
            wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
@@ -1578,6 +1686,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_COMPLETED &&
                    wpa_s->current_ssid &&
                    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+                   !locally_generated &&
                    disconnect_reason_recoverable(reason_code)) {
                        /*
                         * It looks like the AP has dropped association with
@@ -1588,7 +1697,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                        fast_reconnect = wpa_s->current_bss;
                        fast_reconnect_ssid = wpa_s->current_ssid;
                } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
-                       wpa_supplicant_req_scan(wpa_s, 0, 100000);
+                       wpa_supplicant_req_scan(wpa_s, 0, 500000);
                else
                        wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
                                "immediate scan");
@@ -1597,6 +1706,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                        "try to re-connect");
                wpa_s->reassociate = 0;
                wpa_s->disconnected = 1;
+               wpa_supplicant_cancel_sched_scan(wpa_s);
        }
        bssid = wpa_s->bssid;
        if (is_zero_ether_addr(bssid))
@@ -1604,9 +1714,13 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
        if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
                wpas_connection_failed(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
-               " reason=%d",
-               MAC2STR(bssid), reason_code);
+       if (!is_zero_ether_addr(bssid) ||
+           wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+                       " reason=%d%s",
+                       MAC2STR(bssid), reason_code,
+                       locally_generated ? " locally_generated=1" : "");
+       }
        if (wpa_supplicant_dynamic_keys(wpa_s)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
                wpa_s->keys_cleared = 0;
@@ -1675,6 +1789,9 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
 
                /* initialize countermeasures */
                wpa_s->countermeasures = 1;
+
+               wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
                wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
 
                /*
@@ -1766,11 +1883,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
                        wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
                                "driver after interface was added");
                }
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                break;
        case EVENT_INTERFACE_REMOVED:
                wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
                wpa_s->interface_removed = 1;
                wpa_supplicant_mark_disassoc(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
                l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = NULL;
 #ifdef CONFIG_IBSS_RSN
@@ -1987,18 +2106,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 {
        struct wpa_supplicant *wpa_s = ctx;
        u16 reason_code = 0;
+       int locally_generated = 0;
 
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
            event != EVENT_INTERFACE_ENABLED &&
-           event != EVENT_INTERFACE_STATUS) {
+           event != EVENT_INTERFACE_STATUS &&
+           event != EVENT_SCHED_SCAN_STOPPED) {
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "Ignore event %s (%d) while interface is disabled",
                        event_to_string(event), event);
                return;
        }
 
-       wpa_dbg(wpa_s, MSG_DEBUG, "Event %s (%d) received",
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+       int level = MSG_DEBUG;
+
+       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+           data->rx_mgmt.frame_len >= 24) {
+               const struct ieee80211_hdr *hdr;
+               u16 fc;
+               hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+               fc = le_to_host16(hdr->frame_control);
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+                       level = MSG_EXCESSIVE;
+       }
+
+       wpa_dbg(wpa_s, level, "Event %s (%d) received",
                event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
        switch (event) {
        case EVENT_AUTH:
@@ -2010,8 +2148,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_DISASSOC:
                wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
                if (data) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
-                               data->disassoc_info.reason_code);
+                       wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+                               data->disassoc_info.reason_code,
+                               data->disassoc_info.locally_generated ?
+                               " (locally generated)" : "");
                        if (data->disassoc_info.addr)
                                wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
                                        MAC2STR(data->disassoc_info.addr));
@@ -2022,9 +2162,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                               data->disassoc_info.addr);
                        break;
                }
+               if (wpa_s->ap_iface) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
+                               "AP mode");
+                       break;
+               }
 #endif /* CONFIG_AP */
                if (data) {
                        reason_code = data->disassoc_info.reason_code;
+                       locally_generated =
+                               data->disassoc_info.locally_generated;
                        wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
                                    data->disassoc_info.ie,
                                    data->disassoc_info.ie_len);
@@ -2044,8 +2191,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                "Deauthentication notification");
                        if (data) {
                                reason_code = data->deauth_info.reason_code;
-                               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
-                                       data->deauth_info.reason_code);
+                               locally_generated =
+                                       data->deauth_info.locally_generated;
+                               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+                                       data->deauth_info.reason_code,
+                                       data->deauth_info.locally_generated ?
+                                       " (locally generated)" : "");
                                if (data->deauth_info.addr) {
                                        wpa_dbg(wpa_s, MSG_DEBUG, " * address "
                                                MACSTR,
@@ -2071,8 +2222,25 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                               data->deauth_info.addr);
                        break;
                }
+               if (wpa_s->ap_iface) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
+                               "AP mode");
+                       break;
+               }
 #endif /* CONFIG_AP */
-               wpa_supplicant_event_disassoc(wpa_s, reason_code);
+
+               if (data->deauth_info.reason_code
+                   == WLAN_REASON_PREV_AUTH_NOT_VALID &&
+                   wpa_s->ignore_deauth_event) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event"
+                               " with reason=2");
+                       wpa_s->ignore_deauth_event = 0;
+               } else {
+                       wpa_supplicant_event_disassoc(wpa_s,
+                                                     reason_code,
+                                                     locally_generated,
+                                                     data->deauth_info.addr);
+               }
                break;
        case EVENT_MICHAEL_MIC_FAILURE:
                wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -2411,6 +2579,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        data->signal_change.current_noise,
                        data->signal_change.current_txrate);
                break;
+       case EVENT_ROAMING_ENABLED:
+               wpa_supplicant_enable_roaming(wpa_s);
+               break;
+       case EVENT_ROAMING_DISABLED:
+               wpa_supplicant_disable_roaming(wpa_s);
+               break;
+
+       case EVENT_START_ROAMING:
+               if (!is_zero_ether_addr(wpa_s->bssid)) {
+                       wpa_s->roaming = 1;
+                       bgscan_notify_beacon_loss(wpa_s);
+               }
+               break;
+
        case EVENT_INTERFACE_ENABLED:
                wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
@@ -2437,6 +2619,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_CHANNEL_LIST_CHANGED:
                if (wpa_s->drv_priv == NULL)
                        break; /* Ignore event during drv initialization */
+
+               free_hw_features(wpa_s);
+               wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+                       wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
 #ifdef CONFIG_P2P
                wpas_p2p_update_channel_list(wpa_s);
 #endif /* CONFIG_P2P */
@@ -2495,14 +2682,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
        case EVENT_SCHED_SCAN_STOPPED:
                wpa_s->sched_scanning = 0;
-               wpa_supplicant_notify_scanning(wpa_s, 0);
+
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+                       break;
 
                /*
                 * If we timed out, start a new sched scan to continue
                 * searching for more SSIDs.
                 */
-               if (wpa_s->sched_scan_timed_out)
-                       wpa_supplicant_req_sched_scan(wpa_s);
+               if (wpa_s->override_sched_scan) {
+                       if (wpa_supplicant_req_sched_scan(wpa_s))
+                               wpa_supplicant_req_new_scan(wpa_s,
+                                                   wpa_s->scan_interval, 0);
+               }
                break;
        case EVENT_WPS_BUTTON_PUSHED:
 #ifdef CONFIG_WPS