aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-10-05 04:41:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-05 13:37:51 -0400
commit025e6be220e448c02045e8499c7db8ce4bc8eea2 (patch)
tree0b28807104e80926d33eec8634dd94c5561e64ab /net/mac80211/util.c
parent6774889314ba507483e63c014fcb81adfc127202 (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/util.c')
-rw-r--r--net/mac80211/util.c20
1 files changed, 3 insertions, 17 deletions
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 */
1300void ieee80211_recalc_smps(struct ieee80211_local *local, 1300void 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;