aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c1
-rw-r--r--net/wireless/core.h30
-rw-r--r--net/wireless/ibss.c6
-rw-r--r--net/wireless/mlme.c191
-rw-r--r--net/wireless/nl80211.c5
-rw-r--r--net/wireless/sme.c542
-rw-r--r--net/wireless/wext-sme.c8
7 files changed, 335 insertions, 448 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f553b9484c1e..221e76b53a97 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -821,7 +821,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
821 pr_err("failed to add phy80211 symlink to netdev!\n"); 821 pr_err("failed to add phy80211 symlink to netdev!\n");
822 } 822 }
823 wdev->netdev = dev; 823 wdev->netdev = dev;
824 wdev->sme_state = CFG80211_SME_IDLE;
825#ifdef CONFIG_CFG80211_WEXT 824#ifdef CONFIG_CFG80211_WEXT
826 wdev->wext.default_key = -1; 825 wdev->wext.default_key = -1;
827 wdev->wext.default_mgmt_key = -1; 826 wdev->wext.default_mgmt_key = -1;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index a65eaf8a84c1..a6b45bf00f33 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -308,11 +308,6 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
308 bool local_state_change); 308 bool local_state_change);
309void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 309void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
310 struct net_device *dev); 310 struct net_device *dev);
311void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
312 const u8 *req_ie, size_t req_ie_len,
313 const u8 *resp_ie, size_t resp_ie_len,
314 u16 status, bool wextev,
315 struct cfg80211_bss *bss);
316int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, 311int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
317 u16 frame_type, const u8 *match_data, 312 u16 frame_type, const u8 *match_data,
318 int match_len); 313 int match_len);
@@ -328,12 +323,19 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
328void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, 323void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
329 const struct ieee80211_vht_cap *vht_capa_mask); 324 const struct ieee80211_vht_cap *vht_capa_mask);
330 325
331/* SME */ 326/* SME events */
332int cfg80211_connect(struct cfg80211_registered_device *rdev, 327int cfg80211_connect(struct cfg80211_registered_device *rdev,
333 struct net_device *dev, 328 struct net_device *dev,
334 struct cfg80211_connect_params *connect, 329 struct cfg80211_connect_params *connect,
335 struct cfg80211_cached_keys *connkeys, 330 struct cfg80211_cached_keys *connkeys,
336 const u8 *prev_bssid); 331 const u8 *prev_bssid);
332void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
333 const u8 *req_ie, size_t req_ie_len,
334 const u8 *resp_ie, size_t resp_ie_len,
335 u16 status, bool wextev,
336 struct cfg80211_bss *bss);
337void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
338 size_t ie_len, u16 reason, bool from_ap);
337int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 339int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
338 struct net_device *dev, u16 reason, 340 struct net_device *dev, u16 reason,
339 bool wextev); 341 bool wextev);
@@ -344,21 +346,21 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
344int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, 346int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
345 struct wireless_dev *wdev); 347 struct wireless_dev *wdev);
346 348
349/* SME implementation */
347void cfg80211_conn_work(struct work_struct *work); 350void cfg80211_conn_work(struct work_struct *work);
348void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); 351void cfg80211_sme_scan_done(struct net_device *dev);
349bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); 352bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status);
353void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len);
354void cfg80211_sme_disassoc(struct wireless_dev *wdev);
355void cfg80211_sme_deauth(struct wireless_dev *wdev);
356void cfg80211_sme_auth_timeout(struct wireless_dev *wdev);
357void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev);
350 358
351/* internal helpers */ 359/* internal helpers */
352bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); 360bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
353int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, 361int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
354 struct key_params *params, int key_idx, 362 struct key_params *params, int key_idx,
355 bool pairwise, const u8 *mac_addr); 363 bool pairwise, const u8 *mac_addr);
356void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
357 size_t ie_len, u16 reason, bool from_ap);
358void cfg80211_sme_scan_done(struct net_device *dev);
359void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
360void cfg80211_sme_disassoc(struct net_device *dev,
361 struct cfg80211_internal_bss *bss);
362void __cfg80211_scan_done(struct work_struct *wk); 364void __cfg80211_scan_done(struct work_struct *wk);
363void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); 365void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
364void __cfg80211_sched_scan_results(struct work_struct *wk); 366void __cfg80211_sched_scan_results(struct work_struct *wk);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 5449c5a6de84..39bff7d36768 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -43,7 +43,6 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
43 cfg80211_hold_bss(bss_from_pub(bss)); 43 cfg80211_hold_bss(bss_from_pub(bss));
44 wdev->current_bss = bss_from_pub(bss); 44 wdev->current_bss = bss_from_pub(bss);
45 45
46 wdev->sme_state = CFG80211_SME_CONNECTED;
47 cfg80211_upload_connect_keys(wdev); 46 cfg80211_upload_connect_keys(wdev);
48 47
49 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, 48 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
@@ -64,8 +63,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
64 63
65 trace_cfg80211_ibss_joined(dev, bssid); 64 trace_cfg80211_ibss_joined(dev, bssid);
66 65
67 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
68
69 ev = kzalloc(sizeof(*ev), gfp); 66 ev = kzalloc(sizeof(*ev), gfp);
70 if (!ev) 67 if (!ev)
71 return; 68 return;
@@ -120,7 +117,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
120#ifdef CONFIG_CFG80211_WEXT 117#ifdef CONFIG_CFG80211_WEXT
121 wdev->wext.ibss.chandef = params->chandef; 118 wdev->wext.ibss.chandef = params->chandef;
122#endif 119#endif
123 wdev->sme_state = CFG80211_SME_CONNECTING;
124 120
125 err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, 121 err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
126 params->channel_fixed 122 params->channel_fixed
@@ -134,7 +130,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
134 err = rdev_join_ibss(rdev, dev, params); 130 err = rdev_join_ibss(rdev, dev, params);
135 if (err) { 131 if (err) {
136 wdev->connect_keys = NULL; 132 wdev->connect_keys = NULL;
137 wdev->sme_state = CFG80211_SME_IDLE;
138 return err; 133 return err;
139 } 134 }
140 135
@@ -186,7 +181,6 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
186 } 181 }
187 182
188 wdev->current_bss = NULL; 183 wdev->current_bss = NULL;
189 wdev->sme_state = CFG80211_SME_IDLE;
190 wdev->ssid_len = 0; 184 wdev->ssid_len = 0;
191#ifdef CONFIG_CFG80211_WEXT 185#ifdef CONFIG_CFG80211_WEXT
192 if (!nowext) 186 if (!nowext)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4b9c2be0d56d..a61a44bc6cf0 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -21,129 +21,85 @@
21void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, 21void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
22 const u8 *buf, size_t len) 22 const u8 *buf, size_t len)
23{ 23{
24 u16 status_code;
25 struct wireless_dev *wdev = dev->ieee80211_ptr; 24 struct wireless_dev *wdev = dev->ieee80211_ptr;
26 struct wiphy *wiphy = wdev->wiphy; 25 struct wiphy *wiphy = wdev->wiphy;
27 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 26 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
28 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 27 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
29 u8 *ie = mgmt->u.assoc_resp.variable; 28 u8 *ie = mgmt->u.assoc_resp.variable;
30 int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 29 int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
30 u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
31 31
32 trace_cfg80211_send_rx_assoc(dev, bss); 32 trace_cfg80211_send_rx_assoc(dev, bss);
33 33
34 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
35
36 /* 34 /*
37 * This is a bit of a hack, we don't notify userspace of 35 * This is a bit of a hack, we don't notify userspace of
38 * a (re-)association reply if we tried to send a reassoc 36 * a (re-)association reply if we tried to send a reassoc
39 * and got a reject -- we only try again with an assoc 37 * and got a reject -- we only try again with an assoc
40 * frame instead of reassoc. 38 * frame instead of reassoc.
41 */ 39 */
42 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && 40 if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
43 cfg80211_sme_failed_reassoc(wdev)) {
44 cfg80211_put_bss(wiphy, bss); 41 cfg80211_put_bss(wiphy, bss);
45 return; 42 return;
46 } 43 }
47 44
48 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); 45 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
49 46 /* update current_bss etc., consumes the bss reference */
50 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
51 cfg80211_sme_failed_assoc(wdev);
52 /*
53 * do not call connect_result() now because the
54 * sme will schedule work that does it later.
55 */
56 cfg80211_put_bss(wiphy, bss);
57 return;
58 }
59
60 if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
61 /*
62 * This is for the userspace SME, the CONNECTING
63 * state will be changed to CONNECTED by
64 * __cfg80211_connect_result() below.
65 */
66 wdev->sme_state = CFG80211_SME_CONNECTING;
67 }
68
69 /* this consumes the bss reference */
70 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, 47 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
71 status_code, 48 status_code,
72 status_code == WLAN_STATUS_SUCCESS, bss); 49 status_code == WLAN_STATUS_SUCCESS, bss);
73} 50}
74EXPORT_SYMBOL(cfg80211_rx_assoc_resp); 51EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
75 52
76static void cfg80211_process_deauth(struct net_device *dev, 53static void cfg80211_process_auth(struct wireless_dev *wdev,
54 const u8 *buf, size_t len)
55{
56 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
57
58 nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
59 cfg80211_sme_rx_auth(wdev, buf, len);
60}
61
62static void cfg80211_process_deauth(struct wireless_dev *wdev,
77 const u8 *buf, size_t len) 63 const u8 *buf, size_t len)
78{ 64{
79 struct wireless_dev *wdev = dev->ieee80211_ptr; 65 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
80 struct wiphy *wiphy = wdev->wiphy;
81 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
82 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 66 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
83 const u8 *bssid = mgmt->bssid; 67 const u8 *bssid = mgmt->bssid;
84 bool was_current = false; 68 u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
85 69 bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
86 if (wdev->current_bss &&
87 ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
88 cfg80211_unhold_bss(wdev->current_bss);
89 cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
90 wdev->current_bss = NULL;
91 was_current = true;
92 }
93 70
94 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); 71 nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
95 72
96 if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { 73 if (!wdev->current_bss ||
97 u16 reason_code; 74 !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
98 bool from_ap; 75 return;
99
100 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
101 76
102 from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); 77 __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
103 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 78 cfg80211_sme_deauth(wdev);
104 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
105 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
106 WLAN_STATUS_UNSPECIFIED_FAILURE,
107 false, NULL);
108 }
109} 79}
110 80
111static void cfg80211_process_disassoc(struct net_device *dev, 81static void cfg80211_process_disassoc(struct wireless_dev *wdev,
112 const u8 *buf, size_t len) 82 const u8 *buf, size_t len)
113{ 83{
114 struct wireless_dev *wdev = dev->ieee80211_ptr; 84 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
115 struct wiphy *wiphy = wdev->wiphy;
116 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
117 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 85 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
118 const u8 *bssid = mgmt->bssid; 86 const u8 *bssid = mgmt->bssid;
119 u16 reason_code; 87 u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
120 bool from_ap; 88 bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
121 89
122 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); 90 nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL);
123 91
124 if (wdev->sme_state != CFG80211_SME_CONNECTED) 92 if (WARN_ON(!wdev->current_bss ||
93 !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
125 return; 94 return;
126 95
127 if (wdev->current_bss && 96 __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
128 ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { 97 cfg80211_sme_disassoc(wdev);
129 cfg80211_sme_disassoc(dev, wdev->current_bss);
130 cfg80211_unhold_bss(wdev->current_bss);
131 cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
132 wdev->current_bss = NULL;
133 } else
134 WARN_ON(1);
135
136 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
137
138 from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
139 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
140} 98}
141 99
142void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) 100void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
143{ 101{
144 struct wireless_dev *wdev = dev->ieee80211_ptr; 102 struct wireless_dev *wdev = dev->ieee80211_ptr;
145 struct wiphy *wiphy = wdev->wiphy;
146 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
147 struct ieee80211_mgmt *mgmt = (void *)buf; 103 struct ieee80211_mgmt *mgmt = (void *)buf;
148 104
149 ASSERT_WDEV_LOCK(wdev); 105 ASSERT_WDEV_LOCK(wdev);
@@ -153,14 +109,12 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
153 if (WARN_ON(len < 2)) 109 if (WARN_ON(len < 2))
154 return; 110 return;
155 111
156 if (ieee80211_is_auth(mgmt->frame_control)) { 112 if (ieee80211_is_auth(mgmt->frame_control))
157 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); 113 cfg80211_process_auth(wdev, buf, len);
158 cfg80211_sme_rx_auth(dev, buf, len); 114 else if (ieee80211_is_deauth(mgmt->frame_control))
159 } else if (ieee80211_is_deauth(mgmt->frame_control)) { 115 cfg80211_process_deauth(wdev, buf, len);
160 cfg80211_process_deauth(dev, buf, len); 116 else if (ieee80211_is_disassoc(mgmt->frame_control))
161 } else if (ieee80211_is_disassoc(mgmt->frame_control)) { 117 cfg80211_process_disassoc(wdev, buf, len);
162 cfg80211_process_disassoc(dev, buf, len);
163 }
164} 118}
165EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); 119EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
166 120
@@ -173,10 +127,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
173 trace_cfg80211_send_auth_timeout(dev, addr); 127 trace_cfg80211_send_auth_timeout(dev, addr);
174 128
175 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); 129 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
176 if (wdev->sme_state == CFG80211_SME_CONNECTING) 130 cfg80211_sme_auth_timeout(wdev);
177 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
178 WLAN_STATUS_UNSPECIFIED_FAILURE,
179 false, NULL);
180} 131}
181EXPORT_SYMBOL(cfg80211_auth_timeout); 132EXPORT_SYMBOL(cfg80211_auth_timeout);
182 133
@@ -189,10 +140,7 @@ void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr)
189 trace_cfg80211_send_assoc_timeout(dev, addr); 140 trace_cfg80211_send_assoc_timeout(dev, addr);
190 141
191 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); 142 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
192 if (wdev->sme_state == CFG80211_SME_CONNECTING) 143 cfg80211_sme_assoc_timeout(wdev);
193 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
194 WLAN_STATUS_UNSPECIFIED_FAILURE,
195 false, NULL);
196} 144}
197EXPORT_SYMBOL(cfg80211_assoc_timeout); 145EXPORT_SYMBOL(cfg80211_assoc_timeout);
198 146
@@ -209,9 +157,9 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
209 return; 157 return;
210 158
211 if (ieee80211_is_deauth(mgmt->frame_control)) 159 if (ieee80211_is_deauth(mgmt->frame_control))
212 cfg80211_process_deauth(dev, buf, len); 160 cfg80211_process_deauth(wdev, buf, len);
213 else 161 else
214 cfg80211_process_disassoc(dev, buf, len); 162 cfg80211_process_disassoc(wdev, buf, len);
215} 163}
216EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); 164EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);
217 165
@@ -336,21 +284,12 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
336{ 284{
337 struct wireless_dev *wdev = dev->ieee80211_ptr; 285 struct wireless_dev *wdev = dev->ieee80211_ptr;
338 int err; 286 int err;
339 bool was_connected = false;
340 287
341 ASSERT_WDEV_LOCK(wdev); 288 ASSERT_WDEV_LOCK(wdev);
342 289
343 if (wdev->current_bss && req->prev_bssid && 290 if (wdev->current_bss &&
344 ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { 291 (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid,
345 /* 292 req->prev_bssid)))
346 * Trying to reassociate: Allow this to proceed and let the old
347 * association to be dropped when the new one is completed.
348 */
349 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
350 was_connected = true;
351 wdev->sme_state = CFG80211_SME_CONNECTING;
352 }
353 } else if (wdev->current_bss)
354 return -EALREADY; 293 return -EALREADY;
355 294
356 cfg80211_oper_and_ht_capa(&req->ht_capa_mask, 295 cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
@@ -360,11 +299,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
360 299
361 req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 300 req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
362 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 301 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
363 if (!req->bss) { 302 if (!req->bss)
364 if (was_connected)
365 wdev->sme_state = CFG80211_SME_CONNECTED;
366 return -ENOENT; 303 return -ENOENT;
367 }
368 304
369 err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); 305 err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
370 if (err) 306 if (err)
@@ -373,11 +309,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
373 err = rdev_assoc(rdev, dev, req); 309 err = rdev_assoc(rdev, dev, req);
374 310
375out: 311out:
376 if (err) { 312 if (err)
377 if (was_connected)
378 wdev->sme_state = CFG80211_SME_CONNECTED;
379 cfg80211_put_bss(&rdev->wiphy, req->bss); 313 cfg80211_put_bss(&rdev->wiphy, req->bss);
380 }
381 314
382 return err; 315 return err;
383} 316}
@@ -398,8 +331,9 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
398 331
399 ASSERT_WDEV_LOCK(wdev); 332 ASSERT_WDEV_LOCK(wdev);
400 333
401 if (local_state_change && (!wdev->current_bss || 334 if (local_state_change &&
402 !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) 335 (!wdev->current_bss ||
336 !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
403 return 0; 337 return 0;
404 338
405 return rdev_deauth(rdev, dev, &req); 339 return rdev_deauth(rdev, dev, &req);
@@ -417,13 +351,11 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
417 .ie = ie, 351 .ie = ie,
418 .ie_len = ie_len, 352 .ie_len = ie_len,
419 }; 353 };
354 int err;
420 355
421 ASSERT_WDEV_LOCK(wdev); 356 ASSERT_WDEV_LOCK(wdev);
422 357
423 if (wdev->sme_state != CFG80211_SME_CONNECTED) 358 if (!wdev->current_bss)
424 return -ENOTCONN;
425
426 if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
427 return -ENOTCONN; 359 return -ENOTCONN;
428 360
429 if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) 361 if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
@@ -431,7 +363,13 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
431 else 363 else
432 return -ENOTCONN; 364 return -ENOTCONN;
433 365
434 return rdev_disassoc(rdev, dev, &req); 366 err = rdev_disassoc(rdev, dev, &req);
367 if (err)
368 return err;
369
370 /* driver should have reported the disassoc */
371 WARN_ON(wdev->current_bss);
372 return 0;
435} 373}
436 374
437void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 375void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
@@ -439,10 +377,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
439{ 377{
440 struct wireless_dev *wdev = dev->ieee80211_ptr; 378 struct wireless_dev *wdev = dev->ieee80211_ptr;
441 u8 bssid[ETH_ALEN]; 379 u8 bssid[ETH_ALEN];
442 struct cfg80211_deauth_request req = {
443 .reason_code = WLAN_REASON_DEAUTH_LEAVING,
444 .bssid = bssid,
445 };
446 380
447 ASSERT_WDEV_LOCK(wdev); 381 ASSERT_WDEV_LOCK(wdev);
448 382
@@ -453,13 +387,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
453 return; 387 return;
454 388
455 memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); 389 memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
456 rdev_deauth(rdev, dev, &req); 390 cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
457 391 WLAN_REASON_DEAUTH_LEAVING, false);
458 if (wdev->current_bss) {
459 cfg80211_unhold_bss(wdev->current_bss);
460 cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
461 wdev->current_bss = NULL;
462 }
463} 392}
464 393
465struct cfg80211_mgmt_registration { 394struct cfg80211_mgmt_registration {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 444f5effb77f..88e820b73674 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -800,12 +800,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
800 case NL80211_IFTYPE_MESH_POINT: 800 case NL80211_IFTYPE_MESH_POINT:
801 break; 801 break;
802 case NL80211_IFTYPE_ADHOC: 802 case NL80211_IFTYPE_ADHOC:
803 if (!wdev->current_bss)
804 return -ENOLINK;
805 break;
806 case NL80211_IFTYPE_STATION: 803 case NL80211_IFTYPE_STATION:
807 case NL80211_IFTYPE_P2P_CLIENT: 804 case NL80211_IFTYPE_P2P_CLIENT:
808 if (wdev->sme_state != CFG80211_SME_CONNECTED) 805 if (!wdev->current_bss)
809 return -ENOLINK; 806 return -ENOLINK;
810 break; 807 break;
811 default: 808 default:
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}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index a53f8404f451..14c9a2583ba0 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -89,7 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
89 89
90 wdev_lock(wdev); 90 wdev_lock(wdev);
91 91
92 if (wdev->sme_state != CFG80211_SME_IDLE) { 92 if (wdev->conn) {
93 bool event = true; 93 bool event = true;
94 94
95 if (wdev->wext.connect.channel == chan) { 95 if (wdev->wext.connect.channel == chan) {
@@ -188,7 +188,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
188 188
189 err = 0; 189 err = 0;
190 190
191 if (wdev->sme_state != CFG80211_SME_IDLE) { 191 if (wdev->conn) {
192 bool event = true; 192 bool event = true;
193 193
194 if (wdev->wext.connect.ssid && len && 194 if (wdev->wext.connect.ssid && len &&
@@ -277,7 +277,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
277 277
278 wdev_lock(wdev); 278 wdev_lock(wdev);
279 279
280 if (wdev->sme_state != CFG80211_SME_IDLE) { 280 if (wdev->conn) {
281 err = 0; 281 err = 0;
282 /* both automatic */ 282 /* both automatic */
283 if (!bssid && !wdev->wext.connect.bssid) 283 if (!bssid && !wdev->wext.connect.bssid)
@@ -364,7 +364,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
364 wdev->wext.ie = ie; 364 wdev->wext.ie = ie;
365 wdev->wext.ie_len = ie_len; 365 wdev->wext.ie_len = ie_len;
366 366
367 if (wdev->sme_state != CFG80211_SME_IDLE) { 367 if (wdev->conn) {
368 err = cfg80211_disconnect(rdev, dev, 368 err = cfg80211_disconnect(rdev, dev,
369 WLAN_REASON_DEAUTH_LEAVING, false); 369 WLAN_REASON_DEAUTH_LEAVING, false);
370 if (err) 370 if (err)