aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/offchannel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/offchannel.c')
-rw-r--r--net/mac80211/offchannel.c68
1 files changed, 37 insertions, 31 deletions
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index b4e52676f3f..13427b194ce 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -17,10 +17,14 @@
17#include "driver-trace.h" 17#include "driver-trace.h"
18 18
19/* 19/*
20 * inform AP that we will go to sleep so that it will buffer the frames 20 * Tell our hardware to disable PS.
21 * while we scan 21 * Optionally inform AP that we will go to sleep so that it will buffer
22 * the frames while we are doing off-channel work. This is optional
23 * because we *may* be doing work on-operating channel, and want our
24 * hardware unconditionally awake, but still let the AP send us normal frames.
22 */ 25 */
23static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) 26static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
27 bool tell_ap)
24{ 28{
25 struct ieee80211_local *local = sdata->local; 29 struct ieee80211_local *local = sdata->local;
26 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 30 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -41,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
41 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 45 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
42 } 46 }
43 47
44 if (!(local->offchannel_ps_enabled) || 48 if (tell_ap && (!local->offchannel_ps_enabled ||
45 !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) 49 !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
46 /* 50 /*
47 * If power save was enabled, no need to send a nullfunc 51 * If power save was enabled, no need to send a nullfunc
48 * frame because AP knows that we are sleeping. But if the 52 * frame because AP knows that we are sleeping. But if the
@@ -77,6 +81,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
77 * we are sleeping, let's just enable power save mode in 81 * we are sleeping, let's just enable power save mode in
78 * hardware. 82 * hardware.
79 */ 83 */
84 /* TODO: Only set hardware if CONF_PS changed?
85 * TODO: Should we set offchannel_ps_enabled to false?
86 */
80 local->hw.conf.flags |= IEEE80211_CONF_PS; 87 local->hw.conf.flags |= IEEE80211_CONF_PS;
81 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 88 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
82 } else if (local->hw.conf.dynamic_ps_timeout > 0) { 89 } else if (local->hw.conf.dynamic_ps_timeout > 0) {
@@ -95,63 +102,61 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
95 ieee80211_sta_reset_conn_monitor(sdata); 102 ieee80211_sta_reset_conn_monitor(sdata);
96} 103}
97 104
98void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) 105void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
106 bool offchannel_ps_enable)
99{ 107{
100 struct ieee80211_sub_if_data *sdata; 108 struct ieee80211_sub_if_data *sdata;
101 109
110 /*
111 * notify the AP about us leaving the channel and stop all
112 * STA interfaces.
113 */
102 mutex_lock(&local->iflist_mtx); 114 mutex_lock(&local->iflist_mtx);
103 list_for_each_entry(sdata, &local->interfaces, list) { 115 list_for_each_entry(sdata, &local->interfaces, list) {
104 if (!ieee80211_sdata_running(sdata)) 116 if (!ieee80211_sdata_running(sdata))
105 continue; 117 continue;
106 118
107 /* disable beaconing */ 119 if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
120 set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
121
122 /* Check to see if we should disable beaconing. */
108 if (sdata->vif.type == NL80211_IFTYPE_AP || 123 if (sdata->vif.type == NL80211_IFTYPE_AP ||
109 sdata->vif.type == NL80211_IFTYPE_ADHOC || 124 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
110 sdata->vif.type == NL80211_IFTYPE_MESH_POINT) 125 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
111 ieee80211_bss_info_change_notify( 126 ieee80211_bss_info_change_notify(
112 sdata, BSS_CHANGED_BEACON_ENABLED); 127 sdata, BSS_CHANGED_BEACON_ENABLED);
113 128
114 /* 129 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
115 * only handle non-STA interfaces here, STA interfaces
116 * are handled in ieee80211_offchannel_stop_station(),
117 * e.g., from the background scan state machine.
118 *
119 * In addition, do not stop monitor interface to allow it to be
120 * used from user space controlled off-channel operations.
121 */
122 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
123 sdata->vif.type != NL80211_IFTYPE_MONITOR) {
124 set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
125 netif_tx_stop_all_queues(sdata->dev); 130 netif_tx_stop_all_queues(sdata->dev);
131 if (offchannel_ps_enable &&
132 (sdata->vif.type == NL80211_IFTYPE_STATION) &&
133 sdata->u.mgd.associated)
134 ieee80211_offchannel_ps_enable(sdata, true);
126 } 135 }
127 } 136 }
128 mutex_unlock(&local->iflist_mtx); 137 mutex_unlock(&local->iflist_mtx);
129} 138}
130 139
131void ieee80211_offchannel_stop_station(struct ieee80211_local *local) 140void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
141 bool tell_ap)
132{ 142{
133 struct ieee80211_sub_if_data *sdata; 143 struct ieee80211_sub_if_data *sdata;
134 144
135 /*
136 * notify the AP about us leaving the channel and stop all STA interfaces
137 */
138 mutex_lock(&local->iflist_mtx); 145 mutex_lock(&local->iflist_mtx);
139 list_for_each_entry(sdata, &local->interfaces, list) { 146 list_for_each_entry(sdata, &local->interfaces, list) {
140 if (!ieee80211_sdata_running(sdata)) 147 if (!ieee80211_sdata_running(sdata))
141 continue; 148 continue;
142 149
143 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 150 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
144 set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); 151 sdata->u.mgd.associated)
145 netif_tx_stop_all_queues(sdata->dev); 152 ieee80211_offchannel_ps_enable(sdata, tell_ap);
146 if (sdata->u.mgd.associated)
147 ieee80211_offchannel_ps_enable(sdata);
148 }
149 } 153 }
150 mutex_unlock(&local->iflist_mtx); 154 mutex_unlock(&local->iflist_mtx);
151} 155}
152 156
153void ieee80211_offchannel_return(struct ieee80211_local *local, 157void ieee80211_offchannel_return(struct ieee80211_local *local,
154 bool enable_beaconing) 158 bool enable_beaconing,
159 bool offchannel_ps_disable)
155{ 160{
156 struct ieee80211_sub_if_data *sdata; 161 struct ieee80211_sub_if_data *sdata;
157 162
@@ -161,7 +166,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
161 continue; 166 continue;
162 167
163 /* Tell AP we're back */ 168 /* Tell AP we're back */
164 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 169 if (offchannel_ps_disable &&
170 sdata->vif.type == NL80211_IFTYPE_STATION) {
165 if (sdata->u.mgd.associated) 171 if (sdata->u.mgd.associated)
166 ieee80211_offchannel_ps_disable(sdata); 172 ieee80211_offchannel_ps_disable(sdata);
167 } 173 }
@@ -181,7 +187,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
181 netif_tx_wake_all_queues(sdata->dev); 187 netif_tx_wake_all_queues(sdata->dev);
182 } 188 }
183 189
184 /* re-enable beaconing */ 190 /* Check to see if we should re-enable beaconing */
185 if (enable_beaconing && 191 if (enable_beaconing &&
186 (sdata->vif.type == NL80211_IFTYPE_AP || 192 (sdata->vif.type == NL80211_IFTYPE_AP ||
187 sdata->vif.type == NL80211_IFTYPE_ADHOC || 193 sdata->vif.type == NL80211_IFTYPE_ADHOC ||