diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-12-23 07:15:40 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-28 16:55:01 -0500 |
commit | b203ffc3a447eb8d9e6120b783ddee081b143061 (patch) | |
tree | 520473f30067c9ebf003c95d8053fe4cbe39e11e /net/mac80211/scan.c | |
parent | 0c1ad2cac1cb54db38fd4cc1822965071ee83f6e (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.c | 156 |
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 | */ | ||
234 | static 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 */ | ||
267 | static 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 | |||
302 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 230 | void 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 | ||
385 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 291 | static 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, | |||
568 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | 453 | static 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 | |||
604 | static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, | 473 | static 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 | ||