Home | History | Annotate | Download | only in wifi
      1 //
      2 // Copyright (C) 2013 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/wifi/scan_session.h"
     18 
     19 #include <algorithm>
     20 #include <set>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include <base/bind.h>
     25 #include <base/memory/weak_ptr.h>
     26 #include <base/stl_util.h>
     27 #include <base/strings/stringprintf.h>
     28 
     29 #include "shill/event_dispatcher.h"
     30 #include "shill/logging.h"
     31 #include "shill/metrics.h"
     32 #include "shill/net/netlink_manager.h"
     33 #include "shill/net/netlink_message.h"
     34 #include "shill/net/nl80211_attribute.h"
     35 #include "shill/net/nl80211_message.h"
     36 
     37 using base::Bind;
     38 using base::StringPrintf;
     39 using std::set;
     40 using std::string;
     41 using std::vector;
     42 
     43 namespace shill {
     44 
     45 namespace Logging {
     46 static auto kModuleLogScope = ScopeLogger::kWiFi;
     47 static string ObjectID(ScanSession* s) { return "(scan_session)"; }
     48 }
     49 
     50 const float ScanSession::kAllFrequencies = 1.1;
     51 const uint64_t ScanSession::kScanRetryDelayMilliseconds = 200;  // Arbitrary.
     52 const size_t ScanSession::kScanRetryCount = 50;
     53 
     54 ScanSession::ScanSession(
     55     NetlinkManager* netlink_manager,
     56     EventDispatcher* dispatcher,
     57     const WiFiProvider::FrequencyCountList& previous_frequencies,
     58     const set<uint16_t>& available_frequencies,
     59     uint32_t ifindex,
     60     const FractionList& fractions,
     61     size_t min_frequencies,
     62     size_t max_frequencies,
     63     OnScanFailed on_scan_failed,
     64     Metrics* metrics)
     65     : weak_ptr_factory_(this),
     66       netlink_manager_(netlink_manager),
     67       dispatcher_(dispatcher),
     68       frequency_list_(previous_frequencies),
     69       total_connections_(0),
     70       total_connects_provided_(0),
     71       total_fraction_wanted_(0.0),
     72       wifi_interface_index_(ifindex),
     73       ssids_(ByteString::IsLessThan),
     74       fractions_(fractions),
     75       min_frequencies_(min_frequencies),
     76       max_frequencies_(max_frequencies),
     77       on_scan_failed_(on_scan_failed),
     78       scan_tries_left_(kScanRetryCount),
     79       found_error_(false),
     80       metrics_(metrics) {
     81   sort(frequency_list_.begin(), frequency_list_.end(),
     82        &ScanSession::CompareFrequencyCount);
     83   // Add to |frequency_list_| all the frequencies from |available_frequencies|
     84   // that aren't in |previous_frequencies|.
     85   set<uint16_t> seen_frequencies;
     86   for (const auto& freq_conn : frequency_list_) {
     87     seen_frequencies.insert(freq_conn.frequency);
     88     total_connections_ += freq_conn.connection_count;
     89   }
     90   for (const auto freq : available_frequencies) {
     91     if (!ContainsKey(seen_frequencies, freq)) {
     92       frequency_list_.push_back(WiFiProvider::FrequencyCount(freq, 0));
     93     }
     94   }
     95 
     96   SLOG(this, 6) << "Frequency connections vector:";
     97   for (const auto& freq_conn : frequency_list_) {
     98     SLOG(this, 6) << "    freq[" << freq_conn.frequency << "] = "
     99                   << freq_conn.connection_count;
    100   }
    101 
    102   original_frequency_count_ = frequency_list_.size();
    103   ebusy_timer_.Pause();
    104 }
    105 
    106 ScanSession::~ScanSession() {
    107   const int kLogLevel = 6;
    108   ReportResults(kLogLevel);
    109 }
    110 
    111 bool ScanSession::HasMoreFrequencies() const {
    112   return !frequency_list_.empty();
    113 }
    114 
    115 vector<uint16_t> ScanSession::GetScanFrequencies(float fraction_wanted,
    116                                                  size_t min_frequencies,
    117                                                  size_t max_frequencies) {
    118   DCHECK_GE(fraction_wanted, 0);
    119   total_fraction_wanted_ += fraction_wanted;
    120   float total_connects_wanted = total_fraction_wanted_ * total_connections_;
    121 
    122   vector<uint16_t> frequencies;
    123   WiFiProvider::FrequencyCountList::iterator freq_connect =
    124       frequency_list_.begin();
    125   SLOG(this, 7) << "Scanning for frequencies:";
    126   while (freq_connect != frequency_list_.end()) {
    127     if (frequencies.size() >= min_frequencies) {
    128       if (total_connects_provided_ >= total_connects_wanted)
    129         break;
    130       if (frequencies.size() >= max_frequencies)
    131         break;
    132     }
    133     uint16_t frequency = freq_connect->frequency;
    134     size_t connection_count = freq_connect->connection_count;
    135     total_connects_provided_ += connection_count;
    136     frequencies.push_back(frequency);
    137     SLOG(this, 7) << "    freq[" << frequency << "] = " << connection_count;
    138 
    139     freq_connect = frequency_list_.erase(freq_connect);
    140   }
    141   return frequencies;
    142 }
    143 
    144 void ScanSession::InitiateScan() {
    145   float fraction_wanted = kAllFrequencies;
    146   if (!fractions_.empty()) {
    147     fraction_wanted = fractions_.front();
    148     fractions_.pop_front();
    149   }
    150   current_scan_frequencies_ = GetScanFrequencies(fraction_wanted,
    151                                                  min_frequencies_,
    152                                                  max_frequencies_);
    153   DoScan(current_scan_frequencies_);
    154 }
    155 
    156 void ScanSession::ReInitiateScan() {
    157   ebusy_timer_.Pause();
    158   DoScan(current_scan_frequencies_);
    159 }
    160 
    161 void ScanSession::DoScan(const vector<uint16_t>& scan_frequencies) {
    162   if (scan_frequencies.empty()) {
    163     LOG(INFO) << "Not sending empty frequency list";
    164     return;
    165   }
    166   TriggerScanMessage trigger_scan;
    167   trigger_scan.attributes()->CreateNl80211Attribute(
    168       NL80211_ATTR_SCAN_FREQUENCIES, NetlinkMessage::MessageContext());
    169   trigger_scan.attributes()->CreateNl80211Attribute(
    170       NL80211_ATTR_SCAN_SSIDS, NetlinkMessage::MessageContext());
    171   trigger_scan.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
    172                                                   wifi_interface_index_);
    173   AttributeListRefPtr frequency_list;
    174   if (!trigger_scan.attributes()->GetNestedAttributeList(
    175       NL80211_ATTR_SCAN_FREQUENCIES, &frequency_list) || !frequency_list) {
    176     LOG(FATAL) << "Couldn't get NL80211_ATTR_SCAN_FREQUENCIES.";
    177   }
    178   trigger_scan.attributes()->SetNestedAttributeHasAValue(
    179       NL80211_ATTR_SCAN_FREQUENCIES);
    180 
    181   SLOG(this, 6) << "We have requested scan frequencies:";
    182   string attribute_name;
    183   int i = 0;
    184   for (const auto freq : scan_frequencies) {
    185     SLOG(this, 6) << "  " << freq;
    186     attribute_name = StringPrintf("Frequency-%d", i);
    187     frequency_list->CreateU32Attribute(i, attribute_name.c_str());
    188     frequency_list->SetU32AttributeValue(i, freq);
    189     ++i;
    190   }
    191 
    192   if (!ssids_.empty()) {
    193     AttributeListRefPtr ssid_list;
    194     if (!trigger_scan.attributes()->GetNestedAttributeList(
    195         NL80211_ATTR_SCAN_SSIDS, &ssid_list) || !ssid_list) {
    196       LOG(FATAL) << "Couldn't get NL80211_ATTR_SCAN_SSIDS attribute.";
    197     }
    198     trigger_scan.attributes()->SetNestedAttributeHasAValue(
    199         NL80211_ATTR_SCAN_SSIDS);
    200     int i = 0;
    201     string attribute_name;
    202     for (const auto& ssid : ssids_) {
    203       attribute_name = StringPrintf("NL80211_ATTR_SSID_%d", i);
    204       ssid_list->CreateRawAttribute(i, attribute_name.c_str());
    205       ssid_list->SetRawAttributeValue(i, ssid);
    206       ++i;
    207     }
    208     // Add an empty one at the end so we ask for a broadcast in addition to
    209     // the specific SSIDs.
    210     attribute_name = StringPrintf("NL80211_ATTR_SSID_%d", i);
    211     ssid_list->CreateRawAttribute(i, attribute_name.c_str());
    212     ssid_list->SetRawAttributeValue(i, ByteString());
    213   }
    214   netlink_manager_->SendNl80211Message(
    215       &trigger_scan,
    216       Bind(&ScanSession::OnTriggerScanResponse,
    217            weak_ptr_factory_.GetWeakPtr()),
    218       Bind(&NetlinkManager::OnAckDoNothing),
    219       Bind(&ScanSession::OnTriggerScanErrorResponse,
    220            weak_ptr_factory_.GetWeakPtr()));
    221 }
    222 
    223 void ScanSession::OnTriggerScanResponse(const Nl80211Message& netlink_message) {
    224   LOG(WARNING) << "Didn't expect _this_ netlink message, here:";
    225   netlink_message.Print(0, 0);
    226   on_scan_failed_.Run();
    227   return;
    228 }
    229 
    230 void ScanSession::OnTriggerScanErrorResponse(
    231     NetlinkManager::AuxilliaryMessageType type,
    232     const NetlinkMessage* netlink_message) {
    233   switch (type) {
    234     case NetlinkManager::kErrorFromKernel: {
    235         if (!netlink_message) {
    236           LOG(ERROR) << __func__ << ": Message failed: NetlinkManager Error.";
    237           found_error_ = true;
    238           on_scan_failed_.Run();
    239           break;
    240         }
    241         if (netlink_message->message_type() !=
    242             ErrorAckMessage::GetMessageType()) {
    243           LOG(ERROR) << __func__ << ": Message failed: Not an error.";
    244           found_error_ = true;
    245           on_scan_failed_.Run();
    246           break;
    247         }
    248         const ErrorAckMessage* error_ack_message =
    249             static_cast<const ErrorAckMessage*>(netlink_message);
    250         if (error_ack_message->error()) {
    251           LOG(ERROR) << __func__ << ": Message failed: "
    252                      << error_ack_message->ToString();
    253           if (error_ack_message->error() == EBUSY) {
    254             if (scan_tries_left_ == 0) {
    255               LOG(ERROR) << "Retried progressive scan " << kScanRetryCount
    256                          << " times and failed each time.  Giving up.";
    257               found_error_ = true;
    258               on_scan_failed_.Run();
    259               scan_tries_left_ = kScanRetryCount;
    260               return;
    261             }
    262             --scan_tries_left_;
    263             SLOG(this, 3) << __func__ << " - trying again (" << scan_tries_left_
    264                           << " remaining after this)";
    265             ebusy_timer_.Resume();
    266             dispatcher_->PostDelayedTask(Bind(&ScanSession::ReInitiateScan,
    267                                               weak_ptr_factory_.GetWeakPtr()),
    268                                          kScanRetryDelayMilliseconds);
    269             break;
    270           }
    271           found_error_ = true;
    272           on_scan_failed_.Run();
    273         } else {
    274           SLOG(this, 6) << __func__ << ": Message ACKed";
    275         }
    276       }
    277       break;
    278 
    279     case NetlinkManager::kUnexpectedResponseType:
    280       LOG(ERROR) << "Message not handled by regular message handler:";
    281       if (netlink_message) {
    282         netlink_message->Print(0, 0);
    283       }
    284       found_error_ = true;
    285       on_scan_failed_.Run();
    286       break;
    287 
    288     case NetlinkManager::kTimeoutWaitingForResponse:
    289       // This is actually expected since, in the working case, a trigger scan
    290       // message gets its responses broadcast rather than unicast.
    291       break;
    292 
    293     default:
    294       LOG(ERROR) << "Unexpected auxiliary message type: " << type;
    295       found_error_ = true;
    296       on_scan_failed_.Run();
    297       break;
    298   }
    299 }
    300 
    301 void ScanSession::ReportResults(int log_level) {
    302   SLOG(this, log_level) << "------ ScanSession finished ------";
    303   SLOG(this, log_level) << "Scanned "
    304                         << original_frequency_count_ - frequency_list_.size()
    305                         << " frequencies (" << frequency_list_.size()
    306                         << " remaining)";
    307   if (found_error_) {
    308     SLOG(this, log_level) << "ERROR encountered during scan ("
    309                           << current_scan_frequencies_.size() << " frequencies"
    310                           << " dangling - counted as scanned but, really, not)";
    311   } else {
    312     SLOG(this, log_level) << "No error encountered during scan.";
    313   }
    314 
    315   base::TimeDelta elapsed_time;
    316   ebusy_timer_.GetElapsedTime(&elapsed_time);
    317   if (metrics_) {
    318     metrics_->SendToUMA(Metrics::kMetricWiFiScanTimeInEbusyMilliseconds,
    319                         elapsed_time.InMilliseconds(),
    320                         Metrics::kMetricTimeToScanMillisecondsMin,
    321                         Metrics::kMetricTimeToScanMillisecondsMax,
    322                         Metrics::kMetricTimeToScanMillisecondsNumBuckets);
    323   }
    324   SLOG(this, log_level) << "Spent " << elapsed_time.InMillisecondsRoundedUp()
    325                         << " milliseconds waiting for EBUSY.";
    326 }
    327 
    328 void ScanSession::AddSsid(const ByteString& ssid) {
    329   ssids_.insert(ssid);
    330 }
    331 
    332 // static
    333 bool ScanSession::CompareFrequencyCount(
    334     const WiFiProvider::FrequencyCount& first,
    335     const WiFiProvider::FrequencyCount& second) {
    336   return first.connection_count > second.connection_count;
    337 }
    338 
    339 }  // namespace shill
    340 
    341