aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-02-12 16:24:20 -0500
committerLuciano Coelho <coelho@ti.com>2011-02-22 11:06:36 -0500
commita100885d9dfd8685e0b4e442afc9041ee4c90586 (patch)
tree554a0aac55b22fa5760b9c58979a976a247f717d /drivers/net/wireless
parent92fe9b5f112c77dbb63f42f7bed885d709586106 (diff)
wl12xx: avoid blocking while holding rcu lock on bss info change
Some blocking functions were called while holding the rcu lock for accessing STA information. This can lead to a deadlock. Save the required info beforehand and release the rcu without blocking. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/wl12xx/main.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index cf8b3cebe9d6..d51d55998f4e 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2222,6 +2222,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2222 u32 sta_rate_set = 0; 2222 u32 sta_rate_set = 0;
2223 int ret; 2223 int ret;
2224 struct ieee80211_sta *sta; 2224 struct ieee80211_sta *sta;
2225 bool sta_exists = false;
2226 struct ieee80211_sta_ht_cap sta_ht_cap;
2225 2227
2226 if (is_ibss) { 2228 if (is_ibss) {
2227 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, 2229 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
@@ -2293,16 +2295,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2293 if (sta->ht_cap.ht_supported) 2295 if (sta->ht_cap.ht_supported)
2294 sta_rate_set |= 2296 sta_rate_set |=
2295 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); 2297 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
2298 sta_ht_cap = sta->ht_cap;
2299 sta_exists = true;
2300 }
2301 rcu_read_unlock();
2296 2302
2303 if (sta_exists) {
2297 /* handle new association with HT and HT information change */ 2304 /* handle new association with HT and HT information change */
2298 if ((changed & BSS_CHANGED_HT) && 2305 if ((changed & BSS_CHANGED_HT) &&
2299 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { 2306 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2300 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, 2307 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
2301 true); 2308 true);
2302 if (ret < 0) { 2309 if (ret < 0) {
2303 wl1271_warning("Set ht cap true failed %d", 2310 wl1271_warning("Set ht cap true failed %d",
2304 ret); 2311 ret);
2305 rcu_read_unlock();
2306 goto out; 2312 goto out;
2307 } 2313 }
2308 ret = wl1271_acx_set_ht_information(wl, 2314 ret = wl1271_acx_set_ht_information(wl,
@@ -2310,23 +2316,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2310 if (ret < 0) { 2316 if (ret < 0) {
2311 wl1271_warning("Set ht information failed %d", 2317 wl1271_warning("Set ht information failed %d",
2312 ret); 2318 ret);
2313 rcu_read_unlock();
2314 goto out; 2319 goto out;
2315 } 2320 }
2316 } 2321 }
2317 /* handle new association without HT and disassociation */ 2322 /* handle new association without HT and disassociation */
2318 else if (changed & BSS_CHANGED_ASSOC) { 2323 else if (changed & BSS_CHANGED_ASSOC) {
2319 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, 2324 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
2320 false); 2325 false);
2321 if (ret < 0) { 2326 if (ret < 0) {
2322 wl1271_warning("Set ht cap false failed %d", 2327 wl1271_warning("Set ht cap false failed %d",
2323 ret); 2328 ret);
2324 rcu_read_unlock();
2325 goto out; 2329 goto out;
2326 } 2330 }
2327 } 2331 }
2328 } 2332 }
2329 rcu_read_unlock();
2330 2333
2331 if ((changed & BSS_CHANGED_ASSOC)) { 2334 if ((changed & BSS_CHANGED_ASSOC)) {
2332 if (bss_conf->assoc) { 2335 if (bss_conf->assoc) {