cfg80211: fix disassociation warning due to misuse of wdev->current_bss
[pandora-kernel.git] / net / wireless / mlme.c
1 /*
2  * cfg80211 MLME SAP interface
3  *
4  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5  */
6
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"
16
17 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
18 {
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;
27
28         wdev_lock(wdev);
29
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);
39                         }
40                         wdev->authtry_bsses[i] = NULL;
41                         done = true;
42                         break;
43                 }
44         }
45
46         WARN_ON(!done);
47
48         nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
49         cfg80211_sme_rx_auth(dev, buf, len);
50
51         wdev_unlock(wdev);
52 }
53 EXPORT_SYMBOL(cfg80211_send_rx_auth);
54
55 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
56 {
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
66         wdev_lock(wdev);
67
68         status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
69
70         nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
71
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;
83                         }
84                 }
85
86                 WARN_ON(!bss);
87         }
88
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);
98         }
99
100         wdev_unlock(wdev);
101 }
102 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
103
104 static void __cfg80211_send_deauth(struct net_device *dev,
105                                    const u8 *buf, size_t len)
106 {
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;
114
115         ASSERT_WDEV_LOCK(wdev);
116
117         nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
118
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;
133                 }
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;
141                 }
142         }
143
144         WARN_ON(!done);
145
146         if (wdev->sme_state == CFG80211_SME_CONNECTED) {
147                 u16 reason_code;
148                 bool from_ap;
149
150                 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
151
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);
158         }
159 }
160
161
162 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
163                           void *cookie)
164 {
165         struct wireless_dev *wdev = dev->ieee80211_ptr;
166
167         BUG_ON(cookie && wdev != cookie);
168
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);
176         }
177 }
178 EXPORT_SYMBOL(cfg80211_send_deauth);
179
180 static void __cfg80211_send_disassoc(struct net_device *dev,
181                                      const u8 *buf, size_t len)
182 {
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;
192
193         ASSERT_WDEV_LOCK(wdev);
194
195         nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
196
197         if (wdev->sme_state != CFG80211_SME_CONNECTED)
198                 return;
199
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;
210                 }
211                 WARN_ON(!done);
212         } else
213                 WARN_ON(1);
214
215
216         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
217
218         from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
219         __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
220 }
221
222 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
223                             void *cookie)
224 {
225         struct wireless_dev *wdev = dev->ieee80211_ptr;
226
227         BUG_ON(cookie && wdev != cookie);
228
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);
236         }
237 }
238 EXPORT_SYMBOL(cfg80211_send_disassoc);
239
240 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
241 {
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;
247
248         wdev_lock(wdev);
249
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);
255
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;
265                 }
266         }
267
268         WARN_ON(!done);
269
270         wdev_unlock(wdev);
271 }
272 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
273
274 void cfg80211_send_assoc_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         int i;
280         bool done = false;
281
282         wdev_lock(wdev);
283
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);
289
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;
299                 }
300         }
301
302         WARN_ON(!done);
303
304         wdev_unlock(wdev);
305 }
306 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
307
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)
311 {
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);
317
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);
327         }
328 #endif
329
330         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
331 }
332 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
333
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)
343 {
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;
348
349         ASSERT_WDEV_LOCK(wdev);
350
351         if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
352                 if (!key || !key_len || key_idx < 0 || key_idx > 4)
353                         return -EINVAL;
354
355         if (wdev->current_bss &&
356             memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
357                 return -EALREADY;
358
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;
368         }
369
370         memset(&req, 0, sizeof(req));
371
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;
382
383         bss = bss_from_pub(req.bss);
384
385         for (i = 0; i < MAX_AUTH_BSSES; i++) {
386                 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
387                         slot = i;
388                         nfree++;
389                 }
390         }
391
392         /* we need one free slot for disassoc and one for this auth */
393         if (nfree < 2) {
394                 err = -ENOSPC;
395                 goto out;
396         }
397
398         wdev->authtry_bsses[slot] = bss;
399         cfg80211_hold_bss(bss);
400
401         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
402         if (err) {
403                 wdev->authtry_bsses[slot] = NULL;
404                 cfg80211_unhold_bss(bss);
405         }
406
407  out:
408         if (err)
409                 cfg80211_put_bss(req.bss);
410         return err;
411 }
412
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)
419 {
420         int err;
421
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);
427
428         return err;
429 }
430
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)
438 {
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;
443
444         ASSERT_WDEV_LOCK(wdev);
445
446         memset(&req, 0, sizeof(req));
447
448         if (wdev->current_bss)
449                 return -EALREADY;
450
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;
460
461         bss = bss_from_pub(req.bss);
462
463         for (i = 0; i < MAX_AUTH_BSSES; i++) {
464                 if (bss == wdev->auth_bsses[i]) {
465                         slot = i;
466                         break;
467                 }
468         }
469
470         if (slot < 0) {
471                 err = -ENOTCONN;
472                 goto out;
473         }
474
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;
480 }
481
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)
489 {
490         struct wireless_dev *wdev = dev->ieee80211_ptr;
491         int err;
492
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);
497
498         return err;
499 }
500
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)
504 {
505         struct wireless_dev *wdev = dev->ieee80211_ptr;
506         struct cfg80211_deauth_request req;
507         int i;
508
509         ASSERT_WDEV_LOCK(wdev);
510
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;
523                 }
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;
528                 }
529         }
530
531         if (!req.bss)
532                 return -ENOTCONN;
533
534         return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
535 }
536
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)
540 {
541         struct wireless_dev *wdev = dev->ieee80211_ptr;
542         int err;
543
544         wdev_lock(wdev);
545         err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
546         wdev_unlock(wdev);
547
548         return err;
549 }
550
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)
554 {
555         struct wireless_dev *wdev = dev->ieee80211_ptr;
556         struct cfg80211_disassoc_request req;
557
558         ASSERT_WDEV_LOCK(wdev);
559
560         if (wdev->sme_state != CFG80211_SME_CONNECTED)
561                 return -ENOTCONN;
562
563         if (WARN_ON(!wdev->current_bss))
564                 return -ENOTCONN;
565
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;
574
575         return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
576 }
577
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)
581 {
582         struct wireless_dev *wdev = dev->ieee80211_ptr;
583         int err;
584
585         wdev_lock(wdev);
586         err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
587         wdev_unlock(wdev);
588
589         return err;
590 }
591
592 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
593                         struct net_device *dev)
594 {
595         struct wireless_dev *wdev = dev->ieee80211_ptr;
596         struct cfg80211_deauth_request req;
597         int i;
598
599         ASSERT_WDEV_LOCK(wdev);
600
601         if (!rdev->ops->deauth)
602                 return;
603
604         memset(&req, 0, sizeof(req));
605         req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
606         req.ie = NULL;
607         req.ie_len = 0;
608
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;
616                 }
617         }
618
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;
627                         }
628                 }
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;
636                         }
637                 }
638         }
639 }