SAE: Implement retransmission timer
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>
This commit is contained in:
parent
a206e2a175
commit
f3b8ad4d78
4 changed files with 103 additions and 1 deletions
|
@ -328,6 +328,10 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
|
||||||
|
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
|
|
||||||
|
#define dot11RSNASAERetransPeriod 40 /* msec */
|
||||||
|
#define dot11RSNASAESync 5 /* attempts */
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
||||||
struct sta_info *sta, int update)
|
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,
|
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
const u8 *bssid, u8 auth_transaction)
|
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.
|
* when receiving Confirm from STA.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
sta->sae->sync = 0;
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
} else {
|
} else {
|
||||||
hostapd_logger(hapd, sta->addr,
|
hostapd_logger(hapd, sta->addr,
|
||||||
HOSTAPD_MODULE_IEEE80211,
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
@ -538,6 +604,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SAE_COMMITTED:
|
case SAE_COMMITTED:
|
||||||
|
sae_clear_retransmit_timer(hapd, sta);
|
||||||
if (auth_transaction == 1) {
|
if (auth_transaction == 1) {
|
||||||
if (sae_process_commit(sta->sae) < 0)
|
if (sae_process_commit(sta->sae) < 0)
|
||||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
@ -546,14 +613,22 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
sta->sae->state = SAE_CONFIRMED;
|
sta->sae->state = SAE_CONFIRMED;
|
||||||
|
sta->sae->sync = 0;
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
} else if (hapd->conf->mesh & MESH_ENABLED) {
|
} else if (hapd->conf->mesh & MESH_ENABLED) {
|
||||||
/*
|
/*
|
||||||
* In mesh case, follow SAE finite state machine and
|
* 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);
|
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* For instructure BSS, send the postponed Confirm from
|
* 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;
|
break;
|
||||||
case SAE_CONFIRMED:
|
case SAE_CONFIRMED:
|
||||||
|
sae_clear_retransmit_timer(hapd, sta);
|
||||||
if (auth_transaction == 1) {
|
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);
|
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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);
|
ret = auth_sae_send_confirm(hapd, sta, bssid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
} else {
|
} else {
|
||||||
sta->flags |= WLAN_STA_AUTH;
|
sta->flags |= WLAN_STA_AUTH;
|
||||||
sta->auth_alg = WLAN_AUTH_SAE;
|
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));
|
MAC2STR(sta->addr));
|
||||||
ap_free_sta(hapd, sta);
|
ap_free_sta(hapd, sta);
|
||||||
} else {
|
} else {
|
||||||
|
if (sae_check_big_sync(sta))
|
||||||
|
return WLAN_STATUS_SUCCESS;
|
||||||
|
sta->sae->sync++;
|
||||||
|
|
||||||
ret = auth_sae_send_confirm(hapd, sta, bssid);
|
ret = auth_sae_send_confirm(hapd, sta, bssid);
|
||||||
sae_clear_temp_data(sta->sae);
|
sae_clear_temp_data(sta->sae);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -632,6 +718,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
if (sta->sae == NULL)
|
if (sta->sae == NULL)
|
||||||
return;
|
return;
|
||||||
sta->sae->state = SAE_NOTHING;
|
sta->sae->state = SAE_NOTHING;
|
||||||
|
sta->sae->sync = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth_transaction == 1) {
|
if (auth_transaction == 1) {
|
||||||
|
@ -685,6 +772,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sta->sae->state = SAE_COMMITTED;
|
sta->sae->state = SAE_COMMITTED;
|
||||||
|
sta->sae->sync = 0;
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,6 +871,8 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
sta->sae->state = SAE_COMMITTED;
|
sta->sae->state = SAE_COMMITTED;
|
||||||
|
sta->sae->sync = 0;
|
||||||
|
sae_set_retransmit_timer(hapd, sta);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
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);
|
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 */
|
#endif /* IEEE802_11_H */
|
||||||
|
|
|
@ -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_handle_session_warning_timer, hapd, sta);
|
||||||
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
eloop_cancel_timeout(ap_sta_disassoc_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);
|
ieee802_1x_free_station(sta);
|
||||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct sae_data {
|
||||||
u8 pmk[SAE_PMK_LEN];
|
u8 pmk[SAE_PMK_LEN];
|
||||||
struct crypto_bignum *peer_commit_scalar;
|
struct crypto_bignum *peer_commit_scalar;
|
||||||
int group;
|
int group;
|
||||||
|
int sync;
|
||||||
struct sae_temporary_data *tmp;
|
struct sae_temporary_data *tmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue