diff options
-rw-r--r-- | include/net/cfg80211.h | 4 | ||||
-rw-r--r-- | net/wireless/core.h | 4 | ||||
-rw-r--r-- | net/wireless/mlme.c | 11 | ||||
-rw-r--r-- | net/wireless/sme.c | 54 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 8 |
5 files changed, 65 insertions, 16 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 64df51d9a89f..1ee30fcd6fdc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1335,10 +1335,10 @@ struct wireless_dev { | |||
1335 | struct cfg80211_cached_keys *keys; | 1335 | struct cfg80211_cached_keys *keys; |
1336 | u8 *ie; | 1336 | u8 *ie; |
1337 | size_t ie_len; | 1337 | size_t ie_len; |
1338 | u8 bssid[ETH_ALEN]; | 1338 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
1339 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 1339 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
1340 | s8 default_key, default_mgmt_key; | 1340 | s8 default_key, default_mgmt_key; |
1341 | bool ps; | 1341 | bool ps, prev_bssid_valid; |
1342 | int ps_timeout; | 1342 | int ps_timeout; |
1343 | } wext; | 1343 | } wext; |
1344 | #endif | 1344 | #endif |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5696b95af9be..92e0492b0e4d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -335,7 +335,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
336 | struct net_device *dev, | 336 | struct net_device *dev, |
337 | struct cfg80211_connect_params *connect, | 337 | struct cfg80211_connect_params *connect, |
338 | struct cfg80211_cached_keys *connkeys); | 338 | struct cfg80211_cached_keys *connkeys, |
339 | const u8 *prev_bssid); | ||
339 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 340 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, | 341 | struct net_device *dev, |
341 | struct cfg80211_connect_params *connect, | 342 | struct cfg80211_connect_params *connect, |
@@ -353,6 +354,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
353 | struct wireless_dev *wdev); | 354 | struct wireless_dev *wdev); |
354 | 355 | ||
355 | void cfg80211_conn_work(struct work_struct *work); | 356 | void cfg80211_conn_work(struct work_struct *work); |
357 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | ||
356 | 358 | ||
357 | /* internal helpers */ | 359 | /* internal helpers */ |
358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 360 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 51d5df67c632..da64071ceb84 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -67,6 +67,16 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
67 | 67 | ||
68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
69 | 69 | ||
70 | /* | ||
71 | * This is a bit of a hack, we don't notify userspace of | ||
72 | * a (re-)association reply if we tried to send a reassoc | ||
73 | * and got a reject -- we only try again with an assoc | ||
74 | * frame instead of reassoc. | ||
75 | */ | ||
76 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | ||
77 | cfg80211_sme_failed_reassoc(wdev)) | ||
78 | goto out; | ||
79 | |||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 80 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 81 | ||
72 | if (status_code == WLAN_STATUS_SUCCESS) { | 82 | if (status_code == WLAN_STATUS_SUCCESS) { |
@@ -97,6 +107,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
97 | cfg80211_put_bss(&bss->pub); | 107 | cfg80211_put_bss(&bss->pub); |
98 | } | 108 | } |
99 | 109 | ||
110 | out: | ||
100 | wdev_unlock(wdev); | 111 | wdev_unlock(wdev); |
101 | } | 112 | } |
102 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 113 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 219c3bc2c37d..104b33e34d22 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 | ||
@@ -110,6 +110,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
110 | { | 110 | { |
111 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 111 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
112 | struct cfg80211_connect_params *params; | 112 | struct cfg80211_connect_params *params; |
113 | const u8 *prev_bssid = NULL; | ||
113 | int err; | 114 | int err; |
114 | 115 | ||
115 | ASSERT_WDEV_LOCK(wdev); | 116 | ASSERT_WDEV_LOCK(wdev); |
@@ -135,15 +136,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
135 | case CFG80211_CONN_ASSOCIATE_NEXT: | 136 | case CFG80211_CONN_ASSOCIATE_NEXT: |
136 | BUG_ON(!rdev->ops->assoc); | 137 | BUG_ON(!rdev->ops->assoc); |
137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 138 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
138 | /* | 139 | if (wdev->conn->prev_bssid_valid) |
139 | * We could, later, implement roaming here and then actually | 140 | 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, | 141 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, |
145 | params->channel, params->bssid, | 142 | params->channel, params->bssid, |
146 | NULL, | 143 | prev_bssid, |
147 | params->ssid, params->ssid_len, | 144 | params->ssid, params->ssid_len, |
148 | params->ie, params->ie_len, | 145 | params->ie, params->ie_len, |
149 | false, ¶ms->crypto); | 146 | false, ¶ms->crypto); |
@@ -316,6 +313,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
316 | } | 313 | } |
317 | } | 314 | } |
318 | 315 | ||
316 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | ||
317 | { | ||
318 | struct wiphy *wiphy = wdev->wiphy; | ||
319 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
320 | |||
321 | if (WARN_ON(!wdev->conn)) | ||
322 | return false; | ||
323 | |||
324 | if (!wdev->conn->prev_bssid_valid) | ||
325 | return false; | ||
326 | |||
327 | /* | ||
328 | * Some stupid APs don't accept reassoc, so we | ||
329 | * need to fall back to trying regular assoc. | ||
330 | */ | ||
331 | wdev->conn->prev_bssid_valid = false; | ||
332 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
333 | schedule_work(&rdev->conn_work); | ||
334 | |||
335 | return true; | ||
336 | } | ||
337 | |||
319 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 338 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
320 | const u8 *req_ie, size_t req_ie_len, | 339 | const u8 *req_ie, size_t req_ie_len, |
321 | const u8 *resp_ie, size_t resp_ie_len, | 340 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -359,8 +378,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
359 | 378 | ||
360 | memset(&wrqu, 0, sizeof(wrqu)); | 379 | memset(&wrqu, 0, sizeof(wrqu)); |
361 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 380 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
362 | if (bssid && status == WLAN_STATUS_SUCCESS) | 381 | if (bssid && status == WLAN_STATUS_SUCCESS) { |
363 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 382 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
383 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
384 | wdev->wext.prev_bssid_valid = true; | ||
385 | } | ||
364 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 386 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
365 | } | 387 | } |
366 | #endif | 388 | #endif |
@@ -511,6 +533,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
511 | memset(&wrqu, 0, sizeof(wrqu)); | 533 | memset(&wrqu, 0, sizeof(wrqu)); |
512 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 534 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
513 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 535 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
536 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
537 | wdev->wext.prev_bssid_valid = true; | ||
514 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); | 538 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
515 | #endif | 539 | #endif |
516 | } | 540 | } |
@@ -643,7 +667,8 @@ EXPORT_SYMBOL(cfg80211_disconnected); | |||
643 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 667 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
644 | struct net_device *dev, | 668 | struct net_device *dev, |
645 | struct cfg80211_connect_params *connect, | 669 | struct cfg80211_connect_params *connect, |
646 | struct cfg80211_cached_keys *connkeys) | 670 | struct cfg80211_cached_keys *connkeys, |
671 | const u8 *prev_bssid) | ||
647 | { | 672 | { |
648 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 673 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
649 | struct ieee80211_channel *chan; | 674 | struct ieee80211_channel *chan; |
@@ -742,6 +767,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
742 | wdev->sme_state = CFG80211_SME_CONNECTING; | 767 | wdev->sme_state = CFG80211_SME_CONNECTING; |
743 | wdev->connect_keys = connkeys; | 768 | wdev->connect_keys = connkeys; |
744 | 769 | ||
770 | if (prev_bssid) { | ||
771 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
772 | wdev->conn->prev_bssid_valid = true; | ||
773 | } | ||
774 | |||
745 | /* we're good if we have both BSSID and channel */ | 775 | /* we're good if we have both BSSID and channel */ |
746 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { | 776 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { |
747 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 777 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
@@ -794,7 +824,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
794 | 824 | ||
795 | mutex_lock(&rdev->devlist_mtx); | 825 | mutex_lock(&rdev->devlist_mtx); |
796 | wdev_lock(dev->ieee80211_ptr); | 826 | wdev_lock(dev->ieee80211_ptr); |
797 | err = __cfg80211_connect(rdev, dev, connect, connkeys); | 827 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); |
798 | wdev_unlock(dev->ieee80211_ptr); | 828 | wdev_unlock(dev->ieee80211_ptr); |
799 | mutex_unlock(&rdev->devlist_mtx); | 829 | mutex_unlock(&rdev->devlist_mtx); |
800 | 830 | ||
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fe1a53639122..907470063f22 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -15,6 +15,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
15 | struct wireless_dev *wdev) | 15 | struct wireless_dev *wdev) |
16 | { | 16 | { |
17 | struct cfg80211_cached_keys *ck = NULL; | 17 | struct cfg80211_cached_keys *ck = NULL; |
18 | const u8 *prev_bssid = NULL; | ||
18 | int err, i; | 19 | int err, i; |
19 | 20 | ||
20 | ASSERT_RDEV_LOCK(rdev); | 21 | ASSERT_RDEV_LOCK(rdev); |
@@ -42,8 +43,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
42 | for (i = 0; i < 6; i++) | 43 | for (i = 0; i < 6; i++) |
43 | ck->params[i].key = ck->data[i]; | 44 | ck->params[i].key = ck->data[i]; |
44 | } | 45 | } |
46 | |||
47 | if (wdev->wext.prev_bssid_valid) | ||
48 | prev_bssid = wdev->wext.prev_bssid; | ||
49 | |||
45 | err = __cfg80211_connect(rdev, wdev->netdev, | 50 | err = __cfg80211_connect(rdev, wdev->netdev, |
46 | &wdev->wext.connect, ck); | 51 | &wdev->wext.connect, ck, prev_bssid); |
47 | if (err) | 52 | if (err) |
48 | kfree(ck); | 53 | kfree(ck); |
49 | 54 | ||
@@ -184,6 +189,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
184 | goto out; | 189 | goto out; |
185 | } | 190 | } |
186 | 191 | ||
192 | wdev->wext.prev_bssid_valid = false; | ||
187 | wdev->wext.connect.ssid = wdev->wext.ssid; | 193 | wdev->wext.connect.ssid = wdev->wext.ssid; |
188 | memcpy(wdev->wext.ssid, ssid, len); | 194 | memcpy(wdev->wext.ssid, ssid, len); |
189 | wdev->wext.connect.ssid_len = len; | 195 | wdev->wext.connect.ssid_len = len; |