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.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index dc0fc4989d54..a8c2d6b877ae 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -7,6 +7,7 @@
7 7
8#include <linux/etherdevice.h> 8#include <linux/etherdevice.h>
9#include <linux/if_arp.h> 9#include <linux/if_arp.h>
10#include <linux/slab.h>
10#include <linux/workqueue.h> 11#include <linux/workqueue.h>
11#include <linux/wireless.h> 12#include <linux/wireless.h>
12#include <net/iw_handler.h> 13#include <net/iw_handler.h>
@@ -34,6 +35,44 @@ struct cfg80211_conn {
34 bool auto_auth, prev_bssid_valid; 35 bool auto_auth, prev_bssid_valid;
35}; 36};
36 37
38static bool cfg80211_is_all_idle(void)
39{
40 struct cfg80211_registered_device *rdev;
41 struct wireless_dev *wdev;
42 bool is_all_idle = true;
43
44 mutex_lock(&cfg80211_mutex);
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 cfg80211_lock_rdev(rdev);
53 list_for_each_entry(wdev, &rdev->netdev_list, list) {
54 wdev_lock(wdev);
55 if (wdev->sme_state != CFG80211_SME_IDLE)
56 is_all_idle = false;
57 wdev_unlock(wdev);
58 }
59 cfg80211_unlock_rdev(rdev);
60 }
61
62 mutex_unlock(&cfg80211_mutex);
63
64 return is_all_idle;
65}
66
67static void disconnect_work(struct work_struct *work)
68{
69 if (!cfg80211_is_all_idle())
70 return;
71
72 regulatory_hint_disconnect();
73}
74
75static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
37 76
38static int cfg80211_conn_scan(struct wireless_dev *wdev) 77static int cfg80211_conn_scan(struct wireless_dev *wdev)
39{ 78{
@@ -132,7 +171,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
132 params->ssid, params->ssid_len, 171 params->ssid, params->ssid_len,
133 NULL, 0, 172 NULL, 0,
134 params->key, params->key_len, 173 params->key, params->key_len,
135 params->key_idx); 174 params->key_idx, false);
136 case CFG80211_CONN_ASSOCIATE_NEXT: 175 case CFG80211_CONN_ASSOCIATE_NEXT:
137 BUG_ON(!rdev->ops->assoc); 176 BUG_ON(!rdev->ops->assoc);
138 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 177 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -147,12 +186,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
147 if (err) 186 if (err)
148 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 187 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
149 NULL, 0, 188 NULL, 0,
150 WLAN_REASON_DEAUTH_LEAVING); 189 WLAN_REASON_DEAUTH_LEAVING,
190 false);
151 return err; 191 return err;
152 case CFG80211_CONN_DEAUTH_ASSOC_FAIL: 192 case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
153 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 193 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
154 NULL, 0, 194 NULL, 0,
155 WLAN_REASON_DEAUTH_LEAVING); 195 WLAN_REASON_DEAUTH_LEAVING, false);
156 /* return an error so that we call __cfg80211_connect_result() */ 196 /* return an error so that we call __cfg80211_connect_result() */
157 return -EINVAL; 197 return -EINVAL;
158 default: 198 default:
@@ -454,6 +494,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
454 * - and country_ie[1] which is the IE length 494 * - and country_ie[1] which is the IE length
455 */ 495 */
456 regulatory_hint_11d(wdev->wiphy, 496 regulatory_hint_11d(wdev->wiphy,
497 bss->channel->band,
457 country_ie + 2, 498 country_ie + 2,
458 country_ie[1]); 499 country_ie[1]);
459} 500}
@@ -477,12 +518,16 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
477 ev->type = EVENT_CONNECT_RESULT; 518 ev->type = EVENT_CONNECT_RESULT;
478 if (bssid) 519 if (bssid)
479 memcpy(ev->cr.bssid, bssid, ETH_ALEN); 520 memcpy(ev->cr.bssid, bssid, ETH_ALEN);
480 ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); 521 if (req_ie_len) {
481 ev->cr.req_ie_len = req_ie_len; 522 ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
482 memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); 523 ev->cr.req_ie_len = req_ie_len;
483 ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; 524 memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
484 ev->cr.resp_ie_len = resp_ie_len; 525 }
485 memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); 526 if (resp_ie_len) {
527 ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
528 ev->cr.resp_ie_len = resp_ie_len;
529 memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
530 }
486 ev->cr.status = status; 531 ev->cr.status = status;
487 532
488 spin_lock_irqsave(&wdev->event_lock, flags); 533 spin_lock_irqsave(&wdev->event_lock, flags);
@@ -636,7 +681,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
636 continue; 681 continue;
637 bssid = wdev->auth_bsses[i]->pub.bssid; 682 bssid = wdev->auth_bsses[i]->pub.bssid;
638 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, 683 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
639 WLAN_REASON_DEAUTH_LEAVING); 684 WLAN_REASON_DEAUTH_LEAVING,
685 false);
640 WARN(ret, "deauth failed: %d\n", ret); 686 WARN(ret, "deauth failed: %d\n", ret);
641 } 687 }
642 } 688 }
@@ -657,6 +703,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
657 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 703 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
658 wdev->wext.connect.ssid_len = 0; 704 wdev->wext.connect.ssid_len = 0;
659#endif 705#endif
706
707 schedule_work(&cfg80211_disconnect_work);
660} 708}
661 709
662void cfg80211_disconnected(struct net_device *dev, u16 reason, 710void cfg80211_disconnected(struct net_device *dev, u16 reason,
@@ -693,7 +741,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
693 const u8 *prev_bssid) 741 const u8 *prev_bssid)
694{ 742{
695 struct wireless_dev *wdev = dev->ieee80211_ptr; 743 struct wireless_dev *wdev = dev->ieee80211_ptr;
696 struct ieee80211_channel *chan;
697 struct cfg80211_bss *bss = NULL; 744 struct cfg80211_bss *bss = NULL;
698 int err; 745 int err;
699 746
@@ -702,10 +749,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
702 if (wdev->sme_state != CFG80211_SME_IDLE) 749 if (wdev->sme_state != CFG80211_SME_IDLE)
703 return -EALREADY; 750 return -EALREADY;
704 751
705 chan = rdev_fixed_channel(rdev, wdev);
706 if (chan && chan != connect->channel)
707 return -EBUSY;
708
709 if (WARN_ON(wdev->connect_keys)) { 752 if (WARN_ON(wdev->connect_keys)) {
710 kfree(wdev->connect_keys); 753 kfree(wdev->connect_keys);
711 wdev->connect_keys = NULL; 754 wdev->connect_keys = NULL;
@@ -893,7 +936,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
893 /* wdev->conn->params.bssid must be set if > SCANNING */ 936 /* wdev->conn->params.bssid must be set if > SCANNING */
894 err = __cfg80211_mlme_deauth(rdev, dev, 937 err = __cfg80211_mlme_deauth(rdev, dev,
895 wdev->conn->params.bssid, 938 wdev->conn->params.bssid,
896 NULL, 0, reason); 939 NULL, 0, reason, false);
897 if (err) 940 if (err)
898 return err; 941 return err;
899 } else { 942 } else {
@@ -949,7 +992,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
949 992
950 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); 993 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
951 if (__cfg80211_mlme_deauth(rdev, dev, bssid, 994 if (__cfg80211_mlme_deauth(rdev, dev, bssid,
952 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { 995 NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
996 false)) {
953 /* whatever -- assume gone anyway */ 997 /* whatever -- assume gone anyway */
954 cfg80211_unhold_bss(wdev->auth_bsses[idx]); 998 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
955 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); 999 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);