aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r--net/mac80211/pm.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 79a48f37d409..e45b83610e85 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -7,25 +7,23 @@
7#include "led.h" 7#include "led.h"
8 8
9/* return value indicates whether the driver should be further notified */ 9/* return value indicates whether the driver should be further notified */
10static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) 10static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
11{ 11{
12 switch (sdata->vif.type) { 12 switch (sdata->vif.type) {
13 case NL80211_IFTYPE_STATION: 13 case NL80211_IFTYPE_STATION:
14 ieee80211_sta_quiesce(sdata); 14 ieee80211_sta_quiesce(sdata);
15 return true; 15 break;
16 case NL80211_IFTYPE_ADHOC: 16 case NL80211_IFTYPE_ADHOC:
17 ieee80211_ibss_quiesce(sdata); 17 ieee80211_ibss_quiesce(sdata);
18 return true; 18 break;
19 case NL80211_IFTYPE_MESH_POINT: 19 case NL80211_IFTYPE_MESH_POINT:
20 ieee80211_mesh_quiesce(sdata); 20 ieee80211_mesh_quiesce(sdata);
21 return true; 21 break;
22 case NL80211_IFTYPE_AP_VLAN:
23 case NL80211_IFTYPE_MONITOR:
24 /* don't tell driver about this */
25 return false;
26 default: 22 default:
27 return true; 23 break;
28 } 24 }
25
26 cancel_work_sync(&sdata->work);
29} 27}
30 28
31int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 29int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
@@ -44,7 +42,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
44 mutex_lock(&local->sta_mtx); 42 mutex_lock(&local->sta_mtx);
45 list_for_each_entry(sta, &local->sta_list, list) { 43 list_for_each_entry(sta, &local->sta_list, list) {
46 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 44 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
47 ieee80211_sta_tear_down_BA_sessions(sta, true); 45 ieee80211_sta_tear_down_BA_sessions(
46 sta, AGG_STOP_LOCAL_REQUEST);
48 } 47 }
49 mutex_unlock(&local->sta_mtx); 48 mutex_unlock(&local->sta_mtx);
50 } 49 }
@@ -94,10 +93,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
94 WARN_ON(err != 1); 93 WARN_ON(err != 1);
95 local->wowlan = false; 94 local->wowlan = false;
96 } else { 95 } else {
97 list_for_each_entry(sdata, &local->interfaces, list) { 96 list_for_each_entry(sdata, &local->interfaces, list)
98 cancel_work_sync(&sdata->work); 97 if (ieee80211_sdata_running(sdata))
99 ieee80211_quiesce(sdata); 98 ieee80211_quiesce(sdata);
100 }
101 goto suspend; 99 goto suspend;
102 } 100 }
103 } 101 }
@@ -124,17 +122,43 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
124 122
125 /* remove all interfaces */ 123 /* remove all interfaces */
126 list_for_each_entry(sdata, &local->interfaces, list) { 124 list_for_each_entry(sdata, &local->interfaces, list) {
127 cancel_work_sync(&sdata->work); 125 static u8 zero_addr[ETH_ALEN] = {};
126 u32 changed = 0;
128 127
129 if (!ieee80211_quiesce(sdata)) 128 if (!ieee80211_sdata_running(sdata))
130 continue; 129 continue;
131 130
132 if (!ieee80211_sdata_running(sdata)) 131 switch (sdata->vif.type) {
132 case NL80211_IFTYPE_AP_VLAN:
133 case NL80211_IFTYPE_MONITOR:
134 /* skip these */
133 continue; 135 continue;
136 case NL80211_IFTYPE_STATION:
137 if (sdata->vif.bss_conf.assoc)
138 changed = BSS_CHANGED_ASSOC |
139 BSS_CHANGED_BSSID |
140 BSS_CHANGED_IDLE;
141 break;
142 case NL80211_IFTYPE_AP:
143 case NL80211_IFTYPE_ADHOC:
144 case NL80211_IFTYPE_MESH_POINT:
145 if (sdata->vif.bss_conf.enable_beacon)
146 changed = BSS_CHANGED_BEACON_ENABLED;
147 break;
148 default:
149 break;
150 }
151
152 ieee80211_quiesce(sdata);
153
154 sdata->suspend_bss_conf = sdata->vif.bss_conf;
155 memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
156 sdata->vif.bss_conf.idle = true;
157 if (sdata->suspend_bss_conf.bssid)
158 sdata->vif.bss_conf.bssid = zero_addr;
134 159
135 /* disable beaconing */ 160 /* disable beaconing or remove association */
136 ieee80211_bss_info_change_notify(sdata, 161 ieee80211_bss_info_change_notify(sdata, changed);
137 BSS_CHANGED_BEACON_ENABLED);
138 162
139 if (sdata->vif.type == NL80211_IFTYPE_AP && 163 if (sdata->vif.type == NL80211_IFTYPE_AP &&
140 rcu_access_pointer(sdata->u.ap.beacon)) 164 rcu_access_pointer(sdata->u.ap.beacon))