• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 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_service.h"
18 
19 #include <algorithm>
20 #include <limits>
21 #include <string>
22 #include <utility>
23 
24 #include <base/strings/stringprintf.h>
25 #include <base/strings/string_number_conversions.h>
26 #include <base/strings/string_split.h>
27 #include <base/strings/string_util.h>
28 #if defined(__ANDROID__)
29 #include <dbus/service_constants.h>
30 #else
31 #include <chromeos/dbus/service_constants.h>
32 #endif  // __ANDROID__
33 
34 #include "shill/adaptor_interfaces.h"
35 #include "shill/certificate_file.h"
36 #include "shill/control_interface.h"
37 #include "shill/device.h"
38 #include "shill/eap_credentials.h"
39 #include "shill/error.h"
40 #include "shill/event_dispatcher.h"
41 #include "shill/logging.h"
42 #include "shill/manager.h"
43 #include "shill/metrics.h"
44 #include "shill/net/ieee80211.h"
45 #include "shill/property_accessor.h"
46 #include "shill/store_interface.h"
47 #include "shill/supplicant/wpa_supplicant.h"
48 #include "shill/wifi/wifi.h"
49 #include "shill/wifi/wifi_endpoint.h"
50 #include "shill/wifi/wifi_provider.h"
51 
52 using std::map;
53 using std::set;
54 using std::string;
55 using std::vector;
56 
57 namespace shill {
58 
59 namespace Logging {
60 static auto kModuleLogScope = ScopeLogger::kService;
ObjectID(const WiFiService * w)61 static string ObjectID(const WiFiService* w) { return w->GetRpcIdentifier(); }
62 }
63 
64 const char WiFiService::kAutoConnNoEndpoint[] = "no endpoints";
65 const char WiFiService::kAnyDeviceAddress[] = "any";
66 const int WiFiService::kSuspectedCredentialFailureThreshold = 3;
67 
68 const char WiFiService::kStorageHiddenSSID[] = "WiFi.HiddenSSID";
69 const char WiFiService::kStorageMode[] = "WiFi.Mode";
70 const char WiFiService::kStoragePassphrase[] = "Passphrase";
71 const char WiFiService::kStorageSecurity[] = "WiFi.Security";
72 const char WiFiService::kStorageSecurityClass[] = "WiFi.SecurityClass";
73 const char WiFiService::kStorageSSID[] = "SSID";
74 const char WiFiService::kStoragePreferredDevice[] = "WiFi.PreferredDevice";
75 const char WiFiService::kStorageRoamThreshold[] = "WiFi.RoamThreshold";
76 const char WiFiService::kStorageRoamThresholdSet[] = "WiFi.RoamThresholdSet";
77 
78 bool WiFiService::logged_signal_warning = false;
79 
WiFiService(ControlInterface * control_interface,EventDispatcher * dispatcher,Metrics * metrics,Manager * manager,WiFiProvider * provider,const vector<uint8_t> & ssid,const string & mode,const string & security,bool hidden_ssid)80 WiFiService::WiFiService(ControlInterface* control_interface,
81                          EventDispatcher* dispatcher,
82                          Metrics* metrics,
83                          Manager* manager,
84                          WiFiProvider* provider,
85                          const vector<uint8_t>& ssid,
86                          const string& mode,
87                          const string& security,
88                          bool hidden_ssid)
89     : Service(control_interface, dispatcher, metrics, manager,
90               Technology::kWifi),
91       need_passphrase_(false),
92       security_(security),
93       mode_(mode),
94       hidden_ssid_(hidden_ssid),
95       frequency_(0),
96       physical_mode_(Metrics::kWiFiNetworkPhyModeUndef),
97       raw_signal_strength_(0),
98       cipher_8021x_(kCryptoNone),
99       suspected_credential_failures_(0),
100       ssid_(ssid),
101       ieee80211w_required_(false),
102       expecting_disconnect_(false),
103       certificate_file_(new CertificateFile()),
104       roam_threshold_db_(0),
105       roam_threshold_db_set_(false),
106       provider_(provider) {
107   PropertyStore* store = this->mutable_store();
108   store->RegisterConstString(kModeProperty, &mode_);
109   HelpRegisterWriteOnlyDerivedString(kPassphraseProperty,
110                                      &WiFiService::SetPassphrase,
111                                      &WiFiService::ClearPassphrase,
112                                      nullptr);
113   store->RegisterBool(kPassphraseRequiredProperty, &need_passphrase_);
114   HelpRegisterConstDerivedString(kSecurityProperty,
115                                  &WiFiService::GetSecurity);
116   HelpRegisterConstDerivedString(kSecurityClassProperty,
117                                  &WiFiService::GetSecurityClass);
118 
119   store->RegisterConstString(kWifiAuthMode, &auth_mode_);
120   store->RegisterBool(kWifiHiddenSsid, &hidden_ssid_);
121   store->RegisterConstUint16(kWifiFrequency, &frequency_);
122   store->RegisterConstUint16s(kWifiFrequencyListProperty, &frequency_list_);
123   store->RegisterConstUint16(kWifiPhyMode, &physical_mode_);
124   store->RegisterConstString(kWifiBSsid, &bssid_);
125   store->RegisterConstString(kCountryProperty, &country_code_);
126   store->RegisterConstStringmap(kWifiVendorInformationProperty,
127                                 &vendor_information_);
128   store->RegisterConstBool(kWifiProtectedManagementFrameRequiredProperty,
129                            &ieee80211w_required_);
130 
131   hex_ssid_ = base::HexEncode(ssid_.data(), ssid_.size());
132   store->RegisterConstString(kWifiHexSsid, &hex_ssid_);
133   HelpRegisterDerivedString(kWifiPreferredDeviceProperty,
134                             &WiFiService::GetPreferredDevice,
135                             &WiFiService::SetPreferredDevice);
136   HelpRegisterDerivedUint16(kWifiRoamThresholdProperty,
137                             &WiFiService::GetRoamThreshold,
138                             &WiFiService::SetRoamThreshold,
139                             &WiFiService::ClearRoamThreshold);
140 
141   string ssid_string(
142       reinterpret_cast<const char*>(ssid_.data()), ssid_.size());
143   WiFi::SanitizeSSID(&ssid_string);
144   set_friendly_name(ssid_string);
145 
146   SetEapCredentials(new EapCredentials());
147 
148   // TODO(quiche): determine if it is okay to set EAP.KeyManagement for
149   // a service that is not 802.1x.
150   if (Is8021x()) {
151     // Passphrases are not mandatory for 802.1X.
152     need_passphrase_ = false;
153   } else if (security_ == kSecurityPsk) {
154     SetEAPKeyManagement("WPA-PSK");
155   } else if (security_ == kSecurityRsn) {
156     SetEAPKeyManagement("WPA-PSK");
157   } else if (security_ == kSecurityWpa) {
158     SetEAPKeyManagement("WPA-PSK");
159   } else if (security_ == kSecurityWep) {
160     SetEAPKeyManagement("NONE");
161   } else if (security_ == kSecurityNone) {
162     SetEAPKeyManagement("NONE");
163   } else {
164     LOG(ERROR) << "Unsupported security method " << security_;
165   }
166 
167   // Until we know better (at Profile load time), use the generic name.
168   storage_identifier_ = GetDefaultStorageIdentifier();
169   UpdateConnectable();
170   UpdateSecurity();
171 
172   // Now that |this| is a fully constructed WiFiService, synchronize observers
173   // with our current state, and emit the appropriate change notifications.
174   // (Initial observer state may have been set in our base class.)
175   NotifyPropertyChanges();
176 
177   IgnoreParameterForConfigure(kModeProperty);
178   IgnoreParameterForConfigure(kSSIDProperty);
179   IgnoreParameterForConfigure(kSecurityProperty);
180   IgnoreParameterForConfigure(kSecurityClassProperty);
181   IgnoreParameterForConfigure(kWifiHexSsid);
182 
183   InitializeCustomMetrics();
184 
185   // Log the |unique_name| to |friendly_name| mapping for debugging purposes.
186   // The latter will be tagged for scrubbing.
187   LOG(INFO) << "Constructed WiFi service " << unique_name()
188             << " name: " << WiFi::LogSSID(friendly_name());
189 }
190 
~WiFiService()191 WiFiService::~WiFiService() {}
192 
IsAutoConnectable(const char ** reason) const193 bool WiFiService::IsAutoConnectable(const char** reason) const {
194   if (!Service::IsAutoConnectable(reason)) {
195     return false;
196   }
197 
198   // Only auto-connect to Services which have visible Endpoints.
199   // (Needed because hidden Services may remain registered with
200   // Manager even without visible Endpoints.)
201   if (!HasEndpoints()) {
202     *reason = kAutoConnNoEndpoint;
203     return false;
204   }
205 
206   CHECK(wifi_) << "We have endpoints but no WiFi device is selected?";
207 
208   // Do not preempt an existing connection (whether pending, or
209   // connected, and whether to this service, or another).
210   if (!wifi_->IsIdle()) {
211     *reason = kAutoConnBusy;
212     return false;
213   }
214 
215   return true;
216 }
217 
SetEAPKeyManagement(const string & key_management)218 void WiFiService::SetEAPKeyManagement(const string& key_management) {
219   Service::SetEAPKeyManagement(key_management);
220   UpdateSecurity();
221 }
222 
AddEndpoint(const WiFiEndpointConstRefPtr & endpoint)223 void WiFiService::AddEndpoint(const WiFiEndpointConstRefPtr& endpoint) {
224   DCHECK(endpoint->ssid() == ssid());
225   endpoints_.insert(endpoint);
226   UpdateFromEndpoints();
227 }
228 
RemoveEndpoint(const WiFiEndpointConstRefPtr & endpoint)229 void WiFiService::RemoveEndpoint(const WiFiEndpointConstRefPtr& endpoint) {
230   set<WiFiEndpointConstRefPtr>::iterator i = endpoints_.find(endpoint);
231   DCHECK(i != endpoints_.end());
232   if (i == endpoints_.end()) {
233     LOG(WARNING) << "In " << __func__ << "(): "
234                  << "ignoring non-existent endpoint "
235                  << endpoint->bssid_string();
236     return;
237   }
238   endpoints_.erase(i);
239   if (current_endpoint_ == endpoint) {
240     current_endpoint_ = nullptr;
241   }
242   UpdateFromEndpoints();
243 }
244 
NotifyCurrentEndpoint(const WiFiEndpointConstRefPtr & endpoint)245 void WiFiService::NotifyCurrentEndpoint(
246     const WiFiEndpointConstRefPtr& endpoint) {
247   DCHECK(!endpoint || (endpoints_.find(endpoint) != endpoints_.end()));
248   current_endpoint_ = endpoint;
249   UpdateFromEndpoints();
250 }
251 
NotifyEndpointUpdated(const WiFiEndpointConstRefPtr & endpoint)252 void WiFiService::NotifyEndpointUpdated(
253     const WiFiEndpointConstRefPtr& endpoint) {
254   DCHECK(endpoints_.find(endpoint) != endpoints_.end());
255   UpdateFromEndpoints();
256 }
257 
GetStorageIdentifier() const258 string WiFiService::GetStorageIdentifier() const {
259   return storage_identifier_;
260 }
261 
SetPassphrase(const string & passphrase,Error * error)262 bool WiFiService::SetPassphrase(const string& passphrase, Error* error) {
263   if (security_ == kSecurityWep) {
264     ValidateWEPPassphrase(passphrase, error);
265   } else if (security_ == kSecurityPsk ||
266              security_ == kSecurityWpa ||
267              security_ == kSecurityRsn) {
268     ValidateWPAPassphrase(passphrase, error);
269   } else {
270     error->Populate(Error::kNotSupported);
271   }
272 
273   if (!error->IsSuccess()) {
274     LOG(ERROR) << "Passphrase could not be set: " << error->message();
275     return false;
276   }
277 
278   return SetPassphraseInternal(passphrase, Service::kReasonPropertyUpdate);
279 }
280 
SetPassphraseInternal(const string & passphrase,Service::UpdateCredentialsReason reason)281 bool WiFiService::SetPassphraseInternal(
282     const string& passphrase,
283     Service::UpdateCredentialsReason reason) {
284   if (passphrase_ == passphrase) {
285     // After a user logs in, Chrome may reconfigure a Service with the
286     // same credentials as before login. When that occurs, we don't
287     // want to bump the user off the network. Hence, we MUST return
288     // early. (See crbug.com/231456#c17)
289     return false;
290   }
291   passphrase_ = passphrase;
292   OnCredentialChange(reason);
293   return true;
294 }
295 
296 // ClearPassphrase is separate from SetPassphrase, because the default
297 // value for |passphrase_| would not pass validation.
ClearPassphrase(Error *)298 void WiFiService::ClearPassphrase(Error* /*error*/) {
299   passphrase_.clear();
300   ClearCachedCredentials();
301   UpdateConnectable();
302 }
303 
GetPreferredDevice(Error *)304 string WiFiService::GetPreferredDevice(Error* /*error*/) {
305   return preferred_device_;
306 }
307 
SetPreferredDevice(const string & device_name,Error *)308 bool WiFiService::SetPreferredDevice(const string& device_name,
309                                      Error* /*error*/) {
310   // Reset device if it is not the preferred device.
311   if (!device_name.empty() && wifi_ && wifi_->link_name() != device_name) {
312     ResetWiFi();
313   }
314   preferred_device_ = device_name;
315   return true;
316 }
317 
GetTethering(Error *) const318 string WiFiService::GetTethering(Error* /*error*/) const {
319   if (IsConnected() && wifi_ && wifi_->IsConnectedViaTether()) {
320     return kTetheringConfirmedState;
321   }
322 
323   // Only perform BSSID tests if there is exactly one matching endpoint,
324   // so we ignore campuses that may use locally administered BSSIDs.
325   if (endpoints_.size() == 1 &&
326       (*endpoints_.begin())->has_tethering_signature()) {
327     return kTetheringSuspectedState;
328   }
329 
330   return kTetheringNotDetectedState;
331 }
332 
GetLoadableStorageIdentifier(const StoreInterface & storage) const333 string WiFiService::GetLoadableStorageIdentifier(
334     const StoreInterface& storage) const {
335   set<string> groups = storage.GetGroupsWithProperties(GetStorageProperties());
336   if (groups.empty()) {
337     LOG(WARNING) << "Configuration for service "
338                  << unique_name()
339                  << " is not available in the persistent store";
340     return "";
341   }
342   if (groups.size() > 1) {
343     LOG(WARNING) << "More than one configuration for service "
344                  << unique_name()
345                  << " is available; choosing the first.";
346   }
347   return *groups.begin();
348 }
349 
IsLoadableFrom(const StoreInterface & storage) const350 bool WiFiService::IsLoadableFrom(const StoreInterface& storage) const {
351   return !storage.GetGroupsWithProperties(GetStorageProperties()).empty();
352 }
353 
IsVisible() const354 bool WiFiService::IsVisible() const {
355   // WiFi Services should be displayed only if they are in range (have
356   // endpoints that have shown up in a scan) or if the service is actively
357   // being connected.
358   return HasEndpoints() || IsConnected() || IsConnecting();
359 }
360 
Load(StoreInterface * storage)361 bool WiFiService::Load(StoreInterface* storage) {
362   string id = GetLoadableStorageIdentifier(*storage);
363   if (id.empty()) {
364     return false;
365   }
366 
367   // Set our storage identifier to match the storage name in the Profile.
368   storage_identifier_ = id;
369 
370   // Load properties common to all Services.
371   if (!Service::Load(storage)) {
372     return false;
373   }
374 
375   // Load properties specific to WiFi services.
376   storage->GetBool(id, kStorageHiddenSSID, &hidden_ssid_);
377 
378   // NB: mode, security and ssid parameters are never read in from
379   // Load() as they are provided from the scan.
380 
381   string passphrase;
382   if (storage->GetCryptedString(id, kStoragePassphrase, &passphrase)) {
383     if (SetPassphraseInternal(passphrase, Service::kReasonCredentialsLoaded)) {
384       SLOG(this, 3) << "Loaded passphrase in WiFiService::Load.";
385     }
386   }
387 
388   string preferred_device;
389   storage->GetString(id, kStoragePreferredDevice, &preferred_device);
390   SetPreferredDevice(preferred_device, nullptr);
391 
392   uint64_t stored_roam_threshold_temp;
393   storage->GetUint64(id, kStorageRoamThreshold, &stored_roam_threshold_temp);
394   // Storing a uint64_t in a uint16_t is safe here since we know that we only
395   // set this storage value to a uint16_t value in WiFiService::Save.
396   roam_threshold_db_ = static_cast<uint16_t>(stored_roam_threshold_temp);
397   storage->GetBool(id, kStorageRoamThresholdSet, &roam_threshold_db_set_);
398 
399   expecting_disconnect_ = false;
400   return true;
401 }
402 
Save(StoreInterface * storage)403 bool WiFiService::Save(StoreInterface* storage) {
404   // Save properties common to all Services.
405   if (!Service::Save(storage)) {
406     return false;
407   }
408 
409   // Save properties specific to WiFi services.
410   const string id = GetStorageIdentifier();
411   storage->SetBool(id, kStorageHiddenSSID, hidden_ssid_);
412   storage->SetString(id, kStorageMode, mode_);
413   storage->SetCryptedString(id, kStoragePassphrase, passphrase_);
414   storage->SetString(id, kStorageSecurity, security_);
415   storage->SetString(id, kStorageSecurityClass,
416                      ComputeSecurityClass(security_));
417   storage->SetString(id, kStorageSSID, hex_ssid_);
418   storage->SetUint64(id, kStorageRoamThreshold,
419                      static_cast<uint64_t>(roam_threshold_db_));
420   storage->SetBool(id, kStorageRoamThresholdSet, roam_threshold_db_set_);
421   Service::SaveString(storage, id, kStoragePreferredDevice, preferred_device_,
422                       false, false);
423 
424   return true;
425 }
426 
Unload()427 bool WiFiService::Unload() {
428   // Expect the service to be disconnected if is currently connected or
429   // in the process of connecting.
430   if (IsConnected() || IsConnecting()) {
431     expecting_disconnect_ = true;
432   } else {
433     expecting_disconnect_ = false;
434   }
435   Service::Unload();
436   if (wifi_) {
437     wifi_->DestroyServiceLease(*this);
438   }
439   hidden_ssid_ = false;
440   ResetSuspectedCredentialFailures();
441   Error unused_error;
442   ClearPassphrase(&unused_error);
443   preferred_device_.clear();
444   roam_threshold_db_ = 0;
445   roam_threshold_db_set_ = false;
446   return provider_->OnServiceUnloaded(this);
447 }
448 
SetState(ConnectState state)449 void WiFiService::SetState(ConnectState state) {
450   Service::SetState(state);
451   NotifyPropertyChanges();
452 }
453 
IsSecurityMatch(const string & security) const454 bool WiFiService::IsSecurityMatch(const string& security) const {
455   return ComputeSecurityClass(security) == ComputeSecurityClass(security_);
456 }
457 
AddSuspectedCredentialFailure()458 bool WiFiService::AddSuspectedCredentialFailure() {
459   if (!has_ever_connected()) {
460     return true;
461   }
462   ++suspected_credential_failures_;
463   return suspected_credential_failures_ >= kSuspectedCredentialFailureThreshold;
464 }
465 
ResetSuspectedCredentialFailures()466 void WiFiService::ResetSuspectedCredentialFailures() {
467   suspected_credential_failures_ = 0;
468 }
469 
InitializeCustomMetrics() const470 void WiFiService::InitializeCustomMetrics() const {
471   SLOG(Metrics, this, 2) << __func__ << " for " << unique_name();
472   string histogram = metrics()->GetFullMetricName(
473       Metrics::kMetricTimeToJoinMillisecondsSuffix,
474       technology());
475   metrics()->AddServiceStateTransitionTimer(*this,
476                                             histogram,
477                                             Service::kStateAssociating,
478                                             Service::kStateConfiguring);
479 }
480 
SendPostReadyStateMetrics(int64_t time_resume_to_ready_milliseconds) const481 void WiFiService::SendPostReadyStateMetrics(
482     int64_t time_resume_to_ready_milliseconds) const {
483   metrics()->SendEnumToUMA(
484       metrics()->GetFullMetricName(Metrics::kMetricNetworkChannelSuffix,
485                                    technology()),
486       Metrics::WiFiFrequencyToChannel(frequency_),
487       Metrics::kMetricNetworkChannelMax);
488 
489   DCHECK(physical_mode_ < Metrics::kWiFiNetworkPhyModeMax);
490   metrics()->SendEnumToUMA(
491       metrics()->GetFullMetricName(Metrics::kMetricNetworkPhyModeSuffix,
492                                    technology()),
493       static_cast<Metrics::WiFiNetworkPhyMode>(physical_mode_),
494       Metrics::kWiFiNetworkPhyModeMax);
495 
496   string security_mode = security_;
497   if (current_endpoint_) {
498     security_mode = current_endpoint_->security_mode();
499   }
500   Metrics::WiFiSecurity security_uma =
501       Metrics::WiFiSecurityStringToEnum(security_mode);
502   DCHECK(security_uma != Metrics::kWiFiSecurityUnknown);
503   metrics()->SendEnumToUMA(
504       metrics()->GetFullMetricName(Metrics::kMetricNetworkSecuritySuffix,
505                                    technology()),
506       security_uma,
507       Metrics::kMetricNetworkSecurityMax);
508 
509   if (Is8021x()) {
510     eap()->OutputConnectionMetrics(metrics(), technology());
511   }
512 
513   // We invert the sign of the signal strength value, since UMA histograms
514   // cannot represent negative numbers (it stores them but cannot display
515   // them), and dBm values of interest start at 0 and go negative from there.
516   metrics()->SendToUMA(
517       metrics()->GetFullMetricName(Metrics::kMetricNetworkSignalStrengthSuffix,
518                                    technology()),
519       -raw_signal_strength_,
520       Metrics::kMetricNetworkSignalStrengthMin,
521       Metrics::kMetricNetworkSignalStrengthMax,
522       Metrics::kMetricNetworkSignalStrengthNumBuckets);
523 
524   if (time_resume_to_ready_milliseconds > 0) {
525     metrics()->SendToUMA(
526         metrics()->GetFullMetricName(
527             Metrics::kMetricTimeResumeToReadyMillisecondsSuffix, technology()),
528         time_resume_to_ready_milliseconds,
529         Metrics::kTimerHistogramMillisecondsMin,
530         Metrics::kTimerHistogramMillisecondsMax,
531         Metrics::kTimerHistogramNumBuckets);
532   }
533 
534   Metrics::WiFiApMode ap_mode_uma = Metrics::WiFiApModeStringToEnum(mode_);
535   metrics()->SendEnumToUMA(
536       metrics()->GetFullMetricName(Metrics::kMetricNetworkApModeSuffix,
537                                    technology()),
538       ap_mode_uma,
539       Metrics::kWiFiApModeMax);
540 }
541 
542 // private methods
HelpRegisterConstDerivedString(const string & name,string (WiFiService::* get)(Error *))543 void WiFiService::HelpRegisterConstDerivedString(
544     const string& name,
545     string(WiFiService::*get)(Error*)) {
546   mutable_store()->RegisterDerivedString(
547       name,
548       StringAccessor(
549           new CustomAccessor<WiFiService, string>(this, get, nullptr)));
550 }
551 
HelpRegisterDerivedString(const string & name,string (WiFiService::* get)(Error * error),bool (WiFiService::* set)(const string &,Error *))552 void WiFiService::HelpRegisterDerivedString(
553     const string& name,
554     string(WiFiService::*get)(Error* error),
555     bool(WiFiService::*set)(const string&, Error*)) {
556   mutable_store()->RegisterDerivedString(
557       name,
558       StringAccessor(new CustomAccessor<WiFiService, string>(this, get, set)));
559 }
560 
HelpRegisterWriteOnlyDerivedString(const string & name,bool (WiFiService::* set)(const string &,Error *),void (WiFiService::* clear)(Error * error),const string * default_value)561 void WiFiService::HelpRegisterWriteOnlyDerivedString(
562     const string& name,
563     bool(WiFiService::*set)(const string&, Error*),
564     void(WiFiService::*clear)(Error* error),
565     const string* default_value) {
566   mutable_store()->RegisterDerivedString(
567       name,
568       StringAccessor(
569           new CustomWriteOnlyAccessor<WiFiService, string>(
570               this, set, clear, default_value)));
571 }
572 
HelpRegisterDerivedUint16(const string & name,uint16_t (WiFiService::* get)(Error * error),bool (WiFiService::* set)(const uint16_t & value,Error * error),void (WiFiService::* clear)(Error * error))573 void WiFiService::HelpRegisterDerivedUint16(
574     const string& name,
575     uint16_t(WiFiService::*get)(Error* error),
576     bool(WiFiService::*set)(const uint16_t& value, Error* error),
577     void(WiFiService::*clear)(Error* error)) {
578   mutable_store()->RegisterDerivedUint16(
579       name, Uint16Accessor(new CustomAccessor<WiFiService, uint16_t>(
580                 this, get, set, clear)));
581 }
582 
Connect(Error * error,const char * reason)583 void WiFiService::Connect(Error* error, const char* reason) {
584   if (!connectable()) {
585     LOG(ERROR) << "Can't connect. Service " << unique_name()
586                << " is not connectable.";
587     Error::PopulateAndLog(FROM_HERE,
588                           error,
589                           Error::kOperationFailed,
590                           Error::GetDefaultMessage(Error::kOperationFailed));
591     return;
592   }
593   if (IsConnecting() || IsConnected()) {
594     LOG(WARNING) << "Can't connect.  Service " << unique_name()
595                  << " is already connecting or connected.";
596     Error::PopulateAndLog(FROM_HERE,
597                           error,
598                           Error::kAlreadyConnected,
599                           Error::GetDefaultMessage(Error::kAlreadyConnected));
600     return;
601   }
602 
603   WiFiRefPtr wifi = wifi_;
604   if (!wifi) {
605     // If this is a hidden service before it has been found in a scan, we
606     // may need to late-bind to any available WiFi Device.  We don't actually
607     // set |wifi_| in this case since we do not yet see any endpoints.  This
608     // will mean this service is not disconnectable until an endpoint is
609     // found.
610     wifi = ChooseDevice();
611     if (!wifi) {
612       LOG(ERROR) << "Can't connect. Service " << unique_name()
613                  << " cannot find a WiFi device.";
614       Error::PopulateAndLog(FROM_HERE,
615                             error,
616                             Error::kOperationFailed,
617                             Error::GetDefaultMessage(Error::kOperationFailed));
618       return;
619     }
620   }
621 
622   if (wifi->IsCurrentService(this)) {
623     LOG(WARNING) << "Can't connect.  Service " << unique_name()
624                  << " is the current service (but, in " << GetStateString()
625                  << " state, not connected).";
626     Error::PopulateAndLog(FROM_HERE,
627                           error,
628                           Error::kInProgress,
629                           Error::GetDefaultMessage(Error::kInProgress));
630     return;
631   }
632 
633   // Report number of BSSes available for this service.
634   metrics()->NotifyWifiAvailableBSSes(endpoints_.size());
635 
636   if (Is8021x()) {
637     // If EAP key management is not set, set to a default.
638     if (GetEAPKeyManagement().empty())
639       SetEAPKeyManagement("WPA-EAP");
640     ClearEAPCertification();
641   }
642 
643   expecting_disconnect_ = false;
644   Service::Connect(error, reason);
645   wifi->ConnectTo(this);
646 }
647 
GetSupplicantConfigurationParameters() const648 KeyValueStore WiFiService::GetSupplicantConfigurationParameters() const {
649   KeyValueStore params;
650 
651   params.SetUint(WPASupplicant::kNetworkPropertyMode,
652                  WiFiEndpoint::ModeStringToUint(mode_));
653 
654   if (mode_ == kModeAdhoc && frequency_ != 0) {
655     // Frequency is required in order to successfully connect to an IBSS
656     // with wpa_supplicant.  If we have one from our endpoint, insert it
657     // here.
658     params.SetInt(WPASupplicant::kNetworkPropertyFrequency, frequency_);
659   }
660 
661   if (Is8021x()) {
662     eap()->PopulateSupplicantProperties(certificate_file_.get(), &params);
663   } else if (security_ == kSecurityPsk ||
664              security_ == kSecurityRsn ||
665              security_ == kSecurityWpa) {
666     const string psk_proto =
667         base::StringPrintf("%s %s",
668                            WPASupplicant::kSecurityModeWPA,
669                            WPASupplicant::kSecurityModeRSN);
670     params.SetString(WPASupplicant::kPropertySecurityProtocol, psk_proto);
671     params.SetString(WPASupplicant::kPropertyPreSharedKey, passphrase_);
672   } else if (security_ == kSecurityWep) {
673     params.SetString(WPASupplicant::kPropertyAuthAlg,
674                      WPASupplicant::kSecurityAuthAlg);
675     Error unused_error;
676     int key_index;
677     std::vector<uint8_t> password_bytes;
678     ParseWEPPassphrase(passphrase_, &key_index, &password_bytes, &unused_error);
679     params.SetUint8s(WPASupplicant::kPropertyWEPKey +
680                          base::IntToString(key_index),
681                      password_bytes);
682     params.SetUint(WPASupplicant::kPropertyWEPTxKeyIndex, key_index);
683   } else if (security_ == kSecurityNone) {
684     // Nothing special to do here.
685   } else {
686     NOTIMPLEMENTED() << "Unsupported security method " << security_;
687   }
688 
689   params.SetString(WPASupplicant::kNetworkPropertyEapKeyManagement,
690                    key_management());
691 
692   if (ieee80211w_required_) {
693     // TODO(pstew): We should also enable IEEE 802.11w if the user
694     // explicitly enables support for this through a service / device
695     // property.  crbug.com/219950
696     params.SetUint(WPASupplicant::kNetworkPropertyIeee80211w,
697                    WPASupplicant::kNetworkIeee80211wEnabled);
698   }
699 
700   params.SetUint8s(WPASupplicant::kNetworkPropertySSID, ssid_);
701 
702   return params;
703 }
704 
705 
Disconnect(Error * error,const char * reason)706 void WiFiService::Disconnect(Error* error, const char* reason) {
707   Service::Disconnect(error, reason);
708   if (!wifi_) {
709     // If we are connecting to a hidden service, but have not yet found
710     // any endpoints, we could end up with a disconnect request without
711     // a wifi_ reference.  This is not a fatal error.
712     LOG_IF(ERROR, IsConnecting())
713          << "WiFi endpoints do not (yet) exist.  Cannot disconnect service "
714          << unique_name();
715     LOG_IF(FATAL, IsConnected())
716          << "WiFi device does not exist.  Cannot disconnect service "
717          << unique_name();
718     error->Populate(Error::kOperationFailed);
719     return;
720   }
721   wifi_->DisconnectFromIfActive(this);
722 }
723 
GetDeviceRpcId(Error * error) const724 string WiFiService::GetDeviceRpcId(Error* error) const {
725   if (!wifi_) {
726     error->Populate(Error::kNotFound, "Not associated with a device");
727     return control_interface()->NullRPCIdentifier();
728   }
729   return wifi_->GetRpcIdentifier();
730 }
731 
UpdateConnectable()732 void WiFiService::UpdateConnectable() {
733   bool is_connectable = false;
734   if (security_ == kSecurityNone) {
735     DCHECK(passphrase_.empty());
736     need_passphrase_ = false;
737     is_connectable = true;
738   } else if (Is8021x()) {
739     is_connectable = Is8021xConnectable();
740   } else if (security_ == kSecurityWep ||
741              security_ == kSecurityWpa ||
742              security_ == kSecurityPsk ||
743              security_ == kSecurityRsn) {
744     need_passphrase_ = passphrase_.empty();
745     is_connectable = !need_passphrase_;
746   }
747   SetConnectable(is_connectable);
748 }
749 
UpdateFromEndpoints()750 void WiFiService::UpdateFromEndpoints() {
751   const WiFiEndpoint* representative_endpoint = nullptr;
752 
753   if (current_endpoint_) {
754     representative_endpoint = current_endpoint_.get();
755   } else {
756     int16_t best_signal = std::numeric_limits<int16_t>::min();
757     bool preferred_device_found = false;
758     // This will set the representative_endpoint to the best endpoint associated
759     // with the preferred_device_ if it exist, otherwise the best overall
760     // endpoint.
761     for (const auto& endpoint : endpoints_) {
762       if (preferred_device_found) {
763         // Skip endpoints associated with non-preferred device.
764         if (endpoint->device()->link_name() != preferred_device_) {
765           continue;
766         }
767       } else if (endpoint->device() &&
768           endpoint->device()->link_name() == preferred_device_) {
769         // Found first endpoint associated with preferred device.
770         preferred_device_found = true;
771         best_signal = std::numeric_limits<int16_t>::min();
772       }
773 
774       if (endpoint->signal_strength() >= best_signal) {
775         best_signal = endpoint->signal_strength();
776         representative_endpoint = endpoint.get();
777       }
778     }
779   }
780 
781   WiFiRefPtr wifi;
782   if (representative_endpoint) {
783     wifi = representative_endpoint->device();
784     if (bssid_ != representative_endpoint->bssid_string() ||
785         raw_signal_strength_ != representative_endpoint->signal_strength() ||
786         frequency_ != representative_endpoint->frequency()) {
787         LOG(INFO)
788             << "Representative endpoint updated for service " << unique_name()
789             << ". "
790             << WiFi::LogSSID(representative_endpoint->ssid_string()) << ", "
791             << "bssid: " << representative_endpoint->bssid_string() << ", "
792             << "signal: " << representative_endpoint->signal_strength() << ", "
793             << "security: " << representative_endpoint->security_mode() << ", "
794             << "frequency: " << representative_endpoint->frequency();
795     }
796   } else if (IsConnected() || IsConnecting()) {
797     LOG(WARNING) << "Service " << unique_name()
798                  << " will disconnect due to no remaining endpoints.";
799   }
800 
801   SetWiFi(wifi);
802 
803   for (const auto& endpoint : endpoints_) {
804     if (endpoint->ieee80211w_required()) {
805       // Never reset ieee80211w_required_ to false, so we track whether we have
806       // ever seen an AP that requires 802.11w.
807       ieee80211w_required_ = true;
808     }
809   }
810 
811   set<uint16_t> frequency_set;
812   for (const auto& endpoint : endpoints_) {
813     frequency_set.insert(endpoint->frequency());
814   }
815   frequency_list_.assign(frequency_set.begin(), frequency_set.end());
816 
817   if (Is8021x())
818     cipher_8021x_ = ComputeCipher8021x(endpoints_);
819 
820   uint16_t frequency = 0;
821   int16_t signal = std::numeric_limits<int16_t>::min();
822   string bssid;
823   string country_code;
824   Stringmap vendor_information;
825   uint16_t physical_mode = Metrics::kWiFiNetworkPhyModeUndef;
826   // Represent "unknown raw signal strength" as 0.
827   raw_signal_strength_ = 0;
828   if (representative_endpoint) {
829     frequency = representative_endpoint->frequency();
830     signal = representative_endpoint->signal_strength();
831     raw_signal_strength_ = signal;
832     bssid = representative_endpoint->bssid_string();
833     country_code = representative_endpoint->country_code();
834     vendor_information = representative_endpoint->GetVendorInformation();
835     physical_mode = representative_endpoint->physical_mode();
836   }
837 
838   if (frequency_ != frequency) {
839     frequency_ = frequency;
840     adaptor()->EmitUint16Changed(kWifiFrequency, frequency_);
841   }
842   if (bssid_ != bssid) {
843     bssid_ = bssid;
844     adaptor()->EmitStringChanged(kWifiBSsid, bssid_);
845   }
846   if (country_code_ != country_code) {
847     country_code_ = country_code;
848     adaptor()->EmitStringChanged(kCountryProperty, country_code_);
849   }
850   if (vendor_information_ != vendor_information) {
851     vendor_information_ = vendor_information;
852     adaptor()->EmitStringmapChanged(kWifiVendorInformationProperty,
853                                     vendor_information_);
854   }
855   if (physical_mode_ != physical_mode) {
856     physical_mode_ = physical_mode;
857     adaptor()->EmitUint16Changed(kWifiPhyMode, physical_mode_);
858   }
859   adaptor()->EmitUint16sChanged(kWifiFrequencyListProperty, frequency_list_);
860   SetStrength(SignalToStrength(signal));
861   UpdateSecurity();
862   NotifyPropertyChanges();
863 }
864 
UpdateSecurity()865 void WiFiService::UpdateSecurity() {
866   CryptoAlgorithm algorithm = kCryptoNone;
867   bool key_rotation = false;
868   bool endpoint_auth = false;
869 
870   if (security_ == kSecurityNone) {
871     // initial values apply
872   } else if (security_ == kSecurityWep) {
873     algorithm = kCryptoRc4;
874     key_rotation = Is8021x();
875     endpoint_auth = Is8021x();
876   } else if (security_ == kSecurityPsk ||
877              security_ == kSecurityWpa) {
878     algorithm = kCryptoRc4;
879     key_rotation = true;
880     endpoint_auth = false;
881   } else if (security_ == kSecurityRsn) {
882     algorithm = kCryptoAes;
883     key_rotation = true;
884     endpoint_auth = false;
885   } else if (security_ == kSecurity8021x) {
886     algorithm = cipher_8021x_;
887     key_rotation = true;
888     endpoint_auth = true;
889   }
890   SetSecurity(algorithm, key_rotation, endpoint_auth);
891 }
892 
893 // static
ComputeCipher8021x(const set<WiFiEndpointConstRefPtr> & endpoints)894 Service::CryptoAlgorithm WiFiService::ComputeCipher8021x(
895     const set<WiFiEndpointConstRefPtr>& endpoints) {
896 
897   if (endpoints.empty())
898     return kCryptoNone;  // Will update after scan results.
899 
900   // Find weakest cipher (across endpoints) of the strongest ciphers
901   // (per endpoint).
902   Service::CryptoAlgorithm cipher = Service::kCryptoAes;
903   for (const auto& endpoint : endpoints) {
904     Service::CryptoAlgorithm endpoint_cipher;
905     if (endpoint->has_rsn_property()) {
906       endpoint_cipher = Service::kCryptoAes;
907     } else if (endpoint->has_wpa_property()) {
908       endpoint_cipher = Service::kCryptoRc4;
909     } else {
910       // We could be in the Dynamic WEP case here. But that's okay,
911       // because |cipher_8021x_| is not defined in that case.
912       endpoint_cipher = Service::kCryptoNone;
913     }
914     cipher = std::min(cipher, endpoint_cipher);
915   }
916   return cipher;
917 }
918 
919 // static
ValidateWEPPassphrase(const std::string & passphrase,Error * error)920 void WiFiService::ValidateWEPPassphrase(const std::string& passphrase,
921                                         Error* error) {
922   ParseWEPPassphrase(passphrase, nullptr, nullptr, error);
923 }
924 
925 // static
ValidateWPAPassphrase(const std::string & passphrase,Error * error)926 void WiFiService::ValidateWPAPassphrase(const std::string& passphrase,
927                                         Error* error) {
928   unsigned int length = passphrase.length();
929   vector<uint8_t> passphrase_bytes;
930 
931   if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
932     if (length != IEEE_80211::kWPAHexLen &&
933         (length < IEEE_80211::kWPAAsciiMinLen ||
934          length > IEEE_80211::kWPAAsciiMaxLen)) {
935       error->Populate(Error::kInvalidPassphrase);
936     }
937   } else {
938     if (length < IEEE_80211::kWPAAsciiMinLen ||
939         length > IEEE_80211::kWPAAsciiMaxLen) {
940       error->Populate(Error::kInvalidPassphrase);
941     }
942   }
943 }
944 
945 // static
ParseWEPPassphrase(const string & passphrase,int * key_index,std::vector<uint8_t> * password_bytes,Error * error)946 void WiFiService::ParseWEPPassphrase(const string& passphrase,
947                                      int* key_index,
948                                      std::vector<uint8_t>* password_bytes,
949                                      Error* error) {
950   unsigned int length = passphrase.length();
951   int key_index_local;
952   std::string password_text;
953   bool is_hex = false;
954 
955   switch (length) {
956     case IEEE_80211::kWEP40AsciiLen:
957     case IEEE_80211::kWEP104AsciiLen:
958       key_index_local = 0;
959       password_text = passphrase;
960       break;
961     case IEEE_80211::kWEP40AsciiLen + 2:
962     case IEEE_80211::kWEP104AsciiLen + 2:
963       if (CheckWEPKeyIndex(passphrase, error)) {
964         base::StringToInt(passphrase.substr(0, 1), &key_index_local);
965         password_text = passphrase.substr(2);
966       }
967       break;
968     case IEEE_80211::kWEP40HexLen:
969     case IEEE_80211::kWEP104HexLen:
970       if (CheckWEPIsHex(passphrase, error)) {
971         key_index_local = 0;
972         password_text = passphrase;
973         is_hex = true;
974       }
975       break;
976     case IEEE_80211::kWEP40HexLen + 2:
977     case IEEE_80211::kWEP104HexLen + 2:
978       if (CheckWEPKeyIndex(passphrase, error) &&
979          CheckWEPIsHex(passphrase.substr(2), error)) {
980         base::StringToInt(passphrase.substr(0, 1), &key_index_local);
981         password_text = passphrase.substr(2);
982         is_hex = true;
983       } else if (CheckWEPPrefix(passphrase, error) &&
984                  CheckWEPIsHex(passphrase.substr(2), error)) {
985         key_index_local = 0;
986         password_text = passphrase.substr(2);
987         is_hex = true;
988       }
989       break;
990     case IEEE_80211::kWEP40HexLen + 4:
991     case IEEE_80211::kWEP104HexLen + 4:
992       if (CheckWEPKeyIndex(passphrase, error) &&
993           CheckWEPPrefix(passphrase.substr(2), error) &&
994           CheckWEPIsHex(passphrase.substr(4), error)) {
995         base::StringToInt(passphrase.substr(0, 1), &key_index_local);
996         password_text = passphrase.substr(4);
997         is_hex = true;
998       }
999       break;
1000     default:
1001       error->Populate(Error::kInvalidPassphrase);
1002       break;
1003   }
1004 
1005   if (error->IsSuccess()) {
1006     if (key_index)
1007       *key_index = key_index_local;
1008     if (password_bytes) {
1009       if (is_hex)
1010         base::HexStringToBytes(password_text, password_bytes);
1011       else
1012         password_bytes->insert(password_bytes->end(),
1013                                password_text.begin(),
1014                                password_text.end());
1015     }
1016   }
1017 }
1018 
1019 // static
CheckWEPIsHex(const string & passphrase,Error * error)1020 bool WiFiService::CheckWEPIsHex(const string& passphrase, Error* error) {
1021   vector<uint8_t> passphrase_bytes;
1022   if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
1023     return true;
1024   } else {
1025     error->Populate(Error::kInvalidPassphrase);
1026     return false;
1027   }
1028 }
1029 
1030 // static
CheckWEPKeyIndex(const string & passphrase,Error * error)1031 bool WiFiService::CheckWEPKeyIndex(const string& passphrase, Error* error) {
1032   const auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
1033   if (base::StartsWith(passphrase, "0:", kCaseInsensitive) ||
1034       base::StartsWith(passphrase, "1:", kCaseInsensitive) ||
1035       base::StartsWith(passphrase, "2:", kCaseInsensitive) ||
1036       base::StartsWith(passphrase, "3:", kCaseInsensitive)) {
1037     return true;
1038   } else {
1039     error->Populate(Error::kInvalidPassphrase);
1040     return false;
1041   }
1042 }
1043 
1044 // static
CheckWEPPrefix(const string & passphrase,Error * error)1045 bool WiFiService::CheckWEPPrefix(const string& passphrase, Error* error) {
1046   if (base::StartsWith(passphrase, "0x",
1047                        base::CompareCase::INSENSITIVE_ASCII)) {
1048     return true;
1049   } else {
1050     error->Populate(Error::kInvalidPassphrase);
1051     return false;
1052   }
1053 }
1054 
1055 // static
ComputeSecurityClass(const string & security)1056 string WiFiService::ComputeSecurityClass(const string& security) {
1057   if (security == kSecurityRsn ||
1058       security == kSecurityWpa) {
1059     return kSecurityPsk;
1060   } else {
1061     return security;
1062   }
1063 }
1064 
1065 
SignalLevel() const1066 int16_t WiFiService::SignalLevel() const {
1067   return current_endpoint_ ? current_endpoint_->signal_strength() :
1068       std::numeric_limits<int16_t>::min();
1069 }
1070 
1071 // static
ParseStorageIdentifier(const string & storage_name,string * address,string * mode,string * security)1072 bool WiFiService::ParseStorageIdentifier(const string& storage_name,
1073                                          string* address,
1074                                          string* mode,
1075                                          string* security) {
1076   vector<string> wifi_parts = base::SplitString(
1077       storage_name, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1078   if ((wifi_parts.size() != 5 && wifi_parts.size() != 6) ||
1079       wifi_parts[0] != kTypeWifi) {
1080     return false;
1081   }
1082   *address = wifi_parts[1];
1083   *mode = wifi_parts[3];
1084   if (wifi_parts.size() == 5) {
1085     *security = wifi_parts[4];
1086   } else {
1087     // Account for security type "802_1x" which got split up above.
1088     *security = wifi_parts[4] + "_" + wifi_parts[5];
1089   }
1090   return true;
1091 }
1092 
1093 // static
FixupServiceEntries(StoreInterface * storage)1094 bool WiFiService::FixupServiceEntries(StoreInterface* storage) {
1095   bool fixed_entry = false;
1096   set<string> groups = storage->GetGroups();
1097   for (const auto& id : groups) {
1098     string device_address, network_mode, security;
1099     if (!ParseStorageIdentifier(id, &device_address,
1100                                 &network_mode, &security)) {
1101       continue;
1102     }
1103     if (!storage->GetString(id, kStorageType, nullptr)) {
1104       storage->SetString(id, kStorageType, kTypeWifi);
1105       fixed_entry = true;
1106     }
1107     if (!storage->GetString(id, kStorageMode, nullptr)) {
1108       storage->SetString(id, kStorageMode, network_mode);
1109       fixed_entry = true;
1110     }
1111     if (!storage->GetString(id, kStorageSecurity, nullptr)) {
1112       storage->SetString(id, kStorageSecurity, security);
1113       fixed_entry = true;
1114     }
1115     if (!storage->GetString(id, kStorageSecurityClass, nullptr)) {
1116       storage->SetString(id, kStorageSecurityClass,
1117                          ComputeSecurityClass(security));
1118       fixed_entry = true;
1119     }
1120   }
1121   return fixed_entry;
1122 }
1123 
1124 // static
IsValidMode(const string & mode)1125 bool WiFiService::IsValidMode(const string& mode) {
1126   return mode == kModeManaged || mode == kModeAdhoc;
1127 }
1128 
1129 // static
IsValidSecurityMethod(const string & method)1130 bool WiFiService::IsValidSecurityMethod(const string& method) {
1131   return method == kSecurityNone ||
1132       method == kSecurityWep ||
1133       method == kSecurityPsk ||
1134       method == kSecurityWpa ||
1135       method == kSecurityRsn ||
1136       method == kSecurity8021x;
1137 }
1138 
1139 // static
IsValidSecurityClass(const string & security_class)1140 bool WiFiService::IsValidSecurityClass(const string& security_class) {
1141   return IsValidSecurityMethod(security_class) &&
1142       ComputeSecurityClass(security_class) == security_class;
1143 }
1144 
1145 // static
SignalToStrength(int16_t signal_dbm)1146 uint8_t WiFiService::SignalToStrength(int16_t signal_dbm) {
1147   int16_t strength;
1148   if (signal_dbm > 0) {
1149     if (!logged_signal_warning) {
1150       LOG(WARNING) << "Signal strength is suspiciously high. "
1151                    << "Assuming value " << signal_dbm << " is not in dBm.";
1152       logged_signal_warning = true;
1153     }
1154     strength = signal_dbm;
1155   } else {
1156     strength = 120 + signal_dbm;  // Call -20dBm "perfect".
1157   }
1158 
1159   if (strength > kStrengthMax) {
1160     strength = kStrengthMax;
1161   } else if (strength < kStrengthMin) {
1162     strength = kStrengthMin;
1163   }
1164   return strength;
1165 }
1166 
GetStorageProperties() const1167 KeyValueStore WiFiService::GetStorageProperties() const {
1168   KeyValueStore args;
1169   args.SetString(kStorageType, kTypeWifi);
1170   args.SetString(kStorageSSID, hex_ssid_);
1171   args.SetString(kStorageMode, mode_);
1172   args.SetString(kStorageSecurityClass, ComputeSecurityClass(security_));
1173   return args;
1174 }
1175 
GetDefaultStorageIdentifier() const1176 string WiFiService::GetDefaultStorageIdentifier() const {
1177   string security = ComputeSecurityClass(security_);
1178   return base::ToLowerASCII(base::StringPrintf("%s_%s_%s_%s_%s",
1179                                                kTypeWifi,
1180                                                kAnyDeviceAddress,
1181                                                hex_ssid_.c_str(),
1182                                                mode_.c_str(),
1183                                                security.c_str()));
1184 }
1185 
GetSecurity(Error *)1186 string WiFiService::GetSecurity(Error* /*error*/) {
1187   if (current_endpoint_) {
1188     return current_endpoint_->security_mode();
1189   }
1190   return security_;
1191 }
1192 
GetSecurityClass(Error * error)1193 string WiFiService::GetSecurityClass(Error* error) {
1194   return ComputeSecurityClass(GetSecurity(error));
1195 }
1196 
ClearCachedCredentials()1197 void WiFiService::ClearCachedCredentials() {
1198   if (wifi_) {
1199     wifi_->ClearCachedCredentials(this);
1200   }
1201 }
1202 
OnEapCredentialsChanged(Service::UpdateCredentialsReason reason)1203 void WiFiService::OnEapCredentialsChanged(
1204     Service::UpdateCredentialsReason reason) {
1205   if (Is8021x()) {
1206     OnCredentialChange(reason);
1207   }
1208 }
1209 
OnCredentialChange(Service::UpdateCredentialsReason reason)1210 void WiFiService::OnCredentialChange(Service::UpdateCredentialsReason reason) {
1211   ClearCachedCredentials();
1212   // Credential changes due to a property update are new and have not
1213   // necessarily been used for a successful connection.
1214   if (reason == kReasonPropertyUpdate)
1215     SetHasEverConnected(false);
1216   UpdateConnectable();
1217   ResetSuspectedCredentialFailures();
1218 }
1219 
OnProfileConfigured()1220 void WiFiService::OnProfileConfigured() {
1221   if (profile() || !hidden_ssid()) {
1222     return;
1223   }
1224   // This situation occurs when a hidden WiFi service created via GetService
1225   // has been persisted to a profile in Manager::ConfigureService().  Now
1226   // that configuration is saved, we must join the service with its profile,
1227   // which will make this SSID eligible for directed probes during scans.
1228   manager()->RegisterService(this);
1229 }
1230 
Is8021x() const1231 bool WiFiService::Is8021x() const {
1232   if (security_ == kSecurity8021x)
1233     return true;
1234 
1235   // Dynamic WEP + 802.1x.
1236   if (security_ == kSecurityWep &&
1237       GetEAPKeyManagement() == WPASupplicant::kKeyManagementIeee8021X)
1238     return true;
1239   return false;
1240 }
1241 
ChooseDevice()1242 WiFiRefPtr WiFiService::ChooseDevice() {
1243   DeviceRefPtr device = nullptr;
1244   if (!preferred_device_.empty()) {
1245     device = manager()->GetEnabledDeviceByLinkName(preferred_device_);
1246     if (device->technology() != Technology::kWifi) {
1247       device = nullptr;
1248     }
1249   }
1250   if (!device) {
1251     device = manager()->GetEnabledDeviceWithTechnology(Technology::kWifi);
1252   }
1253   // If we have a valid device here, it's better be a WiFi device.
1254   CHECK(!device || device->technology() == Technology::kWifi)
1255       << "Unexpected device technology: " << device->technology();
1256   return static_cast<WiFi*>(device.get());
1257 }
1258 
ResetWiFi()1259 void WiFiService::ResetWiFi() {
1260   SetWiFi(nullptr);
1261 }
1262 
SetWiFi(const WiFiRefPtr & new_wifi)1263 void WiFiService::SetWiFi(const WiFiRefPtr& new_wifi) {
1264   if (wifi_ == new_wifi) {
1265     return;
1266   }
1267   ClearCachedCredentials();
1268   if (wifi_) {
1269     wifi_->DisassociateFromService(this);
1270   }
1271   if (new_wifi) {
1272     adaptor()->EmitRpcIdentifierChanged(kDeviceProperty,
1273                                         new_wifi->GetRpcIdentifier());
1274   } else {
1275     adaptor()->EmitRpcIdentifierChanged(
1276         kDeviceProperty, control_interface()->NullRPCIdentifier());
1277   }
1278   wifi_ = new_wifi;
1279 }
1280 
GetRoamThreshold(Error *)1281 uint16_t WiFiService::GetRoamThreshold(Error* /*error*/) {
1282   return roam_threshold_db_;
1283 }
1284 
SetRoamThreshold(const uint16_t & threshold,Error *)1285 bool WiFiService::SetRoamThreshold(const uint16_t& threshold,
1286                                    Error* /*error*/) {
1287   roam_threshold_db_ = threshold;
1288   roam_threshold_db_set_ = true;
1289   return true;
1290 }
1291 
ClearRoamThreshold(Error *)1292 void WiFiService::ClearRoamThreshold(Error* /*error*/) {
1293   roam_threshold_db_ = 0;
1294   roam_threshold_db_set_ = false;
1295 }
1296 
1297 }  // namespace shill
1298