diff options
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r-- | net/wireless/sme.c | 156 |
1 files changed, 93 insertions, 63 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d4e0b4065cbc..412161f7b08e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -103,44 +103,37 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
103 | static int cfg80211_conn_do_work(struct wireless_dev *wdev) | 103 | static int cfg80211_conn_do_work(struct wireless_dev *wdev) |
104 | { | 104 | { |
105 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); | 105 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); |
106 | union { | 106 | struct cfg80211_connect_params *params; |
107 | struct cfg80211_auth_request auth_req; | 107 | int err; |
108 | struct cfg80211_assoc_request assoc_req; | ||
109 | } u; | ||
110 | |||
111 | memset(&u, 0, sizeof(u)); | ||
112 | 108 | ||
113 | if (!wdev->conn) | 109 | if (!wdev->conn) |
114 | return 0; | 110 | return 0; |
115 | 111 | ||
112 | params = &wdev->conn->params; | ||
113 | |||
116 | switch (wdev->conn->state) { | 114 | switch (wdev->conn->state) { |
117 | case CFG80211_CONN_SCAN_AGAIN: | 115 | case CFG80211_CONN_SCAN_AGAIN: |
118 | return cfg80211_conn_scan(wdev); | 116 | return cfg80211_conn_scan(wdev); |
119 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 117 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
120 | u.auth_req.chan = wdev->conn->params.channel; | ||
121 | u.auth_req.peer_addr = wdev->conn->params.bssid; | ||
122 | u.auth_req.ssid = wdev->conn->params.ssid; | ||
123 | u.auth_req.ssid_len = wdev->conn->params.ssid_len; | ||
124 | u.auth_req.auth_type = wdev->conn->params.auth_type; | ||
125 | u.auth_req.ie = NULL; | ||
126 | u.auth_req.ie_len = 0; | ||
127 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; | ||
128 | BUG_ON(!drv->ops->auth); | 118 | BUG_ON(!drv->ops->auth); |
129 | return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); | 119 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; |
120 | return cfg80211_mlme_auth(drv, wdev->netdev, | ||
121 | params->channel, params->auth_type, | ||
122 | params->bssid, | ||
123 | params->ssid, params->ssid_len, | ||
124 | NULL, 0); | ||
130 | case CFG80211_CONN_ASSOCIATE_NEXT: | 125 | case CFG80211_CONN_ASSOCIATE_NEXT: |
131 | u.assoc_req.chan = wdev->conn->params.channel; | ||
132 | u.assoc_req.peer_addr = wdev->conn->params.bssid; | ||
133 | u.assoc_req.ssid = wdev->conn->params.ssid; | ||
134 | u.assoc_req.ssid_len = wdev->conn->params.ssid_len; | ||
135 | u.assoc_req.ie = wdev->conn->params.ie; | ||
136 | u.assoc_req.ie_len = wdev->conn->params.ie_len; | ||
137 | u.assoc_req.use_mfp = false; | ||
138 | memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto, | ||
139 | sizeof(u.assoc_req.crypto)); | ||
140 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | ||
141 | BUG_ON(!drv->ops->assoc); | 126 | BUG_ON(!drv->ops->assoc); |
142 | return drv->ops->assoc(wdev->wiphy, wdev->netdev, | 127 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
143 | &u.assoc_req); | 128 | err = cfg80211_mlme_assoc(drv, wdev->netdev, |
129 | params->channel, params->bssid, | ||
130 | params->ssid, params->ssid_len, | ||
131 | params->ie, params->ie_len, | ||
132 | false, ¶ms->crypto); | ||
133 | if (err) | ||
134 | cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, | ||
135 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING); | ||
136 | return err; | ||
144 | default: | 137 | default: |
145 | return 0; | 138 | return 0; |
146 | } | 139 | } |
@@ -186,7 +179,6 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
186 | wdev->conn->params.ssid_len, | 179 | wdev->conn->params.ssid_len, |
187 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | 180 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, |
188 | capa); | 181 | capa); |
189 | |||
190 | if (!bss) | 182 | if (!bss) |
191 | return false; | 183 | return false; |
192 | 184 | ||
@@ -264,9 +256,11 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
264 | } | 256 | } |
265 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 257 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
266 | schedule_work(&rdev->conn_work); | 258 | schedule_work(&rdev->conn_work); |
267 | } else if (status_code != WLAN_STATUS_SUCCESS) | 259 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
268 | wdev->sme_state = CFG80211_SME_IDLE; | 260 | wdev->sme_state = CFG80211_SME_IDLE; |
269 | else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 261 | kfree(wdev->conn); |
262 | wdev->conn = NULL; | ||
263 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | ||
270 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | 264 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
271 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 265 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
272 | schedule_work(&rdev->conn_work); | 266 | schedule_work(&rdev->conn_work); |
@@ -330,10 +324,13 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
330 | 324 | ||
331 | if (wdev->current_bss) { | 325 | if (wdev->current_bss) { |
332 | cfg80211_unhold_bss(wdev->current_bss); | 326 | cfg80211_unhold_bss(wdev->current_bss); |
333 | cfg80211_put_bss(wdev->current_bss); | 327 | cfg80211_put_bss(&wdev->current_bss->pub); |
334 | wdev->current_bss = NULL; | 328 | wdev->current_bss = NULL; |
335 | } | 329 | } |
336 | 330 | ||
331 | if (wdev->conn) | ||
332 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
333 | |||
337 | if (status == WLAN_STATUS_SUCCESS) { | 334 | if (status == WLAN_STATUS_SUCCESS) { |
338 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 335 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
339 | wdev->ssid, wdev->ssid_len, | 336 | wdev->ssid, wdev->ssid_len, |
@@ -343,16 +340,15 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
343 | if (WARN_ON(!bss)) | 340 | if (WARN_ON(!bss)) |
344 | return; | 341 | return; |
345 | 342 | ||
346 | cfg80211_hold_bss(bss); | 343 | cfg80211_hold_bss(bss_from_pub(bss)); |
347 | wdev->current_bss = bss; | 344 | wdev->current_bss = bss_from_pub(bss); |
348 | 345 | ||
349 | wdev->sme_state = CFG80211_SME_CONNECTED; | 346 | wdev->sme_state = CFG80211_SME_CONNECTED; |
350 | } else { | 347 | } else { |
351 | wdev->sme_state = CFG80211_SME_IDLE; | 348 | wdev->sme_state = CFG80211_SME_IDLE; |
349 | kfree(wdev->conn); | ||
350 | wdev->conn = NULL; | ||
352 | } | 351 | } |
353 | |||
354 | if (wdev->conn) | ||
355 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
356 | } | 352 | } |
357 | 353 | ||
358 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 354 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
@@ -387,7 +383,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
387 | } | 383 | } |
388 | 384 | ||
389 | cfg80211_unhold_bss(wdev->current_bss); | 385 | cfg80211_unhold_bss(wdev->current_bss); |
390 | cfg80211_put_bss(wdev->current_bss); | 386 | cfg80211_put_bss(&wdev->current_bss->pub); |
391 | wdev->current_bss = NULL; | 387 | wdev->current_bss = NULL; |
392 | 388 | ||
393 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 389 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
@@ -397,8 +393,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
397 | if (WARN_ON(!bss)) | 393 | if (WARN_ON(!bss)) |
398 | return; | 394 | return; |
399 | 395 | ||
400 | cfg80211_hold_bss(bss); | 396 | cfg80211_hold_bss(bss_from_pub(bss)); |
401 | wdev->current_bss = bss; | 397 | wdev->current_bss = bss_from_pub(bss); |
402 | 398 | ||
403 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, | 399 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, |
404 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); | 400 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); |
@@ -440,7 +436,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
440 | 436 | ||
441 | if (wdev->current_bss) { | 437 | if (wdev->current_bss) { |
442 | cfg80211_unhold_bss(wdev->current_bss); | 438 | cfg80211_unhold_bss(wdev->current_bss); |
443 | cfg80211_put_bss(wdev->current_bss); | 439 | cfg80211_put_bss(&wdev->current_bss->pub); |
444 | } | 440 | } |
445 | 441 | ||
446 | wdev->current_bss = NULL; | 442 | wdev->current_bss = NULL; |
@@ -449,6 +445,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
449 | if (wdev->conn) { | 445 | if (wdev->conn) { |
450 | kfree(wdev->conn->ie); | 446 | kfree(wdev->conn->ie); |
451 | wdev->conn->ie = NULL; | 447 | wdev->conn->ie = NULL; |
448 | kfree(wdev->conn); | ||
449 | wdev->conn = NULL; | ||
452 | } | 450 | } |
453 | 451 | ||
454 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | 452 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, |
@@ -482,12 +480,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
482 | if (!rdev->ops->auth || !rdev->ops->assoc) | 480 | if (!rdev->ops->auth || !rdev->ops->assoc) |
483 | return -EOPNOTSUPP; | 481 | return -EOPNOTSUPP; |
484 | 482 | ||
485 | if (!wdev->conn) { | 483 | if (WARN_ON(wdev->conn)) |
486 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | 484 | return -EINPROGRESS; |
487 | if (!wdev->conn) | 485 | |
488 | return -ENOMEM; | 486 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); |
489 | } else | 487 | if (!wdev->conn) |
490 | memset(wdev->conn, 0, sizeof(*wdev->conn)); | 488 | return -ENOMEM; |
491 | 489 | ||
492 | /* | 490 | /* |
493 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | 491 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. |
@@ -502,8 +500,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
502 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | 500 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, |
503 | GFP_KERNEL); | 501 | GFP_KERNEL); |
504 | wdev->conn->params.ie = wdev->conn->ie; | 502 | wdev->conn->params.ie = wdev->conn->ie; |
505 | if (!wdev->conn->ie) | 503 | if (!wdev->conn->ie) { |
504 | kfree(wdev->conn); | ||
505 | wdev->conn = NULL; | ||
506 | return -ENOMEM; | 506 | return -ENOMEM; |
507 | } | ||
507 | } | 508 | } |
508 | 509 | ||
509 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | 510 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { |
@@ -543,8 +544,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
543 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | 544 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; |
544 | } | 545 | } |
545 | } | 546 | } |
546 | if (err) | 547 | if (err) { |
548 | kfree(wdev->conn); | ||
549 | wdev->conn = NULL; | ||
547 | wdev->sme_state = CFG80211_SME_IDLE; | 550 | wdev->sme_state = CFG80211_SME_IDLE; |
551 | } | ||
548 | 552 | ||
549 | return err; | 553 | return err; |
550 | } else { | 554 | } else { |
@@ -572,31 +576,27 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
572 | return -EINVAL; | 576 | return -EINVAL; |
573 | 577 | ||
574 | if (!rdev->ops->disconnect) { | 578 | if (!rdev->ops->disconnect) { |
575 | struct cfg80211_deauth_request deauth; | 579 | if (!rdev->ops->deauth) |
576 | u8 bssid[ETH_ALEN]; | 580 | return -EOPNOTSUPP; |
577 | 581 | ||
578 | /* internal bug. */ | 582 | /* was it connected by userspace SME? */ |
579 | if (WARN_ON(!wdev->conn)) | 583 | if (!wdev->conn) { |
580 | return -EINVAL; | 584 | cfg80211_mlme_down(rdev, dev); |
585 | return 0; | ||
586 | } | ||
581 | 587 | ||
582 | if (wdev->sme_state == CFG80211_SME_CONNECTING && | 588 | if (wdev->sme_state == CFG80211_SME_CONNECTING && |
583 | (wdev->conn->state == CFG80211_CONN_SCANNING || | 589 | (wdev->conn->state == CFG80211_CONN_SCANNING || |
584 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { | 590 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { |
585 | wdev->sme_state = CFG80211_SME_IDLE; | 591 | wdev->sme_state = CFG80211_SME_IDLE; |
592 | kfree(wdev->conn); | ||
593 | wdev->conn = NULL; | ||
586 | return 0; | 594 | return 0; |
587 | } | 595 | } |
588 | 596 | ||
589 | if (!rdev->ops->deauth) | ||
590 | return -EOPNOTSUPP; | ||
591 | |||
592 | memset(&deauth, 0, sizeof(deauth)); | ||
593 | |||
594 | /* wdev->conn->params.bssid must be set if > SCANNING */ | 597 | /* wdev->conn->params.bssid must be set if > SCANNING */ |
595 | memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); | 598 | err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, |
596 | deauth.peer_addr = bssid; | 599 | NULL, 0, reason); |
597 | deauth.reason_code = reason; | ||
598 | |||
599 | err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth); | ||
600 | if (err) | 600 | if (err) |
601 | return err; | 601 | return err; |
602 | } else { | 602 | } else { |
@@ -614,3 +614,33 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
614 | 614 | ||
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | |||
618 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) | ||
619 | { | ||
620 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
621 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
622 | u8 bssid[ETH_ALEN]; | ||
623 | |||
624 | if (!wdev->conn) | ||
625 | return; | ||
626 | |||
627 | if (wdev->conn->state == CFG80211_CONN_IDLE) | ||
628 | return; | ||
629 | |||
630 | /* | ||
631 | * Ok, so the association was made by this SME -- we don't | ||
632 | * want it any more so deauthenticate too. | ||
633 | */ | ||
634 | |||
635 | if (!wdev->auth_bsses[idx]) | ||
636 | return; | ||
637 | |||
638 | memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); | ||
639 | if (cfg80211_mlme_deauth(rdev, dev, bssid, | ||
640 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { | ||
641 | /* whatever -- assume gone anyway */ | ||
642 | cfg80211_unhold_bss(wdev->auth_bsses[idx]); | ||
643 | cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); | ||
644 | wdev->auth_bsses[idx] = NULL; | ||
645 | } | ||
646 | } | ||