Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 */
+9 −0
Original line number Original line Diff line number Diff line
@@ -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)
		}
		}


		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) {
+19 −2
Original line number Original line Diff line number Diff line
@@ -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)
					       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)
	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)
			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)
	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,