diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-29 05:23:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-04 16:43:24 -0400 |
commit | df7fc0f9735085bb617fff774bfd71465edb448c (patch) | |
tree | 2b47f3823a8aee6c13e86aa3dedc06bda9ebae38 /net/wireless | |
parent | 97af743207466ff8b477e14bfb7af0ba2c93375b (diff) |
cfg80211: keep track of current_bss for userspace SME
When a userspace SME is active, we're currently not
keeping track of the BSS properly for reporting the
current link and for internal use. Additionally, it
looks like there is a possible BSS leak in that the
BSS never gets removed from auth_bsses[]. To fix it,
pass the BSS struct to __cfg80211_connect_result in
this case.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 3 | ||||
-rw-r--r-- | net/wireless/core.h | 8 | ||||
-rw-r--r-- | net/wireless/mlme.c | 38 | ||||
-rw-r--r-- | net/wireless/sme.c | 35 |
4 files changed, 51 insertions, 33 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index f9fee65dc06a..755cdf1643c9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -314,7 +314,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) | |||
314 | ev->cr.req_ie, ev->cr.req_ie_len, | 314 | ev->cr.req_ie, ev->cr.req_ie_len, |
315 | ev->cr.resp_ie, ev->cr.resp_ie_len, | 315 | ev->cr.resp_ie, ev->cr.resp_ie_len, |
316 | ev->cr.status, | 316 | ev->cr.status, |
317 | ev->cr.status == WLAN_STATUS_SUCCESS); | 317 | ev->cr.status == WLAN_STATUS_SUCCESS, |
318 | NULL); | ||
318 | break; | 319 | break; |
319 | case EVENT_ROAMED: | 320 | case EVENT_ROAMED: |
320 | __cfg80211_roamed(wdev, ev->rm.bssid, | 321 | __cfg80211_roamed(wdev, ev->rm.bssid, |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 6d903c1d721d..325c17e6198c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -127,6 +127,11 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu | |||
127 | return container_of(pub, struct cfg80211_internal_bss, pub); | 127 | return container_of(pub, struct cfg80211_internal_bss, pub); |
128 | } | 128 | } |
129 | 129 | ||
130 | static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) | ||
131 | { | ||
132 | kref_get(&bss->ref); | ||
133 | } | ||
134 | |||
130 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | 135 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) |
131 | { | 136 | { |
132 | atomic_inc(&bss->hold); | 137 | atomic_inc(&bss->hold); |
@@ -323,7 +328,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
323 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 328 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
324 | const u8 *req_ie, size_t req_ie_len, | 329 | const u8 *req_ie, size_t req_ie_len, |
325 | const u8 *resp_ie, size_t resp_ie_len, | 330 | const u8 *resp_ie, size_t resp_ie_len, |
326 | u16 status, bool wextev); | 331 | u16 status, bool wextev, |
332 | struct cfg80211_bss *bss); | ||
327 | 333 | ||
328 | /* SME */ | 334 | /* SME */ |
329 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 097a87d7bae1..525e8e247b30 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -61,7 +61,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
61 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 61 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
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 | bool done; | 64 | struct cfg80211_internal_bss *bss = NULL; |
65 | 65 | ||
66 | wdev_lock(wdev); | 66 | wdev_lock(wdev); |
67 | 67 | ||
@@ -69,22 +69,32 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
69 | 69 | ||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 71 | ||
72 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | ||
73 | status_code, | ||
74 | status_code == WLAN_STATUS_SUCCESS); | ||
75 | |||
76 | if (status_code == WLAN_STATUS_SUCCESS) { | 72 | if (status_code == WLAN_STATUS_SUCCESS) { |
77 | for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { | 73 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
78 | if (wdev->auth_bsses[i] == wdev->current_bss) { | 74 | if (!wdev->auth_bsses[i]) |
79 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | 75 | continue; |
80 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | 76 | if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid, |
77 | ETH_ALEN) == 0) { | ||
78 | bss = wdev->auth_bsses[i]; | ||
81 | wdev->auth_bsses[i] = NULL; | 79 | wdev->auth_bsses[i] = NULL; |
82 | done = true; | 80 | /* additional reference to drop hold */ |
81 | cfg80211_ref_bss(bss); | ||
83 | break; | 82 | break; |
84 | } | 83 | } |
85 | } | 84 | } |
86 | 85 | ||
87 | WARN_ON(!done); | 86 | WARN_ON(!bss); |
87 | } | ||
88 | |||
89 | /* this consumes one bss reference (unless bss is NULL) */ | ||
90 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | ||
91 | status_code, | ||
92 | status_code == WLAN_STATUS_SUCCESS, | ||
93 | bss ? &bss->pub : NULL); | ||
94 | /* drop hold now, and also reference acquired above */ | ||
95 | if (bss) { | ||
96 | cfg80211_unhold_bss(bss); | ||
97 | cfg80211_put_bss(&bss->pub); | ||
88 | } | 98 | } |
89 | 99 | ||
90 | wdev_unlock(wdev); | 100 | wdev_unlock(wdev); |
@@ -144,7 +154,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
144 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 154 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
145 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 155 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
146 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 156 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
147 | false); | 157 | false, NULL); |
148 | } | 158 | } |
149 | } | 159 | } |
150 | 160 | ||
@@ -241,7 +251,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
241 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 251 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
242 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 252 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
243 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 253 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
244 | false); | 254 | false, NULL); |
245 | 255 | ||
246 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 256 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
247 | if (wdev->authtry_bsses[i] && | 257 | if (wdev->authtry_bsses[i] && |
@@ -275,7 +285,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
275 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 285 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
276 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 286 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
277 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 287 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
278 | false); | 288 | false, NULL); |
279 | 289 | ||
280 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 290 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
281 | if (wdev->auth_bsses[i] && | 291 | if (wdev->auth_bsses[i] && |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d2b5d4ce0a00..3728d2b88b25 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -182,7 +182,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
182 | wdev->conn->params.bssid, | 182 | wdev->conn->params.bssid, |
183 | NULL, 0, NULL, 0, | 183 | NULL, 0, NULL, 0, |
184 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 184 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
185 | false); | 185 | false, NULL); |
186 | wdev_unlock(wdev); | 186 | wdev_unlock(wdev); |
187 | } | 187 | } |
188 | 188 | ||
@@ -247,7 +247,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
247 | wdev->conn->params.bssid, | 247 | wdev->conn->params.bssid, |
248 | NULL, 0, NULL, 0, | 248 | NULL, 0, NULL, 0, |
249 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 249 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
250 | false); | 250 | false, NULL); |
251 | } | 251 | } |
252 | } | 252 | } |
253 | 253 | ||
@@ -305,7 +305,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
305 | schedule_work(&rdev->conn_work); | 305 | schedule_work(&rdev->conn_work); |
306 | } else if (status_code != WLAN_STATUS_SUCCESS) { | 306 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
307 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 307 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
308 | status_code, false); | 308 | status_code, false, NULL); |
309 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 309 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && |
310 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | 310 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
311 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 311 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
@@ -316,10 +316,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
316 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 316 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
317 | const u8 *req_ie, size_t req_ie_len, | 317 | const u8 *req_ie, size_t req_ie_len, |
318 | const u8 *resp_ie, size_t resp_ie_len, | 318 | const u8 *resp_ie, size_t resp_ie_len, |
319 | u16 status, bool wextev) | 319 | u16 status, bool wextev, |
320 | struct cfg80211_bss *bss) | ||
320 | { | 321 | { |
321 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 322 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
322 | struct cfg80211_bss *bss; | ||
323 | #ifdef CONFIG_WIRELESS_EXT | 323 | #ifdef CONFIG_WIRELESS_EXT |
324 | union iwreq_data wrqu; | 324 | union iwreq_data wrqu; |
325 | #endif | 325 | #endif |
@@ -361,6 +361,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
361 | } | 361 | } |
362 | #endif | 362 | #endif |
363 | 363 | ||
364 | if (wdev->current_bss) { | ||
365 | cfg80211_unhold_bss(wdev->current_bss); | ||
366 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
367 | wdev->current_bss = NULL; | ||
368 | } | ||
369 | |||
364 | if (status == WLAN_STATUS_SUCCESS && | 370 | if (status == WLAN_STATUS_SUCCESS && |
365 | wdev->sme_state == CFG80211_SME_IDLE) | 371 | wdev->sme_state == CFG80211_SME_IDLE) |
366 | goto success; | 372 | goto success; |
@@ -368,12 +374,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
368 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 374 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
369 | return; | 375 | return; |
370 | 376 | ||
371 | if (wdev->current_bss) { | ||
372 | cfg80211_unhold_bss(wdev->current_bss); | ||
373 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
374 | wdev->current_bss = NULL; | ||
375 | } | ||
376 | |||
377 | if (wdev->conn) | 377 | if (wdev->conn) |
378 | wdev->conn->state = CFG80211_CONN_IDLE; | 378 | wdev->conn->state = CFG80211_CONN_IDLE; |
379 | 379 | ||
@@ -386,10 +386,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
386 | return; | 386 | return; |
387 | } | 387 | } |
388 | 388 | ||
389 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 389 | success: |
390 | wdev->ssid, wdev->ssid_len, | 390 | if (!bss) |
391 | WLAN_CAPABILITY_ESS, | 391 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
392 | WLAN_CAPABILITY_ESS); | 392 | wdev->ssid, wdev->ssid_len, |
393 | WLAN_CAPABILITY_ESS, | ||
394 | WLAN_CAPABILITY_ESS); | ||
393 | 395 | ||
394 | if (WARN_ON(!bss)) | 396 | if (WARN_ON(!bss)) |
395 | return; | 397 | return; |
@@ -397,7 +399,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
397 | cfg80211_hold_bss(bss_from_pub(bss)); | 399 | cfg80211_hold_bss(bss_from_pub(bss)); |
398 | wdev->current_bss = bss_from_pub(bss); | 400 | wdev->current_bss = bss_from_pub(bss); |
399 | 401 | ||
400 | success: | ||
401 | wdev->sme_state = CFG80211_SME_CONNECTED; | 402 | wdev->sme_state = CFG80211_SME_CONNECTED; |
402 | cfg80211_upload_connect_keys(wdev); | 403 | cfg80211_upload_connect_keys(wdev); |
403 | } | 404 | } |
@@ -788,7 +789,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
788 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | 789 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) |
789 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | 790 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, |
790 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 791 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
791 | wextev); | 792 | wextev, NULL); |
792 | 793 | ||
793 | return 0; | 794 | return 0; |
794 | } | 795 | } |