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(), ¶ms);
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