xref: /linux/net/wireless/mlme.c (revision dfc349402de8e95f6a42e8341e9ea193b718eee3)
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 }
669