diff options
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r-- | net/wireless/mlme.c | 105 |
1 files changed, 56 insertions, 49 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 0a6b7a0eca6b..1001db4912f7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -62,7 +62,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
62 | u8 *ie = mgmt->u.assoc_resp.variable; | 62 | u8 *ie = mgmt->u.assoc_resp.variable; |
63 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 63 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
64 | struct cfg80211_internal_bss *bss = NULL; | 64 | struct cfg80211_internal_bss *bss = NULL; |
65 | bool need_connect_result = true; | ||
66 | 65 | ||
67 | wdev_lock(wdev); | 66 | wdev_lock(wdev); |
68 | 67 | ||
@@ -97,7 +96,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
97 | WARN_ON(!bss); | 96 | WARN_ON(!bss); |
98 | } else if (wdev->conn) { | 97 | } else if (wdev->conn) { |
99 | cfg80211_sme_failed_assoc(wdev); | 98 | cfg80211_sme_failed_assoc(wdev); |
100 | need_connect_result = false; | ||
101 | /* | 99 | /* |
102 | * do not call connect_result() now because the | 100 | * do not call connect_result() now because the |
103 | * sme will schedule work that does it later. | 101 | * sme will schedule work that does it later. |
@@ -130,7 +128,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
130 | } | 128 | } |
131 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 129 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
132 | 130 | ||
133 | static void __cfg80211_send_deauth(struct net_device *dev, | 131 | void __cfg80211_send_deauth(struct net_device *dev, |
134 | const u8 *buf, size_t len) | 132 | const u8 *buf, size_t len) |
135 | { | 133 | { |
136 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 134 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -139,7 +137,6 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
139 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 137 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
140 | const u8 *bssid = mgmt->bssid; | 138 | const u8 *bssid = mgmt->bssid; |
141 | int i; | 139 | int i; |
142 | bool done = false; | ||
143 | 140 | ||
144 | ASSERT_WDEV_LOCK(wdev); | 141 | ASSERT_WDEV_LOCK(wdev); |
145 | 142 | ||
@@ -147,7 +144,6 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
147 | 144 | ||
148 | if (wdev->current_bss && | 145 | if (wdev->current_bss && |
149 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { | 146 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { |
150 | done = true; | ||
151 | cfg80211_unhold_bss(wdev->current_bss); | 147 | cfg80211_unhold_bss(wdev->current_bss); |
152 | cfg80211_put_bss(&wdev->current_bss->pub); | 148 | cfg80211_put_bss(&wdev->current_bss->pub); |
153 | wdev->current_bss = NULL; | 149 | wdev->current_bss = NULL; |
@@ -157,7 +153,6 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
157 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | 153 | cfg80211_unhold_bss(wdev->auth_bsses[i]); |
158 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | 154 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); |
159 | wdev->auth_bsses[i] = NULL; | 155 | wdev->auth_bsses[i] = NULL; |
160 | done = true; | ||
161 | break; | 156 | break; |
162 | } | 157 | } |
163 | if (wdev->authtry_bsses[i] && | 158 | if (wdev->authtry_bsses[i] && |
@@ -165,13 +160,10 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
165 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | 160 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); |
166 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | 161 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); |
167 | wdev->authtry_bsses[i] = NULL; | 162 | wdev->authtry_bsses[i] = NULL; |
168 | done = true; | ||
169 | break; | 163 | break; |
170 | } | 164 | } |
171 | } | 165 | } |
172 | 166 | ||
173 | WARN_ON(!done); | ||
174 | |||
175 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | 167 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { |
176 | u16 reason_code; | 168 | u16 reason_code; |
177 | bool from_ap; | 169 | bool from_ap; |
@@ -186,27 +178,19 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
186 | false, NULL); | 178 | false, NULL); |
187 | } | 179 | } |
188 | } | 180 | } |
181 | EXPORT_SYMBOL(__cfg80211_send_deauth); | ||
189 | 182 | ||
190 | 183 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) | |
191 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, | ||
192 | void *cookie) | ||
193 | { | 184 | { |
194 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 185 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
195 | 186 | ||
196 | BUG_ON(cookie && wdev != cookie); | 187 | wdev_lock(wdev); |
197 | 188 | __cfg80211_send_deauth(dev, buf, len); | |
198 | if (cookie) { | 189 | wdev_unlock(wdev); |
199 | /* called within callback */ | ||
200 | __cfg80211_send_deauth(dev, buf, len); | ||
201 | } else { | ||
202 | wdev_lock(wdev); | ||
203 | __cfg80211_send_deauth(dev, buf, len); | ||
204 | wdev_unlock(wdev); | ||
205 | } | ||
206 | } | 190 | } |
207 | EXPORT_SYMBOL(cfg80211_send_deauth); | 191 | EXPORT_SYMBOL(cfg80211_send_deauth); |
208 | 192 | ||
209 | static void __cfg80211_send_disassoc(struct net_device *dev, | 193 | void __cfg80211_send_disassoc(struct net_device *dev, |
210 | const u8 *buf, size_t len) | 194 | const u8 *buf, size_t len) |
211 | { | 195 | { |
212 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 196 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -247,40 +231,24 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
247 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; | 231 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
248 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 232 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
249 | } | 233 | } |
234 | EXPORT_SYMBOL(__cfg80211_send_disassoc); | ||
250 | 235 | ||
251 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, | 236 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) |
252 | void *cookie) | ||
253 | { | 237 | { |
254 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 238 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
255 | 239 | ||
256 | BUG_ON(cookie && wdev != cookie); | 240 | wdev_lock(wdev); |
257 | 241 | __cfg80211_send_disassoc(dev, buf, len); | |
258 | if (cookie) { | 242 | wdev_unlock(wdev); |
259 | /* called within callback */ | ||
260 | __cfg80211_send_disassoc(dev, buf, len); | ||
261 | } else { | ||
262 | wdev_lock(wdev); | ||
263 | __cfg80211_send_disassoc(dev, buf, len); | ||
264 | wdev_unlock(wdev); | ||
265 | } | ||
266 | } | 243 | } |
267 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 244 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
268 | 245 | ||
269 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | 246 | static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) |
270 | { | 247 | { |
271 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
272 | struct wiphy *wiphy = wdev->wiphy; | ||
273 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
274 | int i; | 248 | int i; |
275 | bool done = false; | 249 | bool done = false; |
276 | 250 | ||
277 | wdev_lock(wdev); | 251 | ASSERT_WDEV_LOCK(wdev); |
278 | |||
279 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | ||
280 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | ||
281 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
282 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
283 | false, NULL); | ||
284 | 252 | ||
285 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 253 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
286 | if (wdev->authtry_bsses[i] && | 254 | if (wdev->authtry_bsses[i] && |
@@ -295,6 +263,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
295 | } | 263 | } |
296 | 264 | ||
297 | WARN_ON(!done); | 265 | WARN_ON(!done); |
266 | } | ||
267 | |||
268 | void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr) | ||
269 | { | ||
270 | __cfg80211_auth_remove(dev->ieee80211_ptr, addr); | ||
271 | } | ||
272 | EXPORT_SYMBOL(__cfg80211_auth_canceled); | ||
273 | |||
274 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | ||
275 | { | ||
276 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
277 | struct wiphy *wiphy = wdev->wiphy; | ||
278 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
279 | |||
280 | wdev_lock(wdev); | ||
281 | |||
282 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | ||
283 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | ||
284 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
285 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
286 | false, NULL); | ||
287 | |||
288 | __cfg80211_auth_remove(wdev, addr); | ||
298 | 289 | ||
299 | wdev_unlock(wdev); | 290 | wdev_unlock(wdev); |
300 | } | 291 | } |
@@ -340,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | |||
340 | { | 331 | { |
341 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 332 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
342 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 333 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
343 | #ifdef CONFIG_WIRELESS_EXT | 334 | #ifdef CONFIG_CFG80211_WEXT |
344 | union iwreq_data wrqu; | 335 | union iwreq_data wrqu; |
345 | char *buf = kmalloc(128, gfp); | 336 | char *buf = kmalloc(128, gfp); |
346 | 337 | ||
@@ -469,12 +460,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
469 | struct cfg80211_assoc_request req; | 460 | struct cfg80211_assoc_request req; |
470 | struct cfg80211_internal_bss *bss; | 461 | struct cfg80211_internal_bss *bss; |
471 | int i, err, slot = -1; | 462 | int i, err, slot = -1; |
463 | bool was_connected = false; | ||
472 | 464 | ||
473 | ASSERT_WDEV_LOCK(wdev); | 465 | ASSERT_WDEV_LOCK(wdev); |
474 | 466 | ||
475 | memset(&req, 0, sizeof(req)); | 467 | memset(&req, 0, sizeof(req)); |
476 | 468 | ||
477 | if (wdev->current_bss) | 469 | if (wdev->current_bss && prev_bssid && |
470 | memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) { | ||
471 | /* | ||
472 | * Trying to reassociate: Allow this to proceed and let the old | ||
473 | * association to be dropped when the new one is completed. | ||
474 | */ | ||
475 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | ||
476 | was_connected = true; | ||
477 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
478 | } | ||
479 | } else if (wdev->current_bss) | ||
478 | return -EALREADY; | 480 | return -EALREADY; |
479 | 481 | ||
480 | req.ie = ie; | 482 | req.ie = ie; |
@@ -484,8 +486,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
484 | req.prev_bssid = prev_bssid; | 486 | req.prev_bssid = prev_bssid; |
485 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 487 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
486 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 488 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
487 | if (!req.bss) | 489 | if (!req.bss) { |
490 | if (was_connected) | ||
491 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
488 | return -ENOENT; | 492 | return -ENOENT; |
493 | } | ||
489 | 494 | ||
490 | bss = bss_from_pub(req.bss); | 495 | bss = bss_from_pub(req.bss); |
491 | 496 | ||
@@ -503,6 +508,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
503 | 508 | ||
504 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | 509 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); |
505 | out: | 510 | out: |
511 | if (err && was_connected) | ||
512 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
506 | /* still a reference in wdev->auth_bsses[slot] */ | 513 | /* still a reference in wdev->auth_bsses[slot] */ |
507 | cfg80211_put_bss(req.bss); | 514 | cfg80211_put_bss(req.bss); |
508 | return err; | 515 | return err; |