aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-05-15 18:55:45 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-06-04 07:03:11 -0400
commitceca7b7121795ef81bd598a240d53a925662d0c1 (patch)
tree510d7a6c578d7ede025c8b4714b9584729517b0a /net
parent6ff57cf88807dd81300b5b9c623dc5eb6422b9f6 (diff)
cfg80211: separate internal SME implementation
The current internal SME implementation in cfg80211 is very mixed up with the MLME handling, which has been causing issues for a long time. There are three things that the implementation has to provide: * a basic SME implementation for nl80211's connect() call (for drivers implementing auth/assoc, which is really just mac80211) and wireless extensions * MLME events for the userspace SME * SME events (connected, disconnected etc.) for all different SME implementation possibilities (driver, cfg80211 and userspace) To achieve these goals it isn't necessary to track the software SME's connection status outside of it's state (which is the part that caused many issues.) Instead, track it only in the SME data (wdev->conn) and in the general case only track whether the wdev is connected or not (via wdev->current_bss.) Also separate the internal implementation to not have callbacks from the SME events, but rather call it from the API functions that the driver (or rather mac80211) calls. This separates the code better. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-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)