blob: 9de078d921b0b0a344c3ba9608b5fdbd2a6ccf84 [file] [log] [blame]
Arman Uguray2717a102013-01-29 23:36:06 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Paul Stewart75897df2011-04-27 09:05:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masoneb2e326b2011-07-12 13:28:51 -07005#include "shill/service.h"
6
Paul Stewart75897df2011-04-27 09:05:53 -07007#include <time.h>
Paul Stewart75897df2011-04-27 09:05:53 -07008#include <stdio.h>
Chris Masoneee929b72011-05-10 10:02:18 -07009
Chris Masone8fe2c7e2011-06-09 15:51:19 -070010#include <map>
Paul Stewart75897df2011-04-27 09:05:53 -070011#include <string>
Chris Masone8fe2c7e2011-06-09 15:51:19 -070012#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070013
Chris Masone3bd3c8c2011-06-13 08:20:26 -070014#include <base/memory/scoped_ptr.h>
mukesh agrawal51a7e932011-07-27 16:18:26 -070015#include <base/string_number_conversions.h>
Paul Stewart2bf424f2012-04-11 18:59:39 -070016#include <base/stringprintf.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070017#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070018
Paul Stewartbe5f5b32011-12-07 17:11:11 -080019#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070020#include "shill/control_interface.h"
Darin Petkov385b9bc2012-12-03 15:25:05 +010021#include "shill/diagnostics_reporter.h"
Paul Stewartc43cbbe2013-04-11 06:29:30 -070022#include "shill/eap_credentials.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070023#include "shill/error.h"
Paul Stewartbe5f5b32011-12-07 17:11:11 -080024#include "shill/http_proxy.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070025#include "shill/logging.h"
Chris Masone6791a432011-07-12 13:23:19 -070026#include "shill/manager.h"
Thieu Le48e6d6d2011-12-06 00:40:27 +000027#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070028#include "shill/profile.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070029#include "shill/property_accessor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070030#include "shill/refptr_types.h"
Chris Masoned7732e42011-05-20 11:08:56 -070031#include "shill/service_dbus_adaptor.h"
Darin Petkov5eb05422012-05-11 15:45:25 +020032#include "shill/sockets.h"
Darin Petkovba40dd32011-07-11 20:06:39 -070033#include "shill/store_interface.h"
Paul Stewart75897df2011-04-27 09:05:53 -070034
Christopher Wiley0801d192012-09-24 11:57:15 -070035using base::Bind;
Darin Petkov385b9bc2012-12-03 15:25:05 +010036using std::deque;
Chris Masone8fe2c7e2011-06-09 15:51:19 -070037using std::map;
Paul Stewart75897df2011-04-27 09:05:53 -070038using std::string;
Chris Masone8fe2c7e2011-06-09 15:51:19 -070039using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070040
41namespace shill {
Darin Petkovba40dd32011-07-11 20:06:39 -070042
mukesh agrawal03c15ce2012-11-29 17:36:21 -080043const char Service::kAutoConnBusy[] = "busy";
mukesh agrawalbf14e942012-03-02 14:36:34 -080044const char Service::kAutoConnConnected[] = "connected";
45const char Service::kAutoConnConnecting[] = "connecting";
46const char Service::kAutoConnExplicitDisconnect[] = "explicitly disconnected";
47const char Service::kAutoConnNotConnectable[] = "not connectable";
Darin Petkov4cbff5b2013-01-29 16:29:05 +010048const char Service::kAutoConnOffline[] = "offline";
Christopher Wiley0801d192012-09-24 11:57:15 -070049const char Service::kAutoConnThrottled[] = "throttled";
mukesh agrawalbf14e942012-03-02 14:36:34 -080050
Paul Stewartbc6e7392012-05-24 07:07:48 -070051const size_t Service::kEAPMaxCertificationElements = 10;
52
Darin Petkovba40dd32011-07-11 20:06:39 -070053const char Service::kCheckPortalAuto[] = "auto";
54const char Service::kCheckPortalFalse[] = "false";
55const char Service::kCheckPortalTrue[] = "true";
56
Darin Petkovaba89322013-03-11 14:48:22 +010057const char Service::kErrorDetailsNone[] = "";
58
Paul Stewartac4ac002011-08-26 12:04:26 -070059const int Service::kPriorityNone = 0;
60
Darin Petkov2f903b32012-04-18 12:56:43 +020061const char Service::kServiceSortAutoConnect[] = "AutoConnect";
62const char Service::kServiceSortConnectable[] = "Connectable";
Paul Stewartdf3c0a82012-11-09 15:54:33 -080063const char Service::kServiceSortDependency[] = "Dependency";
Paul Stewart2da34c02013-10-17 15:28:56 -070064const char Service::kServiceSortHasEverConnected[] = "HasEverConnected";
mukesh agrawalddc378f2012-02-17 18:26:20 -080065const char Service::kServiceSortIsConnected[] = "IsConnected";
66const char Service::kServiceSortIsConnecting[] = "IsConnecting";
67const char Service::kServiceSortIsFailed[] = "IsFailed";
Paul Stewarta121c442012-06-09 14:12:58 -070068const char Service::kServiceSortIsPortalled[] = "IsPortal";
Darin Petkov2f903b32012-04-18 12:56:43 +020069const char Service::kServiceSortPriority[] = "Priority";
mukesh agrawalddc378f2012-02-17 18:26:20 -080070const char Service::kServiceSortSecurityEtc[] = "SecurityEtc";
mukesh agrawale37ad322013-10-08 16:33:56 -070071const char Service::kServiceSortSerialNumber[] = "SerialNumber";
Darin Petkov2f903b32012-04-18 12:56:43 +020072const char Service::kServiceSortTechnology[] = "Technology";
mukesh agrawalddc378f2012-02-17 18:26:20 -080073
Darin Petkovba40dd32011-07-11 20:06:39 -070074const char Service::kStorageAutoConnect[] = "AutoConnect";
75const char Service::kStorageCheckPortal[] = "CheckPortal";
Paul Stewart0756db92012-01-27 08:34:47 -080076const char Service::kStorageError[] = "Error";
Darin Petkovba40dd32011-07-11 20:06:39 -070077const char Service::kStorageFavorite[] = "Favorite";
Paul Stewart0756db92012-01-27 08:34:47 -080078const char Service::kStorageGUID[] = "GUID";
mukesh agrawalcf24a242012-05-21 16:46:11 -070079const char Service::kStorageHasEverConnected[] = "HasEverConnected";
Paul Stewartdded0072013-10-24 12:38:54 -070080const char Service::kStorageLastDHCPOptionFailure[] = "LastDHCPOptionFailure";
Darin Petkovba40dd32011-07-11 20:06:39 -070081const char Service::kStorageName[] = "Name";
82const char Service::kStoragePriority[] = "Priority";
83const char Service::kStorageProxyConfig[] = "ProxyConfig";
84const char Service::kStorageSaveCredentials[] = "SaveCredentials";
Paul Stewart2706aaf2011-12-14 16:44:04 -080085const char Service::kStorageType[] = "Type";
Paul Stewart987e71e2011-12-05 09:45:06 -080086const char Service::kStorageUIData[] = "UIData";
Darin Petkovba40dd32011-07-11 20:06:39 -070087
mukesh agrawal8f3f7752012-02-17 19:42:09 -080088const uint8 Service::kStrengthMax = 100;
89const uint8 Service::kStrengthMin = 0;
90
Christopher Wiley0801d192012-09-24 11:57:15 -070091const uint64 Service::kMaxAutoConnectCooldownTimeMilliseconds = 30 * 60 * 1000;
92const uint64 Service::kMinAutoConnectCooldownTimeMilliseconds = 1000;
93const uint64 Service::kAutoConnectCooldownBackoffFactor = 2;
94
Darin Petkov385b9bc2012-12-03 15:25:05 +010095const int Service::kDisconnectsMonitorSeconds = 5 * 60;
96const int Service::kMisconnectsMonitorSeconds = 5 * 60;
97const int Service::kReportDisconnectsThreshold = 2;
98const int Service::kReportMisconnectsThreshold = 3;
99const int Service::kMaxDisconnectEventHistory = 20;
Paul Stewartdded0072013-10-24 12:38:54 -0700100const int Service::kMaxDHCPOptionFailures = 2;
101
102// If we encounter MTU issues, hold off sending a full DHCP request for 30 days.
103const int Service::kDHCPOptionHoldOffPeriodSeconds = 30 * 24 * 60 * 60;
Darin Petkov385b9bc2012-12-03 15:25:05 +0100104
mukesh agrawal51a7e932011-07-27 16:18:26 -0700105// static
mukesh agrawale37ad322013-10-08 16:33:56 -0700106unsigned int Service::next_serial_number_ = 0;
mukesh agrawal51a7e932011-07-27 16:18:26 -0700107
Paul Stewart75897df2011-04-27 09:05:53 -0700108Service::Service(ControlInterface *control_interface,
mukesh agrawalb54601c2011-06-07 17:39:22 -0700109 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -0800110 Metrics *metrics,
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700111 Manager *manager,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800112 Technology::Identifier technology)
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700113 : weak_ptr_factory_(this),
114 state_(kStateIdle),
Darin Petkovc8d91e52013-01-21 11:43:47 +0100115 previous_state_(kStateIdle),
Paul Stewart03dba0b2011-08-22 16:32:45 -0700116 failure_(kFailureUnknown),
117 auto_connect_(false),
Paul Stewart2da34c02013-10-17 15:28:56 -0700118 retain_auto_connect_(false),
Darin Petkovba40dd32011-07-11 20:06:39 -0700119 check_portal_(kCheckPortalAuto),
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700120 connectable_(false),
Paul Stewartf2d60912012-07-15 08:37:30 -0700121 error_(ConnectFailureToString(failure_)),
Darin Petkovaba89322013-03-11 14:48:22 +0100122 error_details_(kErrorDetailsNone),
mukesh agrawaladb68482012-01-17 16:31:51 -0800123 explicitly_disconnected_(false),
Darin Petkovba40dd32011-07-11 20:06:39 -0700124 priority_(kPriorityNone),
mukesh agrawal43970a22013-02-15 16:00:07 -0800125 crypto_algorithm_(kCryptoNone),
126 key_rotation_(false),
127 endpoint_auth_(false),
Paul Stewart22aa71b2011-09-16 12:15:11 -0700128 strength_(0),
Darin Petkovba40dd32011-07-11 20:06:39 -0700129 save_credentials_(true),
Gaurav Shah435de2c2011-11-17 19:01:07 -0800130 technology_(technology),
mukesh agrawal568b5c62012-02-28 14:44:47 -0800131 failed_time_(0),
mukesh agrawalcf24a242012-05-21 16:46:11 -0700132 has_ever_connected_(false),
Christopher Wiley0801d192012-09-24 11:57:15 -0700133 auto_connect_cooldown_milliseconds_(0),
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700134 store_(PropertyStore::PropertyChangeCallback(
135 base::Bind(&Service::OnPropertyChanged,
136 weak_ptr_factory_.GetWeakPtr()))),
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700137 dispatcher_(dispatcher),
mukesh agrawale37ad322013-10-08 16:33:56 -0700138 serial_number_(next_serial_number_++),
139 unique_name_(base::UintToString(serial_number_)),
mukesh agrawald835b202011-10-07 15:26:47 -0700140 friendly_name_(unique_name_),
Chris Masone6791a432011-07-12 13:23:19 -0700141 adaptor_(control_interface->CreateServiceAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -0800142 metrics_(metrics),
Darin Petkov5eb05422012-05-11 15:45:25 +0200143 manager_(manager),
Christopher Wiley0801d192012-09-24 11:57:15 -0700144 sockets_(new Sockets()),
Darin Petkov385b9bc2012-12-03 15:25:05 +0100145 time_(Time::GetInstance()),
Paul Stewartdded0072013-10-24 12:38:54 -0700146 diagnostics_reporter_(DiagnosticsReporter::GetInstance()),
147 consecutive_dhcp_failures_(0),
148 dhcp_option_failure_state_(kDHCPOptionFailureNotDetected) {
Ben Chan923a5022013-09-20 11:23:23 -0700149 HelpRegisterDerivedBool(kAutoConnectProperty,
Thieu Le284fe792012-01-31 17:53:19 -0800150 &Service::GetAutoConnect,
Paul Stewart43d8dc02013-10-17 10:32:53 -0700151 &Service::SetAutoConnectFull,
152 &Service::ClearAutoConnect);
Chris Masone4d42df82011-07-02 17:09:39 -0700153
Ben Chan408a8562014-02-05 00:02:18 -0800154 // kActivateOverNonCellularNetworkProperty: Registered in CellularService
Ben Chan923a5022013-09-20 11:23:23 -0700155 // kActivationStateProperty: Registered in CellularService
156 // kCellularApnProperty: Registered in CellularService
157 // kCellularLastGoodApnProperty: Registered in CellularService
158 // kNetworkTechnologyProperty: Registered in CellularService
Ben Chan408a8562014-02-05 00:02:18 -0800159 // kOutOfCreditsProperty: Registered in CellularService
160 // kPaymentPortalProperty: Registered in CellularService
Ben Chan923a5022013-09-20 11:23:23 -0700161 // kRoamingStateProperty: Registered in CellularService
162 // kServingOperatorProperty: Registered in CellularService
Ben Chan408a8562014-02-05 00:02:18 -0800163 // kUsageURLProperty: Registered in CellularService
164 // kCellularPPPUsernameProperty: Registered in CellularService
165 // kCellularPPPPasswordProperty: Registered in CellularService
166
167 // kNetworkIdProperty: Registered in WiMaxService
Chris Masone4d42df82011-07-02 17:09:39 -0700168
Ben Chan923a5022013-09-20 11:23:23 -0700169 HelpRegisterDerivedString(kCheckPortalProperty,
Paul Stewartd215af62012-04-24 23:25:50 -0700170 &Service::GetCheckPortal,
171 &Service::SetCheckPortal);
Ben Chan923a5022013-09-20 11:23:23 -0700172 store_.RegisterConstBool(kConnectableProperty, &connectable_);
173 HelpRegisterConstDerivedRpcIdentifier(kDeviceProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700174 &Service::GetDeviceRpcId);
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700175 store_.RegisterConstStrings(kEapRemoteCertificationProperty,
176 &remote_certification_);
Ben Chan923a5022013-09-20 11:23:23 -0700177 HelpRegisterDerivedString(kGuidProperty,
mukesh agrawalcbfb34e2013-04-17 19:33:25 -0700178 &Service::GetGuid,
179 &Service::SetGuid);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700180
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400181 // TODO(ers): in flimflam clearing Error has the side-effect of
182 // setting the service state to IDLE. Is this important? I could
183 // see an autotest depending on it.
Ben Chan923a5022013-09-20 11:23:23 -0700184 store_.RegisterConstString(kErrorProperty, &error_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700185 store_.RegisterConstString(kErrorDetailsProperty, &error_details_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700186 HelpRegisterConstDerivedUint16(kHTTPProxyPortProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700187 &Service::GetHTTPProxyPort);
Ben Chan39a7beb2013-09-21 11:28:00 -0700188 HelpRegisterConstDerivedRpcIdentifier(kIPConfigProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700189 &Service::GetIPConfigRpcIdentifier);
Paul Stewart43d8dc02013-10-17 10:32:53 -0700190 HelpRegisterDerivedBool(kIsActiveProperty, &Service::IsActive, NULL, NULL);
Ben Chan923a5022013-09-20 11:23:23 -0700191 // kModeProperty: Registered in WiFiService
Paul Stewart0c438332012-04-11 07:55:27 -0700192
Ben Chan923a5022013-09-20 11:23:23 -0700193 HelpRegisterDerivedString(kNameProperty,
Paul Stewart0c438332012-04-11 07:55:27 -0700194 &Service::GetNameProperty,
Darin Petkov9c6e9812013-03-26 13:49:07 +0100195 &Service::SetNameProperty);
Ben Chan923a5022013-09-20 11:23:23 -0700196 // kPassphraseProperty: Registered in WiFiService
Ben Chan408a8562014-02-05 00:02:18 -0800197 // kPassphraseRequiredProperty: Registered in WiFiService, WiMaxService
Ben Chan923a5022013-09-20 11:23:23 -0700198 HelpRegisterDerivedInt32(kPriorityProperty,
mukesh agrawalcbfb34e2013-04-17 19:33:25 -0700199 &Service::GetPriority,
200 &Service::SetPriority);
Ben Chan923a5022013-09-20 11:23:23 -0700201 HelpRegisterDerivedString(kProfileProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700202 &Service::GetProfileRpcId,
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800203 &Service::SetProfileRpcId);
Ben Chan923a5022013-09-20 11:23:23 -0700204 HelpRegisterDerivedString(kProxyConfigProperty,
Philipp Neubeck79173602012-11-13 21:10:09 +0100205 &Service::GetProxyConfig,
206 &Service::SetProxyConfig);
Ben Chan923a5022013-09-20 11:23:23 -0700207 store_.RegisterBool(kSaveCredentialsProperty, &save_credentials_);
Paul Stewartfa11e282013-12-02 22:04:25 -0800208 HelpRegisterConstDerivedString(kTetheringProperty,
209 &Service::GetTethering);
Ben Chan923a5022013-09-20 11:23:23 -0700210 HelpRegisterDerivedString(kTypeProperty,
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200211 &Service::CalculateTechnology,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800212 NULL);
Ben Chan923a5022013-09-20 11:23:23 -0700213 // kSecurityProperty: Registered in WiFiService
214 HelpRegisterDerivedString(kStateProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700215 &Service::CalculateState,
216 NULL);
Ben Chan923a5022013-09-20 11:23:23 -0700217 store_.RegisterConstUint8(kSignalStrengthProperty, &strength_);
218 store_.RegisterString(kUIDataProperty, &ui_data_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700219 HelpRegisterConstDerivedStrings(kDiagnosticsDisconnectsProperty,
Darin Petkov0c65bdd2012-12-05 13:42:41 +0100220 &Service::GetDisconnectsProperty);
Ben Chan39a7beb2013-09-21 11:28:00 -0700221 HelpRegisterConstDerivedStrings(kDiagnosticsMisconnectsProperty,
Darin Petkov0c65bdd2012-12-05 13:42:41 +0100222 &Service::GetMisconnectsProperty);
Wade Guthrie7ac610b2013-10-01 17:48:14 -0700223 metrics_->RegisterService(*this);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000224
Paul Stewart1062d9d2012-04-27 10:42:27 -0700225 static_ip_parameters_.PlumbPropertyStore(&store_);
226
Ben Chan923a5022013-09-20 11:23:23 -0700227 IgnoreParameterForConfigure(kTypeProperty);
228 IgnoreParameterForConfigure(kProfileProperty);
Paul Stewartcb59fed2012-03-21 21:14:46 -0700229
Darin Petkov9c366992013-01-10 12:32:21 +0100230 LOG(INFO) << Technology::NameFromIdentifier(technology) << " service "
231 << unique_name_ << " constructed.";
Paul Stewart75897df2011-04-27 09:05:53 -0700232}
233
Thieu Le48e6d6d2011-12-06 00:40:27 +0000234Service::~Service() {
Wade Guthrie7ac610b2013-10-01 17:48:14 -0700235 metrics_->DeregisterService(*this);
mukesh agrawal6cfe53f2013-08-13 13:39:01 -0700236 LOG(INFO) << "Service " << unique_name_ << " destroyed.";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000237}
Paul Stewart75897df2011-04-27 09:05:53 -0700238
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000239void Service::AutoConnect() {
Darin Petkov3abc3be2012-06-27 10:48:23 +0200240 const char *reason = NULL;
241 if (IsAutoConnectable(&reason)) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700242 Error error;
Darin Petkov457728b2013-01-09 09:49:08 +0100243 LOG(INFO) << "Auto-connecting to service " << unique_name_;
Christopher Wiley0801d192012-09-24 11:57:15 -0700244 ThrottleFutureAutoConnects();
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700245 Connect(&error, __func__);
mukesh agrawal76d13882012-01-12 15:23:11 -0800246 } else {
mukesh agrawal03c15ce2012-11-29 17:36:21 -0800247 if (reason == kAutoConnConnected || reason == kAutoConnBusy) {
248 SLOG(Service, 1)
Darin Petkov457728b2013-01-09 09:49:08 +0100249 << "Suppressed autoconnect to service " << unique_name_ << " "
mukesh agrawal03c15ce2012-11-29 17:36:21 -0800250 << "(" << reason << ")";
251 } else {
Darin Petkov457728b2013-01-09 09:49:08 +0100252 LOG(INFO) << "Suppressed autoconnect to service " << unique_name_ << " "
mukesh agrawal03c15ce2012-11-29 17:36:21 -0800253 << "(" << reason << ")";
254 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000255 }
256}
257
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700258void Service::Connect(Error */*error*/, const char *reason) {
259 LOG(INFO) << "Connect to service " << unique_name() <<": " << reason;
mukesh agrawaladb68482012-01-17 16:31:51 -0800260 explicitly_disconnected_ = false;
Thieu Leaf471412013-06-27 14:12:37 -0700261 // Clear any failure state from a previous connect attempt.
262 if (state() == kStateFailure)
263 SetState(kStateIdle);
mukesh agrawaladb68482012-01-17 16:31:51 -0800264}
265
266void Service::Disconnect(Error */*error*/) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700267 LOG(INFO) << "Disconnecting from service " << unique_name_;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700268 MemoryLog::GetInstance()->FlushToDisk();
mukesh agrawaladb68482012-01-17 16:31:51 -0800269}
270
Christopher Wileyabd3b502012-09-26 13:08:52 -0700271void Service::DisconnectWithFailure(ConnectFailure failure, Error *error) {
272 Disconnect(error);
273 SetFailure(failure);
274}
275
276void Service::UserInitiatedDisconnect(Error *error) {
277 Disconnect(error);
278 explicitly_disconnected_ = true;
279}
280
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500281void Service::ActivateCellularModem(const string &/*carrier*/,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500282 Error *error,
283 const ResultCallback &/*callback*/) {
284 Error::PopulateAndLog(error, Error::kNotSupported,
285 "Service doesn't support cellular modem activation.");
Darin Petkovc408e692011-08-17 13:47:15 -0700286}
287
Ben Chan5d924542013-02-14 17:49:08 -0800288void Service::CompleteCellularActivation(Error *error) {
289 Error::PopulateAndLog(
290 error, Error::kNotSupported,
291 "Service doesn't support cellular activation completion.");
292}
293
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800294bool Service::IsActive(Error */*error*/) {
Paul Stewartbfb82552012-10-24 16:48:48 -0700295 return state() != kStateUnknown &&
296 state() != kStateIdle &&
297 state() != kStateFailure;
Paul Stewart03dba0b2011-08-22 16:32:45 -0700298}
299
Darin Petkovc8d91e52013-01-21 11:43:47 +0100300// static
301bool Service::IsConnectedState(ConnectState state) {
302 return (state == kStateConnected ||
303 state == kStatePortal ||
304 state == kStateOnline);
305}
306
307// static
308bool Service::IsConnectingState(ConnectState state) {
309 return (state == kStateAssociating ||
310 state == kStateConfiguring);
311}
312
313bool Service::IsConnected() const {
314 return IsConnectedState(state());
315}
316
317bool Service::IsConnecting() const {
318 return IsConnectingState(state());
319}
320
Paul Stewart03dba0b2011-08-22 16:32:45 -0700321void Service::SetState(ConnectState state) {
322 if (state == state_) {
323 return;
324 }
325
Darin Petkov457728b2013-01-09 09:49:08 +0100326 LOG(INFO) << "Service " << unique_name_ << ": state "
327 << ConnectStateToString(state_) << " -> "
328 << ConnectStateToString(state);
329
Darin Petkov0857f8e2012-12-21 10:49:17 +0100330 if (state == kStateFailure) {
Darin Petkov385b9bc2012-12-03 15:25:05 +0100331 NoteDisconnectEvent();
332 }
333
Darin Petkovc8d91e52013-01-21 11:43:47 +0100334 previous_state_ = state_;
Paul Stewart03dba0b2011-08-22 16:32:45 -0700335 state_ = state;
336 if (state != kStateFailure) {
337 failure_ = kFailureUnknown;
Darin Petkovaba89322013-03-11 14:48:22 +0100338 SetErrorDetails(kErrorDetailsNone);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700339 }
mukesh agrawalcf24a242012-05-21 16:46:11 -0700340 if (state == kStateConnected) {
Christopher Wiley0801d192012-09-24 11:57:15 -0700341 failed_time_ = 0;
mukesh agrawalcf24a242012-05-21 16:46:11 -0700342 has_ever_connected_ = true;
343 SaveToProfile();
Christopher Wiley0801d192012-09-24 11:57:15 -0700344 // When we succeed in connecting, forget that connects failed in the past.
345 // Give services one chance at a fast autoconnect retry by resetting the
346 // cooldown to 0 to indicate that the last connect was successful.
347 auto_connect_cooldown_milliseconds_ = 0;
348 reenable_auto_connect_task_.Cancel();
mukesh agrawalcf24a242012-05-21 16:46:11 -0700349 }
Paul Stewartf2d60912012-07-15 08:37:30 -0700350 UpdateErrorProperty();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700351 manager_->UpdateService(this);
Wade Guthrie7ac610b2013-10-01 17:48:14 -0700352 metrics_->NotifyServiceStateChanged(*this, state);
Ben Chan923a5022013-09-20 11:23:23 -0700353 adaptor_->EmitStringChanged(kStateProperty, GetStateString());
Paul Stewart03dba0b2011-08-22 16:32:45 -0700354}
355
Christopher Wiley0801d192012-09-24 11:57:15 -0700356void Service::ReEnableAutoConnectTask() {
357 // Kill the thing blocking AutoConnect().
358 reenable_auto_connect_task_.Cancel();
359 // Post to the manager, giving it an opportunity to AutoConnect again.
360 manager_->UpdateService(this);
361}
362
363void Service::ThrottleFutureAutoConnects() {
364 if (auto_connect_cooldown_milliseconds_ > 0) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700365 LOG(INFO) << "Throttling future autoconnects to service " << unique_name_
366 << ". Next autoconnect in "
Christopher Wiley0801d192012-09-24 11:57:15 -0700367 << auto_connect_cooldown_milliseconds_ << " milliseconds.";
368 reenable_auto_connect_task_.Reset(Bind(&Service::ReEnableAutoConnectTask,
369 weak_ptr_factory_.GetWeakPtr()));
370 dispatcher_->PostDelayedTask(reenable_auto_connect_task_.callback(),
371 auto_connect_cooldown_milliseconds_);
372 }
373 auto_connect_cooldown_milliseconds_ =
374 std::min(kMaxAutoConnectCooldownTimeMilliseconds,
375 std::max(kMinAutoConnectCooldownTimeMilliseconds,
376 auto_connect_cooldown_milliseconds_ *
377 kAutoConnectCooldownBackoffFactor));
378}
379
Paul Stewart03dba0b2011-08-22 16:32:45 -0700380void Service::SetFailure(ConnectFailure failure) {
381 failure_ = failure;
mukesh agrawal568b5c62012-02-28 14:44:47 -0800382 failed_time_ = time(NULL);
Paul Stewartf2d60912012-07-15 08:37:30 -0700383 UpdateErrorProperty();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700384 SetState(kStateFailure);
385}
386
mukesh agrawal568b5c62012-02-28 14:44:47 -0800387void Service::SetFailureSilent(ConnectFailure failure) {
Darin Petkov0857f8e2012-12-21 10:49:17 +0100388 NoteDisconnectEvent();
mukesh agrawal568b5c62012-02-28 14:44:47 -0800389 // Note that order matters here, since SetState modifies |failure_| and
390 // |failed_time_|.
391 SetState(kStateIdle);
392 failure_ = failure;
Paul Stewartf2d60912012-07-15 08:37:30 -0700393 UpdateErrorProperty();
mukesh agrawal568b5c62012-02-28 14:44:47 -0800394 failed_time_ = time(NULL);
395}
396
Chris Masone6791a432011-07-12 13:23:19 -0700397string Service::GetRpcIdentifier() const {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700398 return adaptor_->GetRpcIdentifier();
399}
400
Paul Stewarte7de2942013-04-25 17:07:31 -0700401string Service::GetLoadableStorageIdentifier(
402 const StoreInterface &storage) const {
403 return IsLoadableFrom(storage) ? GetStorageIdentifier() : "";
404}
405
406bool Service::IsLoadableFrom(const StoreInterface &storage) const {
407 return storage.ContainsGroup(GetStorageIdentifier());
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700408}
409
Chris Masone9d779932011-08-25 16:33:41 -0700410bool Service::Load(StoreInterface *storage) {
411 const string id = GetStorageIdentifier();
Chris Masone34af2182011-08-22 11:59:36 -0700412 if (!storage->ContainsGroup(id)) {
413 LOG(WARNING) << "Service is not available in the persistent store: " << id;
414 return false;
415 }
Paul Stewart2da34c02013-10-17 15:28:56 -0700416
Paul Stewart000f0332013-10-25 13:30:28 -0700417 auto_connect_ = IsAutoConnectByDefault();
Paul Stewart2da34c02013-10-17 15:28:56 -0700418 retain_auto_connect_ =
419 storage->GetBool(id, kStorageAutoConnect, &auto_connect_);
420 // The legacy "Favorite" flag will override retain_auto_connect_ if present.
421 storage->GetBool(id, kStorageFavorite, &retain_auto_connect_);
422
Paul Stewartc3dbff12013-07-17 10:32:48 -0700423 LoadString(storage, id, kStorageCheckPortal, kCheckPortalAuto,
424 &check_portal_);
Paul Stewartc3dbff12013-07-17 10:32:48 -0700425 LoadString(storage, id, kStorageGUID, "", &guid_);
mukesh agrawalcf24a242012-05-21 16:46:11 -0700426 storage->GetBool(id, kStorageHasEverConnected, &has_ever_connected_);
Paul Stewartc3dbff12013-07-17 10:32:48 -0700427 if (!storage->GetInt(id, kStoragePriority, &priority_)) {
428 priority_ = kPriorityNone;
429 }
430 LoadString(storage, id, kStorageProxyConfig, "", &proxy_config_);
Chris Masone34af2182011-08-22 11:59:36 -0700431 storage->GetBool(id, kStorageSaveCredentials, &save_credentials_);
Paul Stewartc3dbff12013-07-17 10:32:48 -0700432 LoadString(storage, id, kStorageUIData, "", &ui_data_);
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700433
Paul Stewartdded0072013-10-24 12:38:54 -0700434 uint64 last_dhcp_option_failure;
435 if (storage->GetUint64(id, kStorageLastDHCPOptionFailure,
436 &last_dhcp_option_failure)) {
437 struct timeval tv = { 0, 0 };
438 tv.tv_sec = last_dhcp_option_failure;
439 last_dhcp_option_failure_ = Timestamp(tv, "");
440 dhcp_option_failure_state_ = kDHCPOptionFailureConfirmed;
441 } else {
442 last_dhcp_option_failure_ = Timestamp();
443 dhcp_option_failure_state_ = kDHCPOptionFailureNotDetected;
444 }
445
Paul Stewart1062d9d2012-04-27 10:42:27 -0700446 static_ip_parameters_.Load(storage, id);
Chris Masone34af2182011-08-22 11:59:36 -0700447
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700448 if (mutable_eap()) {
449 mutable_eap()->Load(storage, id);
450 OnEapCredentialsChanged();
451 }
452
mukesh agrawaladb68482012-01-17 16:31:51 -0800453 explicitly_disconnected_ = false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800454
Chris Masone34af2182011-08-22 11:59:36 -0700455 return true;
Darin Petkovba40dd32011-07-11 20:06:39 -0700456}
457
Paul Stewart65512e12012-03-26 18:01:08 -0700458bool Service::Unload() {
Paul Stewart7fb09382012-07-18 17:32:27 -0700459 auto_connect_ = IsAutoConnectByDefault();
Paul Stewart2da34c02013-10-17 15:28:56 -0700460 retain_auto_connect_ = false;
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800461 check_portal_ = kCheckPortalAuto;
Christopher Wileyabd3b502012-09-26 13:08:52 -0700462 explicitly_disconnected_ = false;
Paul Stewarte7cce8f2012-09-11 10:56:38 -0700463 guid_ = "";
Paul Stewart88769de2012-09-21 13:14:36 -0700464 has_ever_connected_ = false;
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800465 priority_ = kPriorityNone;
466 proxy_config_ = "";
467 save_credentials_ = true;
468 ui_data_ = "";
Paul Stewartdded0072013-10-24 12:38:54 -0700469 consecutive_dhcp_failures_ = 0;
470 last_dhcp_option_failure_ = Timestamp();
471 dhcp_option_failure_state_ = kDHCPOptionFailureNotDetected;
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700472 if (mutable_eap()) {
473 mutable_eap()->Reset();
474 }
475 ClearEAPCertification();
Paul Stewartd8ad3c42012-01-09 12:39:38 -0800476
Wade Guthrie9e0c2502012-04-19 15:26:40 -0700477 Error error; // Ignored.
478 Disconnect(&error);
Paul Stewart65512e12012-03-26 18:01:08 -0700479 return false;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800480}
481
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800482void Service::Remove(Error */*error*/) {
Paul Stewartd3d03882013-08-29 15:43:42 -0700483 manager()->RemoveService(this);
484 // |this| may no longer be valid now.
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800485}
486
Chris Masone9d779932011-08-25 16:33:41 -0700487bool Service::Save(StoreInterface *storage) {
488 const string id = GetStorageIdentifier();
Chris Masone34af2182011-08-22 11:59:36 -0700489
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200490 storage->SetString(id, kStorageType, GetTechnologyString());
Paul Stewart2706aaf2011-12-14 16:44:04 -0800491
Paul Stewart2da34c02013-10-17 15:28:56 -0700492 if (retain_auto_connect_) {
493 storage->SetBool(id, kStorageAutoConnect, auto_connect_);
494 } else {
495 storage->DeleteKey(id, kStorageAutoConnect);
496 }
497
498 // Remove this legacy flag.
499 storage->DeleteKey(id, kStorageFavorite);
500
Chris Masone34af2182011-08-22 11:59:36 -0700501 if (check_portal_ == kCheckPortalAuto) {
502 storage->DeleteKey(id, kStorageCheckPortal);
503 } else {
504 storage->SetString(id, kStorageCheckPortal, check_portal_);
505 }
Paul Stewart2da34c02013-10-17 15:28:56 -0700506
mukesh agrawalcf24a242012-05-21 16:46:11 -0700507 SaveString(storage, id, kStorageGUID, guid_, false, true);
508 storage->SetBool(id, kStorageHasEverConnected, has_ever_connected_);
mukesh agrawald835b202011-10-07 15:26:47 -0700509 storage->SetString(id, kStorageName, friendly_name_);
Chris Masone34af2182011-08-22 11:59:36 -0700510 if (priority_ != kPriorityNone) {
511 storage->SetInt(id, kStoragePriority, priority_);
512 } else {
513 storage->DeleteKey(id, kStoragePriority);
514 }
Paul Stewart987e71e2011-12-05 09:45:06 -0800515 SaveString(storage, id, kStorageProxyConfig, proxy_config_, false, true);
Darin Petkov0debec02013-01-22 10:40:05 +0100516 storage->SetBool(id, kStorageSaveCredentials, save_credentials_);
Paul Stewart987e71e2011-12-05 09:45:06 -0800517 SaveString(storage, id, kStorageUIData, ui_data_, false, true);
Chris Masone34af2182011-08-22 11:59:36 -0700518
Paul Stewartdded0072013-10-24 12:38:54 -0700519 if (dhcp_option_failure_state_ == kDHCPOptionFailureConfirmed ||
520 dhcp_option_failure_state_ == kDHCPOptionFailureRetestMinimalRequest ||
521 dhcp_option_failure_state_ == kDHCPOptionFailureRetestFullRequest ||
522 dhcp_option_failure_state_ == kDHCPOptionFailureRetestGotNoReply) {
523 // In any of the states where we maintain a history of DHCP option
524 // failures and we haven't confirmed that this is no longer an issue,
525 // we should save the last option failure time even if it is very long ago.
526 storage->SetUint64(id, kStorageLastDHCPOptionFailure,
527 last_dhcp_option_failure_.monotonic.tv_sec);
528 } else {
529 storage->DeleteKey(id, kStorageLastDHCPOptionFailure);
530 }
531
Paul Stewart1062d9d2012-04-27 10:42:27 -0700532 static_ip_parameters_.Save(storage, id);
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700533 if (eap()) {
534 eap()->Save(storage, id, save_credentials_);
535 }
Paul Stewartdded0072013-10-24 12:38:54 -0700536
Chris Masone34af2182011-08-22 11:59:36 -0700537 return true;
538}
539
Gary Moraind93615e2012-04-27 11:50:03 -0700540void Service::SaveToCurrentProfile() {
541 // Some unittests do not specify a manager.
542 if (manager()) {
543 manager()->SaveServiceToProfile(this);
544 }
Thieu Led4e9e552012-02-16 16:26:07 -0800545}
546
Paul Stewartcb59fed2012-03-21 21:14:46 -0700547void Service::Configure(const KeyValueStore &args, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700548 SLOG(Service, 5) << "Configuring bool properties:";
Paul Stewart99dc9f32013-06-27 07:39:25 -0700549 for (const auto &bool_it : args.bool_properties()) {
550 if (ContainsKey(parameters_ignored_for_configure_, bool_it.first)) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700551 continue;
552 }
Paul Stewart99dc9f32013-06-27 07:39:25 -0700553 SLOG(Service, 5) << " " << bool_it.first;
Paul Stewartcb59fed2012-03-21 21:14:46 -0700554 Error set_error;
Paul Stewart99dc9f32013-06-27 07:39:25 -0700555 store_.SetBoolProperty(bool_it.first, bool_it.second, &set_error);
556 OnPropertyChanged(bool_it.first);
Paul Stewartcb59fed2012-03-21 21:14:46 -0700557 if (error->IsSuccess() && set_error.IsFailure()) {
558 error->CopyFrom(set_error);
559 }
560 }
Paul Stewart7a20aa42013-01-17 12:21:41 -0800561 SLOG(Service, 5) << "Configuring int32 properties:";
Paul Stewart99dc9f32013-06-27 07:39:25 -0700562 for (const auto &int_it : args.int_properties()) {
563 if (ContainsKey(parameters_ignored_for_configure_, int_it.first)) {
Paul Stewartcb59fed2012-03-21 21:14:46 -0700564 continue;
565 }
Paul Stewart99dc9f32013-06-27 07:39:25 -0700566 SLOG(Service, 5) << " " << int_it.first;
Paul Stewartcb59fed2012-03-21 21:14:46 -0700567 Error set_error;
Paul Stewart99dc9f32013-06-27 07:39:25 -0700568 store_.SetInt32Property(int_it.first, int_it.second, &set_error);
569 OnPropertyChanged(int_it.first);
570 if (error->IsSuccess() && set_error.IsFailure()) {
571 error->CopyFrom(set_error);
572 }
573 }
574 SLOG(Service, 5) << "Configuring string properties:";
575 for (const auto &string_it : args.string_properties()) {
576 if (ContainsKey(parameters_ignored_for_configure_, string_it.first)) {
577 continue;
578 }
579 SLOG(Service, 5) << " " << string_it.first;
580 Error set_error;
581 store_.SetStringProperty(string_it.first, string_it.second, &set_error);
582 OnPropertyChanged(string_it.first);
583 if (error->IsSuccess() && set_error.IsFailure()) {
584 error->CopyFrom(set_error);
585 }
586 }
587 SLOG(Service, 5) << "Configuring string array properties:";
588 for (const auto &strings_it : args.strings_properties()) {
589 if (ContainsKey(parameters_ignored_for_configure_, strings_it.first)) {
590 continue;
591 }
592 SLOG(Service, 5) << " " << strings_it.first;
593 Error set_error;
594 store_.SetStringsProperty(strings_it.first, strings_it.second, &set_error);
595 OnPropertyChanged(strings_it.first);
Paul Stewartcb59fed2012-03-21 21:14:46 -0700596 if (error->IsSuccess() && set_error.IsFailure()) {
597 error->CopyFrom(set_error);
598 }
599 }
Arman Uguray631c7e42013-07-30 16:41:12 -0700600 SLOG(Service, 5) << "Configuring string map properties:";
601 for (const auto &stringmap_it : args.stringmap_properties()) {
602 if (ContainsKey(parameters_ignored_for_configure_, stringmap_it.first)) {
603 continue;
604 }
605 SLOG(Service, 5) << " " << stringmap_it.first;
606 Error set_error;
607 store_.SetStringmapProperty(
608 stringmap_it.first, stringmap_it.second, &set_error);
609 OnPropertyChanged(stringmap_it.first);
610 if (error->IsSuccess() && set_error.IsFailure()) {
611 error->CopyFrom(set_error);
612 }
613 }
Paul Stewartcb59fed2012-03-21 21:14:46 -0700614}
615
Paul Stewart7a20aa42013-01-17 12:21:41 -0800616bool Service::DoPropertiesMatch(const KeyValueStore &args) const {
Paul Stewart7a20aa42013-01-17 12:21:41 -0800617 SLOG(Service, 5) << "Checking bool properties:";
Paul Stewart99dc9f32013-06-27 07:39:25 -0700618 for (const auto &bool_it: args.bool_properties()) {
619 SLOG(Service, 5) << " " << bool_it.first;
Paul Stewart7a20aa42013-01-17 12:21:41 -0800620 Error get_error;
621 bool value;
Paul Stewart99dc9f32013-06-27 07:39:25 -0700622 if (!store_.GetBoolProperty(bool_it.first, &value, &get_error) ||
623 value != bool_it.second) {
Paul Stewart7a20aa42013-01-17 12:21:41 -0800624 return false;
625 }
626 }
627 SLOG(Service, 5) << "Checking int32 properties:";
Paul Stewart99dc9f32013-06-27 07:39:25 -0700628 for (const auto &int_it : args.int_properties()) {
629 SLOG(Service, 5) << " " << int_it.first;
Paul Stewart7a20aa42013-01-17 12:21:41 -0800630 Error get_error;
631 int32 value;
Paul Stewart99dc9f32013-06-27 07:39:25 -0700632 if (!store_.GetInt32Property(int_it.first, &value, &get_error) ||
633 value != int_it.second) {
634 return false;
635 }
636 }
637 SLOG(Service, 5) << "Checking string properties:";
638 for (const auto &string_it : args.string_properties()) {
639 SLOG(Service, 5) << " " << string_it.first;
640 Error get_error;
641 string value;
642 if (!store_.GetStringProperty(string_it.first, &value, &get_error) ||
643 value != string_it.second) {
644 return false;
645 }
646 }
647 SLOG(Service, 5) << "Checking string array properties:";
648 for (const auto &strings_it : args.strings_properties()) {
649 SLOG(Service, 5) << " " << strings_it.first;
650 Error get_error;
651 vector<string> value;
652 if (!store_.GetStringsProperty(strings_it.first, &value, &get_error) ||
653 value != strings_it.second) {
Paul Stewart7a20aa42013-01-17 12:21:41 -0800654 return false;
655 }
656 }
657 return true;
658}
659
Paul Stewart10ccbb32012-04-26 15:59:30 -0700660bool Service::IsRemembered() const {
661 return profile_ && !manager_->IsServiceEphemeral(this);
662}
663
Paul Stewartdf3c0a82012-11-09 15:54:33 -0800664bool Service::IsDependentOn(const ServiceRefPtr &b) const {
Paul Stewartcd7f5852013-03-27 13:54:23 -0700665 if (!connection_ || !b || !b->connection()) {
Paul Stewartdf3c0a82012-11-09 15:54:33 -0800666 return false;
667 }
668 return connection_->GetLowerConnection() == b->connection();
669}
670
Paul Stewart2da34c02013-10-17 15:28:56 -0700671void Service::EnableAndRetainAutoConnect() {
672 if (retain_auto_connect_) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000673 // We do not want to clobber the value of auto_connect_ (it may
674 // be user-set). So return early.
675 return;
676 }
677
mukesh agrawalcbfb34e2013-04-17 19:33:25 -0700678 SetAutoConnect(true);
Paul Stewart2da34c02013-10-17 15:28:56 -0700679 RetainAutoConnect();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000680}
681
Darin Petkov5eb05422012-05-11 15:45:25 +0200682void Service::SetConnection(const ConnectionRefPtr &connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800683 if (connection.get()) {
Paul Stewart1e3bc4962012-09-14 12:20:22 -0700684 // TODO(pstew): Make this function testable by using a factory here.
Paul Stewartee6b3d72013-07-12 16:07:51 -0700685 // http://crbug.com/216664
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800686 http_proxy_.reset(new HTTPProxy(connection));
Darin Petkov5eb05422012-05-11 15:45:25 +0200687 http_proxy_->Start(dispatcher_, sockets_.get());
Paul Stewart7f5d9c02013-12-03 18:26:00 -0800688 Error unused_error;
689 connection->set_tethering(GetTethering(&unused_error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800690 } else {
691 http_proxy_.reset();
Paul Stewartdef189e2012-08-02 20:12:09 -0700692 static_ip_parameters_.ClearSavedParameters();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800693 }
694 connection_ = connection;
Paul Stewart1e3bc4962012-09-14 12:20:22 -0700695 Error error;
696 string ipconfig = GetIPConfigRpcIdentifier(&error);
697 if (error.IsSuccess()) {
Ben Chan39a7beb2013-09-21 11:28:00 -0700698 adaptor_->EmitRpcIdentifierChanged(kIPConfigProperty, ipconfig);
Paul Stewart1e3bc4962012-09-14 12:20:22 -0700699 }
Paul Stewartbe5f5b32011-12-07 17:11:11 -0800700}
701
Gaurav Shah10109f22011-11-11 20:16:22 -0800702bool Service::Is8021xConnectable() const {
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700703 return eap() && eap()->IsConnectable();
Gaurav Shah10109f22011-11-11 20:16:22 -0800704}
705
Paul Stewartbc6e7392012-05-24 07:07:48 -0700706bool Service::AddEAPCertification(const string &name, size_t depth) {
707 if (depth >= kEAPMaxCertificationElements) {
708 LOG(WARNING) << "Ignoring certification " << name
709 << " because depth " << depth
710 << " exceeds our maximum of "
711 << kEAPMaxCertificationElements;
712 return false;
713 }
714
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700715 if (depth >= remote_certification_.size()) {
716 remote_certification_.resize(depth + 1);
717 } else if (name == remote_certification_[depth]) {
Paul Stewartbc6e7392012-05-24 07:07:48 -0700718 return true;
719 }
720
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700721 remote_certification_[depth] = name;
Paul Stewartbc6e7392012-05-24 07:07:48 -0700722 LOG(INFO) << "Received certification for "
723 << name
724 << " at depth "
725 << depth;
726 return true;
727}
728
729void Service::ClearEAPCertification() {
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700730 remote_certification_.clear();
Paul Stewartbc6e7392012-05-24 07:07:48 -0700731}
732
mukesh agrawalcbfb34e2013-04-17 19:33:25 -0700733void Service::SetAutoConnect(bool connect) {
734 if (auto_connect() == connect) {
735 return;
736 }
737 auto_connect_ = connect;
Ben Chan923a5022013-09-20 11:23:23 -0700738 adaptor_->EmitBoolChanged(kAutoConnectProperty, auto_connect());
mukesh agrawalcbfb34e2013-04-17 19:33:25 -0700739}
740
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700741void Service::SetEapCredentials(EapCredentials *eap) {
742 // This operation must be done at most once for the lifetime of the service.
743 CHECK(eap && !eap_);
744
745 eap_.reset(eap);
746 eap_->InitPropertyStore(mutable_store());
Gaurav Shah10109f22011-11-11 20:16:22 -0800747}
748
mukesh agrawal00917ce2011-11-22 23:56:55 +0000749// static
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800750const char *Service::ConnectFailureToString(const ConnectFailure &state) {
751 switch (state) {
752 case kFailureUnknown:
753 return "Unknown";
Paul Stewartf2d60912012-07-15 08:37:30 -0700754 case kFailureAAA:
Ben Chan923a5022013-09-20 11:23:23 -0700755 return kErrorAaaFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700756 case kFailureActivation:
Ben Chan923a5022013-09-20 11:23:23 -0700757 return kErrorActivationFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700758 case kFailureBadPassphrase:
Ben Chan923a5022013-09-20 11:23:23 -0700759 return kErrorBadPassphrase;
Paul Stewartf2d60912012-07-15 08:37:30 -0700760 case kFailureBadWEPKey:
Ben Chan923a5022013-09-20 11:23:23 -0700761 return kErrorBadWEPKey;
Paul Stewartf2d60912012-07-15 08:37:30 -0700762 case kFailureConnect:
Ben Chan923a5022013-09-20 11:23:23 -0700763 return kErrorConnectFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700764 case kFailureDNSLookup:
Ben Chan923a5022013-09-20 11:23:23 -0700765 return kErrorDNSLookupFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700766 case kFailureDHCP:
Ben Chan923a5022013-09-20 11:23:23 -0700767 return kErrorDhcpFailed;
Darin Petkov1c049c72013-03-21 13:15:45 +0100768 case kFailureEAPAuthentication:
Ben Chan39a7beb2013-09-21 11:28:00 -0700769 return kErrorEapAuthenticationFailed;
Darin Petkov1c049c72013-03-21 13:15:45 +0100770 case kFailureEAPLocalTLS:
Ben Chan39a7beb2013-09-21 11:28:00 -0700771 return kErrorEapLocalTlsFailed;
Darin Petkov1c049c72013-03-21 13:15:45 +0100772 case kFailureEAPRemoteTLS:
Ben Chan39a7beb2013-09-21 11:28:00 -0700773 return kErrorEapRemoteTlsFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700774 case kFailureHTTPGet:
Ben Chan923a5022013-09-20 11:23:23 -0700775 return kErrorHTTPGetFailed;
Darin Petkov1c049c72013-03-21 13:15:45 +0100776 case kFailureInternal:
Ben Chan923a5022013-09-20 11:23:23 -0700777 return kErrorInternal;
Darin Petkov1c049c72013-03-21 13:15:45 +0100778 case kFailureIPSecCertAuth:
Ben Chan923a5022013-09-20 11:23:23 -0700779 return kErrorIpsecCertAuthFailed;
Darin Petkov1c049c72013-03-21 13:15:45 +0100780 case kFailureIPSecPSKAuth:
Ben Chan923a5022013-09-20 11:23:23 -0700781 return kErrorIpsecPskAuthFailed;
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800782 case kFailureNeedEVDO:
Ben Chan923a5022013-09-20 11:23:23 -0700783 return kErrorNeedEvdo;
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800784 case kFailureNeedHomeNetwork:
Ben Chan923a5022013-09-20 11:23:23 -0700785 return kErrorNeedHomeNetwork;
Paul Stewartf2d60912012-07-15 08:37:30 -0700786 case kFailureOTASP:
Ben Chan923a5022013-09-20 11:23:23 -0700787 return kErrorOtaspFailed;
Paul Stewartf2d60912012-07-15 08:37:30 -0700788 case kFailureOutOfRange:
Ben Chan923a5022013-09-20 11:23:23 -0700789 return kErrorOutOfRange;
Paul Stewartf2d60912012-07-15 08:37:30 -0700790 case kFailurePinMissing:
Ben Chan923a5022013-09-20 11:23:23 -0700791 return kErrorPinMissing;
Paul Stewartf2d60912012-07-15 08:37:30 -0700792 case kFailurePPPAuth:
Ben Chan923a5022013-09-20 11:23:23 -0700793 return kErrorPppAuthFailed;
Thieu Le48e6d6d2011-12-06 00:40:27 +0000794 case kFailureMax:
Darin Petkov1c049c72013-03-21 13:15:45 +0100795 NOTREACHED();
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800796 }
797 return "Invalid";
798}
799
800// static
801const char *Service::ConnectStateToString(const ConnectState &state) {
802 switch (state) {
803 case kStateUnknown:
804 return "Unknown";
805 case kStateIdle:
806 return "Idle";
807 case kStateAssociating:
808 return "Associating";
809 case kStateConfiguring:
810 return "Configuring";
811 case kStateConnected:
812 return "Connected";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000813 case kStatePortal:
814 return "Portal";
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800815 case kStateFailure:
816 return "Failure";
817 case kStateOnline:
818 return "Online";
819 }
820 return "Invalid";
821}
822
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200823string Service::GetTechnologyString() const {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800824 return Technology::NameFromIdentifier(technology());
825}
826
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200827string Service::CalculateTechnology(Error */*error*/) {
828 return GetTechnologyString();
829}
830
Paul Stewart483e4722012-12-18 10:23:17 -0800831// static
832void Service::ExpireEventsBefore(
833 int seconds_ago, const Timestamp &now, std::deque<Timestamp> *events) {
834 struct timeval period = (const struct timeval){ seconds_ago };
835 while (!events->empty()) {
836 if (events->size() < static_cast<size_t>(kMaxDisconnectEventHistory)) {
Paul Stewartdded0072013-10-24 12:38:54 -0700837 struct timeval elapsed { 0 };
Paul Stewart483e4722012-12-18 10:23:17 -0800838 timersub(&now.monotonic, &events->front().monotonic, &elapsed);
839 if (timercmp(&elapsed, &period, <)) {
840 break;
841 }
842 }
843 events->pop_front();
844 }
845}
846
Darin Petkov385b9bc2012-12-03 15:25:05 +0100847void Service::NoteDisconnectEvent() {
848 SLOG(Service, 2) << __func__;
Darin Petkovcb0b5662012-12-13 09:59:44 +0100849 // Ignore the event if it's user-initiated explicit disconnect.
Darin Petkov385b9bc2012-12-03 15:25:05 +0100850 if (explicitly_disconnected_) {
Darin Petkovcb0b5662012-12-13 09:59:44 +0100851 SLOG(Service, 2) << "Explicit disconnect ignored.";
852 return;
853 }
854 // Ignore the event if manager is not running (e.g., service disconnects on
855 // shutdown).
856 if (!manager_->running()) {
857 SLOG(Service, 2) << "Disconnect while manager stopped ignored.";
858 return;
859 }
860 // Ignore the event if the power state is not on (e.g., when suspending).
861 PowerManager *power_manager = manager_->power_manager();
862 if (!power_manager ||
863 (power_manager->power_state() != PowerManager::kOn &&
864 power_manager->power_state() != PowerManager::kUnknown)) {
865 SLOG(Service, 2) << "Disconnect in transitional power state ignored.";
Darin Petkov385b9bc2012-12-03 15:25:05 +0100866 return;
867 }
Paul Stewart483e4722012-12-18 10:23:17 -0800868 int period = 0;
Darin Petkov385b9bc2012-12-03 15:25:05 +0100869 size_t threshold = 0;
Darin Petkov0c65bdd2012-12-05 13:42:41 +0100870 deque<Timestamp> *events = NULL;
Darin Petkovc8d91e52013-01-21 11:43:47 +0100871 // Sometimes services transition to Idle before going into a failed state so
872 // take into account the last non-idle state.
873 ConnectState state = state_ == kStateIdle ? previous_state_ : state_;
874 if (IsConnectedState(state)) {
Darin Petkovcb0b5662012-12-13 09:59:44 +0100875 LOG(INFO) << "Noting an unexpected connection drop.";
Paul Stewart483e4722012-12-18 10:23:17 -0800876 period = kDisconnectsMonitorSeconds;
Darin Petkov385b9bc2012-12-03 15:25:05 +0100877 threshold = kReportDisconnectsThreshold;
878 events = &disconnects_;
Darin Petkovc8d91e52013-01-21 11:43:47 +0100879 } else if (IsConnectingState(state)) {
Darin Petkovcb0b5662012-12-13 09:59:44 +0100880 LOG(INFO) << "Noting an unexpected failure to connect.";
Paul Stewart483e4722012-12-18 10:23:17 -0800881 period = kMisconnectsMonitorSeconds;
Darin Petkov385b9bc2012-12-03 15:25:05 +0100882 threshold = kReportMisconnectsThreshold;
883 events = &misconnects_;
884 } else {
Darin Petkovcb0b5662012-12-13 09:59:44 +0100885 SLOG(Service, 2)
886 << "Not connected or connecting, state transition ignored.";
Darin Petkov385b9bc2012-12-03 15:25:05 +0100887 return;
888 }
Darin Petkov0c65bdd2012-12-05 13:42:41 +0100889 Timestamp now = time_->GetNow();
Paul Stewart483e4722012-12-18 10:23:17 -0800890 // Discard old events first.
891 ExpireEventsBefore(period, now, events);
Darin Petkov385b9bc2012-12-03 15:25:05 +0100892 events->push_back(now);
893 if (events->size() >= threshold) {
894 diagnostics_reporter_->OnConnectivityEvent();
895 }
896}
897
Paul Stewart483e4722012-12-18 10:23:17 -0800898bool Service::HasRecentConnectionIssues() {
899 Timestamp now = time_->GetNow();
900 ExpireEventsBefore(kDisconnectsMonitorSeconds, now, &disconnects_);
901 ExpireEventsBefore(kMisconnectsMonitorSeconds, now, &misconnects_);
902 return !disconnects_.empty() || !misconnects_.empty();
903}
904
Jason Glasgowb5790052012-01-27 01:03:52 -0500905// static
Paul Stewart22aa71b2011-09-16 12:15:11 -0700906bool Service::DecideBetween(int a, int b, bool *decision) {
907 if (a == b)
908 return false;
909 *decision = (a > b);
910 return true;
911}
912
mukesh agrawal43970a22013-02-15 16:00:07 -0800913uint16 Service::SecurityLevel() {
914 return (crypto_algorithm_ << 2) | (key_rotation_ << 1) | endpoint_auth_;
915}
916
mukesh agrawal00917ce2011-11-22 23:56:55 +0000917// static
Paul Stewart22aa71b2011-09-16 12:15:11 -0700918bool Service::Compare(ServiceRefPtr a,
919 ServiceRefPtr b,
Paul Stewart39db5ca2013-03-18 14:15:17 -0700920 bool compare_connectivity_state,
mukesh agrawalddc378f2012-02-17 18:26:20 -0800921 const vector<Technology::Identifier> &tech_order,
922 const char **reason) {
Paul Stewart22aa71b2011-09-16 12:15:11 -0700923 bool ret;
924
Paul Stewart39db5ca2013-03-18 14:15:17 -0700925 if (compare_connectivity_state && a->state() != b->state()) {
Paul Stewart22aa71b2011-09-16 12:15:11 -0700926 if (DecideBetween(a->IsConnected(), b->IsConnected(), &ret)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800927 *reason = kServiceSortIsConnected;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700928 return ret;
929 }
930
Paul Stewarta121c442012-06-09 14:12:58 -0700931 if (DecideBetween(!a->IsPortalled(), !b->IsPortalled(), &ret)) {
932 *reason = kServiceSortIsPortalled;
933 return ret;
934 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700935
936 if (DecideBetween(a->IsConnecting(), b->IsConnecting(), &ret)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800937 *reason = kServiceSortIsConnecting;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700938 return ret;
939 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000940
941 if (DecideBetween(!a->IsFailed(), !b->IsFailed(), &ret)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800942 *reason = kServiceSortIsFailed;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000943 return ret;
944 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700945 }
946
Darin Petkov2f903b32012-04-18 12:56:43 +0200947 if (DecideBetween(a->connectable(), b->connectable(), &ret)) {
948 *reason = kServiceSortConnectable;
949 return ret;
950 }
951
Paul Stewartdf3c0a82012-11-09 15:54:33 -0800952 if (DecideBetween(a->IsDependentOn(b), b->IsDependentOn(a), &ret)) {
953 *reason = kServiceSortDependency;
954 return ret;
955 }
956
Darin Petkov2f903b32012-04-18 12:56:43 +0200957 // Ignore the auto-connect property if both services are connected
958 // already. This allows connected non-autoconnectable VPN services to be
959 // sorted higher than other connected services based on technology order.
960 if (!a->IsConnected() &&
961 DecideBetween(a->auto_connect(), b->auto_connect(), &ret)) {
962 *reason = kServiceSortAutoConnect;
963 return ret;
964 }
965
Paul Stewart2da34c02013-10-17 15:28:56 -0700966 if (DecideBetween(a->has_ever_connected(), b->has_ever_connected(), &ret)) {
967 *reason = kServiceSortHasEverConnected;
Darin Petkov2f903b32012-04-18 12:56:43 +0200968 return ret;
969 }
970
971 if (DecideBetween(a->priority(), b->priority(), &ret)) {
972 *reason = kServiceSortPriority;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700973 return ret;
974 }
975
976 // TODO(pstew): Below this point we are making value judgements on
977 // services that are not related to anything intrinsic or
978 // user-specified. These heuristics should be richer (contain
979 // historical information, for example) and be subject to user
980 // customization.
Paul Stewart22aa71b2011-09-16 12:15:11 -0700981 for (vector<Technology::Identifier>::const_iterator it = tech_order.begin();
982 it != tech_order.end();
983 ++it) {
Joshua Kroll053fa822012-06-05 09:50:43 -0700984 if (DecideBetween(a->technology() == *it, b->technology() == *it, &ret)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800985 *reason = kServiceSortTechnology;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700986 return ret;
mukesh agrawalddc378f2012-02-17 18:26:20 -0800987 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700988 }
989
mukesh agrawal43970a22013-02-15 16:00:07 -0800990 if (DecideBetween(a->SecurityLevel(), b->SecurityLevel(), &ret) ||
Paul Stewart22aa71b2011-09-16 12:15:11 -0700991 DecideBetween(a->strength(), b->strength(), &ret)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800992 *reason = kServiceSortSecurityEtc;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700993 return ret;
994 }
995
mukesh agrawale37ad322013-10-08 16:33:56 -0700996 *reason = kServiceSortSerialNumber;
997 return a->serial_number_ < b->serial_number_;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700998}
999
Chris Masone34af2182011-08-22 11:59:36 -07001000const ProfileRefPtr &Service::profile() const { return profile_; }
1001
1002void Service::set_profile(const ProfileRefPtr &p) { profile_ = p; }
1003
Philipp Neubeck79173602012-11-13 21:10:09 +01001004void Service::SetProfile(const ProfileRefPtr &p) {
1005 SLOG(Service, 2) << "SetProfile from "
1006 << (profile_ ? profile_->GetFriendlyName() : "")
1007 << " to " << (p ? p->GetFriendlyName() : "");
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001008 if (profile_ == p) {
1009 return;
1010 }
Philipp Neubeck79173602012-11-13 21:10:09 +01001011 profile_ = p;
1012 Error error;
1013 string profile_rpc_id = GetProfileRpcId(&error);
1014 if (!error.IsSuccess()) {
1015 return;
1016 }
Ben Chan923a5022013-09-20 11:23:23 -07001017 adaptor_->EmitStringChanged(kProfileProperty, profile_rpc_id);
Philipp Neubeck79173602012-11-13 21:10:09 +01001018}
1019
Paul Stewartff14b022012-04-24 20:06:23 -07001020void Service::OnPropertyChanged(const string &property) {
Paul Stewartc43cbbe2013-04-11 06:29:30 -07001021 if (Is8021x() && EapCredentials::IsEapAuthenticationProperty(property)) {
1022 OnEapCredentialsChanged();
Paul Stewart81426132012-05-16 10:05:10 -07001023 }
mukesh agrawalcf24a242012-05-21 16:46:11 -07001024 SaveToProfile();
Ben Chan923a5022013-09-20 11:23:23 -07001025 if ((property == kCheckPortalProperty ||
1026 property == kProxyConfigProperty) &&
Paul Stewartd215af62012-04-24 23:25:50 -07001027 (state_ == kStateConnected ||
1028 state_ == kStatePortal ||
1029 state_ == kStateOnline)) {
1030 manager_->RecheckPortalOnService(this);
1031 }
Paul Stewartff14b022012-04-24 20:06:23 -07001032}
1033
Christopher Wiley0801d192012-09-24 11:57:15 -07001034void Service::OnAfterResume() {
1035 // Forget old autoconnect failures across suspend/resume.
1036 auto_connect_cooldown_milliseconds_ = 0;
1037 reenable_auto_connect_task_.Cancel();
Christopher Wileya4c61ae2012-10-01 11:04:30 -07001038 // Forget if the user disconnected us, we might be able to connect now.
1039 explicitly_disconnected_ = false;
Christopher Wiley0801d192012-09-24 11:57:15 -07001040}
1041
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001042string Service::GetIPConfigRpcIdentifier(Error *error) const {
Paul Stewart10241e32012-04-23 18:15:06 -07001043 if (!connection_) {
1044 error->Populate(Error::kNotFound);
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001045 return DBusAdaptor::kNullPath;
Paul Stewart10241e32012-04-23 18:15:06 -07001046 }
1047
1048 string id = connection_->ipconfig_rpc_identifier();
1049
1050 if (id.empty()) {
1051 // Do not return an empty IPConfig.
1052 error->Populate(Error::kNotFound);
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001053 return DBusAdaptor::kNullPath;
Paul Stewart10241e32012-04-23 18:15:06 -07001054 }
1055
1056 return id;
1057}
1058
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001059void Service::SetConnectable(bool connectable) {
1060 if (connectable_ == connectable)
1061 return;
mukesh agrawal29c13a12011-11-24 00:09:19 +00001062 connectable_ = connectable;
Ben Chan923a5022013-09-20 11:23:23 -07001063 adaptor_->EmitBoolChanged(kConnectableProperty, connectable_);
mukesh agrawal29c13a12011-11-24 00:09:19 +00001064}
1065
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001066void Service::SetConnectableFull(bool connectable) {
Darin Petkovb2ba39f2012-06-06 10:33:43 +02001067 if (connectable_ == connectable) {
1068 return;
1069 }
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001070 SetConnectable(connectable);
Darin Petkovb2ba39f2012-06-06 10:33:43 +02001071 if (manager_->HasService(this)) {
1072 manager_->UpdateService(this);
1073 }
1074}
1075
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001076string Service::GetStateString() const {
Ben Chan923a5022013-09-20 11:23:23 -07001077 // TODO(benchan): We may want to rename shill::kState* to avoid name clashing
1078 // with Service::kState*.
Paul Stewart03e29f72013-09-26 00:49:48 -07001079 switch (state()) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001080 case kStateIdle:
Ben Chan923a5022013-09-20 11:23:23 -07001081 return shill::kStateIdle;
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001082 case kStateAssociating:
Ben Chan923a5022013-09-20 11:23:23 -07001083 return shill::kStateAssociation;
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001084 case kStateConfiguring:
Ben Chan923a5022013-09-20 11:23:23 -07001085 return shill::kStateConfiguration;
mukesh agrawalf2f68a52011-09-01 12:15:48 -07001086 case kStateConnected:
Ben Chan923a5022013-09-20 11:23:23 -07001087 return shill::kStateReady;
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001088 case kStateFailure:
Ben Chan923a5022013-09-20 11:23:23 -07001089 return shill::kStateFailure;
Paul Stewart20088d82012-02-16 06:58:55 -08001090 case kStatePortal:
Ben Chan923a5022013-09-20 11:23:23 -07001091 return shill::kStatePortal;
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001092 case kStateOnline:
Ben Chan923a5022013-09-20 11:23:23 -07001093 return shill::kStateOnline;
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001094 case kStateUnknown:
mukesh agrawalf2f68a52011-09-01 12:15:48 -07001095 default:
Gaurav Shahc6d6c722011-11-17 18:59:39 -08001096 return "";
mukesh agrawalf2f68a52011-09-01 12:15:48 -07001097 }
1098}
1099
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001100string Service::CalculateState(Error */*error*/) {
1101 return GetStateString();
1102}
1103
mukesh agrawalbf14e942012-03-02 14:36:34 -08001104bool Service::IsAutoConnectable(const char **reason) const {
1105 if (!connectable()) {
1106 *reason = kAutoConnNotConnectable;
1107 return false;
1108 }
1109
1110 if (IsConnected()) {
1111 *reason = kAutoConnConnected;
1112 return false;
1113 }
1114
1115 if (IsConnecting()) {
1116 *reason = kAutoConnConnecting;
1117 return false;
1118 }
1119
1120 if (explicitly_disconnected_) {
1121 *reason = kAutoConnExplicitDisconnect;
1122 return false;
1123 }
1124
Christopher Wiley0801d192012-09-24 11:57:15 -07001125 if (!reenable_auto_connect_task_.IsCancelled()) {
1126 *reason = kAutoConnThrottled;
1127 return false;
1128 }
1129
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001130 if (!Technology::IsPrimaryConnectivityTechnology(technology_) &&
1131 !manager_->IsOnline()) {
1132 *reason = kAutoConnOffline;
1133 return false;
1134 }
1135
mukesh agrawalbf14e942012-03-02 14:36:34 -08001136 return true;
mukesh agrawal76d13882012-01-12 15:23:11 -08001137}
1138
Paul Stewartd215af62012-04-24 23:25:50 -07001139bool Service::IsPortalDetectionDisabled() const {
1140 return check_portal_ == kCheckPortalFalse;
1141}
1142
1143bool Service::IsPortalDetectionAuto() const {
1144 return check_portal_ == kCheckPortalAuto;
1145}
1146
mukesh agrawalffa3d042011-10-06 15:26:10 -07001147void Service::HelpRegisterDerivedBool(
1148 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001149 bool(Service::*get)(Error *),
Paul Stewart43d8dc02013-10-17 10:32:53 -07001150 bool(Service::*set)(const bool&, Error *),
1151 void(Service::*clear)(Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001152 store_.RegisterDerivedBool(
1153 name,
Paul Stewart43d8dc02013-10-17 10:32:53 -07001154 BoolAccessor(new CustomAccessor<Service, bool>(this, get, set, clear)));
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001155}
1156
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001157void Service::HelpRegisterDerivedInt32(
1158 const string &name,
1159 int32(Service::*get)(Error *),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001160 bool(Service::*set)(const int32&, Error *)) {
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001161 store_.RegisterDerivedInt32(
1162 name,
1163 Int32Accessor(new CustomAccessor<Service, int32>(this, get, set)));
1164}
1165
mukesh agrawalffa3d042011-10-06 15:26:10 -07001166void Service::HelpRegisterDerivedString(
1167 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001168 string(Service::*get)(Error *),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001169 bool(Service::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001170 store_.RegisterDerivedString(
1171 name,
1172 StringAccessor(new CustomAccessor<Service, string>(this, get, set)));
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001173}
1174
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001175void Service::HelpRegisterConstDerivedRpcIdentifier(
Jason Glasgowacdc11f2012-03-30 14:12:22 -04001176 const string &name,
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001177 RpcIdentifier(Service::*get)(Error *) const) {
Jason Glasgowacdc11f2012-03-30 14:12:22 -04001178 store_.RegisterDerivedRpcIdentifier(
1179 name,
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001180 RpcIdentifierAccessor(new CustomReadOnlyAccessor<Service, RpcIdentifier>(
1181 this, get)));
Jason Glasgowacdc11f2012-03-30 14:12:22 -04001182}
1183
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001184void Service::HelpRegisterConstDerivedUint16(
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001185 const string &name,
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001186 uint16(Service::*get)(Error *) const) {
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001187 store_.RegisterDerivedUint16(
1188 name,
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001189 Uint16Accessor(new CustomReadOnlyAccessor<Service, uint16>(this, get)));
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001190}
1191
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001192void Service::HelpRegisterConstDerivedStrings(
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001193 const string &name, Strings(Service::*get)(Error *error) const) {
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001194 store_.RegisterDerivedStrings(
1195 name,
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001196 StringsAccessor(new CustomReadOnlyAccessor<Service, Strings>(this, get)));
1197}
1198
1199void Service::HelpRegisterConstDerivedString(
1200 const string &name, string(Service::*get)(Error *error) const) {
1201 store_.RegisterDerivedString(
1202 name,
1203 StringAccessor(new CustomReadOnlyAccessor<Service, string>(this, get)));
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001204}
1205
Paul Stewartc43cbbe2013-04-11 06:29:30 -07001206// static
Paul Stewartc3dbff12013-07-17 10:32:48 -07001207void Service::LoadString(StoreInterface *storage,
1208 const string &id,
1209 const string &key,
1210 const string &default_value,
1211 string *value) {
1212 if (!storage->GetString(id, key, value)) {
1213 *value = default_value;
1214 }
1215}
1216
1217// static
Darin Petkovba40dd32011-07-11 20:06:39 -07001218void Service::SaveString(StoreInterface *storage,
Chris Masone34af2182011-08-22 11:59:36 -07001219 const string &id,
Darin Petkovba40dd32011-07-11 20:06:39 -07001220 const string &key,
1221 const string &value,
1222 bool crypted,
1223 bool save) {
1224 if (value.empty() || !save) {
Chris Masone34af2182011-08-22 11:59:36 -07001225 storage->DeleteKey(id, key);
Darin Petkovba40dd32011-07-11 20:06:39 -07001226 return;
1227 }
1228 if (crypted) {
Chris Masone34af2182011-08-22 11:59:36 -07001229 storage->SetCryptedString(id, key, value);
Darin Petkovba40dd32011-07-11 20:06:39 -07001230 return;
1231 }
Chris Masone34af2182011-08-22 11:59:36 -07001232 storage->SetString(id, key, value);
Darin Petkovba40dd32011-07-11 20:06:39 -07001233}
1234
Paul Stewart967eaeb2013-04-25 19:53:07 -07001235map<string, string> Service::GetLoadableProfileEntries() {
1236 return manager_->GetLoadableProfileEntriesForService(this);
1237}
1238
Paul Stewartcb59fed2012-03-21 21:14:46 -07001239void Service::IgnoreParameterForConfigure(const string &parameter) {
1240 parameters_ignored_for_configure_.insert(parameter);
1241}
1242
Paul Stewartac4ac002011-08-26 12:04:26 -07001243const string &Service::GetEAPKeyManagement() const {
Paul Stewartc43cbbe2013-04-11 06:29:30 -07001244 CHECK(eap());
1245 return eap()->key_management();
Paul Stewartac4ac002011-08-26 12:04:26 -07001246}
1247
1248void Service::SetEAPKeyManagement(const string &key_management) {
Paul Stewartc43cbbe2013-04-11 06:29:30 -07001249 CHECK(mutable_eap());
1250 mutable_eap()->SetKeyManagement(key_management, NULL);
Paul Stewartac4ac002011-08-26 12:04:26 -07001251}
1252
Thieu Le284fe792012-01-31 17:53:19 -08001253bool Service::GetAutoConnect(Error */*error*/) {
1254 return auto_connect();
1255}
1256
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001257bool Service::SetAutoConnectFull(const bool &connect, Error */*error*/) {
Darin Petkov36d962d2013-03-25 13:03:14 +01001258 LOG(INFO) << "Service " << unique_name() << ": AutoConnect="
1259 << auto_connect() << "->" << connect;
Paul Stewart36e67be2013-12-12 14:36:10 -08001260 RetainAutoConnect();
1261
1262 if (auto_connect() == connect) {
1263 return false;
Darin Petkov36d962d2013-03-25 13:03:14 +01001264 }
Paul Stewart96a6d092013-08-26 09:32:49 -07001265
Paul Stewart36e67be2013-12-12 14:36:10 -08001266 SetAutoConnect(connect);
1267 manager_->UpdateService(this);
1268 return true;
Thieu Le284fe792012-01-31 17:53:19 -08001269}
1270
Paul Stewart43d8dc02013-10-17 10:32:53 -07001271void Service::ClearAutoConnect(Error */*error*/) {
Paul Stewart43d8dc02013-10-17 10:32:53 -07001272 if (auto_connect()) {
1273 SetAutoConnect(false);
Paul Stewart43d8dc02013-10-17 10:32:53 -07001274 manager_->UpdateService(this);
1275 }
Paul Stewart2da34c02013-10-17 15:28:56 -07001276
1277 retain_auto_connect_ = false;
Paul Stewart43d8dc02013-10-17 10:32:53 -07001278}
1279
Paul Stewartd215af62012-04-24 23:25:50 -07001280string Service::GetCheckPortal(Error *error) {
1281 return check_portal_;
1282}
1283
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001284bool Service::SetCheckPortal(const string &check_portal, Error *error) {
Paul Stewartd215af62012-04-24 23:25:50 -07001285 if (check_portal != kCheckPortalFalse &&
1286 check_portal != kCheckPortalTrue &&
1287 check_portal != kCheckPortalAuto) {
1288 Error::PopulateAndLog(error, Error::kInvalidArguments,
1289 base::StringPrintf(
1290 "Invalid Service CheckPortal property value: %s",
1291 check_portal.c_str()));
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001292 return false;
1293 }
1294 if (check_portal == check_portal_) {
1295 return false;
Paul Stewartd215af62012-04-24 23:25:50 -07001296 }
1297 check_portal_ = check_portal;
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001298 return true;
Paul Stewartd215af62012-04-24 23:25:50 -07001299}
1300
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001301string Service::GetGuid(Error *error) {
1302 return guid_;
1303}
1304
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001305bool Service::SetGuid(const string &guid, Error */*error*/) {
1306 if (guid_ == guid) {
1307 return false;
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001308 }
1309 guid_ = guid;
Ben Chan923a5022013-09-20 11:23:23 -07001310 adaptor_->EmitStringChanged(kGuidProperty, guid_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001311 return true;
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001312}
1313
Paul Stewart2da34c02013-10-17 15:28:56 -07001314void Service::RetainAutoConnect() {
1315 retain_auto_connect_ = true;
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001316}
1317
mukesh agrawal43970a22013-02-15 16:00:07 -08001318void Service::SetSecurity(CryptoAlgorithm crypto_algorithm, bool key_rotation,
1319 bool endpoint_auth) {
1320 crypto_algorithm_ = crypto_algorithm;
1321 key_rotation_ = key_rotation;
1322 endpoint_auth_ = endpoint_auth;
1323}
1324
mukesh agrawald4dc0832013-03-25 14:38:26 -07001325string Service::GetNameProperty(Error */*error*/) {
Paul Stewart0c438332012-04-11 07:55:27 -07001326 return friendly_name_;
1327}
1328
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001329bool Service::SetNameProperty(const string &name, Error *error) {
Paul Stewart0c438332012-04-11 07:55:27 -07001330 if (name != friendly_name_) {
1331 Error::PopulateAndLog(error, Error::kInvalidArguments,
Paul Stewart2bf424f2012-04-11 18:59:39 -07001332 base::StringPrintf(
Darin Petkov457728b2013-01-09 09:49:08 +01001333 "Service %s Name property cannot be modified.",
1334 unique_name_.c_str()));
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001335 return false;
Paul Stewart0c438332012-04-11 07:55:27 -07001336 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001337 return false;
Paul Stewart0c438332012-04-11 07:55:27 -07001338}
1339
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001340int32 Service::GetPriority(Error *error) {
1341 return priority_;
1342}
1343
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001344bool Service::SetPriority(const int32 &priority, Error *error) {
1345 if (priority_ == priority) {
1346 return false;
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001347 }
1348 priority_ = priority;
Ben Chan923a5022013-09-20 11:23:23 -07001349 adaptor_->EmitIntChanged(kPriorityProperty, priority_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001350 return true;
mukesh agrawalcbfb34e2013-04-17 19:33:25 -07001351}
1352
Paul Stewart1b1a7f22012-01-06 16:24:06 -08001353string Service::GetProfileRpcId(Error *error) {
1354 if (!profile_) {
1355 // This happens in some unit tests where profile_ is not set.
1356 error->Populate(Error::kNotFound);
1357 return "";
1358 }
1359 return profile_->GetRpcIdentifier();
1360}
1361
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001362bool Service::SetProfileRpcId(const string &profile, Error *error) {
1363 if (profile_ && profile_->GetRpcIdentifier() == profile) {
1364 return false;
1365 }
1366 ProfileConstRefPtr old_profile = profile_;
1367 // No need to Emit afterwards, since SetProfileForService will call
1368 // into SetProfile (if the profile actually changes).
Paul Stewart1b1a7f22012-01-06 16:24:06 -08001369 manager_->SetProfileForService(this, profile, error);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001370 // Can't just use error.IsSuccess(), because that also requires saving
1371 // the profile to succeed. (See Profile::AdoptService)
1372 return (profile_ != old_profile);
Paul Stewart1b1a7f22012-01-06 16:24:06 -08001373}
1374
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001375uint16 Service::GetHTTPProxyPort(Error */*error*/) const {
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001376 if (http_proxy_.get()) {
1377 return static_cast<uint16>(http_proxy_->proxy_port());
1378 }
1379 return 0;
1380}
1381
Philipp Neubeck79173602012-11-13 21:10:09 +01001382string Service::GetProxyConfig(Error *error) {
1383 return proxy_config_;
1384}
1385
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001386bool Service::SetProxyConfig(const string &proxy_config, Error *error) {
1387 if (proxy_config_ == proxy_config)
1388 return false;
Philipp Neubeck79173602012-11-13 21:10:09 +01001389 proxy_config_ = proxy_config;
Ben Chan923a5022013-09-20 11:23:23 -07001390 adaptor_->EmitStringChanged(kProxyConfigProperty, proxy_config_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001391 return true;
Philipp Neubeck79173602012-11-13 21:10:09 +01001392}
1393
Paul Stewartfa11e282013-12-02 22:04:25 -08001394string Service::GetTethering(Error *error) const {
1395 // The "Tethering" property isn't supported by the Service base class, and
1396 // therefore should not be listed in the properties returned by
1397 // the GetProperties() RPC method.
1398 error->Populate(Error::kNotSupported);
1399 return "";
1400}
1401
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001402// static
1403Strings Service::ExtractWallClockToStrings(
1404 const deque<Timestamp> &timestamps) {
1405 Strings strings;
1406 for (deque<Timestamp>::const_iterator it = timestamps.begin();
1407 it != timestamps.end(); ++it) {
1408 strings.push_back(it->wall_clock);
1409 }
1410 return strings;
1411}
1412
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001413Strings Service::GetDisconnectsProperty(Error */*error*/) const {
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001414 return ExtractWallClockToStrings(disconnects_);
1415}
1416
Paul Stewart1cf7eb82013-12-03 19:34:36 -08001417Strings Service::GetMisconnectsProperty(Error */*error*/) const {
Darin Petkov0c65bdd2012-12-05 13:42:41 +01001418 return ExtractWallClockToStrings(misconnects_);
1419}
1420
mukesh agrawalcf24a242012-05-21 16:46:11 -07001421void Service::SaveToProfile() {
1422 if (profile_.get() && profile_->GetConstStorage()) {
1423 profile_->UpdateService(this);
1424 }
1425}
1426
Arman Uguray2717a102013-01-29 23:36:06 -08001427void Service::SetFriendlyName(const string &friendly_name) {
1428 if (friendly_name == friendly_name_)
1429 return;
1430 friendly_name_ = friendly_name;
Ben Chan923a5022013-09-20 11:23:23 -07001431 adaptor()->EmitStringChanged(kNameProperty, friendly_name_);
Arman Uguray2717a102013-01-29 23:36:06 -08001432}
1433
Darin Petkovd78ee7e2012-01-12 11:21:10 +01001434void Service::SetStrength(uint8 strength) {
1435 if (strength == strength_) {
1436 return;
1437 }
1438 strength_ = strength;
Ben Chan923a5022013-09-20 11:23:23 -07001439 adaptor_->EmitUint8Changed(kSignalStrengthProperty, strength);
Darin Petkovd78ee7e2012-01-12 11:21:10 +01001440}
1441
Darin Petkovaba89322013-03-11 14:48:22 +01001442void Service::SetErrorDetails(const string &details) {
1443 if (error_details_ == details) {
1444 return;
1445 }
1446 error_details_ = details;
Ben Chan39a7beb2013-09-21 11:28:00 -07001447 adaptor_->EmitStringChanged(kErrorDetailsProperty, error_details_);
Darin Petkovaba89322013-03-11 14:48:22 +01001448}
1449
Paul Stewartf2d60912012-07-15 08:37:30 -07001450void Service::UpdateErrorProperty() {
1451 const string error(ConnectFailureToString(failure_));
1452 if (error == error_) {
1453 return;
1454 }
1455 error_ = error;
Ben Chan923a5022013-09-20 11:23:23 -07001456 adaptor_->EmitStringChanged(kErrorProperty, error);
Paul Stewartf2d60912012-07-15 08:37:30 -07001457}
1458
Paul Stewartdded0072013-10-24 12:38:54 -07001459void Service::OnDHCPFailure() {
1460 consecutive_dhcp_failures_++;
1461 switch (dhcp_option_failure_state_) {
1462 case kDHCPOptionFailureNotDetected:
1463 // If we run into too many consecutive DHCP failures, we must suspect
1464 // that this may be due in part to the number of options we are requesting
1465 // from the server. Next time, we should try asking for less options.
1466 if (consecutive_dhcp_failures_ >= kMaxDHCPOptionFailures) {
1467 SLOG(Service, 2) << "Service " << unique_name_ << " is failing to "
1468 << "receive DHCP responses. The next attempt will "
1469 << "be with minimal DHCP options.";
1470 dhcp_option_failure_state_ = kDHCPOptionFailureSuspected;
1471 }
1472 break;
1473
1474 case kDHCPOptionFailureSuspected:
1475 // Requesting a shorter DHCP reply does not seem to have helped. As
1476 // such, we should exonerate DHCP options as the source of the failures.
1477 SLOG(Service, 2) << "Service " << unique_name_ << " did not get a DHCP "
1478 << "response even with minimal options set.";
1479 dhcp_option_failure_state_ = kDHCPOptionFailureNotDetected;
1480
1481 // Unless we set our failure count back to 0, we'll end up toggling back
1482 // and forth endlessly between the Suspected and NotDetected states.
1483 consecutive_dhcp_failures_ = 0;
1484 break;
1485
1486 case kDHCPOptionFailureConfirmed:
1487 // Nothing to do here. We've previously confirmed that this network
1488 // has problems with requests for a large number of DHCP options, so
1489 // we'll continue to send small requests until our timeout expires.
1490 break;
1491
1492 case kDHCPOptionFailureRetestFullRequest:
1493 // This means that we are still running into issues with DHCP responses
1494 // when we send a full request. It's likely that the problem with this
1495 // network still exists. Let's confirm this by switching back to minimal
1496 // requests.
1497 SLOG(Service, 2) << "Service " << unique_name_ << " tried a full DHCP "
1498 << "request and it still appears to be failing.";
1499 dhcp_option_failure_state_ = kDHCPOptionFailureRetestMinimalRequest;
1500 break;
1501
1502 case kDHCPOptionFailureRetestMinimalRequest:
1503 // Requesting a shorter DHCP reply does not seem to have helped.
1504 // However we still have a memory of this once being a problem, so
1505 // it is probably best to continue sending short requests and postpone
1506 // a re-test until we get a reply.
1507 SLOG(Service, 2) << "Service " << unique_name_ << " seems not to be "
1508 << "getting any DHCP responses at all.";
1509 dhcp_option_failure_state_ = kDHCPOptionFailureRetestGotNoReply;
1510 break;
1511
1512 case kDHCPOptionFailureRetestGotNoReply:
1513 // Nothing to do here. We are still failing to receive a reply.
1514 break;
1515 }
1516}
1517
1518void Service::OnDHCPSuccess() {
1519 consecutive_dhcp_failures_ = 0;
1520 switch (dhcp_option_failure_state_) {
1521 case kDHCPOptionFailureNotDetected:
1522 // Nothing to do. All is well with the world.
1523 break;
1524
1525 case kDHCPOptionFailureSuspected: // FALLTHROUGH
1526 case kDHCPOptionFailureRetestMinimalRequest:
1527 LOG(WARNING) << "Service " << unique_name_ << " can get a DHCP "
1528 << "response only with minimal options requested.";
1529 // We just performed an experiment to prove that the DHCP failures we
1530 // have been having might be related to the number of options we have
1531 // been requesting. It appears that as soon as we reduced the option
1532 // count, our request succeeded.
1533 dhcp_option_failure_state_ = kDHCPOptionFailureConfirmed;
1534 last_dhcp_option_failure_ = time_->GetNow();
1535 metrics_->NotifyDHCPOptionFailure(*this);
1536 break;
1537
1538 case kDHCPOptionFailureConfirmed:
1539 // Nothing to do here. We've previously confirmed that this network
1540 // has problems with requests for a large number of DHCP options, so
1541 // we'll continue to send small requests until our timeout expires.
1542 break;
1543
1544 case kDHCPOptionFailureRetestFullRequest:
1545 // We expected this request to fail, since we attempted a full request
1546 // on a network we previously believed dropped DHCP replies for such
1547 // requests. Let's exonerate this network.
1548 SLOG(Service, 2) << "Service " << unique_name_ << " was able to receive "
1549 << "a response to a full DHCP request. Switching back "
1550 << "to full requests by default.";
1551 dhcp_option_failure_state_ = kDHCPOptionFailureNotDetected;
1552 break;
1553
1554 case kDHCPOptionFailureRetestGotNoReply:
1555 // We are finally receiving DHCP replies again. Resume the test
1556 // starting with the next time we perform a DHCP request.
1557 SLOG(Service, 2) << "Service " << unique_name_ << " was finally able to "
1558 << "receive a DHCP response.";
1559 dhcp_option_failure_state_ = kDHCPOptionFailureRetestFullRequest;
1560 break;
1561 }
1562}
1563
1564bool Service::ShouldUseMinimalDHCPConfig() {
1565 // If it's been a while since we have tested for options failures, we should
1566 // re-confirm if this issue still exists.
1567 if (dhcp_option_failure_state_ == kDHCPOptionFailureConfirmed) {
1568 Timestamp now = time_->GetNow();
1569 struct timeval elapsed { 0 };
1570 timersub(&now.monotonic, &last_dhcp_option_failure_.monotonic, &elapsed);
1571 struct timeval period { kDHCPOptionHoldOffPeriodSeconds };
1572 if (timercmp(&elapsed, &period, >=)) {
1573 SLOG(Service, 2) << "Service " << unique_name_ << " will be re-tested to "
1574 << "see if the server responds to a full DHCP request.";
1575 dhcp_option_failure_state_ = kDHCPOptionFailureRetestFullRequest;
1576 }
1577 }
1578
1579 return
1580 dhcp_option_failure_state_ == kDHCPOptionFailureSuspected ||
1581 dhcp_option_failure_state_ == kDHCPOptionFailureConfirmed ||
1582 dhcp_option_failure_state_ == kDHCPOptionFailureRetestMinimalRequest ||
1583 dhcp_option_failure_state_ == kDHCPOptionFailureRetestGotNoReply;
1584}
1585
Paul Stewart75897df2011-04-27 09:05:53 -07001586} // namespace shill