aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r--net/wireless/sme.c104
1 files changed, 88 insertions, 16 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 8a7dcbf90602..8e2ef54ea714 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -27,10 +27,10 @@ struct cfg80211_conn {
27 CFG80211_CONN_ASSOCIATE_NEXT, 27 CFG80211_CONN_ASSOCIATE_NEXT,
28 CFG80211_CONN_ASSOCIATING, 28 CFG80211_CONN_ASSOCIATING,
29 } state; 29 } state;
30 u8 bssid[ETH_ALEN]; 30 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
31 u8 *ie; 31 u8 *ie;
32 size_t ie_len; 32 size_t ie_len;
33 bool auto_auth; 33 bool auto_auth, prev_bssid_valid;
34}; 34};
35 35
36 36
@@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
65 if (!request) 65 if (!request)
66 return -ENOMEM; 66 return -ENOMEM;
67 67
68 request->channels = (void *)((char *)request + sizeof(*request));
69 if (wdev->conn->params.channel) 68 if (wdev->conn->params.channel)
70 request->channels[0] = wdev->conn->params.channel; 69 request->channels[0] = wdev->conn->params.channel;
71 else { 70 else {
@@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
82 } 81 }
83 } 82 }
84 request->n_channels = n_channels; 83 request->n_channels = n_channels;
85 request->ssids = (void *)(request->channels + n_channels); 84 request->ssids = (void *)&request->channels[n_channels];
86 request->n_ssids = 1; 85 request->n_ssids = 1;
87 86
88 memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, 87 memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
@@ -110,6 +109,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
110{ 109{
111 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 110 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
112 struct cfg80211_connect_params *params; 111 struct cfg80211_connect_params *params;
112 const u8 *prev_bssid = NULL;
113 int err; 113 int err;
114 114
115 ASSERT_WDEV_LOCK(wdev); 115 ASSERT_WDEV_LOCK(wdev);
@@ -135,15 +135,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
135 case CFG80211_CONN_ASSOCIATE_NEXT: 135 case CFG80211_CONN_ASSOCIATE_NEXT:
136 BUG_ON(!rdev->ops->assoc); 136 BUG_ON(!rdev->ops->assoc);
137 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 137 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
138 /* 138 if (wdev->conn->prev_bssid_valid)
139 * We could, later, implement roaming here and then actually 139 prev_bssid = wdev->conn->prev_bssid;
140 * set prev_bssid to non-NULL. But then we need to be aware
141 * that some APs don't like that -- so we'd need to retry
142 * the association.
143 */
144 err = __cfg80211_mlme_assoc(rdev, wdev->netdev, 140 err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
145 params->channel, params->bssid, 141 params->channel, params->bssid,
146 NULL, 142 prev_bssid,
147 params->ssid, params->ssid_len, 143 params->ssid, params->ssid_len,
148 params->ie, params->ie_len, 144 params->ie, params->ie_len,
149 false, &params->crypto); 145 false, &params->crypto);
@@ -256,9 +252,11 @@ void cfg80211_sme_scan_done(struct net_device *dev)
256{ 252{
257 struct wireless_dev *wdev = dev->ieee80211_ptr; 253 struct wireless_dev *wdev = dev->ieee80211_ptr;
258 254
255 mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
259 wdev_lock(wdev); 256 wdev_lock(wdev);
260 __cfg80211_sme_scan_done(dev); 257 __cfg80211_sme_scan_done(dev);
261 wdev_unlock(wdev); 258 wdev_unlock(wdev);
259 mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
262} 260}
263 261
264void cfg80211_sme_rx_auth(struct net_device *dev, 262void cfg80211_sme_rx_auth(struct net_device *dev,
@@ -314,6 +312,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
314 } 312 }
315} 313}
316 314
315bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
316{
317 struct wiphy *wiphy = wdev->wiphy;
318 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
319
320 if (WARN_ON(!wdev->conn))
321 return false;
322
323 if (!wdev->conn->prev_bssid_valid)
324 return false;
325
326 /*
327 * Some stupid APs don't accept reassoc, so we
328 * need to fall back to trying regular assoc.
329 */
330 wdev->conn->prev_bssid_valid = false;
331 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
332 schedule_work(&rdev->conn_work);
333
334 return true;
335}
336
317void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 337void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
318 const u8 *req_ie, size_t req_ie_len, 338 const u8 *req_ie, size_t req_ie_len,
319 const u8 *resp_ie, size_t resp_ie_len, 339 const u8 *resp_ie, size_t resp_ie_len,
@@ -357,8 +377,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
357 377
358 memset(&wrqu, 0, sizeof(wrqu)); 378 memset(&wrqu, 0, sizeof(wrqu));
359 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 379 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
360 if (bssid && status == WLAN_STATUS_SUCCESS) 380 if (bssid && status == WLAN_STATUS_SUCCESS) {
361 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 381 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
382 memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
383 wdev->wext.prev_bssid_valid = true;
384 }
362 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 385 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
363 } 386 }
364#endif 387#endif
@@ -509,6 +532,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
509 memset(&wrqu, 0, sizeof(wrqu)); 532 memset(&wrqu, 0, sizeof(wrqu));
510 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 533 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
511 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 534 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
535 memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
536 wdev->wext.prev_bssid_valid = true;
512 wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); 537 wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
513#endif 538#endif
514} 539}
@@ -570,10 +595,30 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
570 wdev->ssid_len = 0; 595 wdev->ssid_len = 0;
571 596
572 if (wdev->conn) { 597 if (wdev->conn) {
598 const u8 *bssid;
599 int ret;
600
573 kfree(wdev->conn->ie); 601 kfree(wdev->conn->ie);
574 wdev->conn->ie = NULL; 602 wdev->conn->ie = NULL;
575 kfree(wdev->conn); 603 kfree(wdev->conn);
576 wdev->conn = NULL; 604 wdev->conn = NULL;
605
606 /*
607 * If this disconnect was due to a disassoc, we
608 * we might still have an auth BSS around. For
609 * the userspace SME that's currently expected,
610 * but for the kernel SME (nl80211 CONNECT or
611 * wireless extensions) we want to clear up all
612 * state.
613 */
614 for (i = 0; i < MAX_AUTH_BSSES; i++) {
615 if (!wdev->auth_bsses[i])
616 continue;
617 bssid = wdev->auth_bsses[i]->pub.bssid;
618 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
619 WLAN_REASON_DEAUTH_LEAVING);
620 WARN(ret, "deauth failed: %d\n", ret);
621 }
577 } 622 }
578 623
579 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); 624 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
@@ -621,9 +666,11 @@ EXPORT_SYMBOL(cfg80211_disconnected);
621int __cfg80211_connect(struct cfg80211_registered_device *rdev, 666int __cfg80211_connect(struct cfg80211_registered_device *rdev,
622 struct net_device *dev, 667 struct net_device *dev,
623 struct cfg80211_connect_params *connect, 668 struct cfg80211_connect_params *connect,
624 struct cfg80211_cached_keys *connkeys) 669 struct cfg80211_cached_keys *connkeys,
670 const u8 *prev_bssid)
625{ 671{
626 struct wireless_dev *wdev = dev->ieee80211_ptr; 672 struct wireless_dev *wdev = dev->ieee80211_ptr;
673 struct ieee80211_channel *chan;
627 int err; 674 int err;
628 675
629 ASSERT_WDEV_LOCK(wdev); 676 ASSERT_WDEV_LOCK(wdev);
@@ -631,6 +678,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
631 if (wdev->sme_state != CFG80211_SME_IDLE) 678 if (wdev->sme_state != CFG80211_SME_IDLE)
632 return -EALREADY; 679 return -EALREADY;
633 680
681 chan = rdev_fixed_channel(rdev, wdev);
682 if (chan && chan != connect->channel)
683 return -EBUSY;
684
634 if (WARN_ON(wdev->connect_keys)) { 685 if (WARN_ON(wdev->connect_keys)) {
635 kfree(wdev->connect_keys); 686 kfree(wdev->connect_keys);
636 wdev->connect_keys = NULL; 687 wdev->connect_keys = NULL;
@@ -638,14 +689,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
638 689
639 if (connkeys && connkeys->def >= 0) { 690 if (connkeys && connkeys->def >= 0) {
640 int idx; 691 int idx;
692 u32 cipher;
641 693
642 idx = connkeys->def; 694 idx = connkeys->def;
695 cipher = connkeys->params[idx].cipher;
643 /* If given a WEP key we may need it for shared key auth */ 696 /* If given a WEP key we may need it for shared key auth */
644 if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || 697 if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
645 connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { 698 cipher == WLAN_CIPHER_SUITE_WEP104) {
646 connect->key_idx = idx; 699 connect->key_idx = idx;
647 connect->key = connkeys->params[idx].key; 700 connect->key = connkeys->params[idx].key;
648 connect->key_len = connkeys->params[idx].key_len; 701 connect->key_len = connkeys->params[idx].key_len;
702
703 /*
704 * If ciphers are not set (e.g. when going through
705 * iwconfig), we have to set them appropriately here.
706 */
707 if (connect->crypto.cipher_group == 0)
708 connect->crypto.cipher_group = cipher;
709
710 if (connect->crypto.n_ciphers_pairwise == 0) {
711 connect->crypto.n_ciphers_pairwise = 1;
712 connect->crypto.ciphers_pairwise[0] = cipher;
713 }
649 } 714 }
650 } 715 }
651 716
@@ -701,6 +766,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
701 wdev->sme_state = CFG80211_SME_CONNECTING; 766 wdev->sme_state = CFG80211_SME_CONNECTING;
702 wdev->connect_keys = connkeys; 767 wdev->connect_keys = connkeys;
703 768
769 if (prev_bssid) {
770 memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
771 wdev->conn->prev_bssid_valid = true;
772 }
773
704 /* we're good if we have both BSSID and channel */ 774 /* we're good if we have both BSSID and channel */
705 if (wdev->conn->params.bssid && wdev->conn->params.channel) { 775 if (wdev->conn->params.bssid && wdev->conn->params.channel) {
706 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 776 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
@@ -751,9 +821,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
751{ 821{
752 int err; 822 int err;
753 823
824 mutex_lock(&rdev->devlist_mtx);
754 wdev_lock(dev->ieee80211_ptr); 825 wdev_lock(dev->ieee80211_ptr);
755 err = __cfg80211_connect(rdev, dev, connect, connkeys); 826 err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
756 wdev_unlock(dev->ieee80211_ptr); 827 wdev_unlock(dev->ieee80211_ptr);
828 mutex_unlock(&rdev->devlist_mtx);
757 829
758 return err; 830 return err;
759} 831}