Linux 2.6.32.42
[linux/fpc-iii.git] / net / wireless / mlme.c
blobec9a9d40a6c667ce3b8f5f4ed168508c98d457eb
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 if (done) {
47 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
48 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;
65 bool need_connect_result = true;
67 wdev_lock(wdev);
69 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
72 * This is a bit of a hack, we don't notify userspace of
73 * a (re-)association reply if we tried to send a reassoc
74 * and got a reject -- we only try again with an assoc
75 * frame instead of reassoc.
77 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
78 cfg80211_sme_failed_reassoc(wdev))
79 goto out;
81 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
83 if (status_code == WLAN_STATUS_SUCCESS) {
84 for (i = 0; i < MAX_AUTH_BSSES; i++) {
85 if (!wdev->auth_bsses[i])
86 continue;
87 if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
88 ETH_ALEN) == 0) {
89 bss = wdev->auth_bsses[i];
90 wdev->auth_bsses[i] = NULL;
91 /* additional reference to drop hold */
92 cfg80211_ref_bss(bss);
93 break;
98 * We might be coming here because the driver reported
99 * a successful association at the same time as the
100 * user requested a deauth. In that case, we will have
101 * removed the BSS from the auth_bsses list due to the
102 * deauth request when the assoc response makes it. If
103 * the two code paths acquire the lock the other way
104 * around, that's just the standard situation of a
105 * deauth being requested while connected.
107 if (!bss)
108 goto out;
109 } else if (wdev->conn) {
110 cfg80211_sme_failed_assoc(wdev);
111 need_connect_result = false;
113 * do not call connect_result() now because the
114 * sme will schedule work that does it later.
116 goto out;
119 if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
121 * This is for the userspace SME, the CONNECTING
122 * state will be changed to CONNECTED by
123 * __cfg80211_connect_result() below.
125 wdev->sme_state = CFG80211_SME_CONNECTING;
128 /* this consumes one bss reference (unless bss is NULL) */
129 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
130 status_code,
131 status_code == WLAN_STATUS_SUCCESS,
132 bss ? &bss->pub : NULL);
133 /* drop hold now, and also reference acquired above */
134 if (bss) {
135 cfg80211_unhold_bss(bss);
136 cfg80211_put_bss(&bss->pub);
139 out:
140 wdev_unlock(wdev);
142 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
144 static void __cfg80211_send_deauth(struct net_device *dev,
145 const u8 *buf, size_t len)
147 struct wireless_dev *wdev = dev->ieee80211_ptr;
148 struct wiphy *wiphy = wdev->wiphy;
149 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
150 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
151 const u8 *bssid = mgmt->bssid;
152 int i;
153 bool done = false;
155 ASSERT_WDEV_LOCK(wdev);
157 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
159 if (wdev->current_bss &&
160 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
161 done = true;
162 cfg80211_unhold_bss(wdev->current_bss);
163 cfg80211_put_bss(&wdev->current_bss->pub);
164 wdev->current_bss = NULL;
165 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
166 if (wdev->auth_bsses[i] &&
167 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
168 cfg80211_unhold_bss(wdev->auth_bsses[i]);
169 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
170 wdev->auth_bsses[i] = NULL;
171 done = true;
172 break;
174 if (wdev->authtry_bsses[i] &&
175 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
176 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
177 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
178 wdev->authtry_bsses[i] = NULL;
179 done = true;
180 break;
184 WARN_ON(!done);
186 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
187 u16 reason_code;
188 bool from_ap;
190 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
192 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
193 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
194 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
195 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
196 WLAN_STATUS_UNSPECIFIED_FAILURE,
197 false, NULL);
202 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
203 void *cookie)
205 struct wireless_dev *wdev = dev->ieee80211_ptr;
207 BUG_ON(cookie && wdev != cookie);
209 if (cookie) {
210 /* called within callback */
211 __cfg80211_send_deauth(dev, buf, len);
212 } else {
213 wdev_lock(wdev);
214 __cfg80211_send_deauth(dev, buf, len);
215 wdev_unlock(wdev);
218 EXPORT_SYMBOL(cfg80211_send_deauth);
220 static void __cfg80211_send_disassoc(struct net_device *dev,
221 const u8 *buf, size_t len)
223 struct wireless_dev *wdev = dev->ieee80211_ptr;
224 struct wiphy *wiphy = wdev->wiphy;
225 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
226 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
227 const u8 *bssid = mgmt->bssid;
228 int i;
229 u16 reason_code;
230 bool from_ap;
231 bool done = false;
233 ASSERT_WDEV_LOCK(wdev);
235 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
237 if (wdev->sme_state != CFG80211_SME_CONNECTED)
238 return;
240 if (wdev->current_bss &&
241 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
242 for (i = 0; i < MAX_AUTH_BSSES; i++) {
243 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
244 continue;
245 wdev->auth_bsses[i] = wdev->current_bss;
246 wdev->current_bss = NULL;
247 done = true;
248 cfg80211_sme_disassoc(dev, i);
249 break;
251 WARN_ON(!done);
252 } else
253 WARN_ON(1);
256 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
258 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
259 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
262 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
263 void *cookie)
265 struct wireless_dev *wdev = dev->ieee80211_ptr;
267 BUG_ON(cookie && wdev != cookie);
269 if (cookie) {
270 /* called within callback */
271 __cfg80211_send_disassoc(dev, buf, len);
272 } else {
273 wdev_lock(wdev);
274 __cfg80211_send_disassoc(dev, buf, len);
275 wdev_unlock(wdev);
278 EXPORT_SYMBOL(cfg80211_send_disassoc);
280 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
282 struct wireless_dev *wdev = dev->ieee80211_ptr;
283 struct wiphy *wiphy = wdev->wiphy;
284 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
285 int i;
286 bool done = false;
288 wdev_lock(wdev);
290 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
291 if (wdev->sme_state == CFG80211_SME_CONNECTING)
292 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
293 WLAN_STATUS_UNSPECIFIED_FAILURE,
294 false, NULL);
296 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
297 if (wdev->authtry_bsses[i] &&
298 memcmp(wdev->authtry_bsses[i]->pub.bssid,
299 addr, ETH_ALEN) == 0) {
300 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
301 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
302 wdev->authtry_bsses[i] = NULL;
303 done = true;
304 break;
308 WARN_ON(!done);
310 wdev_unlock(wdev);
312 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
314 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
316 struct wireless_dev *wdev = dev->ieee80211_ptr;
317 struct wiphy *wiphy = wdev->wiphy;
318 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
319 int i;
320 bool done = false;
322 wdev_lock(wdev);
324 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
325 if (wdev->sme_state == CFG80211_SME_CONNECTING)
326 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
327 WLAN_STATUS_UNSPECIFIED_FAILURE,
328 false, NULL);
330 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
331 if (wdev->auth_bsses[i] &&
332 memcmp(wdev->auth_bsses[i]->pub.bssid,
333 addr, ETH_ALEN) == 0) {
334 cfg80211_unhold_bss(wdev->auth_bsses[i]);
335 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
336 wdev->auth_bsses[i] = NULL;
337 done = true;
338 break;
342 WARN_ON(!done);
344 wdev_unlock(wdev);
346 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
348 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
349 enum nl80211_key_type key_type, int key_id,
350 const u8 *tsc, gfp_t gfp)
352 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
353 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
354 #ifdef CONFIG_WIRELESS_EXT
355 union iwreq_data wrqu;
356 char *buf = kmalloc(128, gfp);
358 if (buf) {
359 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
360 "keyid=%d %scast addr=%pM)", key_id,
361 key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
362 addr);
363 memset(&wrqu, 0, sizeof(wrqu));
364 wrqu.data.length = strlen(buf);
365 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
366 kfree(buf);
368 #endif
370 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
372 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
374 /* some MLME handling for userspace SME */
375 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
376 struct net_device *dev,
377 struct ieee80211_channel *chan,
378 enum nl80211_auth_type auth_type,
379 const u8 *bssid,
380 const u8 *ssid, int ssid_len,
381 const u8 *ie, int ie_len,
382 const u8 *key, int key_len, int key_idx)
384 struct wireless_dev *wdev = dev->ieee80211_ptr;
385 struct cfg80211_auth_request req;
386 struct cfg80211_internal_bss *bss;
387 int i, err, slot = -1, nfree = 0;
389 ASSERT_WDEV_LOCK(wdev);
391 if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
392 if (!key || !key_len || key_idx < 0 || key_idx > 4)
393 return -EINVAL;
395 if (wdev->current_bss &&
396 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
397 return -EALREADY;
399 for (i = 0; i < MAX_AUTH_BSSES; i++) {
400 if (wdev->authtry_bsses[i] &&
401 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
402 ETH_ALEN) == 0)
403 return -EALREADY;
404 if (wdev->auth_bsses[i] &&
405 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
406 ETH_ALEN) == 0)
407 return -EALREADY;
410 memset(&req, 0, sizeof(req));
412 req.ie = ie;
413 req.ie_len = ie_len;
414 req.auth_type = auth_type;
415 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
416 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
417 req.key = key;
418 req.key_len = key_len;
419 req.key_idx = key_idx;
420 if (!req.bss)
421 return -ENOENT;
423 bss = bss_from_pub(req.bss);
425 for (i = 0; i < MAX_AUTH_BSSES; i++) {
426 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
427 slot = i;
428 nfree++;
432 /* we need one free slot for disassoc and one for this auth */
433 if (nfree < 2) {
434 err = -ENOSPC;
435 goto out;
438 wdev->authtry_bsses[slot] = bss;
439 cfg80211_hold_bss(bss);
441 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
442 if (err) {
443 wdev->authtry_bsses[slot] = NULL;
444 cfg80211_unhold_bss(bss);
447 out:
448 if (err)
449 cfg80211_put_bss(req.bss);
450 return err;
453 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
454 struct net_device *dev, struct ieee80211_channel *chan,
455 enum nl80211_auth_type auth_type, const u8 *bssid,
456 const u8 *ssid, int ssid_len,
457 const u8 *ie, int ie_len,
458 const u8 *key, int key_len, int key_idx)
460 int err;
462 wdev_lock(dev->ieee80211_ptr);
463 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
464 ssid, ssid_len, ie, ie_len,
465 key, key_len, key_idx);
466 wdev_unlock(dev->ieee80211_ptr);
468 return err;
471 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
472 struct net_device *dev,
473 struct ieee80211_channel *chan,
474 const u8 *bssid, const u8 *prev_bssid,
475 const u8 *ssid, int ssid_len,
476 const u8 *ie, int ie_len, bool use_mfp,
477 struct cfg80211_crypto_settings *crypt)
479 struct wireless_dev *wdev = dev->ieee80211_ptr;
480 struct cfg80211_assoc_request req;
481 struct cfg80211_internal_bss *bss;
482 int i, err, slot = -1;
484 ASSERT_WDEV_LOCK(wdev);
486 memset(&req, 0, sizeof(req));
488 if (wdev->current_bss)
489 return -EALREADY;
491 req.ie = ie;
492 req.ie_len = ie_len;
493 memcpy(&req.crypto, crypt, sizeof(req.crypto));
494 req.use_mfp = use_mfp;
495 req.prev_bssid = prev_bssid;
496 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
497 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
498 if (!req.bss)
499 return -ENOENT;
501 bss = bss_from_pub(req.bss);
503 for (i = 0; i < MAX_AUTH_BSSES; i++) {
504 if (bss == wdev->auth_bsses[i]) {
505 slot = i;
506 break;
510 if (slot < 0) {
511 err = -ENOTCONN;
512 goto out;
515 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
516 out:
517 /* still a reference in wdev->auth_bsses[slot] */
518 cfg80211_put_bss(req.bss);
519 return err;
522 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
523 struct net_device *dev,
524 struct ieee80211_channel *chan,
525 const u8 *bssid, const u8 *prev_bssid,
526 const u8 *ssid, int ssid_len,
527 const u8 *ie, int ie_len, bool use_mfp,
528 struct cfg80211_crypto_settings *crypt)
530 struct wireless_dev *wdev = dev->ieee80211_ptr;
531 int err;
533 wdev_lock(wdev);
534 err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
535 ssid, ssid_len, ie, ie_len, use_mfp, crypt);
536 wdev_unlock(wdev);
538 return err;
541 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
542 struct net_device *dev, const u8 *bssid,
543 const u8 *ie, int ie_len, u16 reason)
545 struct wireless_dev *wdev = dev->ieee80211_ptr;
546 struct cfg80211_deauth_request req;
547 int i;
549 ASSERT_WDEV_LOCK(wdev);
551 memset(&req, 0, sizeof(req));
552 req.reason_code = reason;
553 req.ie = ie;
554 req.ie_len = ie_len;
555 if (wdev->current_bss &&
556 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
557 req.bss = &wdev->current_bss->pub;
558 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
559 if (wdev->auth_bsses[i] &&
560 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
561 req.bss = &wdev->auth_bsses[i]->pub;
562 break;
564 if (wdev->authtry_bsses[i] &&
565 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
566 req.bss = &wdev->authtry_bsses[i]->pub;
567 break;
571 if (!req.bss)
572 return -ENOTCONN;
574 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
577 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
578 struct net_device *dev, const u8 *bssid,
579 const u8 *ie, int ie_len, u16 reason)
581 struct wireless_dev *wdev = dev->ieee80211_ptr;
582 int err;
584 wdev_lock(wdev);
585 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
586 wdev_unlock(wdev);
588 return err;
591 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
592 struct net_device *dev, const u8 *bssid,
593 const u8 *ie, int ie_len, u16 reason)
595 struct wireless_dev *wdev = dev->ieee80211_ptr;
596 struct cfg80211_disassoc_request req;
598 ASSERT_WDEV_LOCK(wdev);
600 if (wdev->sme_state != CFG80211_SME_CONNECTED)
601 return -ENOTCONN;
603 if (WARN_ON(!wdev->current_bss))
604 return -ENOTCONN;
606 memset(&req, 0, sizeof(req));
607 req.reason_code = reason;
608 req.ie = ie;
609 req.ie_len = ie_len;
610 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
611 req.bss = &wdev->current_bss->pub;
612 else
613 return -ENOTCONN;
615 return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
618 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
619 struct net_device *dev, const u8 *bssid,
620 const u8 *ie, int ie_len, u16 reason)
622 struct wireless_dev *wdev = dev->ieee80211_ptr;
623 int err;
625 wdev_lock(wdev);
626 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
627 wdev_unlock(wdev);
629 return err;
632 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
633 struct net_device *dev)
635 struct wireless_dev *wdev = dev->ieee80211_ptr;
636 struct cfg80211_deauth_request req;
637 int i;
639 ASSERT_WDEV_LOCK(wdev);
641 if (!rdev->ops->deauth)
642 return;
644 memset(&req, 0, sizeof(req));
645 req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
646 req.ie = NULL;
647 req.ie_len = 0;
649 if (wdev->current_bss) {
650 req.bss = &wdev->current_bss->pub;
651 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
652 if (wdev->current_bss) {
653 cfg80211_unhold_bss(wdev->current_bss);
654 cfg80211_put_bss(&wdev->current_bss->pub);
655 wdev->current_bss = NULL;
659 for (i = 0; i < MAX_AUTH_BSSES; i++) {
660 if (wdev->auth_bsses[i]) {
661 req.bss = &wdev->auth_bsses[i]->pub;
662 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
663 if (wdev->auth_bsses[i]) {
664 cfg80211_unhold_bss(wdev->auth_bsses[i]);
665 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
666 wdev->auth_bsses[i] = NULL;
669 if (wdev->authtry_bsses[i]) {
670 req.bss = &wdev->authtry_bsses[i]->pub;
671 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
672 if (wdev->authtry_bsses[i]) {
673 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
674 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
675 wdev->authtry_bsses[i] = NULL;