aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-11-08 10:21:21 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-11 12:32:49 -0500
commit07ef03ee8b280a536b38ccfe512b9556996f0492 (patch)
treec5f61667cb7bea4dbd9dee8175ac61aebb61c5de /net/mac80211/scan.c
parent86a2ea4134b48f6371103cfceb521bf2d2bf76cd (diff)
mac80211: simplify scan state machine
Attempting to micro-optimise the scan by going fully live again when scanning the operating channel just made the code extremely complex and has little gain in most use cases. Remove all that code and simplify the state machine again. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c199
1 files changed, 77 insertions, 122 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 83a0b050b374..7107159d4155 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -212,12 +212,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
212 if (bss) 212 if (bss)
213 ieee80211_rx_bss_put(sdata->local, bss); 213 ieee80211_rx_bss_put(sdata->local, bss);
214 214
215 /* If we are on-operating-channel, and this packet is for the 215 if (channel == sdata->local->oper_channel)
216 * current channel, pass the pkt on up the stack so that
217 * the rest of the stack can make use of it.
218 */
219 if (ieee80211_cfg_on_oper_channel(sdata->local)
220 && (channel == sdata->local->oper_channel))
221 return RX_CONTINUE; 216 return RX_CONTINUE;
222 217
223 dev_kfree_skb(skb); 218 dev_kfree_skb(skb);
@@ -263,8 +258,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
263 bool was_hw_scan) 258 bool was_hw_scan)
264{ 259{
265 struct ieee80211_local *local = hw_to_local(hw); 260 struct ieee80211_local *local = hw_to_local(hw);
266 bool on_oper_chan;
267 bool enable_beacons = false;
268 261
269 lockdep_assert_held(&local->mtx); 262 lockdep_assert_held(&local->mtx);
270 263
@@ -297,25 +290,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
297 local->scanning = 0; 290 local->scanning = 0;
298 local->scan_channel = NULL; 291 local->scan_channel = NULL;
299 292
300 on_oper_chan = ieee80211_cfg_on_oper_channel(local); 293 /* Set power back to normal operating levels. */
301 294 ieee80211_hw_config(local, 0);
302 if (was_hw_scan || !on_oper_chan)
303 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
304 else
305 /* Set power back to normal operating levels. */
306 ieee80211_hw_config(local, 0);
307 295
308 if (!was_hw_scan) { 296 if (!was_hw_scan) {
309 bool on_oper_chan2;
310 ieee80211_configure_filter(local); 297 ieee80211_configure_filter(local);
311 drv_sw_scan_complete(local); 298 drv_sw_scan_complete(local);
312 on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); 299 ieee80211_offchannel_return(local, true, true);
313 /* We should always be on-channel at this point. */
314 WARN_ON(!on_oper_chan2);
315 if (on_oper_chan2 && (on_oper_chan != on_oper_chan2))
316 enable_beacons = true;
317
318 ieee80211_offchannel_return(local, enable_beacons, true);
319 } 300 }
320 301
321 ieee80211_recalc_idle(local); 302 ieee80211_recalc_idle(local);
@@ -360,11 +341,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
360 local->next_scan_state = SCAN_DECISION; 341 local->next_scan_state = SCAN_DECISION;
361 local->scan_channel_idx = 0; 342 local->scan_channel_idx = 0;
362 343
363 /* We always want to use off-channel PS, even if we 344 ieee80211_offchannel_stop_vifs(local, true);
364 * are not really leaving oper-channel. Don't
365 * tell the AP though, as long as we are on-channel.
366 */
367 ieee80211_offchannel_enable_all_ps(local, false);
368 345
369 ieee80211_configure_filter(local); 346 ieee80211_configure_filter(local);
370 347
@@ -372,8 +349,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
372 ieee80211_hw_config(local, 0); 349 ieee80211_hw_config(local, 0);
373 350
374 ieee80211_queue_delayed_work(&local->hw, 351 ieee80211_queue_delayed_work(&local->hw,
375 &local->scan_work, 352 &local->scan_work, 0);
376 IEEE80211_CHANNEL_TIME);
377 353
378 return 0; 354 return 0;
379} 355}
@@ -509,96 +485,39 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
509 485
510 next_chan = local->scan_req->channels[local->scan_channel_idx]; 486 next_chan = local->scan_req->channels[local->scan_channel_idx];
511 487
512 if (ieee80211_cfg_on_oper_channel(local)) {
513 /* We're currently on operating channel. */
514 if (next_chan == local->oper_channel)
515 /* We don't need to move off of operating channel. */
516 local->next_scan_state = SCAN_SET_CHANNEL;
517 else
518 /*
519 * We do need to leave operating channel, as next
520 * scan is somewhere else.
521 */
522 local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
523 } else {
524 /*
525 * we're currently scanning a different channel, let's
526 * see if we can scan another channel without interfering
527 * with the current traffic situation.
528 *
529 * Since we don't know if the AP has pending frames for us
530 * we can only check for our tx queues and use the current
531 * pm_qos requirements for rx. Hence, if no tx traffic occurs
532 * at all we will scan as many channels in a row as the pm_qos
533 * latency allows us to. Additionally we also check for the
534 * currently negotiated listen interval to prevent losing
535 * frames unnecessarily.
536 *
537 * Otherwise switch back to the operating channel.
538 */
539
540 bad_latency = time_after(jiffies +
541 ieee80211_scan_get_channel_time(next_chan),
542 local->leave_oper_channel_time +
543 usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
544
545 listen_int_exceeded = time_after(jiffies +
546 ieee80211_scan_get_channel_time(next_chan),
547 local->leave_oper_channel_time +
548 usecs_to_jiffies(min_beacon_int * 1024) *
549 local->hw.conf.listen_interval);
550
551 if (associated && ( !tx_empty || bad_latency ||
552 listen_int_exceeded))
553 local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
554 else
555 local->next_scan_state = SCAN_SET_CHANNEL;
556 }
557
558 *next_delay = 0;
559}
560
561static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
562 unsigned long *next_delay)
563{
564 /* PS will already be in off-channel mode,
565 * we do that once at the beginning of scanning.
566 */
567 ieee80211_offchannel_stop_vifs(local, false);
568
569 /* 488 /*
570 * What if the nullfunc frames didn't arrive? 489 * we're currently scanning a different channel, let's
490 * see if we can scan another channel without interfering
491 * with the current traffic situation.
492 *
493 * Since we don't know if the AP has pending frames for us
494 * we can only check for our tx queues and use the current
495 * pm_qos requirements for rx. Hence, if no tx traffic occurs
496 * at all we will scan as many channels in a row as the pm_qos
497 * latency allows us to. Additionally we also check for the
498 * currently negotiated listen interval to prevent losing
499 * frames unnecessarily.
500 *
501 * Otherwise switch back to the operating channel.
571 */ 502 */
572 drv_flush(local, false);
573 if (local->ops->flush)
574 *next_delay = 0;
575 else
576 *next_delay = HZ / 10;
577 503
578 /* remember when we left the operating channel */ 504 bad_latency = time_after(jiffies +
579 local->leave_oper_channel_time = jiffies; 505 ieee80211_scan_get_channel_time(next_chan),
506 local->leave_oper_channel_time +
507 usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
580 508
581 /* advance to the next channel to be scanned */ 509 listen_int_exceeded = time_after(jiffies +
582 local->next_scan_state = SCAN_SET_CHANNEL; 510 ieee80211_scan_get_channel_time(next_chan),
583} 511 local->leave_oper_channel_time +
584 512 usecs_to_jiffies(min_beacon_int * 1024) *
585static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, 513 local->hw.conf.listen_interval);
586 unsigned long *next_delay)
587{
588 /* switch back to the operating channel */
589 local->scan_channel = NULL;
590 if (!ieee80211_cfg_on_oper_channel(local))
591 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
592 514
593 /* 515 if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
594 * Re-enable vifs and beaconing. Leave PS 516 local->next_scan_state = SCAN_SUSPEND;
595 * in off-channel state..will put that back 517 else
596 * on-channel at the end of scanning. 518 local->next_scan_state = SCAN_SET_CHANNEL;
597 */
598 ieee80211_offchannel_return(local, true, false);
599 519
600 *next_delay = HZ / 5; 520 *next_delay = 0;
601 local->next_scan_state = SCAN_DECISION;
602} 521}
603 522
604static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, 523static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -612,10 +531,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
612 531
613 local->scan_channel = chan; 532 local->scan_channel = chan;
614 533
615 /* Only call hw-config if we really need to change channels. */ 534 if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
616 if (chan != local->hw.conf.channel) 535 skip = 1;
617 if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
618 skip = 1;
619 536
620 /* advance state machine to next channel/band */ 537 /* advance state machine to next channel/band */
621 local->scan_channel_idx++; 538 local->scan_channel_idx++;
@@ -672,6 +589,44 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
672 local->next_scan_state = SCAN_DECISION; 589 local->next_scan_state = SCAN_DECISION;
673} 590}
674 591
592static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
593 unsigned long *next_delay)
594{
595 /* switch back to the operating channel */
596 local->scan_channel = NULL;
597 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
598
599 /*
600 * Re-enable vifs and beaconing. Leave PS
601 * in off-channel state..will put that back
602 * on-channel at the end of scanning.
603 */
604 ieee80211_offchannel_return(local, true, false);
605
606 *next_delay = HZ / 5;
607 /* afterwards, resume scan & go to next channel */
608 local->next_scan_state = SCAN_RESUME;
609}
610
611static void ieee80211_scan_state_resume(struct ieee80211_local *local,
612 unsigned long *next_delay)
613{
614 /* PS already is in off-channel mode */
615 ieee80211_offchannel_stop_vifs(local, false);
616
617 if (local->ops->flush) {
618 drv_flush(local, false);
619 *next_delay = 0;
620 } else
621 *next_delay = HZ / 10;
622
623 /* remember when we left the operating channel */
624 local->leave_oper_channel_time = jiffies;
625
626 /* advance to the next channel to be scanned */
627 local->next_scan_state = SCAN_DECISION;
628}
629
675void ieee80211_scan_work(struct work_struct *work) 630void ieee80211_scan_work(struct work_struct *work)
676{ 631{
677 struct ieee80211_local *local = 632 struct ieee80211_local *local =
@@ -742,11 +697,11 @@ void ieee80211_scan_work(struct work_struct *work)
742 case SCAN_SEND_PROBE: 697 case SCAN_SEND_PROBE:
743 ieee80211_scan_state_send_probe(local, &next_delay); 698 ieee80211_scan_state_send_probe(local, &next_delay);
744 break; 699 break;
745 case SCAN_LEAVE_OPER_CHANNEL: 700 case SCAN_SUSPEND:
746 ieee80211_scan_state_leave_oper_channel(local, &next_delay); 701 ieee80211_scan_state_suspend(local, &next_delay);
747 break; 702 break;
748 case SCAN_ENTER_OPER_CHANNEL: 703 case SCAN_RESUME:
749 ieee80211_scan_state_enter_oper_channel(local, &next_delay); 704 ieee80211_scan_state_resume(local, &next_delay);
750 break; 705 break;
751 } 706 }
752 } while (next_delay == 0); 707 } while (next_delay == 0);