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