aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
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
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')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mlme.c2
-rw-r--r--net/mac80211/util.c20
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);
1298int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, 1298int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
1299 enum ieee80211_smps_mode smps_mode); 1299 enum ieee80211_smps_mode smps_mode);
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
1303size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 1302size_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 */
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;