Commit c9c99f89 authored by Johannes Berg's avatar Johannes Berg

mac80211: act upon and report deauth while associating

When trying to associate, the AP could send a deauth frame instead.
Currently mac80211 drops that frame and doesn't report it to the
supplicant, which, in some versions and/or in certain circumstances
will simply keep trying to associate over and over again instead of
trying authentication again.

Fix this by reacting to deauth frames while associating, reporting
them to the supplicant and dropping the association attempt (which
is bound to fail.)
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f7959e9c
...@@ -2521,6 +2521,34 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, ...@@ -2521,6 +2521,34 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.auth_data = NULL; sdata->u.mgd.auth_data = NULL;
} }
static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
bool assoc)
{
struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
sdata_assert_lock(sdata);
if (!assoc) {
/*
* we are not associated yet, the only timer that could be
* running is the timeout for the association response which
* which is not relevant anymore.
*/
del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
eth_zero_addr(sdata->u.mgd.bssid);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
mutex_lock(&sdata->local->mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&sdata->local->mtx);
}
kfree(assoc_data);
sdata->u.mgd.assoc_data = NULL;
}
static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len) struct ieee80211_mgmt *mgmt, size_t len)
{ {
...@@ -2713,28 +2741,42 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ...@@ -2713,28 +2741,42 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len) struct ieee80211_mgmt *mgmt, size_t len)
{ {
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
const u8 *bssid = NULL; u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
u16 reason_code;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
if (len < 24 + 2) if (len < 24 + 2)
return; return;
if (!ifmgd->associated || if (ifmgd->associated &&
!ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) {
return; const u8 *bssid = ifmgd->associated->bssid;
bssid = ifmgd->associated->bssid; sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n",
bssid, reason_code,
ieee80211_get_reason_code_string(reason_code));
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n", ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false,
bssid, reason_code, ieee80211_get_reason_code_string(reason_code)); reason_code);
return;
}
ieee80211_set_disassoc(sdata, 0, 0, false, NULL); if (ifmgd->assoc_data &&
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
const u8 *bssid = ifmgd->assoc_data->bss->bssid;
ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); sdata_info(sdata,
"deauthenticated from %pM while associating (Reason: %u=%s)\n",
bssid, reason_code,
ieee80211_get_reason_code_string(reason_code));
ieee80211_destroy_assoc_data(sdata, false);
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
return;
}
} }
...@@ -2814,34 +2856,6 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, ...@@ -2814,34 +2856,6 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
} }
} }
static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
bool assoc)
{
struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
sdata_assert_lock(sdata);
if (!assoc) {
/*
* we are not associated yet, the only timer that could be
* running is the timeout for the association response which
* which is not relevant anymore.
*/
del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
eth_zero_addr(sdata->u.mgd.bssid);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
mutex_lock(&sdata->local->mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&sdata->local->mtx);
}
kfree(assoc_data);
sdata->u.mgd.assoc_data = NULL;
}
static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss, struct cfg80211_bss *cbss,
struct ieee80211_mgmt *mgmt, size_t len) struct ieee80211_mgmt *mgmt, size_t len)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment