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