From: Johannes Berg Date: Sat, 14 Mar 2009 08:42:49 +0000 (+0100) Subject: mac80211: acquire sta_lock for station suspend/resume X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=7f0216a49bea717b9606b81c60f2f0b6152123eb;p=linux-2.6-omap-h63xx.git mac80211: acquire sta_lock for station suspend/resume To avoid concurrent manipulations of the sta list (which shouldn't be possible at this point, but anyway) we need to hold the sta_lock around iterating the list. At the same time, we do not need to iterate the list at all if the driver doesn't want to be notified. Signed-off-by: Johannes Berg Acked-by: Bob Copeland Signed-off-by: John W. Linville --- diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index c923ceb089a..ef7be1ce2c8 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -10,6 +10,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct ieee80211_sub_if_data *sdata; struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); @@ -21,9 +22,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) ieee80211_disable_keys(sdata); /* remove STAs */ - list_for_each_entry(sta, &local->sta_list, list) { - - if (local->ops->sta_notify) { + if (local->ops->sta_notify) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, @@ -32,11 +33,11 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) local->ops->sta_notify(hw, &sdata->vif, STA_NOTIFY_REMOVE, &sta->sta); } + spin_unlock_irqrestore(&local->sta_lock, flags); } /* remove all interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_MONITOR && netif_running(sdata->dev)) { @@ -64,6 +65,7 @@ int __ieee80211_resume(struct ieee80211_hw *hw) struct ieee80211_sub_if_data *sdata; struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; int res; /* restart hardware */ @@ -75,7 +77,6 @@ int __ieee80211_resume(struct ieee80211_hw *hw) /* add interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_MONITOR && netif_running(sdata->dev)) { @@ -87,9 +88,9 @@ int __ieee80211_resume(struct ieee80211_hw *hw) } /* add STAs back */ - list_for_each_entry(sta, &local->sta_list, list) { - - if (local->ops->sta_notify) { + if (local->ops->sta_notify) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, @@ -98,6 +99,7 @@ int __ieee80211_resume(struct ieee80211_hw *hw) local->ops->sta_notify(hw, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); } + spin_unlock_irqrestore(&local->sta_lock, flags); } /* add back keys */