aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2012-04-17 13:54:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-23 15:28:33 -0400
commit8a690674e0601efbe9a7b16a5826fc522645cca3 (patch)
treec22f122d36d33a2ac446a0626a0fa4213cb9190d /net/mac80211
parente828b9fb4f6c3513950759d5fb902db5bd054048 (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')
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/scan.c95
4 files changed, 77 insertions, 27 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index bd7a451b0849..1d074260acd1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -803,6 +803,8 @@ struct tpt_led_trigger {
803 * well be on the operating channel 803 * well be on the operating channel
804 * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to 804 * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
805 * determine if we are on the operating channel or not 805 * determine if we are on the operating channel or not
806 * @SCAN_ONCHANNEL_SCANNING: Do a software scan on only the current operating
807 * channel. This should not interrupt normal traffic.
806 * @SCAN_COMPLETED: Set for our scan work function when the driver reported 808 * @SCAN_COMPLETED: Set for our scan work function when the driver reported
807 * that the scan completed. 809 * that the scan completed.
808 * @SCAN_ABORTED: Set for our scan work function when the driver reported 810 * @SCAN_ABORTED: Set for our scan work function when the driver reported
@@ -811,6 +813,7 @@ struct tpt_led_trigger {
811enum { 813enum {
812 SCAN_SW_SCANNING, 814 SCAN_SW_SCANNING,
813 SCAN_HW_SCANNING, 815 SCAN_HW_SCANNING,
816 SCAN_ONCHANNEL_SCANNING,
814 SCAN_COMPLETED, 817 SCAN_COMPLETED,
815 SCAN_ABORTED, 818 SCAN_ABORTED,
816}; 819};
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ac79d5e8e0d0..b70f7f09da61 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -47,7 +47,8 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
47 if (atomic_read(&local->iff_allmultis)) 47 if (atomic_read(&local->iff_allmultis))
48 new_flags |= FIF_ALLMULTI; 48 new_flags |= FIF_ALLMULTI;
49 49
50 if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning)) 50 if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning) ||
51 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning))
51 new_flags |= FIF_BCN_PRBRESP_PROMISC; 52 new_flags |= FIF_BCN_PRBRESP_PROMISC;
52 53
53 if (local->fif_probe_req || local->probe_req_reg) 54 if (local->fif_probe_req || local->probe_req_reg)
@@ -148,6 +149,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
148 } 149 }
149 150
150 if (test_bit(SCAN_SW_SCANNING, &local->scanning) || 151 if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
152 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
151 test_bit(SCAN_HW_SCANNING, &local->scanning)) 153 test_bit(SCAN_HW_SCANNING, &local->scanning))
152 power = chan->max_power; 154 power = chan->max_power;
153 else 155 else
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 54a049123a60..dd2fbec23eeb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -425,6 +425,7 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
425 425
426 if (test_bit(SCAN_HW_SCANNING, &local->scanning) || 426 if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
427 test_bit(SCAN_SW_SCANNING, &local->scanning) || 427 test_bit(SCAN_SW_SCANNING, &local->scanning) ||
428 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
428 local->sched_scanning) 429 local->sched_scanning)
429 return ieee80211_scan_rx(rx->sdata, skb); 430 return ieee80211_scan_rx(rx->sdata, skb);
430 431
@@ -2915,6 +2916,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2915 local->dot11ReceivedFragmentCount++; 2916 local->dot11ReceivedFragmentCount++;
2916 2917
2917 if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || 2918 if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
2919 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
2918 test_bit(SCAN_SW_SCANNING, &local->scanning))) 2920 test_bit(SCAN_SW_SCANNING, &local->scanning)))
2919 status->rx_flags |= IEEE80211_RX_IN_SCAN; 2921 status->rx_flags |= IEEE80211_RX_IN_SCAN;
2920 2922
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
404static 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
404static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, 428static 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
614static 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
638static void ieee80211_scan_state_suspend(struct ieee80211_local *local, 675static 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;