cfg80211: self-contained wext handling where possible
[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         bool done;
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         __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
73                                   status_code,
74                                   status_code == WLAN_STATUS_SUCCESS);
75
76         if (status_code == WLAN_STATUS_SUCCESS) {
77                 for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
78                         if (wdev->auth_bsses[i] == wdev->current_bss) {
79                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
80                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
81                                 wdev->auth_bsses[i] = NULL;
82                                 done = true;
83                                 break;
84                         }
85                 }
86
87                 WARN_ON(!done);
88         }
89
90         wdev_unlock(wdev);
91 }
92 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
93
94 static void __cfg80211_send_deauth(struct net_device *dev,
95                                    const u8 *buf, size_t len)
96 {
97         struct wireless_dev *wdev = dev->ieee80211_ptr;
98         struct wiphy *wiphy = wdev->wiphy;
99         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
100         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
101         const u8 *bssid = mgmt->bssid;
102         int i;
103         bool done = false;
104
105         ASSERT_WDEV_LOCK(wdev);
106
107         nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
108
109         if (wdev->current_bss &&
110             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
111                 done = true;
112                 cfg80211_unhold_bss(wdev->current_bss);
113                 cfg80211_put_bss(&wdev->current_bss->pub);
114                 wdev->current_bss = NULL;
115         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
116                 if (wdev->auth_bsses[i] &&
117                     memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
118                         cfg80211_unhold_bss(wdev->auth_bsses[i]);
119                         cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
120                         wdev->auth_bsses[i] = NULL;
121                         done = true;
122                         break;
123                 }
124                 if (wdev->authtry_bsses[i] &&
125                     memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
126                         cfg80211_unhold_bss(wdev->authtry_bsses[i]);
127                         cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
128                         wdev->authtry_bsses[i] = NULL;
129                         done = true;
130                         break;
131                 }
132         }
133
134         WARN_ON(!done);
135
136         if (wdev->sme_state == CFG80211_SME_CONNECTED) {
137                 u16 reason_code;
138                 bool from_ap;
139
140                 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
141
142                 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
143                 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
144         } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
145                 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
146                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
147                                           false);
148         }
149 }
150
151
152 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
153                           void *cookie)
154 {
155         struct wireless_dev *wdev = dev->ieee80211_ptr;
156
157         BUG_ON(cookie && wdev != cookie);
158
159         if (cookie) {
160                 /* called within callback */
161                 __cfg80211_send_deauth(dev, buf, len);
162         } else {
163                 wdev_lock(wdev);
164                 __cfg80211_send_deauth(dev, buf, len);
165                 wdev_unlock(wdev);
166         }
167 }
168 EXPORT_SYMBOL(cfg80211_send_deauth);
169
170 static void __cfg80211_send_disassoc(struct net_device *dev,
171                                      const u8 *buf, size_t len)
172 {
173         struct wireless_dev *wdev = dev->ieee80211_ptr;
174         struct wiphy *wiphy = wdev->wiphy;
175         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
176         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
177         const u8 *bssid = mgmt->bssid;
178         int i;
179         u16 reason_code;
180         bool from_ap;
181         bool done = false;
182
183         ASSERT_WDEV_LOCK(wdev);
184
185         nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
186
187         if (wdev->sme_state != CFG80211_SME_CONNECTED)
188                 return;
189
190         if (wdev->current_bss &&
191             memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
192                 for (i = 0; i < MAX_AUTH_BSSES; i++) {
193                         if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
194                                 continue;
195                         wdev->auth_bsses[i] = wdev->current_bss;
196                         wdev->current_bss = NULL;
197                         done = true;
198                         cfg80211_sme_disassoc(dev, i);
199                         break;
200                 }
201                 WARN_ON(!done);
202         } else
203                 WARN_ON(1);
204
205
206         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
207
208         from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
209         __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
210 }
211
212 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
213                             void *cookie)
214 {
215         struct wireless_dev *wdev = dev->ieee80211_ptr;
216
217         BUG_ON(cookie && wdev != cookie);
218
219         if (cookie) {
220                 /* called within callback */
221                 __cfg80211_send_disassoc(dev, buf, len);
222         } else {
223                 wdev_lock(wdev);
224                 __cfg80211_send_disassoc(dev, buf, len);
225                 wdev_unlock(wdev);
226         }
227 }
228 EXPORT_SYMBOL(cfg80211_send_disassoc);
229
230 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
231 {
232         struct wireless_dev *wdev = dev->ieee80211_ptr;
233         struct wiphy *wiphy = wdev->wiphy;
234         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
235         int i;
236         bool done = false;
237
238         wdev_lock(wdev);
239
240         nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
241         if (wdev->sme_state == CFG80211_SME_CONNECTING)
242                 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
243                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
244                                           false);
245
246         for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
247                 if (wdev->authtry_bsses[i] &&
248                     memcmp(wdev->authtry_bsses[i]->pub.bssid,
249                            addr, ETH_ALEN) == 0) {
250                         cfg80211_unhold_bss(wdev->authtry_bsses[i]);
251                         cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
252                         wdev->authtry_bsses[i] = NULL;
253                         done = true;
254                         break;
255                 }
256         }
257
258         WARN_ON(!done);
259
260         wdev_unlock(wdev);
261 }
262 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
263
264 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
265 {
266         struct wireless_dev *wdev = dev->ieee80211_ptr;
267         struct wiphy *wiphy = wdev->wiphy;
268         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
269         int i;
270         bool done = false;
271
272         wdev_lock(wdev);
273
274         nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
275         if (wdev->sme_state == CFG80211_SME_CONNECTING)
276                 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
277                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
278                                           false);
279
280         for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
281                 if (wdev->auth_bsses[i] &&
282                     memcmp(wdev->auth_bsses[i]->pub.bssid,
283                            addr, ETH_ALEN) == 0) {
284                         cfg80211_unhold_bss(wdev->auth_bsses[i]);
285                         cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
286                         wdev->auth_bsses[i] = NULL;
287                         done = true;
288                         break;
289                 }
290         }
291
292         WARN_ON(!done);
293
294         wdev_unlock(wdev);
295 }
296 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
297
298 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
299                                   enum nl80211_key_type key_type, int key_id,
300                                   const u8 *tsc, gfp_t gfp)
301 {
302         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
303         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
304 #ifdef CONFIG_WIRELESS_EXT
305         union iwreq_data wrqu;
306         char *buf = kmalloc(128, gfp);
307
308         if (buf) {
309                 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
310                         "keyid=%d %scast addr=%pM)", key_id,
311                         key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
312                         addr);
313                 memset(&wrqu, 0, sizeof(wrqu));
314                 wrqu.data.length = strlen(buf);
315                 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
316                 kfree(buf);
317         }
318 #endif
319
320         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
321 }
322 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
323
324 /* some MLME handling for userspace SME */
325 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
326                          struct net_device *dev,
327                          struct ieee80211_channel *chan,
328                          enum nl80211_auth_type auth_type,
329                          const u8 *bssid,
330                          const u8 *ssid, int ssid_len,
331                          const u8 *ie, int ie_len,
332                          const u8 *key, int key_len, int key_idx)
333 {
334         struct wireless_dev *wdev = dev->ieee80211_ptr;
335         struct cfg80211_auth_request req;
336         struct cfg80211_internal_bss *bss;
337         int i, err, slot = -1, nfree = 0;
338
339         ASSERT_WDEV_LOCK(wdev);
340
341         if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
342                 if (!key || !key_len || key_idx < 0 || key_idx > 4)
343                         return -EINVAL;
344
345         if (wdev->current_bss &&
346             memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
347                 return -EALREADY;
348
349         for (i = 0; i < MAX_AUTH_BSSES; i++) {
350                 if (wdev->authtry_bsses[i] &&
351                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
352                                                 ETH_ALEN) == 0)
353                         return -EALREADY;
354                 if (wdev->auth_bsses[i] &&
355                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
356                                                 ETH_ALEN) == 0)
357                         return -EALREADY;
358         }
359
360         memset(&req, 0, sizeof(req));
361
362         req.ie = ie;
363         req.ie_len = ie_len;
364         req.auth_type = auth_type;
365         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
366                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
367         req.key = key;
368         req.key_len = key_len;
369         req.key_idx = key_idx;
370         if (!req.bss)
371                 return -ENOENT;
372
373         bss = bss_from_pub(req.bss);
374
375         for (i = 0; i < MAX_AUTH_BSSES; i++) {
376                 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
377                         slot = i;
378                         nfree++;
379                 }
380         }
381
382         /* we need one free slot for disassoc and one for this auth */
383         if (nfree < 2) {
384                 err = -ENOSPC;
385                 goto out;
386         }
387
388         wdev->authtry_bsses[slot] = bss;
389         cfg80211_hold_bss(bss);
390
391         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
392         if (err) {
393                 wdev->authtry_bsses[slot] = NULL;
394                 cfg80211_unhold_bss(bss);
395         }
396
397  out:
398         if (err)
399                 cfg80211_put_bss(req.bss);
400         return err;
401 }
402
403 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
404                        struct net_device *dev, struct ieee80211_channel *chan,
405                        enum nl80211_auth_type auth_type, const u8 *bssid,
406                        const u8 *ssid, int ssid_len,
407                        const u8 *ie, int ie_len,
408                        const u8 *key, int key_len, int key_idx)
409 {
410         int err;
411
412         wdev_lock(dev->ieee80211_ptr);
413         err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
414                                    ssid, ssid_len, ie, ie_len,
415                                    key, key_len, key_idx);
416         wdev_unlock(dev->ieee80211_ptr);
417
418         return err;
419 }
420
421 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
422                           struct net_device *dev,
423                           struct ieee80211_channel *chan,
424                           const u8 *bssid, const u8 *prev_bssid,
425                           const u8 *ssid, int ssid_len,
426                           const u8 *ie, int ie_len, bool use_mfp,
427                           struct cfg80211_crypto_settings *crypt)
428 {
429         struct wireless_dev *wdev = dev->ieee80211_ptr;
430         struct cfg80211_assoc_request req;
431         struct cfg80211_internal_bss *bss;
432         int i, err, slot = -1;
433
434         ASSERT_WDEV_LOCK(wdev);
435
436         memset(&req, 0, sizeof(req));
437
438         if (wdev->current_bss)
439                 return -EALREADY;
440
441         req.ie = ie;
442         req.ie_len = ie_len;
443         memcpy(&req.crypto, crypt, sizeof(req.crypto));
444         req.use_mfp = use_mfp;
445         req.prev_bssid = prev_bssid;
446         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
447                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
448         if (!req.bss)
449                 return -ENOENT;
450
451         bss = bss_from_pub(req.bss);
452
453         for (i = 0; i < MAX_AUTH_BSSES; i++) {
454                 if (bss == wdev->auth_bsses[i]) {
455                         slot = i;
456                         break;
457                 }
458         }
459
460         if (slot < 0) {
461                 err = -ENOTCONN;
462                 goto out;
463         }
464
465         err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
466  out:
467         /* still a reference in wdev->auth_bsses[slot] */
468         cfg80211_put_bss(req.bss);
469         return err;
470 }
471
472 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
473                         struct net_device *dev,
474                         struct ieee80211_channel *chan,
475                         const u8 *bssid, const u8 *prev_bssid,
476                         const u8 *ssid, int ssid_len,
477                         const u8 *ie, int ie_len, bool use_mfp,
478                         struct cfg80211_crypto_settings *crypt)
479 {
480         struct wireless_dev *wdev = dev->ieee80211_ptr;
481         int err;
482
483         wdev_lock(wdev);
484         err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
485                                     ssid, ssid_len, ie, ie_len, use_mfp, crypt);
486         wdev_unlock(wdev);
487
488         return err;
489 }
490
491 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
492                            struct net_device *dev, const u8 *bssid,
493                            const u8 *ie, int ie_len, u16 reason)
494 {
495         struct wireless_dev *wdev = dev->ieee80211_ptr;
496         struct cfg80211_deauth_request req;
497         int i;
498
499         ASSERT_WDEV_LOCK(wdev);
500
501         memset(&req, 0, sizeof(req));
502         req.reason_code = reason;
503         req.ie = ie;
504         req.ie_len = ie_len;
505         if (wdev->current_bss &&
506             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
507                 req.bss = &wdev->current_bss->pub;
508         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
509                 if (wdev->auth_bsses[i] &&
510                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
511                         req.bss = &wdev->auth_bsses[i]->pub;
512                         break;
513                 }
514                 if (wdev->authtry_bsses[i] &&
515                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
516                         req.bss = &wdev->authtry_bsses[i]->pub;
517                         break;
518                 }
519         }
520
521         if (!req.bss)
522                 return -ENOTCONN;
523
524         return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
525 }
526
527 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
528                          struct net_device *dev, const u8 *bssid,
529                          const u8 *ie, int ie_len, u16 reason)
530 {
531         struct wireless_dev *wdev = dev->ieee80211_ptr;
532         int err;
533
534         wdev_lock(wdev);
535         err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
536         wdev_unlock(wdev);
537
538         return err;
539 }
540
541 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
542                                     struct net_device *dev, const u8 *bssid,
543                                     const u8 *ie, int ie_len, u16 reason)
544 {
545         struct wireless_dev *wdev = dev->ieee80211_ptr;
546         struct cfg80211_disassoc_request req;
547
548         ASSERT_WDEV_LOCK(wdev);
549
550         if (wdev->sme_state != CFG80211_SME_CONNECTED)
551                 return -ENOTCONN;
552
553         if (WARN_ON(!wdev->current_bss))
554                 return -ENOTCONN;
555
556         memset(&req, 0, sizeof(req));
557         req.reason_code = reason;
558         req.ie = ie;
559         req.ie_len = ie_len;
560         if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
561                 req.bss = &wdev->current_bss->pub;
562         else
563                 return -ENOTCONN;
564
565         return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
566 }
567
568 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
569                            struct net_device *dev, const u8 *bssid,
570                            const u8 *ie, int ie_len, u16 reason)
571 {
572         struct wireless_dev *wdev = dev->ieee80211_ptr;
573         int err;
574
575         wdev_lock(wdev);
576         err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
577         wdev_unlock(wdev);
578
579         return err;
580 }
581
582 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
583                         struct net_device *dev)
584 {
585         struct wireless_dev *wdev = dev->ieee80211_ptr;
586         struct cfg80211_deauth_request req;
587         int i;
588
589         ASSERT_WDEV_LOCK(wdev);
590
591         if (!rdev->ops->deauth)
592                 return;
593
594         memset(&req, 0, sizeof(req));
595         req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
596         req.ie = NULL;
597         req.ie_len = 0;
598
599         if (wdev->current_bss) {
600                 req.bss = &wdev->current_bss->pub;
601                 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
602                 if (wdev->current_bss) {
603                         cfg80211_unhold_bss(wdev->current_bss);
604                         cfg80211_put_bss(&wdev->current_bss->pub);
605                         wdev->current_bss = NULL;
606                 }
607         }
608
609         for (i = 0; i < MAX_AUTH_BSSES; i++) {
610                 if (wdev->auth_bsses[i]) {
611                         req.bss = &wdev->auth_bsses[i]->pub;
612                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
613                         if (wdev->auth_bsses[i]) {
614                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
615                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
616                                 wdev->auth_bsses[i] = NULL;
617                         }
618                 }
619                 if (wdev->authtry_bsses[i]) {
620                         req.bss = &wdev->authtry_bsses[i]->pub;
621                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
622                         if (wdev->authtry_bsses[i]) {
623                                 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
624                                 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
625                                 wdev->authtry_bsses[i] = NULL;
626                         }
627                 }
628         }
629 }