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