cfg80211: fix disassociation warning due to misuse of wdev->current_bss
[linux-2.6/kvm.git] / net / wireless / mlme.c
blobb44b6c024c14c7926ea8866f1ff834d03f2280ce
1 /*
2 * cfg80211 MLME SAP interface
4 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 */
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/netdevice.h>
10 #include <linux/nl80211.h>
11 #include <linux/wireless.h>
12 #include <net/cfg80211.h>
13 #include <net/iw_handler.h>
14 #include "core.h"
15 #include "nl80211.h"
17 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
19 struct wireless_dev *wdev = dev->ieee80211_ptr;
20 struct wiphy *wiphy = wdev->wiphy;
21 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
22 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
23 u8 *bssid = mgmt->bssid;
24 int i;
25 u16 status = le16_to_cpu(mgmt->u.auth.status_code);
26 bool done = false;
28 wdev_lock(wdev);
30 for (i = 0; i < MAX_AUTH_BSSES; i++) {
31 if (wdev->authtry_bsses[i] &&
32 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
33 ETH_ALEN) == 0) {
34 if (status == WLAN_STATUS_SUCCESS) {
35 wdev->auth_bsses[i] = wdev->authtry_bsses[i];
36 } else {
37 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
38 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
40 wdev->authtry_bsses[i] = NULL;
41 done = true;
42 break;
46 WARN_ON(!done);
48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
49 cfg80211_sme_rx_auth(dev, buf, len);
51 wdev_unlock(wdev);
53 EXPORT_SYMBOL(cfg80211_send_rx_auth);
55 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
57 u16 status_code;
58 struct wireless_dev *wdev = dev->ieee80211_ptr;
59 struct wiphy *wiphy = wdev->wiphy;
60 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
61 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
62 u8 *ie = mgmt->u.assoc_resp.variable;
63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
64 struct cfg80211_internal_bss *bss = NULL;
66 wdev_lock(wdev);
68 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
70 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
72 if (status_code == WLAN_STATUS_SUCCESS) {
73 for (i = 0; i < MAX_AUTH_BSSES; i++) {
74 if (!wdev->auth_bsses[i])
75 continue;
76 if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
77 ETH_ALEN) == 0) {
78 bss = wdev->auth_bsses[i];
79 wdev->auth_bsses[i] = NULL;
80 /* additional reference to drop hold */
81 cfg80211_ref_bss(bss);
82 break;
86 WARN_ON(!bss);
89 /* this consumes one bss reference (unless bss is NULL) */
90 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
91 status_code,
92 status_code == WLAN_STATUS_SUCCESS,
93 bss ? &bss->pub : NULL);
94 /* drop hold now, and also reference acquired above */
95 if (bss) {
96 cfg80211_unhold_bss(bss);
97 cfg80211_put_bss(&bss->pub);
100 wdev_unlock(wdev);
102 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
104 static void __cfg80211_send_deauth(struct net_device *dev,
105 const u8 *buf, size_t len)
107 struct wireless_dev *wdev = dev->ieee80211_ptr;
108 struct wiphy *wiphy = wdev->wiphy;
109 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
110 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
111 const u8 *bssid = mgmt->bssid;
112 int i;
113 bool done = false;
115 ASSERT_WDEV_LOCK(wdev);
117 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
119 if (wdev->current_bss &&
120 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
121 done = true;
122 cfg80211_unhold_bss(wdev->current_bss);
123 cfg80211_put_bss(&wdev->current_bss->pub);
124 wdev->current_bss = NULL;
125 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
126 if (wdev->auth_bsses[i] &&
127 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
128 cfg80211_unhold_bss(wdev->auth_bsses[i]);
129 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
130 wdev->auth_bsses[i] = NULL;
131 done = true;
132 break;
134 if (wdev->authtry_bsses[i] &&
135 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
136 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
137 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
138 wdev->authtry_bsses[i] = NULL;
139 done = true;
140 break;
144 WARN_ON(!done);
146 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
147 u16 reason_code;
148 bool from_ap;
150 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
152 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
153 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
154 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
155 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
156 WLAN_STATUS_UNSPECIFIED_FAILURE,
157 false, NULL);
162 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
163 void *cookie)
165 struct wireless_dev *wdev = dev->ieee80211_ptr;
167 BUG_ON(cookie && wdev != cookie);
169 if (cookie) {
170 /* called within callback */
171 __cfg80211_send_deauth(dev, buf, len);
172 } else {
173 wdev_lock(wdev);
174 __cfg80211_send_deauth(dev, buf, len);
175 wdev_unlock(wdev);
178 EXPORT_SYMBOL(cfg80211_send_deauth);
180 static void __cfg80211_send_disassoc(struct net_device *dev,
181 const u8 *buf, size_t len)
183 struct wireless_dev *wdev = dev->ieee80211_ptr;
184 struct wiphy *wiphy = wdev->wiphy;
185 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
186 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
187 const u8 *bssid = mgmt->bssid;
188 int i;
189 u16 reason_code;
190 bool from_ap;
191 bool done = false;
193 ASSERT_WDEV_LOCK(wdev);
195 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
197 if (wdev->sme_state != CFG80211_SME_CONNECTED)
198 return;
200 if (wdev->current_bss &&
201 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
202 for (i = 0; i < MAX_AUTH_BSSES; i++) {
203 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
204 continue;
205 wdev->auth_bsses[i] = wdev->current_bss;
206 wdev->current_bss = NULL;
207 done = true;
208 cfg80211_sme_disassoc(dev, i);
209 break;
211 WARN_ON(!done);
212 } else
213 WARN_ON(1);
216 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
218 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
219 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
222 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
223 void *cookie)
225 struct wireless_dev *wdev = dev->ieee80211_ptr;
227 BUG_ON(cookie && wdev != cookie);
229 if (cookie) {
230 /* called within callback */
231 __cfg80211_send_disassoc(dev, buf, len);
232 } else {
233 wdev_lock(wdev);
234 __cfg80211_send_disassoc(dev, buf, len);
235 wdev_unlock(wdev);
238 EXPORT_SYMBOL(cfg80211_send_disassoc);
240 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
242 struct wireless_dev *wdev = dev->ieee80211_ptr;
243 struct wiphy *wiphy = wdev->wiphy;
244 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
245 int i;
246 bool done = false;
248 wdev_lock(wdev);
250 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
251 if (wdev->sme_state == CFG80211_SME_CONNECTING)
252 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
253 WLAN_STATUS_UNSPECIFIED_FAILURE,
254 false, NULL);
256 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
257 if (wdev->authtry_bsses[i] &&
258 memcmp(wdev->authtry_bsses[i]->pub.bssid,
259 addr, ETH_ALEN) == 0) {
260 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
261 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
262 wdev->authtry_bsses[i] = NULL;
263 done = true;
264 break;
268 WARN_ON(!done);
270 wdev_unlock(wdev);
272 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
274 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
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 int i;
280 bool done = false;
282 wdev_lock(wdev);
284 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
285 if (wdev->sme_state == CFG80211_SME_CONNECTING)
286 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
287 WLAN_STATUS_UNSPECIFIED_FAILURE,
288 false, NULL);
290 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
291 if (wdev->auth_bsses[i] &&
292 memcmp(wdev->auth_bsses[i]->pub.bssid,
293 addr, ETH_ALEN) == 0) {
294 cfg80211_unhold_bss(wdev->auth_bsses[i]);
295 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
296 wdev->auth_bsses[i] = NULL;
297 done = true;
298 break;
302 WARN_ON(!done);
304 wdev_unlock(wdev);
306 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
308 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
309 enum nl80211_key_type key_type, int key_id,
310 const u8 *tsc, gfp_t gfp)
312 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
313 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
314 #ifdef CONFIG_WIRELESS_EXT
315 union iwreq_data wrqu;
316 char *buf = kmalloc(128, gfp);
318 if (buf) {
319 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
320 "keyid=%d %scast addr=%pM)", key_id,
321 key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
322 addr);
323 memset(&wrqu, 0, sizeof(wrqu));
324 wrqu.data.length = strlen(buf);
325 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
326 kfree(buf);
328 #endif
330 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
332 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
334 /* some MLME handling for userspace SME */
335 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
336 struct net_device *dev,
337 struct ieee80211_channel *chan,
338 enum nl80211_auth_type auth_type,
339 const u8 *bssid,
340 const u8 *ssid, int ssid_len,
341 const u8 *ie, int ie_len,
342 const u8 *key, int key_len, int key_idx)
344 struct wireless_dev *wdev = dev->ieee80211_ptr;
345 struct cfg80211_auth_request req;
346 struct cfg80211_internal_bss *bss;
347 int i, err, slot = -1, nfree = 0;
349 ASSERT_WDEV_LOCK(wdev);
351 if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
352 if (!key || !key_len || key_idx < 0 || key_idx > 4)
353 return -EINVAL;
355 if (wdev->current_bss &&
356 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
357 return -EALREADY;
359 for (i = 0; i < MAX_AUTH_BSSES; i++) {
360 if (wdev->authtry_bsses[i] &&
361 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
362 ETH_ALEN) == 0)
363 return -EALREADY;
364 if (wdev->auth_bsses[i] &&
365 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
366 ETH_ALEN) == 0)
367 return -EALREADY;
370 memset(&req, 0, sizeof(req));
372 req.ie = ie;
373 req.ie_len = ie_len;
374 req.auth_type = auth_type;
375 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
376 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
377 req.key = key;
378 req.key_len = key_len;
379 req.key_idx = key_idx;
380 if (!req.bss)
381 return -ENOENT;
383 bss = bss_from_pub(req.bss);
385 for (i = 0; i < MAX_AUTH_BSSES; i++) {
386 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
387 slot = i;
388 nfree++;
392 /* we need one free slot for disassoc and one for this auth */
393 if (nfree < 2) {
394 err = -ENOSPC;
395 goto out;
398 wdev->authtry_bsses[slot] = bss;
399 cfg80211_hold_bss(bss);
401 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
402 if (err) {
403 wdev->authtry_bsses[slot] = NULL;
404 cfg80211_unhold_bss(bss);
407 out:
408 if (err)
409 cfg80211_put_bss(req.bss);
410 return err;
413 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
414 struct net_device *dev, struct ieee80211_channel *chan,
415 enum nl80211_auth_type auth_type, const u8 *bssid,
416 const u8 *ssid, int ssid_len,
417 const u8 *ie, int ie_len,
418 const u8 *key, int key_len, int key_idx)
420 int err;
422 wdev_lock(dev->ieee80211_ptr);
423 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
424 ssid, ssid_len, ie, ie_len,
425 key, key_len, key_idx);
426 wdev_unlock(dev->ieee80211_ptr);
428 return err;
431 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
432 struct net_device *dev,
433 struct ieee80211_channel *chan,
434 const u8 *bssid, const u8 *prev_bssid,
435 const u8 *ssid, int ssid_len,
436 const u8 *ie, int ie_len, bool use_mfp,
437 struct cfg80211_crypto_settings *crypt)
439 struct wireless_dev *wdev = dev->ieee80211_ptr;
440 struct cfg80211_assoc_request req;
441 struct cfg80211_internal_bss *bss;
442 int i, err, slot = -1;
444 ASSERT_WDEV_LOCK(wdev);
446 memset(&req, 0, sizeof(req));
448 if (wdev->current_bss)
449 return -EALREADY;
451 req.ie = ie;
452 req.ie_len = ie_len;
453 memcpy(&req.crypto, crypt, sizeof(req.crypto));
454 req.use_mfp = use_mfp;
455 req.prev_bssid = prev_bssid;
456 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
457 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
458 if (!req.bss)
459 return -ENOENT;
461 bss = bss_from_pub(req.bss);
463 for (i = 0; i < MAX_AUTH_BSSES; i++) {
464 if (bss == wdev->auth_bsses[i]) {
465 slot = i;
466 break;
470 if (slot < 0) {
471 err = -ENOTCONN;
472 goto out;
475 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
476 out:
477 /* still a reference in wdev->auth_bsses[slot] */
478 cfg80211_put_bss(req.bss);
479 return err;
482 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
483 struct net_device *dev,
484 struct ieee80211_channel *chan,
485 const u8 *bssid, const u8 *prev_bssid,
486 const u8 *ssid, int ssid_len,
487 const u8 *ie, int ie_len, bool use_mfp,
488 struct cfg80211_crypto_settings *crypt)
490 struct wireless_dev *wdev = dev->ieee80211_ptr;
491 int err;
493 wdev_lock(wdev);
494 err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
495 ssid, ssid_len, ie, ie_len, use_mfp, crypt);
496 wdev_unlock(wdev);
498 return err;
501 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
502 struct net_device *dev, const u8 *bssid,
503 const u8 *ie, int ie_len, u16 reason)
505 struct wireless_dev *wdev = dev->ieee80211_ptr;
506 struct cfg80211_deauth_request req;
507 int i;
509 ASSERT_WDEV_LOCK(wdev);
511 memset(&req, 0, sizeof(req));
512 req.reason_code = reason;
513 req.ie = ie;
514 req.ie_len = ie_len;
515 if (wdev->current_bss &&
516 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
517 req.bss = &wdev->current_bss->pub;
518 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
519 if (wdev->auth_bsses[i] &&
520 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
521 req.bss = &wdev->auth_bsses[i]->pub;
522 break;
524 if (wdev->authtry_bsses[i] &&
525 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
526 req.bss = &wdev->authtry_bsses[i]->pub;
527 break;
531 if (!req.bss)
532 return -ENOTCONN;
534 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
537 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
538 struct net_device *dev, const u8 *bssid,
539 const u8 *ie, int ie_len, u16 reason)
541 struct wireless_dev *wdev = dev->ieee80211_ptr;
542 int err;
544 wdev_lock(wdev);
545 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
546 wdev_unlock(wdev);
548 return err;
551 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
552 struct net_device *dev, const u8 *bssid,
553 const u8 *ie, int ie_len, u16 reason)
555 struct wireless_dev *wdev = dev->ieee80211_ptr;
556 struct cfg80211_disassoc_request req;
558 ASSERT_WDEV_LOCK(wdev);
560 if (wdev->sme_state != CFG80211_SME_CONNECTED)
561 return -ENOTCONN;
563 if (WARN_ON(!wdev->current_bss))
564 return -ENOTCONN;
566 memset(&req, 0, sizeof(req));
567 req.reason_code = reason;
568 req.ie = ie;
569 req.ie_len = ie_len;
570 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
571 req.bss = &wdev->current_bss->pub;
572 else
573 return -ENOTCONN;
575 return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
578 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
579 struct net_device *dev, const u8 *bssid,
580 const u8 *ie, int ie_len, u16 reason)
582 struct wireless_dev *wdev = dev->ieee80211_ptr;
583 int err;
585 wdev_lock(wdev);
586 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
587 wdev_unlock(wdev);
589 return err;
592 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
593 struct net_device *dev)
595 struct wireless_dev *wdev = dev->ieee80211_ptr;
596 struct cfg80211_deauth_request req;
597 int i;
599 ASSERT_WDEV_LOCK(wdev);
601 if (!rdev->ops->deauth)
602 return;
604 memset(&req, 0, sizeof(req));
605 req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
606 req.ie = NULL;
607 req.ie_len = 0;
609 if (wdev->current_bss) {
610 req.bss = &wdev->current_bss->pub;
611 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
612 if (wdev->current_bss) {
613 cfg80211_unhold_bss(wdev->current_bss);
614 cfg80211_put_bss(&wdev->current_bss->pub);
615 wdev->current_bss = NULL;
619 for (i = 0; i < MAX_AUTH_BSSES; i++) {
620 if (wdev->auth_bsses[i]) {
621 req.bss = &wdev->auth_bsses[i]->pub;
622 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
623 if (wdev->auth_bsses[i]) {
624 cfg80211_unhold_bss(wdev->auth_bsses[i]);
625 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
626 wdev->auth_bsses[i] = NULL;
629 if (wdev->authtry_bsses[i]) {
630 req.bss = &wdev->authtry_bsses[i]->pub;
631 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
632 if (wdev->authtry_bsses[i]) {
633 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
634 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
635 wdev->authtry_bsses[i] = NULL;