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/wifi_provider.h" 18 19 #include <stdlib.h> 20 21 #include <algorithm> 22 #include <limits> 23 #include <set> 24 #include <string> 25 #include <vector> 26 27 #include <base/bind.h> 28 #include <base/format_macros.h> 29 #include <base/strings/string_number_conversions.h> 30 #include <base/strings/string_split.h> 31 #include <base/strings/string_util.h> 32 33 #include "shill/error.h" 34 #include "shill/event_dispatcher.h" 35 #include "shill/key_value_store.h" 36 #include "shill/logging.h" 37 #include "shill/manager.h" 38 #include "shill/metrics.h" 39 #include "shill/net/byte_string.h" 40 #include "shill/net/ieee80211.h" 41 #include "shill/net/shill_time.h" 42 #include "shill/profile.h" 43 #include "shill/store_interface.h" 44 #include "shill/technology.h" 45 #include "shill/wifi/wifi_endpoint.h" 46 #include "shill/wifi/wifi_service.h" 47 48 using base::Bind; 49 using base::SplitString; 50 using base::StringPrintf; 51 using std::set; 52 using std::string; 53 using std::vector; 54 55 namespace shill { 56 57 namespace Logging { 58 static auto kModuleLogScope = ScopeLogger::kWiFi; 59 static string ObjectID(WiFiProvider* w) { return "(wifi_provider)"; } 60 } 61 62 // Note that WiFiProvider generates some manager-level errors, because it 63 // implements the WiFi portion of the Manager.GetService flimflam API. The 64 // API is implemented here, rather than in manager, to keep WiFi-specific 65 // logic in the right place. 66 const char WiFiProvider::kManagerErrorSSIDRequired[] = "must specify SSID"; 67 const char WiFiProvider::kManagerErrorSSIDTooLong[] = "SSID is too long"; 68 const char WiFiProvider::kManagerErrorSSIDTooShort[] = "SSID is too short"; 69 const char WiFiProvider::kManagerErrorUnsupportedSecurityClass[] = 70 "security class is unsupported"; 71 const char WiFiProvider::kManagerErrorUnsupportedSecurityMode[] = 72 "security mode is unsupported"; 73 const char WiFiProvider::kManagerErrorUnsupportedServiceMode[] = 74 "service mode is unsupported"; 75 const char WiFiProvider::kManagerErrorArgumentConflict[] = 76 "provided arguments are inconsistent"; 77 const char WiFiProvider::kFrequencyDelimiter = ':'; 78 const char WiFiProvider::kStartWeekHeader[] = "@"; 79 const time_t WiFiProvider::kIllegalStartWeek = 80 std::numeric_limits<time_t>::max(); 81 const char WiFiProvider::kStorageId[] = "provider_of_wifi"; 82 const char WiFiProvider::kStorageFrequencies[] = "Frequencies"; 83 const int WiFiProvider::kMaxStorageFrequencies = 20; 84 const time_t WiFiProvider::kWeeksToKeepFrequencyCounts = 3; 85 const time_t WiFiProvider::kSecondsPerWeek = 60 * 60 * 24 * 7; 86 87 WiFiProvider::WiFiProvider(ControlInterface* control_interface, 88 EventDispatcher* dispatcher, 89 Metrics* metrics, 90 Manager* manager) 91 : control_interface_(control_interface), 92 dispatcher_(dispatcher), 93 metrics_(metrics), 94 manager_(manager), 95 running_(false), 96 total_frequency_connections_(-1L), 97 time_(Time::GetInstance()), 98 disable_vht_(false) {} 99 100 WiFiProvider::~WiFiProvider() {} 101 102 void WiFiProvider::Start() { 103 running_ = true; 104 } 105 106 void WiFiProvider::Stop() { 107 SLOG(this, 2) << __func__; 108 while (!services_.empty()) { 109 WiFiServiceRefPtr service = services_.back(); 110 ForgetService(service); 111 SLOG(this, 3) << "WiFiProvider deregistering service " 112 << service->unique_name(); 113 manager_->DeregisterService(service); 114 } 115 service_by_endpoint_.clear(); 116 running_ = false; 117 } 118 119 void WiFiProvider::CreateServicesFromProfile(const ProfileRefPtr& profile) { 120 const StoreInterface* storage = profile->GetConstStorage(); 121 KeyValueStore args; 122 args.SetString(kTypeProperty, kTypeWifi); 123 bool created_hidden_service = false; 124 for (const auto& group : storage->GetGroupsWithProperties(args)) { 125 vector<uint8_t> ssid_bytes; 126 string network_mode; 127 string security; 128 bool is_hidden = false; 129 if (!GetServiceParametersFromStorage(storage, 130 group, 131 &ssid_bytes, 132 &network_mode, 133 &security, 134 &is_hidden, 135 nullptr)) { 136 continue; 137 } 138 139 if (FindService(ssid_bytes, network_mode, security)) { 140 // If service already exists, we have nothing to do, since the 141 // service has already loaded its configuration from storage. 142 // This is guaranteed to happen in the single case where 143 // CreateServicesFromProfile() is called on a WiFiProvider from 144 // Manager::PushProfile(): 145 continue; 146 } 147 148 AddService(ssid_bytes, network_mode, security, is_hidden); 149 150 // By registering the service in AddService, the rest of the configuration 151 // will be loaded from the profile into the service via ConfigureService(). 152 153 if (is_hidden) { 154 created_hidden_service = true; 155 } 156 } 157 158 // If WiFi is unconnected and we created a hidden service as a result 159 // of opening the profile, we should initiate a WiFi scan, which will 160 // allow us to find any hidden services that we may have created. 161 if (created_hidden_service && 162 !manager_->IsTechnologyConnected(Technology::kWifi)) { 163 Error unused_error; 164 manager_->RequestScan(Device::kProgressiveScan, kTypeWifi, &unused_error); 165 } 166 167 ReportRememberedNetworkCount(); 168 169 // Only report service source metrics when a user profile is pushed. 170 // This ensures that we have an equal number of samples for the 171 // default profile and user profiles. 172 if (!profile->IsDefault()) { 173 ReportServiceSourceMetrics(); 174 } 175 } 176 177 ServiceRefPtr WiFiProvider::FindSimilarService( 178 const KeyValueStore& args, Error* error) const { 179 vector<uint8_t> ssid; 180 string mode; 181 string security; 182 bool hidden_ssid; 183 184 if (!GetServiceParametersFromArgs( 185 args, &ssid, &mode, &security, &hidden_ssid, error)) { 186 return nullptr; 187 } 188 189 WiFiServiceRefPtr service(FindService(ssid, mode, security)); 190 if (!service) { 191 error->Populate(Error::kNotFound, "Matching service was not found"); 192 } 193 194 return service; 195 } 196 197 ServiceRefPtr WiFiProvider::CreateTemporaryService( 198 const KeyValueStore& args, Error* error) { 199 vector<uint8_t> ssid; 200 string mode; 201 string security; 202 bool hidden_ssid; 203 204 if (!GetServiceParametersFromArgs( 205 args, &ssid, &mode, &security, &hidden_ssid, error)) { 206 return nullptr; 207 } 208 209 return new WiFiService(control_interface_, 210 dispatcher_, 211 metrics_, 212 manager_, 213 this, 214 ssid, 215 mode, 216 security, 217 hidden_ssid); 218 } 219 220 ServiceRefPtr WiFiProvider::CreateTemporaryServiceFromProfile( 221 const ProfileRefPtr& profile, const std::string& entry_name, Error* error) { 222 vector<uint8_t> ssid; 223 string mode; 224 string security; 225 bool hidden_ssid; 226 if (!GetServiceParametersFromStorage(profile->GetConstStorage(), 227 entry_name, 228 &ssid, 229 &mode, 230 &security, 231 &hidden_ssid, 232 error)) { 233 return nullptr; 234 } 235 return new WiFiService(control_interface_, 236 dispatcher_, 237 metrics_, 238 manager_, 239 this, 240 ssid, 241 mode, 242 security, 243 hidden_ssid); 244 } 245 246 ServiceRefPtr WiFiProvider::GetService( 247 const KeyValueStore& args, Error* error) { 248 return GetWiFiService(args, error); 249 } 250 251 WiFiServiceRefPtr WiFiProvider::GetWiFiService( 252 const KeyValueStore& args, Error* error) { 253 vector<uint8_t> ssid_bytes; 254 string mode; 255 string security_method; 256 bool hidden_ssid; 257 258 if (!GetServiceParametersFromArgs( 259 args, &ssid_bytes, &mode, &security_method, &hidden_ssid, error)) { 260 return nullptr; 261 } 262 263 WiFiServiceRefPtr service(FindService(ssid_bytes, mode, security_method)); 264 if (!service) { 265 service = AddService(ssid_bytes, 266 mode, 267 security_method, 268 hidden_ssid); 269 } 270 271 return service; 272 } 273 274 WiFiServiceRefPtr WiFiProvider::FindServiceForEndpoint( 275 const WiFiEndpointConstRefPtr& endpoint) { 276 EndpointServiceMap::iterator service_it = 277 service_by_endpoint_.find(endpoint.get()); 278 if (service_it == service_by_endpoint_.end()) 279 return nullptr; 280 return service_it->second; 281 } 282 283 void WiFiProvider::OnEndpointAdded(const WiFiEndpointConstRefPtr& endpoint) { 284 if (!running_) { 285 return; 286 } 287 288 WiFiServiceRefPtr service = FindService(endpoint->ssid(), 289 endpoint->network_mode(), 290 endpoint->security_mode()); 291 if (!service) { 292 const bool hidden_ssid = false; 293 service = AddService( 294 endpoint->ssid(), 295 endpoint->network_mode(), 296 WiFiService::ComputeSecurityClass(endpoint->security_mode()), 297 hidden_ssid); 298 } 299 300 service->AddEndpoint(endpoint); 301 service_by_endpoint_[endpoint.get()] = service; 302 303 SLOG(this, 1) << "Assigned endpoint " << endpoint->bssid_string() 304 << " to service " << service->unique_name() << "."; 305 306 manager_->UpdateService(service); 307 } 308 309 WiFiServiceRefPtr WiFiProvider::OnEndpointRemoved( 310 const WiFiEndpointConstRefPtr& endpoint) { 311 if (!running_) { 312 return nullptr; 313 } 314 315 WiFiServiceRefPtr service = FindServiceForEndpoint(endpoint); 316 317 CHECK(service) << "Can't find Service for Endpoint " 318 << "(with BSSID " << endpoint->bssid_string() << ")."; 319 SLOG(this, 1) << "Removing endpoint " << endpoint->bssid_string() 320 << " from Service " << service->unique_name(); 321 service->RemoveEndpoint(endpoint); 322 service_by_endpoint_.erase(endpoint.get()); 323 324 if (service->HasEndpoints() || service->IsRemembered()) { 325 // Keep services around if they are in a profile or have remaining 326 // endpoints. 327 manager_->UpdateService(service); 328 return nullptr; 329 } 330 331 ForgetService(service); 332 manager_->DeregisterService(service); 333 334 return service; 335 } 336 337 void WiFiProvider::OnEndpointUpdated(const WiFiEndpointConstRefPtr& endpoint) { 338 if (!running_) { 339 return; 340 } 341 342 WiFiService* service = FindServiceForEndpoint(endpoint).get(); 343 CHECK(service); 344 345 // If the service still matches the endpoint in its new configuration, 346 // we need only to update the service. 347 if (service->ssid() == endpoint->ssid() && 348 service->mode() == endpoint->network_mode() && 349 service->IsSecurityMatch(endpoint->security_mode())) { 350 service->NotifyEndpointUpdated(endpoint); 351 return; 352 } 353 354 // The endpoint no longer matches the associated service. Remove the 355 // endpoint, so current references to the endpoint are reset, then add 356 // it again so it can be associated with a new service. 357 OnEndpointRemoved(endpoint); 358 OnEndpointAdded(endpoint); 359 } 360 361 bool WiFiProvider::OnServiceUnloaded(const WiFiServiceRefPtr& service) { 362 // If the service still has endpoints, it should remain in the service list. 363 if (service->HasEndpoints()) { 364 return false; 365 } 366 367 // This is the one place where we forget the service but do not also 368 // deregister the service with the manager. However, by returning 369 // true below, the manager will do so itself. 370 ForgetService(service); 371 return true; 372 } 373 374 void WiFiProvider::LoadAndFixupServiceEntries(Profile* profile) { 375 CHECK(profile); 376 StoreInterface* storage = profile->GetStorage(); 377 bool is_default_profile = profile->IsDefault(); 378 if (WiFiService::FixupServiceEntries(storage)) { 379 storage->Flush(); 380 Metrics::ServiceFixupProfileType profile_type = 381 is_default_profile ? 382 Metrics::kMetricServiceFixupDefaultProfile : 383 Metrics::kMetricServiceFixupUserProfile; 384 metrics_->SendEnumToUMA( 385 metrics_->GetFullMetricName(Metrics::kMetricServiceFixupEntriesSuffix, 386 Technology::kWifi), 387 profile_type, 388 Metrics::kMetricServiceFixupMax); 389 } 390 // TODO(wdg): Determine how this should be structured for, currently 391 // non-existant, autotests. |kStorageFrequencies| should only exist in the 392 // default profile except for autotests where a test_profile is pushed. This 393 // may need to be modified for that case. 394 if (is_default_profile) { 395 static_assert(kMaxStorageFrequencies > kWeeksToKeepFrequencyCounts, 396 "Persistently storing more frequencies than we can hold"); 397 total_frequency_connections_ = 0L; 398 connect_count_by_frequency_.clear(); 399 time_t this_week = time_->GetSecondsSinceEpoch() / kSecondsPerWeek; 400 for (int freq = 0; freq < kMaxStorageFrequencies; ++freq) { 401 ConnectFrequencyMap connect_count_by_frequency; 402 string freq_string = StringPrintf("%s%d", kStorageFrequencies, freq); 403 vector<string> frequencies; 404 if (!storage->GetStringList(kStorageId, freq_string, &frequencies)) { 405 SLOG(this, 7) << "Frequency list " << freq_string << " not found"; 406 break; 407 } 408 time_t start_week = StringListToFrequencyMap(frequencies, 409 &connect_count_by_frequency); 410 if (start_week == kIllegalStartWeek) { 411 continue; // |StringListToFrequencyMap| will have output an error msg. 412 } 413 414 if (start_week > this_week) { 415 LOG(WARNING) << "Discarding frequency count info from the future"; 416 continue; 417 } 418 connect_count_by_frequency_dated_[start_week] = 419 connect_count_by_frequency; 420 421 for (const auto& freq_count : 422 connect_count_by_frequency_dated_[start_week]) { 423 connect_count_by_frequency_[freq_count.first] += freq_count.second; 424 total_frequency_connections_ += freq_count.second; 425 } 426 } 427 SLOG(this, 7) << __func__ << " - total count=" 428 << total_frequency_connections_; 429 } 430 } 431 432 bool WiFiProvider::Save(StoreInterface* storage) const { 433 int freq = 0; 434 // Iterating backwards since I want to make sure that I get the newest data. 435 ConnectFrequencyMapDated::const_reverse_iterator freq_count; 436 for (freq_count = connect_count_by_frequency_dated_.crbegin(); 437 freq_count != connect_count_by_frequency_dated_.crend(); 438 ++freq_count) { 439 vector<string> frequencies; 440 FrequencyMapToStringList(freq_count->first, freq_count->second, 441 &frequencies); 442 string freq_string = StringPrintf("%s%d", kStorageFrequencies, freq); 443 storage->SetStringList(kStorageId, freq_string, frequencies); 444 if (++freq >= kMaxStorageFrequencies) { 445 LOG(WARNING) << "Internal frequency count list has more entries than the " 446 << "string list we had allocated for it."; 447 break; 448 } 449 } 450 return true; 451 } 452 453 WiFiServiceRefPtr WiFiProvider::AddService(const vector<uint8_t>& ssid, 454 const string& mode, 455 const string& security, 456 bool is_hidden) { 457 WiFiServiceRefPtr service = new WiFiService(control_interface_, 458 dispatcher_, 459 metrics_, 460 manager_, 461 this, 462 ssid, 463 mode, 464 security, 465 is_hidden); 466 467 services_.push_back(service); 468 manager_->RegisterService(service); 469 return service; 470 } 471 472 WiFiServiceRefPtr WiFiProvider::FindService(const vector<uint8_t>& ssid, 473 const string& mode, 474 const string& security) const { 475 for (const auto& service : services_) { 476 if (service->ssid() == ssid && service->mode() == mode && 477 service->IsSecurityMatch(security)) { 478 return service; 479 } 480 } 481 return nullptr; 482 } 483 484 ByteArrays WiFiProvider::GetHiddenSSIDList() { 485 // Create a unique set of hidden SSIDs. 486 set<ByteArray> hidden_ssids_set; 487 for (const auto& service : services_) { 488 if (service->hidden_ssid() && service->IsRemembered()) { 489 hidden_ssids_set.insert(service->ssid()); 490 } 491 } 492 SLOG(this, 2) << "Found " << hidden_ssids_set.size() << " hidden services"; 493 return ByteArrays(hidden_ssids_set.begin(), hidden_ssids_set.end()); 494 } 495 496 void WiFiProvider::ForgetService(const WiFiServiceRefPtr& service) { 497 vector<WiFiServiceRefPtr>::iterator it; 498 it = std::find(services_.begin(), services_.end(), service); 499 if (it == services_.end()) { 500 return; 501 } 502 (*it)->ResetWiFi(); 503 services_.erase(it); 504 } 505 506 void WiFiProvider::ReportRememberedNetworkCount() { 507 metrics_->SendToUMA( 508 Metrics::kMetricRememberedWiFiNetworkCount, 509 std::count_if( 510 services_.begin(), services_.end(), 511 [](ServiceRefPtr s) { return s->IsRemembered(); }), 512 Metrics::kMetricRememberedWiFiNetworkCountMin, 513 Metrics::kMetricRememberedWiFiNetworkCountMax, 514 Metrics::kMetricRememberedWiFiNetworkCountNumBuckets); 515 } 516 517 void WiFiProvider::ReportServiceSourceMetrics() { 518 for (const auto& security_mode : 519 {kSecurityNone, kSecurityWep, kSecurityPsk, kSecurity8021x}) { 520 metrics_->SendToUMA( 521 base::StringPrintf( 522 Metrics:: 523 kMetricRememberedSystemWiFiNetworkCountBySecurityModeFormat, 524 security_mode), 525 std::count_if( 526 services_.begin(), services_.end(), 527 [security_mode](WiFiServiceRefPtr s) { 528 return s->IsRemembered() && s->IsSecurityMatch(security_mode) && 529 s->profile()->IsDefault(); 530 }), 531 Metrics::kMetricRememberedWiFiNetworkCountMin, 532 Metrics::kMetricRememberedWiFiNetworkCountMax, 533 Metrics::kMetricRememberedWiFiNetworkCountNumBuckets); 534 metrics_->SendToUMA( 535 base::StringPrintf( 536 Metrics:: 537 kMetricRememberedUserWiFiNetworkCountBySecurityModeFormat, 538 security_mode), 539 std::count_if( 540 services_.begin(), services_.end(), 541 [security_mode](WiFiServiceRefPtr s) { 542 return s->IsRemembered() && s->IsSecurityMatch(security_mode) && 543 !s->profile()->IsDefault(); 544 }), 545 Metrics::kMetricRememberedWiFiNetworkCountMin, 546 Metrics::kMetricRememberedWiFiNetworkCountMax, 547 Metrics::kMetricRememberedWiFiNetworkCountNumBuckets); 548 } 549 } 550 551 // static 552 bool WiFiProvider::GetServiceParametersFromArgs(const KeyValueStore& args, 553 vector<uint8_t>* ssid_bytes, 554 string* mode, 555 string* security_method, 556 bool* hidden_ssid, 557 Error* error) { 558 CHECK_EQ(args.LookupString(kTypeProperty, ""), kTypeWifi); 559 560 string mode_test = 561 args.LookupString(kModeProperty, kModeManaged); 562 if (!WiFiService::IsValidMode(mode_test)) { 563 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 564 kManagerErrorUnsupportedServiceMode); 565 return false; 566 } 567 568 vector<uint8_t> ssid; 569 if (args.ContainsString(kWifiHexSsid)) { 570 string ssid_hex_string = args.GetString(kWifiHexSsid); 571 if (!base::HexStringToBytes(ssid_hex_string, &ssid)) { 572 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 573 "Hex SSID parameter is not valid"); 574 return false; 575 } 576 } else if (args.ContainsString(kSSIDProperty)) { 577 string ssid_string = args.GetString(kSSIDProperty); 578 ssid = vector<uint8_t>(ssid_string.begin(), ssid_string.end()); 579 } else { 580 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 581 kManagerErrorSSIDRequired); 582 return false; 583 } 584 585 if (ssid.size() < 1) { 586 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidNetworkName, 587 kManagerErrorSSIDTooShort); 588 return false; 589 } 590 591 if (ssid.size() > IEEE_80211::kMaxSSIDLen) { 592 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidNetworkName, 593 kManagerErrorSSIDTooLong); 594 return false; 595 } 596 597 const string kDefaultSecurity = kSecurityNone; 598 if (args.ContainsString(kSecurityProperty) && 599 args.ContainsString(kSecurityClassProperty) && 600 args.LookupString(kSecurityClassProperty, kDefaultSecurity) != 601 args.LookupString(kSecurityProperty, kDefaultSecurity)) { 602 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 603 kManagerErrorArgumentConflict); 604 return false; 605 } 606 if (args.ContainsString(kSecurityClassProperty)) { 607 string security_class_test = 608 args.LookupString(kSecurityClassProperty, kDefaultSecurity); 609 if (!WiFiService::IsValidSecurityClass(security_class_test)) { 610 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 611 kManagerErrorUnsupportedSecurityClass); 612 return false; 613 } 614 *security_method = security_class_test; 615 } else if (args.ContainsString(kSecurityProperty)) { 616 string security_method_test = 617 args.LookupString(kSecurityProperty, kDefaultSecurity); 618 if (!WiFiService::IsValidSecurityMethod(security_method_test)) { 619 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 620 kManagerErrorUnsupportedSecurityMode); 621 return false; 622 } 623 *security_method = security_method_test; 624 } else { 625 *security_method = kDefaultSecurity; 626 } 627 628 *ssid_bytes = ssid; 629 *mode = mode_test; 630 631 // If the caller hasn't specified otherwise, we assume it is a hidden service. 632 *hidden_ssid = args.LookupBool(kWifiHiddenSsid, true); 633 634 return true; 635 } 636 637 // static 638 bool WiFiProvider::GetServiceParametersFromStorage( 639 const StoreInterface* storage, 640 const std::string& entry_name, 641 std::vector<uint8_t>* ssid_bytes, 642 std::string* mode, 643 std::string* security, 644 bool* hidden_ssid, 645 Error* error) { 646 // Verify service type. 647 string type; 648 if (!storage->GetString(entry_name, WiFiService::kStorageType, &type) || 649 type != kTypeWifi) { 650 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 651 "Unspecified or invalid network type"); 652 return false; 653 } 654 string ssid_hex; 655 if (!storage->GetString(entry_name, WiFiService::kStorageSSID, &ssid_hex) || 656 !base::HexStringToBytes(ssid_hex, ssid_bytes)) { 657 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 658 "Unspecified or invalid SSID"); 659 return false; 660 } 661 if (!storage->GetString(entry_name, WiFiService::kStorageMode, mode) || 662 mode->empty()) { 663 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 664 "Network mode not specified"); 665 return false; 666 } 667 if (!storage->GetString(entry_name, WiFiService::kStorageSecurity, security) 668 || !WiFiService::IsValidSecurityMethod(*security)) { 669 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 670 "Unspecified or invalid security mode"); 671 return false; 672 } 673 if (!storage->GetBool( 674 entry_name, WiFiService::kStorageHiddenSSID, hidden_ssid)) { 675 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 676 "Hidden SSID not specified"); 677 return false; 678 } 679 return true; 680 } 681 682 // static 683 time_t WiFiProvider::StringListToFrequencyMap(const vector<string>& strings, 684 ConnectFrequencyMap* numbers) { 685 if (!numbers) { 686 LOG(ERROR) << "Null |numbers| parameter"; 687 return kIllegalStartWeek; 688 } 689 690 // Extract the start week from the first string. 691 vector<string>::const_iterator strings_it = strings.begin(); 692 if (strings_it == strings.end()) { 693 SLOG(nullptr, 7) << "Empty |strings|."; 694 return kIllegalStartWeek; 695 } 696 time_t start_week = GetStringListStartWeek(*strings_it); 697 if (start_week == kIllegalStartWeek) { 698 return kIllegalStartWeek; 699 } 700 701 // Extract the frequency:count values from the remaining strings. 702 for (++strings_it; strings_it != strings.end(); ++strings_it) { 703 ParseStringListFreqCount(*strings_it, numbers); 704 } 705 return start_week; 706 } 707 708 // static 709 time_t WiFiProvider::GetStringListStartWeek(const string& week_string) { 710 if (!base::StartsWith(week_string, kStartWeekHeader, 711 base::CompareCase::INSENSITIVE_ASCII)) { 712 LOG(ERROR) << "Found no leading '" << kStartWeekHeader << "' in '" 713 << week_string << "'"; 714 return kIllegalStartWeek; 715 } 716 return atoll(week_string.c_str() + 1); 717 } 718 719 // static 720 void WiFiProvider::ParseStringListFreqCount(const string& freq_count_string, 721 ConnectFrequencyMap* numbers) { 722 vector<string> freq_count = SplitString( 723 freq_count_string, std::string{kFrequencyDelimiter}, 724 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 725 if (freq_count.size() != 2) { 726 LOG(WARNING) << "Found " << freq_count.size() - 1 << " '" 727 << kFrequencyDelimiter << "' in '" << freq_count_string 728 << "'. Expected 1."; 729 return; 730 } 731 uint16_t freq = atoi(freq_count[0].c_str()); 732 uint64_t connections = atoll(freq_count[1].c_str()); 733 (*numbers)[freq] = connections; 734 } 735 736 // static 737 void WiFiProvider::FrequencyMapToStringList(time_t start_week, 738 const ConnectFrequencyMap& numbers, 739 vector<string>* strings) { 740 if (!strings) { 741 LOG(ERROR) << "Null |strings| parameter"; 742 return; 743 } 744 745 strings->push_back(StringPrintf("%s%" PRIu64, kStartWeekHeader, 746 static_cast<uint64_t>(start_week))); 747 748 for (const auto& freq_conn : numbers) { 749 // Use base::Int64ToString() instead of using something like "%llu" 750 // (not correct for native 64 bit architectures) or PRId64 (does not 751 // work correctly using cros_workon_make due to include intricacies). 752 strings->push_back(StringPrintf("%u%c%s", 753 freq_conn.first, kFrequencyDelimiter, 754 base::Int64ToString(freq_conn.second).c_str())); 755 } 756 } 757 758 void WiFiProvider::IncrementConnectCount(uint16_t frequency_mhz) { 759 CHECK(total_frequency_connections_ < std::numeric_limits<int64_t>::max()); 760 761 ++connect_count_by_frequency_[frequency_mhz]; 762 ++total_frequency_connections_; 763 764 time_t this_week = time_->GetSecondsSinceEpoch() / kSecondsPerWeek; 765 ++connect_count_by_frequency_dated_[this_week][frequency_mhz]; 766 767 ConnectFrequencyMapDated::iterator oldest = 768 connect_count_by_frequency_dated_.begin(); 769 time_t oldest_legal_week = this_week - kWeeksToKeepFrequencyCounts; 770 while (oldest->first < oldest_legal_week) { 771 SLOG(this, 6) << "Discarding frequency count info that's " 772 << this_week - oldest->first << " weeks old"; 773 for (const auto& freq_count : oldest->second) { 774 connect_count_by_frequency_[freq_count.first] -= freq_count.second; 775 if (connect_count_by_frequency_[freq_count.first] <= 0) { 776 connect_count_by_frequency_.erase(freq_count.first); 777 } 778 total_frequency_connections_ -= freq_count.second; 779 } 780 connect_count_by_frequency_dated_.erase(oldest); 781 oldest = connect_count_by_frequency_dated_.begin(); 782 } 783 784 manager_->UpdateWiFiProvider(); 785 metrics_->SendToUMA( 786 Metrics::kMetricFrequenciesConnectedEver, 787 connect_count_by_frequency_.size(), 788 Metrics::kMetricFrequenciesConnectedMin, 789 Metrics::kMetricFrequenciesConnectedMax, 790 Metrics::kMetricFrequenciesConnectedNumBuckets); 791 } 792 793 WiFiProvider::FrequencyCountList WiFiProvider::GetScanFrequencies() const { 794 FrequencyCountList freq_connects_list; 795 for (const auto freq_count : connect_count_by_frequency_) { 796 freq_connects_list.push_back(FrequencyCount(freq_count.first, 797 freq_count.second)); 798 } 799 return freq_connects_list; 800 } 801 802 void WiFiProvider::ReportAutoConnectableServices() { 803 int num_services = NumAutoConnectableServices(); 804 // Only report stats when there are wifi services available. 805 if (num_services) { 806 metrics_->NotifyWifiAutoConnectableServices(num_services); 807 } 808 } 809 810 int WiFiProvider::NumAutoConnectableServices() { 811 const char* reason = nullptr; 812 int num_services = 0; 813 // Determine the number of services available for auto-connect. 814 for (const auto& service : services_) { 815 // Service is available for auto connect if it is configured for auto 816 // connect, and is auto-connectable. 817 if (service->auto_connect() && service->IsAutoConnectable(&reason)) { 818 num_services++; 819 } 820 } 821 return num_services; 822 } 823 824 vector<ByteString> WiFiProvider::GetSsidsConfiguredForAutoConnect() { 825 vector<ByteString> results; 826 for (const auto& service : services_) { 827 if (service->auto_connect()) { 828 // Service configured for auto-connect. 829 ByteString ssid_bytes(service->ssid()); 830 results.push_back(ssid_bytes); 831 } 832 } 833 return results; 834 } 835 836 } // namespace shill 837