From 45c94154a61d932174232e19f096e346a129b028 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 26 Dec 2008 12:30:34 +0200 Subject: [PATCH] Updated SA Query procedure to use timeouts per 802.11w/D7.0 The previous max_attempts * timeout is now replaced with two timeouts (one for each retry, the other one for maximum wait). --- hostapd/ap.h | 1 + hostapd/config.c | 26 ++++++++++++----------- hostapd/config.h | 8 ++++---- hostapd/hostapd.conf | 14 +++++++------ hostapd/ieee802_11.c | 17 ++++++++++++--- hostapd/sta_info.c | 49 +++++++++++++++++++++++++++++++------------- hostapd/sta_info.h | 1 + 7 files changed, 77 insertions(+), 39 deletions(-) diff --git a/hostapd/ap.h b/hostapd/ap.h index 4f67e276e..98f8ee744 100644 --- a/hostapd/ap.h +++ b/hostapd/ap.h @@ -106,6 +106,7 @@ struct sta_info { u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * * sa_query_count octets of pending SA Query * transaction identifiers */ + struct os_time sa_query_start; #endif /* CONFIG_IEEE80211W */ struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ diff --git a/hostapd/config.c b/hostapd/config.c index 39cc18d77..650ddb92d 100644 --- a/hostapd/config.c +++ b/hostapd/config.c @@ -184,8 +184,8 @@ static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->max_listen_interval = 65535; #ifdef CONFIG_IEEE80211W - bss->assoc_ping_timeout = 1000; - bss->assoc_ping_attempts = 3; + bss->assoc_sa_query_max_timeout = 1000; + bss->assoc_sa_query_retry_timeout = 201; #endif /* CONFIG_IEEE80211W */ #ifdef EAP_FAST /* both anonymous and authenticated provisioning */ @@ -2064,18 +2064,20 @@ struct hostapd_config * hostapd_config_read(const char *fname) #ifdef CONFIG_IEEE80211W } else if (os_strcmp(buf, "ieee80211w") == 0) { bss->ieee80211w = atoi(pos); - } else if (os_strcmp(buf, "assoc_ping_timeout") == 0) { - bss->assoc_ping_timeout = atoi(pos); - if (bss->assoc_ping_timeout == 0) { - printf("Line %d: invalid assoc_ping_timeout\n", - line); + } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { + bss->assoc_sa_query_max_timeout = atoi(pos); + if (bss->assoc_sa_query_max_timeout == 0) { + printf("Line %d: invalid " + "assoc_sa_query_max_timeout\n", + line); errors++; } - } else if (os_strcmp(buf, "assoc_ping_attempts") == 0) { - bss->assoc_ping_timeout = atoi(pos); - if (bss->assoc_ping_timeout == 0) { - printf("Line %d: invalid assoc_ping_attempts " - "(valid range: 1..255)\n", + } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) + { + bss->assoc_sa_query_retry_timeout = atoi(pos); + if (bss->assoc_sa_query_retry_timeout == 0) { + printf("Line %d: invalid " + "assoc_sa_query_retry_timeout\n", line); errors++; } diff --git a/hostapd/config.h b/hostapd/config.h index 68b985685..c9c715c92 100644 --- a/hostapd/config.h +++ b/hostapd/config.h @@ -210,10 +210,10 @@ struct hostapd_bss_config { IEEE80211W_OPTIONAL = 1, IEEE80211W_REQUIRED = 2 } ieee80211w; - /* dot11AssociationPingResponseTimeout (in TU) */ - unsigned int assoc_ping_timeout; - /* dot11AssociationMaximumPingAttempts */ - int assoc_ping_attempts; + /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ + unsigned int assoc_sa_query_max_timeout; + /* dot11AssociationSAQueryRetryTimeout (in TUs) */ + int assoc_sa_query_retry_timeout; #endif /* CONFIG_IEEE80211W */ int wpa_pairwise; int wpa_group; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index eaf0d4e13..973257350 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -755,13 +755,15 @@ own_ip_addr=127.0.0.1 # 2 = required #ieee80211w=0 -# Association ping timeout (in TU = 1.024 ms; for MFP) -# dot11AssociationPingResponseTimeout, 1...4294967295 -#assoc_ping_timeout=1000 +# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) +# (maximum time to wait for a SA Query response) +# dot11AssociationSAQueryMaximumTimeout, 1...4294967295 +#assoc_sa_query_max_timeout=1000 -# Maximum number of association pings -# dot11AssociationMaximumPingAttempts , 1...255 -#assoc_ping_attempts=3 +# Association SA Query retry timeout (in TU = 1.024 ms; for MFP) +# (time between two subsequent SA Query requests) +# dot11AssociationSAQueryRetryTimeout, 1...4294967295 +#assoc_sa_query_retry_timeout=201 # okc: Opportunistic Key Caching (aka Proactive Key Caching) diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c index b80e6c394..c8f6ed859 100644 --- a/hostapd/ieee802_11.c +++ b/hostapd/ieee802_11.c @@ -298,12 +298,20 @@ static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, struct sta_info *sta, u8 *eid) { u8 *pos = eid; - u32 timeout; + u32 timeout, tu; + struct os_time now, passed; *pos++ = WLAN_EID_ASSOC_COMEBACK_TIME; *pos++ = 4; - timeout = (hapd->conf->assoc_ping_attempts - sta->sa_query_count + 1) * - hapd->conf->assoc_ping_timeout; + os_get_time(&now); + os_time_sub(&now, &sta->sa_query_start, &passed); + tu = (passed.sec * 1000000 + passed.usec) / 1024; + if (hapd->conf->assoc_sa_query_max_timeout > tu) + timeout = hapd->conf->assoc_sa_query_max_timeout - tu; + else + timeout = 0; + if (timeout < hapd->conf->assoc_sa_query_max_timeout) + timeout++; /* add some extra time for local timers */ WPA_PUT_LE32(pos, timeout); pos += 4; @@ -893,6 +901,9 @@ static void handle_assoc(struct hostapd_data *hapd, if (resp != WLAN_STATUS_SUCCESS) goto fail; #ifdef CONFIG_IEEE80211W + if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + sta->sa_query_count > 0) + ap_check_sa_query_timeout(hapd, sta); if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out) { /* * STA has already been associated with MFP and SA diff --git a/hostapd/sta_info.c b/hostapd/sta_info.c index 3beda7f90..df1190135 100644 --- a/hostapd/sta_info.c +++ b/hostapd/sta_info.c @@ -637,6 +637,30 @@ static void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, } +int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) +{ + u32 tu; + struct os_time now, passed; + os_get_time(&now); + os_time_sub(&now, &sta->sa_query_start, &passed); + tu = (passed.sec * 1000000 + passed.usec) / 1024; + if (hapd->conf->assoc_sa_query_max_timeout < tu) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "association SA Query timed out"); + sta->sa_query_timed_out = 1; + os_free(sta->sa_query_trans_id); + sta->sa_query_trans_id = NULL; + sta->sa_query_count = 0; + eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); + return 1; + } + + return 0; +} + + static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) { struct hostapd_data *hapd = eloop_ctx; @@ -644,37 +668,34 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) unsigned int timeout, sec, usec; u8 *trans_id, *nbuf; - if (sta->sa_query_count >= hapd->conf->assoc_ping_attempts) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association SA Query timed out"); - sta->sa_query_timed_out = 1; - os_free(sta->sa_query_trans_id); - sta->sa_query_trans_id = NULL; - sta->sa_query_count = 0; + if (sta->sa_query_count > 0 && + ap_check_sa_query_timeout(hapd, sta)) return; - } nbuf = os_realloc(sta->sa_query_trans_id, (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN); if (nbuf == NULL) return; + if (sta->sa_query_count == 0) { + /* Starting a new SA Query procedure */ + os_get_time(&sta->sa_query_start); + } trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; sta->sa_query_trans_id = nbuf; sta->sa_query_count++; os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN); + timeout = hapd->conf->assoc_sa_query_retry_timeout; + sec = ((timeout / 1000) * 1024) / 1000; + usec = (timeout % 1000) * 1024; + eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "association SA Query attempt %d", sta->sa_query_count); ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); - - timeout = hapd->conf->assoc_ping_timeout; - sec = ((timeout / 1000) * 1024) / 1000; - usec = (timeout % 1000) * 1024; - eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); } diff --git a/hostapd/sta_info.h b/hostapd/sta_info.h index 024cf33b7..e83597092 100644 --- a/hostapd/sta_info.h +++ b/hostapd/sta_info.h @@ -38,5 +38,6 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, int old_vlanid); void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); +int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); #endif /* STA_INFO_H */