diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-10-05 04:41:47 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-05 13:37:51 -0400 |
commit | 025e6be220e448c02045e8499c7db8ce4bc8eea2 (patch) | |
tree | 0b28807104e80926d33eec8634dd94c5561e64ab /net/mac80211 | |
parent | 6774889314ba507483e63c014fcb81adfc127202 (diff) |
mac80211: fix deadlock with multiple interfaces
The locking around ieee80211_recalc_smps is
buggy -- it cannot acquire another interface's
mutex while the iflist mutex is held because
another code path could be holding the iface
mutex and trying to acquire the iflist mutex.
But the locking is also unnecessary, we only
check "ifmgd->associated" as a bool, and don't
use the pointer (in check_mgd_smps).
Reported-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 20 |
5 files changed, 7 insertions, 22 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a7a78f28ff6f..94bf550bd4c9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1394,7 +1394,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
1394 | if (!sdata->u.mgd.associated || | 1394 | if (!sdata->u.mgd.associated || |
1395 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 1395 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { |
1396 | mutex_lock(&sdata->local->iflist_mtx); | 1396 | mutex_lock(&sdata->local->iflist_mtx); |
1397 | ieee80211_recalc_smps(sdata->local, sdata); | 1397 | ieee80211_recalc_smps(sdata->local); |
1398 | mutex_unlock(&sdata->local->iflist_mtx); | 1398 | mutex_unlock(&sdata->local->iflist_mtx); |
1399 | return 0; | 1399 | return 0; |
1400 | } | 1400 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 55d79db985fc..08509e212841 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1297,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1297 | enum ieee80211_band band); | 1297 | enum ieee80211_band band); |
1298 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1298 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
1299 | enum ieee80211_smps_mode smps_mode); | 1299 | enum ieee80211_smps_mode smps_mode); |
1300 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local); |
1301 | struct ieee80211_sub_if_data *forsdata); | ||
1302 | 1301 | ||
1303 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1302 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1304 | const u8 *ids, int n_ids, size_t offset); | 1303 | const u8 *ids, int n_ids, size_t offset); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9c2f3f934c74..e3717092115f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -333,7 +333,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
333 | container_of(work, struct ieee80211_local, recalc_smps); | 333 | container_of(work, struct ieee80211_local, recalc_smps); |
334 | 334 | ||
335 | mutex_lock(&local->iflist_mtx); | 335 | mutex_lock(&local->iflist_mtx); |
336 | ieee80211_recalc_smps(local, NULL); | 336 | ieee80211_recalc_smps(local); |
337 | mutex_unlock(&local->iflist_mtx); | 337 | mutex_unlock(&local->iflist_mtx); |
338 | } | 338 | } |
339 | 339 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c37086a12f51..2b2982782bcd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -913,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
913 | 913 | ||
914 | mutex_lock(&local->iflist_mtx); | 914 | mutex_lock(&local->iflist_mtx); |
915 | ieee80211_recalc_ps(local, -1); | 915 | ieee80211_recalc_ps(local, -1); |
916 | ieee80211_recalc_smps(local, sdata); | 916 | ieee80211_recalc_smps(local); |
917 | mutex_unlock(&local->iflist_mtx); | 917 | mutex_unlock(&local->iflist_mtx); |
918 | 918 | ||
919 | netif_tx_start_all_queues(sdata->dev); | 919 | netif_tx_start_all_queues(sdata->dev); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aba025d748e9..4ee8f2b53cb7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | |||
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | /* must hold iflist_mtx */ | 1299 | /* must hold iflist_mtx */ |
1300 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local) |
1301 | struct ieee80211_sub_if_data *forsdata) | ||
1302 | { | 1301 | { |
1303 | struct ieee80211_sub_if_data *sdata; | 1302 | struct ieee80211_sub_if_data *sdata; |
1304 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1303 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; |
1305 | int count = 0; | 1304 | int count = 0; |
1306 | 1305 | ||
1307 | if (forsdata) | ||
1308 | lockdep_assert_held(&forsdata->u.mgd.mtx); | ||
1309 | |||
1310 | lockdep_assert_held(&local->iflist_mtx); | 1306 | lockdep_assert_held(&local->iflist_mtx); |
1311 | 1307 | ||
1312 | /* | 1308 | /* |
@@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | |||
1324 | continue; | 1320 | continue; |
1325 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1321 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1326 | goto set; | 1322 | goto set; |
1327 | if (sdata != forsdata) { | 1323 | |
1328 | /* | 1324 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); |
1329 | * This nested is ok -- we are holding the iflist_mtx | ||
1330 | * so can't get here twice or so. But it's required | ||
1331 | * since normally we acquire it first and then the | ||
1332 | * iflist_mtx. | ||
1333 | */ | ||
1334 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1335 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1336 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1337 | } else | ||
1338 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1339 | 1325 | ||
1340 | if (count > 1) { | 1326 | if (count > 1) { |
1341 | smps_mode = IEEE80211_SMPS_OFF; | 1327 | smps_mode = IEEE80211_SMPS_OFF; |