aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-02 11:20:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:53 -0400
commit19957bb399e2722719c0e20c9ae91cf8b6aaff04 (patch)
tree9c4d53fe5938ceee41333a1afd5be0ed5c1ce313 /net/wireless/sme.c
parent517357c685ccc4b5783cc7dbdae8824ada19a97f (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.c156
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)
103static int cfg80211_conn_do_work(struct wireless_dev *wdev) 103static 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, &params->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
358void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 354void 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
618void 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}