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 } 98 99 if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { 100 /* 101 * This is for the userspace SME, the CONNECTING 102 * state will be changed to CONNECTED by 103 * __cfg80211_connect_result() below. 104 */ 105 wdev->sme_state = CFG80211_SME_CONNECTING; 106 } 107 108 /* this consumes one bss reference (unless bss is NULL) */ 109 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, 110 status_code, 111 status_code == WLAN_STATUS_SUCCESS, 112 bss ? &bss->pub : NULL); 113 /* drop hold now, and also reference acquired above */ 114 if (bss) { 115 cfg80211_unhold_bss(bss); 116 cfg80211_put_bss(&bss->pub); 117 } 118 119 out: 120 wdev_unlock(wdev); 121 } 122 EXPORT_SYMBOL(cfg80211_send_rx_assoc); 123 124 static void __cfg80211_send_deauth(struct net_device *dev, 125 const u8 *buf, size_t len) 126 { 127 struct wireless_dev *wdev = dev->ieee80211_ptr; 128 struct wiphy *wiphy = wdev->wiphy; 129 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 130 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 131 const u8 *bssid = mgmt->bssid; 132 int i; 133 bool done = false; 134 135 ASSERT_WDEV_LOCK(wdev); 136 137 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); 138 139 if (wdev->current_bss && 140 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 141 done = true; 142 cfg80211_unhold_bss(wdev->current_bss); 143 cfg80211_put_bss(&wdev->current_bss->pub); 144 wdev->current_bss = NULL; 145 } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 146 if (wdev->auth_bsses[i] && 147 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 148 cfg80211_unhold_bss(wdev->auth_bsses[i]); 149 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 150 wdev->auth_bsses[i] = NULL; 151 done = true; 152 break; 153 } 154 if (wdev->authtry_bsses[i] && 155 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 156 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 157 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 158 wdev->authtry_bsses[i] = NULL; 159 done = true; 160 break; 161 } 162 } 163 164 WARN_ON(!done); 165 166 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 167 u16 reason_code; 168 bool from_ap; 169 170 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); 171 172 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; 173 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 174 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { 175 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, 176 WLAN_STATUS_UNSPECIFIED_FAILURE, 177 false, NULL); 178 } 179 } 180 181 182 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, 183 void *cookie) 184 { 185 struct wireless_dev *wdev = dev->ieee80211_ptr; 186 187 BUG_ON(cookie && wdev != cookie); 188 189 if (cookie) { 190 /* called within callback */ 191 __cfg80211_send_deauth(dev, buf, len); 192 } else { 193 wdev_lock(wdev); 194 __cfg80211_send_deauth(dev, buf, len); 195 wdev_unlock(wdev); 196 } 197 } 198 EXPORT_SYMBOL(cfg80211_send_deauth); 199 200 static void __cfg80211_send_disassoc(struct net_device *dev, 201 const u8 *buf, size_t len) 202 { 203 struct wireless_dev *wdev = dev->ieee80211_ptr; 204 struct wiphy *wiphy = wdev->wiphy; 205 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 206 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 207 const u8 *bssid = mgmt->bssid; 208 int i; 209 u16 reason_code; 210 bool from_ap; 211 bool done = false; 212 213 ASSERT_WDEV_LOCK(wdev); 214 215 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); 216 217 if (wdev->sme_state != CFG80211_SME_CONNECTED) 218 return; 219 220 if (wdev->current_bss && 221 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 222 for (i = 0; i < MAX_AUTH_BSSES; i++) { 223 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) 224 continue; 225 wdev->auth_bsses[i] = wdev->current_bss; 226 wdev->current_bss = NULL; 227 done = true; 228 cfg80211_sme_disassoc(dev, i); 229 break; 230 } 231 WARN_ON(!done); 232 } else 233 WARN_ON(1); 234 235 236 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); 237 238 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; 239 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 240 } 241 242 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, 243 void *cookie) 244 { 245 struct wireless_dev *wdev = dev->ieee80211_ptr; 246 247 BUG_ON(cookie && wdev != cookie); 248 249 if (cookie) { 250 /* called within callback */ 251 __cfg80211_send_disassoc(dev, buf, len); 252 } else { 253 wdev_lock(wdev); 254 __cfg80211_send_disassoc(dev, buf, len); 255 wdev_unlock(wdev); 256 } 257 } 258 EXPORT_SYMBOL(cfg80211_send_disassoc); 259 260 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 261 { 262 struct wireless_dev *wdev = dev->ieee80211_ptr; 263 struct wiphy *wiphy = wdev->wiphy; 264 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 265 int i; 266 bool done = false; 267 268 wdev_lock(wdev); 269 270 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); 271 if (wdev->sme_state == CFG80211_SME_CONNECTING) 272 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, 273 WLAN_STATUS_UNSPECIFIED_FAILURE, 274 false, NULL); 275 276 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 277 if (wdev->authtry_bsses[i] && 278 memcmp(wdev->authtry_bsses[i]->pub.bssid, 279 addr, ETH_ALEN) == 0) { 280 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 281 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 282 wdev->authtry_bsses[i] = NULL; 283 done = true; 284 break; 285 } 286 } 287 288 WARN_ON(!done); 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_WIRELESS_EXT 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 464 ASSERT_WDEV_LOCK(wdev); 465 466 memset(&req, 0, sizeof(req)); 467 468 if (wdev->current_bss) 469 return -EALREADY; 470 471 req.ie = ie; 472 req.ie_len = ie_len; 473 memcpy(&req.crypto, crypt, sizeof(req.crypto)); 474 req.use_mfp = use_mfp; 475 req.prev_bssid = prev_bssid; 476 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 477 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 478 if (!req.bss) 479 return -ENOENT; 480 481 bss = bss_from_pub(req.bss); 482 483 for (i = 0; i < MAX_AUTH_BSSES; i++) { 484 if (bss == wdev->auth_bsses[i]) { 485 slot = i; 486 break; 487 } 488 } 489 490 if (slot < 0) { 491 err = -ENOTCONN; 492 goto out; 493 } 494 495 err = rdev->ops->assoc(&rdev->wiphy, dev, &req); 496 out: 497 /* still a reference in wdev->auth_bsses[slot] */ 498 cfg80211_put_bss(req.bss); 499 return err; 500 } 501 502 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 503 struct net_device *dev, 504 struct ieee80211_channel *chan, 505 const u8 *bssid, const u8 *prev_bssid, 506 const u8 *ssid, int ssid_len, 507 const u8 *ie, int ie_len, bool use_mfp, 508 struct cfg80211_crypto_settings *crypt) 509 { 510 struct wireless_dev *wdev = dev->ieee80211_ptr; 511 int err; 512 513 wdev_lock(wdev); 514 err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, 515 ssid, ssid_len, ie, ie_len, use_mfp, crypt); 516 wdev_unlock(wdev); 517 518 return err; 519 } 520 521 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 522 struct net_device *dev, const u8 *bssid, 523 const u8 *ie, int ie_len, u16 reason) 524 { 525 struct wireless_dev *wdev = dev->ieee80211_ptr; 526 struct cfg80211_deauth_request req; 527 int i; 528 529 ASSERT_WDEV_LOCK(wdev); 530 531 memset(&req, 0, sizeof(req)); 532 req.reason_code = reason; 533 req.ie = ie; 534 req.ie_len = ie_len; 535 if (wdev->current_bss && 536 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 537 req.bss = &wdev->current_bss->pub; 538 } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 539 if (wdev->auth_bsses[i] && 540 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { 541 req.bss = &wdev->auth_bsses[i]->pub; 542 break; 543 } 544 if (wdev->authtry_bsses[i] && 545 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { 546 req.bss = &wdev->authtry_bsses[i]->pub; 547 break; 548 } 549 } 550 551 if (!req.bss) 552 return -ENOTCONN; 553 554 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 555 } 556 557 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 558 struct net_device *dev, const u8 *bssid, 559 const u8 *ie, int ie_len, u16 reason) 560 { 561 struct wireless_dev *wdev = dev->ieee80211_ptr; 562 int err; 563 564 wdev_lock(wdev); 565 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); 566 wdev_unlock(wdev); 567 568 return err; 569 } 570 571 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 572 struct net_device *dev, const u8 *bssid, 573 const u8 *ie, int ie_len, u16 reason) 574 { 575 struct wireless_dev *wdev = dev->ieee80211_ptr; 576 struct cfg80211_disassoc_request req; 577 578 ASSERT_WDEV_LOCK(wdev); 579 580 if (wdev->sme_state != CFG80211_SME_CONNECTED) 581 return -ENOTCONN; 582 583 if (WARN_ON(!wdev->current_bss)) 584 return -ENOTCONN; 585 586 memset(&req, 0, sizeof(req)); 587 req.reason_code = reason; 588 req.ie = ie; 589 req.ie_len = ie_len; 590 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) 591 req.bss = &wdev->current_bss->pub; 592 else 593 return -ENOTCONN; 594 595 return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev); 596 } 597 598 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 int err; 604 605 wdev_lock(wdev); 606 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); 607 wdev_unlock(wdev); 608 609 return err; 610 } 611 612 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 613 struct net_device *dev) 614 { 615 struct wireless_dev *wdev = dev->ieee80211_ptr; 616 struct cfg80211_deauth_request req; 617 int i; 618 619 ASSERT_WDEV_LOCK(wdev); 620 621 if (!rdev->ops->deauth) 622 return; 623 624 memset(&req, 0, sizeof(req)); 625 req.reason_code = WLAN_REASON_DEAUTH_LEAVING; 626 req.ie = NULL; 627 req.ie_len = 0; 628 629 if (wdev->current_bss) { 630 req.bss = &wdev->current_bss->pub; 631 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 632 if (wdev->current_bss) { 633 cfg80211_unhold_bss(wdev->current_bss); 634 cfg80211_put_bss(&wdev->current_bss->pub); 635 wdev->current_bss = NULL; 636 } 637 } 638 639 for (i = 0; i < MAX_AUTH_BSSES; i++) { 640 if (wdev->auth_bsses[i]) { 641 req.bss = &wdev->auth_bsses[i]->pub; 642 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 643 if (wdev->auth_bsses[i]) { 644 cfg80211_unhold_bss(wdev->auth_bsses[i]); 645 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 646 wdev->auth_bsses[i] = NULL; 647 } 648 } 649 if (wdev->authtry_bsses[i]) { 650 req.bss = &wdev->authtry_bsses[i]->pub; 651 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); 652 if (wdev->authtry_bsses[i]) { 653 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 654 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 655 wdev->authtry_bsses[i] = NULL; 656 } 657 } 658 } 659 } 660