wpa_supplicant: Enable Automatic Channel Selection support for AP mode
[mech_eap.git] / wpa_supplicant / events.c
index 30f276b..2870e89 100644 (file)
@@ -1518,6 +1518,10 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
        wpas_wps_update_ap_info(wpa_s, scan_res);
 
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+           wpa_s->wpa_state < WPA_COMPLETED)
+               goto scan_work_done;
+
        wpa_scan_results_free(scan_res);
 
        if (own_request && wpa_s->scan_work) {
@@ -1570,6 +1574,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                        return 0;
                }
 
+               if (ssid != wpa_s->current_ssid &&
+                   wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+                       wpa_s->own_disconnect_req = 1;
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               }
+
                if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
                        return -1;
@@ -1844,6 +1855,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_FST
+static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
+                               const u8 *ie, size_t ie_len)
+{
+       struct mb_ies_info mb_ies;
+
+       if (!ie || !ie_len || !wpa_s->fst)
+           return -ENOENT;
+
+       os_memset(&mb_ies, 0, sizeof(mb_ies));
+
+       while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+               size_t len;
+
+               len = 2 + ie[1];
+               if (len > ie_len) {
+                       wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found",
+                                   ie, ie_len);
+                       break;
+               }
+
+               if (ie[0] == WLAN_EID_MULTI_BAND) {
+                       wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+                                  (unsigned int) len);
+                       mb_ies.ies[mb_ies.nof_ies].ie = ie + 2;
+                       mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2;
+                       mb_ies.nof_ies++;
+               }
+
+               ie_len -= len;
+               ie += len;
+       }
+
+       if (mb_ies.nof_ies > 0) {
+               wpabuf_free(wpa_s->received_mb_ies);
+               wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+#endif /* CONFIG_FST */
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                                          union wpa_event_data *data)
 {
@@ -2026,19 +2081,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        if (wpa_found || rsn_found)
                wpa_s->ap_ies_from_associnfo = 1;
 
-#ifdef CONFIG_FST
-       wpabuf_free(wpa_s->received_mb_ies);
-       wpa_s->received_mb_ies = NULL;
-       if (wpa_s->fst) {
-               struct mb_ies_info mb_ies;
-
-               wpa_printf(MSG_DEBUG, "Looking for MB IE");
-               if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies,
-                                       data->assoc_info.resp_ies_len))
-                       wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
-       }
-#endif /* CONFIG_FST */
-
        if (wpa_s->assoc_freq && data->assoc_info.freq &&
            wpa_s->assoc_freq != data->assoc_info.freq) {
                wpa_printf(MSG_DEBUG, "Operating frequency changed from "
@@ -2077,6 +2119,45 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
+                                    union wpa_event_data *data)
+{
+#ifdef CONFIG_FST
+       struct assoc_info *ai = data ? &data->assoc_info : NULL;
+       struct wpa_bss *bss = wpa_s->current_bss;
+       const u8 *ieprb, *iebcn;
+
+       wpabuf_free(wpa_s->received_mb_ies);
+       wpa_s->received_mb_ies = NULL;
+
+       if (ai &&
+           !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) {
+               wpa_printf(MSG_DEBUG,
+                          "FST: MB IEs updated from Association Response frame");
+               return;
+       }
+
+       if (ai &&
+           !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) {
+               wpa_printf(MSG_DEBUG,
+                          "FST: MB IEs updated from association event Beacon IEs");
+               return;
+       }
+
+       if (!bss)
+               return;
+
+       ieprb = (const u8 *) (bss + 1);
+       iebcn = ieprb + bss->ie_len;
+
+       if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
+               wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE");
+       else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len))
+               wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE");
+#endif /* CONFIG_FST */
+}
+
+
 static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                                       union wpa_event_data *data)
 {
@@ -2137,6 +2218,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                                "WPA/RSN IEs not updated");
        }
 
+       wpas_fst_update_mb_assoc(wpa_s, data);
+
 #ifdef CONFIG_SME
        os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
        wpa_s->sme.prev_bssid_set = 1;
@@ -3252,6 +3335,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 
        switch (event) {
        case EVENT_AUTH:
+#ifdef CONFIG_FST
+               if (!wpas_fst_update_mbie(wpa_s, data->auth.ies,
+                                         data->auth.ies_len))
+                       wpa_printf(MSG_DEBUG,
+                                  "FST: MB IEs updated from auth IE");
+#endif /* CONFIG_FST */
                sme_event_auth(wpa_s, data);
                break;
        case EVENT_ASSOC:
@@ -3849,6 +3938,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                     data->mesh_peer.ie_len);
 #endif /* CONFIG_MESH */
                break;
+       case EVENT_SURVEY:
+#ifdef CONFIG_AP
+               if (!wpa_s->ap_iface)
+                       break;
+               hostapd_event_get_survey(wpa_s->ap_iface,
+                                        &data->survey_results);
+#endif /* CONFIG_AP */
+               break;
+       case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_ACS
+               if (!wpa_s->ap_iface)
+                       break;
+               hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+                                            &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+               break;
        default:
                wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
                break;