aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorHelmut Schaa <Helmut.Schaa@gmx.de>2010-02-24 08:19:21 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-09 15:03:07 -0500
commitdf13cce53a7b28a81460e6bfc4857e9df4956141 (patch)
tree5c7be2b33088f457b0510e7de660a88b8dc9c397 /net/mac80211/scan.c
parent74bad5cb497080514c4a945f38589bdb574fdfb7 (diff)
mac80211: Improve software scan timing
The current software scan implemenation in mac80211 returns to the operating channel after each scanned channel. However, in some situations (e.g. no traffic) it would be nicer to scan a few channels in a row to speed up the scan itself. Hence, after scanning a channel, check if we have queued up any tx frames and return to the operating channel in that case. Unfortunately we don't know if the AP has buffered any frames for us. Hence, scan only as many channels in a row as the pm_qos latency and the negotiated listen interval allows us to. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c71
1 files changed, 65 insertions, 6 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index b822dce97867..75a85978c3b3 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -14,6 +14,8 @@
14 14
15#include <linux/if_arp.h> 15#include <linux/if_arp.h>
16#include <linux/rtnetlink.h> 16#include <linux/rtnetlink.h>
17#include <linux/pm_qos_params.h>
18#include <net/sch_generic.h>
17#include <net/mac80211.h> 19#include <net/mac80211.h>
18 20
19#include "ieee80211_i.h" 21#include "ieee80211_i.h"
@@ -321,6 +323,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
321 323
322 ieee80211_offchannel_stop_beaconing(local); 324 ieee80211_offchannel_stop_beaconing(local);
323 325
326 local->leave_oper_channel_time = 0;
324 local->next_scan_state = SCAN_DECISION; 327 local->next_scan_state = SCAN_DECISION;
325 local->scan_channel_idx = 0; 328 local->scan_channel_idx = 0;
326 329
@@ -425,11 +428,28 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
425 return rc; 428 return rc;
426} 429}
427 430
431static unsigned long
432ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
433{
434 /*
435 * TODO: channel switching also consumes quite some time,
436 * add that delay as well to get a better estimation
437 */
438 if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
439 return IEEE80211_PASSIVE_CHANNEL_TIME;
440 return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
441}
442
428static int ieee80211_scan_state_decision(struct ieee80211_local *local, 443static int ieee80211_scan_state_decision(struct ieee80211_local *local,
429 unsigned long *next_delay) 444 unsigned long *next_delay)
430{ 445{
431 bool associated = false; 446 bool associated = false;
447 bool tx_empty = true;
448 bool bad_latency;
449 bool listen_int_exceeded;
450 unsigned long min_beacon_int = 0;
432 struct ieee80211_sub_if_data *sdata; 451 struct ieee80211_sub_if_data *sdata;
452 struct ieee80211_channel *next_chan;
433 453
434 /* if no more bands/channels left, complete scan and advance to the idle state */ 454 /* if no more bands/channels left, complete scan and advance to the idle state */
435 if (local->scan_channel_idx >= local->scan_req->n_channels) { 455 if (local->scan_channel_idx >= local->scan_req->n_channels) {
@@ -437,7 +457,11 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
437 return 1; 457 return 1;
438 } 458 }
439 459
440 /* check if at least one STA interface is associated */ 460 /*
461 * check if at least one STA interface is associated,
462 * check if at least one STA interface has pending tx frames
463 * and grab the lowest used beacon interval
464 */
441 mutex_lock(&local->iflist_mtx); 465 mutex_lock(&local->iflist_mtx);
442 list_for_each_entry(sdata, &local->interfaces, list) { 466 list_for_each_entry(sdata, &local->interfaces, list) {
443 if (!ieee80211_sdata_running(sdata)) 467 if (!ieee80211_sdata_running(sdata))
@@ -446,7 +470,16 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
446 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 470 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
447 if (sdata->u.mgd.associated) { 471 if (sdata->u.mgd.associated) {
448 associated = true; 472 associated = true;
449 break; 473
474 if (sdata->vif.bss_conf.beacon_int <
475 min_beacon_int || min_beacon_int == 0)
476 min_beacon_int =
477 sdata->vif.bss_conf.beacon_int;
478
479 if (!qdisc_all_tx_empty(sdata->dev)) {
480 tx_empty = false;
481 break;
482 }
450 } 483 }
451 } 484 }
452 } 485 }
@@ -455,11 +488,34 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
455 if (local->scan_channel) { 488 if (local->scan_channel) {
456 /* 489 /*
457 * we're currently scanning a different channel, let's 490 * we're currently scanning a different channel, let's
458 * switch back to the operating channel now if at least 491 * see if we can scan another channel without interfering
459 * one interface is associated. Otherwise just scan the 492 * with the current traffic situation.
460 * next channel 493 *
494 * Since we don't know if the AP has pending frames for us
495 * we can only check for our tx queues and use the current
496 * pm_qos requirements for rx. Hence, if no tx traffic occurs
497 * at all we will scan as many channels in a row as the pm_qos
498 * latency allows us to. Additionally we also check for the
499 * currently negotiated listen interval to prevent losing
500 * frames unnecessarily.
501 *
502 * Otherwise switch back to the operating channel.
461 */ 503 */
462 if (associated) 504 next_chan = local->scan_req->channels[local->scan_channel_idx];
505
506 bad_latency = time_after(jiffies +
507 ieee80211_scan_get_channel_time(next_chan),
508 local->leave_oper_channel_time +
509 usecs_to_jiffies(pm_qos_requirement(PM_QOS_NETWORK_LATENCY)));
510
511 listen_int_exceeded = time_after(jiffies +
512 ieee80211_scan_get_channel_time(next_chan),
513 local->leave_oper_channel_time +
514 usecs_to_jiffies(min_beacon_int * 1024) *
515 local->hw.conf.listen_interval);
516
517 if (associated && ( !tx_empty || bad_latency ||
518 listen_int_exceeded))
463 local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; 519 local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
464 else 520 else
465 local->next_scan_state = SCAN_SET_CHANNEL; 521 local->next_scan_state = SCAN_SET_CHANNEL;
@@ -491,6 +547,9 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
491 else 547 else
492 *next_delay = HZ / 10; 548 *next_delay = HZ / 10;
493 549
550 /* remember when we left the operating channel */
551 local->leave_oper_channel_time = jiffies;
552
494 /* advance to the next channel to be scanned */ 553 /* advance to the next channel to be scanned */
495 local->next_scan_state = SCAN_SET_CHANNEL; 554 local->next_scan_state = SCAN_SET_CHANNEL;
496} 555}