aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2017-10-17 15:56:20 -0400
committerJohannes Berg <johannes.berg@intel.com>2017-10-18 03:39:44 -0400
commit51e13359cd5ea34acc62c90627603352956380af (patch)
tree1e31a3a0e4d5aed3ec1552351990686b1d6b951a
parent2bdd713b92a9cade239d3c7d15205a09f556624d (diff)
cfg80211: fix connect/disconnect edge cases
If we try to connect while already connected/connecting, but this fails, we set ssid_len=0 but leave current_bss hanging, leading to errors. Check all of this better, first of all ensuring that we can't try to connect to a different SSID while connected/ing; ensure that prev_bssid is set for re-association attempts even in the case of the driver supporting the connect() method, and don't reset ssid_len in the failure cases. While at it, also reset ssid_len while disconnecting unless we were connected and expect a disconnected event, and warn on a successful connection without ssid_len being set. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/wireless/sme.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 0a49b88070d0..b6533ecbf5b1 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -522,11 +522,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
522 return -EOPNOTSUPP; 522 return -EOPNOTSUPP;
523 523
524 if (wdev->current_bss) { 524 if (wdev->current_bss) {
525 if (!prev_bssid)
526 return -EALREADY;
527 if (prev_bssid &&
528 !ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
529 return -ENOTCONN;
530 cfg80211_unhold_bss(wdev->current_bss); 525 cfg80211_unhold_bss(wdev->current_bss);
531 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); 526 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
532 wdev->current_bss = NULL; 527 wdev->current_bss = NULL;
@@ -1063,11 +1058,35 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
1063 1058
1064 ASSERT_WDEV_LOCK(wdev); 1059 ASSERT_WDEV_LOCK(wdev);
1065 1060
1066 if (WARN_ON(wdev->connect_keys)) { 1061 /*
1067 kzfree(wdev->connect_keys); 1062 * If we have an ssid_len, we're trying to connect or are
1068 wdev->connect_keys = NULL; 1063 * already connected, so reject a new SSID unless it's the
1064 * same (which is the case for re-association.)
1065 */
1066 if (wdev->ssid_len &&
1067 (wdev->ssid_len != connect->ssid_len ||
1068 memcmp(wdev->ssid, connect->ssid, wdev->ssid_len)))
1069 return -EALREADY;
1070
1071 /*
1072 * If connected, reject (re-)association unless prev_bssid
1073 * matches the current BSSID.
1074 */
1075 if (wdev->current_bss) {
1076 if (!prev_bssid)
1077 return -EALREADY;
1078 if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
1079 return -ENOTCONN;
1069 } 1080 }
1070 1081
1082 /*
1083 * Reject if we're in the process of connecting with WEP,
1084 * this case isn't very interesting and trying to handle
1085 * it would make the code much more complex.
1086 */
1087 if (wdev->connect_keys)
1088 return -EINPROGRESS;
1089
1071 cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, 1090 cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
1072 rdev->wiphy.ht_capa_mod_mask); 1091 rdev->wiphy.ht_capa_mod_mask);
1073 1092
@@ -1118,7 +1137,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
1118 1137
1119 if (err) { 1138 if (err) {
1120 wdev->connect_keys = NULL; 1139 wdev->connect_keys = NULL;
1121 wdev->ssid_len = 0; 1140 /*
1141 * This could be reassoc getting refused, don't clear
1142 * ssid_len in that case.
1143 */
1144 if (!wdev->current_bss)
1145 wdev->ssid_len = 0;
1122 return err; 1146 return err;
1123 } 1147 }
1124 1148
@@ -1145,6 +1169,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
1145 else if (wdev->ssid_len) 1169 else if (wdev->ssid_len)
1146 err = rdev_disconnect(rdev, dev, reason); 1170 err = rdev_disconnect(rdev, dev, reason);
1147 1171
1172 /*
1173 * Clear ssid_len unless we actually were fully connected,
1174 * in which case cfg80211_disconnected() will take care of
1175 * this later.
1176 */
1177 if (!wdev->current_bss)
1178 wdev->ssid_len = 0;
1179
1148 return err; 1180 return err;
1149} 1181}
1150 1182