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