3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-06-07 22:07:23 +02:00

netdev: support handling NL80211_CMD_ASSOC_COMEBACK

A BSS can temporarily reject associations and provide a delay that
the station should wait for before retrying. This is useful when
sane values are used, but taking it to the extreme an AP could
potentially request the client wait UINT32_MAX TU's which equates
to 49 days.

Either due to a bug, or worse by design, the kernel will wait for
however long that timeout is. Luckily the kernel also sends an event
to userspace with the amount of time it will be waiting. To guard
against excessive timeouts IWD will now handle this event and enforce
a maximum allowed value. If the timeout exceeds this IWD will
deauthenticate.
This commit is contained in:
James Prestwood 2025-05-22 11:41:52 -07:00 committed by Denis Kenzior
parent d135bfc4b8
commit c9c8790ff2

View File

@ -5451,6 +5451,39 @@ static void netdev_michael_mic_failure(struct l_genl_msg *msg,
l_debug("ifindex=%u key_idx=%u type=%u", netdev->index, idx, type); l_debug("ifindex=%u key_idx=%u type=%u", netdev->index, idx, type);
} }
#define MAX_COMEBACK_DELAY 1200
static void netdev_assoc_comeback(struct l_genl_msg *msg,
struct netdev *netdev)
{
const uint8_t *mac;
uint32_t timeout;
if (L_WARN_ON(!netdev->connected))
return;
if (nl80211_parse_attrs(msg, NL80211_ATTR_MAC, &mac,
NL80211_ATTR_TIMEOUT, &timeout,
NL80211_ATTR_UNSPEC) < 0)
return;
if (L_WARN_ON(memcmp(mac, netdev->handshake->aa, ETH_ALEN)))
return;
if (timeout <= MAX_COMEBACK_DELAY) {
l_debug(MAC" requested an association comeback delay of %u TU",
MAC_STR(netdev->handshake->aa), timeout);
return;
}
l_debug("Comeback delay of %u exceeded maximum of %u, deauthenticating",
timeout, MAX_COMEBACK_DELAY);
netdev_deauth_and_fail_connection(netdev,
NETDEV_RESULT_ASSOCIATION_FAILED,
MMPDU_STATUS_CODE_REFUSED_TEMPORARILY);
}
static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data) static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
{ {
struct netdev *netdev = NULL; struct netdev *netdev = NULL;
@ -5504,6 +5537,9 @@ static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
case NL80211_CMD_MICHAEL_MIC_FAILURE: case NL80211_CMD_MICHAEL_MIC_FAILURE:
netdev_michael_mic_failure(msg, netdev); netdev_michael_mic_failure(msg, netdev);
break; break;
case NL80211_CMD_ASSOC_COMEBACK:
netdev_assoc_comeback(msg, netdev);
break;
} }
} }