aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-01-20 07:55:25 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-06 14:50:37 -0500
commit95de817b9034d50860319f6033ec85d25024694c (patch)
tree8dc100ec6a5ee527a6e86b33e904f5f9d14181ab /net/wireless
parent7852e36186d2a1983c215836d7e3d7b8927c930d (diff)
cfg80211: stop tracking authenticated state
To track authenticated state seems to have been a design mistake in cfg80211. It is possible to have out of band authentication (FT), tracking multiple authentications caused more problems than it ever helped, and the implementation in mac80211 is too complex. Remove all this complexity, and let userspace do whatever it wants to, mac80211 can deal with that just fine. Association is still tracked of course, but authentication no longer is. Local auth state changes are thus no longer of value, so ignore them completely. This will also help implement SAE -- asking the driver to do an authentication is now almost equivalent to sending an authentication frame, with the exception of shared key authentication which is still handled completely. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.h9
-rw-r--r--net/wireless/mlme.c322
-rw-r--r--net/wireless/nl80211.c18
-rw-r--r--net/wireless/sme.c41
4 files changed, 72 insertions, 318 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 43ad9c81efcf..2b454caf4395 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -325,15 +325,13 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
325 const u8 *bssid, 325 const u8 *bssid,
326 const u8 *ssid, int ssid_len, 326 const u8 *ssid, int ssid_len,
327 const u8 *ie, int ie_len, 327 const u8 *ie, int ie_len,
328 const u8 *key, int key_len, int key_idx, 328 const u8 *key, int key_len, int key_idx);
329 bool local_state_change);
330int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 329int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
331 struct net_device *dev, struct ieee80211_channel *chan, 330 struct net_device *dev, struct ieee80211_channel *chan,
332 enum nl80211_auth_type auth_type, const u8 *bssid, 331 enum nl80211_auth_type auth_type, const u8 *bssid,
333 const u8 *ssid, int ssid_len, 332 const u8 *ssid, int ssid_len,
334 const u8 *ie, int ie_len, 333 const u8 *ie, int ie_len,
335 const u8 *key, int key_len, int key_idx, 334 const u8 *key, int key_len, int key_idx);
336 bool local_state_change);
337int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 335int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
338 struct net_device *dev, 336 struct net_device *dev,
339 struct ieee80211_channel *chan, 337 struct ieee80211_channel *chan,
@@ -421,7 +419,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
421 size_t ie_len, u16 reason, bool from_ap); 419 size_t ie_len, u16 reason, bool from_ap);
422void cfg80211_sme_scan_done(struct net_device *dev); 420void cfg80211_sme_scan_done(struct net_device *dev);
423void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 421void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
424void cfg80211_sme_disassoc(struct net_device *dev, int idx); 422void cfg80211_sme_disassoc(struct net_device *dev,
423 struct cfg80211_internal_bss *bss);
425void __cfg80211_scan_done(struct work_struct *wk); 424void __cfg80211_scan_done(struct work_struct *wk);
426void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); 425void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
427void __cfg80211_sched_scan_results(struct work_struct *wk); 426void __cfg80211_sched_scan_results(struct work_struct *wk);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 438dfc105b4a..d553d365e751 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -20,40 +20,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
20 struct wireless_dev *wdev = dev->ieee80211_ptr; 20 struct wireless_dev *wdev = dev->ieee80211_ptr;
21 struct wiphy *wiphy = wdev->wiphy; 21 struct wiphy *wiphy = wdev->wiphy;
22 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 22 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
23 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
24 u8 *bssid = mgmt->bssid;
25 int i;
26 u16 status = le16_to_cpu(mgmt->u.auth.status_code);
27 bool done = false;
28 23
29 wdev_lock(wdev); 24 wdev_lock(wdev);
30 25
31 for (i = 0; i < MAX_AUTH_BSSES; i++) { 26 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
32 if (wdev->authtry_bsses[i] && 27 cfg80211_sme_rx_auth(dev, buf, len);
33 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
34 ETH_ALEN) == 0) {
35 if (status == WLAN_STATUS_SUCCESS) {
36 wdev->auth_bsses[i] = wdev->authtry_bsses[i];
37 } else {
38 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
39 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
40 }
41 wdev->authtry_bsses[i] = NULL;
42 done = true;
43 break;
44 }
45 }
46
47 if (done) {
48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
49 cfg80211_sme_rx_auth(dev, buf, len);
50 }
51 28
52 wdev_unlock(wdev); 29 wdev_unlock(wdev);
53} 30}
54EXPORT_SYMBOL(cfg80211_send_rx_auth); 31EXPORT_SYMBOL(cfg80211_send_rx_auth);
55 32
56void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) 33void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
34 const u8 *buf, size_t len)
57{ 35{
58 u16 status_code; 36 u16 status_code;
59 struct wireless_dev *wdev = dev->ieee80211_ptr; 37 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -61,8 +39,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
61 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 39 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
62 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 40 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
63 u8 *ie = mgmt->u.assoc_resp.variable; 41 u8 *ie = mgmt->u.assoc_resp.variable;
64 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 42 int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
65 struct cfg80211_internal_bss *bss = NULL;
66 43
67 wdev_lock(wdev); 44 wdev_lock(wdev);
68 45
@@ -75,43 +52,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
75 * frame instead of reassoc. 52 * frame instead of reassoc.
76 */ 53 */
77 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && 54 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
78 cfg80211_sme_failed_reassoc(wdev)) 55 cfg80211_sme_failed_reassoc(wdev)) {
56 cfg80211_put_bss(bss);
79 goto out; 57 goto out;
58 }
80 59
81 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); 60 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
82 61
83 if (status_code == WLAN_STATUS_SUCCESS) { 62 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
84 for (i = 0; i < MAX_AUTH_BSSES; i++) {
85 if (!wdev->auth_bsses[i])
86 continue;
87 if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
88 ETH_ALEN) == 0) {
89 bss = wdev->auth_bsses[i];
90 wdev->auth_bsses[i] = NULL;
91 /* additional reference to drop hold */
92 cfg80211_ref_bss(bss);
93 break;
94 }
95 }
96
97 /*
98 * We might be coming here because the driver reported
99 * a successful association at the same time as the
100 * user requested a deauth. In that case, we will have
101 * removed the BSS from the auth_bsses list due to the
102 * deauth request when the assoc response makes it. If
103 * the two code paths acquire the lock the other way
104 * around, that's just the standard situation of a
105 * deauth being requested while connected.
106 */
107 if (!bss)
108 goto out;
109 } else if (wdev->conn) {
110 cfg80211_sme_failed_assoc(wdev); 63 cfg80211_sme_failed_assoc(wdev);
111 /* 64 /*
112 * do not call connect_result() now because the 65 * do not call connect_result() now because the
113 * sme will schedule work that does it later. 66 * sme will schedule work that does it later.
114 */ 67 */
68 cfg80211_put_bss(bss);
115 goto out; 69 goto out;
116 } 70 }
117 71
@@ -124,17 +78,10 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
124 wdev->sme_state = CFG80211_SME_CONNECTING; 78 wdev->sme_state = CFG80211_SME_CONNECTING;
125 } 79 }
126 80
127 /* this consumes one bss reference (unless bss is NULL) */ 81 /* this consumes the bss reference */
128 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, 82 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
129 status_code, 83 status_code,
130 status_code == WLAN_STATUS_SUCCESS, 84 status_code == WLAN_STATUS_SUCCESS, bss);
131 bss ? &bss->pub : NULL);
132 /* drop hold now, and also reference acquired above */
133 if (bss) {
134 cfg80211_unhold_bss(bss);
135 cfg80211_put_bss(&bss->pub);
136 }
137
138 out: 85 out:
139 wdev_unlock(wdev); 86 wdev_unlock(wdev);
140} 87}
@@ -148,8 +95,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
148 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 95 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
149 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 96 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
150 const u8 *bssid = mgmt->bssid; 97 const u8 *bssid = mgmt->bssid;
151 int i; 98 bool was_current = false;
152 bool found = false, was_current = false;
153 99
154 ASSERT_WDEV_LOCK(wdev); 100 ASSERT_WDEV_LOCK(wdev);
155 101
@@ -158,32 +104,9 @@ void __cfg80211_send_deauth(struct net_device *dev,
158 cfg80211_unhold_bss(wdev->current_bss); 104 cfg80211_unhold_bss(wdev->current_bss);
159 cfg80211_put_bss(&wdev->current_bss->pub); 105 cfg80211_put_bss(&wdev->current_bss->pub);
160 wdev->current_bss = NULL; 106 wdev->current_bss = NULL;
161 found = true;
162 was_current = true; 107 was_current = true;
163 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
164 if (wdev->auth_bsses[i] &&
165 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
166 cfg80211_unhold_bss(wdev->auth_bsses[i]);
167 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
168 wdev->auth_bsses[i] = NULL;
169 found = true;
170 break;
171 }
172 if (wdev->authtry_bsses[i] &&
173 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
174 ETH_ALEN) == 0 &&
175 memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) == 0) {
176 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
177 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
178 wdev->authtry_bsses[i] = NULL;
179 found = true;
180 break;
181 }
182 } 108 }
183 109
184 if (!found)
185 return;
186
187 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); 110 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
188 111
189 if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { 112 if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
@@ -220,10 +143,8 @@ void __cfg80211_send_disassoc(struct net_device *dev,
220 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 143 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
221 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 144 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
222 const u8 *bssid = mgmt->bssid; 145 const u8 *bssid = mgmt->bssid;
223 int i;
224 u16 reason_code; 146 u16 reason_code;
225 bool from_ap; 147 bool from_ap;
226 bool done = false;
227 148
228 ASSERT_WDEV_LOCK(wdev); 149 ASSERT_WDEV_LOCK(wdev);
229 150
@@ -234,16 +155,10 @@ void __cfg80211_send_disassoc(struct net_device *dev,
234 155
235 if (wdev->current_bss && 156 if (wdev->current_bss &&
236 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 157 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
237 for (i = 0; i < MAX_AUTH_BSSES; i++) { 158 cfg80211_sme_disassoc(dev, wdev->current_bss);
238 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) 159 cfg80211_unhold_bss(wdev->current_bss);
239 continue; 160 cfg80211_put_bss(&wdev->current_bss->pub);
240 wdev->auth_bsses[i] = wdev->current_bss; 161 wdev->current_bss = NULL;
241 wdev->current_bss = NULL;
242 done = true;
243 cfg80211_sme_disassoc(dev, i);
244 break;
245 }
246 WARN_ON(!done);
247 } else 162 } else
248 WARN_ON(1); 163 WARN_ON(1);
249 164
@@ -287,34 +202,6 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
287} 202}
288EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); 203EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
289 204
290static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
291{
292 int i;
293 bool done = false;
294
295 ASSERT_WDEV_LOCK(wdev);
296
297 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
298 if (wdev->authtry_bsses[i] &&
299 memcmp(wdev->authtry_bsses[i]->pub.bssid,
300 addr, ETH_ALEN) == 0) {
301 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
302 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
303 wdev->authtry_bsses[i] = NULL;
304 done = true;
305 break;
306 }
307 }
308
309 WARN_ON(!done);
310}
311
312void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
313{
314 __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
315}
316EXPORT_SYMBOL(__cfg80211_auth_canceled);
317
318void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 205void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
319{ 206{
320 struct wireless_dev *wdev = dev->ieee80211_ptr; 207 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -329,8 +216,6 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
329 WLAN_STATUS_UNSPECIFIED_FAILURE, 216 WLAN_STATUS_UNSPECIFIED_FAILURE,
330 false, NULL); 217 false, NULL);
331 218
332 __cfg80211_auth_remove(wdev, addr);
333
334 wdev_unlock(wdev); 219 wdev_unlock(wdev);
335} 220}
336EXPORT_SYMBOL(cfg80211_send_auth_timeout); 221EXPORT_SYMBOL(cfg80211_send_auth_timeout);
@@ -340,8 +225,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
340 struct wireless_dev *wdev = dev->ieee80211_ptr; 225 struct wireless_dev *wdev = dev->ieee80211_ptr;
341 struct wiphy *wiphy = wdev->wiphy; 226 struct wiphy *wiphy = wdev->wiphy;
342 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 227 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
343 int i;
344 bool done = false;
345 228
346 wdev_lock(wdev); 229 wdev_lock(wdev);
347 230
@@ -351,20 +234,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
351 WLAN_STATUS_UNSPECIFIED_FAILURE, 234 WLAN_STATUS_UNSPECIFIED_FAILURE,
352 false, NULL); 235 false, NULL);
353 236
354 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
355 if (wdev->auth_bsses[i] &&
356 memcmp(wdev->auth_bsses[i]->pub.bssid,
357 addr, ETH_ALEN) == 0) {
358 cfg80211_unhold_bss(wdev->auth_bsses[i]);
359 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
360 wdev->auth_bsses[i] = NULL;
361 done = true;
362 break;
363 }
364 }
365
366 WARN_ON(!done);
367
368 wdev_unlock(wdev); 237 wdev_unlock(wdev);
369} 238}
370EXPORT_SYMBOL(cfg80211_send_assoc_timeout); 239EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
@@ -403,13 +272,11 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
403 const u8 *bssid, 272 const u8 *bssid,
404 const u8 *ssid, int ssid_len, 273 const u8 *ssid, int ssid_len,
405 const u8 *ie, int ie_len, 274 const u8 *ie, int ie_len,
406 const u8 *key, int key_len, int key_idx, 275 const u8 *key, int key_len, int key_idx)
407 bool local_state_change)
408{ 276{
409 struct wireless_dev *wdev = dev->ieee80211_ptr; 277 struct wireless_dev *wdev = dev->ieee80211_ptr;
410 struct cfg80211_auth_request req; 278 struct cfg80211_auth_request req;
411 struct cfg80211_internal_bss *bss; 279 int err;
412 int i, err, slot = -1, nfree = 0;
413 280
414 ASSERT_WDEV_LOCK(wdev); 281 ASSERT_WDEV_LOCK(wdev);
415 282
@@ -421,20 +288,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
421 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) 288 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
422 return -EALREADY; 289 return -EALREADY;
423 290
424 for (i = 0; i < MAX_AUTH_BSSES; i++) {
425 if (wdev->authtry_bsses[i] &&
426 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
427 ETH_ALEN) == 0)
428 return -EALREADY;
429 if (wdev->auth_bsses[i] &&
430 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
431 ETH_ALEN) == 0)
432 return -EALREADY;
433 }
434
435 memset(&req, 0, sizeof(req)); 291 memset(&req, 0, sizeof(req));
436 292
437 req.local_state_change = local_state_change;
438 req.ie = ie; 293 req.ie = ie;
439 req.ie_len = ie_len; 294 req.ie_len = ie_len;
440 req.auth_type = auth_type; 295 req.auth_type = auth_type;
@@ -446,39 +301,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
446 if (!req.bss) 301 if (!req.bss)
447 return -ENOENT; 302 return -ENOENT;
448 303
449 bss = bss_from_pub(req.bss);
450
451 for (i = 0; i < MAX_AUTH_BSSES; i++) {
452 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
453 slot = i;
454 nfree++;
455 }
456 }
457
458 /* we need one free slot for disassoc and one for this auth */
459 if (nfree < 2) {
460 err = -ENOSPC;
461 goto out;
462 }
463
464 if (local_state_change)
465 wdev->auth_bsses[slot] = bss;
466 else
467 wdev->authtry_bsses[slot] = bss;
468 cfg80211_hold_bss(bss);
469
470 err = rdev->ops->auth(&rdev->wiphy, dev, &req); 304 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
471 if (err) {
472 if (local_state_change)
473 wdev->auth_bsses[slot] = NULL;
474 else
475 wdev->authtry_bsses[slot] = NULL;
476 cfg80211_unhold_bss(bss);
477 }
478 305
479 out: 306 cfg80211_put_bss(req.bss);
480 if (err)
481 cfg80211_put_bss(req.bss);
482 return err; 307 return err;
483} 308}
484 309
@@ -487,15 +312,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
487 enum nl80211_auth_type auth_type, const u8 *bssid, 312 enum nl80211_auth_type auth_type, const u8 *bssid,
488 const u8 *ssid, int ssid_len, 313 const u8 *ssid, int ssid_len,
489 const u8 *ie, int ie_len, 314 const u8 *ie, int ie_len,
490 const u8 *key, int key_len, int key_idx, 315 const u8 *key, int key_len, int key_idx)
491 bool local_state_change)
492{ 316{
493 int err; 317 int err;
494 318
495 wdev_lock(dev->ieee80211_ptr); 319 wdev_lock(dev->ieee80211_ptr);
496 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 320 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
497 ssid, ssid_len, ie, ie_len, 321 ssid, ssid_len, ie, ie_len,
498 key, key_len, key_idx, local_state_change); 322 key, key_len, key_idx);
499 wdev_unlock(dev->ieee80211_ptr); 323 wdev_unlock(dev->ieee80211_ptr);
500 324
501 return err; 325 return err;
@@ -530,8 +354,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
530{ 354{
531 struct wireless_dev *wdev = dev->ieee80211_ptr; 355 struct wireless_dev *wdev = dev->ieee80211_ptr;
532 struct cfg80211_assoc_request req; 356 struct cfg80211_assoc_request req;
533 struct cfg80211_internal_bss *bss; 357 int err;
534 int i, err, slot = -1;
535 bool was_connected = false; 358 bool was_connected = false;
536 359
537 ASSERT_WDEV_LOCK(wdev); 360 ASSERT_WDEV_LOCK(wdev);
@@ -573,26 +396,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
573 return -ENOENT; 396 return -ENOENT;
574 } 397 }
575 398
576 bss = bss_from_pub(req.bss); 399 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
577
578 for (i = 0; i < MAX_AUTH_BSSES; i++) {
579 if (bss == wdev->auth_bsses[i]) {
580 slot = i;
581 break;
582 }
583 }
584 400
585 if (slot < 0) { 401 if (err) {
586 err = -ENOTCONN; 402 if (was_connected)
587 goto out; 403 wdev->sme_state = CFG80211_SME_CONNECTED;
404 cfg80211_put_bss(req.bss);
588 } 405 }
589 406
590 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
591 out:
592 if (err && was_connected)
593 wdev->sme_state = CFG80211_SME_CONNECTED;
594 /* still a reference in wdev->auth_bsses[slot] */
595 cfg80211_put_bss(req.bss);
596 return err; 407 return err;
597} 408}
598 409
@@ -624,34 +435,25 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
624 bool local_state_change) 435 bool local_state_change)
625{ 436{
626 struct wireless_dev *wdev = dev->ieee80211_ptr; 437 struct wireless_dev *wdev = dev->ieee80211_ptr;
627 struct cfg80211_deauth_request req; 438 struct cfg80211_deauth_request req = {
628 int i; 439 .bssid = bssid,
440 .reason_code = reason,
441 .ie = ie,
442 .ie_len = ie_len,
443 };
629 444
630 ASSERT_WDEV_LOCK(wdev); 445 ASSERT_WDEV_LOCK(wdev);
631 446
632 memset(&req, 0, sizeof(req)); 447 if (local_state_change) {
633 req.reason_code = reason; 448 if (wdev->current_bss &&
634 req.local_state_change = local_state_change; 449 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
635 req.ie = ie; 450 cfg80211_unhold_bss(wdev->current_bss);
636 req.ie_len = ie_len; 451 cfg80211_put_bss(&wdev->current_bss->pub);
637 if (wdev->current_bss && 452 wdev->current_bss = NULL;
638 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
639 req.bss = &wdev->current_bss->pub;
640 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
641 if (wdev->auth_bsses[i] &&
642 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
643 req.bss = &wdev->auth_bsses[i]->pub;
644 break;
645 }
646 if (wdev->authtry_bsses[i] &&
647 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
648 req.bss = &wdev->authtry_bsses[i]->pub;
649 break;
650 } 453 }
651 }
652 454
653 if (!req.bss) 455 return 0;
654 return -ENOTCONN; 456 }
655 457
656 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 458 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
657} 459}
@@ -722,7 +524,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
722{ 524{
723 struct wireless_dev *wdev = dev->ieee80211_ptr; 525 struct wireless_dev *wdev = dev->ieee80211_ptr;
724 struct cfg80211_deauth_request req; 526 struct cfg80211_deauth_request req;
725 int i; 527 u8 bssid[ETH_ALEN];
726 528
727 ASSERT_WDEV_LOCK(wdev); 529 ASSERT_WDEV_LOCK(wdev);
728 530
@@ -734,35 +536,17 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
734 req.ie = NULL; 536 req.ie = NULL;
735 req.ie_len = 0; 537 req.ie_len = 0;
736 538
737 if (wdev->current_bss) { 539 if (!wdev->current_bss)
738 req.bss = &wdev->current_bss->pub; 540 return;
739 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
740 if (wdev->current_bss) {
741 cfg80211_unhold_bss(wdev->current_bss);
742 cfg80211_put_bss(&wdev->current_bss->pub);
743 wdev->current_bss = NULL;
744 }
745 }
746 541
747 for (i = 0; i < MAX_AUTH_BSSES; i++) { 542 memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
748 if (wdev->auth_bsses[i]) { 543 req.bssid = bssid;
749 req.bss = &wdev->auth_bsses[i]->pub; 544 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
750 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 545
751 if (wdev->auth_bsses[i]) { 546 if (wdev->current_bss) {
752 cfg80211_unhold_bss(wdev->auth_bsses[i]); 547 cfg80211_unhold_bss(wdev->current_bss);
753 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 548 cfg80211_put_bss(&wdev->current_bss->pub);
754 wdev->auth_bsses[i] = NULL; 549 wdev->current_bss = NULL;
755 }
756 }
757 if (wdev->authtry_bsses[i]) {
758 req.bss = &wdev->authtry_bsses[i]->pub;
759 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
760 if (wdev->authtry_bsses[i]) {
761 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
762 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
763 wdev->authtry_bsses[i] = NULL;
764 }
765 }
766 } 550 }
767} 551}
768 552
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c910b0750dc2..e1fd1bf90729 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4083,7 +4083,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
4083 struct cfg80211_bss *res = &intbss->pub; 4083 struct cfg80211_bss *res = &intbss->pub;
4084 void *hdr; 4084 void *hdr;
4085 struct nlattr *bss; 4085 struct nlattr *bss;
4086 int i;
4087 4086
4088 ASSERT_WDEV_LOCK(wdev); 4087 ASSERT_WDEV_LOCK(wdev);
4089 4088
@@ -4136,13 +4135,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
4136 if (intbss == wdev->current_bss) 4135 if (intbss == wdev->current_bss)
4137 NLA_PUT_U32(msg, NL80211_BSS_STATUS, 4136 NLA_PUT_U32(msg, NL80211_BSS_STATUS,
4138 NL80211_BSS_STATUS_ASSOCIATED); 4137 NL80211_BSS_STATUS_ASSOCIATED);
4139 else for (i = 0; i < MAX_AUTH_BSSES; i++) {
4140 if (intbss != wdev->auth_bsses[i])
4141 continue;
4142 NLA_PUT_U32(msg, NL80211_BSS_STATUS,
4143 NL80211_BSS_STATUS_AUTHENTICATED);
4144 break;
4145 }
4146 break; 4138 break;
4147 case NL80211_IFTYPE_ADHOC: 4139 case NL80211_IFTYPE_ADHOC:
4148 if (intbss == wdev->current_bss) 4140 if (intbss == wdev->current_bss)
@@ -4410,10 +4402,16 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
4410 4402
4411 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; 4403 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
4412 4404
4405 /*
4406 * Since we no longer track auth state, ignore
4407 * requests to only change local state.
4408 */
4409 if (local_state_change)
4410 return 0;
4411
4413 return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 4412 return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
4414 ssid, ssid_len, ie, ie_len, 4413 ssid, ssid_len, ie, ie_len,
4415 key.p.key, key.p.key_len, key.idx, 4414 key.p.key, key.p.key_len, key.idx);
4416 local_state_change);
4417} 4415}
4418 4416
4419static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, 4417static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7b9ecaed96be..f7e937ff8978 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -179,7 +179,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
179 params->ssid, params->ssid_len, 179 params->ssid, params->ssid_len,
180 NULL, 0, 180 NULL, 0,
181 params->key, params->key_len, 181 params->key, params->key_len,
182 params->key_idx, false); 182 params->key_idx);
183 case CFG80211_CONN_ASSOCIATE_NEXT: 183 case CFG80211_CONN_ASSOCIATE_NEXT:
184 BUG_ON(!rdev->ops->assoc); 184 BUG_ON(!rdev->ops->assoc);
185 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 185 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -477,6 +477,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
477 kfree(wdev->connect_keys); 477 kfree(wdev->connect_keys);
478 wdev->connect_keys = NULL; 478 wdev->connect_keys = NULL;
479 wdev->ssid_len = 0; 479 wdev->ssid_len = 0;
480 cfg80211_put_bss(bss);
480 return; 481 return;
481 } 482 }
482 483
@@ -701,31 +702,10 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
701 wdev->ssid_len = 0; 702 wdev->ssid_len = 0;
702 703
703 if (wdev->conn) { 704 if (wdev->conn) {
704 const u8 *bssid;
705 int ret;
706
707 kfree(wdev->conn->ie); 705 kfree(wdev->conn->ie);
708 wdev->conn->ie = NULL; 706 wdev->conn->ie = NULL;
709 kfree(wdev->conn); 707 kfree(wdev->conn);
710 wdev->conn = NULL; 708 wdev->conn = NULL;
711
712 /*
713 * If this disconnect was due to a disassoc, we
714 * we might still have an auth BSS around. For
715 * the userspace SME that's currently expected,
716 * but for the kernel SME (nl80211 CONNECT or
717 * wireless extensions) we want to clear up all
718 * state.
719 */
720 for (i = 0; i < MAX_AUTH_BSSES; i++) {
721 if (!wdev->auth_bsses[i])
722 continue;
723 bssid = wdev->auth_bsses[i]->pub.bssid;
724 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
725 WLAN_REASON_DEAUTH_LEAVING,
726 false);
727 WARN(ret, "deauth failed: %d\n", ret);
728 }
729 } 709 }
730 710
731 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); 711 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
@@ -1012,7 +992,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
1012 return err; 992 return err;
1013} 993}
1014 994
1015void cfg80211_sme_disassoc(struct net_device *dev, int idx) 995void cfg80211_sme_disassoc(struct net_device *dev,
996 struct cfg80211_internal_bss *bss)
1016{ 997{
1017 struct wireless_dev *wdev = dev->ieee80211_ptr; 998 struct wireless_dev *wdev = dev->ieee80211_ptr;
1018 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 999 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1031,16 +1012,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
1031 * want it any more so deauthenticate too. 1012 * want it any more so deauthenticate too.
1032 */ 1013 */
1033 1014
1034 if (!wdev->auth_bsses[idx]) 1015 memcpy(bssid, bss->pub.bssid, ETH_ALEN);
1035 return;
1036 1016
1037 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); 1017 __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
1038 if (__cfg80211_mlme_deauth(rdev, dev, bssid, 1018 WLAN_REASON_DEAUTH_LEAVING, false);
1039 NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
1040 false)) {
1041 /* whatever -- assume gone anyway */
1042 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
1043 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
1044 wdev->auth_bsses[idx] = NULL;
1045 }
1046} 1019}