blob: 1bdf6de17ae7fbf917e466e80104afb42eb73753 [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 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 Masone2b105542011-06-22 10:58:09 -07005#include "shill/device.h"
6
Matthew Wein08add482015-04-20 13:26:48 -07007#include <errno.h>
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -07008#include <netinet/in.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -07009#include <linux/if.h> // NOLINT - Needs definitions from netinet/in.h
Paul Stewart75897df2011-04-27 09:05:53 -070010#include <stdio.h>
Paul Stewart208a97e2015-05-13 09:11:12 -070011#include <sys/param.h>
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -070012#include <time.h>
Matthew Wein08add482015-04-20 13:26:48 -070013#include <unistd.h>
Chris Masoneee929b72011-05-10 10:02:18 -070014
Samuel Tan787a1ce2014-11-11 17:17:27 -080015#include <algorithm>
Garret Kellyc5f89d12015-02-18 14:39:36 -050016#include <set>
Paul Stewart75897df2011-04-27 09:05:53 -070017#include <string>
Chris Masone8fe2c7e2011-06-09 15:51:19 -070018#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070019
Eric Shienbrood3e20a232012-02-16 11:35:56 -050020#include <base/bind.h>
Ben Chan11c213f2014-09-05 08:21:06 -070021#include <base/files/file_util.h>
Chris Masone487b8bf2011-05-13 16:27:57 -070022#include <base/memory/ref_counted.h>
Paul Stewart38fcf162015-06-12 09:52:17 -070023#include <base/stl_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -080024#include <base/strings/stringprintf.h>
Peter Qiu62abf312015-05-05 12:58:05 -070025#include <base/strings/string_number_conversions.h>
26#include <base/strings/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070027#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070028
Arman Ugurayf84a4242013-04-09 20:01:07 -070029#include "shill/async_connection.h"
Paul Stewarte6132022011-08-16 09:11:02 -070030#include "shill/connection.h"
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -070031#include "shill/connection_tester.h"
Paul Stewart75897df2011-04-27 09:05:53 -070032#include "shill/control_interface.h"
Chris Masoned7732e42011-05-20 11:08:56 -070033#include "shill/device_dbus_adaptor.h"
Peter Qiu675d0b02015-06-03 13:08:09 -070034#include "shill/dhcp/dhcp_config.h"
35#include "shill/dhcp/dhcp_provider.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070036#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070037#include "shill/event_dispatcher.h"
Gaurav Shah6d2c72d2012-10-16 16:30:44 -070038#include "shill/geolocation_info.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070039#include "shill/http_proxy.h"
Peter Qiu62abf312015-05-05 12:58:05 -070040#include "shill/icmp.h"
Samuel Tanfe734672014-08-07 15:50:48 -070041#include "shill/ip_address_store.h"
Paul Stewart036dba02012-08-07 12:34:41 -070042#include "shill/link_monitor.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070043#include "shill/logging.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070044#include "shill/manager.h"
Thieu Le85e050b2012-03-13 15:04:38 -070045#include "shill/metrics.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070046#include "shill/net/ip_address.h"
47#include "shill/net/ndisc.h"
48#include "shill/net/rtnl_handler.h"
Chris Masone95207da2011-06-29 16:50:49 -070049#include "shill/property_accessor.h"
Chris Masone2b105542011-06-22 10:58:09 -070050#include "shill/refptr_types.h"
Chris Masone2b105542011-06-22 10:58:09 -070051#include "shill/service.h"
Arman Ugurayf84a4242013-04-09 20:01:07 -070052#include "shill/socket_info_reader.h"
Chris Masone5dec5f42011-07-22 14:07:55 -070053#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080054#include "shill/technology.h"
Paul Stewartfa11e282013-12-02 22:04:25 -080055#include "shill/tethering.h"
Peter Qiudc335f82014-05-15 10:33:17 -070056#include "shill/traffic_monitor.h"
Paul Stewart75897df2011-04-27 09:05:53 -070057
Eric Shienbrood3e20a232012-02-16 11:35:56 -050058using base::Bind;
Peter Qiu6f5618b2014-06-05 15:19:01 -070059using base::Callback;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080060using base::FilePath;
Chris Masone5dec5f42011-07-22 14:07:55 -070061using base::StringPrintf;
Garret Kellyc5f89d12015-02-18 14:39:36 -050062using std::set;
Chris Masone8fe2c7e2011-06-09 15:51:19 -070063using std::string;
64using std::vector;
65
Paul Stewart75897df2011-04-27 09:05:53 -070066namespace shill {
Chris Masone5dec5f42011-07-22 14:07:55 -070067
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070068namespace Logging {
69static auto kModuleLogScope = ScopeLogger::kDevice;
Paul Stewarta794cd62015-06-16 13:13:10 -070070static string ObjectID(Device* d) { return d->GetRpcIdentifier(); }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070071}
72
Chris Masone5dec5f42011-07-22 14:07:55 -070073// static
Paul Stewart2bf1d352011-12-06 15:02:55 -080074const char Device::kIPFlagTemplate[] = "/proc/sys/net/%s/conf/%s/%s";
75// static
76const char Device::kIPFlagVersion4[] = "ipv4";
77// static
78const char Device::kIPFlagVersion6[] = "ipv6";
79// static
80const char Device::kIPFlagDisableIPv6[] = "disable_ipv6";
81// static
82const char Device::kIPFlagUseTempAddr[] = "use_tempaddr";
83// static
84const char Device::kIPFlagUseTempAddrUsedAndDefault[] = "2";
Paul Stewartc8f4bef2011-12-13 09:45:51 -080085// static
86const char Device::kIPFlagReversePathFilter[] = "rp_filter";
87// static
88const char Device::kIPFlagReversePathFilterEnabled[] = "1";
89// static
90const char Device::kIPFlagReversePathFilterLooseMode[] = "2";
Paul Stewart2bf1d352011-12-06 15:02:55 -080091// static
Paul Stewart2cb3fa72014-11-13 01:43:12 -080092const char Device::kIPFlagArpAnnounce[] = "arp_announce";
93// static
94const char Device::kIPFlagArpAnnounceDefault[] = "0";
95// static
96const char Device::kIPFlagArpAnnounceBestLocal[] = "2";
97// static
98const char Device::kIPFlagArpIgnore[] = "arp_ignore";
99// static
100const char Device::kIPFlagArpIgnoreDefault[] = "0";
101// static
102const char Device::kIPFlagArpIgnoreLocalOnly[] = "1";
103// static
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700104const char Device::kStoragePowered[] = "Powered";
105// static
Paul Stewart6ff27f52012-07-11 06:51:41 -0700106const char Device::kStorageReceiveByteCount[] = "ReceiveByteCount";
107// static
108const char Device::kStorageTransmitByteCount[] = "TransmitByteCount";
Peter Qiub9256f32014-05-09 15:27:29 -0700109// static
110const char Device::kFallbackDnsTestHostname[] = "www.gstatic.com";
111// static
112const char* Device::kFallbackDnsServers[] = {
113 "8.8.8.8",
Peter Qiua89154b2014-05-23 15:45:42 -0700114 "8.8.4.4"
Peter Qiub9256f32014-05-09 15:27:29 -0700115};
116
117// static
118const int Device::kDNSTimeoutMilliseconds = 5000;
Peter Qiua388fdb2015-04-03 10:31:22 -0700119const int Device::kLinkUnreliableThresholdSeconds = 60 * 60;
Peter Qiu62abf312015-05-05 12:58:05 -0700120const size_t Device::kHardwareAddressLength = 6U;
Chris Masone5dec5f42011-07-22 14:07:55 -0700121
Paul Stewarta794cd62015-06-16 13:13:10 -0700122Device::Device(ControlInterface* control_interface,
123 EventDispatcher* dispatcher,
124 Metrics* metrics,
125 Manager* manager,
126 const string& link_name,
127 const string& address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800128 int interface_index,
129 Technology::Identifier technology)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500130 : enabled_(false),
131 enabled_persistent_(true),
132 enabled_pending_(enabled_),
Chris Masoneb925cc82011-06-22 15:39:57 -0700133 reconnect_(true),
Chris Masone626719f2011-08-18 16:58:48 -0700134 hardware_address_(address),
mukesh agrawalf60e4062011-05-27 13:13:41 -0700135 interface_index_(interface_index),
136 running_(false),
Darin Petkovafa6fc42011-06-21 16:21:08 -0700137 link_name_(link_name),
Chris Masone19e30402011-07-19 15:48:47 -0700138 unique_id_(link_name),
Darin Petkovd9661952011-08-03 16:25:42 -0700139 control_interface_(control_interface),
140 dispatcher_(dispatcher),
Thieu Le3426c8f2012-01-11 17:35:11 -0800141 metrics_(metrics),
Chris Masone7df0c672011-07-15 10:24:54 -0700142 manager_(manager),
Eric Shienbrood9a245532012-03-07 14:20:39 -0500143 weak_ptr_factory_(this),
Darin Petkov77cb6812011-08-15 16:19:41 -0700144 adaptor_(control_interface->CreateDeviceAdaptor(this)),
Eric Shienbrood9a245532012-03-07 14:20:39 -0500145 portal_detector_callback_(Bind(&Device::PortalDetectorCallback,
146 weak_ptr_factory_.GetWeakPtr())),
Gaurav Shah435de2c2011-11-17 19:01:07 -0800147 technology_(technology),
Thieu Le85e050b2012-03-13 15:04:38 -0700148 portal_attempts_to_online_(0),
Paul Stewart6ff27f52012-07-11 06:51:41 -0700149 receive_byte_offset_(0),
150 transmit_byte_offset_(0),
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700151 dhcp_provider_(DHCPProvider::GetInstance()),
Peter Qiua0572032014-09-26 10:07:37 -0700152 rtnl_handler_(RTNLHandler::GetInstance()),
153 time_(Time::GetInstance()),
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -0700154 last_link_monitor_failed_time_(0),
155 connection_tester_callback_(Bind(&Device::ConnectionTesterCallback,
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800156 weak_ptr_factory_.GetWeakPtr())),
157 is_loose_routing_(false),
158 is_multi_homed_(false) {
Ben Chan923a5022013-09-20 11:23:23 -0700159 store_.RegisterConstString(kAddressProperty, &hardware_address_);
Chris Masone4d42df82011-07-02 17:09:39 -0700160
Ben Chan923a5022013-09-20 11:23:23 -0700161 // kBgscanMethodProperty: Registered in WiFi
162 // kBgscanShortIntervalProperty: Registered in WiFi
163 // kBgscanSignalThresholdProperty: Registered in WiFi
Chris Masone4d42df82011-07-02 17:09:39 -0700164
Ben Chan923a5022013-09-20 11:23:23 -0700165 // kCellularAllowRoamingProperty: Registered in Cellular
166 // kCarrierProperty: Registered in Cellular
167 // kEsnProperty: Registered in Cellular
168 // kHomeProviderProperty: Registered in Cellular
169 // kImeiProperty: Registered in Cellular
170 // kIccidProperty: Registered in Cellular
171 // kImsiProperty: Registered in Cellular
172 // kManufacturerProperty: Registered in Cellular
173 // kMdnProperty: Registered in Cellular
174 // kMeidProperty: Registered in Cellular
175 // kMinProperty: Registered in Cellular
176 // kModelIDProperty: Registered in Cellular
177 // kFirmwareRevisionProperty: Registered in Cellular
178 // kHardwareRevisionProperty: Registered in Cellular
179 // kPRLVersionProperty: Registered in Cellular
180 // kSIMLockStatusProperty: Registered in Cellular
181 // kFoundNetworksProperty: Registered in Cellular
Ben Chan923a5022013-09-20 11:23:23 -0700182 // kDBusObjectProperty: Register in Cellular
Chris Masone4d42df82011-07-02 17:09:39 -0700183
Ben Chan923a5022013-09-20 11:23:23 -0700184 store_.RegisterConstString(kInterfaceProperty, &link_name_);
Christopher Wiley674598d2014-12-12 10:21:39 -0800185 HelpRegisterConstDerivedRpcIdentifier(
186 kSelectedServiceProperty, &Device::GetSelectedServiceRpcIdentifier);
Ben Chan923a5022013-09-20 11:23:23 -0700187 HelpRegisterConstDerivedRpcIdentifiers(kIPConfigsProperty,
Jason Glasgow08afdff2012-04-03 10:22:26 -0400188 &Device::AvailableIPConfigs);
Ben Chan923a5022013-09-20 11:23:23 -0700189 store_.RegisterConstString(kNameProperty, &link_name_);
190 store_.RegisterConstBool(kPoweredProperty, &enabled_);
191 HelpRegisterConstDerivedString(kTypeProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700192 &Device::GetTechnologyString);
Ben Chan39a7beb2013-09-21 11:28:00 -0700193 HelpRegisterConstDerivedUint64(kLinkMonitorResponseTimeProperty,
Paul Stewart036dba02012-08-07 12:34:41 -0700194 &Device::GetLinkMonitorResponseTime);
Jason Glasgowb5790052012-01-27 01:03:52 -0500195
Chris Masoneb925cc82011-06-22 15:39:57 -0700196 // TODO(cmasone): Chrome doesn't use this...does anyone?
Ben Chan923a5022013-09-20 11:23:23 -0700197 // store_.RegisterConstBool(kReconnectProperty, &reconnect_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700198
Chris Masone4e851612011-07-01 10:46:53 -0700199 // TODO(cmasone): Figure out what shill concept maps to flimflam's "Network".
Ben Chan923a5022013-09-20 11:23:23 -0700200 // known_properties_.push_back(kNetworksProperty);
Chris Masoneb925cc82011-06-22 15:39:57 -0700201
Wade Guthrie227c7742013-10-10 11:06:33 -0700202 // kRoamThresholdProperty: Registered in WiFi
Ben Chan923a5022013-09-20 11:23:23 -0700203 // kScanningProperty: Registered in WiFi, Cellular
204 // kScanIntervalProperty: Registered in WiFi, Cellular
Samuel Tan96e35cf2014-10-28 22:27:38 -0700205 // kWakeOnWiFiFeaturesEnabledProperty: Registered in WiFi
Paul Stewart6ff27f52012-07-11 06:51:41 -0700206
207 if (manager_ && manager_->device_info()) { // Unit tests may not have these.
208 manager_->device_info()->GetByteCounts(
209 interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700210 HelpRegisterConstDerivedUint64(kReceiveByteCountProperty,
Ben Chanb061f892013-02-27 17:46:55 -0800211 &Device::GetReceiveByteCountProperty);
Ben Chan39a7beb2013-09-21 11:28:00 -0700212 HelpRegisterConstDerivedUint64(kTransmitByteCountProperty,
Ben Chanb061f892013-02-27 17:46:55 -0800213 &Device::GetTransmitByteCountProperty);
Paul Stewart6ff27f52012-07-11 06:51:41 -0700214 }
215
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800216 DisableArpFiltering();
217 EnableReversePathFilter();
218
Darin Petkova0a0efe2012-06-27 12:50:01 +0200219 LOG(INFO) << "Device created: " << link_name_
220 << " index " << interface_index_;
Paul Stewart75897df2011-04-27 09:05:53 -0700221}
222
223Device::~Device() {
Darin Petkova0a0efe2012-06-27 12:50:01 +0200224 LOG(INFO) << "Device destructed: " << link_name_
225 << " index " << interface_index_;
Paul Stewart75897df2011-04-27 09:05:53 -0700226}
227
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700228void Device::LinkEvent(unsigned flags, unsigned change) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700229 SLOG(this, 2) << "Device " << link_name_
230 << std::showbase << std::hex
231 << " flags " << flags << " changed " << change
232 << std::dec << std::noshowbase;
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700233}
234
Paul Stewarta794cd62015-06-16 13:13:10 -0700235void Device::Scan(ScanType scan_type, Error* error, const string& reason) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700236 SLOG(this, 2) << __func__ << " [Device] on " << link_name() << " from "
237 << reason;
Paul Stewart34f424e2015-01-16 15:30:20 -0800238 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Paul Stewartbe005172011-11-02 18:10:29 -0700239 "Device doesn't support scan.");
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700240}
241
Paul Stewarta794cd62015-06-16 13:13:10 -0700242void Device::SetSchedScan(bool enable, Error* error) {
Peter Qiud51b2442015-02-23 10:41:38 -0800243 SLOG(this, 2) << __func__ << " [Device] on " << link_name();
244 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
245 "Device doesn't support scheduled scan.");
246}
247
Paul Stewarta794cd62015-06-16 13:13:10 -0700248void Device::RegisterOnNetwork(const std::string& /*network_id*/, Error* error,
249 const ResultCallback& /*callback*/) {
Paul Stewart34f424e2015-01-16 15:30:20 -0800250 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Paul Stewartbe005172011-11-02 18:10:29 -0700251 "Device doesn't support network registration.");
Darin Petkov9ae310f2011-08-30 15:41:13 -0700252}
253
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100254void Device::RequirePIN(
Paul Stewarta794cd62015-06-16 13:13:10 -0700255 const string& /*pin*/, bool /*require*/,
256 Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700257 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800258 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500259 "Device doesn't support RequirePIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700260}
261
Paul Stewarta794cd62015-06-16 13:13:10 -0700262void Device::EnterPIN(const string& /*pin*/,
263 Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700264 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800265 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500266 "Device doesn't support EnterPIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700267}
268
Paul Stewarta794cd62015-06-16 13:13:10 -0700269void Device::UnblockPIN(const string& /*unblock_code*/,
270 const string& /*pin*/,
271 Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700272 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800273 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500274 "Device doesn't support UnblockPIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700275}
276
Paul Stewarta794cd62015-06-16 13:13:10 -0700277void Device::ChangePIN(const string& /*old_pin*/,
278 const string& /*new_pin*/,
279 Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700280 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800281 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500282 "Device doesn't support ChangePIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700283}
284
Paul Stewarta794cd62015-06-16 13:13:10 -0700285void Device::Reset(Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700286 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800287 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Ben Chanad663e12013-01-08 01:58:47 -0800288 "Device doesn't support Reset.");
289}
290
Paul Stewarta794cd62015-06-16 13:13:10 -0700291void Device::SetCarrier(const string& /*carrier*/,
292 Error* error, const ResultCallback& /*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700293 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800294 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Darin Petkovc37a9c42012-09-06 15:28:22 +0200295 "Device doesn't support SetCarrier.");
296}
297
Ben Chanbcc6e012013-11-04 14:28:37 -0800298bool Device::IsIPv6Allowed() const {
299 return true;
300}
301
Paul Stewart2bf1d352011-12-06 15:02:55 -0800302void Device::DisableIPv6() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700303 SLOG(this, 2) << __func__;
Paul Stewart2bf1d352011-12-06 15:02:55 -0800304 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "1");
305}
306
307void Device::EnableIPv6() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700308 SLOG(this, 2) << __func__;
Ben Chanbcc6e012013-11-04 14:28:37 -0800309 if (!IsIPv6Allowed()) {
310 LOG(INFO) << "Skip enabling IPv6 on " << link_name_
311 << " as it is not allowed.";
312 return;
313 }
Paul Stewart2bf1d352011-12-06 15:02:55 -0800314 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "0");
315}
316
317void Device::EnableIPv6Privacy() {
318 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagUseTempAddr,
319 kIPFlagUseTempAddrUsedAndDefault);
320}
321
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800322void Device::SetLooseRouting(bool is_loose_routing) {
323 if (is_loose_routing == is_loose_routing_) {
324 return;
325 }
326 is_loose_routing_ = is_loose_routing;
327 if (is_multi_homed_) {
328 // Nothing to do: loose routing is already enabled, and should remain so.
329 return;
330 }
331 if (is_loose_routing) {
332 DisableReversePathFilter();
333 } else {
334 EnableReversePathFilter();
335 }
336}
337
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800338void Device::DisableReversePathFilter() {
339 // TODO(pstew): Current kernel doesn't offer reverse-path filtering flag
Paul Stewartee6b3d72013-07-12 16:07:51 -0700340 // for IPv6. crbug.com/207193
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800341 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
342 kIPFlagReversePathFilterLooseMode);
343}
344
345void Device::EnableReversePathFilter() {
346 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
347 kIPFlagReversePathFilterEnabled);
348}
349
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800350void Device::SetIsMultiHomed(bool is_multi_homed) {
351 if (is_multi_homed == is_multi_homed_) {
352 return;
353 }
354 LOG(INFO) << "Device " << FriendlyName() << " multi-home state is now "
355 << is_multi_homed;
356 is_multi_homed_ = is_multi_homed;
357 if (is_multi_homed) {
358 EnableArpFiltering();
359 if (!is_loose_routing_) {
360 DisableReversePathFilter();
361 }
362 } else {
363 DisableArpFiltering();
364 if (!is_loose_routing_) {
365 EnableReversePathFilter();
366 }
367 }
368}
369
370void Device::DisableArpFiltering() {
371 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
372 kIPFlagArpAnnounceDefault);
373 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore, kIPFlagArpIgnoreDefault);
374}
375
376void Device::EnableArpFiltering() {
377 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
378 kIPFlagArpAnnounceBestLocal);
379 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore,
380 kIPFlagArpIgnoreLocalOnly);
381}
382
Gaurav Shah435de2c2011-11-17 19:01:07 -0800383bool Device::IsConnected() const {
384 if (selected_service_)
385 return selected_service_->IsConnected();
386 return false;
387}
388
Paul Stewarta794cd62015-06-16 13:13:10 -0700389bool Device::IsConnectedToService(const ServiceRefPtr& service) const {
Paul Stewartd215af62012-04-24 23:25:50 -0700390 return service == selected_service_ && IsConnected();
391}
392
Paul Stewartfa11e282013-12-02 22:04:25 -0800393bool Device::IsConnectedViaTether() const {
394 return
395 ipconfig_.get() &&
396 ipconfig_->properties().vendor_encapsulated_options ==
397 Tethering::kAndroidVendorEncapsulatedOptions;
398}
399
mukesh agrawalf6b32092013-04-10 15:49:55 -0700400string Device::GetRpcIdentifier() const {
Chris Masone27c4aa52011-07-02 13:10:14 -0700401 return adaptor_->GetRpcIdentifier();
Chris Masone8fe2c7e2011-06-09 15:51:19 -0700402}
403
mukesh agrawal515873d2014-07-21 17:01:35 -0700404string Device::GetStorageIdentifier() const {
Chris Masone5dec5f42011-07-22 14:07:55 -0700405 string id = GetRpcIdentifier();
406 ControlInterface::RpcIdToStorageId(&id);
Chris Masone626719f2011-08-18 16:58:48 -0700407 size_t needle = id.find('_');
Chris Masone34af2182011-08-22 11:59:36 -0700408 DLOG_IF(ERROR, needle == string::npos) << "No _ in storage id?!?!";
Chris Masone626719f2011-08-18 16:58:48 -0700409 id.replace(id.begin() + needle + 1, id.end(), hardware_address_);
Chris Masone5dec5f42011-07-22 14:07:55 -0700410 return id;
411}
412
Gaurav Shah6d2c72d2012-10-16 16:30:44 -0700413vector<GeolocationInfo> Device::GetGeolocationObjects() const {
414 return vector<GeolocationInfo>();
Wade Guthrie227c7742013-10-10 11:06:33 -0700415}
Gaurav Shah6d2c72d2012-10-16 16:30:44 -0700416
Paul Stewarta794cd62015-06-16 13:13:10 -0700417string Device::GetTechnologyString(Error* /*error*/) {
Jason Glasgowb5790052012-01-27 01:03:52 -0500418 return Technology::NameFromIdentifier(technology());
419}
420
Chris Masone19e30402011-07-19 15:48:47 -0700421const string& Device::FriendlyName() const {
Chris Masone7df0c672011-07-15 10:24:54 -0700422 return link_name_;
Darin Petkovafa6fc42011-06-21 16:21:08 -0700423}
424
Chris Masone19e30402011-07-19 15:48:47 -0700425const string& Device::UniqueName() const {
426 return unique_id_;
427}
428
Paul Stewarta794cd62015-06-16 13:13:10 -0700429bool Device::Load(StoreInterface* storage) {
Chris Masone5dec5f42011-07-22 14:07:55 -0700430 const string id = GetStorageIdentifier();
431 if (!storage->ContainsGroup(id)) {
Paul Stewart34b3f122015-06-12 10:30:24 -0700432 SLOG(this, 2) << "Device is not available in the persistent store: " << id;
Chris Masone5dec5f42011-07-22 14:07:55 -0700433 return false;
434 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500435 enabled_persistent_ = true;
436 storage->GetBool(id, kStoragePowered, &enabled_persistent_);
Ben Chan7fab8972014-08-10 17:14:46 -0700437 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -0700438
439 manager_->device_info()->GetByteCounts(
440 interface_index_, &rx_byte_count, &tx_byte_count);
441 // If there is a byte-count present in the profile, the return value
442 // of Device::Get*ByteCount() should be the this stored value plus
443 // whatever additional bytes we receive since time-of-load. We
444 // accomplish this by the subtractions below, which can validly
445 // roll over "negative" in the subtractions below and in Get*ByteCount.
Ben Chan7fab8972014-08-10 17:14:46 -0700446 uint64_t profile_byte_count;
Paul Stewart6ff27f52012-07-11 06:51:41 -0700447 if (storage->GetUint64(id, kStorageReceiveByteCount, &profile_byte_count)) {
448 receive_byte_offset_ = rx_byte_count - profile_byte_count;
449 }
450 if (storage->GetUint64(id, kStorageTransmitByteCount, &profile_byte_count)) {
451 transmit_byte_offset_ = tx_byte_count - profile_byte_count;
452 }
453
Chris Masone5dec5f42011-07-22 14:07:55 -0700454 return true;
455}
456
Paul Stewarta794cd62015-06-16 13:13:10 -0700457bool Device::Save(StoreInterface* storage) {
Chris Masone5dec5f42011-07-22 14:07:55 -0700458 const string id = GetStorageIdentifier();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500459 storage->SetBool(id, kStoragePowered, enabled_persistent_);
Ben Chanb061f892013-02-27 17:46:55 -0800460 storage->SetUint64(id, kStorageReceiveByteCount, GetReceiveByteCount());
461 storage->SetUint64(id, kStorageTransmitByteCount, GetTransmitByteCount());
Chris Masone5dec5f42011-07-22 14:07:55 -0700462 return true;
463}
464
Paul Stewarta794cd62015-06-16 13:13:10 -0700465void Device::OnBeforeSuspend(const ResultCallback& callback) {
Samuel Tanfbe8d2b2014-09-15 20:23:59 -0700466 // Nothing to be done in the general case, so immediately report success.
467 callback.Run(Error(Error::kSuccess));
mukesh agrawal784566d2012-08-08 18:32:58 -0700468}
469
470void Device::OnAfterResume() {
Samuel Tan787a1ce2014-11-11 17:17:27 -0800471 RenewDHCPLease();
mukesh agrawalbb2231c2013-07-17 16:32:24 -0700472 if (link_monitor_) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700473 SLOG(this, 3) << "Informing Link Monitor of resume.";
mukesh agrawalbb2231c2013-07-17 16:32:24 -0700474 link_monitor_->OnAfterResume();
475 }
Peter Qiua0572032014-09-26 10:07:37 -0700476 // Resume from sleep, could be in different location now.
477 // Ignore previous link monitor failures.
Peter Qiua388fdb2015-04-03 10:31:22 -0700478 if (selected_service_) {
479 selected_service_->set_unreliable(false);
480 reliable_link_callback_.Cancel();
481 }
Peter Qiua0572032014-09-26 10:07:37 -0700482 last_link_monitor_failed_time_ = 0;
mukesh agrawal784566d2012-08-08 18:32:58 -0700483}
484
Paul Stewarta794cd62015-06-16 13:13:10 -0700485void Device::OnDarkResume(const ResultCallback& callback) {
Samuel Tan68b73d22014-10-28 17:00:56 -0700486 // Nothing to be done in the general case, so immediately report success.
487 callback.Run(Error(Error::kSuccess));
Prathmesh Prabhu64ad2382014-08-26 11:19:30 -0700488}
489
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200490void Device::DropConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700491 SLOG(this, 2) << __func__;
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200492 DestroyIPConfig();
Ben Chancc225ef2014-09-30 13:26:51 -0700493 SelectService(nullptr);
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200494}
495
Darin Petkovafa6fc42011-06-21 16:21:08 -0700496void Device::DestroyIPConfig() {
Paul Stewart2bf1d352011-12-06 15:02:55 -0800497 DisableIPv6();
Peter Qiud48fa0c2015-06-10 12:20:48 -0700498 bool ipconfig_changed = false;
Darin Petkovafa6fc42011-06-21 16:21:08 -0700499 if (ipconfig_.get()) {
Paul Stewart217c61d2013-06-13 15:12:02 -0700500 ipconfig_->ReleaseIP(IPConfig::kReleaseReasonDisconnect);
Ben Chancc225ef2014-09-30 13:26:51 -0700501 ipconfig_ = nullptr;
Peter Qiud48fa0c2015-06-10 12:20:48 -0700502 ipconfig_changed = true;
Darin Petkovafa6fc42011-06-21 16:21:08 -0700503 }
Peter Qiu25f1be62014-08-12 10:42:27 -0700504 if (ip6config_.get()) {
505 StopIPv6DNSServerTimer();
Ben Chancc225ef2014-09-30 13:26:51 -0700506 ip6config_ = nullptr;
Peter Qiud48fa0c2015-06-10 12:20:48 -0700507 ipconfig_changed = true;
508 }
509 if (dhcpv6_config_.get()) {
510 dhcpv6_config_->ReleaseIP(IPConfig::kReleaseReasonDisconnect);
511 dhcpv6_config_ = nullptr;
512 ipconfig_changed = true;
513 }
514 // Emit updated IP configs if there are any changes.
515 if (ipconfig_changed) {
Peter Qiu25f1be62014-08-12 10:42:27 -0700516 UpdateIPConfigsProperty();
517 }
Paul Stewarte6132022011-08-16 09:11:02 -0700518 DestroyConnection();
Darin Petkovafa6fc42011-06-21 16:21:08 -0700519}
520
Paul Stewartd4f26482014-04-25 19:12:03 -0700521void Device::OnIPv6AddressChanged() {
522 IPAddress address(IPAddress::kFamilyIPv6);
523 if (!manager_->device_info()->GetPrimaryIPv6Address(
524 interface_index_, &address)) {
525 if (ip6config_) {
Ben Chancc225ef2014-09-30 13:26:51 -0700526 ip6config_ = nullptr;
Paul Stewartd4f26482014-04-25 19:12:03 -0700527 UpdateIPConfigsProperty();
528 }
529 return;
530 }
531
532 IPConfig::Properties properties;
533 if (!address.IntoString(&properties.address)) {
534 LOG(ERROR) << "Unable to convert IPv6 address into a string!";
535 return;
536 }
537 properties.subnet_prefix = address.prefix();
538
539 if (!ip6config_) {
540 ip6config_ = new IPConfig(control_interface_, link_name_);
541 } else if (properties.address == ip6config_->properties().address &&
542 properties.subnet_prefix ==
543 ip6config_->properties().subnet_prefix) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700544 SLOG(this, 2) << __func__ << " primary address for "
545 << link_name_ << " is unchanged.";
Paul Stewartd4f26482014-04-25 19:12:03 -0700546 return;
547 }
548
549 properties.address_family = IPAddress::kFamilyIPv6;
550 properties.method = kTypeIPv6;
Peter Qiu25f1be62014-08-12 10:42:27 -0700551 // It is possible for device to receive DNS server notification before IP
552 // address notification, so preserve the saved DNS server if it exist.
553 properties.dns_servers = ip6config_->properties().dns_servers;
Garret Kellyc5f89d12015-02-18 14:39:36 -0500554 PrependDNSServers(IPAddress::kFamilyIPv6, &properties.dns_servers);
Paul Stewartd4f26482014-04-25 19:12:03 -0700555 ip6config_->set_properties(properties);
556 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700557 OnIPv6ConfigUpdated();
Paul Stewartd4f26482014-04-25 19:12:03 -0700558}
559
Peter Qiu98551702014-07-28 13:28:53 -0700560void Device::OnIPv6DnsServerAddressesChanged() {
Peter Qiu25f1be62014-08-12 10:42:27 -0700561 vector<IPAddress> server_addresses;
Paul Stewart60a922e2015-06-16 11:28:29 -0700562 uint32 lifetime = 0;
Peter Qiu25f1be62014-08-12 10:42:27 -0700563
564 // Stop any existing timer.
565 StopIPv6DNSServerTimer();
566
567 if (!manager_->device_info()->GetIPv6DnsServerAddresses(
568 interface_index_, &server_addresses, &lifetime) || lifetime == 0) {
569 IPv6DNSServerExpired();
570 return;
571 }
572
573 vector<string> addresses_str;
Paul Stewarta794cd62015-06-16 13:13:10 -0700574 for (const auto& ip : server_addresses) {
Peter Qiu25f1be62014-08-12 10:42:27 -0700575 string address_str;
576 if (!ip.IntoString(&address_str)) {
577 LOG(ERROR) << "Unable to convert IPv6 address into a string!";
578 IPv6DNSServerExpired();
579 return;
580 }
581 addresses_str.push_back(address_str);
582 }
583
Peter Qiu25f1be62014-08-12 10:42:27 -0700584 if (!ip6config_) {
585 ip6config_ = new IPConfig(control_interface_, link_name_);
586 }
587
Samuel Tan815a6fb2014-10-23 16:53:59 -0700588 if (lifetime != ND_OPT_LIFETIME_INFINITY) {
589 // Setup timer to monitor DNS server lifetime if not infinite lifetime.
590 StartIPv6DNSServerTimer(lifetime);
591 ip6config_->UpdateLeaseExpirationTime(lifetime);
592 } else {
593 ip6config_->ResetLeaseExpirationTime();
594 }
595
Garret Kellyc5f89d12015-02-18 14:39:36 -0500596 PrependDNSServers(IPAddress::kFamilyIPv6, &addresses_str);
597
Peter Qiu25f1be62014-08-12 10:42:27 -0700598 // Done if no change in server addresses.
599 if (ip6config_->properties().dns_servers == addresses_str) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700600 SLOG(this, 2) << __func__ << " IPv6 DNS server list for "
601 << link_name_ << " is unchanged.";
Peter Qiu25f1be62014-08-12 10:42:27 -0700602 return;
603 }
604
605 ip6config_->UpdateDNSServers(addresses_str);
606 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700607 OnIPv6ConfigUpdated();
Peter Qiu25f1be62014-08-12 10:42:27 -0700608}
609
610void Device::StartIPv6DNSServerTimer(uint32 lifetime_seconds) {
611 int64 delay = static_cast<int64>(lifetime_seconds) * 1000;
612 ipv6_dns_server_expired_callback_.Reset(
613 base::Bind(&Device::IPv6DNSServerExpired, base::Unretained(this)));
614 dispatcher_->PostDelayedTask(ipv6_dns_server_expired_callback_.callback(),
615 delay);
616}
617
618void Device::StopIPv6DNSServerTimer() {
619 ipv6_dns_server_expired_callback_.Cancel();
620}
621
622void Device::IPv6DNSServerExpired() {
623 if (!ip6config_) {
624 return;
625 }
626 ip6config_->UpdateDNSServers(vector<string>());
627 UpdateIPConfigsProperty();
628}
629
630void Device::StopAllActivities() {
631 StopTrafficMonitor();
632 StopPortalDetection();
Paul Stewarte8303eb2014-10-08 22:51:14 -0700633 StopConnectivityTest();
Peter Qiu25f1be62014-08-12 10:42:27 -0700634 StopLinkMonitor();
635 StopDNSTest();
636 StopIPv6DNSServerTimer();
Peter Qiu98551702014-07-28 13:28:53 -0700637}
638
Paul Stewarta794cd62015-06-16 13:13:10 -0700639void Device::AddWakeOnPacketConnection(const string& ip_endpoint,
640 Error* error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700641 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800642 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700643 "AddWakeOnPacketConnection not implemented for " + link_name_ + ".");
644 return;
645}
646
Paul Stewarta794cd62015-06-16 13:13:10 -0700647void Device::RemoveWakeOnPacketConnection(const string& ip_endpoint,
648 Error* error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700649 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800650 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700651 "RemoveWakeOnPacketConnection not implemented for " + link_name_ + ".");
652 return;
653}
654
Paul Stewarta794cd62015-06-16 13:13:10 -0700655void Device::RemoveAllWakeOnPacketConnections(Error* error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700656 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800657 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700658 "RemoveAllWakeOnPacketConnections not implemented for " + link_name_ +
659 ".");
660 return;
661}
662
Samuel Tan787a1ce2014-11-11 17:17:27 -0800663void Device::RenewDHCPLease() {
664 LOG(INFO) << __func__;
665
666 if (ipconfig_) {
667 SLOG(this, 3) << "Renewing IPv4 Address";
668 ipconfig_->RenewIP();
669 }
670 if (ip6config_) {
671 SLOG(this, 3) << "Waiting for new IPv6 configuration";
672 // Invalidate the old IPv6 configuration, will receive notifications
673 // from kernel for new IPv6 configuration if there is one.
674 StopIPv6DNSServerTimer();
675 ip6config_ = nullptr;
676 UpdateIPConfigsProperty();
677 }
Peter Qiud48fa0c2015-06-10 12:20:48 -0700678 if (dhcpv6_config_) {
679 SLOG(this, 3) << "Renewing DHCPv6 lease";
680 dhcpv6_config_->RenewIP();
681 }
Samuel Tan787a1ce2014-11-11 17:17:27 -0800682}
683
Arman Ugurayed8e6102012-11-29 14:47:20 -0800684bool Device::ShouldUseArpGateway() const {
685 return false;
686}
687
Paul Stewart316acef2014-05-29 18:40:48 -0700688bool Device::IsUsingStaticIP() const {
689 if (!selected_service_) {
690 return false;
691 }
692 return selected_service_->HasStaticIPAddress();
693}
694
Garret Kellyd01b5cc2015-03-12 16:20:55 -0400695bool Device::IsUsingStaticNameServers() const {
696 if (!selected_service_) {
697 return false;
698 }
699 return selected_service_->HasStaticNameServers();
700}
701
Paul Stewart2bf1d352011-12-06 15:02:55 -0800702bool Device::AcquireIPConfig() {
Paul Stewartd408fdf2012-05-07 17:15:57 -0700703 return AcquireIPConfigWithLeaseName(string());
704}
705
Paul Stewarta794cd62015-06-16 13:13:10 -0700706bool Device::AcquireIPConfigWithLeaseName(const string& lease_name) {
Darin Petkovafa6fc42011-06-21 16:21:08 -0700707 DestroyIPConfig();
Paul Stewart2bf1d352011-12-06 15:02:55 -0800708 EnableIPv6();
Arman Ugurayed8e6102012-11-29 14:47:20 -0800709 bool arp_gateway = manager_->GetArpGateway() && ShouldUseArpGateway();
Peter Qiu8e0151e2015-06-04 09:41:47 -0700710 auto dhcp_config = dhcp_provider_->CreateIPv4Config(
711 link_name_, manager_->GetHostName(), lease_name, arp_gateway);
Garret Kelly782cdce2015-04-01 16:39:16 -0400712 const int minimum_mtu = manager()->GetMinimumMTU();
713 if (minimum_mtu != IPConfig::kUndefinedMTU) {
714 dhcp_config->set_minimum_mtu(minimum_mtu);
715 }
716
717 ipconfig_ = dhcp_config;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500718 ipconfig_->RegisterUpdateCallback(Bind(&Device::OnIPConfigUpdated,
719 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc5099532013-12-12 07:53:15 -0800720 ipconfig_->RegisterFailureCallback(Bind(&Device::OnIPConfigFailed,
721 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart82236532013-12-10 15:33:11 -0800722 ipconfig_->RegisterRefreshCallback(Bind(&Device::OnIPConfigRefreshed,
723 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart1f916e42013-12-23 09:52:54 -0800724 ipconfig_->RegisterExpireCallback(Bind(&Device::OnIPConfigExpired,
725 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart1062d9d2012-04-27 10:42:27 -0700726 dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
727 weak_ptr_factory_.GetWeakPtr()));
Peter Qiud48fa0c2015-06-10 12:20:48 -0700728 if (!ipconfig_->RequestIP()) {
729 return false;
730 }
731
732#ifndef DISABLE_DHCPV6
733 // Request DHCPv6 configurations. DHCPv6 configurations will not be use to
734 // setup connection for the device.
735 if (manager_->IsDHCPv6EnabledForDevice(link_name_)) {
736 auto dhcpv6_config =
737 dhcp_provider_->CreateIPv6Config(link_name_, lease_name);
738 dhcpv6_config_ = dhcpv6_config;
739 dhcpv6_config_->RegisterUpdateCallback(
740 Bind(&Device::OnDHCPv6ConfigUpdated, weak_ptr_factory_.GetWeakPtr()));
741 dhcpv6_config_->RegisterFailureCallback(
742 Bind(&Device::OnDHCPv6ConfigFailed, weak_ptr_factory_.GetWeakPtr()));
743 dhcpv6_config_->RegisterExpireCallback(
744 Bind(&Device::OnDHCPv6ConfigExpired, weak_ptr_factory_.GetWeakPtr()));
745 if (!dhcpv6_config_->RequestIP()) {
746 return false;
747 }
748 }
749#endif // DISABLE_DHCPV6
750
751 return true;
Darin Petkovafa6fc42011-06-21 16:21:08 -0700752}
753
Paul Stewarta794cd62015-06-16 13:13:10 -0700754void Device::AssignIPConfig(const IPConfig::Properties& properties) {
Ben Chan539ab022014-02-03 16:34:57 -0800755 DestroyIPConfig();
756 EnableIPv6();
757 ipconfig_ = new IPConfig(control_interface_, link_name_);
758 ipconfig_->set_properties(properties);
759 dispatcher_->PostTask(Bind(&Device::OnIPConfigUpdated,
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800760 weak_ptr_factory_.GetWeakPtr(), ipconfig_, true));
Ben Chan539ab022014-02-03 16:34:57 -0800761}
762
Paul Stewarta794cd62015-06-16 13:13:10 -0700763void Device::DestroyIPConfigLease(const string& name) {
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800764 dhcp_provider_->DestroyLease(name);
765}
766
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700767void Device::HelpRegisterConstDerivedString(
Paul Stewarta794cd62015-06-16 13:13:10 -0700768 const string& name,
769 string(Device::*get)(Error* error)) {
Jason Glasgowb5790052012-01-27 01:03:52 -0500770 store_.RegisterDerivedString(
771 name,
Ben Chancc225ef2014-09-30 13:26:51 -0700772 StringAccessor(new CustomAccessor<Device, string>(this, get, nullptr)));
Chris Masone4e851612011-07-01 10:46:53 -0700773}
774
Christopher Wiley674598d2014-12-12 10:21:39 -0800775void Device::HelpRegisterConstDerivedRpcIdentifier(
Paul Stewarta794cd62015-06-16 13:13:10 -0700776 const string& name,
777 RpcIdentifier(Device::*get)(Error* error)) {
Christopher Wiley674598d2014-12-12 10:21:39 -0800778 store_.RegisterDerivedRpcIdentifier(
779 name,
780 RpcIdentifierAccessor(
781 new CustomAccessor<Device, RpcIdentifier>(this, get, nullptr)));
782}
783
Jason Glasgow08afdff2012-04-03 10:22:26 -0400784void Device::HelpRegisterConstDerivedRpcIdentifiers(
Paul Stewarta794cd62015-06-16 13:13:10 -0700785 const string& name,
786 RpcIdentifiers(Device::*get)(Error*)) {
Jason Glasgow08afdff2012-04-03 10:22:26 -0400787 store_.RegisterDerivedRpcIdentifiers(
788 name,
789 RpcIdentifiersAccessor(
Ben Chancc225ef2014-09-30 13:26:51 -0700790 new CustomAccessor<Device, RpcIdentifiers>(this, get, nullptr)));
Jason Glasgow08afdff2012-04-03 10:22:26 -0400791}
792
Paul Stewart6ff27f52012-07-11 06:51:41 -0700793void Device::HelpRegisterConstDerivedUint64(
Paul Stewarta794cd62015-06-16 13:13:10 -0700794 const string& name,
795 uint64_t(Device::*get)(Error*)) {
Paul Stewart6ff27f52012-07-11 06:51:41 -0700796 store_.RegisterDerivedUint64(
797 name,
798 Uint64Accessor(
Ben Chancc225ef2014-09-30 13:26:51 -0700799 new CustomAccessor<Device, uint64_t>(this, get, nullptr)));
Paul Stewart6ff27f52012-07-11 06:51:41 -0700800}
801
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -0700802void Device::ConnectionTesterCallback() {
803 LOG(INFO) << "Device " << FriendlyName() << ": Completed Connectivity Test";
804 return;
805}
806
Paul Stewart1062d9d2012-04-27 10:42:27 -0700807void Device::ConfigureStaticIPTask() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700808 SLOG(this, 2) << __func__ << " selected_service " << selected_service_.get()
809 << " ipconfig " << ipconfig_.get();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700810
811 if (!selected_service_ || !ipconfig_) {
812 return;
813 }
814
Paul Stewart316acef2014-05-29 18:40:48 -0700815 if (IsUsingStaticIP()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700816 SLOG(this, 2) << __func__ << " " << " configuring static IP parameters.";
Paul Stewart1062d9d2012-04-27 10:42:27 -0700817 // If the parameters contain an IP address, apply them now and bring
818 // the interface up. When DHCP information arrives, it will supplement
819 // the static information.
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800820 OnIPConfigUpdated(ipconfig_, true);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700821 } else {
Paul Stewart82236532013-12-10 15:33:11 -0800822 // Either |ipconfig_| has just been created in AcquireIPConfig() or
823 // we're being called by OnIPConfigRefreshed(). In either case a
824 // DHCP client has been started, and will take care of calling
825 // OnIPConfigUpdated() when it completes.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700826 SLOG(this, 2) << __func__ << " " << " no static IP address.";
Paul Stewart1062d9d2012-04-27 10:42:27 -0700827 }
828}
829
Paul Stewarta794cd62015-06-16 13:13:10 -0700830bool Device::IPConfigCompleted(const IPConfigRefPtr& ipconfig) {
Peter Qiub25083f2014-08-25 13:22:31 -0700831 return ipconfig && !ipconfig->properties().address.empty() &&
832 !ipconfig->properties().dns_servers.empty();
833}
834
835void Device::OnIPv6ConfigUpdated() {
836 // Setup connection using IPv6 configuration only if the IPv6 configuration
837 // is ready for connection (contained both IP address and DNS servers), and
838 // there is no existing IPv4 connection. We always prefer IPv4
839 // configuration over IPv6.
840 if (IPConfigCompleted(ip6config_) &&
841 (!connection_ || connection_->IsIPv6())) {
842 SetupConnection(ip6config_);
843 }
844}
845
Paul Stewarta794cd62015-06-16 13:13:10 -0700846void Device::SetupConnection(const IPConfigRefPtr& ipconfig) {
Peter Qiub25083f2014-08-25 13:22:31 -0700847 CreateConnection();
848 connection_->UpdateFromIPConfig(ipconfig);
849
Peter Qiu300769e2014-08-27 11:48:45 -0700850 // Report connection type.
851 Metrics::NetworkConnectionIPType ip_type =
852 connection_->IsIPv6() ? Metrics::kNetworkConnectionIPTypeIPv6
853 : Metrics::kNetworkConnectionIPTypeIPv4;
854 metrics_->NotifyNetworkConnectionIPType(technology_, ip_type);
855
856 // Report if device have IPv6 connectivity
857 bool ipv6_connectivity = IPConfigCompleted(ip6config_);
858 metrics_->NotifyIPv6ConnectivityStatus(technology_, ipv6_connectivity);
859
Peter Qiub25083f2014-08-25 13:22:31 -0700860 // SetConnection must occur after the UpdateFromIPConfig so the
861 // service can use the values derived from the connection.
862 if (selected_service_) {
863 selected_service_->SetConnection(connection_);
864
865 // The service state change needs to happen last, so that at the
866 // time we report the state change to the manager, the service
867 // has its connection.
868 SetServiceState(Service::kStateConnected);
869 OnConnected();
870 portal_attempts_to_online_ = 0;
871
872 // Subtle: Start portal detection after transitioning the service
873 // to the Connected state because this call may immediately transition
874 // to the Online state.
875 StartPortalDetection();
876 }
877
Paul Stewart208a97e2015-05-13 09:11:12 -0700878 SetHostname(ipconfig->properties().accepted_hostname);
Peter Qiub25083f2014-08-25 13:22:31 -0700879 StartLinkMonitor();
880 StartTrafficMonitor();
881}
882
Paul Stewarta794cd62015-06-16 13:13:10 -0700883bool Device::SetHostname(const std::string& hostname) {
Paul Stewart208a97e2015-05-13 09:11:12 -0700884 if (hostname.empty() || !manager()->ShouldAcceptHostnameFrom(link_name_)) {
885 return false;
886 }
887
888 string fixed_hostname = hostname;
889 if (fixed_hostname.length() > MAXHOSTNAMELEN) {
890 auto truncate_length = fixed_hostname.find('.');
891 if (truncate_length == string::npos || truncate_length > MAXHOSTNAMELEN) {
892 truncate_length = MAXHOSTNAMELEN;
893 }
894 fixed_hostname.resize(truncate_length);
895 }
896
897 return manager_->device_info()->SetHostname(fixed_hostname);
898}
899
Paul Stewarta794cd62015-06-16 13:13:10 -0700900void Device::PrependDNSServersIntoIPConfig(const IPConfigRefPtr& ipconfig) {
901 const auto& properties = ipconfig->properties();
Garret Kellyc5f89d12015-02-18 14:39:36 -0500902
903 vector<string> servers(properties.dns_servers.begin(),
904 properties.dns_servers.end());
905 PrependDNSServers(properties.address_family, &servers);
906 if (servers == properties.dns_servers) {
907 // If the server list is the same after being augmented then there's no need
908 // to update the config's list of servers.
909 return;
910 }
911
912 ipconfig->UpdateDNSServers(servers);
913}
914
915void Device::PrependDNSServers(const IPAddress::Family family,
Paul Stewarta794cd62015-06-16 13:13:10 -0700916 vector<string>* servers) {
Paul Stewart1ce231c2015-06-12 19:44:22 -0700917 vector<string>output_servers =
918 manager_->FilterPrependDNSServersByFamily(family);
Garret Kellyc5f89d12015-02-18 14:39:36 -0500919
Paul Stewart1ce231c2015-06-12 19:44:22 -0700920 set<string> unique(output_servers.begin(), output_servers.end());
Paul Stewarta794cd62015-06-16 13:13:10 -0700921 for (const auto& server : *servers) {
Garret Kellyc5f89d12015-02-18 14:39:36 -0500922 if (unique.find(server) == unique.end()) {
Paul Stewart1ce231c2015-06-12 19:44:22 -0700923 output_servers.push_back(server);
Garret Kellyc5f89d12015-02-18 14:39:36 -0500924 unique.insert(server);
925 }
926 }
Paul Stewart1ce231c2015-06-12 19:44:22 -0700927 servers->swap(output_servers);
Garret Kellyc5f89d12015-02-18 14:39:36 -0500928}
929
Paul Stewarta794cd62015-06-16 13:13:10 -0700930void Device::OnIPConfigUpdated(const IPConfigRefPtr& ipconfig,
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800931 bool /*new_lease_acquired*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700932 SLOG(this, 2) << __func__;
Paul Stewartc5099532013-12-12 07:53:15 -0800933 if (selected_service_) {
934 ipconfig->ApplyStaticIPParameters(
935 selected_service_->mutable_static_ip_parameters());
Paul Stewart316acef2014-05-29 18:40:48 -0700936 if (IsUsingStaticIP()) {
Paul Stewartc5099532013-12-12 07:53:15 -0800937 // If we are using a statically configured IP address instead
938 // of a leased IP address, release any acquired lease so it may
939 // be used by others. This allows us to merge other non-leased
940 // parameters (like DNS) when they're available from a DHCP server
941 // and not overridden by static parameters, but at the same time
942 // we avoid taking up a dynamic IP address the DHCP server could
943 // assign to someone else who might actually use it.
944 ipconfig->ReleaseIP(IPConfig::kReleaseReasonStaticIP);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700945 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700946 }
Garret Kellyd01b5cc2015-03-12 16:20:55 -0400947 if (!IsUsingStaticNameServers()) {
948 PrependDNSServersIntoIPConfig(ipconfig);
949 }
Peter Qiub25083f2014-08-25 13:22:31 -0700950 SetupConnection(ipconfig);
Paul Stewartd4f26482014-04-25 19:12:03 -0700951 UpdateIPConfigsProperty();
Paul Stewartc5099532013-12-12 07:53:15 -0800952}
953
Paul Stewarta794cd62015-06-16 13:13:10 -0700954void Device::OnIPConfigFailed(const IPConfigRefPtr& ipconfig) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700955 SLOG(this, 2) << __func__;
Paul Stewartc5099532013-12-12 07:53:15 -0800956 // TODO(pstew): This logic gets yet more complex when multiple
957 // IPConfig types are run in parallel (e.g. DHCP and DHCP6)
958 if (selected_service_) {
Paul Stewart316acef2014-05-29 18:40:48 -0700959 if (IsUsingStaticIP()) {
Paul Stewartc5099532013-12-12 07:53:15 -0800960 // Consider three cases:
961 //
962 // 1. We're here because DHCP failed while starting up. There
963 // are two subcases:
964 // a. DHCP has failed, and Static IP config has _not yet_
965 // completed. It's fine to do nothing, because we'll
966 // apply the static config shortly.
967 // b. DHCP has failed, and Static IP config has _already_
968 // completed. It's fine to do nothing, because we can
969 // continue to use the static config that's already
970 // been applied.
971 //
972 // 2. We're here because a previously valid DHCP configuration
973 // is no longer valid. There's still a static IP config,
974 // because the condition in the if clause evaluated to true.
975 // Furthermore, the static config includes an IP address for
976 // us to use.
977 //
978 // The current configuration may include some DHCP
979 // parameters, overriden by any static parameters
980 // provided. We continue to use this configuration, because
981 // the only configuration element that is leased to us (IP
982 // address) will be overriden by a static parameter.
983 return;
984 }
985 }
986
987 ipconfig->ResetProperties();
Paul Stewartd4f26482014-04-25 19:12:03 -0700988 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700989
990 // Fallback to IPv6 if we have an IPv6 configuration that's ready for
991 // connection, and we're not currently using an IPv6 connection.
992 if (IPConfigCompleted(ip6config_) &&
993 (!connection_ || !connection_->IsIPv6())) {
994 SetupConnection(ip6config_);
995 return;
996 }
997
998 OnIPConfigFailure();
Paul Stewartc5099532013-12-12 07:53:15 -0800999 DestroyConnection();
Chris Masone8fe2c7e2011-06-09 15:51:19 -07001000}
1001
Paul Stewarta794cd62015-06-16 13:13:10 -07001002void Device::OnIPConfigRefreshed(const IPConfigRefPtr& ipconfig) {
Paul Stewart82236532013-12-10 15:33:11 -08001003 // Clear the previously applied static IP parameters.
1004 ipconfig->RestoreSavedIPParameters(
1005 selected_service_->mutable_static_ip_parameters());
1006
1007 dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
1008 weak_ptr_factory_.GetWeakPtr()));
1009}
1010
Paul Stewartf6f96482013-07-12 12:49:15 -07001011void Device::OnIPConfigFailure() {
1012 if (selected_service_) {
1013 Error error;
Samuel Tan0d061192014-07-07 15:45:15 -07001014 selected_service_->DisconnectWithFailure(Service::kFailureDHCP,
1015 &error,
1016 __func__);
Paul Stewartf6f96482013-07-12 12:49:15 -07001017 }
1018}
1019
Paul Stewarta794cd62015-06-16 13:13:10 -07001020void Device::OnIPConfigExpired(const IPConfigRefPtr& ipconfig) {
Paul Stewart1f916e42013-12-23 09:52:54 -08001021 metrics()->SendToUMA(
1022 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001023 Metrics::kMetricExpiredLeaseLengthSecondsSuffix, technology()),
Paul Stewart1f916e42013-12-23 09:52:54 -08001024 ipconfig->properties().lease_duration_seconds,
1025 Metrics::kMetricExpiredLeaseLengthSecondsMin,
1026 Metrics::kMetricExpiredLeaseLengthSecondsMax,
1027 Metrics::kMetricExpiredLeaseLengthSecondsNumBuckets);
1028}
1029
Paul Stewarta794cd62015-06-16 13:13:10 -07001030void Device::OnDHCPv6ConfigUpdated(const IPConfigRefPtr& ipconfig,
Peter Qiud48fa0c2015-06-10 12:20:48 -07001031 bool /*new_lease_acquired*/) {
1032 // Emit configuration update.
1033 UpdateIPConfigsProperty();
1034}
1035
Paul Stewarta794cd62015-06-16 13:13:10 -07001036void Device::OnDHCPv6ConfigFailed(const IPConfigRefPtr& ipconfig) {
Peter Qiud48fa0c2015-06-10 12:20:48 -07001037 // Reset configuration data.
1038 ipconfig->ResetProperties();
1039 UpdateIPConfigsProperty();
1040}
1041
Paul Stewarta794cd62015-06-16 13:13:10 -07001042void Device::OnDHCPv6ConfigExpired(const IPConfigRefPtr& ipconfig) {
Peter Qiud48fa0c2015-06-10 12:20:48 -07001043 // Reset configuration data.
1044 ipconfig->ResetProperties();
1045 UpdateIPConfigsProperty();
1046}
1047
Peter Qiua388fdb2015-04-03 10:31:22 -07001048void Device::OnConnected() {
1049 if (selected_service_->unreliable()) {
1050 // Post a delayed task to reset link back to reliable if no link
1051 // failure is detected in the next 5 minutes.
1052 reliable_link_callback_.Reset(
1053 base::Bind(&Device::OnReliableLink, base::Unretained(this)));
1054 dispatcher_->PostDelayedTask(
1055 reliable_link_callback_.callback(),
1056 kLinkUnreliableThresholdSeconds * 1000);
1057 }
1058}
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001059
Paul Stewart8596f9f2013-03-14 07:58:26 -07001060void Device::OnConnectionUpdated() {
1061 if (selected_service_) {
1062 manager_->UpdateService(selected_service_);
1063 }
1064}
1065
Paul Stewarte6132022011-08-16 09:11:02 -07001066void Device::CreateConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001067 SLOG(this, 2) << __func__;
Paul Stewarte6132022011-08-16 09:11:02 -07001068 if (!connection_.get()) {
mukesh agrawal23ac6b72013-01-31 18:52:37 -08001069 connection_ = new Connection(interface_index_,
1070 link_name_,
1071 technology_,
1072 manager_->device_info());
Paul Stewarte6132022011-08-16 09:11:02 -07001073 }
1074}
1075
1076void Device::DestroyConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001077 SLOG(this, 2) << __func__ << " on " << link_name_;
Peter Qiu25f1be62014-08-12 10:42:27 -07001078 StopAllActivities();
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001079 if (selected_service_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001080 SLOG(this, 3) << "Clearing connection of service "
1081 << selected_service_->unique_name();
Ben Chancc225ef2014-09-30 13:26:51 -07001082 selected_service_->SetConnection(nullptr);
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001083 }
Ben Chancc225ef2014-09-30 13:26:51 -07001084 connection_ = nullptr;
Paul Stewarte6132022011-08-16 09:11:02 -07001085}
1086
Paul Stewarta794cd62015-06-16 13:13:10 -07001087void Device::SelectService(const ServiceRefPtr& service) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001088 SLOG(this, 2) << __func__ << ": service "
1089 << (service ? service->unique_name() : "*reset*")
1090 << " on " << link_name_;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001091
1092 if (selected_service_.get() == service.get()) {
1093 // No change to |selected_service_|. Return early to avoid
1094 // changing its state.
1095 return;
1096 }
1097
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001098 if (selected_service_.get()) {
1099 if (selected_service_->state() != Service::kStateFailure) {
1100 selected_service_->SetState(Service::kStateIdle);
1101 }
Paul Stewart20b0a092012-05-22 20:39:57 -07001102 // Just in case the Device subclass has not already done so, make
1103 // sure the previously selected service has its connection removed.
Ben Chancc225ef2014-09-30 13:26:51 -07001104 selected_service_->SetConnection(nullptr);
Peter Qiua388fdb2015-04-03 10:31:22 -07001105 // Reset link status for the previously selected service.
1106 selected_service_->set_unreliable(false);
1107 reliable_link_callback_.Cancel();
Peter Qiu25f1be62014-08-12 10:42:27 -07001108 StopAllActivities();
Paul Stewart03dba0b2011-08-22 16:32:45 -07001109 }
Peter Qiua0572032014-09-26 10:07:37 -07001110
1111 // Newly selected service (network), previous failures doesn't apply
1112 // anymore.
1113 last_link_monitor_failed_time_ = 0;
1114
Paul Stewart03dba0b2011-08-22 16:32:45 -07001115 selected_service_ = service;
Christopher Wiley674598d2014-12-12 10:21:39 -08001116 adaptor_->EmitRpcIdentifierChanged(
1117 kSelectedServiceProperty, GetSelectedServiceRpcIdentifier(nullptr));
Paul Stewart03dba0b2011-08-22 16:32:45 -07001118}
1119
1120void Device::SetServiceState(Service::ConnectState state) {
1121 if (selected_service_.get()) {
1122 selected_service_->SetState(state);
1123 }
1124}
1125
1126void Device::SetServiceFailure(Service::ConnectFailure failure_state) {
1127 if (selected_service_.get()) {
1128 selected_service_->SetFailure(failure_state);
1129 }
1130}
1131
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -04001132void Device::SetServiceFailureSilent(Service::ConnectFailure failure_state) {
1133 if (selected_service_.get()) {
1134 selected_service_->SetFailureSilent(failure_state);
1135 }
1136}
1137
Paul Stewarta794cd62015-06-16 13:13:10 -07001138bool Device::SetIPFlag(IPAddress::Family family, const string& flag,
1139 const string& value) {
Paul Stewart2bf1d352011-12-06 15:02:55 -08001140 string ip_version;
1141 if (family == IPAddress::kFamilyIPv4) {
1142 ip_version = kIPFlagVersion4;
1143 } else if (family == IPAddress::kFamilyIPv6) {
1144 ip_version = kIPFlagVersion6;
1145 } else {
1146 NOTIMPLEMENTED();
1147 }
1148 FilePath flag_file(StringPrintf(kIPFlagTemplate, ip_version.c_str(),
1149 link_name_.c_str(), flag.c_str()));
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001150 SLOG(this, 2) << "Writing " << value << " to flag file "
1151 << flag_file.value();
Ben Chan6fbf64f2014-05-21 18:07:01 -07001152 if (base::WriteFile(flag_file, value.c_str(), value.length()) != 1) {
Paul Stewart38fcf162015-06-12 09:52:17 -07001153 string message = StringPrintf("IP flag write failed: %s to %s",
1154 value.c_str(), flag_file.value().c_str());
1155 if (!base::PathExists(flag_file) &&
1156 ContainsValue(written_flags_, flag_file.value())) {
1157 SLOG(this, 2) << message << " (device is no longer present?)";
1158 } else {
1159 LOG(ERROR) << message;
1160 }
Paul Stewart2bf1d352011-12-06 15:02:55 -08001161 return false;
Paul Stewart38fcf162015-06-12 09:52:17 -07001162 } else {
1163 written_flags_.insert(flag_file.value());
Paul Stewart2bf1d352011-12-06 15:02:55 -08001164 }
1165 return true;
1166}
1167
Paul Stewarta794cd62015-06-16 13:13:10 -07001168string Device::PerformTDLSOperation(const string& /* operation */,
1169 const string& /* peer */,
1170 Error* /* error */) {
Paul Stewartc6fbad92013-11-13 14:50:52 -08001171 return "";
1172}
1173
Paul Stewart6ff27f52012-07-11 06:51:41 -07001174void Device::ResetByteCounters() {
1175 manager_->device_info()->GetByteCounts(
1176 interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
1177 manager_->UpdateDevice(this);
1178}
1179
Paul Stewartd215af62012-04-24 23:25:50 -07001180bool Device::RestartPortalDetection() {
1181 StopPortalDetection();
1182 return StartPortalDetection();
1183}
1184
Paul Stewartc681fa02012-03-02 19:40:04 -08001185bool Device::RequestPortalDetection() {
1186 if (!selected_service_) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001187 SLOG(this, 2) << FriendlyName()
1188 << ": No selected service, so no need for portal check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001189 return false;
1190 }
1191
1192 if (!connection_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001193 SLOG(this, 2) << FriendlyName()
1194 << ": No connection, so no need for portal check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001195 return false;
1196 }
1197
1198 if (selected_service_->state() != Service::kStatePortal) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001199 SLOG(this, 2) << FriendlyName()
1200 << ": Service is not in portal state. "
1201 << "No need to start check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001202 return false;
1203 }
1204
1205 if (!connection_->is_default()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001206 SLOG(this, 2) << FriendlyName()
1207 << ": Service is not the default connection. "
1208 << "Don't start check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001209 return false;
1210 }
1211
1212 if (portal_detector_.get() && portal_detector_->IsInProgress()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001213 SLOG(this, 2) << FriendlyName()
1214 << ": Portal detection is already running.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001215 return true;
1216 }
1217
1218 return StartPortalDetection();
1219}
1220
Paul Stewart20088d82012-02-16 06:58:55 -08001221bool Device::StartPortalDetection() {
Darin Petkov457728b2013-01-09 09:49:08 +01001222 DCHECK(selected_service_);
Paul Stewartd215af62012-04-24 23:25:50 -07001223 if (selected_service_->IsPortalDetectionDisabled()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001224 SLOG(this, 2) << "Service " << selected_service_->unique_name()
1225 << ": Portal detection is disabled; "
1226 << "marking service online.";
Paul Stewartd215af62012-04-24 23:25:50 -07001227 SetServiceConnectedState(Service::kStateOnline);
1228 return false;
1229 }
1230
1231 if (selected_service_->IsPortalDetectionAuto() &&
1232 !manager_->IsPortalDetectionEnabled(technology())) {
Paul Stewart20088d82012-02-16 06:58:55 -08001233 // If portal detection is disabled for this technology, immediately set
1234 // the service state to "Online".
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001235 SLOG(this, 2) << "Device " << FriendlyName()
1236 << ": Portal detection is disabled; "
1237 << "marking service online.";
Paul Stewart20088d82012-02-16 06:58:55 -08001238 SetServiceConnectedState(Service::kStateOnline);
1239 return false;
1240 }
1241
Paul Stewart20088d82012-02-16 06:58:55 -08001242 if (selected_service_->HasProxyConfig()) {
1243 // Services with HTTP proxy configurations should not be checked by the
1244 // connection manager, since we don't have the ability to evaluate
1245 // arbitrary proxy configs and their possible credentials.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001246 SLOG(this, 2) << "Device " << FriendlyName()
1247 << ": Service has proxy config; marking it online.";
Paul Stewart20088d82012-02-16 06:58:55 -08001248 SetServiceConnectedState(Service::kStateOnline);
1249 return false;
1250 }
1251
1252 portal_detector_.reset(new PortalDetector(connection_,
1253 dispatcher_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -05001254 portal_detector_callback_));
Paul Stewart20088d82012-02-16 06:58:55 -08001255 if (!portal_detector_->Start(manager_->GetPortalCheckURL())) {
1256 LOG(ERROR) << "Device " << FriendlyName()
1257 << ": Portal detection failed to start: likely bad URL: "
1258 << manager_->GetPortalCheckURL();
1259 SetServiceConnectedState(Service::kStateOnline);
1260 return false;
1261 }
1262
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001263 SLOG(this, 2) << "Device " << FriendlyName()
1264 << ": Portal detection has started.";
Paul Stewart20088d82012-02-16 06:58:55 -08001265 return true;
1266}
1267
1268void Device::StopPortalDetection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001269 SLOG(this, 2) << "Device " << FriendlyName()
1270 << ": Portal detection stopping.";
Paul Stewart20088d82012-02-16 06:58:55 -08001271 portal_detector_.reset();
1272}
1273
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001274bool Device::StartConnectivityTest() {
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -07001275 LOG(INFO) << "Device " << FriendlyName() << " starting connectivity test.";
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001276
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -07001277 connection_tester_.reset(new ConnectionTester(connection_,
1278 dispatcher_,
1279 connection_tester_callback_));
1280 connection_tester_->Start();
1281 return true;
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001282}
1283
Paul Stewarte8303eb2014-10-08 22:51:14 -07001284void Device::StopConnectivityTest() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001285 SLOG(this, 2) << "Device " << FriendlyName()
1286 << ": Connectivity test stopping.";
Paul Stewarte8303eb2014-10-08 22:51:14 -07001287 connection_tester_.reset();
1288}
1289
Paul Stewarta794cd62015-06-16 13:13:10 -07001290void Device::set_link_monitor(LinkMonitor* link_monitor) {
Paul Stewart036dba02012-08-07 12:34:41 -07001291 link_monitor_.reset(link_monitor);
1292}
1293
1294bool Device::StartLinkMonitor() {
1295 if (!manager_->IsTechnologyLinkMonitorEnabled(technology())) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001296 SLOG(this, 2) << "Device " << FriendlyName()
1297 << ": Link Monitoring is disabled.";
Paul Stewart036dba02012-08-07 12:34:41 -07001298 return false;
1299 }
1300
Peter Qiud49760e2014-09-19 16:13:42 -07001301 if (selected_service_ && selected_service_->link_monitor_disabled()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001302 SLOG(this, 2) << "Device " << FriendlyName()
1303 << ": Link Monitoring is disabled for the selected service";
Peter Qiud49760e2014-09-19 16:13:42 -07001304 return false;
1305 }
1306
Paul Stewart036dba02012-08-07 12:34:41 -07001307 if (!link_monitor()) {
1308 set_link_monitor(
1309 new LinkMonitor(
1310 connection_, dispatcher_, metrics(), manager_->device_info(),
Peter Qiub5d124f2014-04-14 12:05:02 -07001311 Bind(&Device::OnLinkMonitorFailure, weak_ptr_factory_.GetWeakPtr()),
1312 Bind(&Device::OnLinkMonitorGatewayChange,
1313 weak_ptr_factory_.GetWeakPtr())));
Paul Stewart036dba02012-08-07 12:34:41 -07001314 }
1315
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001316 SLOG(this, 2) << "Device " << FriendlyName()
1317 << ": Link Monitor starting.";
Paul Stewart036dba02012-08-07 12:34:41 -07001318 return link_monitor_->Start();
1319}
1320
1321void Device::StopLinkMonitor() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001322 SLOG(this, 2) << "Device " << FriendlyName()
1323 << ": Link Monitor stopping.";
Paul Stewart036dba02012-08-07 12:34:41 -07001324 link_monitor_.reset();
1325}
1326
Peter Qiu8e1ad162014-10-02 15:58:24 -07001327void Device::OnUnreliableLink() {
Peter Qiua388fdb2015-04-03 10:31:22 -07001328 SLOG(this, 2) << "Device " << FriendlyName()
1329 << ": Link is unreliable.";
1330 selected_service_->set_unreliable(true);
1331 reliable_link_callback_.Cancel();
Peter Qiu8e1ad162014-10-02 15:58:24 -07001332 metrics_->NotifyUnreliableLinkSignalStrength(
1333 technology_, selected_service_->strength());
1334}
1335
Peter Qiua388fdb2015-04-03 10:31:22 -07001336void Device::OnReliableLink() {
1337 SLOG(this, 2) << "Device " << FriendlyName()
1338 << ": Link is reliable.";
1339 selected_service_->set_unreliable(false);
1340 // TODO(zqiu): report signal strength to UMA.
1341}
1342
Paul Stewart036dba02012-08-07 12:34:41 -07001343void Device::OnLinkMonitorFailure() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001344 SLOG(this, 2) << "Device " << FriendlyName()
1345 << ": Link Monitor indicates failure.";
Peter Qiua0572032014-09-26 10:07:37 -07001346 if (!selected_service_) {
1347 return;
1348 }
1349
1350 time_t now;
1351 time_->GetSecondsBoottime(&now);
1352
Peter Qiua388fdb2015-04-03 10:31:22 -07001353 if (last_link_monitor_failed_time_ != 0 &&
1354 now - last_link_monitor_failed_time_ < kLinkUnreliableThresholdSeconds) {
Peter Qiu8e1ad162014-10-02 15:58:24 -07001355 OnUnreliableLink();
Peter Qiua0572032014-09-26 10:07:37 -07001356 }
1357 last_link_monitor_failed_time_ = now;
Paul Stewart036dba02012-08-07 12:34:41 -07001358}
1359
Peter Qiu9d581932014-04-14 16:37:37 -07001360void Device::OnLinkMonitorGatewayChange() {
1361 string gateway_mac = link_monitor()->gateway_mac_address().HexEncode();
1362 int connection_id = manager_->CalcConnectionId(
1363 ipconfig_->properties().gateway, gateway_mac);
1364
1365 CHECK(selected_service_);
1366 selected_service_->set_connection_id(connection_id);
1367
1368 manager_->ReportServicesOnSameNetwork(connection_id);
1369}
1370
Peter Qiu6f5618b2014-06-05 15:19:01 -07001371bool Device::StartDNSTest(
Paul Stewarta794cd62015-06-16 13:13:10 -07001372 const vector<string>& dns_servers,
Peter Qiu6f5618b2014-06-05 15:19:01 -07001373 bool retry_until_success,
Paul Stewarta794cd62015-06-16 13:13:10 -07001374 const Callback<void(const DNSServerTester::Status)>& callback) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001375 if (dns_server_tester_.get()) {
1376 LOG(ERROR) << FriendlyName() << ": "
1377 << "Failed to start DNS Test: current test still running";
1378 return false;
Peter Qiub9256f32014-05-09 15:27:29 -07001379 }
1380
Peter Qiu6f5618b2014-06-05 15:19:01 -07001381 dns_server_tester_.reset(new DNSServerTester(connection_,
1382 dispatcher_,
1383 dns_servers,
1384 retry_until_success,
1385 callback));
1386 dns_server_tester_->Start();
1387 return true;
1388}
1389
1390void Device::StopDNSTest() {
1391 dns_server_tester_.reset();
Peter Qiub9256f32014-05-09 15:27:29 -07001392}
1393
Peter Qiud670d032014-06-03 15:04:43 -07001394void Device::FallbackDNSResultCallback(const DNSServerTester::Status status) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001395 StopDNSTest();
Peter Qiuf18e7712014-05-20 09:59:46 -07001396 int result = Metrics::kFallbackDNSTestResultFailure;
Peter Qiud670d032014-06-03 15:04:43 -07001397 if (status == DNSServerTester::kStatusSuccess) {
Peter Qiuf18e7712014-05-20 09:59:46 -07001398 result = Metrics::kFallbackDNSTestResultSuccess;
Peter Qiua89154b2014-05-23 15:45:42 -07001399
1400 // Switch to fallback DNS server if service is configured to allow DNS
1401 // fallback.
1402 CHECK(selected_service_);
1403 if (selected_service_->is_dns_auto_fallback_allowed()) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001404 LOG(INFO) << "Device " << FriendlyName()
1405 << ": Switching to fallback DNS servers.";
1406 // Save the DNS servers from ipconfig.
1407 config_dns_servers_ = ipconfig_->properties().dns_servers;
Peter Qiua89154b2014-05-23 15:45:42 -07001408 SwitchDNSServers(vector<string>(std::begin(kFallbackDnsServers),
1409 std::end(kFallbackDnsServers)));
Peter Qiu6f5618b2014-06-05 15:19:01 -07001410 // Start DNS test for configured DNS servers.
1411 StartDNSTest(config_dns_servers_,
1412 true,
1413 Bind(&Device::ConfigDNSResultCallback,
1414 weak_ptr_factory_.GetWeakPtr()));
Peter Qiua89154b2014-05-23 15:45:42 -07001415 }
Peter Qiub9256f32014-05-09 15:27:29 -07001416 }
Peter Qiuf18e7712014-05-20 09:59:46 -07001417 metrics()->NotifyFallbackDNSTestResult(technology_, result);
Peter Qiu6f5618b2014-06-05 15:19:01 -07001418}
1419
1420void Device::ConfigDNSResultCallback(const DNSServerTester::Status status) {
1421 StopDNSTest();
1422 // DNS test failed to start due to internal error.
1423 if (status == DNSServerTester::kStatusFailure) {
1424 return;
1425 }
1426
1427 // Switch back to the configured DNS servers.
1428 LOG(INFO) << "Device " << FriendlyName()
1429 << ": Switching back to configured DNS servers.";
1430 SwitchDNSServers(config_dns_servers_);
Peter Qiub9256f32014-05-09 15:27:29 -07001431}
1432
Paul Stewarta794cd62015-06-16 13:13:10 -07001433void Device::SwitchDNSServers(const vector<string>& dns_servers) {
Peter Qiua89154b2014-05-23 15:45:42 -07001434 CHECK(ipconfig_);
1435 CHECK(connection_);
1436 // Push new DNS servers setting to the IP config object.
1437 ipconfig_->UpdateDNSServers(dns_servers);
1438 // Push new DNS servers setting to the current connection, so the resolver
1439 // will be updated to use the new DNS servers.
1440 connection_->UpdateDNSServers(dns_servers);
1441 // Allow the service to notify Chrome of ipconfig changes.
1442 selected_service_->NotifyIPConfigChanges();
Peter Qiu6f5618b2014-06-05 15:19:01 -07001443 // Restart the portal detection with the new DNS setting.
1444 RestartPortalDetection();
Peter Qiua89154b2014-05-23 15:45:42 -07001445}
1446
Paul Stewarta794cd62015-06-16 13:13:10 -07001447void Device::set_traffic_monitor(TrafficMonitor* traffic_monitor) {
Peter Qiudc335f82014-05-15 10:33:17 -07001448 traffic_monitor_.reset(traffic_monitor);
1449}
1450
Paul Stewarta794cd62015-06-16 13:13:10 -07001451bool Device::TimeToNextDHCPLeaseRenewal(uint32_t* result) {
Samuel Tan787a1ce2014-11-11 17:17:27 -08001452 if (!ipconfig() && !ip6config()) {
1453 return false;
1454 }
1455 uint32_t time_to_ipv4_lease_expiry = UINT32_MAX;
1456 uint32_t time_to_ipv6_lease_expiry = UINT32_MAX;
1457 if (ipconfig()) {
1458 ipconfig()->TimeToLeaseExpiry(&time_to_ipv4_lease_expiry);
1459 }
1460 if (ip6config()) {
1461 ip6config()->TimeToLeaseExpiry(&time_to_ipv6_lease_expiry);
1462 }
1463 *result = std::min(time_to_ipv4_lease_expiry, time_to_ipv6_lease_expiry);
1464 return true;
1465}
1466
Peter Qiudc335f82014-05-15 10:33:17 -07001467bool Device::IsTrafficMonitorEnabled() const {
1468 return false;
1469}
1470
1471void Device::StartTrafficMonitor() {
1472 // Return if traffic monitor is not enabled for this device.
1473 if (!IsTrafficMonitorEnabled()) {
1474 return;
1475 }
1476
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001477 SLOG(this, 2) << "Device " << FriendlyName()
1478 << ": Traffic Monitor starting.";
Peter Qiudc335f82014-05-15 10:33:17 -07001479 if (!traffic_monitor_.get()) {
1480 traffic_monitor_.reset(new TrafficMonitor(this, dispatcher_));
1481 traffic_monitor_->set_network_problem_detected_callback(
1482 Bind(&Device::OnEncounterNetworkProblem,
1483 weak_ptr_factory_.GetWeakPtr()));
1484 }
1485 traffic_monitor_->Start();
1486}
1487
1488void Device::StopTrafficMonitor() {
1489 // Return if traffic monitor is not enabled for this device.
1490 if (!IsTrafficMonitorEnabled()) {
1491 return;
1492 }
1493
1494 if (traffic_monitor_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001495 SLOG(this, 2) << "Device " << FriendlyName()
1496 << ": Traffic Monitor stopping.";
Peter Qiudc335f82014-05-15 10:33:17 -07001497 traffic_monitor_->Stop();
1498 }
1499 traffic_monitor_.reset();
1500}
1501
1502void Device::OnEncounterNetworkProblem(int reason) {
1503 int metric_code;
1504 switch (reason) {
1505 case TrafficMonitor::kNetworkProblemCongestedTxQueue:
1506 metric_code = Metrics::kNetworkProblemCongestedTCPTxQueue;
1507 break;
1508 case TrafficMonitor::kNetworkProblemDNSFailure:
1509 metric_code = Metrics::kNetworkProblemDNSFailure;
1510 break;
1511 default:
1512 LOG(ERROR) << "Invalid network problem code: " << reason;
1513 return;
1514 }
1515
1516 metrics()->NotifyNetworkProblemDetected(technology_, metric_code);
1517 // Stop the traffic monitor, only report the first network problem detected
1518 // on the connection for now.
1519 StopTrafficMonitor();
1520}
1521
Paul Stewart20088d82012-02-16 06:58:55 -08001522void Device::SetServiceConnectedState(Service::ConnectState state) {
1523 DCHECK(selected_service_.get());
1524
1525 if (!selected_service_.get()) {
1526 LOG(ERROR) << FriendlyName() << ": "
1527 << "Portal detection completed but no selected service exists!";
1528 return;
1529 }
1530
1531 if (!selected_service_->IsConnected()) {
1532 LOG(ERROR) << FriendlyName() << ": "
1533 << "Portal detection completed but selected service "
Darin Petkov457728b2013-01-09 09:49:08 +01001534 << selected_service_->unique_name()
Paul Stewart20088d82012-02-16 06:58:55 -08001535 << " is in non-connected state.";
1536 return;
1537 }
1538
Paul Stewartc681fa02012-03-02 19:40:04 -08001539 if (state == Service::kStatePortal && connection_->is_default() &&
1540 manager_->GetPortalCheckInterval() != 0) {
1541 CHECK(portal_detector_.get());
1542 if (!portal_detector_->StartAfterDelay(
1543 manager_->GetPortalCheckURL(),
1544 manager_->GetPortalCheckInterval())) {
1545 LOG(ERROR) << "Device " << FriendlyName()
1546 << ": Portal detection failed to restart: likely bad URL: "
1547 << manager_->GetPortalCheckURL();
1548 SetServiceState(Service::kStateOnline);
1549 portal_detector_.reset();
1550 return;
1551 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001552 SLOG(this, 2) << "Device " << FriendlyName()
1553 << ": Portal detection retrying.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001554 } else {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001555 SLOG(this, 2) << "Device " << FriendlyName()
1556 << ": Portal will not retry.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001557 portal_detector_.reset();
1558 }
1559
Paul Stewart20088d82012-02-16 06:58:55 -08001560 SetServiceState(state);
1561}
1562
Paul Stewarta794cd62015-06-16 13:13:10 -07001563void Device::PortalDetectorCallback(const PortalDetector::Result& result) {
Paul Stewart20088d82012-02-16 06:58:55 -08001564 if (!result.final) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001565 SLOG(this, 2) << "Device " << FriendlyName()
1566 << ": Received non-final status: "
1567 << ConnectivityTrial::StatusToString(
1568 result.trial_result.status);
Paul Stewart20088d82012-02-16 06:58:55 -08001569 return;
1570 }
1571
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001572 SLOG(this, 2) << "Device " << FriendlyName()
1573 << ": Received final status: "
1574 << ConnectivityTrial::StatusToString(
1575 result.trial_result.status);
Paul Stewart20088d82012-02-16 06:58:55 -08001576
Thieu Le85e050b2012-03-13 15:04:38 -07001577 portal_attempts_to_online_ += result.num_attempts;
1578
Peter Qiub9256f32014-05-09 15:27:29 -07001579 int portal_status = Metrics::PortalDetectionResultToEnum(result);
Thieu Le85e050b2012-03-13 15:04:38 -07001580 metrics()->SendEnumToUMA(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001581 metrics()->GetFullMetricName(Metrics::kMetricPortalResultSuffix,
1582 technology()),
Peter Qiub9256f32014-05-09 15:27:29 -07001583 portal_status,
Thieu Le85e050b2012-03-13 15:04:38 -07001584 Metrics::kPortalResultMax);
1585
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -07001586 if (result.trial_result.status == ConnectivityTrial::kStatusSuccess) {
Paul Stewart20088d82012-02-16 06:58:55 -08001587 SetServiceConnectedState(Service::kStateOnline);
Thieu Le85e050b2012-03-13 15:04:38 -07001588
1589 metrics()->SendToUMA(
1590 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001591 Metrics::kMetricPortalAttemptsToOnlineSuffix, technology()),
Thieu Le85e050b2012-03-13 15:04:38 -07001592 portal_attempts_to_online_,
1593 Metrics::kMetricPortalAttemptsToOnlineMin,
1594 Metrics::kMetricPortalAttemptsToOnlineMax,
1595 Metrics::kMetricPortalAttemptsToOnlineNumBuckets);
Paul Stewart20088d82012-02-16 06:58:55 -08001596 } else {
Peter Qiu9b83c892014-08-09 23:06:02 -07001597 // Set failure phase and status.
1598 if (selected_service_.get()) {
1599 selected_service_->SetPortalDetectionFailure(
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -07001600 ConnectivityTrial::PhaseToString(result.trial_result.phase),
1601 ConnectivityTrial::StatusToString(result.trial_result.status));
Peter Qiu9b83c892014-08-09 23:06:02 -07001602 }
Paul Stewart20088d82012-02-16 06:58:55 -08001603 SetServiceConnectedState(Service::kStatePortal);
Thieu Le85e050b2012-03-13 15:04:38 -07001604
1605 metrics()->SendToUMA(
1606 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001607 Metrics::kMetricPortalAttemptsSuffix, technology()),
Thieu Le85e050b2012-03-13 15:04:38 -07001608 result.num_attempts,
1609 Metrics::kMetricPortalAttemptsMin,
1610 Metrics::kMetricPortalAttemptsMax,
1611 Metrics::kMetricPortalAttemptsNumBuckets);
Peter Qiub9256f32014-05-09 15:27:29 -07001612
Peter Qiub25083f2014-08-25 13:22:31 -07001613 // TODO(zqiu): Only support fallback DNS server for IPv4 for now.
1614 if (connection_->IsIPv6()) {
1615 return;
1616 }
1617
Peter Qiub9256f32014-05-09 15:27:29 -07001618 // Perform fallback DNS test if the portal failure is DNS related.
1619 // The test will send a DNS request to Google's DNS server to determine
1620 // if the DNS failure is due to bad DNS server settings.
1621 if ((portal_status == Metrics::kPortalResultDNSFailure) ||
1622 (portal_status == Metrics::kPortalResultDNSTimeout)) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001623 StartDNSTest(vector<string>(std::begin(kFallbackDnsServers),
1624 std::end(kFallbackDnsServers)),
1625 false,
1626 Bind(&Device::FallbackDNSResultCallback,
1627 weak_ptr_factory_.GetWeakPtr()));
Peter Qiub9256f32014-05-09 15:27:29 -07001628 }
Paul Stewart20088d82012-02-16 06:58:55 -08001629 }
1630}
1631
Paul Stewarta794cd62015-06-16 13:13:10 -07001632string Device::GetSelectedServiceRpcIdentifier(Error* /*error*/) {
Christopher Wiley674598d2014-12-12 10:21:39 -08001633 if (!selected_service_) {
1634 return "/";
1635 }
1636 return selected_service_->GetRpcIdentifier();
1637}
1638
Paul Stewarta794cd62015-06-16 13:13:10 -07001639vector<string> Device::AvailableIPConfigs(Error* /*error*/) {
Paul Stewartd4f26482014-04-25 19:12:03 -07001640 vector<string> ipconfigs;
1641 if (ipconfig_) {
1642 ipconfigs.push_back(ipconfig_->GetRpcIdentifier());
Jason Glasgow08afdff2012-04-03 10:22:26 -04001643 }
Paul Stewartd4f26482014-04-25 19:12:03 -07001644 if (ip6config_) {
1645 ipconfigs.push_back(ip6config_->GetRpcIdentifier());
1646 }
Peter Qiud48fa0c2015-06-10 12:20:48 -07001647 if (dhcpv6_config_) {
1648 ipconfigs.push_back(dhcpv6_config_->GetRpcIdentifier());
1649 }
Paul Stewartd4f26482014-04-25 19:12:03 -07001650 return ipconfigs;
Chris Masone4e851612011-07-01 10:46:53 -07001651}
1652
1653string Device::GetRpcConnectionIdentifier() {
1654 return adaptor_->GetRpcConnectionIdentifier();
1655}
1656
Paul Stewarta794cd62015-06-16 13:13:10 -07001657uint64_t Device::GetLinkMonitorResponseTime(Error* error) {
Paul Stewart036dba02012-08-07 12:34:41 -07001658 if (!link_monitor_.get()) {
1659 // It is not strictly an error that the link monitor does not
1660 // exist, but returning an error here allows the GetProperties
1661 // call in our Adaptor to omit this parameter.
1662 error->Populate(Error::kNotFound, "Device is not running LinkMonitor");
1663 return 0;
1664 }
1665 return link_monitor_->GetResponseTimeMilliseconds();
1666}
1667
Ben Chan7fab8972014-08-10 17:14:46 -07001668uint64_t Device::GetReceiveByteCount() {
1669 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -07001670 manager_->device_info()->GetByteCounts(
1671 interface_index_, &rx_byte_count, &tx_byte_count);
1672 return rx_byte_count - receive_byte_offset_;
1673}
1674
Ben Chan7fab8972014-08-10 17:14:46 -07001675uint64_t Device::GetTransmitByteCount() {
1676 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -07001677 manager_->device_info()->GetByteCounts(
1678 interface_index_, &rx_byte_count, &tx_byte_count);
1679 return tx_byte_count - transmit_byte_offset_;
1680}
1681
Paul Stewarta794cd62015-06-16 13:13:10 -07001682uint64_t Device::GetReceiveByteCountProperty(Error* /*error*/) {
Ben Chanb061f892013-02-27 17:46:55 -08001683 return GetReceiveByteCount();
1684}
1685
Paul Stewarta794cd62015-06-16 13:13:10 -07001686uint64_t Device::GetTransmitByteCountProperty(Error* /*error*/) {
Ben Chanb061f892013-02-27 17:46:55 -08001687 return GetTransmitByteCount();
1688}
1689
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001690bool Device::IsUnderlyingDeviceEnabled() const {
1691 return false;
1692}
1693
Eric Shienbrood9a245532012-03-07 14:20:39 -05001694// callback
Paul Stewarta794cd62015-06-16 13:13:10 -07001695void Device::OnEnabledStateChanged(const ResultCallback& callback,
1696 const Error& error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001697 SLOG(this, 2) << __func__
1698 << " (target: " << enabled_pending_ << ","
1699 << " success: " << error.IsSuccess() << ")"
1700 << " on " << link_name_;
Eric Shienbrood9a245532012-03-07 14:20:39 -05001701 if (error.IsSuccess()) {
1702 enabled_ = enabled_pending_;
1703 manager_->UpdateEnabledTechnologies();
Ben Chan923a5022013-09-20 11:23:23 -07001704 adaptor_->EmitBoolChanged(kPoweredProperty, enabled_);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001705 }
Gary Morainbaeefdf2012-04-30 14:53:35 -07001706 enabled_pending_ = enabled_;
Eric Shienbrood9a245532012-03-07 14:20:39 -05001707 if (!callback.is_null())
1708 callback.Run(error);
1709}
1710
1711void Device::SetEnabled(bool enable) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001712 SLOG(this, 2) << __func__ << "(" << enable << ")";
Jason Glasgow4a490792012-04-10 15:02:05 -04001713 Error error;
mukesh agrawal28185512013-10-18 16:57:09 -07001714 SetEnabledChecked(enable, false, &error, ResultCallback());
Arman Uguray8bf6a5c2013-08-12 14:18:03 -07001715
1716 // SetEnabledInternal might fail here if there is an unfinished enable or
1717 // disable operation. Don't log error in this case, as this method is only
1718 // called when the underlying device is already in the target state and the
1719 // pending operation should eventually bring the device to the expected
1720 // state.
1721 LOG_IF(ERROR,
1722 error.IsFailure() &&
1723 !error.IsOngoing() &&
1724 error.type() != Error::kInProgress)
Jason Glasgow4a490792012-04-10 15:02:05 -04001725 << "Enabled failed, but no way to report the failure.";
Eric Shienbrood9a245532012-03-07 14:20:39 -05001726}
1727
Ben Chan9f3dcf82013-09-25 18:04:58 -07001728void Device::SetEnabledNonPersistent(bool enable,
Paul Stewarta794cd62015-06-16 13:13:10 -07001729 Error* error,
1730 const ResultCallback& callback) {
mukesh agrawal28185512013-10-18 16:57:09 -07001731 SetEnabledChecked(enable, false, error, callback);
Ben Chan9f3dcf82013-09-25 18:04:58 -07001732}
1733
Eric Shienbrood9a245532012-03-07 14:20:39 -05001734void Device::SetEnabledPersistent(bool enable,
Paul Stewarta794cd62015-06-16 13:13:10 -07001735 Error* error,
1736 const ResultCallback& callback) {
mukesh agrawal28185512013-10-18 16:57:09 -07001737 SetEnabledChecked(enable, true, error, callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001738}
1739
mukesh agrawal28185512013-10-18 16:57:09 -07001740void Device::SetEnabledChecked(bool enable,
1741 bool persist,
Paul Stewarta794cd62015-06-16 13:13:10 -07001742 Error* error,
1743 const ResultCallback& callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -04001744 DCHECK(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001745 SLOG(this, 2) << "Device " << link_name_ << " "
1746 << (enable ? "starting" : "stopping");
Paul Stewartff6be292014-11-24 17:05:03 -08001747 if (enable && manager_->IsTechnologyProhibited(technology())) {
1748 error->Populate(Error::kPermissionDenied, "The " +
1749 Technology::NameFromIdentifier(technology()) +
1750 " technology is prohibited");
1751 return;
1752 }
1753
Eric Shienbrood9a245532012-03-07 14:20:39 -05001754 if (enable == enabled_) {
Arman Uguray2f352e62013-08-28 19:12:53 -07001755 if (enable != enabled_pending_ && persist) {
1756 // Return an error, as there is an ongoing operation to achieve the
1757 // opposite.
1758 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -08001759 FROM_HERE, error, Error::kOperationFailed,
Arman Uguray2f352e62013-08-28 19:12:53 -07001760 enable ? "Cannot enable while the device is disabling." :
1761 "Cannot disable while the device is enabling.");
1762 return;
1763 }
mukesh agrawal28185512013-10-18 16:57:09 -07001764 LOG(INFO) << "Already in desired enable state.";
Jason Glasgow4a490792012-04-10 15:02:05 -04001765 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -05001766 return;
1767 }
1768
1769 if (enabled_pending_ == enable) {
Paul Stewart34f424e2015-01-16 15:30:20 -08001770 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
Jason Glasgow4a490792012-04-10 15:02:05 -04001771 "Enable operation already in progress");
Eric Shienbrood9a245532012-03-07 14:20:39 -05001772 return;
1773 }
1774
1775 if (persist) {
1776 enabled_persistent_ = enable;
Darin Petkove7c6ad32012-06-29 10:22:09 +02001777 manager_->UpdateDevice(this);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001778 }
1779
mukesh agrawal28185512013-10-18 16:57:09 -07001780 SetEnabledUnchecked(enable, error, callback);
1781}
1782
Paul Stewarta794cd62015-06-16 13:13:10 -07001783void Device::SetEnabledUnchecked(bool enable, Error* error,
1784 const ResultCallback& on_enable_complete) {
Eric Shienbrood9a245532012-03-07 14:20:39 -05001785 enabled_pending_ = enable;
mukesh agrawal28185512013-10-18 16:57:09 -07001786 EnabledStateChangedCallback chained_callback =
Eric Shienbrood9a245532012-03-07 14:20:39 -05001787 Bind(&Device::OnEnabledStateChanged,
mukesh agrawal28185512013-10-18 16:57:09 -07001788 weak_ptr_factory_.GetWeakPtr(), on_enable_complete);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001789 if (enable) {
1790 running_ = true;
mukesh agrawal28185512013-10-18 16:57:09 -07001791 Start(error, chained_callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001792 } else {
1793 running_ = false;
1794 DestroyIPConfig(); // breaks a reference cycle
Ben Chancc225ef2014-09-30 13:26:51 -07001795 SelectService(nullptr); // breaks a reference cycle
Eric Shienbrood9a245532012-03-07 14:20:39 -05001796 rtnl_handler_->SetInterfaceFlags(interface_index(), 0, IFF_UP);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001797 SLOG(this, 3) << "Device " << link_name_ << " ipconfig_ "
1798 << (ipconfig_ ? "is set." : "is not set.");
1799 SLOG(this, 3) << "Device " << link_name_ << " ip6config_ "
1800 << (ip6config_ ? "is set." : "is not set.");
1801 SLOG(this, 3) << "Device " << link_name_ << " connection_ "
1802 << (connection_ ? "is set." : "is not set.");
1803 SLOG(this, 3) << "Device " << link_name_ << " selected_service_ "
1804 << (selected_service_ ? "is set." : "is not set.");
mukesh agrawal28185512013-10-18 16:57:09 -07001805 Stop(error, chained_callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001806 }
1807}
1808
Paul Stewartd4f26482014-04-25 19:12:03 -07001809void Device::UpdateIPConfigsProperty() {
1810 adaptor_->EmitRpcIdentifierArrayChanged(
Ben Chancc225ef2014-09-30 13:26:51 -07001811 kIPConfigsProperty, AvailableIPConfigs(nullptr));
Paul Stewartd4f26482014-04-25 19:12:03 -07001812}
1813
Paul Stewarta794cd62015-06-16 13:13:10 -07001814bool Device::ResolvePeerMacAddress(const string& input,
1815 string* output,
1816 Error* error) {
Peter Qiu62abf312015-05-05 12:58:05 -07001817 if (!MakeHardwareAddressFromString(input).empty()) {
1818 // Input is already a MAC address.
1819 *output = input;
1820 return true;
1821 }
1822
1823 IPAddress ip_address(IPAddress::kFamilyIPv4);
1824 if (!ip_address.SetAddressFromString(input)) {
1825 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
1826 "Peer is neither an IP Address nor a MAC address");
1827 return false;
1828 }
1829
1830 // Peer address was specified as an IP address which we need to resolve.
Paul Stewarta794cd62015-06-16 13:13:10 -07001831 const DeviceInfo* device_info = manager()->device_info();
Peter Qiu62abf312015-05-05 12:58:05 -07001832 if (!device_info->HasDirectConnectivityTo(interface_index_, ip_address)) {
1833 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
1834 "IP address is not local to this interface");
1835 return false;
1836 }
1837
1838 ByteString mac_address;
1839 if (device_info->GetMACAddressOfPeer(interface_index_,
1840 ip_address,
1841 &mac_address)) {
1842 *output = MakeStringFromHardwareAddress(
1843 vector<uint8_t>(mac_address.GetConstData(),
1844 mac_address.GetConstData() +
1845 mac_address.GetLength()));
1846 SLOG(this, 2) << "ARP cache lookup returned peer: " << *output;
1847 return true;
1848 }
1849
1850 if (!Icmp().TransmitEchoRequest(ip_address)) {
1851 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed,
1852 "Failed to send ICMP request to peer to setup ARP");
1853 } else {
1854 // ARP request was transmitted successfully, address resolution is still
1855 // pending.
1856 error->Populate(Error::kInProgress,
1857 "Peer MAC address was not found in the ARP cache, "
1858 "but an ARP request was sent to find it. "
1859 "Please try again.");
1860 }
1861 return false;
1862}
1863
1864// static
1865vector<uint8_t> Device::MakeHardwareAddressFromString(
Paul Stewarta794cd62015-06-16 13:13:10 -07001866 const string& address_string) {
Peter Qiu62abf312015-05-05 12:58:05 -07001867 string address_nosep;
1868 base::RemoveChars(address_string, ":", &address_nosep);
1869 vector<uint8_t> address_bytes;
1870 base::HexStringToBytes(address_nosep, &address_bytes);
1871 if (address_bytes.size() != kHardwareAddressLength) {
1872 return vector<uint8_t>();
1873 }
1874 return address_bytes;
1875}
1876
1877// static
1878string Device::MakeStringFromHardwareAddress(
Paul Stewarta794cd62015-06-16 13:13:10 -07001879 const vector<uint8_t>& address_bytes) {
Peter Qiu62abf312015-05-05 12:58:05 -07001880 CHECK_EQ(kHardwareAddressLength, address_bytes.size());
1881 return StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
1882 address_bytes[0], address_bytes[1], address_bytes[2],
1883 address_bytes[3], address_bytes[4], address_bytes[5]);
1884}
1885
Paul Stewart75897df2011-04-27 09:05:53 -07001886} // namespace shill