aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h12
-rw-r--r--net/mac80211/scan.c64
2 files changed, 69 insertions, 7 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index daa539a4287b..174dc1d7526b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1307,11 +1307,13 @@ enum ieee80211_ampdu_mlme_action {
1307 * 1307 *
1308 * @hw_scan: Ask the hardware to service the scan request, no need to start 1308 * @hw_scan: Ask the hardware to service the scan request, no need to start
1309 * the scan state machine in stack. The scan must honour the channel 1309 * the scan state machine in stack. The scan must honour the channel
1310 * configuration done by the regulatory agent in the wiphy's registered 1310 * configuration done by the regulatory agent in the wiphy's
1311 * bands. When the scan finishes, ieee80211_scan_completed() must be 1311 * registered bands. The hardware (or the driver) needs to make sure
1312 * called; note that it also must be called when the scan cannot finish 1312 * that power save is disabled. When the scan finishes,
1313 * because the hardware is turned off! Anything else is a bug! 1313 * ieee80211_scan_completed() must be called; note that it also must
1314 * Returns a negative error code which will be seen in userspace. 1314 * be called when the scan cannot finish because the hardware is
1315 * turned off! Anything else is a bug! Returns a negative error code
1316 * which will be seen in userspace.
1315 * 1317 *
1316 * @sw_scan_start: Notifier function that is called just before a software scan 1318 * @sw_scan_start: Notifier function that is called just before a software scan
1317 * is started. Can be NULL, if the driver doesn't need this notification. 1319 * is started. Can be NULL, if the driver doesn't need this notification.
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 46f35dc6accb..3bf9839f5916 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -214,6 +214,66 @@ void ieee80211_scan_failed(struct ieee80211_local *local)
214 local->scan_req = NULL; 214 local->scan_req = NULL;
215} 215}
216 216
217/*
218 * inform AP that we will go to sleep so that it will buffer the frames
219 * while we scan
220 */
221static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
222{
223 struct ieee80211_local *local = sdata->local;
224 bool ps = false;
225
226 /* FIXME: what to do when local->pspolling is true? */
227
228 del_timer_sync(&local->dynamic_ps_timer);
229 cancel_work_sync(&local->dynamic_ps_enable_work);
230
231 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
232 ps = true;
233 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
234 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
235 }
236
237 if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
238 /*
239 * If power save was enabled, no need to send a nullfunc
240 * frame because AP knows that we are sleeping. But if the
241 * hardware is creating the nullfunc frame for power save
242 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
243 * enabled) and power save was enabled, the firmware just
244 * sent a null frame with power save disabled. So we need
245 * to send a new nullfunc frame to inform the AP that we
246 * are again sleeping.
247 */
248 ieee80211_send_nullfunc(local, sdata, 1);
249}
250
251/* inform AP that we are awake again, unless power save is enabled */
252static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
253{
254 struct ieee80211_local *local = sdata->local;
255
256 if (!local->powersave)
257 ieee80211_send_nullfunc(local, sdata, 0);
258 else {
259 /*
260 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
261 * will send a nullfunc frame with the powersave bit set
262 * even though the AP already knows that we are sleeping.
263 * This could be avoided by sending a null frame with power
264 * save bit disabled before enabling the power save, but
265 * this doesn't gain anything.
266 *
267 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
268 * to send a nullfunc frame because AP already knows that
269 * we are sleeping, let's just enable power save mode in
270 * hardware.
271 */
272 local->hw.conf.flags |= IEEE80211_CONF_PS;
273 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
274 }
275}
276
217void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 277void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
218{ 278{
219 struct ieee80211_local *local = hw_to_local(hw); 279 struct ieee80211_local *local = hw_to_local(hw);
@@ -268,7 +328,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
268 /* Tell AP we're back */ 328 /* Tell AP we're back */
269 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 329 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
270 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { 330 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
271 ieee80211_send_nullfunc(local, sdata, 0); 331 ieee80211_scan_ps_disable(sdata);
272 netif_tx_wake_all_queues(sdata->dev); 332 netif_tx_wake_all_queues(sdata->dev);
273 } 333 }
274 } else 334 } else
@@ -441,7 +501,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
441 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 501 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
442 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { 502 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
443 netif_tx_stop_all_queues(sdata->dev); 503 netif_tx_stop_all_queues(sdata->dev);
444 ieee80211_send_nullfunc(local, sdata, 1); 504 ieee80211_scan_ps_enable(sdata);
445 } 505 }
446 } else 506 } else
447 netif_tx_stop_all_queues(sdata->dev); 507 netif_tx_stop_all_queues(sdata->dev);