aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r--net/wireless/mlme.c105
1 files changed, 56 insertions, 49 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 0a6b7a0eca6b..1001db4912f7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -62,7 +62,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
62 u8 *ie = mgmt->u.assoc_resp.variable; 62 u8 *ie = mgmt->u.assoc_resp.variable;
63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
64 struct cfg80211_internal_bss *bss = NULL; 64 struct cfg80211_internal_bss *bss = NULL;
65 bool need_connect_result = true;
66 65
67 wdev_lock(wdev); 66 wdev_lock(wdev);
68 67
@@ -97,7 +96,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
97 WARN_ON(!bss); 96 WARN_ON(!bss);
98 } else if (wdev->conn) { 97 } else if (wdev->conn) {
99 cfg80211_sme_failed_assoc(wdev); 98 cfg80211_sme_failed_assoc(wdev);
100 need_connect_result = false;
101 /* 99 /*
102 * do not call connect_result() now because the 100 * do not call connect_result() now because the
103 * sme will schedule work that does it later. 101 * sme will schedule work that does it later.
@@ -130,7 +128,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
130} 128}
131EXPORT_SYMBOL(cfg80211_send_rx_assoc); 129EXPORT_SYMBOL(cfg80211_send_rx_assoc);
132 130
133static void __cfg80211_send_deauth(struct net_device *dev, 131void __cfg80211_send_deauth(struct net_device *dev,
134 const u8 *buf, size_t len) 132 const u8 *buf, size_t len)
135{ 133{
136 struct wireless_dev *wdev = dev->ieee80211_ptr; 134 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -139,7 +137,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
139 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 137 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
140 const u8 *bssid = mgmt->bssid; 138 const u8 *bssid = mgmt->bssid;
141 int i; 139 int i;
142 bool done = false;
143 140
144 ASSERT_WDEV_LOCK(wdev); 141 ASSERT_WDEV_LOCK(wdev);
145 142
@@ -147,7 +144,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
147 144
148 if (wdev->current_bss && 145 if (wdev->current_bss &&
149 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 146 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
150 done = true;
151 cfg80211_unhold_bss(wdev->current_bss); 147 cfg80211_unhold_bss(wdev->current_bss);
152 cfg80211_put_bss(&wdev->current_bss->pub); 148 cfg80211_put_bss(&wdev->current_bss->pub);
153 wdev->current_bss = NULL; 149 wdev->current_bss = NULL;
@@ -157,7 +153,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
157 cfg80211_unhold_bss(wdev->auth_bsses[i]); 153 cfg80211_unhold_bss(wdev->auth_bsses[i]);
158 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 154 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
159 wdev->auth_bsses[i] = NULL; 155 wdev->auth_bsses[i] = NULL;
160 done = true;
161 break; 156 break;
162 } 157 }
163 if (wdev->authtry_bsses[i] && 158 if (wdev->authtry_bsses[i] &&
@@ -165,13 +160,10 @@ static void __cfg80211_send_deauth(struct net_device *dev,
165 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 160 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
166 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 161 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
167 wdev->authtry_bsses[i] = NULL; 162 wdev->authtry_bsses[i] = NULL;
168 done = true;
169 break; 163 break;
170 } 164 }
171 } 165 }
172 166
173 WARN_ON(!done);
174
175 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 167 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
176 u16 reason_code; 168 u16 reason_code;
177 bool from_ap; 169 bool from_ap;
@@ -186,27 +178,19 @@ static void __cfg80211_send_deauth(struct net_device *dev,
186 false, NULL); 178 false, NULL);
187 } 179 }
188} 180}
181EXPORT_SYMBOL(__cfg80211_send_deauth);
189 182
190 183void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
191void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
192 void *cookie)
193{ 184{
194 struct wireless_dev *wdev = dev->ieee80211_ptr; 185 struct wireless_dev *wdev = dev->ieee80211_ptr;
195 186
196 BUG_ON(cookie && wdev != cookie); 187 wdev_lock(wdev);
197 188 __cfg80211_send_deauth(dev, buf, len);
198 if (cookie) { 189 wdev_unlock(wdev);
199 /* called within callback */
200 __cfg80211_send_deauth(dev, buf, len);
201 } else {
202 wdev_lock(wdev);
203 __cfg80211_send_deauth(dev, buf, len);
204 wdev_unlock(wdev);
205 }
206} 190}
207EXPORT_SYMBOL(cfg80211_send_deauth); 191EXPORT_SYMBOL(cfg80211_send_deauth);
208 192
209static void __cfg80211_send_disassoc(struct net_device *dev, 193void __cfg80211_send_disassoc(struct net_device *dev,
210 const u8 *buf, size_t len) 194 const u8 *buf, size_t len)
211{ 195{
212 struct wireless_dev *wdev = dev->ieee80211_ptr; 196 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -247,40 +231,24 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
247 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; 231 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
248 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 232 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
249} 233}
234EXPORT_SYMBOL(__cfg80211_send_disassoc);
250 235
251void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, 236void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
252 void *cookie)
253{ 237{
254 struct wireless_dev *wdev = dev->ieee80211_ptr; 238 struct wireless_dev *wdev = dev->ieee80211_ptr;
255 239
256 BUG_ON(cookie && wdev != cookie); 240 wdev_lock(wdev);
257 241 __cfg80211_send_disassoc(dev, buf, len);
258 if (cookie) { 242 wdev_unlock(wdev);
259 /* called within callback */
260 __cfg80211_send_disassoc(dev, buf, len);
261 } else {
262 wdev_lock(wdev);
263 __cfg80211_send_disassoc(dev, buf, len);
264 wdev_unlock(wdev);
265 }
266} 243}
267EXPORT_SYMBOL(cfg80211_send_disassoc); 244EXPORT_SYMBOL(cfg80211_send_disassoc);
268 245
269void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 246static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
270{ 247{
271 struct wireless_dev *wdev = dev->ieee80211_ptr;
272 struct wiphy *wiphy = wdev->wiphy;
273 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
274 int i; 248 int i;
275 bool done = false; 249 bool done = false;
276 250
277 wdev_lock(wdev); 251 ASSERT_WDEV_LOCK(wdev);
278
279 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
280 if (wdev->sme_state == CFG80211_SME_CONNECTING)
281 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
282 WLAN_STATUS_UNSPECIFIED_FAILURE,
283 false, NULL);
284 252
285 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 253 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
286 if (wdev->authtry_bsses[i] && 254 if (wdev->authtry_bsses[i] &&
@@ -295,6 +263,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
295 } 263 }
296 264
297 WARN_ON(!done); 265 WARN_ON(!done);
266}
267
268void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
269{
270 __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
271}
272EXPORT_SYMBOL(__cfg80211_auth_canceled);
273
274void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
275{
276 struct wireless_dev *wdev = dev->ieee80211_ptr;
277 struct wiphy *wiphy = wdev->wiphy;
278 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
279
280 wdev_lock(wdev);
281
282 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
283 if (wdev->sme_state == CFG80211_SME_CONNECTING)
284 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
285 WLAN_STATUS_UNSPECIFIED_FAILURE,
286 false, NULL);
287
288 __cfg80211_auth_remove(wdev, addr);
298 289
299 wdev_unlock(wdev); 290 wdev_unlock(wdev);
300} 291}
@@ -340,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
340{ 331{
341 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
342 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
343#ifdef CONFIG_WIRELESS_EXT 334#ifdef CONFIG_CFG80211_WEXT
344 union iwreq_data wrqu; 335 union iwreq_data wrqu;
345 char *buf = kmalloc(128, gfp); 336 char *buf = kmalloc(128, gfp);
346 337
@@ -469,12 +460,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
469 struct cfg80211_assoc_request req; 460 struct cfg80211_assoc_request req;
470 struct cfg80211_internal_bss *bss; 461 struct cfg80211_internal_bss *bss;
471 int i, err, slot = -1; 462 int i, err, slot = -1;
463 bool was_connected = false;
472 464
473 ASSERT_WDEV_LOCK(wdev); 465 ASSERT_WDEV_LOCK(wdev);
474 466
475 memset(&req, 0, sizeof(req)); 467 memset(&req, 0, sizeof(req));
476 468
477 if (wdev->current_bss) 469 if (wdev->current_bss && prev_bssid &&
470 memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
471 /*
472 * Trying to reassociate: Allow this to proceed and let the old
473 * association to be dropped when the new one is completed.
474 */
475 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
476 was_connected = true;
477 wdev->sme_state = CFG80211_SME_CONNECTING;
478 }
479 } else if (wdev->current_bss)
478 return -EALREADY; 480 return -EALREADY;
479 481
480 req.ie = ie; 482 req.ie = ie;
@@ -484,8 +486,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
484 req.prev_bssid = prev_bssid; 486 req.prev_bssid = prev_bssid;
485 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 487 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
486 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 488 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
487 if (!req.bss) 489 if (!req.bss) {
490 if (was_connected)
491 wdev->sme_state = CFG80211_SME_CONNECTED;
488 return -ENOENT; 492 return -ENOENT;
493 }
489 494
490 bss = bss_from_pub(req.bss); 495 bss = bss_from_pub(req.bss);
491 496
@@ -503,6 +508,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
503 508
504 err = rdev->ops->assoc(&rdev->wiphy, dev, &req); 509 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
505 out: 510 out:
511 if (err && was_connected)
512 wdev->sme_state = CFG80211_SME_CONNECTED;
506 /* still a reference in wdev->auth_bsses[slot] */ 513 /* still a reference in wdev->auth_bsses[slot] */
507 cfg80211_put_bss(req.bss); 514 cfg80211_put_bss(req.bss);
508 return err; 515 return err;