aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h4
-rw-r--r--net/wireless/core.h4
-rw-r--r--net/wireless/mlme.c11
-rw-r--r--net/wireless/sme.c54
-rw-r--r--net/wireless/wext-sme.c8
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,
335int __cfg80211_connect(struct cfg80211_registered_device *rdev, 335int __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);
339int cfg80211_connect(struct cfg80211_registered_device *rdev, 340int 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
355void cfg80211_conn_work(struct work_struct *work); 356void cfg80211_conn_work(struct work_struct *work);
357bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
356 358
357/* internal helpers */ 359/* internal helpers */
358int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, 360int 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}
102EXPORT_SYMBOL(cfg80211_send_rx_assoc); 113EXPORT_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, &params->crypto); 146 false, &params->crypto);
@@ -316,6 +313,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
316 } 313 }
317} 314}
318 315
316bool 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
319void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 338void __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);
643int __cfg80211_connect(struct cfg80211_registered_device *rdev, 667int __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;