]> 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 0cc1fc26858d4c319d8bc2e88994af09340941c5..191748a8afe89bf3bc561e8b8d9e8eb85d40bd36 100644 (file)
@@ -98,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)
 {
@@ -116,6 +134,7 @@ 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);
@@ -266,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)");
@@ -627,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) {
@@ -823,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;
        }
 
@@ -846,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
@@ -858,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;
@@ -922,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 */
 
@@ -951,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);
@@ -984,7 +1029,11 @@ 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 */
 }
 
 
@@ -1131,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;
@@ -1503,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) &&
@@ -1538,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 "
@@ -1591,7 +1642,8 @@ static int disconnect_reason_recoverable(u16 reason_code)
 
 static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                                          u16 reason_code,
-                                         int locally_generated)
+                                         int locally_generated,
+                                         const u8 *addr)
 {
        const u8 *bssid;
        int authenticating;
@@ -1613,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 - "
@@ -1638,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");
@@ -1655,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;
@@ -2165,8 +2228,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                }
 #endif /* CONFIG_AP */
-               wpa_supplicant_event_disassoc(wpa_s, reason_code,
-                                             locally_generated);
+
+               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);
@@ -2505,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) {
@@ -2531,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 */
@@ -2589,7 +2682,6 @@ 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;
@@ -2598,8 +2690,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                 * 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