Skip to content

Commit

Permalink
mac80211: fix deadlock with multiple interfaces
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Oct 5, 2010
1 parent 6774889 commit 025e6be
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 22 deletions.
2 changes: 1 addition & 1 deletion net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
if (!sdata->u.mgd.associated ||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_smps(sdata->local, sdata);
ieee80211_recalc_smps(sdata->local);
mutex_unlock(&sdata->local->iflist_mtx);
return 0;
}
Expand Down
3 changes: 1 addition & 2 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1297,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
enum ieee80211_band band);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *forsdata);
void ieee80211_recalc_smps(struct ieee80211_local *local);

size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
container_of(work, struct ieee80211_local, recalc_smps);

mutex_lock(&local->iflist_mtx);
ieee80211_recalc_smps(local, NULL);
ieee80211_recalc_smps(local);
mutex_unlock(&local->iflist_mtx);
}

Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,

mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
ieee80211_recalc_smps(local, sdata);
ieee80211_recalc_smps(local);
mutex_unlock(&local->iflist_mtx);

netif_tx_start_all_queues(sdata->dev);
Expand Down
20 changes: 3 additions & 17 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
}

/* must hold iflist_mtx */
void ieee80211_recalc_smps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *forsdata)
void ieee80211_recalc_smps(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
int count = 0;

if (forsdata)
lockdep_assert_held(&forsdata->u.mgd.mtx);

lockdep_assert_held(&local->iflist_mtx);

/*
Expand All @@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
continue;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
goto set;
if (sdata != forsdata) {
/*
* This nested is ok -- we are holding the iflist_mtx
* so can't get here twice or so. But it's required
* since normally we acquire it first and then the
* iflist_mtx.
*/
mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
mutex_unlock(&sdata->u.mgd.mtx);
} else
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);

count += check_mgd_smps(&sdata->u.mgd, &smps_mode);

if (count > 1) {
smps_mode = IEEE80211_SMPS_OFF;
Expand Down

0 comments on commit 025e6be

Please sign in to comment.