sme.c revision a9a11622c5c742c115fad371c0397ae86dd3bb67
1/* 2 * SME code for cfg80211's connect emulation. 3 * 4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 5 * Copyright (C) 2009 Intel Corporation. All rights reserved. 6 */ 7 8#include <linux/etherdevice.h> 9#include <linux/if_arp.h> 10#include <linux/workqueue.h> 11#include <linux/wireless.h> 12#include <net/iw_handler.h> 13#include <net/cfg80211.h> 14#include <net/rtnetlink.h> 15#include "nl80211.h" 16 17struct cfg80211_conn { 18 struct cfg80211_connect_params params; 19 /* these are sub-states of the _CONNECTING sme_state */ 20 enum { 21 CFG80211_CONN_IDLE, 22 CFG80211_CONN_SCANNING, 23 CFG80211_CONN_SCAN_AGAIN, 24 CFG80211_CONN_AUTHENTICATE_NEXT, 25 CFG80211_CONN_AUTHENTICATING, 26 CFG80211_CONN_ASSOCIATE_NEXT, 27 CFG80211_CONN_ASSOCIATING, 28 } state; 29 u8 bssid[ETH_ALEN]; 30 u8 *ie; 31 size_t ie_len; 32 bool auto_auth; 33}; 34 35 36static int cfg80211_conn_scan(struct wireless_dev *wdev) 37{ 38 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 39 struct cfg80211_scan_request *request; 40 int n_channels, err; 41 42 ASSERT_RTNL(); 43 ASSERT_RDEV_LOCK(rdev); 44 ASSERT_WDEV_LOCK(wdev); 45 46 if (rdev->scan_req) 47 return -EBUSY; 48 49 if (wdev->conn->params.channel) { 50 n_channels = 1; 51 } else { 52 enum ieee80211_band band; 53 n_channels = 0; 54 55 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 56 if (!wdev->wiphy->bands[band]) 57 continue; 58 n_channels += wdev->wiphy->bands[band]->n_channels; 59 } 60 } 61 request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + 62 sizeof(request->channels[0]) * n_channels, 63 GFP_KERNEL); 64 if (!request) 65 return -ENOMEM; 66 67 request->channels = (void *)((char *)request + sizeof(*request)); 68 if (wdev->conn->params.channel) 69 request->channels[0] = wdev->conn->params.channel; 70 else { 71 int i = 0, j; 72 enum ieee80211_band band; 73 74 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 75 if (!wdev->wiphy->bands[band]) 76 continue; 77 for (j = 0; j < wdev->wiphy->bands[band]->n_channels; 78 i++, j++) 79 request->channels[i] = 80 &wdev->wiphy->bands[band]->channels[j]; 81 } 82 } 83 request->n_channels = n_channels; 84 request->ssids = (void *)(request->channels + n_channels); 85 request->n_ssids = 1; 86 87 memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, 88 wdev->conn->params.ssid_len); 89 request->ssids[0].ssid_len = wdev->conn->params.ssid_len; 90 91 request->dev = wdev->netdev; 92 request->wiphy = &rdev->wiphy; 93 94 rdev->scan_req = request; 95 96 err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); 97 if (!err) { 98 wdev->conn->state = CFG80211_CONN_SCANNING; 99 nl80211_send_scan_start(rdev, wdev->netdev); 100 dev_hold(wdev->netdev); 101 } else { 102 rdev->scan_req = NULL; 103 kfree(request); 104 } 105 return err; 106} 107 108static int cfg80211_conn_do_work(struct wireless_dev *wdev) 109{ 110 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 111 struct cfg80211_connect_params *params; 112 int err; 113 114 ASSERT_WDEV_LOCK(wdev); 115 116 if (!wdev->conn) 117 return 0; 118 119 params = &wdev->conn->params; 120 121 switch (wdev->conn->state) { 122 case CFG80211_CONN_SCAN_AGAIN: 123 return cfg80211_conn_scan(wdev); 124 case CFG80211_CONN_AUTHENTICATE_NEXT: 125 BUG_ON(!rdev->ops->auth); 126 wdev->conn->state = CFG80211_CONN_AUTHENTICATING; 127 return __cfg80211_mlme_auth(rdev, wdev->netdev, 128 params->channel, params->auth_type, 129 params->bssid, 130 params->ssid, params->ssid_len, 131 NULL, 0, 132 params->key, params->key_len, 133 params->key_idx); 134 case CFG80211_CONN_ASSOCIATE_NEXT: 135 BUG_ON(!rdev->ops->assoc); 136 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 137 /* 138 * We could, later, implement roaming here and then actually 139 * set prev_bssid to non-NULL. But then we need to be aware 140 * that some APs don't like that -- so we'd need to retry 141 * the association. 142 */ 143 err = __cfg80211_mlme_assoc(rdev, wdev->netdev, 144 params->channel, params->bssid, 145 NULL, 146 params->ssid, params->ssid_len, 147 params->ie, params->ie_len, 148 false, ¶ms->crypto); 149 if (err) 150 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 151 NULL, 0, 152 WLAN_REASON_DEAUTH_LEAVING); 153 return err; 154 default: 155 return 0; 156 } 157} 158 159void cfg80211_conn_work(struct work_struct *work) 160{ 161 struct cfg80211_registered_device *rdev = 162 container_of(work, struct cfg80211_registered_device, conn_work); 163 struct wireless_dev *wdev; 164 165 rtnl_lock(); 166 cfg80211_lock_rdev(rdev); 167 mutex_lock(&rdev->devlist_mtx); 168 169 list_for_each_entry(wdev, &rdev->netdev_list, list) { 170 wdev_lock(wdev); 171 if (!netif_running(wdev->netdev)) { 172 wdev_unlock(wdev); 173 continue; 174 } 175 if (wdev->sme_state != CFG80211_SME_CONNECTING) { 176 wdev_unlock(wdev); 177 continue; 178 } 179 if (cfg80211_conn_do_work(wdev)) 180 __cfg80211_connect_result( 181 wdev->netdev, 182 wdev->conn->params.bssid, 183 NULL, 0, NULL, 0, 184 WLAN_STATUS_UNSPECIFIED_FAILURE, 185 false); 186 wdev_unlock(wdev); 187 } 188 189 mutex_unlock(&rdev->devlist_mtx); 190 cfg80211_unlock_rdev(rdev); 191 rtnl_unlock(); 192} 193 194static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) 195{ 196 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 197 struct cfg80211_bss *bss; 198 u16 capa = WLAN_CAPABILITY_ESS; 199 200 ASSERT_WDEV_LOCK(wdev); 201 202 if (wdev->conn->params.privacy) 203 capa |= WLAN_CAPABILITY_PRIVACY; 204 205 bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid, 206 wdev->conn->params.ssid, 207 wdev->conn->params.ssid_len, 208 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, 209 capa); 210 if (!bss) 211 return false; 212 213 memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN); 214 wdev->conn->params.bssid = wdev->conn->bssid; 215 wdev->conn->params.channel = bss->channel; 216 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 217 schedule_work(&rdev->conn_work); 218 219 cfg80211_put_bss(bss); 220 return true; 221} 222 223static void __cfg80211_sme_scan_done(struct net_device *dev) 224{ 225 struct wireless_dev *wdev = dev->ieee80211_ptr; 226 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 227 228 ASSERT_WDEV_LOCK(wdev); 229 230 if (wdev->sme_state != CFG80211_SME_CONNECTING) 231 return; 232 233 if (!wdev->conn) 234 return; 235 236 if (wdev->conn->state != CFG80211_CONN_SCANNING && 237 wdev->conn->state != CFG80211_CONN_SCAN_AGAIN) 238 return; 239 240 if (!cfg80211_get_conn_bss(wdev)) { 241 /* not found */ 242 if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) 243 schedule_work(&rdev->conn_work); 244 else 245 __cfg80211_connect_result( 246 wdev->netdev, 247 wdev->conn->params.bssid, 248 NULL, 0, NULL, 0, 249 WLAN_STATUS_UNSPECIFIED_FAILURE, 250 false); 251 } 252} 253 254void cfg80211_sme_scan_done(struct net_device *dev) 255{ 256 struct wireless_dev *wdev = dev->ieee80211_ptr; 257 258 wdev_lock(wdev); 259 __cfg80211_sme_scan_done(dev); 260 wdev_unlock(wdev); 261} 262 263void cfg80211_sme_rx_auth(struct net_device *dev, 264 const u8 *buf, size_t len) 265{ 266 struct wireless_dev *wdev = dev->ieee80211_ptr; 267 struct wiphy *wiphy = wdev->wiphy; 268 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 269 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 270 u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); 271 272 ASSERT_WDEV_LOCK(wdev); 273 274 /* should only RX auth frames when connecting */ 275 if (wdev->sme_state != CFG80211_SME_CONNECTING) 276 return; 277 278 if (WARN_ON(!wdev->conn)) 279 return; 280 281 if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && 282 wdev->conn->auto_auth && 283 wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) { 284 /* select automatically between only open, shared, leap */ 285 switch (wdev->conn->params.auth_type) { 286 case NL80211_AUTHTYPE_OPEN_SYSTEM: 287 if (wdev->connect_keys) 288 wdev->conn->params.auth_type = 289 NL80211_AUTHTYPE_SHARED_KEY; 290 else 291 wdev->conn->params.auth_type = 292 NL80211_AUTHTYPE_NETWORK_EAP; 293 break; 294 case NL80211_AUTHTYPE_SHARED_KEY: 295 wdev->conn->params.auth_type = 296 NL80211_AUTHTYPE_NETWORK_EAP; 297 break; 298 default: 299 /* huh? */ 300 wdev->conn->params.auth_type = 301 NL80211_AUTHTYPE_OPEN_SYSTEM; 302 break; 303 } 304 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 305 schedule_work(&rdev->conn_work); 306 } else if (status_code != WLAN_STATUS_SUCCESS) { 307 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, 308 status_code, false); 309 } else if (wdev->sme_state == CFG80211_SME_CONNECTING && 310 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { 311 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; 312 schedule_work(&rdev->conn_work); 313 } 314} 315 316void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 317 const u8 *req_ie, size_t req_ie_len, 318 const u8 *resp_ie, size_t resp_ie_len, 319 u16 status, bool wextev) 320{ 321 struct wireless_dev *wdev = dev->ieee80211_ptr; 322 struct cfg80211_bss *bss; 323#ifdef CONFIG_WIRELESS_EXT 324 union iwreq_data wrqu; 325#endif 326 327 ASSERT_WDEV_LOCK(wdev); 328 329 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 330 return; 331 332 if (wdev->sme_state == CFG80211_SME_CONNECTED) 333 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, 334 bssid, req_ie, req_ie_len, 335 resp_ie, resp_ie_len, GFP_KERNEL); 336 else 337 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, 338 bssid, req_ie, req_ie_len, 339 resp_ie, resp_ie_len, 340 status, GFP_KERNEL); 341 342#ifdef CONFIG_WIRELESS_EXT 343 if (wextev) { 344 if (req_ie && status == WLAN_STATUS_SUCCESS) { 345 memset(&wrqu, 0, sizeof(wrqu)); 346 wrqu.data.length = req_ie_len; 347 wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie); 348 } 349 350 if (resp_ie && status == WLAN_STATUS_SUCCESS) { 351 memset(&wrqu, 0, sizeof(wrqu)); 352 wrqu.data.length = resp_ie_len; 353 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); 354 } 355 356 memset(&wrqu, 0, sizeof(wrqu)); 357 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 358 if (bssid && status == WLAN_STATUS_SUCCESS) 359 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 360 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 361 } 362#endif 363 364 if (status == WLAN_STATUS_SUCCESS && 365 wdev->sme_state == CFG80211_SME_IDLE) 366 goto success; 367 368 if (wdev->sme_state != CFG80211_SME_CONNECTING) 369 return; 370 371 if (wdev->current_bss) { 372 cfg80211_unhold_bss(wdev->current_bss); 373 cfg80211_put_bss(&wdev->current_bss->pub); 374 wdev->current_bss = NULL; 375 } 376 377 if (wdev->conn) 378 wdev->conn->state = CFG80211_CONN_IDLE; 379 380 if (status != WLAN_STATUS_SUCCESS) { 381 wdev->sme_state = CFG80211_SME_IDLE; 382 kfree(wdev->conn); 383 wdev->conn = NULL; 384 kfree(wdev->connect_keys); 385 wdev->connect_keys = NULL; 386 return; 387 } 388 389 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, 390 wdev->ssid, wdev->ssid_len, 391 WLAN_CAPABILITY_ESS, 392 WLAN_CAPABILITY_ESS); 393 394 if (WARN_ON(!bss)) 395 return; 396 397 cfg80211_hold_bss(bss_from_pub(bss)); 398 wdev->current_bss = bss_from_pub(bss); 399 400 success: 401 wdev->sme_state = CFG80211_SME_CONNECTED; 402 cfg80211_upload_connect_keys(wdev); 403} 404 405void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 406 const u8 *req_ie, size_t req_ie_len, 407 const u8 *resp_ie, size_t resp_ie_len, 408 u16 status, gfp_t gfp) 409{ 410 struct wireless_dev *wdev = dev->ieee80211_ptr; 411 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 412 struct cfg80211_event *ev; 413 unsigned long flags; 414 415 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); 416 if (!ev) 417 return; 418 419 ev->type = EVENT_CONNECT_RESULT; 420 memcpy(ev->cr.bssid, bssid, ETH_ALEN); 421 ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); 422 ev->cr.req_ie_len = req_ie_len; 423 memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); 424 ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; 425 ev->cr.resp_ie_len = resp_ie_len; 426 memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); 427 ev->cr.status = status; 428 429 spin_lock_irqsave(&wdev->event_lock, flags); 430 list_add_tail(&ev->list, &wdev->event_list); 431 spin_unlock_irqrestore(&wdev->event_lock, flags); 432 schedule_work(&rdev->event_work); 433} 434EXPORT_SYMBOL(cfg80211_connect_result); 435 436void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, 437 const u8 *req_ie, size_t req_ie_len, 438 const u8 *resp_ie, size_t resp_ie_len) 439{ 440 struct cfg80211_bss *bss; 441#ifdef CONFIG_WIRELESS_EXT 442 union iwreq_data wrqu; 443#endif 444 445 ASSERT_WDEV_LOCK(wdev); 446 447 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 448 return; 449 450 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) 451 return; 452 453 /* internal error -- how did we get to CONNECTED w/o BSS? */ 454 if (WARN_ON(!wdev->current_bss)) { 455 return; 456 } 457 458 cfg80211_unhold_bss(wdev->current_bss); 459 cfg80211_put_bss(&wdev->current_bss->pub); 460 wdev->current_bss = NULL; 461 462 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, 463 wdev->ssid, wdev->ssid_len, 464 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 465 466 if (WARN_ON(!bss)) 467 return; 468 469 cfg80211_hold_bss(bss_from_pub(bss)); 470 wdev->current_bss = bss_from_pub(bss); 471 472 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid, 473 req_ie, req_ie_len, resp_ie, resp_ie_len, 474 GFP_KERNEL); 475 476#ifdef CONFIG_WIRELESS_EXT 477 if (req_ie) { 478 memset(&wrqu, 0, sizeof(wrqu)); 479 wrqu.data.length = req_ie_len; 480 wireless_send_event(wdev->netdev, IWEVASSOCREQIE, 481 &wrqu, req_ie); 482 } 483 484 if (resp_ie) { 485 memset(&wrqu, 0, sizeof(wrqu)); 486 wrqu.data.length = resp_ie_len; 487 wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, 488 &wrqu, resp_ie); 489 } 490 491 memset(&wrqu, 0, sizeof(wrqu)); 492 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 493 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 494 wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); 495#endif 496} 497 498void cfg80211_roamed(struct net_device *dev, const u8 *bssid, 499 const u8 *req_ie, size_t req_ie_len, 500 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) 501{ 502 struct wireless_dev *wdev = dev->ieee80211_ptr; 503 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 504 struct cfg80211_event *ev; 505 unsigned long flags; 506 507 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); 508 if (!ev) 509 return; 510 511 ev->type = EVENT_ROAMED; 512 memcpy(ev->rm.bssid, bssid, ETH_ALEN); 513 ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev); 514 ev->rm.req_ie_len = req_ie_len; 515 memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len); 516 ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; 517 ev->rm.resp_ie_len = resp_ie_len; 518 memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len); 519 520 spin_lock_irqsave(&wdev->event_lock, flags); 521 list_add_tail(&ev->list, &wdev->event_list); 522 spin_unlock_irqrestore(&wdev->event_lock, flags); 523 schedule_work(&rdev->event_work); 524} 525EXPORT_SYMBOL(cfg80211_roamed); 526 527void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, 528 size_t ie_len, u16 reason, bool from_ap) 529{ 530 struct wireless_dev *wdev = dev->ieee80211_ptr; 531 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 532 int i; 533#ifdef CONFIG_WIRELESS_EXT 534 union iwreq_data wrqu; 535#endif 536 537 ASSERT_WDEV_LOCK(wdev); 538 539 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 540 return; 541 542 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) 543 return; 544 545 if (wdev->current_bss) { 546 cfg80211_unhold_bss(wdev->current_bss); 547 cfg80211_put_bss(&wdev->current_bss->pub); 548 } 549 550 wdev->current_bss = NULL; 551 wdev->sme_state = CFG80211_SME_IDLE; 552 553 if (wdev->conn) { 554 kfree(wdev->conn->ie); 555 wdev->conn->ie = NULL; 556 kfree(wdev->conn); 557 wdev->conn = NULL; 558 } 559 560 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); 561 562 /* 563 * Delete all the keys ... pairwise keys can't really 564 * exist any more anyway, but default keys might. 565 */ 566 if (rdev->ops->del_key) 567 for (i = 0; i < 6; i++) 568 rdev->ops->del_key(wdev->wiphy, dev, i, NULL); 569 570#ifdef CONFIG_WIRELESS_EXT 571 memset(&wrqu, 0, sizeof(wrqu)); 572 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 573 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 574#endif 575} 576 577void cfg80211_disconnected(struct net_device *dev, u16 reason, 578 u8 *ie, size_t ie_len, gfp_t gfp) 579{ 580 struct wireless_dev *wdev = dev->ieee80211_ptr; 581 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 582 struct cfg80211_event *ev; 583 unsigned long flags; 584 585 ev = kzalloc(sizeof(*ev) + ie_len, gfp); 586 if (!ev) 587 return; 588 589 ev->type = EVENT_DISCONNECTED; 590 ev->dc.ie = ((u8 *)ev) + sizeof(*ev); 591 ev->dc.ie_len = ie_len; 592 memcpy((void *)ev->dc.ie, ie, ie_len); 593 ev->dc.reason = reason; 594 595 spin_lock_irqsave(&wdev->event_lock, flags); 596 list_add_tail(&ev->list, &wdev->event_list); 597 spin_unlock_irqrestore(&wdev->event_lock, flags); 598 schedule_work(&rdev->event_work); 599} 600EXPORT_SYMBOL(cfg80211_disconnected); 601 602int __cfg80211_connect(struct cfg80211_registered_device *rdev, 603 struct net_device *dev, 604 struct cfg80211_connect_params *connect, 605 struct cfg80211_cached_keys *connkeys) 606{ 607 struct wireless_dev *wdev = dev->ieee80211_ptr; 608 int err; 609 610 ASSERT_WDEV_LOCK(wdev); 611 612 if (wdev->sme_state != CFG80211_SME_IDLE) 613 return -EALREADY; 614 615 if (WARN_ON(wdev->connect_keys)) { 616 kfree(wdev->connect_keys); 617 wdev->connect_keys = NULL; 618 } 619 620 if (connkeys && connkeys->def >= 0) { 621 int idx; 622 623 idx = connkeys->def; 624 /* If given a WEP key we may need it for shared key auth */ 625 if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || 626 connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { 627 connect->key_idx = idx; 628 connect->key = connkeys->params[idx].key; 629 connect->key_len = connkeys->params[idx].key_len; 630 } 631 } 632 633 if (!rdev->ops->connect) { 634 if (!rdev->ops->auth || !rdev->ops->assoc) 635 return -EOPNOTSUPP; 636 637 if (WARN_ON(wdev->conn)) 638 return -EINPROGRESS; 639 640 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); 641 if (!wdev->conn) 642 return -ENOMEM; 643 644 /* 645 * Copy all parameters, and treat explicitly IEs, BSSID, SSID. 646 */ 647 memcpy(&wdev->conn->params, connect, sizeof(*connect)); 648 if (connect->bssid) { 649 wdev->conn->params.bssid = wdev->conn->bssid; 650 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); 651 } 652 653 if (connect->ie) { 654 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, 655 GFP_KERNEL); 656 wdev->conn->params.ie = wdev->conn->ie; 657 if (!wdev->conn->ie) { 658 kfree(wdev->conn); 659 wdev->conn = NULL; 660 return -ENOMEM; 661 } 662 } 663 664 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { 665 wdev->conn->auto_auth = true; 666 /* start with open system ... should mostly work */ 667 wdev->conn->params.auth_type = 668 NL80211_AUTHTYPE_OPEN_SYSTEM; 669 } else { 670 wdev->conn->auto_auth = false; 671 } 672 673 memcpy(wdev->ssid, connect->ssid, connect->ssid_len); 674 wdev->ssid_len = connect->ssid_len; 675 wdev->conn->params.ssid = wdev->ssid; 676 wdev->conn->params.ssid_len = connect->ssid_len; 677 678 /* don't care about result -- but fill bssid & channel */ 679 if (!wdev->conn->params.bssid || !wdev->conn->params.channel) 680 cfg80211_get_conn_bss(wdev); 681 682 wdev->sme_state = CFG80211_SME_CONNECTING; 683 wdev->connect_keys = connkeys; 684 685 /* we're good if we have both BSSID and channel */ 686 if (wdev->conn->params.bssid && wdev->conn->params.channel) { 687 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 688 err = cfg80211_conn_do_work(wdev); 689 } else { 690 /* otherwise we'll need to scan for the AP first */ 691 err = cfg80211_conn_scan(wdev); 692 /* 693 * If we can't scan right now, then we need to scan again 694 * after the current scan finished, since the parameters 695 * changed (unless we find a good AP anyway). 696 */ 697 if (err == -EBUSY) { 698 err = 0; 699 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; 700 } 701 } 702 if (err) { 703 kfree(wdev->conn); 704 wdev->conn = NULL; 705 wdev->sme_state = CFG80211_SME_IDLE; 706 wdev->connect_keys = NULL; 707 } 708 709 return err; 710 } else { 711 wdev->sme_state = CFG80211_SME_CONNECTING; 712 wdev->connect_keys = connkeys; 713 err = rdev->ops->connect(&rdev->wiphy, dev, connect); 714 if (err) { 715 wdev->connect_keys = NULL; 716 wdev->sme_state = CFG80211_SME_IDLE; 717 return err; 718 } 719 720 memcpy(wdev->ssid, connect->ssid, connect->ssid_len); 721 wdev->ssid_len = connect->ssid_len; 722 723 return 0; 724 } 725} 726 727int cfg80211_connect(struct cfg80211_registered_device *rdev, 728 struct net_device *dev, 729 struct cfg80211_connect_params *connect, 730 struct cfg80211_cached_keys *connkeys) 731{ 732 int err; 733 734 wdev_lock(dev->ieee80211_ptr); 735 err = __cfg80211_connect(rdev, dev, connect, connkeys); 736 wdev_unlock(dev->ieee80211_ptr); 737 738 return err; 739} 740 741int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, 742 struct net_device *dev, u16 reason, bool wextev) 743{ 744 struct wireless_dev *wdev = dev->ieee80211_ptr; 745 int err; 746 747 ASSERT_WDEV_LOCK(wdev); 748 749 if (wdev->sme_state == CFG80211_SME_IDLE) 750 return -EINVAL; 751 752 kfree(wdev->connect_keys); 753 wdev->connect_keys = NULL; 754 755 if (!rdev->ops->disconnect) { 756 if (!rdev->ops->deauth) 757 return -EOPNOTSUPP; 758 759 /* was it connected by userspace SME? */ 760 if (!wdev->conn) { 761 cfg80211_mlme_down(rdev, dev); 762 return 0; 763 } 764 765 if (wdev->sme_state == CFG80211_SME_CONNECTING && 766 (wdev->conn->state == CFG80211_CONN_SCANNING || 767 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { 768 wdev->sme_state = CFG80211_SME_IDLE; 769 kfree(wdev->conn); 770 wdev->conn = NULL; 771 return 0; 772 } 773 774 /* wdev->conn->params.bssid must be set if > SCANNING */ 775 err = __cfg80211_mlme_deauth(rdev, dev, 776 wdev->conn->params.bssid, 777 NULL, 0, reason); 778 if (err) 779 return err; 780 } else { 781 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); 782 if (err) 783 return err; 784 } 785 786 if (wdev->sme_state == CFG80211_SME_CONNECTED) 787 __cfg80211_disconnected(dev, NULL, 0, 0, false); 788 else if (wdev->sme_state == CFG80211_SME_CONNECTING) 789 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, 790 WLAN_STATUS_UNSPECIFIED_FAILURE, 791 wextev); 792 793 return 0; 794} 795 796int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 797 struct net_device *dev, 798 u16 reason, bool wextev) 799{ 800 int err; 801 802 wdev_lock(dev->ieee80211_ptr); 803 err = __cfg80211_disconnect(rdev, dev, reason, wextev); 804 wdev_unlock(dev->ieee80211_ptr); 805 806 return err; 807} 808 809void cfg80211_sme_disassoc(struct net_device *dev, int idx) 810{ 811 struct wireless_dev *wdev = dev->ieee80211_ptr; 812 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 813 u8 bssid[ETH_ALEN]; 814 815 ASSERT_WDEV_LOCK(wdev); 816 817 if (!wdev->conn) 818 return; 819 820 if (wdev->conn->state == CFG80211_CONN_IDLE) 821 return; 822 823 /* 824 * Ok, so the association was made by this SME -- we don't 825 * want it any more so deauthenticate too. 826 */ 827 828 if (!wdev->auth_bsses[idx]) 829 return; 830 831 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); 832 if (__cfg80211_mlme_deauth(rdev, dev, bssid, 833 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { 834 /* whatever -- assume gone anyway */ 835 cfg80211_unhold_bss(wdev->auth_bsses[idx]); 836 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); 837 wdev->auth_bsses[idx] = NULL; 838 } 839} 840