Commit 7d930bc3 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211: sme: deauthenticate on assoc failure

When the in-kernel SME gets an association failure from
the AP we don't deauthenticate, and thus get into a very
confused state which will lead to warnings later on. Fix
this by actually deauthenticating when the AP indicates
an association failure.

(Brought to you by the hacking session at Kernel Summit 2009 in Tokyo,
Japan. -- JWL)
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2ef6e444
...@@ -358,6 +358,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, ...@@ -358,6 +358,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev); struct wireless_dev *wdev);
void cfg80211_conn_work(struct work_struct *work); void cfg80211_conn_work(struct work_struct *work);
void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
/* internal helpers */ /* internal helpers */
......
...@@ -62,6 +62,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) ...@@ -62,6 +62,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
u8 *ie = mgmt->u.assoc_resp.variable; u8 *ie = mgmt->u.assoc_resp.variable;
int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
struct cfg80211_internal_bss *bss = NULL; struct cfg80211_internal_bss *bss = NULL;
bool need_connect_result = true;
wdev_lock(wdev); wdev_lock(wdev);
...@@ -94,6 +95,14 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) ...@@ -94,6 +95,14 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
} }
WARN_ON(!bss); WARN_ON(!bss);
} else if (wdev->conn) {
cfg80211_sme_failed_assoc(wdev);
need_connect_result = false;
/*
* do not call connect_result() now because the
* sme will schedule work that does it later.
*/
goto out;
} }
if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
......
...@@ -26,6 +26,7 @@ struct cfg80211_conn { ...@@ -26,6 +26,7 @@ struct cfg80211_conn {
CFG80211_CONN_AUTHENTICATING, CFG80211_CONN_AUTHENTICATING,
CFG80211_CONN_ASSOCIATE_NEXT, CFG80211_CONN_ASSOCIATE_NEXT,
CFG80211_CONN_ASSOCIATING, CFG80211_CONN_ASSOCIATING,
CFG80211_CONN_DEAUTH_ASSOC_FAIL,
} state; } state;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 *ie; u8 *ie;
...@@ -148,6 +149,12 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) ...@@ -148,6 +149,12 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
NULL, 0, NULL, 0,
WLAN_REASON_DEAUTH_LEAVING); WLAN_REASON_DEAUTH_LEAVING);
return err; return err;
case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
WLAN_REASON_DEAUTH_LEAVING);
/* return an error so that we call __cfg80211_connect_result() */
return -EINVAL;
default: default:
return 0; return 0;
} }
...@@ -158,6 +165,7 @@ void cfg80211_conn_work(struct work_struct *work) ...@@ -158,6 +165,7 @@ void cfg80211_conn_work(struct work_struct *work)
struct cfg80211_registered_device *rdev = struct cfg80211_registered_device *rdev =
container_of(work, struct cfg80211_registered_device, conn_work); container_of(work, struct cfg80211_registered_device, conn_work);
struct wireless_dev *wdev; struct wireless_dev *wdev;
u8 bssid[ETH_ALEN];
rtnl_lock(); rtnl_lock();
cfg80211_lock_rdev(rdev); cfg80211_lock_rdev(rdev);
...@@ -173,10 +181,10 @@ void cfg80211_conn_work(struct work_struct *work) ...@@ -173,10 +181,10 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev); wdev_unlock(wdev);
continue; continue;
} }
memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN);
if (cfg80211_conn_do_work(wdev)) if (cfg80211_conn_do_work(wdev))
__cfg80211_connect_result( __cfg80211_connect_result(
wdev->netdev, wdev->netdev, bssid,
wdev->conn->params.bssid,
NULL, 0, NULL, 0, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
false, NULL); false, NULL);
...@@ -337,6 +345,15 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) ...@@ -337,6 +345,15 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
return true; return true;
} }
void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL;
schedule_work(&rdev->conn_work);
}
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, const u8 *resp_ie, size_t resp_ie_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