aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-07 08:51:05 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:43 -0400
commitf401a6f7ede753e56b84025e7d2db0d5ef560ce6 (patch)
tree12b077096234ba0f990c637665d11e0afa608b17 /net
parent59bbb6f7574bc693ed8313b98eac641116c95b94 (diff)
cfg80211: use reassociation when possible
With the move of everything related to the SME from mac80211 to cfg80211, we lost the ability to send reassociation frames. This adds them back, but only for wireless extensions. With the userspace SME, it shall control assoc vs. reassoc (it already can do so with the nl80211 interface). I haven't touched the connect() implementation, so it is not possible to reassociate with the nl80211 connect primitive. I think that should be done with the NL80211_CMD_ROAM command, but we'll have to see how that can be handled in the future, especially with fullmac chips. This patch addresses only the immediate regression we had in mac80211, which previously sent reassoc. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-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
4 files changed, 63 insertions, 14 deletions
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;