diff options
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r-- | net/wireless/sme.c | 97 |
1 files changed, 71 insertions, 26 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 79ca56cbfd36..d635a99dba51 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -125,7 +125,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
125 | params->channel, params->auth_type, | 125 | params->channel, params->auth_type, |
126 | params->bssid, | 126 | params->bssid, |
127 | params->ssid, params->ssid_len, | 127 | params->ssid, params->ssid_len, |
128 | NULL, 0); | 128 | NULL, 0, |
129 | params->key, params->key_len, | ||
130 | params->key_idx); | ||
129 | case CFG80211_CONN_ASSOCIATE_NEXT: | 131 | case CFG80211_CONN_ASSOCIATE_NEXT: |
130 | BUG_ON(!rdev->ops->assoc); | 132 | BUG_ON(!rdev->ops->assoc); |
131 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 133 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
@@ -279,8 +281,12 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
279 | /* select automatically between only open, shared, leap */ | 281 | /* select automatically between only open, shared, leap */ |
280 | switch (wdev->conn->params.auth_type) { | 282 | switch (wdev->conn->params.auth_type) { |
281 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | 283 | case NL80211_AUTHTYPE_OPEN_SYSTEM: |
282 | wdev->conn->params.auth_type = | 284 | if (wdev->connect_keys) |
283 | NL80211_AUTHTYPE_SHARED_KEY; | 285 | wdev->conn->params.auth_type = |
286 | NL80211_AUTHTYPE_SHARED_KEY; | ||
287 | else | ||
288 | wdev->conn->params.auth_type = | ||
289 | NL80211_AUTHTYPE_NETWORK_EAP; | ||
284 | break; | 290 | break; |
285 | case NL80211_AUTHTYPE_SHARED_KEY: | 291 | case NL80211_AUTHTYPE_SHARED_KEY: |
286 | wdev->conn->params.auth_type = | 292 | wdev->conn->params.auth_type = |
@@ -353,10 +359,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
353 | #endif | 359 | #endif |
354 | 360 | ||
355 | if (status == WLAN_STATUS_SUCCESS && | 361 | if (status == WLAN_STATUS_SUCCESS && |
356 | wdev->sme_state == CFG80211_SME_IDLE) { | 362 | wdev->sme_state == CFG80211_SME_IDLE) |
357 | wdev->sme_state = CFG80211_SME_CONNECTED; | 363 | goto success; |
358 | return; | ||
359 | } | ||
360 | 364 | ||
361 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 365 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
362 | return; | 366 | return; |
@@ -370,24 +374,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
370 | if (wdev->conn) | 374 | if (wdev->conn) |
371 | wdev->conn->state = CFG80211_CONN_IDLE; | 375 | wdev->conn->state = CFG80211_CONN_IDLE; |
372 | 376 | ||
373 | if (status == WLAN_STATUS_SUCCESS) { | 377 | if (status != WLAN_STATUS_SUCCESS) { |
374 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | ||
375 | wdev->ssid, wdev->ssid_len, | ||
376 | WLAN_CAPABILITY_ESS, | ||
377 | WLAN_CAPABILITY_ESS); | ||
378 | |||
379 | if (WARN_ON(!bss)) | ||
380 | return; | ||
381 | |||
382 | cfg80211_hold_bss(bss_from_pub(bss)); | ||
383 | wdev->current_bss = bss_from_pub(bss); | ||
384 | |||
385 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
386 | } else { | ||
387 | wdev->sme_state = CFG80211_SME_IDLE; | 378 | wdev->sme_state = CFG80211_SME_IDLE; |
388 | kfree(wdev->conn); | 379 | kfree(wdev->conn); |
389 | wdev->conn = NULL; | 380 | wdev->conn = NULL; |
381 | kfree(wdev->connect_keys); | ||
382 | wdev->connect_keys = NULL; | ||
383 | return; | ||
390 | } | 384 | } |
385 | |||
386 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | ||
387 | wdev->ssid, wdev->ssid_len, | ||
388 | WLAN_CAPABILITY_ESS, | ||
389 | WLAN_CAPABILITY_ESS); | ||
390 | |||
391 | if (WARN_ON(!bss)) | ||
392 | return; | ||
393 | |||
394 | cfg80211_hold_bss(bss_from_pub(bss)); | ||
395 | wdev->current_bss = bss_from_pub(bss); | ||
396 | |||
397 | success: | ||
398 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
399 | cfg80211_upload_connect_keys(wdev); | ||
391 | } | 400 | } |
392 | 401 | ||
393 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 402 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
@@ -516,6 +525,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
516 | size_t ie_len, u16 reason, bool from_ap) | 525 | size_t ie_len, u16 reason, bool from_ap) |
517 | { | 526 | { |
518 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 527 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
528 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
529 | int i; | ||
519 | #ifdef CONFIG_WIRELESS_EXT | 530 | #ifdef CONFIG_WIRELESS_EXT |
520 | union iwreq_data wrqu; | 531 | union iwreq_data wrqu; |
521 | #endif | 532 | #endif |
@@ -543,8 +554,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
543 | wdev->conn = NULL; | 554 | wdev->conn = NULL; |
544 | } | 555 | } |
545 | 556 | ||
546 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | 557 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
547 | reason, ie, ie_len, from_ap); | 558 | |
559 | /* | ||
560 | * Delete all the keys ... pairwise keys can't really | ||
561 | * exist any more anyway, but default keys might. | ||
562 | */ | ||
563 | if (rdev->ops->del_key) | ||
564 | for (i = 0; i < 6; i++) | ||
565 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | ||
548 | 566 | ||
549 | #ifdef CONFIG_WIRELESS_EXT | 567 | #ifdef CONFIG_WIRELESS_EXT |
550 | memset(&wrqu, 0, sizeof(wrqu)); | 568 | memset(&wrqu, 0, sizeof(wrqu)); |
@@ -580,7 +598,8 @@ EXPORT_SYMBOL(cfg80211_disconnected); | |||
580 | 598 | ||
581 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 599 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
582 | struct net_device *dev, | 600 | struct net_device *dev, |
583 | struct cfg80211_connect_params *connect) | 601 | struct cfg80211_connect_params *connect, |
602 | struct cfg80211_cached_keys *connkeys) | ||
584 | { | 603 | { |
585 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 604 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
586 | int err; | 605 | int err; |
@@ -590,6 +609,24 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
590 | if (wdev->sme_state != CFG80211_SME_IDLE) | 609 | if (wdev->sme_state != CFG80211_SME_IDLE) |
591 | return -EALREADY; | 610 | return -EALREADY; |
592 | 611 | ||
612 | if (WARN_ON(wdev->connect_keys)) { | ||
613 | kfree(wdev->connect_keys); | ||
614 | wdev->connect_keys = NULL; | ||
615 | } | ||
616 | |||
617 | if (connkeys && connkeys->def >= 0) { | ||
618 | int idx; | ||
619 | |||
620 | idx = connkeys->def; | ||
621 | /* If given a WEP key we may need it for shared key auth */ | ||
622 | if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
623 | connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { | ||
624 | connect->key_idx = idx; | ||
625 | connect->key = connkeys->params[idx].key; | ||
626 | connect->key_len = connkeys->params[idx].key_len; | ||
627 | } | ||
628 | } | ||
629 | |||
593 | if (!rdev->ops->connect) { | 630 | if (!rdev->ops->connect) { |
594 | if (!rdev->ops->auth || !rdev->ops->assoc) | 631 | if (!rdev->ops->auth || !rdev->ops->assoc) |
595 | return -EOPNOTSUPP; | 632 | return -EOPNOTSUPP; |
@@ -640,6 +677,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
640 | cfg80211_get_conn_bss(wdev); | 677 | cfg80211_get_conn_bss(wdev); |
641 | 678 | ||
642 | wdev->sme_state = CFG80211_SME_CONNECTING; | 679 | wdev->sme_state = CFG80211_SME_CONNECTING; |
680 | wdev->connect_keys = connkeys; | ||
643 | 681 | ||
644 | /* we're good if we have both BSSID and channel */ | 682 | /* we're good if we have both BSSID and channel */ |
645 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { | 683 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { |
@@ -662,13 +700,16 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
662 | kfree(wdev->conn); | 700 | kfree(wdev->conn); |
663 | wdev->conn = NULL; | 701 | wdev->conn = NULL; |
664 | wdev->sme_state = CFG80211_SME_IDLE; | 702 | wdev->sme_state = CFG80211_SME_IDLE; |
703 | wdev->connect_keys = NULL; | ||
665 | } | 704 | } |
666 | 705 | ||
667 | return err; | 706 | return err; |
668 | } else { | 707 | } else { |
669 | wdev->sme_state = CFG80211_SME_CONNECTING; | 708 | wdev->sme_state = CFG80211_SME_CONNECTING; |
709 | wdev->connect_keys = connkeys; | ||
670 | err = rdev->ops->connect(&rdev->wiphy, dev, connect); | 710 | err = rdev->ops->connect(&rdev->wiphy, dev, connect); |
671 | if (err) { | 711 | if (err) { |
712 | wdev->connect_keys = NULL; | ||
672 | wdev->sme_state = CFG80211_SME_IDLE; | 713 | wdev->sme_state = CFG80211_SME_IDLE; |
673 | return err; | 714 | return err; |
674 | } | 715 | } |
@@ -682,12 +723,13 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
682 | 723 | ||
683 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 724 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
684 | struct net_device *dev, | 725 | struct net_device *dev, |
685 | struct cfg80211_connect_params *connect) | 726 | struct cfg80211_connect_params *connect, |
727 | struct cfg80211_cached_keys *connkeys) | ||
686 | { | 728 | { |
687 | int err; | 729 | int err; |
688 | 730 | ||
689 | wdev_lock(dev->ieee80211_ptr); | 731 | wdev_lock(dev->ieee80211_ptr); |
690 | err = __cfg80211_connect(rdev, dev, connect); | 732 | err = __cfg80211_connect(rdev, dev, connect, connkeys); |
691 | wdev_unlock(dev->ieee80211_ptr); | 733 | wdev_unlock(dev->ieee80211_ptr); |
692 | 734 | ||
693 | return err; | 735 | return err; |
@@ -704,6 +746,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
704 | if (wdev->sme_state == CFG80211_SME_IDLE) | 746 | if (wdev->sme_state == CFG80211_SME_IDLE) |
705 | return -EINVAL; | 747 | return -EINVAL; |
706 | 748 | ||
749 | kfree(wdev->connect_keys); | ||
750 | wdev->connect_keys = NULL; | ||
751 | |||
707 | if (!rdev->ops->disconnect) { | 752 | if (!rdev->ops->disconnect) { |
708 | if (!rdev->ops->deauth) | 753 | if (!rdev->ops->deauth) |
709 | return -EOPNOTSUPP; | 754 | return -EOPNOTSUPP; |