aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
commitf8965467f366fd18f01feafb5db10512d7b4422c (patch)
tree3706a9cd779859271ca61b85c63a1bc3f82d626e /net/mac80211/scan.c
parenta26272e5200765691e67d6780e52b32498fdb659 (diff)
parent2ec8c6bb5d8f3a62a79f463525054bae1e3d4487 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1674 commits) qlcnic: adding co maintainer ixgbe: add support for active DA cables ixgbe: dcb, do not tag tc_prio_control frames ixgbe: fix ixgbe_tx_is_paused logic ixgbe: always enable vlan strip/insert when DCB is enabled ixgbe: remove some redundant code in setting FCoE FIP filter ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp ixgbe: fix header len when unsplit packet overflows to data buffer ipv6: Never schedule DAD timer on dead address ipv6: Use POSTDAD state ipv6: Use state_lock to protect ifa state ipv6: Replace inet6_ifaddr->dead with state cxgb4: notify upper drivers if the device is already up when they load cxgb4: keep interrupts available when the ports are brought down cxgb4: fix initial addition of MAC address cnic: Return SPQ credit to bnx2x after ring setup and shutdown. cnic: Convert cnic_local_flags to atomic ops. can: Fix SJA1000 command register writes on SMP systems bridge: fix build for CONFIG_SYSFS disabled ARCNET: Limit com20020 PCI ID matches for SOHARD cards ... Fix up various conflicts with pcmcia tree drivers/net/ {pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and wireless/orinoco/spectrum_cs.c} and feature removal (Documentation/feature-removal-schedule.txt). Also fix a non-content conflict due to pm_qos_requirement getting renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c126
1 files changed, 107 insertions, 19 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 85507bd9e34..e1b0be7a57b 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 <linux/slab.h> 19#include <linux/slab.h>
18#include <net/mac80211.h> 20#include <net/mac80211.h>
19 21
@@ -83,7 +85,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
83{ 85{
84 struct cfg80211_bss *cbss; 86 struct cfg80211_bss *cbss;
85 struct ieee80211_bss *bss; 87 struct ieee80211_bss *bss;
86 int clen; 88 int clen, srlen;
87 s32 signal = 0; 89 s32 signal = 0;
88 90
89 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) 91 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
@@ -112,23 +114,24 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
112 bss->dtim_period = tim_ie->dtim_period; 114 bss->dtim_period = tim_ie->dtim_period;
113 } 115 }
114 116
115 bss->supp_rates_len = 0; 117 /* replace old supported rates if we get new values */
118 srlen = 0;
116 if (elems->supp_rates) { 119 if (elems->supp_rates) {
117 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 120 clen = IEEE80211_MAX_SUPP_RATES;
118 if (clen > elems->supp_rates_len) 121 if (clen > elems->supp_rates_len)
119 clen = elems->supp_rates_len; 122 clen = elems->supp_rates_len;
120 memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates, 123 memcpy(bss->supp_rates, elems->supp_rates, clen);
121 clen); 124 srlen += clen;
122 bss->supp_rates_len += clen;
123 } 125 }
124 if (elems->ext_supp_rates) { 126 if (elems->ext_supp_rates) {
125 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 127 clen = IEEE80211_MAX_SUPP_RATES - srlen;
126 if (clen > elems->ext_supp_rates_len) 128 if (clen > elems->ext_supp_rates_len)
127 clen = elems->ext_supp_rates_len; 129 clen = elems->ext_supp_rates_len;
128 memcpy(&bss->supp_rates[bss->supp_rates_len], 130 memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen);
129 elems->ext_supp_rates, clen); 131 srlen += clen;
130 bss->supp_rates_len += clen;
131 } 132 }
133 if (srlen)
134 bss->supp_rates_len = srlen;
132 135
133 bss->wmm_used = elems->wmm_param || elems->wmm_info; 136 bss->wmm_used = elems->wmm_param || elems->wmm_info;
134 bss->uapsd_supported = is_uapsd_supported(elems); 137 bss->uapsd_supported = is_uapsd_supported(elems);
@@ -246,6 +249,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
246 struct ieee80211_local *local = hw_to_local(hw); 249 struct ieee80211_local *local = hw_to_local(hw);
247 bool was_hw_scan; 250 bool was_hw_scan;
248 251
252 trace_api_scan_completed(local, aborted);
253
249 mutex_lock(&local->scan_mtx); 254 mutex_lock(&local->scan_mtx);
250 255
251 /* 256 /*
@@ -322,6 +327,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
322 327
323 ieee80211_offchannel_stop_beaconing(local); 328 ieee80211_offchannel_stop_beaconing(local);
324 329
330 local->leave_oper_channel_time = 0;
325 local->next_scan_state = SCAN_DECISION; 331 local->next_scan_state = SCAN_DECISION;
326 local->scan_channel_idx = 0; 332 local->scan_channel_idx = 0;
327 333
@@ -406,7 +412,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
406 412
407 if (local->ops->hw_scan) { 413 if (local->ops->hw_scan) {
408 WARN_ON(!ieee80211_prep_hw_scan(local)); 414 WARN_ON(!ieee80211_prep_hw_scan(local));
409 rc = drv_hw_scan(local, local->hw_scan_req); 415 rc = drv_hw_scan(local, sdata, local->hw_scan_req);
410 } else 416 } else
411 rc = ieee80211_start_sw_scan(local); 417 rc = ieee80211_start_sw_scan(local);
412 418
@@ -426,11 +432,28 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
426 return rc; 432 return rc;
427} 433}
428 434
435static unsigned long
436ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
437{
438 /*
439 * TODO: channel switching also consumes quite some time,
440 * add that delay as well to get a better estimation
441 */
442 if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
443 return IEEE80211_PASSIVE_CHANNEL_TIME;
444 return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
445}
446
429static int ieee80211_scan_state_decision(struct ieee80211_local *local, 447static int ieee80211_scan_state_decision(struct ieee80211_local *local,
430 unsigned long *next_delay) 448 unsigned long *next_delay)
431{ 449{
432 bool associated = false; 450 bool associated = false;
451 bool tx_empty = true;
452 bool bad_latency;
453 bool listen_int_exceeded;
454 unsigned long min_beacon_int = 0;
433 struct ieee80211_sub_if_data *sdata; 455 struct ieee80211_sub_if_data *sdata;
456 struct ieee80211_channel *next_chan;
434 457
435 /* if no more bands/channels left, complete scan and advance to the idle state */ 458 /* if no more bands/channels left, complete scan and advance to the idle state */
436 if (local->scan_channel_idx >= local->scan_req->n_channels) { 459 if (local->scan_channel_idx >= local->scan_req->n_channels) {
@@ -438,7 +461,11 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
438 return 1; 461 return 1;
439 } 462 }
440 463
441 /* check if at least one STA interface is associated */ 464 /*
465 * check if at least one STA interface is associated,
466 * check if at least one STA interface has pending tx frames
467 * and grab the lowest used beacon interval
468 */
442 mutex_lock(&local->iflist_mtx); 469 mutex_lock(&local->iflist_mtx);
443 list_for_each_entry(sdata, &local->interfaces, list) { 470 list_for_each_entry(sdata, &local->interfaces, list) {
444 if (!ieee80211_sdata_running(sdata)) 471 if (!ieee80211_sdata_running(sdata))
@@ -447,7 +474,16 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
447 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 474 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
448 if (sdata->u.mgd.associated) { 475 if (sdata->u.mgd.associated) {
449 associated = true; 476 associated = true;
450 break; 477
478 if (sdata->vif.bss_conf.beacon_int <
479 min_beacon_int || min_beacon_int == 0)
480 min_beacon_int =
481 sdata->vif.bss_conf.beacon_int;
482
483 if (!qdisc_all_tx_empty(sdata->dev)) {
484 tx_empty = false;
485 break;
486 }
451 } 487 }
452 } 488 }
453 } 489 }
@@ -456,11 +492,34 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
456 if (local->scan_channel) { 492 if (local->scan_channel) {
457 /* 493 /*
458 * we're currently scanning a different channel, let's 494 * we're currently scanning a different channel, let's
459 * switch back to the operating channel now if at least 495 * see if we can scan another channel without interfering
460 * one interface is associated. Otherwise just scan the 496 * with the current traffic situation.
461 * next channel 497 *
498 * Since we don't know if the AP has pending frames for us
499 * we can only check for our tx queues and use the current
500 * pm_qos requirements for rx. Hence, if no tx traffic occurs
501 * at all we will scan as many channels in a row as the pm_qos
502 * latency allows us to. Additionally we also check for the
503 * currently negotiated listen interval to prevent losing
504 * frames unnecessarily.
505 *
506 * Otherwise switch back to the operating channel.
462 */ 507 */
463 if (associated) 508 next_chan = local->scan_req->channels[local->scan_channel_idx];
509
510 bad_latency = time_after(jiffies +
511 ieee80211_scan_get_channel_time(next_chan),
512 local->leave_oper_channel_time +
513 usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
514
515 listen_int_exceeded = time_after(jiffies +
516 ieee80211_scan_get_channel_time(next_chan),
517 local->leave_oper_channel_time +
518 usecs_to_jiffies(min_beacon_int * 1024) *
519 local->hw.conf.listen_interval);
520
521 if (associated && ( !tx_empty || bad_latency ||
522 listen_int_exceeded))
464 local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; 523 local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
465 else 524 else
466 local->next_scan_state = SCAN_SET_CHANNEL; 525 local->next_scan_state = SCAN_SET_CHANNEL;
@@ -492,6 +551,9 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
492 else 551 else
493 *next_delay = HZ / 10; 552 *next_delay = HZ / 10;
494 553
554 /* remember when we left the operating channel */
555 local->leave_oper_channel_time = jiffies;
556
495 /* advance to the next channel to be scanned */ 557 /* advance to the next channel to be scanned */
496 local->next_scan_state = SCAN_SET_CHANNEL; 558 local->next_scan_state = SCAN_SET_CHANNEL;
497} 559}
@@ -594,7 +656,7 @@ void ieee80211_scan_work(struct work_struct *work)
594 } 656 }
595 657
596 if (local->hw_scan_req) { 658 if (local->hw_scan_req) {
597 int rc = drv_hw_scan(local, local->hw_scan_req); 659 int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
598 mutex_unlock(&local->scan_mtx); 660 mutex_unlock(&local->scan_mtx);
599 if (rc) 661 if (rc)
600 ieee80211_scan_completed(&local->hw, true); 662 ieee80211_scan_completed(&local->hw, true);
@@ -667,10 +729,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
667} 729}
668 730
669int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, 731int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
670 const u8 *ssid, u8 ssid_len) 732 const u8 *ssid, u8 ssid_len,
733 struct ieee80211_channel *chan)
671{ 734{
672 struct ieee80211_local *local = sdata->local; 735 struct ieee80211_local *local = sdata->local;
673 int ret = -EBUSY; 736 int ret = -EBUSY;
737 enum nl80211_band band;
674 738
675 mutex_lock(&local->scan_mtx); 739 mutex_lock(&local->scan_mtx);
676 740
@@ -678,6 +742,30 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
678 if (local->scan_req) 742 if (local->scan_req)
679 goto unlock; 743 goto unlock;
680 744
745 /* fill internal scan request */
746 if (!chan) {
747 int i, nchan = 0;
748
749 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
750 if (!local->hw.wiphy->bands[band])
751 continue;
752 for (i = 0;
753 i < local->hw.wiphy->bands[band]->n_channels;
754 i++) {
755 local->int_scan_req->channels[nchan] =
756 &local->hw.wiphy->bands[band]->channels[i];
757 nchan++;
758 }
759 }
760
761 local->int_scan_req->n_channels = nchan;
762 } else {
763 local->int_scan_req->channels[0] = chan;
764 local->int_scan_req->n_channels = 1;
765 }
766
767 local->int_scan_req->ssids = &local->scan_ssid;
768 local->int_scan_req->n_ssids = 1;
681 memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); 769 memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
682 local->int_scan_req->ssids[0].ssid_len = ssid_len; 770 local->int_scan_req->ssids[0].ssid_len = ssid_len;
683 771