os_memset(¶ms, 0, sizeof(params));
+ /* Save auth type, in case we need to retry after comeback timer. */
+ wpa_s->sme.assoc_auth_type = auth_type;
+
#ifdef CONFIG_FILS
if (auth_type == WLAN_AUTH_FILS_SK ||
auth_type == WLAN_AUTH_FILS_SK_PFS) {
}
+static void sme_assoc_comeback_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (!wpa_s->current_bss || !wpa_s->current_ssid) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "SME: Comeback timeout expired; SSID/BSSID cleared; ignoring");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "SME: Comeback timeout expired; retry associating with "
+ MACSTR "; mode=%d auth_type=%u",
+ MAC2STR(wpa_s->current_bss->bssid),
+ wpa_s->current_ssid->mode,
+ wpa_s->sme.assoc_auth_type);
+
+ /* Authentication state was completed already; just try association
+ * again. */
+ sme_associate(wpa_s, wpa_s->current_ssid->mode,
+ wpa_s->current_bss->bssid,
+ wpa_s->sme.assoc_auth_type);
+}
+
+
+static bool sme_try_assoc_comeback(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct ieee802_11_elems elems;
+ u32 timeout_interval;
+ unsigned long comeback_usec;
+
+ if (ieee802_11_parse_elems(data->assoc_reject.resp_ies,
+ data->assoc_reject.resp_ies_len,
+ &elems, 0) == ParseFailed) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Temporary assoc reject: failed to parse (Re)Association Response frame elements");
+ return false;
+ }
+
+ if (!elems.timeout_int) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Temporary assoc reject: missing timeout interval IE");
+ return false;
+ }
+
+ if (elems.timeout_int[0] != WLAN_TIMEOUT_ASSOC_COMEBACK) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Temporary assoc reject: missing association comeback time");
+ return false;
+ }
+
+ timeout_interval = WPA_GET_LE32(&elems.timeout_int[1]);
+ if (timeout_interval > 60000) {
+ /* This is unprotected information and there is no point in
+ * getting stuck waiting for very long duration based on it */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "SME: Ignore overly long association comeback interval: %u TUs",
+ timeout_interval);
+ return false;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "SME: Association comeback interval: %u TUs",
+ timeout_interval);
+
+ comeback_usec = timeout_interval * 1024;
+ eloop_register_timeout(comeback_usec / 1000000, comeback_usec % 1000000,
+ sme_assoc_comeback_timer, wpa_s, NULL);
+ return true;
+}
+
+
void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
union wpa_event_data *data,
const u8 **link_bssids)
{
+ const u8 *bssid;
+
+ if (wpa_s->valid_links)
+ bssid = wpa_s->ap_mld_addr;
+ else
+ bssid = wpa_s->pending_bssid;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
"status code %d", MAC2STR(wpa_s->pending_bssid),
data->assoc_reject.status_code);
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+ eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
+
+ /* Authentication phase has been completed at this point. Check whether
+ * the AP rejected association temporarily due to still holding a
+ * security associationis with us (MFP). If so, we must wait for the
+ * AP's association comeback timeout period before associating again. */
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "SME: Temporary association reject from BSS " MACSTR,
+ MAC2STR(bssid));
+ if (sme_try_assoc_comeback(wpa_s, data)) {
+ /* Break out early; comeback error is not a failure. */
+ return;
+ }
+ }
#ifdef CONFIG_SAE
if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
if (wpa_s->current_bss) {
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
- const u8 *bssid;
-
- if (wpa_s->valid_links)
- bssid = wpa_s->ap_mld_addr;
- else
- bssid = wpa_s->pending_bssid;
wpa_drv_deauthenticate(wpa_s, bssid,
WLAN_REASON_DEAUTH_LEAVING);
void sme_state_changed(struct wpa_supplicant *wpa_s)
{
/* Make sure timers are cleaned up appropriately. */
- if (wpa_s->wpa_state != WPA_ASSOCIATING)
+ if (wpa_s->wpa_state != WPA_ASSOCIATING) {
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+ eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
+ }
if (wpa_s->wpa_state != WPA_AUTHENTICATING)
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
}
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
}