3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-22 23:09:34 +01:00

ap: Implement EAPOL frame retries

This commit is contained in:
Andrew Zaborowski 2017-09-30 04:28:10 +02:00 committed by Denis Kenzior
parent 9d05a6ddb7
commit f011b81b19

View File

@ -79,6 +79,8 @@ struct sta_state {
uint8_t anonce[32]; uint8_t anonce[32];
uint8_t snonce[32]; uint8_t snonce[32];
uint8_t ptk[64]; uint8_t ptk[64];
unsigned int frame_retry;
struct l_timeout *frame_timeout;
bool have_anonce : 1; bool have_anonce : 1;
bool ptk_complete : 1; bool ptk_complete : 1;
}; };
@ -97,6 +99,9 @@ static void ap_sta_free(void *data)
if (sta->assoc_resp_cmd_id) if (sta->assoc_resp_cmd_id)
l_genl_family_cancel(nl80211, sta->assoc_resp_cmd_id); l_genl_family_cancel(nl80211, sta->assoc_resp_cmd_id);
if (sta->frame_timeout)
l_timeout_remove(sta->frame_timeout);
l_free(sta); l_free(sta);
} }
@ -257,6 +262,11 @@ static void ap_drop_rsna(struct ap_state *ap, struct sta_state *sta)
sta->rsna = false; sta->rsna = false;
if (sta->frame_timeout) {
l_timeout_remove(sta->frame_timeout);
sta->frame_timeout = NULL;
}
msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 128); msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 128);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr); l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);
@ -289,6 +299,40 @@ static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
rsn->group_cipher = IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC; rsn->group_cipher = IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC;
} }
/* Default dot11RSNAConfigPairwiseUpdateCount value */
#define AP_PAIRWISE_UPDATE_COUNT 3
static void ap_set_eapol_key_timeout(struct sta_state *sta,
l_timeout_notify_cb_t cb)
{
/*
* 802.11-2016 12.7.6.6: "The retransmit timeout value shall be
* 100 ms for the first timeout, half the listen interval for the
* second timeout, and the listen interval for subsequent timeouts.
* If there is no listen interval or the listen interval is zero,
* then 100 ms shall be used for all timeout values."
*/
unsigned int timeout_ms = 100;
unsigned int beacon_us = sta->ap->beacon_interval * 1024;
sta->frame_retry++;
if (sta->frame_retry == 2 && sta->listen_interval != 0)
timeout_ms = sta->listen_interval * beacon_us / 2000;
else if (sta->frame_retry > 2 && sta->listen_interval != 0)
timeout_ms = sta->listen_interval * beacon_us / 1000;
if (sta->frame_retry > 1)
l_timeout_modify_ms(sta->frame_timeout, timeout_ms);
else {
if (sta->frame_timeout)
l_timeout_remove(sta->frame_timeout);
sta->frame_timeout = l_timeout_create_ms(timeout_ms, cb, sta,
NULL);
}
}
/* 802.11-2016 Section 12.7.6.2 */ /* 802.11-2016 Section 12.7.6.2 */
static void ap_send_ptk_1_of_4(struct ap_state *ap, struct sta_state *sta) static void ap_send_ptk_1_of_4(struct ap_state *ap, struct sta_state *sta)
{ {
@ -332,6 +376,22 @@ static void ap_send_ptk_1_of_4(struct ap_state *ap, struct sta_state *sta)
(struct eapol_frame *) ek); (struct eapol_frame *) ek);
} }
static void ap_ptk_1_of_4_retry(struct l_timeout *timeout, void *user_data)
{
struct sta_state *sta = user_data;
if (sta->frame_retry >= AP_PAIRWISE_UPDATE_COUNT) {
/* TODO: Send Deauthenticate */
return;
}
ap_send_ptk_1_of_4(sta->ap, sta);
ap_set_eapol_key_timeout(sta, ap_ptk_1_of_4_retry);
l_debug("attempt %i", sta->frame_retry);
}
/* 802.11-2016 Section 12.7.6.4 */ /* 802.11-2016 Section 12.7.6.4 */
static void ap_send_ptk_3_of_4(struct ap_state *ap, struct sta_state *sta) static void ap_send_ptk_3_of_4(struct ap_state *ap, struct sta_state *sta)
{ {
@ -391,6 +451,22 @@ static void ap_send_ptk_3_of_4(struct ap_state *ap, struct sta_state *sta)
(struct eapol_frame *) ek); (struct eapol_frame *) ek);
} }
static void ap_ptk_3_of_4_retry(struct l_timeout *timeout, void *user_data)
{
struct sta_state *sta = user_data;
if (sta->frame_retry >= AP_PAIRWISE_UPDATE_COUNT) {
/* TODO: Send Deauthenticate */
return;
}
ap_send_ptk_3_of_4(sta->ap, sta);
ap_set_eapol_key_timeout(sta, ap_ptk_3_of_4_retry);
l_debug("attempt %i", sta->frame_retry);
}
/* 802.11-2016 Section 12.7.6.3 */ /* 802.11-2016 Section 12.7.6.3 */
static void ap_handle_ptk_2_of_4(struct sta_state *sta, static void ap_handle_ptk_2_of_4(struct sta_state *sta,
const struct eapol_key *ek) const struct eapol_key *ek)
@ -433,8 +509,8 @@ static void ap_handle_ptk_2_of_4(struct sta_state *sta,
memcpy(sta->snonce, ek->key_nonce, sizeof(sta->snonce)); memcpy(sta->snonce, ek->key_nonce, sizeof(sta->snonce));
sta->ptk_complete = true; sta->ptk_complete = true;
/* TODO: retry counters and timers */ sta->frame_retry = 0;
ap_send_ptk_3_of_4(sta->ap, sta); ap_ptk_3_of_4_retry(NULL, sta);
} }
/* 802.11-2016 Section 12.7.6.5 */ /* 802.11-2016 Section 12.7.6.5 */
@ -454,6 +530,9 @@ static void ap_handle_ptk_4_of_4(struct sta_state *sta,
if (!eapol_verify_mic(ptk->kck, ek)) if (!eapol_verify_mic(ptk->kck, ek))
return; return;
l_timeout_remove(sta->frame_timeout);
sta->frame_timeout = NULL;
ap_new_rsna(sta->ap, sta); ap_new_rsna(sta->ap, sta);
} }
@ -636,8 +715,8 @@ static void ap_new_sta_cb(struct l_genl_msg *msg, void *user_data)
return; return;
} }
/* TODO: retry counters and timers */ sta->frame_retry = 0;
ap_send_ptk_1_of_4(sta->ap, sta); ap_ptk_1_of_4_retry(NULL, sta);
} }
static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta) static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta)
@ -697,6 +776,11 @@ static void ap_disassociate_sta(struct ap_state *ap, struct sta_state *sta)
sta->associated = false; sta->associated = false;
sta->rsna = false; sta->rsna = false;
if (sta->frame_timeout) {
l_timeout_remove(sta->frame_timeout);
sta->frame_timeout = NULL;
}
msg = l_genl_msg_new_sized(NL80211_CMD_DEL_STATION, 64); msg = l_genl_msg_new_sized(NL80211_CMD_DEL_STATION, 64);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr); l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);