ft: track FT auth/action response status

Certain return codes, though failures, can indicate that the AP is
just confused or booting up and treating it as a full failure may
not be the best route.

For example in some production deployments if an AP is rebooted it
may take some time for neighboring APs to exchange keys for
current associations. If a client roams during that time it will
reject saying the PMKID is invalid.

Use the ft_associate call return to communicate the status (if any)
that was in the auth/action response. If there was a parsing error
or no response -ENOENT is still returned.
This commit is contained in:
James Prestwood 2023-08-31 05:39:22 -07:00 committed by Denis Kenzior
parent 927e27b8b5
commit 0007699677
1 changed files with 26 additions and 11 deletions

View File

@ -58,13 +58,14 @@ struct ft_info {
uint32_t frequency;
uint32_t ds_frequency;
uint32_t offchannel_id;
/* Status of Authenticate/Action frame response, or error (< 0) */
int status;
struct l_timeout *timeout;
struct wiphy_radio_work_item work;
struct ie_ft_info ft_info;
bool parsed : 1;
bool onchannel : 1;
};
@ -526,22 +527,23 @@ static int ft_over_ds_parse_action_response(const uint8_t *frame,
if (memcmp(spa, hdr->address_1, 6))
return -EINVAL;
status = l_get_le16(frame + 14);
if (status != 0)
return (int)status;
if (spa_out)
*spa_out = spa;
if (aa_out)
*aa_out = aa;
status = l_get_le16(frame + 14);
if (status != 0)
goto done;
if (ies_out && ies_len) {
*ies_out = frame + 16;
*ies_len = frame_len - 16;
}
return 0;
done:
return (int)status;
}
int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
@ -825,7 +827,7 @@ void __ft_rx_action(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
ret = ft_over_ds_parse_action_response(frame, frame_len, &spa, &aa,
&ies, &ies_len);
if (ret != 0) {
if (ret < 0) {
l_debug("Could not parse action response");
return;
}
@ -836,13 +838,22 @@ void __ft_rx_action(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
return;
}
if (ret != 0) {
l_debug("BSS "MAC" rejected FT action with status=%u",
MAC_STR(info->aa), ret);
info->status = ret;
goto done;
}
if (!ft_parse_ies(info, hs, ies, ies_len)) {
l_debug("Could not parse action response IEs");
goto ft_error;
}
info->parsed = true;
info->status = ret;
done:
l_timeout_remove(info->timeout);
info->timeout = NULL;
@ -872,6 +883,7 @@ static struct ft_info *ft_info_new(struct handshake_state *hs,
target_bss->rsne[1] + 2);
l_getrandom(info->snonce, 32);
info->status = -ENOENT;
return info;
}
@ -1016,6 +1028,7 @@ void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame,
if (status != 0) {
l_debug("BSS "MAC" rejected FT auth with status=%u",
MAC_STR(info->aa), status);
info->status = status;
goto cancel;
}
@ -1024,7 +1037,7 @@ void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame,
goto cancel;
}
info->parsed = true;
info->status = status;
cancel:
/*
@ -1164,11 +1177,13 @@ int ft_associate(uint32_t ifindex, const uint8_t *addr)
* Either failed or no response. This may have been an FT-over-DS
* attempt so clear out the entry so FT-over-Air can try again.
*/
if (!info->parsed) {
if (info->status != 0) {
int status = info->status;
l_queue_remove(info_list, info);
ft_info_destroy(info);
return -ENOENT;
return status;
}
ft_prepare_handshake(info, hs);