diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-02 11:20:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:01:53 -0400 |
commit | 19957bb399e2722719c0e20c9ae91cf8b6aaff04 (patch) | |
tree | 9c4d53fe5938ceee41333a1afd5be0ed5c1ce313 /net/wireless/sme.c | |
parent | 517357c685ccc4b5783cc7dbdae8824ada19a97f (diff) |
cfg80211: keep track of BSSes
In order to avoid problems with BSS structs going away
while they're in use, I've long wanted to make cfg80211
keep track of them. Without the SME, that wasn't doable
but now that we have the SME we can do this too. It can
keep track of up to four separate authentications and
one association, regardless of whether it's controlled
by the cfg80211 SME or the userspace SME.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
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 | } | ||