blob: 95dcf5c0e9c7c6ae560346ddbf1a63a17017e4bf [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
mukesh agrawalb54601c2011-06-07 17:39:22 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/wifi_service.h"
6
mukesh agrawal43970a22013-02-15 16:00:07 -08007#include <algorithm>
mukesh agrawalb54601c2011-06-07 17:39:22 -07008#include <string>
Gaurav Shah10109f22011-11-11 20:16:22 -08009#include <utility>
mukesh agrawalb54601c2011-06-07 17:39:22 -070010
Chris Masone34af2182011-08-22 11:59:36 -070011#include <base/stringprintf.h>
12#include <base/string_number_conversions.h>
Paul Stewarta41e38d2011-11-11 07:47:29 -080013#include <base/string_split.h>
Chris Masone34af2182011-08-22 11:59:36 -070014#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070015#include <chromeos/dbus/service_constants.h>
mukesh agrawal6e277772011-09-29 15:04:23 -070016#include <dbus/dbus.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -070017
mukesh agrawale1d90e92012-02-15 17:36:08 -080018#include "shill/adaptor_interfaces.h"
Paul Stewart5baebb72013-03-14 11:43:29 -070019#include "shill/certificate_file.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070020#include "shill/control_interface.h"
21#include "shill/device.h"
mukesh agrawal1a056262011-10-05 14:36:54 -070022#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070023#include "shill/event_dispatcher.h"
mukesh agrawal1a056262011-10-05 14:36:54 -070024#include "shill/ieee80211.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070025#include "shill/logging.h"
Paul Stewart4357f4e2012-04-26 17:39:26 -070026#include "shill/manager.h"
Thieu Le48e6d6d2011-12-06 00:40:27 +000027#include "shill/metrics.h"
Paul Stewartecf4cd12012-04-17 11:08:39 -070028#include "shill/nss.h"
Thieu Lef7709452011-11-15 01:13:19 +000029#include "shill/property_accessor.h"
Paul Stewartd08f4432011-11-04 07:48:20 -070030#include "shill/store_interface.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070031#include "shill/wifi.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070032#include "shill/wifi_endpoint.h"
Paul Stewart3c504012013-01-17 17:49:58 -080033#include "shill/wifi_provider.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070034#include "shill/wpa_supplicant.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070035
mukesh agrawal261daca2011-12-02 18:56:56 +000036using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070037using std::string;
mukesh agrawal1a056262011-10-05 14:36:54 -070038using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070039
40namespace shill {
mukesh agrawalb54601c2011-06-07 17:39:22 -070041
mukesh agrawalbf14e942012-03-02 14:36:34 -080042const char WiFiService::kAutoConnNoEndpoint[] = "no endpoints";
Paul Stewart3c504012013-01-17 17:49:58 -080043const char WiFiService::kAnyDeviceAddress[] = "any";
mukesh agrawalbf14e942012-03-02 14:36:34 -080044
Paul Stewartd08f4432011-11-04 07:48:20 -070045const char WiFiService::kStorageHiddenSSID[] = "WiFi.HiddenSSID";
Paul Stewart2706aaf2011-12-14 16:44:04 -080046const char WiFiService::kStorageMode[] = "WiFi.Mode";
47const char WiFiService::kStoragePassphrase[] = "Passphrase";
48const char WiFiService::kStorageSecurity[] = "WiFi.Security";
Paul Stewart71a4d3b2013-01-18 18:12:56 -080049const char WiFiService::kStorageSecurityClass[] = "WiFi.SecurityClass";
Paul Stewart2706aaf2011-12-14 16:44:04 -080050const char WiFiService::kStorageSSID[] = "SSID";
mukesh agrawale1d90e92012-02-15 17:36:08 -080051bool WiFiService::logged_signal_warning = false;
Paul Stewartd08f4432011-11-04 07:48:20 -070052
mukesh agrawalb54601c2011-06-07 17:39:22 -070053WiFiService::WiFiService(ControlInterface *control_interface,
54 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080055 Metrics *metrics,
Chris Masone6791a432011-07-12 13:23:19 -070056 Manager *manager,
Paul Stewart3c504012013-01-17 17:49:58 -080057 WiFiProvider *provider,
Paul Stewarta41e38d2011-11-11 07:47:29 -080058 const vector<uint8_t> &ssid,
59 const string &mode,
60 const string &security,
Paul Stewartced6a0b2011-11-08 15:32:04 -080061 bool hidden_ssid)
Thieu Le3426c8f2012-01-11 17:35:11 -080062 : Service(control_interface, dispatcher, metrics, manager,
63 Technology::kWifi),
Chris Masone75612302011-10-12 16:31:21 -070064 need_passphrase_(false),
mukesh agrawal6e277772011-09-29 15:04:23 -070065 security_(security),
Chris Masone092df3e2011-08-22 09:41:39 -070066 mode_(mode),
Paul Stewartced6a0b2011-11-08 15:32:04 -080067 hidden_ssid_(hidden_ssid),
Thieu Lee41a72d2012-02-06 20:46:51 +000068 frequency_(0),
Paul Stewart20088d82012-02-16 06:58:55 -080069 physical_mode_(0),
Paul Stewart23b393a2012-09-25 21:21:06 -070070 raw_signal_strength_(0),
mukesh agrawal43970a22013-02-15 16:00:07 -080071 cipher_8021x_(kCryptoNone),
Paul Stewartecf4cd12012-04-17 11:08:39 -070072 ssid_(ssid),
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080073 ieee80211w_required_(false),
Paul Stewart3c504012013-01-17 17:49:58 -080074 nss_(NSS::GetInstance()),
Paul Stewart5baebb72013-03-14 11:43:29 -070075 certificate_file_(new CertificateFile(manager->glib())),
Paul Stewart3c504012013-01-17 17:49:58 -080076 provider_(provider) {
mukesh agrawalde29fa82011-09-16 16:16:36 -070077 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -070078 store->RegisterConstString(flimflam::kModeProperty, &mode_);
mukesh agrawal292dc0f2012-01-26 18:02:46 -080079 HelpRegisterWriteOnlyDerivedString(flimflam::kPassphraseProperty,
80 &WiFiService::SetPassphrase,
81 &WiFiService::ClearPassphrase,
82 NULL);
Paul Stewartac4ac002011-08-26 12:04:26 -070083 store->RegisterBool(flimflam::kPassphraseRequiredProperty, &need_passphrase_);
Paul Stewart6df20bd2013-03-13 19:31:25 -070084 HelpRegisterDerivedString(flimflam::kSecurityProperty,
85 &WiFiService::GetSecurity,
86 NULL);
Chris Masone3bd3c8c2011-06-13 08:20:26 -070087
Paul Stewartac4ac002011-08-26 12:04:26 -070088 store->RegisterConstString(flimflam::kWifiAuthMode, &auth_mode_);
Paul Stewart0cab5682012-09-13 18:50:34 -070089 store->RegisterBool(flimflam::kWifiHiddenSsid, &hidden_ssid_);
Paul Stewartac4ac002011-08-26 12:04:26 -070090 store->RegisterConstUint16(flimflam::kWifiFrequency, &frequency_);
91 store->RegisterConstUint16(flimflam::kWifiPhyMode, &physical_mode_);
mukesh agrawal923f14f2012-06-04 16:46:08 -070092 store->RegisterConstString(flimflam::kWifiBSsid, &bssid_);
Paul Stewart72b2fdc2012-06-02 08:58:51 -070093 store->RegisterConstStringmap(kWifiVendorInformationProperty,
94 &vendor_information_);
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080095 store->RegisterConstBool(kWifiProtectedManagementFrameRequiredProperty,
96 &ieee80211w_required_);
mukesh agrawal32399322011-09-01 10:53:43 -070097
mukesh agrawald835b202011-10-07 15:26:47 -070098 hex_ssid_ = base::HexEncode(ssid_.data(), ssid_.size());
99 string ssid_string(
100 reinterpret_cast<const char *>(ssid_.data()), ssid_.size());
mukesh agrawal16bc1b82012-02-09 18:38:26 -0800101 if (WiFi::SanitizeSSID(&ssid_string)) {
mukesh agrawald835b202011-10-07 15:26:47 -0700102 // WifiHexSsid property should only be present if Name property
103 // has been munged.
104 store->RegisterConstString(flimflam::kWifiHexSsid, &hex_ssid_);
105 }
106 set_friendly_name(ssid_string);
Chris Masone9d779932011-08-25 16:33:41 -0700107
mukesh agrawal6e277772011-09-29 15:04:23 -0700108 // TODO(quiche): determine if it is okay to set EAP.KeyManagement for
109 // a service that is not 802.1x.
Gaurav Shah29d68882012-01-30 19:06:42 -0800110 if (Is8021x()) {
Gaurav Shah10109f22011-11-11 20:16:22 -0800111 // Passphrases are not mandatory for 802.1X.
112 need_passphrase_ = false;
mukesh agrawal6e277772011-09-29 15:04:23 -0700113 } else if (security_ == flimflam::kSecurityPsk) {
114 SetEAPKeyManagement("WPA-PSK");
mukesh agrawal6e277772011-09-29 15:04:23 -0700115 } else if (security_ == flimflam::kSecurityRsn) {
116 SetEAPKeyManagement("WPA-PSK");
mukesh agrawal6e277772011-09-29 15:04:23 -0700117 } else if (security_ == flimflam::kSecurityWpa) {
118 SetEAPKeyManagement("WPA-PSK");
mukesh agrawal6e277772011-09-29 15:04:23 -0700119 } else if (security_ == flimflam::kSecurityWep) {
120 SetEAPKeyManagement("NONE");
mukesh agrawal6e277772011-09-29 15:04:23 -0700121 } else if (security_ == flimflam::kSecurityNone) {
122 SetEAPKeyManagement("NONE");
mukesh agrawal6e277772011-09-29 15:04:23 -0700123 } else {
Gaurav Shah10109f22011-11-11 20:16:22 -0800124 LOG(ERROR) << "Unsupported security method " << security_;
mukesh agrawal6e277772011-09-29 15:04:23 -0700125 }
126
Paul Stewartd08f4432011-11-04 07:48:20 -0700127 // Until we know better (at Profile load time), use the generic name.
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800128 storage_identifier_ = GetDefaultStorageIdentifier();
mukesh agrawal29c13a12011-11-24 00:09:19 +0000129 UpdateConnectable();
mukesh agrawal43970a22013-02-15 16:00:07 -0800130 UpdateSecurity();
Paul Stewartcb59fed2012-03-21 21:14:46 -0700131
132 IgnoreParameterForConfigure(flimflam::kModeProperty);
133 IgnoreParameterForConfigure(flimflam::kSSIDProperty);
134 IgnoreParameterForConfigure(flimflam::kSecurityProperty);
Darin Petkov457728b2013-01-09 09:49:08 +0100135
136 // Log the |unique_name| to |friendly_name| mapping for debugging purposes at
137 // non-default log level.
138 SLOG(WiFi, 1) << "Constructed WiFi service " << unique_name()
139 << " name: " << friendly_name();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700140}
141
Darin Petkov9cd7ca12012-07-03 11:06:40 +0200142WiFiService::~WiFiService() {}
mukesh agrawalb54601c2011-06-07 17:39:22 -0700143
mukesh agrawalbf14e942012-03-02 14:36:34 -0800144bool WiFiService::IsAutoConnectable(const char **reason) const {
145 if (!Service::IsAutoConnectable(reason)) {
146 return false;
147 }
148
149 // Only auto-connect to Services which have visible Endpoints.
150 // (Needed because hidden Services may remain registered with
151 // Manager even without visible Endpoints.)
152 if (!HasEndpoints()) {
153 *reason = kAutoConnNoEndpoint;
154 return false;
155 }
156
Paul Stewart3c504012013-01-17 17:49:58 -0800157 CHECK(wifi_) << "We have endpoints but no WiFi device is selected?";
158
mukesh agrawalbf14e942012-03-02 14:36:34 -0800159 // Do not preempt an existing connection (whether pending, or
160 // connected, and whether to this service, or another).
161 if (!wifi_->IsIdle()) {
162 *reason = kAutoConnBusy;
163 return false;
164 }
165
166 return true;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000167}
168
mukesh agrawal43970a22013-02-15 16:00:07 -0800169void WiFiService::SetEAPKeyManagement(const string &key_management) {
170 Service::SetEAPKeyManagement(key_management);
171 UpdateSecurity();
172}
173
Darin Petkov4a66cc52012-06-15 10:08:29 +0200174void WiFiService::AddEndpoint(const WiFiEndpointConstRefPtr &endpoint) {
mukesh agrawal261daca2011-12-02 18:56:56 +0000175 DCHECK(endpoint->ssid() == ssid());
176 endpoints_.insert(endpoint);
mukesh agrawale1d90e92012-02-15 17:36:08 -0800177 UpdateFromEndpoints();
mukesh agrawal261daca2011-12-02 18:56:56 +0000178}
179
Darin Petkov4a66cc52012-06-15 10:08:29 +0200180void WiFiService::RemoveEndpoint(const WiFiEndpointConstRefPtr &endpoint) {
mukesh agrawal261daca2011-12-02 18:56:56 +0000181 set<WiFiEndpointConstRefPtr>::iterator i = endpoints_.find(endpoint);
182 DCHECK(i != endpoints_.end());
183 if (i == endpoints_.end()) {
184 LOG(WARNING) << "In " << __func__ << "(): "
Darin Petkov457728b2013-01-09 09:49:08 +0100185 << "ignoring non-existent endpoint "
mukesh agrawal261daca2011-12-02 18:56:56 +0000186 << endpoint->bssid_string();
187 return;
188 }
189 endpoints_.erase(i);
mukesh agrawale1d90e92012-02-15 17:36:08 -0800190 if (current_endpoint_ == endpoint) {
191 current_endpoint_ = NULL;
192 }
193 UpdateFromEndpoints();
mukesh agrawal261daca2011-12-02 18:56:56 +0000194}
195
Paul Stewart3c504012013-01-17 17:49:58 -0800196void WiFiService::NotifyCurrentEndpoint(
197 const WiFiEndpointConstRefPtr &endpoint) {
mukesh agrawale1d90e92012-02-15 17:36:08 -0800198 DCHECK(!endpoint || (endpoints_.find(endpoint) != endpoints_.end()));
199 current_endpoint_ = endpoint;
200 UpdateFromEndpoints();
Thieu Lee41a72d2012-02-06 20:46:51 +0000201}
202
Paul Stewart3c504012013-01-17 17:49:58 -0800203void WiFiService::NotifyEndpointUpdated(
204 const WiFiEndpointConstRefPtr &endpoint) {
205 DCHECK(endpoints_.find(endpoint) != endpoints_.end());
mukesh agrawale1d90e92012-02-15 17:36:08 -0800206 UpdateFromEndpoints();
mukesh agrawalb20776f2012-02-10 16:00:36 -0800207}
208
Chris Masone6515aab2011-10-12 16:19:09 -0700209string WiFiService::GetStorageIdentifier() const {
Paul Stewartd08f4432011-11-04 07:48:20 -0700210 return storage_identifier_;
Chris Masone34af2182011-08-22 11:59:36 -0700211}
mukesh agrawal445e72c2011-06-22 11:13:50 -0700212
mukesh agrawal1a056262011-10-05 14:36:54 -0700213void WiFiService::SetPassphrase(const string &passphrase, Error *error) {
214 if (security_ == flimflam::kSecurityWep) {
Thieu Lef4cbda92011-11-10 23:41:24 +0000215 ValidateWEPPassphrase(passphrase, error);
mukesh agrawal1a056262011-10-05 14:36:54 -0700216 } else if (security_ == flimflam::kSecurityPsk ||
217 security_ == flimflam::kSecurityWpa ||
218 security_ == flimflam::kSecurityRsn) {
Thieu Lef4cbda92011-11-10 23:41:24 +0000219 ValidateWPAPassphrase(passphrase, error);
220 } else {
221 error->Populate(Error::kNotSupported);
mukesh agrawal1a056262011-10-05 14:36:54 -0700222 }
Thieu Lef4cbda92011-11-10 23:41:24 +0000223
Paul Stewart835934a2012-12-06 19:27:09 -0800224 if (!error->IsSuccess() || passphrase == passphrase_) {
225 return;
Paul Stewart2706aaf2011-12-14 16:44:04 -0800226 }
mukesh agrawal29c13a12011-11-24 00:09:19 +0000227
Paul Stewart835934a2012-12-06 19:27:09 -0800228 passphrase_ = passphrase;
229 ClearCachedCredentials();
mukesh agrawal29c13a12011-11-24 00:09:19 +0000230 UpdateConnectable();
mukesh agrawal1a056262011-10-05 14:36:54 -0700231}
232
mukesh agrawal292dc0f2012-01-26 18:02:46 -0800233// ClearPassphrase is separate from SetPassphrase, because the default
234// value for |passphrase_| would not pass validation.
235void WiFiService::ClearPassphrase(Error */*error*/) {
236 passphrase_.clear();
Paul Stewart835934a2012-12-06 19:27:09 -0800237 ClearCachedCredentials();
mukesh agrawal292dc0f2012-01-26 18:02:46 -0800238 UpdateConnectable();
239}
240
Paul Stewartd08f4432011-11-04 07:48:20 -0700241bool WiFiService::IsLoadableFrom(StoreInterface *storage) const {
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800242 return !storage->GetGroupsWithProperties(GetStorageProperties()).empty();
Paul Stewartd08f4432011-11-04 07:48:20 -0700243}
244
Paul Stewarta41e38d2011-11-11 07:47:29 -0800245bool WiFiService::IsVisible() const {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800246 // WiFi Services should be displayed only if they are in range (have
247 // endpoints that have shown up in a scan) or if the service is actively
248 // being connected.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000249 return HasEndpoints() || IsConnected() || IsConnecting();
Paul Stewarta41e38d2011-11-11 07:47:29 -0800250}
251
Paul Stewartd08f4432011-11-04 07:48:20 -0700252bool WiFiService::Load(StoreInterface *storage) {
253 // First find out which storage identifier is available in priority order
254 // of specific, generic.
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800255 set<string> groups = storage->GetGroupsWithProperties(GetStorageProperties());
256 if (groups.empty()) {
257 LOG(WARNING) << "Configuration for service "
258 << unique_name()
259 << " is not available in the persistent store";
260 return false;
Paul Stewartd08f4432011-11-04 07:48:20 -0700261 }
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800262 if (groups.size() > 0) {
263 LOG(WARNING) << "More than one configuration for service "
264 << unique_name()
265 << " is available; choosing the first.";
266 }
267 string id = *groups.begin();
Paul Stewartd08f4432011-11-04 07:48:20 -0700268
269 // Set our storage identifier to match the storage name in the Profile.
270 storage_identifier_ = id;
271
272 // Load properties common to all Services.
273 if (!Service::Load(storage)) {
274 return false;
275 }
276
277 // Load properties specific to WiFi services.
278 storage->GetBool(id, kStorageHiddenSSID, &hidden_ssid_);
mukesh agrawal29c13a12011-11-24 00:09:19 +0000279
Paul Stewart2706aaf2011-12-14 16:44:04 -0800280 // NB: mode, security and ssid parameters are never read in from
281 // Load() as they are provided from the scan.
282
283 string passphrase;
284 if (storage->GetCryptedString(id, kStoragePassphrase, &passphrase)) {
285 Error error;
286 SetPassphrase(passphrase, &error);
287 if (!error.IsSuccess()) {
288 LOG(ERROR) << "Passphrase could not be set: "
289 << Error::GetName(error.type());
290 }
291 }
292
Paul Stewartd08f4432011-11-04 07:48:20 -0700293 return true;
294}
295
296bool WiFiService::Save(StoreInterface *storage) {
297 // Save properties common to all Services.
298 if (!Service::Save(storage)) {
299 return false;
300 }
301
302 // Save properties specific to WiFi services.
303 const string id = GetStorageIdentifier();
Paul Stewart2706aaf2011-12-14 16:44:04 -0800304 storage->SetBool(id, kStorageHiddenSSID, hidden_ssid_);
305 storage->SetString(id, kStorageMode, mode_);
306 storage->SetCryptedString(id, kStoragePassphrase, passphrase_);
307 storage->SetString(id, kStorageSecurity, security_);
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800308 storage->SetString(id, kStorageSecurityClass, GetSecurityClass(security_));
Paul Stewart2706aaf2011-12-14 16:44:04 -0800309 storage->SetString(id, kStorageSSID, hex_ssid_);
mukesh agrawal29c13a12011-11-24 00:09:19 +0000310
Paul Stewartd08f4432011-11-04 07:48:20 -0700311 return true;
312}
313
Paul Stewart65512e12012-03-26 18:01:08 -0700314bool WiFiService::Unload() {
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800315 Service::Unload();
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800316 if (wifi_) {
317 wifi_->DestroyServiceLease(*this);
318 }
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800319 hidden_ssid_ = false;
Wade Guthrie005bd342012-05-02 09:37:07 -0700320 Error unused_error;
321 ClearPassphrase(&unused_error);
Paul Stewart3c504012013-01-17 17:49:58 -0800322 return provider_->OnServiceUnloaded(this);
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800323}
324
Paul Stewart6ab23a92011-11-09 17:17:47 -0800325bool WiFiService::IsSecurityMatch(const string &security) const {
326 return GetSecurityClass(security) == GetSecurityClass(security_);
327}
328
Thieu Le48e6d6d2011-12-06 00:40:27 +0000329void WiFiService::InitializeCustomMetrics() const {
330 string histogram = metrics()->GetFullMetricName(
331 Metrics::kMetricTimeToJoinMilliseconds,
332 technology());
333 metrics()->AddServiceStateTransitionTimer(this,
334 histogram,
335 Service::kStateAssociating,
336 Service::kStateConfiguring);
337}
338
Thieu Leb84ba342012-03-02 15:15:19 -0800339void WiFiService::SendPostReadyStateMetrics(
340 int64 time_resume_to_ready_milliseconds) const {
Thieu Le48e6d6d2011-12-06 00:40:27 +0000341 metrics()->SendEnumToUMA(
342 metrics()->GetFullMetricName(Metrics::kMetricNetworkChannel,
343 technology()),
344 Metrics::WiFiFrequencyToChannel(frequency_),
345 Metrics::kMetricNetworkChannelMax);
Thieu Lead1ec2c2012-01-05 23:39:48 +0000346
347 DCHECK(physical_mode_ < Metrics::kWiFiNetworkPhyModeMax);
348 metrics()->SendEnumToUMA(
349 metrics()->GetFullMetricName(Metrics::kMetricNetworkPhyMode,
350 technology()),
351 static_cast<Metrics::WiFiNetworkPhyMode>(physical_mode_),
352 Metrics::kWiFiNetworkPhyModeMax);
353
Paul Stewart4108db92013-03-11 12:13:24 -0700354 string security_mode = security_;
355 if (current_endpoint_) {
356 security_mode = current_endpoint_->security_mode();
357 }
Thieu Lead1ec2c2012-01-05 23:39:48 +0000358 Metrics::WiFiSecurity security_uma =
Paul Stewart4108db92013-03-11 12:13:24 -0700359 Metrics::WiFiSecurityStringToEnum(security_mode);
Thieu Lead1ec2c2012-01-05 23:39:48 +0000360 DCHECK(security_uma != Metrics::kWiFiSecurityUnknown);
361 metrics()->SendEnumToUMA(
362 metrics()->GetFullMetricName(Metrics::kMetricNetworkSecurity,
363 technology()),
364 security_uma,
365 Metrics::kMetricNetworkSecurityMax);
Thieu Leb84ba342012-03-02 15:15:19 -0800366
Paul Stewart21f40962013-03-01 14:27:28 -0800367 if (Is8021x()) {
368 Metrics::EapOuterProtocol outer_protocol =
369 Metrics::EapOuterProtocolStringToEnum(eap().eap);
370 metrics()->SendEnumToUMA(
371 metrics()->GetFullMetricName(Metrics::kMetricNetworkEapOuterProtocol,
372 technology()),
373 outer_protocol,
374 Metrics::kMetricNetworkEapOuterProtocolMax);
375
376 Metrics::EapInnerProtocol inner_protocol =
377 Metrics::EapInnerProtocolStringToEnum(eap().inner_eap);
378 metrics()->SendEnumToUMA(
379 metrics()->GetFullMetricName(Metrics::kMetricNetworkEapInnerProtocol,
380 technology()),
381 inner_protocol,
382 Metrics::kMetricNetworkEapInnerProtocolMax);
383 }
384
Paul Stewart23b393a2012-09-25 21:21:06 -0700385 // We invert the sign of the signal strength value, since UMA histograms
386 // cannot represent negative numbers (it stores them but cannot display
387 // them), and dBm values of interest start at 0 and go negative from there.
388 metrics()->SendToUMA(
389 metrics()->GetFullMetricName(Metrics::kMetricNetworkSignalStrength,
390 technology()),
391 -raw_signal_strength_,
392 Metrics::kMetricNetworkSignalStrengthMin,
393 Metrics::kMetricNetworkSignalStrengthMax,
394 Metrics::kMetricNetworkSignalStrengthNumBuckets);
395
Thieu Leb84ba342012-03-02 15:15:19 -0800396 if (time_resume_to_ready_milliseconds > 0) {
397 metrics()->SendToUMA(
398 metrics()->GetFullMetricName(
399 Metrics::kMetricTimeResumeToReadyMilliseconds, technology()),
400 time_resume_to_ready_milliseconds,
401 Metrics::kTimerHistogramMillisecondsMin,
402 Metrics::kTimerHistogramMillisecondsMax,
403 Metrics::kTimerHistogramNumBuckets);
404 }
Thieu Le48e6d6d2011-12-06 00:40:27 +0000405}
406
mukesh agrawal32399322011-09-01 10:53:43 -0700407// private methods
Paul Stewart6df20bd2013-03-13 19:31:25 -0700408void WiFiService::HelpRegisterDerivedString(
409 const string &name,
410 string(WiFiService::*get)(Error *),
411 void(WiFiService::*set)(const string&, Error *)) {
412 mutable_store()->RegisterDerivedString(
413 name,
414 StringAccessor(new CustomAccessor<WiFiService, string>(this, get, set)));
415}
416
mukesh agrawal292dc0f2012-01-26 18:02:46 -0800417void WiFiService::HelpRegisterWriteOnlyDerivedString(
418 const string &name,
419 void(WiFiService::*set)(const string &, Error *),
420 void(WiFiService::*clear)(Error *),
421 const string *default_value) {
422 mutable_store()->RegisterDerivedString(
Thieu Lef7709452011-11-15 01:13:19 +0000423 name,
mukesh agrawal292dc0f2012-01-26 18:02:46 -0800424 StringAccessor(
425 new CustomWriteOnlyAccessor<WiFiService, string>(
426 this, set, clear, default_value)));
Thieu Lef7709452011-11-15 01:13:19 +0000427}
428
Wade Guthrie005bd342012-05-02 09:37:07 -0700429void WiFiService::Connect(Error *error) {
Darin Petkov457728b2013-01-09 09:49:08 +0100430 LOG(INFO) << "Connect to service " << unique_name();
mukesh agrawal6e277772011-09-29 15:04:23 -0700431 std::map<string, DBus::Variant> params;
432 DBus::MessageIter writer;
433
Wade Guthrie005bd342012-05-02 09:37:07 -0700434 if (!connectable()) {
Darin Petkov457728b2013-01-09 09:49:08 +0100435 LOG(ERROR) << "Can't connect. Service " << unique_name()
436 << " is not connectable.";
Christopher Wiley1ce658d2012-10-10 10:02:03 -0700437 Error::PopulateAndLog(error,
438 Error::kOperationFailed,
439 Error::GetDefaultMessage(Error::kOperationFailed));
440 return;
441 }
442 if (IsConnecting() || IsConnected()) {
Darin Petkov457728b2013-01-09 09:49:08 +0100443 LOG(WARNING) << "Can't connect. Service " << unique_name()
Christopher Wiley1ce658d2012-10-10 10:02:03 -0700444 << " is already connecting or connected.";
445 Error::PopulateAndLog(error,
446 Error::kAlreadyConnected,
447 Error::GetDefaultMessage(Error::kAlreadyConnected));
Wade Guthrie005bd342012-05-02 09:37:07 -0700448 return;
449 }
Paul Stewart3c504012013-01-17 17:49:58 -0800450
451 WiFiRefPtr wifi = wifi_;
452 if (!wifi) {
453 // If this is a hidden service before it has been found in a scan, we
454 // may need to late-bind to any available WiFi Device. We don't actually
455 // set |wifi_| in this case snce we do not yet see any endpoints. This
456 // will mean this service is not disconnectable until an endpoint is
457 // found.
458 wifi = ChooseDevice();
459 if (!wifi) {
460 LOG(ERROR) << "Can't connect. Service " << unique_name()
461 << " cannot find a WiFi device.";
462 Error::PopulateAndLog(error,
463 Error::kOperationFailed,
464 Error::GetDefaultMessage(Error::kOperationFailed));
465 return;
466 }
467 }
468
469 if (wifi->IsCurrentService(this)) {
Darin Petkov457728b2013-01-09 09:49:08 +0100470 LOG(WARNING) << "Can't connect. Service " << unique_name()
Wade Guthrie8bc50882012-10-31 16:23:20 -0700471 << " is the current service (but, in " << GetStateString()
Paul Stewart3c504012013-01-17 17:49:58 -0800472 << " state, not connected).";
Wade Guthrie8bc50882012-10-31 16:23:20 -0700473 Error::PopulateAndLog(error,
474 Error::kInProgress,
475 Error::GetDefaultMessage(Error::kInProgress));
476 return;
477 }
Wade Guthrie005bd342012-05-02 09:37:07 -0700478
Paul Stewart0654ece2013-03-26 15:21:26 -0700479 params[WPASupplicant::kNetworkPropertyMode].writer().
mukesh agrawal6e277772011-09-29 15:04:23 -0700480 append_uint32(WiFiEndpoint::ModeStringToUint(mode_));
481
Paul Stewarte2d7c502012-07-16 16:35:10 -0700482 if (mode_ == flimflam::kModeAdhoc && frequency_ != 0) {
483 // Frequency is required in order to successfully conntect to an IBSS
484 // with wpa_supplicant. If we have one from our endpoint, insert it
485 // here.
Paul Stewart0654ece2013-03-26 15:21:26 -0700486 params[WPASupplicant::kNetworkPropertyFrequency].writer().
Paul Stewarte2d7c502012-07-16 16:35:10 -0700487 append_int32(frequency_);
488 }
489
Gaurav Shah29d68882012-01-30 19:06:42 -0800490 if (Is8021x()) {
491 // Is EAP key management is not set, set to a default.
Gaurav Shah10109f22011-11-11 20:16:22 -0800492 if (GetEAPKeyManagement().empty())
493 SetEAPKeyManagement("WPA-EAP");
Paul Stewart0654ece2013-03-26 15:21:26 -0700494 vector<char> nss_identifier(ssid_.begin(), ssid_.end());
495 WPASupplicant::Populate8021xProperties(
496 eap(), certificate_file_.get(), nss_, nss_identifier, &params);
Paul Stewartbc6e7392012-05-24 07:07:48 -0700497 ClearEAPCertification();
Paul Stewart4108db92013-03-11 12:13:24 -0700498 } else if (security_ == flimflam::kSecurityPsk ||
499 security_ == flimflam::kSecurityRsn ||
500 security_ == flimflam::kSecurityWpa) {
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800501 const string psk_proto = StringPrintf("%s %s",
Paul Stewart0654ece2013-03-26 15:21:26 -0700502 WPASupplicant::kSecurityModeWPA,
503 WPASupplicant::kSecurityModeRSN);
504 params[WPASupplicant::kPropertySecurityProtocol].writer().
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800505 append_string(psk_proto.c_str());
Paul Stewart0654ece2013-03-26 15:21:26 -0700506 params[WPASupplicant::kPropertyPreSharedKey].writer().
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800507 append_string(passphrase_.c_str());
mukesh agrawal6e277772011-09-29 15:04:23 -0700508 } else if (security_ == flimflam::kSecurityWep) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700509 params[WPASupplicant::kPropertyAuthAlg].writer().
510 append_string(WPASupplicant::kSecurityAuthAlg);
Thieu Lef4cbda92011-11-10 23:41:24 +0000511 Error error;
512 int key_index;
513 std::vector<uint8> password_bytes;
514 ParseWEPPassphrase(passphrase_, &key_index, &password_bytes, &error);
Paul Stewart0654ece2013-03-26 15:21:26 -0700515 writer = params[WPASupplicant::kPropertyWEPKey +
Thieu Lef4cbda92011-11-10 23:41:24 +0000516 base::IntToString(key_index)].writer();
517 writer << password_bytes;
Paul Stewart0654ece2013-03-26 15:21:26 -0700518 params[WPASupplicant::kPropertyWEPTxKeyIndex].writer().
Thieu Lef4cbda92011-11-10 23:41:24 +0000519 append_uint32(key_index);
mukesh agrawal6e277772011-09-29 15:04:23 -0700520 } else if (security_ == flimflam::kSecurityNone) {
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800521 // Nothing special to do here.
mukesh agrawal6e277772011-09-29 15:04:23 -0700522 } else {
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800523 LOG(ERROR) << "Can't connect. Unsupported security method " << security_;
mukesh agrawal6e277772011-09-29 15:04:23 -0700524 }
525
Paul Stewart0654ece2013-03-26 15:21:26 -0700526 params[WPASupplicant::kNetworkPropertyEapKeyManagement].writer().
mukesh agrawal6e277772011-09-29 15:04:23 -0700527 append_string(key_management().c_str());
Gaurav Shah7ad8e532011-11-11 17:14:49 -0800528
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800529 if (ieee80211w_required_) {
530 // TODO(pstew): We should also enable IEEE 802.11w if the user
531 // explicitly enables support for this through a service / device
532 // property. crosbug.com/37800
Paul Stewart0654ece2013-03-26 15:21:26 -0700533 params[WPASupplicant::kNetworkPropertyIeee80211w].writer().
534 append_uint32(WPASupplicant::kNetworkIeee80211wEnabled);
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800535 }
536
Gaurav Shah7ad8e532011-11-11 17:14:49 -0800537 // See note in dbus_adaptor.cc on why we need to use a local.
Paul Stewart0654ece2013-03-26 15:21:26 -0700538 writer = params[WPASupplicant::kNetworkPropertySSID].writer();
mukesh agrawal6e277772011-09-29 15:04:23 -0700539 writer << ssid_;
540
Paul Stewart3c504012013-01-17 17:49:58 -0800541 wifi->ConnectTo(this, params);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700542}
543
Eric Shienbrood9a245532012-03-07 14:20:39 -0500544void WiFiService::Disconnect(Error *error) {
545 LOG(INFO) << __func__;
546 Service::Disconnect(error);
Paul Stewart3c504012013-01-17 17:49:58 -0800547 if (!wifi_) {
548 // If we are connecting to a hidden service, but have not yet found
549 // any endpoints, we could end up with a disconnect request without
550 // a wifi_ reference. This is not a fatal error.
551 LOG_IF(ERROR, IsConnecting())
552 << "WiFi endpoints do not (yet) exist. Cannot disconnect service "
553 << unique_name();
554 LOG_IF(FATAL, IsConnected())
555 << "WiFi device does not exist. Cannot disconnect service "
556 << unique_name();
557 error->Populate(Error::kOperationFailed);
558 return;
559 }
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000560 wifi_->DisconnectFrom(this);
561}
562
Paul Stewart3c504012013-01-17 17:49:58 -0800563string WiFiService::GetDeviceRpcId(Error *error) {
564 if (!wifi_) {
565 error->Populate(Error::kNotFound, "Not associated with a device");
566 return "/";
567 }
Chris Masone95207da2011-06-29 16:50:49 -0700568 return wifi_->GetRpcIdentifier();
569}
570
mukesh agrawal29c13a12011-11-24 00:09:19 +0000571void WiFiService::UpdateConnectable() {
Gaurav Shah10109f22011-11-11 20:16:22 -0800572 bool is_connectable = false;
mukesh agrawal29c13a12011-11-24 00:09:19 +0000573 if (security_ == flimflam::kSecurityNone) {
574 DCHECK(passphrase_.empty());
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800575 need_passphrase_ = false;
Gaurav Shah10109f22011-11-11 20:16:22 -0800576 is_connectable = true;
Gaurav Shah29d68882012-01-30 19:06:42 -0800577 } else if (Is8021x()) {
578 is_connectable = Is8021xConnectable();
mukesh agrawal29c13a12011-11-24 00:09:19 +0000579 } else if (security_ == flimflam::kSecurityWep ||
580 security_ == flimflam::kSecurityWpa ||
581 security_ == flimflam::kSecurityPsk ||
582 security_ == flimflam::kSecurityRsn) {
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800583 need_passphrase_ = passphrase_.empty();
Gaurav Shah10109f22011-11-11 20:16:22 -0800584 is_connectable = !need_passphrase_;
mukesh agrawal29c13a12011-11-24 00:09:19 +0000585 }
Gaurav Shah10109f22011-11-11 20:16:22 -0800586 set_connectable(is_connectable);
mukesh agrawal29c13a12011-11-24 00:09:19 +0000587}
588
mukesh agrawale1d90e92012-02-15 17:36:08 -0800589void WiFiService::UpdateFromEndpoints() {
590 const WiFiEndpoint *representative_endpoint = NULL;
591
592 if (current_endpoint_) {
mukesh agrawale1d90e92012-02-15 17:36:08 -0800593 representative_endpoint = current_endpoint_;
594 } else {
595 int16 best_signal = std::numeric_limits<int16>::min();
596 for (set<WiFiEndpointConstRefPtr>::iterator i = endpoints_.begin();
597 i != endpoints_.end(); ++i) {
598 if ((*i)->signal_strength() >= best_signal) {
599 best_signal = (*i)->signal_strength();
600 representative_endpoint = *i;
601 }
602 }
603 }
604
Paul Stewart3c504012013-01-17 17:49:58 -0800605 WiFiRefPtr wifi;
606 if (representative_endpoint) {
607 wifi = representative_endpoint->device();
Paul Stewart8653f462013-02-06 12:21:05 -0800608 } else if (IsConnected() || IsConnecting()) {
609 LOG(WARNING) << "Service " << unique_name()
610 << " will disconnect due to no remaining endpoints.";
Paul Stewart3c504012013-01-17 17:49:58 -0800611 }
612
613 SetWiFi(wifi);
614
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800615 for (set<WiFiEndpointConstRefPtr>::iterator i = endpoints_.begin();
616 i != endpoints_.end(); ++i) {
617 if ((*i)->ieee80211w_required()) {
618 // Never reset ieee80211w_required_ to false, so we track whether we have
619 // ever seen an AP that requires 802.11w.
620 ieee80211w_required_ = true;
621 }
622 }
623
mukesh agrawal43970a22013-02-15 16:00:07 -0800624 if (Is8021x())
625 cipher_8021x_ = ComputeCipher8021x(endpoints_);
626
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700627 uint16 frequency = 0;
628 int16 signal = std::numeric_limits<int16>::min();
mukesh agrawal923f14f2012-06-04 16:46:08 -0700629 string bssid;
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700630 Stringmap vendor_information;
Paul Stewart23b393a2012-09-25 21:21:06 -0700631 // Represent "unknown raw signal strength" as 0.
632 raw_signal_strength_ = 0;
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700633 if (representative_endpoint) {
mukesh agrawale1d90e92012-02-15 17:36:08 -0800634 frequency = representative_endpoint->frequency();
635 signal = representative_endpoint->signal_strength();
Paul Stewart23b393a2012-09-25 21:21:06 -0700636 raw_signal_strength_ = signal;
mukesh agrawal923f14f2012-06-04 16:46:08 -0700637 bssid = representative_endpoint->bssid_string();
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700638 vendor_information = representative_endpoint->GetVendorInformation();
mukesh agrawale1d90e92012-02-15 17:36:08 -0800639 }
640
641 if (frequency_ != frequency) {
642 frequency_ = frequency;
643 adaptor()->EmitUint16Changed(flimflam::kWifiFrequency, frequency_);
644 }
mukesh agrawal923f14f2012-06-04 16:46:08 -0700645 if (bssid_ != bssid) {
646 bssid_ = bssid;
647 adaptor()->EmitStringChanged(flimflam::kWifiBSsid, bssid_);
648 }
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700649 if (vendor_information_ != vendor_information) {
650 vendor_information_ = vendor_information;
651 adaptor()->EmitStringmapChanged(kWifiVendorInformationProperty,
652 vendor_information_);
653 }
mukesh agrawale1d90e92012-02-15 17:36:08 -0800654 SetStrength(SignalToStrength(signal));
mukesh agrawal43970a22013-02-15 16:00:07 -0800655 UpdateSecurity();
656}
657
658void WiFiService::UpdateSecurity() {
659 CryptoAlgorithm algorithm = kCryptoNone;
660 bool key_rotation = false;
661 bool endpoint_auth = false;
662
663 if (security_ == flimflam::kSecurityNone) {
664 // initial values apply
665 } else if (security_ == flimflam::kSecurityWep) {
666 algorithm = kCryptoRc4;
667 key_rotation = Is8021x();
668 endpoint_auth = Is8021x();
669 } else if (security_ == flimflam::kSecurityPsk ||
670 security_ == flimflam::kSecurityWpa) {
671 algorithm = kCryptoRc4;
672 key_rotation = true;
673 endpoint_auth = false;
674 } else if (security_ == flimflam::kSecurityRsn) {
675 algorithm = kCryptoAes;
676 key_rotation = true;
677 endpoint_auth = false;
678 } else if (security_ == flimflam::kSecurity8021x) {
679 algorithm = cipher_8021x_;
680 key_rotation = true;
681 endpoint_auth = true;
682 }
683 SetSecurity(algorithm, key_rotation, endpoint_auth);
684}
685
686// static
687Service::CryptoAlgorithm WiFiService::ComputeCipher8021x(
688 const set<WiFiEndpointConstRefPtr> &endpoints) {
689
690 if (endpoints.empty())
691 return kCryptoNone; // Will update after scan results.
692
693 // Find weakest cipher (across endpoints) of the strongest ciphers
694 // (per endpoint).
695 Service::CryptoAlgorithm cipher = Service::kCryptoAes;
696 for (set<WiFiEndpointConstRefPtr>::iterator i = endpoints.begin();
697 i != endpoints.end(); ++i) {
698 Service::CryptoAlgorithm endpoint_cipher;
699 if ((*i)->has_rsn_property()) {
700 endpoint_cipher = Service::kCryptoAes;
701 } else if ((*i)->has_wpa_property()) {
702 endpoint_cipher = Service::kCryptoRc4;
703 } else {
704 // We could be in the Dynamic WEP case here. But that's okay,
705 // because |cipher_8021x_| is not defined in that case.
706 endpoint_cipher = Service::kCryptoNone;
707 }
708 cipher = std::min(cipher, endpoint_cipher);
709 }
710 return cipher;
mukesh agrawale1d90e92012-02-15 17:36:08 -0800711}
712
mukesh agrawal1a056262011-10-05 14:36:54 -0700713// static
Thieu Lef4cbda92011-11-10 23:41:24 +0000714void WiFiService::ValidateWEPPassphrase(const std::string &passphrase,
715 Error *error) {
716 ParseWEPPassphrase(passphrase, NULL, NULL, error);
mukesh agrawal1a056262011-10-05 14:36:54 -0700717}
718
719// static
Thieu Lef4cbda92011-11-10 23:41:24 +0000720void WiFiService::ValidateWPAPassphrase(const std::string &passphrase,
721 Error *error) {
mukesh agrawal1a056262011-10-05 14:36:54 -0700722 unsigned int length = passphrase.length();
723 vector<uint8> passphrase_bytes;
724
725 if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
726 if (length != IEEE_80211::kWPAHexLen &&
727 (length < IEEE_80211::kWPAAsciiMinLen ||
728 length > IEEE_80211::kWPAAsciiMaxLen)) {
729 error->Populate(Error::kInvalidPassphrase);
730 }
731 } else {
732 if (length < IEEE_80211::kWPAAsciiMinLen ||
733 length > IEEE_80211::kWPAAsciiMaxLen) {
734 error->Populate(Error::kInvalidPassphrase);
735 }
736 }
Thieu Lef4cbda92011-11-10 23:41:24 +0000737}
mukesh agrawal1a056262011-10-05 14:36:54 -0700738
Thieu Lef4cbda92011-11-10 23:41:24 +0000739// static
740void WiFiService::ParseWEPPassphrase(const string &passphrase,
741 int *key_index,
742 std::vector<uint8> *password_bytes,
743 Error *error) {
744 unsigned int length = passphrase.length();
745 int key_index_local;
746 std::string password_text;
747 bool is_hex = false;
748
749 switch (length) {
750 case IEEE_80211::kWEP40AsciiLen:
751 case IEEE_80211::kWEP104AsciiLen:
752 key_index_local = 0;
753 password_text = passphrase;
754 break;
755 case IEEE_80211::kWEP40AsciiLen + 2:
756 case IEEE_80211::kWEP104AsciiLen + 2:
757 if (CheckWEPKeyIndex(passphrase, error)) {
758 base::StringToInt(passphrase.substr(0,1), &key_index_local);
759 password_text = passphrase.substr(2);
760 }
761 break;
762 case IEEE_80211::kWEP40HexLen:
763 case IEEE_80211::kWEP104HexLen:
764 if (CheckWEPIsHex(passphrase, error)) {
765 key_index_local = 0;
766 password_text = passphrase;
767 is_hex = true;
768 }
769 break;
770 case IEEE_80211::kWEP40HexLen + 2:
771 case IEEE_80211::kWEP104HexLen + 2:
772 if(CheckWEPKeyIndex(passphrase, error) &&
773 CheckWEPIsHex(passphrase.substr(2), error)) {
774 base::StringToInt(passphrase.substr(0,1), &key_index_local);
775 password_text = passphrase.substr(2);
776 is_hex = true;
777 } else if (CheckWEPPrefix(passphrase, error) &&
778 CheckWEPIsHex(passphrase.substr(2), error)) {
779 key_index_local = 0;
780 password_text = passphrase.substr(2);
781 is_hex = true;
782 }
783 break;
784 case IEEE_80211::kWEP40HexLen + 4:
785 case IEEE_80211::kWEP104HexLen + 4:
786 if (CheckWEPKeyIndex(passphrase, error) &&
787 CheckWEPPrefix(passphrase.substr(2), error) &&
788 CheckWEPIsHex(passphrase.substr(4), error)) {
789 base::StringToInt(passphrase.substr(0,1), &key_index_local);
790 password_text = passphrase.substr(4);
791 is_hex = true;
792 }
793 break;
794 default:
795 error->Populate(Error::kInvalidPassphrase);
796 break;
797 }
798
mukesh agrawal1a056262011-10-05 14:36:54 -0700799 if (error->IsSuccess()) {
Thieu Lef4cbda92011-11-10 23:41:24 +0000800 if (key_index)
801 *key_index = key_index_local;
802 if (password_bytes) {
803 if (is_hex)
804 base::HexStringToBytes(password_text, password_bytes);
805 else
806 password_bytes->insert(password_bytes->end(),
807 password_text.begin(),
808 password_text.end());
809 }
mukesh agrawal1a056262011-10-05 14:36:54 -0700810 }
811}
812
813// static
814bool WiFiService::CheckWEPIsHex(const string &passphrase, Error *error) {
815 vector<uint8> passphrase_bytes;
816 if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
817 return true;
818 } else {
819 error->Populate(Error::kInvalidPassphrase);
820 return false;
821 }
822}
823
824// static
825bool WiFiService::CheckWEPKeyIndex(const string &passphrase, Error *error) {
826 if (StartsWithASCII(passphrase, "0:", false) ||
827 StartsWithASCII(passphrase, "1:", false) ||
828 StartsWithASCII(passphrase, "2:", false) ||
829 StartsWithASCII(passphrase, "3:", false)) {
830 return true;
831 } else {
832 error->Populate(Error::kInvalidPassphrase);
833 return false;
834 }
835}
836
837// static
838bool WiFiService::CheckWEPPrefix(const string &passphrase, Error *error) {
839 if (StartsWithASCII(passphrase, "0x", false)) {
840 return true;
841 } else {
842 error->Populate(Error::kInvalidPassphrase);
843 return false;
844 }
845}
846
Paul Stewart6ab23a92011-11-09 17:17:47 -0800847// static
Paul Stewart6ab23a92011-11-09 17:17:47 -0800848string WiFiService::GetSecurityClass(const string &security) {
849 if (security == flimflam::kSecurityRsn ||
850 security == flimflam::kSecurityWpa) {
851 return flimflam::kSecurityPsk;
Paul Stewartd08f4432011-11-04 07:48:20 -0700852 } else {
Paul Stewart6ab23a92011-11-09 17:17:47 -0800853 return security;
Paul Stewartd08f4432011-11-04 07:48:20 -0700854 }
855}
856
Paul Stewarta41e38d2011-11-11 07:47:29 -0800857// static
858bool WiFiService::ParseStorageIdentifier(const string &storage_name,
859 string *address,
860 string *mode,
861 string *security) {
862 vector<string> wifi_parts;
863 base::SplitString(storage_name, '_', &wifi_parts);
Paul Stewart0756db92012-01-27 08:34:47 -0800864 if ((wifi_parts.size() != 5 && wifi_parts.size() != 6) ||
865 wifi_parts[0] != flimflam::kTypeWifi) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800866 return false;
867 }
868 *address = wifi_parts[1];
869 *mode = wifi_parts[3];
Paul Stewart0756db92012-01-27 08:34:47 -0800870 if (wifi_parts.size() == 5) {
871 *security = wifi_parts[4];
872 } else {
873 // Account for security type "802_1x" which got split up above.
874 *security = wifi_parts[4] + "_" + wifi_parts[5];
875 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800876 return true;
877}
878
mukesh agrawale1d90e92012-02-15 17:36:08 -0800879// static
Paul Stewart85aea152013-01-22 09:31:56 -0800880bool WiFiService::FixupServiceEntries(StoreInterface *storage) {
881 bool fixed_entry = false;
882 set<string> groups = storage->GetGroups();
883 for (set<string>::const_iterator it = groups.begin(); it != groups.end();
884 ++it) {
885 const string &id = *it;
886 string device_address, network_mode, security;
887 if (!ParseStorageIdentifier(id, &device_address,
888 &network_mode, &security)) {
889 continue;
890 }
891 if (!storage->GetString(id, kStorageType, NULL)) {
892 storage->SetString(id, kStorageType, flimflam::kTypeWifi);
893 fixed_entry = true;
894 }
895 if (!storage->GetString(id, kStorageMode, NULL)) {
896 storage->SetString(id, kStorageMode, network_mode);
897 fixed_entry = true;
898 }
899 if (!storage->GetString(id, kStorageSecurity, NULL)) {
900 storage->SetString(id, kStorageSecurity, security);
901 fixed_entry = true;
902 }
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800903 if (!storage->GetString(id, kStorageSecurityClass, NULL)) {
904 storage->SetString(id, kStorageSecurityClass, GetSecurityClass(security));
905 fixed_entry = true;
906 }
Paul Stewart85aea152013-01-22 09:31:56 -0800907 }
908 return fixed_entry;
909}
910
911// static
Paul Stewartd2e1c362013-03-03 19:06:07 -0800912bool WiFiService::IsValidMode(const string &mode) {
913 return mode == flimflam::kModeManaged ||
914 mode == flimflam::kModeAdhoc;
915}
916
917// static
Paul Stewart3c504012013-01-17 17:49:58 -0800918bool WiFiService::IsValidSecurityMethod(const string &method) {
919 return method == flimflam::kSecurityNone ||
920 method == flimflam::kSecurityWep ||
921 method == flimflam::kSecurityPsk ||
922 method == flimflam::kSecurityWpa ||
923 method == flimflam::kSecurityRsn ||
924 method == flimflam::kSecurity8021x;
925}
926
927// static
mukesh agrawale1d90e92012-02-15 17:36:08 -0800928uint8 WiFiService::SignalToStrength(int16 signal_dbm) {
929 int16 strength;
930 if (signal_dbm > 0) {
931 if (!logged_signal_warning) {
932 LOG(WARNING) << "Signal strength is suspiciously high. "
933 << "Assuming value " << signal_dbm << " is not in dBm.";
934 logged_signal_warning = true;
935 }
936 strength = signal_dbm;
937 } else {
938 strength = 120 + signal_dbm; // Call -20dBm "perfect".
939 }
940
mukesh agrawal8f3f7752012-02-17 19:42:09 -0800941 if (strength > kStrengthMax) {
942 strength = kStrengthMax;
943 } else if (strength < kStrengthMin) {
944 strength = kStrengthMin;
mukesh agrawale1d90e92012-02-15 17:36:08 -0800945 }
946 return strength;
947}
948
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800949KeyValueStore WiFiService::GetStorageProperties() const {
950 KeyValueStore args;
951 args.SetString(kStorageType, flimflam::kTypeWifi);
952 args.SetString(kStorageSSID, hex_ssid_);
953 args.SetString(kStorageMode, mode_);
954 args.SetString(kStorageSecurityClass, GetSecurityClass(security_));
955 return args;
Paul Stewart6ab23a92011-11-09 17:17:47 -0800956}
957
Paul Stewart71a4d3b2013-01-18 18:12:56 -0800958string WiFiService::GetDefaultStorageIdentifier() const {
959 string security = GetSecurityClass(security_);
960 return StringToLowerASCII(base::StringPrintf("%s_%s_%s_%s_%s",
Paul Stewartd08f4432011-11-04 07:48:20 -0700961 flimflam::kTypeWifi,
Paul Stewart3c504012013-01-17 17:49:58 -0800962 kAnyDeviceAddress,
Paul Stewartd08f4432011-11-04 07:48:20 -0700963 hex_ssid_.c_str(),
964 mode_.c_str(),
965 security.c_str()));
966}
967
Paul Stewart6df20bd2013-03-13 19:31:25 -0700968string WiFiService::GetSecurity(Error */*error*/) {
969 if (current_endpoint_) {
970 return current_endpoint_->security_mode();
971 }
972 return security_;
973}
974
Paul Stewart835934a2012-12-06 19:27:09 -0800975void WiFiService::ClearCachedCredentials() {
Paul Stewart3c504012013-01-17 17:49:58 -0800976 if (wifi_) {
977 wifi_->ClearCachedCredentials(this);
978 }
Paul Stewart835934a2012-12-06 19:27:09 -0800979}
980
Gary Moraine4aaf5e2012-04-05 14:37:32 -0700981void WiFiService::set_eap(const EapCredentials &new_eap) {
982 EapCredentials modified_eap = new_eap;
983
984 // An empty key_management field is invalid. Prevent it, if possible.
985 if (modified_eap.key_management.empty()) {
986 modified_eap.key_management = eap().key_management;
987 }
988 Service::set_eap(modified_eap);
Paul Stewart835934a2012-12-06 19:27:09 -0800989 ClearCachedCredentials();
Gaurav Shah10109f22011-11-11 20:16:22 -0800990 UpdateConnectable();
991}
992
Paul Stewart4357f4e2012-04-26 17:39:26 -0700993void WiFiService::OnProfileConfigured() {
994 if (profile() || !hidden_ssid()) {
995 return;
996 }
997 // This situation occurs when a hidden WiFi service created via GetService
998 // has been persisted to a profile in Manager::ConfigureService(). Now
999 // that configuration is saved, we must join the service with its profile,
1000 // which will make this SSID eligible for directed probes during scans.
1001 manager()->RegisterService(this);
1002}
1003
Gaurav Shah29d68882012-01-30 19:06:42 -08001004bool WiFiService::Is8021x() const {
1005 if (security_ == flimflam::kSecurity8021x)
1006 return true;
1007
1008 // Dynamic WEP + 802.1x.
1009 if (security_ == flimflam::kSecurityWep &&
1010 GetEAPKeyManagement() == "IEEE8021X")
1011 return true;
1012 return false;
1013}
1014
Paul Stewart3c504012013-01-17 17:49:58 -08001015WiFiRefPtr WiFiService::ChooseDevice() {
1016 // TODO(pstew): Style frowns on dynamic_cast. crosbug.com/38237
1017 DeviceRefPtr device =
1018 manager()->GetEnabledDeviceWithTechnology(Technology::kWifi);
1019 return dynamic_cast<WiFi *>(device.get());
1020}
1021
1022void WiFiService::ResetWiFi() {
1023 SetWiFi(NULL);
1024}
1025
1026void WiFiService::SetWiFi(const WiFiRefPtr &wifi) {
1027 if (wifi_ == wifi) {
1028 return;
1029 }
1030 ClearCachedCredentials();
1031 if (wifi_) {
1032 wifi_->DisassociateFromService(this);
1033 }
1034 wifi_ = wifi;
1035}
1036
mukesh agrawalb54601c2011-06-07 17:39:22 -07001037} // namespace shill