aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-12-23 07:15:40 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-28 16:55:01 -0500
commitb203ffc3a447eb8d9e6120b783ddee081b143061 (patch)
tree520473f30067c9ebf003c95d8053fe4cbe39e11e /net/mac80211/scan.c
parent0c1ad2cac1cb54db38fd4cc1822965071ee83f6e (diff)
mac80211: Generalize off-channel operation helpers from scan code
The off-channel operations for going into power save mode (station mode) or stop beaconing (AP/IBSS) are not limited to scanning. Move these into a separate file and allow them to be used for other purposes, too. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c156
1 files changed, 6 insertions, 150 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 2a2d7f6005af..365f40975511 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -227,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
227 return true; 227 return true;
228} 228}
229 229
230/*
231 * inform AP that we will go to sleep so that it will buffer the frames
232 * while we scan
233 */
234static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
235{
236 struct ieee80211_local *local = sdata->local;
237
238 local->scan_ps_enabled = false;
239
240 /* FIXME: what to do when local->pspolling is true? */
241
242 del_timer_sync(&local->dynamic_ps_timer);
243 cancel_work_sync(&local->dynamic_ps_enable_work);
244
245 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
246 local->scan_ps_enabled = true;
247 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
248 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
249 }
250
251 if (!(local->scan_ps_enabled) ||
252 !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
253 /*
254 * If power save was enabled, no need to send a nullfunc
255 * frame because AP knows that we are sleeping. But if the
256 * hardware is creating the nullfunc frame for power save
257 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
258 * enabled) and power save was enabled, the firmware just
259 * sent a null frame with power save disabled. So we need
260 * to send a new nullfunc frame to inform the AP that we
261 * are again sleeping.
262 */
263 ieee80211_send_nullfunc(local, sdata, 1);
264}
265
266/* inform AP that we are awake again, unless power save is enabled */
267static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
268{
269 struct ieee80211_local *local = sdata->local;
270
271 if (!local->ps_sdata)
272 ieee80211_send_nullfunc(local, sdata, 0);
273 else if (local->scan_ps_enabled) {
274 /*
275 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
276 * will send a nullfunc frame with the powersave bit set
277 * even though the AP already knows that we are sleeping.
278 * This could be avoided by sending a null frame with power
279 * save bit disabled before enabling the power save, but
280 * this doesn't gain anything.
281 *
282 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
283 * to send a nullfunc frame because AP already knows that
284 * we are sleeping, let's just enable power save mode in
285 * hardware.
286 */
287 local->hw.conf.flags |= IEEE80211_CONF_PS;
288 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
289 } else if (local->hw.conf.dynamic_ps_timeout > 0) {
290 /*
291 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
292 * had been running before leaving the operating channel,
293 * restart the timer now and send a nullfunc frame to inform
294 * the AP that we are awake.
295 */
296 ieee80211_send_nullfunc(local, sdata, 0);
297 mod_timer(&local->dynamic_ps_timer, jiffies +
298 msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
299 }
300}
301
302void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 230void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
303{ 231{
304 struct ieee80211_local *local = hw_to_local(hw); 232 struct ieee80211_local *local = hw_to_local(hw);
305 struct ieee80211_sub_if_data *sdata;
306 bool was_hw_scan; 233 bool was_hw_scan;
307 234
308 mutex_lock(&local->scan_mtx); 235 mutex_lock(&local->scan_mtx);
@@ -351,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
351 278
352 drv_sw_scan_complete(local); 279 drv_sw_scan_complete(local);
353 280
354 mutex_lock(&local->iflist_mtx); 281 ieee80211_offchannel_return(local, true);
355 list_for_each_entry(sdata, &local->interfaces, list) {
356 if (!ieee80211_sdata_running(sdata))
357 continue;
358
359 /* Tell AP we're back */
360 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
361 if (sdata->u.mgd.associated) {
362 ieee80211_scan_ps_disable(sdata);
363 netif_wake_queue(sdata->dev);
364 }
365 } else
366 netif_wake_queue(sdata->dev);
367
368 /* re-enable beaconing */
369 if (sdata->vif.type == NL80211_IFTYPE_AP ||
370 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
371 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
372 ieee80211_bss_info_change_notify(
373 sdata, BSS_CHANGED_BEACON_ENABLED);
374 }
375 mutex_unlock(&local->iflist_mtx);
376 282
377 done: 283 done:
378 ieee80211_recalc_idle(local); 284 ieee80211_recalc_idle(local);
@@ -384,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
384 290
385static int ieee80211_start_sw_scan(struct ieee80211_local *local) 291static int ieee80211_start_sw_scan(struct ieee80211_local *local)
386{ 292{
387 struct ieee80211_sub_if_data *sdata;
388
389 /* 293 /*
390 * Hardware/driver doesn't support hw_scan, so use software 294 * Hardware/driver doesn't support hw_scan, so use software
391 * scanning instead. First send a nullfunc frame with power save 295 * scanning instead. First send a nullfunc frame with power save
@@ -401,26 +305,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
401 */ 305 */
402 drv_sw_scan_start(local); 306 drv_sw_scan_start(local);
403 307
404 mutex_lock(&local->iflist_mtx); 308 ieee80211_offchannel_stop_beaconing(local);
405 list_for_each_entry(sdata, &local->interfaces, list) {
406 if (!ieee80211_sdata_running(sdata))
407 continue;
408
409 /* disable beaconing */
410 if (sdata->vif.type == NL80211_IFTYPE_AP ||
411 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
412 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
413 ieee80211_bss_info_change_notify(
414 sdata, BSS_CHANGED_BEACON_ENABLED);
415
416 /*
417 * only handle non-STA interfaces here, STA interfaces
418 * are handled in the scan state machine
419 */
420 if (sdata->vif.type != NL80211_IFTYPE_STATION)
421 netif_stop_queue(sdata->dev);
422 }
423 mutex_unlock(&local->iflist_mtx);
424 309
425 local->next_scan_state = SCAN_DECISION; 310 local->next_scan_state = SCAN_DECISION;
426 local->scan_channel_idx = 0; 311 local->scan_channel_idx = 0;
@@ -568,23 +453,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
568static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, 453static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
569 unsigned long *next_delay) 454 unsigned long *next_delay)
570{ 455{
571 struct ieee80211_sub_if_data *sdata; 456 ieee80211_offchannel_stop_station(local);
572
573 /*
574 * notify the AP about us leaving the channel and stop all STA interfaces
575 */
576 mutex_lock(&local->iflist_mtx);
577 list_for_each_entry(sdata, &local->interfaces, list) {
578 if (!ieee80211_sdata_running(sdata))
579 continue;
580
581 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
582 netif_stop_queue(sdata->dev);
583 if (sdata->u.mgd.associated)
584 ieee80211_scan_ps_enable(sdata);
585 }
586 }
587 mutex_unlock(&local->iflist_mtx);
588 457
589 __set_bit(SCAN_OFF_CHANNEL, &local->scanning); 458 __set_bit(SCAN_OFF_CHANNEL, &local->scanning);
590 459
@@ -604,28 +473,15 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
604static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, 473static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
605 unsigned long *next_delay) 474 unsigned long *next_delay)
606{ 475{
607 struct ieee80211_sub_if_data *sdata = local->scan_sdata;
608
609 /* switch back to the operating channel */ 476 /* switch back to the operating channel */
610 local->scan_channel = NULL; 477 local->scan_channel = NULL;
611 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 478 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
612 479
613 /* 480 /*
614 * notify the AP about us being back and restart all STA interfaces 481 * Only re-enable station mode interface now; beaconing will be
482 * re-enabled once the full scan has been completed.
615 */ 483 */
616 mutex_lock(&local->iflist_mtx); 484 ieee80211_offchannel_return(local, false);
617 list_for_each_entry(sdata, &local->interfaces, list) {
618 if (!ieee80211_sdata_running(sdata))
619 continue;
620
621 /* Tell AP we're back */
622 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
623 if (sdata->u.mgd.associated)
624 ieee80211_scan_ps_disable(sdata);
625 netif_wake_queue(sdata->dev);
626 }
627 }
628 mutex_unlock(&local->iflist_mtx);
629 485
630 __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); 486 __clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
631 487