aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r--net/wireless/sme.c542
1 files changed, 254 insertions, 288 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 81be95f3be74..ae7e2cbf45cb 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1,5 +1,7 @@
1/* 1/*
2 * SME code for cfg80211's connect emulation. 2 * SME code for cfg80211
3 * both driver SME event handling and the SME implementation
4 * (for nl80211's connect() and wext)
3 * 5 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved. 7 * Copyright (C) 2009 Intel Corporation. All rights reserved.
@@ -18,18 +20,24 @@
18#include "reg.h" 20#include "reg.h"
19#include "rdev-ops.h" 21#include "rdev-ops.h"
20 22
23/*
24 * Software SME in cfg80211, using auth/assoc/deauth calls to the
25 * driver. This is is for implementing nl80211's connect/disconnect
26 * and wireless extensions (if configured.)
27 */
28
21struct cfg80211_conn { 29struct cfg80211_conn {
22 struct cfg80211_connect_params params; 30 struct cfg80211_connect_params params;
23 /* these are sub-states of the _CONNECTING sme_state */ 31 /* these are sub-states of the _CONNECTING sme_state */
24 enum { 32 enum {
25 CFG80211_CONN_IDLE,
26 CFG80211_CONN_SCANNING, 33 CFG80211_CONN_SCANNING,
27 CFG80211_CONN_SCAN_AGAIN, 34 CFG80211_CONN_SCAN_AGAIN,
28 CFG80211_CONN_AUTHENTICATE_NEXT, 35 CFG80211_CONN_AUTHENTICATE_NEXT,
29 CFG80211_CONN_AUTHENTICATING, 36 CFG80211_CONN_AUTHENTICATING,
30 CFG80211_CONN_ASSOCIATE_NEXT, 37 CFG80211_CONN_ASSOCIATE_NEXT,
31 CFG80211_CONN_ASSOCIATING, 38 CFG80211_CONN_ASSOCIATING,
32 CFG80211_CONN_DEAUTH_ASSOC_FAIL, 39 CFG80211_CONN_DEAUTH,
40 CFG80211_CONN_CONNECTED,
33 } state; 41 } state;
34 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; 42 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
35 u8 *ie; 43 u8 *ie;
@@ -37,39 +45,16 @@ struct cfg80211_conn {
37 bool auto_auth, prev_bssid_valid; 45 bool auto_auth, prev_bssid_valid;
38}; 46};
39 47
40static bool cfg80211_is_all_idle(void) 48static void cfg80211_sme_free(struct wireless_dev *wdev)
41{ 49{
42 struct cfg80211_registered_device *rdev; 50 if (!wdev->conn)
43 struct wireless_dev *wdev; 51 return;
44 bool is_all_idle = true;
45
46 /*
47 * All devices must be idle as otherwise if you are actively
48 * scanning some new beacon hints could be learned and would
49 * count as new regulatory hints.
50 */
51 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
52 list_for_each_entry(wdev, &rdev->wdev_list, list) {
53 wdev_lock(wdev);
54 if (wdev->sme_state != CFG80211_SME_IDLE)
55 is_all_idle = false;
56 wdev_unlock(wdev);
57 }
58 }
59
60 return is_all_idle;
61}
62 52
63static void disconnect_work(struct work_struct *work) 53 kfree(wdev->conn->ie);
64{ 54 kfree(wdev->conn);
65 rtnl_lock(); 55 wdev->conn = NULL;
66 if (cfg80211_is_all_idle())
67 regulatory_hint_disconnect();
68 rtnl_unlock();
69} 56}
70 57
71static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
72
73static int cfg80211_conn_scan(struct wireless_dev *wdev) 58static int cfg80211_conn_scan(struct wireless_dev *wdev)
74{ 59{
75 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 60 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -164,6 +149,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
164 params = &wdev->conn->params; 149 params = &wdev->conn->params;
165 150
166 switch (wdev->conn->state) { 151 switch (wdev->conn->state) {
152 case CFG80211_CONN_SCANNING:
153 /* didn't find it during scan ... */
154 return -ENOENT;
167 case CFG80211_CONN_SCAN_AGAIN: 155 case CFG80211_CONN_SCAN_AGAIN:
168 return cfg80211_conn_scan(wdev); 156 return cfg80211_conn_scan(wdev);
169 case CFG80211_CONN_AUTHENTICATE_NEXT: 157 case CFG80211_CONN_AUTHENTICATE_NEXT:
@@ -200,12 +188,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
200 WLAN_REASON_DEAUTH_LEAVING, 188 WLAN_REASON_DEAUTH_LEAVING,
201 false); 189 false);
202 return err; 190 return err;
203 case CFG80211_CONN_DEAUTH_ASSOC_FAIL: 191 case CFG80211_CONN_DEAUTH:
204 cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 192 cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
205 NULL, 0, 193 NULL, 0,
206 WLAN_REASON_DEAUTH_LEAVING, false); 194 WLAN_REASON_DEAUTH_LEAVING, false);
207 /* return an error so that we call __cfg80211_connect_result() */ 195 return 0;
208 return -EINVAL;
209 default: 196 default:
210 return 0; 197 return 0;
211 } 198 }
@@ -229,7 +216,8 @@ void cfg80211_conn_work(struct work_struct *work)
229 wdev_unlock(wdev); 216 wdev_unlock(wdev);
230 continue; 217 continue;
231 } 218 }
232 if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) { 219 if (!wdev->conn ||
220 wdev->conn->state == CFG80211_CONN_CONNECTED) {
233 wdev_unlock(wdev); 221 wdev_unlock(wdev);
234 continue; 222 continue;
235 } 223 }
@@ -237,12 +225,14 @@ void cfg80211_conn_work(struct work_struct *work)
237 memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); 225 memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
238 bssid = bssid_buf; 226 bssid = bssid_buf;
239 } 227 }
240 if (cfg80211_conn_do_work(wdev)) 228 if (cfg80211_conn_do_work(wdev)) {
241 __cfg80211_connect_result( 229 __cfg80211_connect_result(
242 wdev->netdev, bssid, 230 wdev->netdev, bssid,
243 NULL, 0, NULL, 0, 231 NULL, 0, NULL, 0,
244 WLAN_STATUS_UNSPECIFIED_FAILURE, 232 WLAN_STATUS_UNSPECIFIED_FAILURE,
245 false, NULL); 233 false, NULL);
234 cfg80211_sme_free(wdev);
235 }
246 wdev_unlock(wdev); 236 wdev_unlock(wdev);
247 } 237 }
248 238
@@ -286,9 +276,6 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
286 276
287 ASSERT_WDEV_LOCK(wdev); 277 ASSERT_WDEV_LOCK(wdev);
288 278
289 if (wdev->sme_state != CFG80211_SME_CONNECTING)
290 return;
291
292 if (!wdev->conn) 279 if (!wdev->conn)
293 return; 280 return;
294 281
@@ -297,20 +284,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
297 return; 284 return;
298 285
299 bss = cfg80211_get_conn_bss(wdev); 286 bss = cfg80211_get_conn_bss(wdev);
300 if (bss) { 287 if (bss)
301 cfg80211_put_bss(&rdev->wiphy, bss); 288 cfg80211_put_bss(&rdev->wiphy, bss);
302 } else { 289 else
303 /* not found */ 290 schedule_work(&rdev->conn_work);
304 if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
305 schedule_work(&rdev->conn_work);
306 else
307 __cfg80211_connect_result(
308 wdev->netdev,
309 wdev->conn->params.bssid,
310 NULL, 0, NULL, 0,
311 WLAN_STATUS_UNSPECIFIED_FAILURE,
312 false, NULL);
313 }
314} 291}
315 292
316void cfg80211_sme_scan_done(struct net_device *dev) 293void cfg80211_sme_scan_done(struct net_device *dev)
@@ -322,10 +299,8 @@ void cfg80211_sme_scan_done(struct net_device *dev)
322 wdev_unlock(wdev); 299 wdev_unlock(wdev);
323} 300}
324 301
325void cfg80211_sme_rx_auth(struct net_device *dev, 302void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
326 const u8 *buf, size_t len)
327{ 303{
328 struct wireless_dev *wdev = dev->ieee80211_ptr;
329 struct wiphy *wiphy = wdev->wiphy; 304 struct wiphy *wiphy = wdev->wiphy;
330 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 305 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
331 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 306 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@@ -333,11 +308,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
333 308
334 ASSERT_WDEV_LOCK(wdev); 309 ASSERT_WDEV_LOCK(wdev);
335 310
336 /* should only RX auth frames when connecting */ 311 if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
337 if (wdev->sme_state != CFG80211_SME_CONNECTING)
338 return;
339
340 if (WARN_ON(!wdev->conn))
341 return; 312 return;
342 313
343 if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && 314 if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
@@ -366,46 +337,226 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
366 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 337 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
367 schedule_work(&rdev->conn_work); 338 schedule_work(&rdev->conn_work);
368 } else if (status_code != WLAN_STATUS_SUCCESS) { 339 } else if (status_code != WLAN_STATUS_SUCCESS) {
369 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, 340 __cfg80211_connect_result(wdev->netdev, mgmt->bssid,
341 NULL, 0, NULL, 0,
370 status_code, false, NULL); 342 status_code, false, NULL);
371 } else if (wdev->sme_state == CFG80211_SME_CONNECTING && 343 } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
372 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
373 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; 344 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
374 schedule_work(&rdev->conn_work); 345 schedule_work(&rdev->conn_work);
375 } 346 }
376} 347}
377 348
378bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) 349bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
379{ 350{
380 struct wiphy *wiphy = wdev->wiphy; 351 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
381 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
382 352
383 if (WARN_ON(!wdev->conn)) 353 if (!wdev->conn)
384 return false; 354 return false;
385 355
386 if (!wdev->conn->prev_bssid_valid) 356 if (status == WLAN_STATUS_SUCCESS) {
357 wdev->conn->state = CFG80211_CONN_CONNECTED;
387 return false; 358 return false;
359 }
388 360
389 /* 361 if (wdev->conn->prev_bssid_valid) {
390 * Some stupid APs don't accept reassoc, so we 362 /*
391 * need to fall back to trying regular assoc. 363 * Some stupid APs don't accept reassoc, so we
392 */ 364 * need to fall back to trying regular assoc;
393 wdev->conn->prev_bssid_valid = false; 365 * return true so no event is sent to userspace.
394 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; 366 */
367 wdev->conn->prev_bssid_valid = false;
368 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
369 schedule_work(&rdev->conn_work);
370 return true;
371 }
372
373 wdev->conn->state = CFG80211_CONN_DEAUTH;
395 schedule_work(&rdev->conn_work); 374 schedule_work(&rdev->conn_work);
375 return false;
376}
396 377
397 return true; 378void cfg80211_sme_deauth(struct wireless_dev *wdev)
379{
380 cfg80211_sme_free(wdev);
398} 381}
399 382
400void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) 383void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
401{ 384{
402 struct wiphy *wiphy = wdev->wiphy; 385 cfg80211_sme_free(wdev);
403 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 386}
404 387
405 wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL; 388void cfg80211_sme_disassoc(struct wireless_dev *wdev)
389{
390 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
391
392 if (!wdev->conn)
393 return;
394
395 wdev->conn->state = CFG80211_CONN_DEAUTH;
406 schedule_work(&rdev->conn_work); 396 schedule_work(&rdev->conn_work);
407} 397}
408 398
399void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
400{
401 cfg80211_sme_disassoc(wdev);
402}
403
404static int cfg80211_sme_connect(struct wireless_dev *wdev,
405 struct cfg80211_connect_params *connect,
406 const u8 *prev_bssid)
407{
408 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
409 struct cfg80211_bss *bss;
410 int err;
411
412 if (!rdev->ops->auth || !rdev->ops->assoc)
413 return -EOPNOTSUPP;
414
415 if (wdev->current_bss)
416 return -EALREADY;
417
418 if (WARN_ON(wdev->conn))
419 return -EINPROGRESS;
420
421 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
422 if (!wdev->conn)
423 return -ENOMEM;
424
425 /*
426 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
427 */
428 memcpy(&wdev->conn->params, connect, sizeof(*connect));
429 if (connect->bssid) {
430 wdev->conn->params.bssid = wdev->conn->bssid;
431 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
432 }
433
434 if (connect->ie) {
435 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
436 GFP_KERNEL);
437 wdev->conn->params.ie = wdev->conn->ie;
438 if (!wdev->conn->ie) {
439 kfree(wdev->conn);
440 wdev->conn = NULL;
441 return -ENOMEM;
442 }
443 }
444
445 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
446 wdev->conn->auto_auth = true;
447 /* start with open system ... should mostly work */
448 wdev->conn->params.auth_type =
449 NL80211_AUTHTYPE_OPEN_SYSTEM;
450 } else {
451 wdev->conn->auto_auth = false;
452 }
453
454 wdev->conn->params.ssid = wdev->ssid;
455 wdev->conn->params.ssid_len = connect->ssid_len;
456
457 /* see if we have the bss already */
458 bss = cfg80211_get_conn_bss(wdev);
459
460 if (prev_bssid) {
461 memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
462 wdev->conn->prev_bssid_valid = true;
463 }
464
465 /* we're good if we have a matching bss struct */
466 if (bss) {
467 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
468 err = cfg80211_conn_do_work(wdev);
469 cfg80211_put_bss(wdev->wiphy, bss);
470 } else {
471 /* otherwise we'll need to scan for the AP first */
472 err = cfg80211_conn_scan(wdev);
473
474 /*
475 * If we can't scan right now, then we need to scan again
476 * after the current scan finished, since the parameters
477 * changed (unless we find a good AP anyway).
478 */
479 if (err == -EBUSY) {
480 err = 0;
481 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
482 }
483 }
484
485 if (err)
486 cfg80211_sme_free(wdev);
487
488 return err;
489}
490
491static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
492{
493 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
494 int err;
495
496 if (!wdev->conn)
497 return 0;
498
499 if (!rdev->ops->deauth)
500 return -EOPNOTSUPP;
501
502 if (wdev->conn->state == CFG80211_CONN_SCANNING ||
503 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
504 err = 0;
505 goto out;
506 }
507
508 /* wdev->conn->params.bssid must be set if > SCANNING */
509 err = cfg80211_mlme_deauth(rdev, wdev->netdev,
510 wdev->conn->params.bssid,
511 NULL, 0, reason, false);
512 out:
513 cfg80211_sme_free(wdev);
514 return err;
515}
516
517/*
518 * code shared for in-device and software SME
519 */
520
521static bool cfg80211_is_all_idle(void)
522{
523 struct cfg80211_registered_device *rdev;
524 struct wireless_dev *wdev;
525 bool is_all_idle = true;
526
527 /*
528 * All devices must be idle as otherwise if you are actively
529 * scanning some new beacon hints could be learned and would
530 * count as new regulatory hints.
531 */
532 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
533 list_for_each_entry(wdev, &rdev->wdev_list, list) {
534 wdev_lock(wdev);
535 if (wdev->conn || wdev->current_bss)
536 is_all_idle = false;
537 wdev_unlock(wdev);
538 }
539 }
540
541 return is_all_idle;
542}
543
544static void disconnect_work(struct work_struct *work)
545{
546 rtnl_lock();
547 if (cfg80211_is_all_idle())
548 regulatory_hint_disconnect();
549 rtnl_unlock();
550}
551
552static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
553
554
555/*
556 * API calls for drivers implementing connect/disconnect and
557 * SME event handling
558 */
559
409void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 560void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
410 const u8 *req_ie, size_t req_ie_len, 561 const u8 *req_ie, size_t req_ie_len,
411 const u8 *resp_ie, size_t resp_ie_len, 562 const u8 *resp_ie, size_t resp_ie_len,
@@ -424,9 +575,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
424 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) 575 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
425 return; 576 return;
426 577
427 if (wdev->sme_state != CFG80211_SME_CONNECTING)
428 return;
429
430 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, 578 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
431 bssid, req_ie, req_ie_len, 579 bssid, req_ie, req_ie_len,
432 resp_ie, resp_ie_len, 580 resp_ie, resp_ie_len,
@@ -463,15 +611,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
463 wdev->current_bss = NULL; 611 wdev->current_bss = NULL;
464 } 612 }
465 613
466 if (wdev->conn)
467 wdev->conn->state = CFG80211_CONN_IDLE;
468
469 if (status != WLAN_STATUS_SUCCESS) { 614 if (status != WLAN_STATUS_SUCCESS) {
470 wdev->sme_state = CFG80211_SME_IDLE;
471 if (wdev->conn)
472 kfree(wdev->conn->ie);
473 kfree(wdev->conn);
474 wdev->conn = NULL;
475 kfree(wdev->connect_keys); 615 kfree(wdev->connect_keys);
476 wdev->connect_keys = NULL; 616 wdev->connect_keys = NULL;
477 wdev->ssid_len = 0; 617 wdev->ssid_len = 0;
@@ -480,21 +620,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
480 } 620 }
481 621
482 if (!bss) 622 if (!bss)
483 bss = cfg80211_get_bss(wdev->wiphy, 623 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
484 wdev->conn ? wdev->conn->params.channel :
485 NULL,
486 bssid,
487 wdev->ssid, wdev->ssid_len, 624 wdev->ssid, wdev->ssid_len,
488 WLAN_CAPABILITY_ESS, 625 WLAN_CAPABILITY_ESS,
489 WLAN_CAPABILITY_ESS); 626 WLAN_CAPABILITY_ESS);
490
491 if (WARN_ON(!bss)) 627 if (WARN_ON(!bss))
492 return; 628 return;
493 629
494 cfg80211_hold_bss(bss_from_pub(bss)); 630 cfg80211_hold_bss(bss_from_pub(bss));
495 wdev->current_bss = bss_from_pub(bss); 631 wdev->current_bss = bss_from_pub(bss);
496 632
497 wdev->sme_state = CFG80211_SME_CONNECTED;
498 cfg80211_upload_connect_keys(wdev); 633 cfg80211_upload_connect_keys(wdev);
499 634
500 rcu_read_lock(); 635 rcu_read_lock();
@@ -530,8 +665,6 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
530 struct cfg80211_event *ev; 665 struct cfg80211_event *ev;
531 unsigned long flags; 666 unsigned long flags;
532 667
533 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
534
535 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); 668 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
536 if (!ev) 669 if (!ev)
537 return; 670 return;
@@ -572,13 +705,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
572 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) 705 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
573 goto out; 706 goto out;
574 707
575 if (wdev->sme_state != CFG80211_SME_CONNECTED) 708 if (WARN_ON(!wdev->current_bss))
576 goto out;
577
578 /* internal error -- how did we get to CONNECTED w/o BSS? */
579 if (WARN_ON(!wdev->current_bss)) {
580 goto out; 709 goto out;
581 }
582 710
583 cfg80211_unhold_bss(wdev->current_bss); 711 cfg80211_unhold_bss(wdev->current_bss);
584 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); 712 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
@@ -628,8 +756,6 @@ void cfg80211_roamed(struct net_device *dev,
628 struct wireless_dev *wdev = dev->ieee80211_ptr; 756 struct wireless_dev *wdev = dev->ieee80211_ptr;
629 struct cfg80211_bss *bss; 757 struct cfg80211_bss *bss;
630 758
631 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
632
633 bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, 759 bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
634 wdev->ssid_len, WLAN_CAPABILITY_ESS, 760 wdev->ssid_len, WLAN_CAPABILITY_ESS,
635 WLAN_CAPABILITY_ESS); 761 WLAN_CAPABILITY_ESS);
@@ -651,8 +777,6 @@ void cfg80211_roamed_bss(struct net_device *dev,
651 struct cfg80211_event *ev; 777 struct cfg80211_event *ev;
652 unsigned long flags; 778 unsigned long flags;
653 779
654 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
655
656 if (WARN_ON(!bss)) 780 if (WARN_ON(!bss))
657 return; 781 return;
658 782
@@ -694,25 +818,14 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
694 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) 818 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
695 return; 819 return;
696 820
697 if (wdev->sme_state != CFG80211_SME_CONNECTED)
698 return;
699
700 if (wdev->current_bss) { 821 if (wdev->current_bss) {
701 cfg80211_unhold_bss(wdev->current_bss); 822 cfg80211_unhold_bss(wdev->current_bss);
702 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); 823 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
703 } 824 }
704 825
705 wdev->current_bss = NULL; 826 wdev->current_bss = NULL;
706 wdev->sme_state = CFG80211_SME_IDLE;
707 wdev->ssid_len = 0; 827 wdev->ssid_len = 0;
708 828
709 if (wdev->conn) {
710 kfree(wdev->conn->ie);
711 wdev->conn->ie = NULL;
712 kfree(wdev->conn);
713 wdev->conn = NULL;
714 }
715
716 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); 829 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
717 830
718 /* 831 /*
@@ -741,8 +854,6 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
741 struct cfg80211_event *ev; 854 struct cfg80211_event *ev;
742 unsigned long flags; 855 unsigned long flags;
743 856
744 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
745
746 ev = kzalloc(sizeof(*ev) + ie_len, gfp); 857 ev = kzalloc(sizeof(*ev) + ie_len, gfp);
747 if (!ev) 858 if (!ev)
748 return; 859 return;
@@ -760,6 +871,9 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
760} 871}
761EXPORT_SYMBOL(cfg80211_disconnected); 872EXPORT_SYMBOL(cfg80211_disconnected);
762 873
874/*
875 * API calls for nl80211/wext compatibility code
876 */
763int cfg80211_connect(struct cfg80211_registered_device *rdev, 877int cfg80211_connect(struct cfg80211_registered_device *rdev,
764 struct net_device *dev, 878 struct net_device *dev,
765 struct cfg80211_connect_params *connect, 879 struct cfg80211_connect_params *connect,
@@ -767,14 +881,10 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
767 const u8 *prev_bssid) 881 const u8 *prev_bssid)
768{ 882{
769 struct wireless_dev *wdev = dev->ieee80211_ptr; 883 struct wireless_dev *wdev = dev->ieee80211_ptr;
770 struct cfg80211_bss *bss = NULL;
771 int err; 884 int err;
772 885
773 ASSERT_WDEV_LOCK(wdev); 886 ASSERT_WDEV_LOCK(wdev);
774 887
775 if (wdev->sme_state != CFG80211_SME_IDLE)
776 return -EALREADY;
777
778 if (WARN_ON(wdev->connect_keys)) { 888 if (WARN_ON(wdev->connect_keys)) {
779 kfree(wdev->connect_keys); 889 kfree(wdev->connect_keys);
780 wdev->connect_keys = NULL; 890 wdev->connect_keys = NULL;
@@ -810,105 +920,22 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
810 } 920 }
811 } 921 }
812 922
813 if (!rdev->ops->connect) { 923 wdev->connect_keys = connkeys;
814 if (!rdev->ops->auth || !rdev->ops->assoc) 924 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
815 return -EOPNOTSUPP; 925 wdev->ssid_len = connect->ssid_len;
816
817 if (WARN_ON(wdev->conn))
818 return -EINPROGRESS;
819
820 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
821 if (!wdev->conn)
822 return -ENOMEM;
823
824 /*
825 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
826 */
827 memcpy(&wdev->conn->params, connect, sizeof(*connect));
828 if (connect->bssid) {
829 wdev->conn->params.bssid = wdev->conn->bssid;
830 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
831 }
832 926
833 if (connect->ie) { 927 if (!rdev->ops->connect)
834 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, 928 err = cfg80211_sme_connect(wdev, connect, prev_bssid);
835 GFP_KERNEL); 929 else
836 wdev->conn->params.ie = wdev->conn->ie;
837 if (!wdev->conn->ie) {
838 kfree(wdev->conn);
839 wdev->conn = NULL;
840 return -ENOMEM;
841 }
842 }
843
844 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
845 wdev->conn->auto_auth = true;
846 /* start with open system ... should mostly work */
847 wdev->conn->params.auth_type =
848 NL80211_AUTHTYPE_OPEN_SYSTEM;
849 } else {
850 wdev->conn->auto_auth = false;
851 }
852
853 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
854 wdev->ssid_len = connect->ssid_len;
855 wdev->conn->params.ssid = wdev->ssid;
856 wdev->conn->params.ssid_len = connect->ssid_len;
857
858 /* see if we have the bss already */
859 bss = cfg80211_get_conn_bss(wdev);
860
861 wdev->sme_state = CFG80211_SME_CONNECTING;
862 wdev->connect_keys = connkeys;
863
864 if (prev_bssid) {
865 memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
866 wdev->conn->prev_bssid_valid = true;
867 }
868
869 /* we're good if we have a matching bss struct */
870 if (bss) {
871 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
872 err = cfg80211_conn_do_work(wdev);
873 cfg80211_put_bss(wdev->wiphy, bss);
874 } else {
875 /* otherwise we'll need to scan for the AP first */
876 err = cfg80211_conn_scan(wdev);
877 /*
878 * If we can't scan right now, then we need to scan again
879 * after the current scan finished, since the parameters
880 * changed (unless we find a good AP anyway).
881 */
882 if (err == -EBUSY) {
883 err = 0;
884 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
885 }
886 }
887 if (err) {
888 kfree(wdev->conn->ie);
889 kfree(wdev->conn);
890 wdev->conn = NULL;
891 wdev->sme_state = CFG80211_SME_IDLE;
892 wdev->connect_keys = NULL;
893 wdev->ssid_len = 0;
894 }
895
896 return err;
897 } else {
898 wdev->sme_state = CFG80211_SME_CONNECTING;
899 wdev->connect_keys = connkeys;
900 err = rdev_connect(rdev, dev, connect); 930 err = rdev_connect(rdev, dev, connect);
901 if (err) {
902 wdev->connect_keys = NULL;
903 wdev->sme_state = CFG80211_SME_IDLE;
904 return err;
905 }
906 931
907 memcpy(wdev->ssid, connect->ssid, connect->ssid_len); 932 if (err) {
908 wdev->ssid_len = connect->ssid_len; 933 wdev->connect_keys = NULL;
909 934 wdev->ssid_len = 0;
910 return 0; 935 return err;
911 } 936 }
937
938 return 0;
912} 939}
913 940
914int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 941int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
@@ -919,78 +946,17 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
919 946
920 ASSERT_WDEV_LOCK(wdev); 947 ASSERT_WDEV_LOCK(wdev);
921 948
922 if (wdev->sme_state == CFG80211_SME_IDLE)
923 return -EINVAL;
924
925 kfree(wdev->connect_keys); 949 kfree(wdev->connect_keys);
926 wdev->connect_keys = NULL; 950 wdev->connect_keys = NULL;
927 951
928 if (!rdev->ops->disconnect) { 952 if (wdev->conn) {
929 if (!rdev->ops->deauth) 953 err = cfg80211_sme_disconnect(wdev, reason);
930 return -EOPNOTSUPP; 954 } else if (!rdev->ops->disconnect) {
931 955 cfg80211_mlme_down(rdev, dev);
932 /* was it connected by userspace SME? */ 956 err = 0;
933 if (!wdev->conn) {
934 cfg80211_mlme_down(rdev, dev);
935 goto disconnect;
936 }
937
938 if (wdev->sme_state == CFG80211_SME_CONNECTING &&
939 (wdev->conn->state == CFG80211_CONN_SCANNING ||
940 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
941 wdev->sme_state = CFG80211_SME_IDLE;
942 kfree(wdev->conn->ie);
943 kfree(wdev->conn);
944 wdev->conn = NULL;
945 wdev->ssid_len = 0;
946 return 0;
947 }
948
949 /* wdev->conn->params.bssid must be set if > SCANNING */
950 err = cfg80211_mlme_deauth(rdev, dev,
951 wdev->conn->params.bssid,
952 NULL, 0, reason, false);
953 if (err)
954 return err;
955 } else { 957 } else {
956 err = rdev_disconnect(rdev, dev, reason); 958 err = rdev_disconnect(rdev, dev, reason);
957 if (err)
958 return err;
959 } 959 }
960 960
961 disconnect: 961 return err;
962 if (wdev->sme_state == CFG80211_SME_CONNECTED)
963 __cfg80211_disconnected(dev, NULL, 0, 0, false);
964 else if (wdev->sme_state == CFG80211_SME_CONNECTING)
965 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
966 WLAN_STATUS_UNSPECIFIED_FAILURE,
967 wextev, NULL);
968
969 return 0;
970}
971
972void cfg80211_sme_disassoc(struct net_device *dev,
973 struct cfg80211_internal_bss *bss)
974{
975 struct wireless_dev *wdev = dev->ieee80211_ptr;
976 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
977 u8 bssid[ETH_ALEN];
978
979 ASSERT_WDEV_LOCK(wdev);
980
981 if (!wdev->conn)
982 return;
983
984 if (wdev->conn->state == CFG80211_CONN_IDLE)
985 return;
986
987 /*
988 * Ok, so the association was made by this SME -- we don't
989 * want it any more so deauthenticate too.
990 */
991
992 memcpy(bssid, bss->pub.bssid, ETH_ALEN);
993
994 cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
995 WLAN_REASON_DEAUTH_LEAVING, false);
996} 962}