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