diff options
author | Ben Greear <greearb@candelatech.com> | 2012-04-17 13:54:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-23 15:28:33 -0400 |
commit | 8a690674e0601efbe9a7b16a5826fc522645cca3 (patch) | |
tree | c22f122d36d33a2ac446a0626a0fa4213cb9190d /net/mac80211/scan.c | |
parent | e828b9fb4f6c3513950759d5fb902db5bd054048 (diff) |
mac80211: Support on-channel scan option.
This based on an idea posted by Stanislaw Gruszka,
though I accept full blame for the implementation!
This has been tested with ath9k.
The idea is to let users scan on the current operating
channel without interrupting normal traffic more than
absolutely necessary (changing power level might reset
some hardware, for instance).
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r-- | net/mac80211/scan.c | 95 |
1 files changed, 69 insertions, 26 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 45f5aa229efd..8282284f835c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -401,6 +401,30 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) | |||
401 | round_jiffies_relative(0)); | 401 | round_jiffies_relative(0)); |
402 | } | 402 | } |
403 | 403 | ||
404 | static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | ||
405 | unsigned long *next_delay) | ||
406 | { | ||
407 | int i; | ||
408 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
409 | enum ieee80211_band band = local->hw.conf.channel->band; | ||
410 | |||
411 | for (i = 0; i < local->scan_req->n_ssids; i++) | ||
412 | ieee80211_send_probe_req( | ||
413 | sdata, NULL, | ||
414 | local->scan_req->ssids[i].ssid, | ||
415 | local->scan_req->ssids[i].ssid_len, | ||
416 | local->scan_req->ie, local->scan_req->ie_len, | ||
417 | local->scan_req->rates[band], false, | ||
418 | local->scan_req->no_cck); | ||
419 | |||
420 | /* | ||
421 | * After sending probe requests, wait for probe responses | ||
422 | * on the channel. | ||
423 | */ | ||
424 | *next_delay = IEEE80211_CHANNEL_TIME; | ||
425 | local->next_scan_state = SCAN_DECISION; | ||
426 | } | ||
427 | |||
404 | static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | 428 | static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, |
405 | struct cfg80211_scan_request *req) | 429 | struct cfg80211_scan_request *req) |
406 | { | 430 | { |
@@ -451,10 +475,47 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
451 | local->scan_req = req; | 475 | local->scan_req = req; |
452 | local->scan_sdata = sdata; | 476 | local->scan_sdata = sdata; |
453 | 477 | ||
454 | if (local->ops->hw_scan) | 478 | if (local->ops->hw_scan) { |
455 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 479 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
456 | else | 480 | } else if ((req->n_channels == 1) && |
481 | (req->channels[0]->center_freq == | ||
482 | local->hw.conf.channel->center_freq)) { | ||
483 | |||
484 | /* If we are scanning only on the current channel, then | ||
485 | * we do not need to stop normal activities | ||
486 | */ | ||
487 | unsigned long next_delay; | ||
488 | |||
489 | __set_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning); | ||
490 | |||
491 | ieee80211_recalc_idle(local); | ||
492 | |||
493 | /* Notify driver scan is starting, keep order of operations | ||
494 | * same as normal software scan, in case that matters. */ | ||
495 | drv_sw_scan_start(local); | ||
496 | |||
497 | ieee80211_configure_filter(local); /* accept probe-responses */ | ||
498 | |||
499 | /* We need to ensure power level is at max for scanning. */ | ||
500 | ieee80211_hw_config(local, 0); | ||
501 | |||
502 | if ((req->channels[0]->flags & | ||
503 | IEEE80211_CHAN_PASSIVE_SCAN) || | ||
504 | !local->scan_req->n_ssids) { | ||
505 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | ||
506 | } else { | ||
507 | ieee80211_scan_state_send_probe(local, &next_delay); | ||
508 | next_delay = IEEE80211_CHANNEL_TIME; | ||
509 | } | ||
510 | |||
511 | /* Now, just wait a bit and we are all done! */ | ||
512 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, | ||
513 | next_delay); | ||
514 | return 0; | ||
515 | } else { | ||
516 | /* Do normal software scan */ | ||
457 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 517 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
518 | } | ||
458 | 519 | ||
459 | ieee80211_recalc_idle(local); | 520 | ieee80211_recalc_idle(local); |
460 | 521 | ||
@@ -611,30 +672,6 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
611 | local->next_scan_state = SCAN_SEND_PROBE; | 672 | local->next_scan_state = SCAN_SEND_PROBE; |
612 | } | 673 | } |
613 | 674 | ||
614 | static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | ||
615 | unsigned long *next_delay) | ||
616 | { | ||
617 | int i; | ||
618 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
619 | enum ieee80211_band band = local->hw.conf.channel->band; | ||
620 | |||
621 | for (i = 0; i < local->scan_req->n_ssids; i++) | ||
622 | ieee80211_send_probe_req( | ||
623 | sdata, NULL, | ||
624 | local->scan_req->ssids[i].ssid, | ||
625 | local->scan_req->ssids[i].ssid_len, | ||
626 | local->scan_req->ie, local->scan_req->ie_len, | ||
627 | local->scan_req->rates[band], false, | ||
628 | local->scan_req->no_cck); | ||
629 | |||
630 | /* | ||
631 | * After sending probe requests, wait for probe responses | ||
632 | * on the channel. | ||
633 | */ | ||
634 | *next_delay = IEEE80211_CHANNEL_TIME; | ||
635 | local->next_scan_state = SCAN_DECISION; | ||
636 | } | ||
637 | |||
638 | static void ieee80211_scan_state_suspend(struct ieee80211_local *local, | 675 | static void ieee80211_scan_state_suspend(struct ieee80211_local *local, |
639 | unsigned long *next_delay) | 676 | unsigned long *next_delay) |
640 | { | 677 | { |
@@ -685,6 +722,12 @@ void ieee80211_scan_work(struct work_struct *work) | |||
685 | 722 | ||
686 | sdata = local->scan_sdata; | 723 | sdata = local->scan_sdata; |
687 | 724 | ||
725 | /* When scanning on-channel, the first-callback means completed. */ | ||
726 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { | ||
727 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); | ||
728 | goto out_complete; | ||
729 | } | ||
730 | |||
688 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { | 731 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { |
689 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); | 732 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); |
690 | goto out_complete; | 733 | goto out_complete; |