]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SAE: Implement retransmission timer
authorBob Copeland <me@bobcopeland.com>
Wed, 7 Jan 2015 06:10:57 +0000 (01:10 -0500)
committerJouni Malinen <j@w1.fi>
Sat, 10 Jan 2015 15:35:52 +0000 (17:35 +0200)
Add the t0 retransmission timer as specified by IEEE Std 802.11-2012,
11.3.8.4. This makes SAE much more likely to succeed in the case of lost
frames.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/sta_info.c
src/common/sae.h

index 0459a17876b2c986c61232b9bfaa6483f669adf1..3d4488a1c7a5daea95ab538e1f5336aaafe8da48 100644 (file)
@@ -328,6 +328,10 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
 
 #ifdef CONFIG_SAE
 
+#define dot11RSNASAERetransPeriod 40   /* msec */
+#define dot11RSNASAESync 5             /* attempts */
+
+
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
                                             struct sta_info *sta, int update)
 {
@@ -483,6 +487,66 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 }
 
 
+static int sae_check_big_sync(struct sta_info *sta)
+{
+       if (sta->sae->sync > dot11RSNASAESync) {
+               sta->sae->state = SAE_NOTHING;
+               sta->sae->sync = 0;
+               return -1;
+       }
+       return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = eloop_data;
+       int ret;
+
+       if (sae_check_big_sync(sta))
+               return;
+       sta->sae->sync++;
+
+       switch (sta->sae->state) {
+       case SAE_COMMITTED:
+               ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+               eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+                                      auth_sae_retransmit_timer, hapd, sta);
+               break;
+       case SAE_CONFIRMED:
+               ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+               eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+                                      auth_sae_retransmit_timer, hapd, sta);
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+
+       if (ret != WLAN_STATUS_SUCCESS)
+               wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+                                    struct sta_info *sta)
+{
+       if (!(hapd->conf->mesh & MESH_ENABLED))
+               return;
+
+       eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+       eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+                              auth_sae_retransmit_timer, hapd, sta);
+}
+
+
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *bssid, u8 auth_transaction)
 {
@@ -530,6 +594,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                 * when receiving Confirm from STA.
                                 */
                        }
+                       sta->sae->sync = 0;
+                       sae_set_retransmit_timer(hapd, sta);
                } else {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_IEEE80211,
@@ -538,6 +604,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                }
                break;
        case SAE_COMMITTED:
+               sae_clear_retransmit_timer(hapd, sta);
                if (auth_transaction == 1) {
                        if (sae_process_commit(sta->sae) < 0)
                                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -546,14 +613,22 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                        if (ret)
                                return ret;
                        sta->sae->state = SAE_CONFIRMED;
+                       sta->sae->sync = 0;
+                       sae_set_retransmit_timer(hapd, sta);
                } else if (hapd->conf->mesh & MESH_ENABLED) {
                        /*
                         * In mesh case, follow SAE finite state machine and
-                        * send Commit now.
+                        * send Commit now, if sync count allows.
                         */
+                       if (sae_check_big_sync(sta))
+                               return WLAN_STATUS_SUCCESS;
+                       sta->sae->sync++;
+
                        ret = auth_sae_send_commit(hapd, sta, bssid, 1);
                        if (ret)
                                return ret;
+
+                       sae_set_retransmit_timer(hapd, sta);
                } else {
                        /*
                         * For instructure BSS, send the postponed Confirm from
@@ -575,7 +650,12 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                }
                break;
        case SAE_CONFIRMED:
+               sae_clear_retransmit_timer(hapd, sta);
                if (auth_transaction == 1) {
+                       if (sae_check_big_sync(sta))
+                               return WLAN_STATUS_SUCCESS;
+                       sta->sae->sync++;
+
                        ret = auth_sae_send_commit(hapd, sta, bssid, 1);
                        if (ret)
                                return ret;
@@ -586,6 +666,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                        ret = auth_sae_send_confirm(hapd, sta, bssid);
                        if (ret)
                                return ret;
+
+                       sae_set_retransmit_timer(hapd, sta);
                } else {
                        sta->flags |= WLAN_STA_AUTH;
                        sta->auth_alg = WLAN_AUTH_SAE;
@@ -603,6 +685,10 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                   MAC2STR(sta->addr));
                        ap_free_sta(hapd, sta);
                } else {
+                       if (sae_check_big_sync(sta))
+                               return WLAN_STATUS_SUCCESS;
+                       sta->sae->sync++;
+
                        ret = auth_sae_send_confirm(hapd, sta, bssid);
                        sae_clear_temp_data(sta->sae);
                        if (ret)
@@ -632,6 +718,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                if (sta->sae == NULL)
                        return;
                sta->sae->state = SAE_NOTHING;
+               sta->sae->sync = 0;
        }
 
        if (auth_transaction == 1) {
@@ -685,6 +772,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                                return;
                        }
                        sta->sae->state = SAE_COMMITTED;
+                       sta->sae->sync = 0;
+                       sae_set_retransmit_timer(hapd, sta);
                        return;
                }
 
@@ -782,6 +871,8 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
                return -1;
 
        sta->sae->state = SAE_COMMITTED;
+       sta->sae->sync = 0;
+       sae_set_retransmit_timer(hapd, sta);
 
        return 0;
 }
index 8229c5e508d5a13784a32e0337be3fc048730f12..beaeac50053a169d25550f72623ee62d42131f75 100644 (file)
@@ -90,5 +90,14 @@ void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
 
 int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
+#ifdef CONFIG_SAE
+void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+                               struct sta_info *sta);
+#else /* CONFIG_SAE */
+static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+                                             struct sta_info *sta)
+{
+}
+#endif /* CONFIG_SAE */
 
 #endif /* IEEE802_11_H */
index debdc067641608b5b32a07a87250d3d8dd3d097d..1c2197a42d3295612f3296683616cbe07ffbeb51 100644 (file)
@@ -250,6 +250,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
        eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
        eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+       sae_clear_retransmit_timer(hapd, sta);
 
        ieee802_1x_free_station(sta);
        wpa_auth_sta_deinit(sta->wpa_sm);
index 89d74ab17bfb7b1ddcb8d46707d515bb0340360c..3ebf40cf4a45d795093a6728053125280515aaae 100644 (file)
@@ -44,6 +44,7 @@ struct sae_data {
        u8 pmk[SAE_PMK_LEN];
        struct crypto_bignum *peer_commit_scalar;
        int group;
+       int sync;
        struct sae_temporary_data *tmp;
 };