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