blob: c6e688d962ef57dc7905a0335942b7ea7b11853e [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>
Ben Chana0ddf462014-02-06 11:32:42 -080023#include <base/strings/stringprintf.h>
Peter Qiu62abf312015-05-05 12:58:05 -070024#include <base/strings/string_number_conversions.h>
25#include <base/strings/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070026#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070027
Arman Ugurayf84a4242013-04-09 20:01:07 -070028#include "shill/async_connection.h"
Paul Stewarte6132022011-08-16 09:11:02 -070029#include "shill/connection.h"
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -070030#include "shill/connection_tester.h"
Paul Stewart75897df2011-04-27 09:05:53 -070031#include "shill/control_interface.h"
Chris Masoned7732e42011-05-20 11:08:56 -070032#include "shill/device_dbus_adaptor.h"
Peter Qiu675d0b02015-06-03 13:08:09 -070033#include "shill/dhcp/dhcp_config.h"
34#include "shill/dhcp/dhcp_provider.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070035#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070036#include "shill/event_dispatcher.h"
Gaurav Shah6d2c72d2012-10-16 16:30:44 -070037#include "shill/geolocation_info.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070038#include "shill/http_proxy.h"
Peter Qiu62abf312015-05-05 12:58:05 -070039#include "shill/icmp.h"
Samuel Tanfe734672014-08-07 15:50:48 -070040#include "shill/ip_address_store.h"
Paul Stewart036dba02012-08-07 12:34:41 -070041#include "shill/link_monitor.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070042#include "shill/logging.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070043#include "shill/manager.h"
Thieu Le85e050b2012-03-13 15:04:38 -070044#include "shill/metrics.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070045#include "shill/net/ip_address.h"
46#include "shill/net/ndisc.h"
47#include "shill/net/rtnl_handler.h"
Chris Masone95207da2011-06-29 16:50:49 -070048#include "shill/property_accessor.h"
Chris Masone2b105542011-06-22 10:58:09 -070049#include "shill/refptr_types.h"
Chris Masone2b105542011-06-22 10:58:09 -070050#include "shill/service.h"
Arman Ugurayf84a4242013-04-09 20:01:07 -070051#include "shill/socket_info_reader.h"
Chris Masone5dec5f42011-07-22 14:07:55 -070052#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080053#include "shill/technology.h"
Paul Stewartfa11e282013-12-02 22:04:25 -080054#include "shill/tethering.h"
Peter Qiudc335f82014-05-15 10:33:17 -070055#include "shill/traffic_monitor.h"
Paul Stewart75897df2011-04-27 09:05:53 -070056
Eric Shienbrood3e20a232012-02-16 11:35:56 -050057using base::Bind;
Peter Qiu6f5618b2014-06-05 15:19:01 -070058using base::Callback;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080059using base::FilePath;
Chris Masone5dec5f42011-07-22 14:07:55 -070060using base::StringPrintf;
Garret Kellyc5f89d12015-02-18 14:39:36 -050061using std::set;
Chris Masone8fe2c7e2011-06-09 15:51:19 -070062using std::string;
63using std::vector;
64
Paul Stewart75897df2011-04-27 09:05:53 -070065namespace shill {
Chris Masone5dec5f42011-07-22 14:07:55 -070066
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070067namespace Logging {
68static auto kModuleLogScope = ScopeLogger::kDevice;
69static string ObjectID(Device *d) { return d->GetRpcIdentifier(); }
70}
71
Chris Masone5dec5f42011-07-22 14:07:55 -070072// static
Paul Stewart2bf1d352011-12-06 15:02:55 -080073const char Device::kIPFlagTemplate[] = "/proc/sys/net/%s/conf/%s/%s";
74// static
75const char Device::kIPFlagVersion4[] = "ipv4";
76// static
77const char Device::kIPFlagVersion6[] = "ipv6";
78// static
79const char Device::kIPFlagDisableIPv6[] = "disable_ipv6";
80// static
81const char Device::kIPFlagUseTempAddr[] = "use_tempaddr";
82// static
83const char Device::kIPFlagUseTempAddrUsedAndDefault[] = "2";
Paul Stewartc8f4bef2011-12-13 09:45:51 -080084// static
85const char Device::kIPFlagReversePathFilter[] = "rp_filter";
86// static
87const char Device::kIPFlagReversePathFilterEnabled[] = "1";
88// static
89const char Device::kIPFlagReversePathFilterLooseMode[] = "2";
Paul Stewart2bf1d352011-12-06 15:02:55 -080090// static
Paul Stewart2cb3fa72014-11-13 01:43:12 -080091const char Device::kIPFlagArpAnnounce[] = "arp_announce";
92// static
93const char Device::kIPFlagArpAnnounceDefault[] = "0";
94// static
95const char Device::kIPFlagArpAnnounceBestLocal[] = "2";
96// static
97const char Device::kIPFlagArpIgnore[] = "arp_ignore";
98// static
99const char Device::kIPFlagArpIgnoreDefault[] = "0";
100// static
101const char Device::kIPFlagArpIgnoreLocalOnly[] = "1";
102// static
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700103const char Device::kStoragePowered[] = "Powered";
104// static
Paul Stewart6ff27f52012-07-11 06:51:41 -0700105const char Device::kStorageReceiveByteCount[] = "ReceiveByteCount";
106// static
107const char Device::kStorageTransmitByteCount[] = "TransmitByteCount";
Peter Qiub9256f32014-05-09 15:27:29 -0700108// static
109const char Device::kFallbackDnsTestHostname[] = "www.gstatic.com";
110// static
111const char* Device::kFallbackDnsServers[] = {
112 "8.8.8.8",
Peter Qiua89154b2014-05-23 15:45:42 -0700113 "8.8.4.4"
Peter Qiub9256f32014-05-09 15:27:29 -0700114};
115
116// static
117const int Device::kDNSTimeoutMilliseconds = 5000;
Peter Qiua388fdb2015-04-03 10:31:22 -0700118const int Device::kLinkUnreliableThresholdSeconds = 60 * 60;
Peter Qiu62abf312015-05-05 12:58:05 -0700119const size_t Device::kHardwareAddressLength = 6U;
Chris Masone5dec5f42011-07-22 14:07:55 -0700120
Paul Stewart75897df2011-04-27 09:05:53 -0700121Device::Device(ControlInterface *control_interface,
Paul Stewartb50f0b92011-05-16 16:31:42 -0700122 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -0800123 Metrics *metrics,
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700124 Manager *manager,
Darin Petkovafa6fc42011-06-21 16:21:08 -0700125 const string &link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700126 const string &address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800127 int interface_index,
128 Technology::Identifier technology)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500129 : enabled_(false),
130 enabled_persistent_(true),
131 enabled_pending_(enabled_),
Chris Masoneb925cc82011-06-22 15:39:57 -0700132 reconnect_(true),
Chris Masone626719f2011-08-18 16:58:48 -0700133 hardware_address_(address),
mukesh agrawalf60e4062011-05-27 13:13:41 -0700134 interface_index_(interface_index),
135 running_(false),
Darin Petkovafa6fc42011-06-21 16:21:08 -0700136 link_name_(link_name),
Chris Masone19e30402011-07-19 15:48:47 -0700137 unique_id_(link_name),
Darin Petkovd9661952011-08-03 16:25:42 -0700138 control_interface_(control_interface),
139 dispatcher_(dispatcher),
Thieu Le3426c8f2012-01-11 17:35:11 -0800140 metrics_(metrics),
Chris Masone7df0c672011-07-15 10:24:54 -0700141 manager_(manager),
Eric Shienbrood9a245532012-03-07 14:20:39 -0500142 weak_ptr_factory_(this),
Darin Petkov77cb6812011-08-15 16:19:41 -0700143 adaptor_(control_interface->CreateDeviceAdaptor(this)),
Eric Shienbrood9a245532012-03-07 14:20:39 -0500144 portal_detector_callback_(Bind(&Device::PortalDetectorCallback,
145 weak_ptr_factory_.GetWeakPtr())),
Gaurav Shah435de2c2011-11-17 19:01:07 -0800146 technology_(technology),
Thieu Le85e050b2012-03-13 15:04:38 -0700147 portal_attempts_to_online_(0),
Paul Stewart6ff27f52012-07-11 06:51:41 -0700148 receive_byte_offset_(0),
149 transmit_byte_offset_(0),
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700150 dhcp_provider_(DHCPProvider::GetInstance()),
Peter Qiua0572032014-09-26 10:07:37 -0700151 rtnl_handler_(RTNLHandler::GetInstance()),
152 time_(Time::GetInstance()),
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -0700153 last_link_monitor_failed_time_(0),
154 connection_tester_callback_(Bind(&Device::ConnectionTesterCallback,
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800155 weak_ptr_factory_.GetWeakPtr())),
156 is_loose_routing_(false),
157 is_multi_homed_(false) {
Ben Chan923a5022013-09-20 11:23:23 -0700158 store_.RegisterConstString(kAddressProperty, &hardware_address_);
Chris Masone4d42df82011-07-02 17:09:39 -0700159
Ben Chan923a5022013-09-20 11:23:23 -0700160 // kBgscanMethodProperty: Registered in WiFi
161 // kBgscanShortIntervalProperty: Registered in WiFi
162 // kBgscanSignalThresholdProperty: Registered in WiFi
Chris Masone4d42df82011-07-02 17:09:39 -0700163
Ben Chan923a5022013-09-20 11:23:23 -0700164 // kCellularAllowRoamingProperty: Registered in Cellular
165 // kCarrierProperty: Registered in Cellular
166 // kEsnProperty: Registered in Cellular
167 // kHomeProviderProperty: Registered in Cellular
168 // kImeiProperty: Registered in Cellular
169 // kIccidProperty: Registered in Cellular
170 // kImsiProperty: Registered in Cellular
171 // kManufacturerProperty: Registered in Cellular
172 // kMdnProperty: Registered in Cellular
173 // kMeidProperty: Registered in Cellular
174 // kMinProperty: Registered in Cellular
175 // kModelIDProperty: Registered in Cellular
176 // kFirmwareRevisionProperty: Registered in Cellular
177 // kHardwareRevisionProperty: Registered in Cellular
178 // kPRLVersionProperty: Registered in Cellular
179 // kSIMLockStatusProperty: Registered in Cellular
180 // kFoundNetworksProperty: Registered in Cellular
Ben Chan923a5022013-09-20 11:23:23 -0700181 // kDBusObjectProperty: Register in Cellular
Chris Masone4d42df82011-07-02 17:09:39 -0700182
Ben Chan923a5022013-09-20 11:23:23 -0700183 store_.RegisterConstString(kInterfaceProperty, &link_name_);
Christopher Wiley674598d2014-12-12 10:21:39 -0800184 HelpRegisterConstDerivedRpcIdentifier(
185 kSelectedServiceProperty, &Device::GetSelectedServiceRpcIdentifier);
Ben Chan923a5022013-09-20 11:23:23 -0700186 HelpRegisterConstDerivedRpcIdentifiers(kIPConfigsProperty,
Jason Glasgow08afdff2012-04-03 10:22:26 -0400187 &Device::AvailableIPConfigs);
Ben Chan923a5022013-09-20 11:23:23 -0700188 store_.RegisterConstString(kNameProperty, &link_name_);
189 store_.RegisterConstBool(kPoweredProperty, &enabled_);
190 HelpRegisterConstDerivedString(kTypeProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700191 &Device::GetTechnologyString);
Ben Chan39a7beb2013-09-21 11:28:00 -0700192 HelpRegisterConstDerivedUint64(kLinkMonitorResponseTimeProperty,
Paul Stewart036dba02012-08-07 12:34:41 -0700193 &Device::GetLinkMonitorResponseTime);
Jason Glasgowb5790052012-01-27 01:03:52 -0500194
Chris Masoneb925cc82011-06-22 15:39:57 -0700195 // TODO(cmasone): Chrome doesn't use this...does anyone?
Ben Chan923a5022013-09-20 11:23:23 -0700196 // store_.RegisterConstBool(kReconnectProperty, &reconnect_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700197
Chris Masone4e851612011-07-01 10:46:53 -0700198 // TODO(cmasone): Figure out what shill concept maps to flimflam's "Network".
Ben Chan923a5022013-09-20 11:23:23 -0700199 // known_properties_.push_back(kNetworksProperty);
Chris Masoneb925cc82011-06-22 15:39:57 -0700200
Wade Guthrie227c7742013-10-10 11:06:33 -0700201 // kRoamThresholdProperty: Registered in WiFi
Ben Chan923a5022013-09-20 11:23:23 -0700202 // kScanningProperty: Registered in WiFi, Cellular
203 // kScanIntervalProperty: Registered in WiFi, Cellular
Samuel Tan96e35cf2014-10-28 22:27:38 -0700204 // kWakeOnWiFiFeaturesEnabledProperty: Registered in WiFi
Paul Stewart6ff27f52012-07-11 06:51:41 -0700205
206 if (manager_ && manager_->device_info()) { // Unit tests may not have these.
207 manager_->device_info()->GetByteCounts(
208 interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700209 HelpRegisterConstDerivedUint64(kReceiveByteCountProperty,
Ben Chanb061f892013-02-27 17:46:55 -0800210 &Device::GetReceiveByteCountProperty);
Ben Chan39a7beb2013-09-21 11:28:00 -0700211 HelpRegisterConstDerivedUint64(kTransmitByteCountProperty,
Ben Chanb061f892013-02-27 17:46:55 -0800212 &Device::GetTransmitByteCountProperty);
Paul Stewart6ff27f52012-07-11 06:51:41 -0700213 }
214
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800215 DisableArpFiltering();
216 EnableReversePathFilter();
217
Darin Petkova0a0efe2012-06-27 12:50:01 +0200218 LOG(INFO) << "Device created: " << link_name_
219 << " index " << interface_index_;
Paul Stewart75897df2011-04-27 09:05:53 -0700220}
221
222Device::~Device() {
Darin Petkova0a0efe2012-06-27 12:50:01 +0200223 LOG(INFO) << "Device destructed: " << link_name_
224 << " index " << interface_index_;
Paul Stewart75897df2011-04-27 09:05:53 -0700225}
226
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700227void Device::LinkEvent(unsigned flags, unsigned change) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700228 SLOG(this, 2) << "Device " << link_name_
229 << std::showbase << std::hex
230 << " flags " << flags << " changed " << change
231 << std::dec << std::noshowbase;
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700232}
233
Wade Guthrie4823f4f2013-07-25 10:03:03 -0700234void Device::Scan(ScanType scan_type, Error *error, const string &reason) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700235 SLOG(this, 2) << __func__ << " [Device] on " << link_name() << " from "
236 << reason;
Paul Stewart34f424e2015-01-16 15:30:20 -0800237 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Paul Stewartbe005172011-11-02 18:10:29 -0700238 "Device doesn't support scan.");
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700239}
240
Peter Qiud51b2442015-02-23 10:41:38 -0800241void Device::SetSchedScan(bool enable, Error *error) {
242 SLOG(this, 2) << __func__ << " [Device] on " << link_name();
243 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
244 "Device doesn't support scheduled scan.");
245}
246
Eric Shienbrood9a245532012-03-07 14:20:39 -0500247void Device::RegisterOnNetwork(const std::string &/*network_id*/, Error *error,
248 const ResultCallback &/*callback*/) {
Paul Stewart34f424e2015-01-16 15:30:20 -0800249 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Paul Stewartbe005172011-11-02 18:10:29 -0700250 "Device doesn't support network registration.");
Darin Petkov9ae310f2011-08-30 15:41:13 -0700251}
252
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100253void Device::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500254 const string &/*pin*/, bool /*require*/,
255 Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700256 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800257 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500258 "Device doesn't support RequirePIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700259}
260
Eric Shienbrood9a245532012-03-07 14:20:39 -0500261void Device::EnterPIN(const string &/*pin*/,
262 Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700263 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800264 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500265 "Device doesn't support EnterPIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700266}
267
mukesh agrawal1830fa12011-09-26 14:31:40 -0700268void Device::UnblockPIN(const string &/*unblock_code*/,
269 const string &/*pin*/,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500270 Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700271 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800272 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500273 "Device doesn't support UnblockPIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700274}
275
mukesh agrawal1830fa12011-09-26 14:31:40 -0700276void Device::ChangePIN(const string &/*old_pin*/,
277 const string &/*new_pin*/,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500278 Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700279 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800280 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500281 "Device doesn't support ChangePIN.");
Darin Petkove42e1012011-08-31 12:35:04 -0700282}
283
Ben Chanad663e12013-01-08 01:58:47 -0800284void Device::Reset(Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700285 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800286 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Ben Chanad663e12013-01-08 01:58:47 -0800287 "Device doesn't support Reset.");
288}
289
Darin Petkovc37a9c42012-09-06 15:28:22 +0200290void Device::SetCarrier(const string &/*carrier*/,
291 Error *error, const ResultCallback &/*callback*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700292 SLOG(this, 2) << __func__;
Paul Stewart34f424e2015-01-16 15:30:20 -0800293 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
Darin Petkovc37a9c42012-09-06 15:28:22 +0200294 "Device doesn't support SetCarrier.");
295}
296
Ben Chanbcc6e012013-11-04 14:28:37 -0800297bool Device::IsIPv6Allowed() const {
298 return true;
299}
300
Paul Stewart2bf1d352011-12-06 15:02:55 -0800301void Device::DisableIPv6() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700302 SLOG(this, 2) << __func__;
Paul Stewart2bf1d352011-12-06 15:02:55 -0800303 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "1");
304}
305
306void Device::EnableIPv6() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700307 SLOG(this, 2) << __func__;
Ben Chanbcc6e012013-11-04 14:28:37 -0800308 if (!IsIPv6Allowed()) {
309 LOG(INFO) << "Skip enabling IPv6 on " << link_name_
310 << " as it is not allowed.";
311 return;
312 }
Paul Stewart2bf1d352011-12-06 15:02:55 -0800313 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "0");
314}
315
316void Device::EnableIPv6Privacy() {
317 SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagUseTempAddr,
318 kIPFlagUseTempAddrUsedAndDefault);
319}
320
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800321void Device::SetLooseRouting(bool is_loose_routing) {
322 if (is_loose_routing == is_loose_routing_) {
323 return;
324 }
325 is_loose_routing_ = is_loose_routing;
326 if (is_multi_homed_) {
327 // Nothing to do: loose routing is already enabled, and should remain so.
328 return;
329 }
330 if (is_loose_routing) {
331 DisableReversePathFilter();
332 } else {
333 EnableReversePathFilter();
334 }
335}
336
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800337void Device::DisableReversePathFilter() {
338 // TODO(pstew): Current kernel doesn't offer reverse-path filtering flag
Paul Stewartee6b3d72013-07-12 16:07:51 -0700339 // for IPv6. crbug.com/207193
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800340 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
341 kIPFlagReversePathFilterLooseMode);
342}
343
344void Device::EnableReversePathFilter() {
345 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
346 kIPFlagReversePathFilterEnabled);
347}
348
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800349void Device::SetIsMultiHomed(bool is_multi_homed) {
350 if (is_multi_homed == is_multi_homed_) {
351 return;
352 }
353 LOG(INFO) << "Device " << FriendlyName() << " multi-home state is now "
354 << is_multi_homed;
355 is_multi_homed_ = is_multi_homed;
356 if (is_multi_homed) {
357 EnableArpFiltering();
358 if (!is_loose_routing_) {
359 DisableReversePathFilter();
360 }
361 } else {
362 DisableArpFiltering();
363 if (!is_loose_routing_) {
364 EnableReversePathFilter();
365 }
366 }
367}
368
369void Device::DisableArpFiltering() {
370 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
371 kIPFlagArpAnnounceDefault);
372 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore, kIPFlagArpIgnoreDefault);
373}
374
375void Device::EnableArpFiltering() {
376 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
377 kIPFlagArpAnnounceBestLocal);
378 SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore,
379 kIPFlagArpIgnoreLocalOnly);
380}
381
Gaurav Shah435de2c2011-11-17 19:01:07 -0800382bool Device::IsConnected() const {
383 if (selected_service_)
384 return selected_service_->IsConnected();
385 return false;
386}
387
Paul Stewartd215af62012-04-24 23:25:50 -0700388bool Device::IsConnectedToService(const ServiceRefPtr &service) const {
389 return service == selected_service_ && IsConnected();
390}
391
Paul Stewartfa11e282013-12-02 22:04:25 -0800392bool Device::IsConnectedViaTether() const {
393 return
394 ipconfig_.get() &&
395 ipconfig_->properties().vendor_encapsulated_options ==
396 Tethering::kAndroidVendorEncapsulatedOptions;
397}
398
mukesh agrawalf6b32092013-04-10 15:49:55 -0700399string Device::GetRpcIdentifier() const {
Chris Masone27c4aa52011-07-02 13:10:14 -0700400 return adaptor_->GetRpcIdentifier();
Chris Masone8fe2c7e2011-06-09 15:51:19 -0700401}
402
mukesh agrawal515873d2014-07-21 17:01:35 -0700403string Device::GetStorageIdentifier() const {
Chris Masone5dec5f42011-07-22 14:07:55 -0700404 string id = GetRpcIdentifier();
405 ControlInterface::RpcIdToStorageId(&id);
Chris Masone626719f2011-08-18 16:58:48 -0700406 size_t needle = id.find('_');
Chris Masone34af2182011-08-22 11:59:36 -0700407 DLOG_IF(ERROR, needle == string::npos) << "No _ in storage id?!?!";
Chris Masone626719f2011-08-18 16:58:48 -0700408 id.replace(id.begin() + needle + 1, id.end(), hardware_address_);
Chris Masone5dec5f42011-07-22 14:07:55 -0700409 return id;
410}
411
Gaurav Shah6d2c72d2012-10-16 16:30:44 -0700412vector<GeolocationInfo> Device::GetGeolocationObjects() const {
413 return vector<GeolocationInfo>();
Wade Guthrie227c7742013-10-10 11:06:33 -0700414}
Gaurav Shah6d2c72d2012-10-16 16:30:44 -0700415
Jason Glasgowb5790052012-01-27 01:03:52 -0500416string Device::GetTechnologyString(Error */*error*/) {
417 return Technology::NameFromIdentifier(technology());
418}
419
Chris Masone19e30402011-07-19 15:48:47 -0700420const string& Device::FriendlyName() const {
Chris Masone7df0c672011-07-15 10:24:54 -0700421 return link_name_;
Darin Petkovafa6fc42011-06-21 16:21:08 -0700422}
423
Chris Masone19e30402011-07-19 15:48:47 -0700424const string& Device::UniqueName() const {
425 return unique_id_;
426}
427
Chris Masone5dec5f42011-07-22 14:07:55 -0700428bool Device::Load(StoreInterface *storage) {
429 const string id = GetStorageIdentifier();
430 if (!storage->ContainsGroup(id)) {
431 LOG(WARNING) << "Device is not available in the persistent store: " << id;
432 return false;
433 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500434 enabled_persistent_ = true;
435 storage->GetBool(id, kStoragePowered, &enabled_persistent_);
Ben Chan7fab8972014-08-10 17:14:46 -0700436 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -0700437
438 manager_->device_info()->GetByteCounts(
439 interface_index_, &rx_byte_count, &tx_byte_count);
440 // If there is a byte-count present in the profile, the return value
441 // of Device::Get*ByteCount() should be the this stored value plus
442 // whatever additional bytes we receive since time-of-load. We
443 // accomplish this by the subtractions below, which can validly
444 // roll over "negative" in the subtractions below and in Get*ByteCount.
Ben Chan7fab8972014-08-10 17:14:46 -0700445 uint64_t profile_byte_count;
Paul Stewart6ff27f52012-07-11 06:51:41 -0700446 if (storage->GetUint64(id, kStorageReceiveByteCount, &profile_byte_count)) {
447 receive_byte_offset_ = rx_byte_count - profile_byte_count;
448 }
449 if (storage->GetUint64(id, kStorageTransmitByteCount, &profile_byte_count)) {
450 transmit_byte_offset_ = tx_byte_count - profile_byte_count;
451 }
452
Chris Masone5dec5f42011-07-22 14:07:55 -0700453 return true;
454}
455
456bool Device::Save(StoreInterface *storage) {
457 const string id = GetStorageIdentifier();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500458 storage->SetBool(id, kStoragePowered, enabled_persistent_);
Ben Chanb061f892013-02-27 17:46:55 -0800459 storage->SetUint64(id, kStorageReceiveByteCount, GetReceiveByteCount());
460 storage->SetUint64(id, kStorageTransmitByteCount, GetTransmitByteCount());
Chris Masone5dec5f42011-07-22 14:07:55 -0700461 return true;
462}
463
Samuel Tanfbe8d2b2014-09-15 20:23:59 -0700464void Device::OnBeforeSuspend(const ResultCallback &callback) {
465 // Nothing to be done in the general case, so immediately report success.
466 callback.Run(Error(Error::kSuccess));
mukesh agrawal784566d2012-08-08 18:32:58 -0700467}
468
469void Device::OnAfterResume() {
Samuel Tan787a1ce2014-11-11 17:17:27 -0800470 RenewDHCPLease();
mukesh agrawalbb2231c2013-07-17 16:32:24 -0700471 if (link_monitor_) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700472 SLOG(this, 3) << "Informing Link Monitor of resume.";
mukesh agrawalbb2231c2013-07-17 16:32:24 -0700473 link_monitor_->OnAfterResume();
474 }
Peter Qiua0572032014-09-26 10:07:37 -0700475 // Resume from sleep, could be in different location now.
476 // Ignore previous link monitor failures.
Peter Qiua388fdb2015-04-03 10:31:22 -0700477 if (selected_service_) {
478 selected_service_->set_unreliable(false);
479 reliable_link_callback_.Cancel();
480 }
Peter Qiua0572032014-09-26 10:07:37 -0700481 last_link_monitor_failed_time_ = 0;
mukesh agrawal784566d2012-08-08 18:32:58 -0700482}
483
Samuel Tan68b73d22014-10-28 17:00:56 -0700484void Device::OnDarkResume(const ResultCallback &callback) {
485 // Nothing to be done in the general case, so immediately report success.
486 callback.Run(Error(Error::kSuccess));
Prathmesh Prabhu64ad2382014-08-26 11:19:30 -0700487}
488
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200489void Device::DropConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700490 SLOG(this, 2) << __func__;
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200491 DestroyIPConfig();
Ben Chancc225ef2014-09-30 13:26:51 -0700492 SelectService(nullptr);
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200493}
494
Darin Petkovafa6fc42011-06-21 16:21:08 -0700495void Device::DestroyIPConfig() {
Paul Stewart2bf1d352011-12-06 15:02:55 -0800496 DisableIPv6();
Darin Petkovafa6fc42011-06-21 16:21:08 -0700497 if (ipconfig_.get()) {
Paul Stewart217c61d2013-06-13 15:12:02 -0700498 ipconfig_->ReleaseIP(IPConfig::kReleaseReasonDisconnect);
Ben Chancc225ef2014-09-30 13:26:51 -0700499 ipconfig_ = nullptr;
Paul Stewartd4f26482014-04-25 19:12:03 -0700500 UpdateIPConfigsProperty();
Darin Petkovafa6fc42011-06-21 16:21:08 -0700501 }
Peter Qiu25f1be62014-08-12 10:42:27 -0700502 if (ip6config_.get()) {
503 StopIPv6DNSServerTimer();
Ben Chancc225ef2014-09-30 13:26:51 -0700504 ip6config_ = nullptr;
Peter Qiu25f1be62014-08-12 10:42:27 -0700505 UpdateIPConfigsProperty();
506 }
Paul Stewarte6132022011-08-16 09:11:02 -0700507 DestroyConnection();
Darin Petkovafa6fc42011-06-21 16:21:08 -0700508}
509
Paul Stewartd4f26482014-04-25 19:12:03 -0700510void Device::OnIPv6AddressChanged() {
511 IPAddress address(IPAddress::kFamilyIPv6);
512 if (!manager_->device_info()->GetPrimaryIPv6Address(
513 interface_index_, &address)) {
514 if (ip6config_) {
Ben Chancc225ef2014-09-30 13:26:51 -0700515 ip6config_ = nullptr;
Paul Stewartd4f26482014-04-25 19:12:03 -0700516 UpdateIPConfigsProperty();
517 }
518 return;
519 }
520
521 IPConfig::Properties properties;
522 if (!address.IntoString(&properties.address)) {
523 LOG(ERROR) << "Unable to convert IPv6 address into a string!";
524 return;
525 }
526 properties.subnet_prefix = address.prefix();
527
528 if (!ip6config_) {
529 ip6config_ = new IPConfig(control_interface_, link_name_);
530 } else if (properties.address == ip6config_->properties().address &&
531 properties.subnet_prefix ==
532 ip6config_->properties().subnet_prefix) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700533 SLOG(this, 2) << __func__ << " primary address for "
534 << link_name_ << " is unchanged.";
Paul Stewartd4f26482014-04-25 19:12:03 -0700535 return;
536 }
537
538 properties.address_family = IPAddress::kFamilyIPv6;
539 properties.method = kTypeIPv6;
Peter Qiu25f1be62014-08-12 10:42:27 -0700540 // It is possible for device to receive DNS server notification before IP
541 // address notification, so preserve the saved DNS server if it exist.
542 properties.dns_servers = ip6config_->properties().dns_servers;
Garret Kellyc5f89d12015-02-18 14:39:36 -0500543 PrependDNSServers(IPAddress::kFamilyIPv6, &properties.dns_servers);
Paul Stewartd4f26482014-04-25 19:12:03 -0700544 ip6config_->set_properties(properties);
545 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700546 OnIPv6ConfigUpdated();
Paul Stewartd4f26482014-04-25 19:12:03 -0700547}
548
Peter Qiu98551702014-07-28 13:28:53 -0700549void Device::OnIPv6DnsServerAddressesChanged() {
Peter Qiu25f1be62014-08-12 10:42:27 -0700550 vector<IPAddress> server_addresses;
551 uint32 lifetime;
552
553 // Stop any existing timer.
554 StopIPv6DNSServerTimer();
555
556 if (!manager_->device_info()->GetIPv6DnsServerAddresses(
557 interface_index_, &server_addresses, &lifetime) || lifetime == 0) {
558 IPv6DNSServerExpired();
559 return;
560 }
561
562 vector<string> addresses_str;
563 for (const auto &ip : server_addresses) {
564 string address_str;
565 if (!ip.IntoString(&address_str)) {
566 LOG(ERROR) << "Unable to convert IPv6 address into a string!";
567 IPv6DNSServerExpired();
568 return;
569 }
570 addresses_str.push_back(address_str);
571 }
572
Peter Qiu25f1be62014-08-12 10:42:27 -0700573 if (!ip6config_) {
574 ip6config_ = new IPConfig(control_interface_, link_name_);
575 }
576
Samuel Tan815a6fb2014-10-23 16:53:59 -0700577 if (lifetime != ND_OPT_LIFETIME_INFINITY) {
578 // Setup timer to monitor DNS server lifetime if not infinite lifetime.
579 StartIPv6DNSServerTimer(lifetime);
580 ip6config_->UpdateLeaseExpirationTime(lifetime);
581 } else {
582 ip6config_->ResetLeaseExpirationTime();
583 }
584
Garret Kellyc5f89d12015-02-18 14:39:36 -0500585 PrependDNSServers(IPAddress::kFamilyIPv6, &addresses_str);
586
Peter Qiu25f1be62014-08-12 10:42:27 -0700587 // Done if no change in server addresses.
588 if (ip6config_->properties().dns_servers == addresses_str) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700589 SLOG(this, 2) << __func__ << " IPv6 DNS server list for "
590 << link_name_ << " is unchanged.";
Peter Qiu25f1be62014-08-12 10:42:27 -0700591 return;
592 }
593
594 ip6config_->UpdateDNSServers(addresses_str);
595 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700596 OnIPv6ConfigUpdated();
Peter Qiu25f1be62014-08-12 10:42:27 -0700597}
598
599void Device::StartIPv6DNSServerTimer(uint32 lifetime_seconds) {
600 int64 delay = static_cast<int64>(lifetime_seconds) * 1000;
601 ipv6_dns_server_expired_callback_.Reset(
602 base::Bind(&Device::IPv6DNSServerExpired, base::Unretained(this)));
603 dispatcher_->PostDelayedTask(ipv6_dns_server_expired_callback_.callback(),
604 delay);
605}
606
607void Device::StopIPv6DNSServerTimer() {
608 ipv6_dns_server_expired_callback_.Cancel();
609}
610
611void Device::IPv6DNSServerExpired() {
612 if (!ip6config_) {
613 return;
614 }
615 ip6config_->UpdateDNSServers(vector<string>());
616 UpdateIPConfigsProperty();
617}
618
619void Device::StopAllActivities() {
620 StopTrafficMonitor();
621 StopPortalDetection();
Paul Stewarte8303eb2014-10-08 22:51:14 -0700622 StopConnectivityTest();
Peter Qiu25f1be62014-08-12 10:42:27 -0700623 StopLinkMonitor();
624 StopDNSTest();
625 StopIPv6DNSServerTimer();
Peter Qiu98551702014-07-28 13:28:53 -0700626}
627
Samuel Tan96bdaec2014-11-05 18:27:38 -0800628void Device::AddWakeOnPacketConnection(const string &ip_endpoint,
Samuel Tanfe734672014-08-07 15:50:48 -0700629 Error *error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700630 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800631 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700632 "AddWakeOnPacketConnection not implemented for " + link_name_ + ".");
633 return;
634}
635
Samuel Tan96bdaec2014-11-05 18:27:38 -0800636void Device::RemoveWakeOnPacketConnection(const string &ip_endpoint,
Samuel Tanfe734672014-08-07 15:50:48 -0700637 Error *error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700638 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800639 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700640 "RemoveWakeOnPacketConnection not implemented for " + link_name_ + ".");
641 return;
642}
643
644void Device::RemoveAllWakeOnPacketConnections(Error *error) {
Samuel Tan5412de02014-08-15 17:56:26 -0700645 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -0800646 FROM_HERE, error, Error::kNotSupported,
Samuel Tanfe734672014-08-07 15:50:48 -0700647 "RemoveAllWakeOnPacketConnections not implemented for " + link_name_ +
648 ".");
649 return;
650}
651
Samuel Tan787a1ce2014-11-11 17:17:27 -0800652void Device::RenewDHCPLease() {
653 LOG(INFO) << __func__;
654
655 if (ipconfig_) {
656 SLOG(this, 3) << "Renewing IPv4 Address";
657 ipconfig_->RenewIP();
658 }
659 if (ip6config_) {
660 SLOG(this, 3) << "Waiting for new IPv6 configuration";
661 // Invalidate the old IPv6 configuration, will receive notifications
662 // from kernel for new IPv6 configuration if there is one.
663 StopIPv6DNSServerTimer();
664 ip6config_ = nullptr;
665 UpdateIPConfigsProperty();
666 }
667}
668
Arman Ugurayed8e6102012-11-29 14:47:20 -0800669bool Device::ShouldUseArpGateway() const {
670 return false;
671}
672
Paul Stewart316acef2014-05-29 18:40:48 -0700673bool Device::IsUsingStaticIP() const {
674 if (!selected_service_) {
675 return false;
676 }
677 return selected_service_->HasStaticIPAddress();
678}
679
Garret Kellyd01b5cc2015-03-12 16:20:55 -0400680bool Device::IsUsingStaticNameServers() const {
681 if (!selected_service_) {
682 return false;
683 }
684 return selected_service_->HasStaticNameServers();
685}
686
Paul Stewart2bf1d352011-12-06 15:02:55 -0800687bool Device::AcquireIPConfig() {
Paul Stewartd408fdf2012-05-07 17:15:57 -0700688 return AcquireIPConfigWithLeaseName(string());
689}
690
691bool Device::AcquireIPConfigWithLeaseName(const string &lease_name) {
Darin Petkovafa6fc42011-06-21 16:21:08 -0700692 DestroyIPConfig();
Paul Stewart2bf1d352011-12-06 15:02:55 -0800693 EnableIPv6();
Arman Ugurayed8e6102012-11-29 14:47:20 -0800694 bool arp_gateway = manager_->GetArpGateway() && ShouldUseArpGateway();
Peter Qiu8e0151e2015-06-04 09:41:47 -0700695 auto dhcp_config = dhcp_provider_->CreateIPv4Config(
696 link_name_, manager_->GetHostName(), lease_name, arp_gateway);
Garret Kelly782cdce2015-04-01 16:39:16 -0400697 const int minimum_mtu = manager()->GetMinimumMTU();
698 if (minimum_mtu != IPConfig::kUndefinedMTU) {
699 dhcp_config->set_minimum_mtu(minimum_mtu);
700 }
701
702 ipconfig_ = dhcp_config;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500703 ipconfig_->RegisterUpdateCallback(Bind(&Device::OnIPConfigUpdated,
704 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc5099532013-12-12 07:53:15 -0800705 ipconfig_->RegisterFailureCallback(Bind(&Device::OnIPConfigFailed,
706 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart82236532013-12-10 15:33:11 -0800707 ipconfig_->RegisterRefreshCallback(Bind(&Device::OnIPConfigRefreshed,
708 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart1f916e42013-12-23 09:52:54 -0800709 ipconfig_->RegisterExpireCallback(Bind(&Device::OnIPConfigExpired,
710 weak_ptr_factory_.GetWeakPtr()));
Paul Stewart1062d9d2012-04-27 10:42:27 -0700711 dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
712 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovafa6fc42011-06-21 16:21:08 -0700713 return ipconfig_->RequestIP();
714}
715
Ben Chan539ab022014-02-03 16:34:57 -0800716void Device::AssignIPConfig(const IPConfig::Properties &properties) {
717 DestroyIPConfig();
718 EnableIPv6();
719 ipconfig_ = new IPConfig(control_interface_, link_name_);
720 ipconfig_->set_properties(properties);
721 dispatcher_->PostTask(Bind(&Device::OnIPConfigUpdated,
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800722 weak_ptr_factory_.GetWeakPtr(), ipconfig_, true));
Ben Chan539ab022014-02-03 16:34:57 -0800723}
724
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800725void Device::DestroyIPConfigLease(const string &name) {
726 dhcp_provider_->DestroyLease(name);
727}
728
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700729void Device::HelpRegisterConstDerivedString(
Jason Glasgowb5790052012-01-27 01:03:52 -0500730 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700731 string(Device::*get)(Error *error)) {
Jason Glasgowb5790052012-01-27 01:03:52 -0500732 store_.RegisterDerivedString(
733 name,
Ben Chancc225ef2014-09-30 13:26:51 -0700734 StringAccessor(new CustomAccessor<Device, string>(this, get, nullptr)));
Chris Masone4e851612011-07-01 10:46:53 -0700735}
736
Christopher Wiley674598d2014-12-12 10:21:39 -0800737void Device::HelpRegisterConstDerivedRpcIdentifier(
738 const string &name,
739 RpcIdentifier(Device::*get)(Error *error)) {
740 store_.RegisterDerivedRpcIdentifier(
741 name,
742 RpcIdentifierAccessor(
743 new CustomAccessor<Device, RpcIdentifier>(this, get, nullptr)));
744}
745
Jason Glasgow08afdff2012-04-03 10:22:26 -0400746void Device::HelpRegisterConstDerivedRpcIdentifiers(
747 const string &name,
748 RpcIdentifiers(Device::*get)(Error *)) {
749 store_.RegisterDerivedRpcIdentifiers(
750 name,
751 RpcIdentifiersAccessor(
Ben Chancc225ef2014-09-30 13:26:51 -0700752 new CustomAccessor<Device, RpcIdentifiers>(this, get, nullptr)));
Jason Glasgow08afdff2012-04-03 10:22:26 -0400753}
754
Paul Stewart6ff27f52012-07-11 06:51:41 -0700755void Device::HelpRegisterConstDerivedUint64(
756 const string &name,
Ben Chan7fab8972014-08-10 17:14:46 -0700757 uint64_t(Device::*get)(Error *)) {
Paul Stewart6ff27f52012-07-11 06:51:41 -0700758 store_.RegisterDerivedUint64(
759 name,
760 Uint64Accessor(
Ben Chancc225ef2014-09-30 13:26:51 -0700761 new CustomAccessor<Device, uint64_t>(this, get, nullptr)));
Paul Stewart6ff27f52012-07-11 06:51:41 -0700762}
763
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -0700764void Device::ConnectionTesterCallback() {
765 LOG(INFO) << "Device " << FriendlyName() << ": Completed Connectivity Test";
766 return;
767}
768
Paul Stewart1062d9d2012-04-27 10:42:27 -0700769void Device::ConfigureStaticIPTask() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700770 SLOG(this, 2) << __func__ << " selected_service " << selected_service_.get()
771 << " ipconfig " << ipconfig_.get();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700772
773 if (!selected_service_ || !ipconfig_) {
774 return;
775 }
776
Paul Stewart316acef2014-05-29 18:40:48 -0700777 if (IsUsingStaticIP()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700778 SLOG(this, 2) << __func__ << " " << " configuring static IP parameters.";
Paul Stewart1062d9d2012-04-27 10:42:27 -0700779 // If the parameters contain an IP address, apply them now and bring
780 // the interface up. When DHCP information arrives, it will supplement
781 // the static information.
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800782 OnIPConfigUpdated(ipconfig_, true);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700783 } else {
Paul Stewart82236532013-12-10 15:33:11 -0800784 // Either |ipconfig_| has just been created in AcquireIPConfig() or
785 // we're being called by OnIPConfigRefreshed(). In either case a
786 // DHCP client has been started, and will take care of calling
787 // OnIPConfigUpdated() when it completes.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700788 SLOG(this, 2) << __func__ << " " << " no static IP address.";
Paul Stewart1062d9d2012-04-27 10:42:27 -0700789 }
790}
791
Peter Qiub25083f2014-08-25 13:22:31 -0700792bool Device::IPConfigCompleted(const IPConfigRefPtr &ipconfig) {
793 return ipconfig && !ipconfig->properties().address.empty() &&
794 !ipconfig->properties().dns_servers.empty();
795}
796
797void Device::OnIPv6ConfigUpdated() {
798 // Setup connection using IPv6 configuration only if the IPv6 configuration
799 // is ready for connection (contained both IP address and DNS servers), and
800 // there is no existing IPv4 connection. We always prefer IPv4
801 // configuration over IPv6.
802 if (IPConfigCompleted(ip6config_) &&
803 (!connection_ || connection_->IsIPv6())) {
804 SetupConnection(ip6config_);
805 }
806}
807
808void Device::SetupConnection(const IPConfigRefPtr &ipconfig) {
809 CreateConnection();
810 connection_->UpdateFromIPConfig(ipconfig);
811
Peter Qiu300769e2014-08-27 11:48:45 -0700812 // Report connection type.
813 Metrics::NetworkConnectionIPType ip_type =
814 connection_->IsIPv6() ? Metrics::kNetworkConnectionIPTypeIPv6
815 : Metrics::kNetworkConnectionIPTypeIPv4;
816 metrics_->NotifyNetworkConnectionIPType(technology_, ip_type);
817
818 // Report if device have IPv6 connectivity
819 bool ipv6_connectivity = IPConfigCompleted(ip6config_);
820 metrics_->NotifyIPv6ConnectivityStatus(technology_, ipv6_connectivity);
821
Peter Qiub25083f2014-08-25 13:22:31 -0700822 // SetConnection must occur after the UpdateFromIPConfig so the
823 // service can use the values derived from the connection.
824 if (selected_service_) {
825 selected_service_->SetConnection(connection_);
826
827 // The service state change needs to happen last, so that at the
828 // time we report the state change to the manager, the service
829 // has its connection.
830 SetServiceState(Service::kStateConnected);
831 OnConnected();
832 portal_attempts_to_online_ = 0;
833
834 // Subtle: Start portal detection after transitioning the service
835 // to the Connected state because this call may immediately transition
836 // to the Online state.
837 StartPortalDetection();
838 }
839
Paul Stewart208a97e2015-05-13 09:11:12 -0700840 SetHostname(ipconfig->properties().accepted_hostname);
Peter Qiub25083f2014-08-25 13:22:31 -0700841 StartLinkMonitor();
842 StartTrafficMonitor();
843}
844
Paul Stewart208a97e2015-05-13 09:11:12 -0700845bool Device::SetHostname(const std::string &hostname) {
846 if (hostname.empty() || !manager()->ShouldAcceptHostnameFrom(link_name_)) {
847 return false;
848 }
849
850 string fixed_hostname = hostname;
851 if (fixed_hostname.length() > MAXHOSTNAMELEN) {
852 auto truncate_length = fixed_hostname.find('.');
853 if (truncate_length == string::npos || truncate_length > MAXHOSTNAMELEN) {
854 truncate_length = MAXHOSTNAMELEN;
855 }
856 fixed_hostname.resize(truncate_length);
857 }
858
859 return manager_->device_info()->SetHostname(fixed_hostname);
860}
861
Garret Kellyc5f89d12015-02-18 14:39:36 -0500862void Device::PrependDNSServersIntoIPConfig(const IPConfigRefPtr &ipconfig) {
863 const auto &properties = ipconfig->properties();
864
865 vector<string> servers(properties.dns_servers.begin(),
866 properties.dns_servers.end());
867 PrependDNSServers(properties.address_family, &servers);
868 if (servers == properties.dns_servers) {
869 // If the server list is the same after being augmented then there's no need
870 // to update the config's list of servers.
871 return;
872 }
873
874 ipconfig->UpdateDNSServers(servers);
875}
876
877void Device::PrependDNSServers(const IPAddress::Family family,
878 vector<string> *servers) {
879 vector<string> suffix(servers->begin(), servers->end());
880 manager_->FilterPrependDNSServersByFamily(family, servers);
881
882 set<string> unique(servers->begin(), servers->end());
883 for (const auto &server : suffix) {
884 if (unique.find(server) == unique.end()) {
885 servers->push_back(server);
886 unique.insert(server);
887 }
888 }
889}
890
Samuel Tan3c3c36a2014-12-16 16:53:19 -0800891void Device::OnIPConfigUpdated(const IPConfigRefPtr &ipconfig,
892 bool /*new_lease_acquired*/) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700893 SLOG(this, 2) << __func__;
Paul Stewartc5099532013-12-12 07:53:15 -0800894 if (selected_service_) {
895 ipconfig->ApplyStaticIPParameters(
896 selected_service_->mutable_static_ip_parameters());
Paul Stewart316acef2014-05-29 18:40:48 -0700897 if (IsUsingStaticIP()) {
Paul Stewartc5099532013-12-12 07:53:15 -0800898 // If we are using a statically configured IP address instead
899 // of a leased IP address, release any acquired lease so it may
900 // be used by others. This allows us to merge other non-leased
901 // parameters (like DNS) when they're available from a DHCP server
902 // and not overridden by static parameters, but at the same time
903 // we avoid taking up a dynamic IP address the DHCP server could
904 // assign to someone else who might actually use it.
905 ipconfig->ReleaseIP(IPConfig::kReleaseReasonStaticIP);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700906 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700907 }
Garret Kellyd01b5cc2015-03-12 16:20:55 -0400908 if (!IsUsingStaticNameServers()) {
909 PrependDNSServersIntoIPConfig(ipconfig);
910 }
Peter Qiub25083f2014-08-25 13:22:31 -0700911 SetupConnection(ipconfig);
Paul Stewartd4f26482014-04-25 19:12:03 -0700912 UpdateIPConfigsProperty();
Paul Stewartc5099532013-12-12 07:53:15 -0800913}
914
915void Device::OnIPConfigFailed(const IPConfigRefPtr &ipconfig) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700916 SLOG(this, 2) << __func__;
Paul Stewartc5099532013-12-12 07:53:15 -0800917 // TODO(pstew): This logic gets yet more complex when multiple
918 // IPConfig types are run in parallel (e.g. DHCP and DHCP6)
919 if (selected_service_) {
Paul Stewart316acef2014-05-29 18:40:48 -0700920 if (IsUsingStaticIP()) {
Paul Stewartc5099532013-12-12 07:53:15 -0800921 // Consider three cases:
922 //
923 // 1. We're here because DHCP failed while starting up. There
924 // are two subcases:
925 // a. DHCP has failed, and Static IP config has _not yet_
926 // completed. It's fine to do nothing, because we'll
927 // apply the static config shortly.
928 // b. DHCP has failed, and Static IP config has _already_
929 // completed. It's fine to do nothing, because we can
930 // continue to use the static config that's already
931 // been applied.
932 //
933 // 2. We're here because a previously valid DHCP configuration
934 // is no longer valid. There's still a static IP config,
935 // because the condition in the if clause evaluated to true.
936 // Furthermore, the static config includes an IP address for
937 // us to use.
938 //
939 // The current configuration may include some DHCP
940 // parameters, overriden by any static parameters
941 // provided. We continue to use this configuration, because
942 // the only configuration element that is leased to us (IP
943 // address) will be overriden by a static parameter.
944 return;
945 }
946 }
947
948 ipconfig->ResetProperties();
Paul Stewartd4f26482014-04-25 19:12:03 -0700949 UpdateIPConfigsProperty();
Peter Qiub25083f2014-08-25 13:22:31 -0700950
951 // Fallback to IPv6 if we have an IPv6 configuration that's ready for
952 // connection, and we're not currently using an IPv6 connection.
953 if (IPConfigCompleted(ip6config_) &&
954 (!connection_ || !connection_->IsIPv6())) {
955 SetupConnection(ip6config_);
956 return;
957 }
958
959 OnIPConfigFailure();
Paul Stewartc5099532013-12-12 07:53:15 -0800960 DestroyConnection();
Chris Masone8fe2c7e2011-06-09 15:51:19 -0700961}
962
Paul Stewart82236532013-12-10 15:33:11 -0800963void Device::OnIPConfigRefreshed(const IPConfigRefPtr &ipconfig) {
964 // Clear the previously applied static IP parameters.
965 ipconfig->RestoreSavedIPParameters(
966 selected_service_->mutable_static_ip_parameters());
967
968 dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
969 weak_ptr_factory_.GetWeakPtr()));
970}
971
Paul Stewartf6f96482013-07-12 12:49:15 -0700972void Device::OnIPConfigFailure() {
973 if (selected_service_) {
974 Error error;
Samuel Tan0d061192014-07-07 15:45:15 -0700975 selected_service_->DisconnectWithFailure(Service::kFailureDHCP,
976 &error,
977 __func__);
Paul Stewartf6f96482013-07-12 12:49:15 -0700978 }
979}
980
Paul Stewart1f916e42013-12-23 09:52:54 -0800981void Device::OnIPConfigExpired(const IPConfigRefPtr &ipconfig) {
982 metrics()->SendToUMA(
983 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -0700984 Metrics::kMetricExpiredLeaseLengthSecondsSuffix, technology()),
Paul Stewart1f916e42013-12-23 09:52:54 -0800985 ipconfig->properties().lease_duration_seconds,
986 Metrics::kMetricExpiredLeaseLengthSecondsMin,
987 Metrics::kMetricExpiredLeaseLengthSecondsMax,
988 Metrics::kMetricExpiredLeaseLengthSecondsNumBuckets);
989}
990
Peter Qiua388fdb2015-04-03 10:31:22 -0700991void Device::OnConnected() {
992 if (selected_service_->unreliable()) {
993 // Post a delayed task to reset link back to reliable if no link
994 // failure is detected in the next 5 minutes.
995 reliable_link_callback_.Reset(
996 base::Bind(&Device::OnReliableLink, base::Unretained(this)));
997 dispatcher_->PostDelayedTask(
998 reliable_link_callback_.callback(),
999 kLinkUnreliableThresholdSeconds * 1000);
1000 }
1001}
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001002
Paul Stewart8596f9f2013-03-14 07:58:26 -07001003void Device::OnConnectionUpdated() {
1004 if (selected_service_) {
1005 manager_->UpdateService(selected_service_);
1006 }
1007}
1008
Paul Stewarte6132022011-08-16 09:11:02 -07001009void Device::CreateConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001010 SLOG(this, 2) << __func__;
Paul Stewarte6132022011-08-16 09:11:02 -07001011 if (!connection_.get()) {
mukesh agrawal23ac6b72013-01-31 18:52:37 -08001012 connection_ = new Connection(interface_index_,
1013 link_name_,
1014 technology_,
1015 manager_->device_info());
Paul Stewarte6132022011-08-16 09:11:02 -07001016 }
1017}
1018
1019void Device::DestroyConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001020 SLOG(this, 2) << __func__ << " on " << link_name_;
Peter Qiu25f1be62014-08-12 10:42:27 -07001021 StopAllActivities();
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001022 if (selected_service_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001023 SLOG(this, 3) << "Clearing connection of service "
1024 << selected_service_->unique_name();
Ben Chancc225ef2014-09-30 13:26:51 -07001025 selected_service_->SetConnection(nullptr);
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001026 }
Ben Chancc225ef2014-09-30 13:26:51 -07001027 connection_ = nullptr;
Paul Stewarte6132022011-08-16 09:11:02 -07001028}
1029
Paul Stewart03dba0b2011-08-22 16:32:45 -07001030void Device::SelectService(const ServiceRefPtr &service) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001031 SLOG(this, 2) << __func__ << ": service "
1032 << (service ? service->unique_name() : "*reset*")
1033 << " on " << link_name_;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001034
1035 if (selected_service_.get() == service.get()) {
1036 // No change to |selected_service_|. Return early to avoid
1037 // changing its state.
1038 return;
1039 }
1040
Paul Stewartbe5f5b32011-12-07 17:11:11 -08001041 if (selected_service_.get()) {
1042 if (selected_service_->state() != Service::kStateFailure) {
1043 selected_service_->SetState(Service::kStateIdle);
1044 }
Paul Stewart20b0a092012-05-22 20:39:57 -07001045 // Just in case the Device subclass has not already done so, make
1046 // sure the previously selected service has its connection removed.
Ben Chancc225ef2014-09-30 13:26:51 -07001047 selected_service_->SetConnection(nullptr);
Peter Qiua388fdb2015-04-03 10:31:22 -07001048 // Reset link status for the previously selected service.
1049 selected_service_->set_unreliable(false);
1050 reliable_link_callback_.Cancel();
Peter Qiu25f1be62014-08-12 10:42:27 -07001051 StopAllActivities();
Paul Stewart03dba0b2011-08-22 16:32:45 -07001052 }
Peter Qiua0572032014-09-26 10:07:37 -07001053
1054 // Newly selected service (network), previous failures doesn't apply
1055 // anymore.
1056 last_link_monitor_failed_time_ = 0;
1057
Paul Stewart03dba0b2011-08-22 16:32:45 -07001058 selected_service_ = service;
Christopher Wiley674598d2014-12-12 10:21:39 -08001059 adaptor_->EmitRpcIdentifierChanged(
1060 kSelectedServiceProperty, GetSelectedServiceRpcIdentifier(nullptr));
Paul Stewart03dba0b2011-08-22 16:32:45 -07001061}
1062
1063void Device::SetServiceState(Service::ConnectState state) {
1064 if (selected_service_.get()) {
1065 selected_service_->SetState(state);
1066 }
1067}
1068
1069void Device::SetServiceFailure(Service::ConnectFailure failure_state) {
1070 if (selected_service_.get()) {
1071 selected_service_->SetFailure(failure_state);
1072 }
1073}
1074
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -04001075void Device::SetServiceFailureSilent(Service::ConnectFailure failure_state) {
1076 if (selected_service_.get()) {
1077 selected_service_->SetFailureSilent(failure_state);
1078 }
1079}
1080
Paul Stewart2bf1d352011-12-06 15:02:55 -08001081bool Device::SetIPFlag(IPAddress::Family family, const string &flag,
1082 const string &value) {
1083 string ip_version;
1084 if (family == IPAddress::kFamilyIPv4) {
1085 ip_version = kIPFlagVersion4;
1086 } else if (family == IPAddress::kFamilyIPv6) {
1087 ip_version = kIPFlagVersion6;
1088 } else {
1089 NOTIMPLEMENTED();
1090 }
1091 FilePath flag_file(StringPrintf(kIPFlagTemplate, ip_version.c_str(),
1092 link_name_.c_str(), flag.c_str()));
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001093 SLOG(this, 2) << "Writing " << value << " to flag file "
1094 << flag_file.value();
Ben Chan6fbf64f2014-05-21 18:07:01 -07001095 if (base::WriteFile(flag_file, value.c_str(), value.length()) != 1) {
Paul Stewart2bf1d352011-12-06 15:02:55 -08001096 LOG(ERROR) << StringPrintf("IP flag write failed: %s to %s",
1097 value.c_str(), flag_file.value().c_str());
1098 return false;
1099 }
1100 return true;
1101}
1102
Paul Stewartc6fbad92013-11-13 14:50:52 -08001103string Device::PerformTDLSOperation(const string &/* operation */,
1104 const string &/* peer */,
1105 Error */* error */) {
1106 return "";
1107}
1108
Paul Stewart6ff27f52012-07-11 06:51:41 -07001109void Device::ResetByteCounters() {
1110 manager_->device_info()->GetByteCounts(
1111 interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
1112 manager_->UpdateDevice(this);
1113}
1114
Paul Stewartd215af62012-04-24 23:25:50 -07001115bool Device::RestartPortalDetection() {
1116 StopPortalDetection();
1117 return StartPortalDetection();
1118}
1119
Paul Stewartc681fa02012-03-02 19:40:04 -08001120bool Device::RequestPortalDetection() {
1121 if (!selected_service_) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001122 SLOG(this, 2) << FriendlyName()
1123 << ": No selected service, so no need for portal check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001124 return false;
1125 }
1126
1127 if (!connection_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001128 SLOG(this, 2) << FriendlyName()
1129 << ": No connection, so no need for portal check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001130 return false;
1131 }
1132
1133 if (selected_service_->state() != Service::kStatePortal) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001134 SLOG(this, 2) << FriendlyName()
1135 << ": Service is not in portal state. "
1136 << "No need to start check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001137 return false;
1138 }
1139
1140 if (!connection_->is_default()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001141 SLOG(this, 2) << FriendlyName()
1142 << ": Service is not the default connection. "
1143 << "Don't start check.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001144 return false;
1145 }
1146
1147 if (portal_detector_.get() && portal_detector_->IsInProgress()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001148 SLOG(this, 2) << FriendlyName()
1149 << ": Portal detection is already running.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001150 return true;
1151 }
1152
1153 return StartPortalDetection();
1154}
1155
Paul Stewart20088d82012-02-16 06:58:55 -08001156bool Device::StartPortalDetection() {
Darin Petkov457728b2013-01-09 09:49:08 +01001157 DCHECK(selected_service_);
Paul Stewartd215af62012-04-24 23:25:50 -07001158 if (selected_service_->IsPortalDetectionDisabled()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001159 SLOG(this, 2) << "Service " << selected_service_->unique_name()
1160 << ": Portal detection is disabled; "
1161 << "marking service online.";
Paul Stewartd215af62012-04-24 23:25:50 -07001162 SetServiceConnectedState(Service::kStateOnline);
1163 return false;
1164 }
1165
1166 if (selected_service_->IsPortalDetectionAuto() &&
1167 !manager_->IsPortalDetectionEnabled(technology())) {
Paul Stewart20088d82012-02-16 06:58:55 -08001168 // If portal detection is disabled for this technology, immediately set
1169 // the service state to "Online".
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001170 SLOG(this, 2) << "Device " << FriendlyName()
1171 << ": Portal detection is disabled; "
1172 << "marking service online.";
Paul Stewart20088d82012-02-16 06:58:55 -08001173 SetServiceConnectedState(Service::kStateOnline);
1174 return false;
1175 }
1176
Paul Stewart20088d82012-02-16 06:58:55 -08001177 if (selected_service_->HasProxyConfig()) {
1178 // Services with HTTP proxy configurations should not be checked by the
1179 // connection manager, since we don't have the ability to evaluate
1180 // arbitrary proxy configs and their possible credentials.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001181 SLOG(this, 2) << "Device " << FriendlyName()
1182 << ": Service has proxy config; marking it online.";
Paul Stewart20088d82012-02-16 06:58:55 -08001183 SetServiceConnectedState(Service::kStateOnline);
1184 return false;
1185 }
1186
1187 portal_detector_.reset(new PortalDetector(connection_,
1188 dispatcher_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -05001189 portal_detector_callback_));
Paul Stewart20088d82012-02-16 06:58:55 -08001190 if (!portal_detector_->Start(manager_->GetPortalCheckURL())) {
1191 LOG(ERROR) << "Device " << FriendlyName()
1192 << ": Portal detection failed to start: likely bad URL: "
1193 << manager_->GetPortalCheckURL();
1194 SetServiceConnectedState(Service::kStateOnline);
1195 return false;
1196 }
1197
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001198 SLOG(this, 2) << "Device " << FriendlyName()
1199 << ": Portal detection has started.";
Paul Stewart20088d82012-02-16 06:58:55 -08001200 return true;
1201}
1202
1203void Device::StopPortalDetection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001204 SLOG(this, 2) << "Device " << FriendlyName()
1205 << ": Portal detection stopping.";
Paul Stewart20088d82012-02-16 06:58:55 -08001206 portal_detector_.reset();
1207}
1208
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001209bool Device::StartConnectivityTest() {
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -07001210 LOG(INFO) << "Device " << FriendlyName() << " starting connectivity test.";
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001211
Rebecca Silbersteinf4365a62014-09-16 11:40:32 -07001212 connection_tester_.reset(new ConnectionTester(connection_,
1213 dispatcher_,
1214 connection_tester_callback_));
1215 connection_tester_->Start();
1216 return true;
Rebecca Silberstein6862b382014-09-11 08:24:51 -07001217}
1218
Paul Stewarte8303eb2014-10-08 22:51:14 -07001219void Device::StopConnectivityTest() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001220 SLOG(this, 2) << "Device " << FriendlyName()
1221 << ": Connectivity test stopping.";
Paul Stewarte8303eb2014-10-08 22:51:14 -07001222 connection_tester_.reset();
1223}
1224
Paul Stewart036dba02012-08-07 12:34:41 -07001225void Device::set_link_monitor(LinkMonitor *link_monitor) {
1226 link_monitor_.reset(link_monitor);
1227}
1228
1229bool Device::StartLinkMonitor() {
1230 if (!manager_->IsTechnologyLinkMonitorEnabled(technology())) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001231 SLOG(this, 2) << "Device " << FriendlyName()
1232 << ": Link Monitoring is disabled.";
Paul Stewart036dba02012-08-07 12:34:41 -07001233 return false;
1234 }
1235
Peter Qiud49760e2014-09-19 16:13:42 -07001236 if (selected_service_ && selected_service_->link_monitor_disabled()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001237 SLOG(this, 2) << "Device " << FriendlyName()
1238 << ": Link Monitoring is disabled for the selected service";
Peter Qiud49760e2014-09-19 16:13:42 -07001239 return false;
1240 }
1241
Paul Stewart036dba02012-08-07 12:34:41 -07001242 if (!link_monitor()) {
1243 set_link_monitor(
1244 new LinkMonitor(
1245 connection_, dispatcher_, metrics(), manager_->device_info(),
Peter Qiub5d124f2014-04-14 12:05:02 -07001246 Bind(&Device::OnLinkMonitorFailure, weak_ptr_factory_.GetWeakPtr()),
1247 Bind(&Device::OnLinkMonitorGatewayChange,
1248 weak_ptr_factory_.GetWeakPtr())));
Paul Stewart036dba02012-08-07 12:34:41 -07001249 }
1250
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001251 SLOG(this, 2) << "Device " << FriendlyName()
1252 << ": Link Monitor starting.";
Paul Stewart036dba02012-08-07 12:34:41 -07001253 return link_monitor_->Start();
1254}
1255
1256void Device::StopLinkMonitor() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001257 SLOG(this, 2) << "Device " << FriendlyName()
1258 << ": Link Monitor stopping.";
Paul Stewart036dba02012-08-07 12:34:41 -07001259 link_monitor_.reset();
1260}
1261
Peter Qiu8e1ad162014-10-02 15:58:24 -07001262void Device::OnUnreliableLink() {
Peter Qiua388fdb2015-04-03 10:31:22 -07001263 SLOG(this, 2) << "Device " << FriendlyName()
1264 << ": Link is unreliable.";
1265 selected_service_->set_unreliable(true);
1266 reliable_link_callback_.Cancel();
Peter Qiu8e1ad162014-10-02 15:58:24 -07001267 metrics_->NotifyUnreliableLinkSignalStrength(
1268 technology_, selected_service_->strength());
1269}
1270
Peter Qiua388fdb2015-04-03 10:31:22 -07001271void Device::OnReliableLink() {
1272 SLOG(this, 2) << "Device " << FriendlyName()
1273 << ": Link is reliable.";
1274 selected_service_->set_unreliable(false);
1275 // TODO(zqiu): report signal strength to UMA.
1276}
1277
Paul Stewart036dba02012-08-07 12:34:41 -07001278void Device::OnLinkMonitorFailure() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001279 SLOG(this, 2) << "Device " << FriendlyName()
1280 << ": Link Monitor indicates failure.";
Peter Qiua0572032014-09-26 10:07:37 -07001281 if (!selected_service_) {
1282 return;
1283 }
1284
1285 time_t now;
1286 time_->GetSecondsBoottime(&now);
1287
Peter Qiua388fdb2015-04-03 10:31:22 -07001288 if (last_link_monitor_failed_time_ != 0 &&
1289 now - last_link_monitor_failed_time_ < kLinkUnreliableThresholdSeconds) {
Peter Qiu8e1ad162014-10-02 15:58:24 -07001290 OnUnreliableLink();
Peter Qiua0572032014-09-26 10:07:37 -07001291 }
1292 last_link_monitor_failed_time_ = now;
Paul Stewart036dba02012-08-07 12:34:41 -07001293}
1294
Peter Qiu9d581932014-04-14 16:37:37 -07001295void Device::OnLinkMonitorGatewayChange() {
1296 string gateway_mac = link_monitor()->gateway_mac_address().HexEncode();
1297 int connection_id = manager_->CalcConnectionId(
1298 ipconfig_->properties().gateway, gateway_mac);
1299
1300 CHECK(selected_service_);
1301 selected_service_->set_connection_id(connection_id);
1302
1303 manager_->ReportServicesOnSameNetwork(connection_id);
1304}
1305
Peter Qiu6f5618b2014-06-05 15:19:01 -07001306bool Device::StartDNSTest(
1307 const vector<string> &dns_servers,
1308 bool retry_until_success,
1309 const Callback<void(const DNSServerTester::Status)> &callback) {
1310 if (dns_server_tester_.get()) {
1311 LOG(ERROR) << FriendlyName() << ": "
1312 << "Failed to start DNS Test: current test still running";
1313 return false;
Peter Qiub9256f32014-05-09 15:27:29 -07001314 }
1315
Peter Qiu6f5618b2014-06-05 15:19:01 -07001316 dns_server_tester_.reset(new DNSServerTester(connection_,
1317 dispatcher_,
1318 dns_servers,
1319 retry_until_success,
1320 callback));
1321 dns_server_tester_->Start();
1322 return true;
1323}
1324
1325void Device::StopDNSTest() {
1326 dns_server_tester_.reset();
Peter Qiub9256f32014-05-09 15:27:29 -07001327}
1328
Peter Qiud670d032014-06-03 15:04:43 -07001329void Device::FallbackDNSResultCallback(const DNSServerTester::Status status) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001330 StopDNSTest();
Peter Qiuf18e7712014-05-20 09:59:46 -07001331 int result = Metrics::kFallbackDNSTestResultFailure;
Peter Qiud670d032014-06-03 15:04:43 -07001332 if (status == DNSServerTester::kStatusSuccess) {
Peter Qiuf18e7712014-05-20 09:59:46 -07001333 result = Metrics::kFallbackDNSTestResultSuccess;
Peter Qiua89154b2014-05-23 15:45:42 -07001334
1335 // Switch to fallback DNS server if service is configured to allow DNS
1336 // fallback.
1337 CHECK(selected_service_);
1338 if (selected_service_->is_dns_auto_fallback_allowed()) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001339 LOG(INFO) << "Device " << FriendlyName()
1340 << ": Switching to fallback DNS servers.";
1341 // Save the DNS servers from ipconfig.
1342 config_dns_servers_ = ipconfig_->properties().dns_servers;
Peter Qiua89154b2014-05-23 15:45:42 -07001343 SwitchDNSServers(vector<string>(std::begin(kFallbackDnsServers),
1344 std::end(kFallbackDnsServers)));
Peter Qiu6f5618b2014-06-05 15:19:01 -07001345 // Start DNS test for configured DNS servers.
1346 StartDNSTest(config_dns_servers_,
1347 true,
1348 Bind(&Device::ConfigDNSResultCallback,
1349 weak_ptr_factory_.GetWeakPtr()));
Peter Qiua89154b2014-05-23 15:45:42 -07001350 }
Peter Qiub9256f32014-05-09 15:27:29 -07001351 }
Peter Qiuf18e7712014-05-20 09:59:46 -07001352 metrics()->NotifyFallbackDNSTestResult(technology_, result);
Peter Qiu6f5618b2014-06-05 15:19:01 -07001353}
1354
1355void Device::ConfigDNSResultCallback(const DNSServerTester::Status status) {
1356 StopDNSTest();
1357 // DNS test failed to start due to internal error.
1358 if (status == DNSServerTester::kStatusFailure) {
1359 return;
1360 }
1361
1362 // Switch back to the configured DNS servers.
1363 LOG(INFO) << "Device " << FriendlyName()
1364 << ": Switching back to configured DNS servers.";
1365 SwitchDNSServers(config_dns_servers_);
Peter Qiub9256f32014-05-09 15:27:29 -07001366}
1367
Peter Qiua89154b2014-05-23 15:45:42 -07001368void Device::SwitchDNSServers(const vector<string> &dns_servers) {
1369 CHECK(ipconfig_);
1370 CHECK(connection_);
1371 // Push new DNS servers setting to the IP config object.
1372 ipconfig_->UpdateDNSServers(dns_servers);
1373 // Push new DNS servers setting to the current connection, so the resolver
1374 // will be updated to use the new DNS servers.
1375 connection_->UpdateDNSServers(dns_servers);
1376 // Allow the service to notify Chrome of ipconfig changes.
1377 selected_service_->NotifyIPConfigChanges();
Peter Qiu6f5618b2014-06-05 15:19:01 -07001378 // Restart the portal detection with the new DNS setting.
1379 RestartPortalDetection();
Peter Qiua89154b2014-05-23 15:45:42 -07001380}
1381
Peter Qiudc335f82014-05-15 10:33:17 -07001382void Device::set_traffic_monitor(TrafficMonitor *traffic_monitor) {
1383 traffic_monitor_.reset(traffic_monitor);
1384}
1385
Samuel Tan787a1ce2014-11-11 17:17:27 -08001386bool Device::TimeToNextDHCPLeaseRenewal(uint32_t *result) {
1387 if (!ipconfig() && !ip6config()) {
1388 return false;
1389 }
1390 uint32_t time_to_ipv4_lease_expiry = UINT32_MAX;
1391 uint32_t time_to_ipv6_lease_expiry = UINT32_MAX;
1392 if (ipconfig()) {
1393 ipconfig()->TimeToLeaseExpiry(&time_to_ipv4_lease_expiry);
1394 }
1395 if (ip6config()) {
1396 ip6config()->TimeToLeaseExpiry(&time_to_ipv6_lease_expiry);
1397 }
1398 *result = std::min(time_to_ipv4_lease_expiry, time_to_ipv6_lease_expiry);
1399 return true;
1400}
1401
Peter Qiudc335f82014-05-15 10:33:17 -07001402bool Device::IsTrafficMonitorEnabled() const {
1403 return false;
1404}
1405
1406void Device::StartTrafficMonitor() {
1407 // Return if traffic monitor is not enabled for this device.
1408 if (!IsTrafficMonitorEnabled()) {
1409 return;
1410 }
1411
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001412 SLOG(this, 2) << "Device " << FriendlyName()
1413 << ": Traffic Monitor starting.";
Peter Qiudc335f82014-05-15 10:33:17 -07001414 if (!traffic_monitor_.get()) {
1415 traffic_monitor_.reset(new TrafficMonitor(this, dispatcher_));
1416 traffic_monitor_->set_network_problem_detected_callback(
1417 Bind(&Device::OnEncounterNetworkProblem,
1418 weak_ptr_factory_.GetWeakPtr()));
1419 }
1420 traffic_monitor_->Start();
1421}
1422
1423void Device::StopTrafficMonitor() {
1424 // Return if traffic monitor is not enabled for this device.
1425 if (!IsTrafficMonitorEnabled()) {
1426 return;
1427 }
1428
1429 if (traffic_monitor_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001430 SLOG(this, 2) << "Device " << FriendlyName()
1431 << ": Traffic Monitor stopping.";
Peter Qiudc335f82014-05-15 10:33:17 -07001432 traffic_monitor_->Stop();
1433 }
1434 traffic_monitor_.reset();
1435}
1436
1437void Device::OnEncounterNetworkProblem(int reason) {
1438 int metric_code;
1439 switch (reason) {
1440 case TrafficMonitor::kNetworkProblemCongestedTxQueue:
1441 metric_code = Metrics::kNetworkProblemCongestedTCPTxQueue;
1442 break;
1443 case TrafficMonitor::kNetworkProblemDNSFailure:
1444 metric_code = Metrics::kNetworkProblemDNSFailure;
1445 break;
1446 default:
1447 LOG(ERROR) << "Invalid network problem code: " << reason;
1448 return;
1449 }
1450
1451 metrics()->NotifyNetworkProblemDetected(technology_, metric_code);
1452 // Stop the traffic monitor, only report the first network problem detected
1453 // on the connection for now.
1454 StopTrafficMonitor();
1455}
1456
Paul Stewart20088d82012-02-16 06:58:55 -08001457void Device::SetServiceConnectedState(Service::ConnectState state) {
1458 DCHECK(selected_service_.get());
1459
1460 if (!selected_service_.get()) {
1461 LOG(ERROR) << FriendlyName() << ": "
1462 << "Portal detection completed but no selected service exists!";
1463 return;
1464 }
1465
1466 if (!selected_service_->IsConnected()) {
1467 LOG(ERROR) << FriendlyName() << ": "
1468 << "Portal detection completed but selected service "
Darin Petkov457728b2013-01-09 09:49:08 +01001469 << selected_service_->unique_name()
Paul Stewart20088d82012-02-16 06:58:55 -08001470 << " is in non-connected state.";
1471 return;
1472 }
1473
Paul Stewartc681fa02012-03-02 19:40:04 -08001474 if (state == Service::kStatePortal && connection_->is_default() &&
1475 manager_->GetPortalCheckInterval() != 0) {
1476 CHECK(portal_detector_.get());
1477 if (!portal_detector_->StartAfterDelay(
1478 manager_->GetPortalCheckURL(),
1479 manager_->GetPortalCheckInterval())) {
1480 LOG(ERROR) << "Device " << FriendlyName()
1481 << ": Portal detection failed to restart: likely bad URL: "
1482 << manager_->GetPortalCheckURL();
1483 SetServiceState(Service::kStateOnline);
1484 portal_detector_.reset();
1485 return;
1486 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001487 SLOG(this, 2) << "Device " << FriendlyName()
1488 << ": Portal detection retrying.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001489 } else {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001490 SLOG(this, 2) << "Device " << FriendlyName()
1491 << ": Portal will not retry.";
Paul Stewartc681fa02012-03-02 19:40:04 -08001492 portal_detector_.reset();
1493 }
1494
Paul Stewart20088d82012-02-16 06:58:55 -08001495 SetServiceState(state);
1496}
1497
1498void Device::PortalDetectorCallback(const PortalDetector::Result &result) {
1499 if (!result.final) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001500 SLOG(this, 2) << "Device " << FriendlyName()
1501 << ": Received non-final status: "
1502 << ConnectivityTrial::StatusToString(
1503 result.trial_result.status);
Paul Stewart20088d82012-02-16 06:58:55 -08001504 return;
1505 }
1506
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001507 SLOG(this, 2) << "Device " << FriendlyName()
1508 << ": Received final status: "
1509 << ConnectivityTrial::StatusToString(
1510 result.trial_result.status);
Paul Stewart20088d82012-02-16 06:58:55 -08001511
Thieu Le85e050b2012-03-13 15:04:38 -07001512 portal_attempts_to_online_ += result.num_attempts;
1513
Peter Qiub9256f32014-05-09 15:27:29 -07001514 int portal_status = Metrics::PortalDetectionResultToEnum(result);
Thieu Le85e050b2012-03-13 15:04:38 -07001515 metrics()->SendEnumToUMA(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001516 metrics()->GetFullMetricName(Metrics::kMetricPortalResultSuffix,
1517 technology()),
Peter Qiub9256f32014-05-09 15:27:29 -07001518 portal_status,
Thieu Le85e050b2012-03-13 15:04:38 -07001519 Metrics::kPortalResultMax);
1520
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -07001521 if (result.trial_result.status == ConnectivityTrial::kStatusSuccess) {
Paul Stewart20088d82012-02-16 06:58:55 -08001522 SetServiceConnectedState(Service::kStateOnline);
Thieu Le85e050b2012-03-13 15:04:38 -07001523
1524 metrics()->SendToUMA(
1525 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001526 Metrics::kMetricPortalAttemptsToOnlineSuffix, technology()),
Thieu Le85e050b2012-03-13 15:04:38 -07001527 portal_attempts_to_online_,
1528 Metrics::kMetricPortalAttemptsToOnlineMin,
1529 Metrics::kMetricPortalAttemptsToOnlineMax,
1530 Metrics::kMetricPortalAttemptsToOnlineNumBuckets);
Paul Stewart20088d82012-02-16 06:58:55 -08001531 } else {
Peter Qiu9b83c892014-08-09 23:06:02 -07001532 // Set failure phase and status.
1533 if (selected_service_.get()) {
1534 selected_service_->SetPortalDetectionFailure(
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -07001535 ConnectivityTrial::PhaseToString(result.trial_result.phase),
1536 ConnectivityTrial::StatusToString(result.trial_result.status));
Peter Qiu9b83c892014-08-09 23:06:02 -07001537 }
Paul Stewart20088d82012-02-16 06:58:55 -08001538 SetServiceConnectedState(Service::kStatePortal);
Thieu Le85e050b2012-03-13 15:04:38 -07001539
1540 metrics()->SendToUMA(
1541 metrics()->GetFullMetricName(
mukesh agrawal132e96f2014-04-24 11:49:42 -07001542 Metrics::kMetricPortalAttemptsSuffix, technology()),
Thieu Le85e050b2012-03-13 15:04:38 -07001543 result.num_attempts,
1544 Metrics::kMetricPortalAttemptsMin,
1545 Metrics::kMetricPortalAttemptsMax,
1546 Metrics::kMetricPortalAttemptsNumBuckets);
Peter Qiub9256f32014-05-09 15:27:29 -07001547
Peter Qiub25083f2014-08-25 13:22:31 -07001548 // TODO(zqiu): Only support fallback DNS server for IPv4 for now.
1549 if (connection_->IsIPv6()) {
1550 return;
1551 }
1552
Peter Qiub9256f32014-05-09 15:27:29 -07001553 // Perform fallback DNS test if the portal failure is DNS related.
1554 // The test will send a DNS request to Google's DNS server to determine
1555 // if the DNS failure is due to bad DNS server settings.
1556 if ((portal_status == Metrics::kPortalResultDNSFailure) ||
1557 (portal_status == Metrics::kPortalResultDNSTimeout)) {
Peter Qiu6f5618b2014-06-05 15:19:01 -07001558 StartDNSTest(vector<string>(std::begin(kFallbackDnsServers),
1559 std::end(kFallbackDnsServers)),
1560 false,
1561 Bind(&Device::FallbackDNSResultCallback,
1562 weak_ptr_factory_.GetWeakPtr()));
Peter Qiub9256f32014-05-09 15:27:29 -07001563 }
Paul Stewart20088d82012-02-16 06:58:55 -08001564 }
1565}
1566
Christopher Wiley674598d2014-12-12 10:21:39 -08001567string Device::GetSelectedServiceRpcIdentifier(Error */*error*/) {
1568 if (!selected_service_) {
1569 return "/";
1570 }
1571 return selected_service_->GetRpcIdentifier();
1572}
1573
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001574vector<string> Device::AvailableIPConfigs(Error */*error*/) {
Paul Stewartd4f26482014-04-25 19:12:03 -07001575 vector<string> ipconfigs;
1576 if (ipconfig_) {
1577 ipconfigs.push_back(ipconfig_->GetRpcIdentifier());
Jason Glasgow08afdff2012-04-03 10:22:26 -04001578 }
Paul Stewartd4f26482014-04-25 19:12:03 -07001579 if (ip6config_) {
1580 ipconfigs.push_back(ip6config_->GetRpcIdentifier());
1581 }
1582 return ipconfigs;
Chris Masone4e851612011-07-01 10:46:53 -07001583}
1584
1585string Device::GetRpcConnectionIdentifier() {
1586 return adaptor_->GetRpcConnectionIdentifier();
1587}
1588
Ben Chan7fab8972014-08-10 17:14:46 -07001589uint64_t Device::GetLinkMonitorResponseTime(Error *error) {
Paul Stewart036dba02012-08-07 12:34:41 -07001590 if (!link_monitor_.get()) {
1591 // It is not strictly an error that the link monitor does not
1592 // exist, but returning an error here allows the GetProperties
1593 // call in our Adaptor to omit this parameter.
1594 error->Populate(Error::kNotFound, "Device is not running LinkMonitor");
1595 return 0;
1596 }
1597 return link_monitor_->GetResponseTimeMilliseconds();
1598}
1599
Ben Chan7fab8972014-08-10 17:14:46 -07001600uint64_t Device::GetReceiveByteCount() {
1601 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -07001602 manager_->device_info()->GetByteCounts(
1603 interface_index_, &rx_byte_count, &tx_byte_count);
1604 return rx_byte_count - receive_byte_offset_;
1605}
1606
Ben Chan7fab8972014-08-10 17:14:46 -07001607uint64_t Device::GetTransmitByteCount() {
1608 uint64_t rx_byte_count = 0, tx_byte_count = 0;
Paul Stewart6ff27f52012-07-11 06:51:41 -07001609 manager_->device_info()->GetByteCounts(
1610 interface_index_, &rx_byte_count, &tx_byte_count);
1611 return tx_byte_count - transmit_byte_offset_;
1612}
1613
Ben Chan7fab8972014-08-10 17:14:46 -07001614uint64_t Device::GetReceiveByteCountProperty(Error */*error*/) {
Ben Chanb061f892013-02-27 17:46:55 -08001615 return GetReceiveByteCount();
1616}
1617
Ben Chan7fab8972014-08-10 17:14:46 -07001618uint64_t Device::GetTransmitByteCountProperty(Error */*error*/) {
Ben Chanb061f892013-02-27 17:46:55 -08001619 return GetTransmitByteCount();
1620}
1621
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001622bool Device::IsUnderlyingDeviceEnabled() const {
1623 return false;
1624}
1625
Eric Shienbrood9a245532012-03-07 14:20:39 -05001626// callback
1627void Device::OnEnabledStateChanged(const ResultCallback &callback,
1628 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001629 SLOG(this, 2) << __func__
1630 << " (target: " << enabled_pending_ << ","
1631 << " success: " << error.IsSuccess() << ")"
1632 << " on " << link_name_;
Eric Shienbrood9a245532012-03-07 14:20:39 -05001633 if (error.IsSuccess()) {
1634 enabled_ = enabled_pending_;
1635 manager_->UpdateEnabledTechnologies();
Ben Chan923a5022013-09-20 11:23:23 -07001636 adaptor_->EmitBoolChanged(kPoweredProperty, enabled_);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001637 }
Gary Morainbaeefdf2012-04-30 14:53:35 -07001638 enabled_pending_ = enabled_;
Eric Shienbrood9a245532012-03-07 14:20:39 -05001639 if (!callback.is_null())
1640 callback.Run(error);
1641}
1642
1643void Device::SetEnabled(bool enable) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001644 SLOG(this, 2) << __func__ << "(" << enable << ")";
Jason Glasgow4a490792012-04-10 15:02:05 -04001645 Error error;
mukesh agrawal28185512013-10-18 16:57:09 -07001646 SetEnabledChecked(enable, false, &error, ResultCallback());
Arman Uguray8bf6a5c2013-08-12 14:18:03 -07001647
1648 // SetEnabledInternal might fail here if there is an unfinished enable or
1649 // disable operation. Don't log error in this case, as this method is only
1650 // called when the underlying device is already in the target state and the
1651 // pending operation should eventually bring the device to the expected
1652 // state.
1653 LOG_IF(ERROR,
1654 error.IsFailure() &&
1655 !error.IsOngoing() &&
1656 error.type() != Error::kInProgress)
Jason Glasgow4a490792012-04-10 15:02:05 -04001657 << "Enabled failed, but no way to report the failure.";
Eric Shienbrood9a245532012-03-07 14:20:39 -05001658}
1659
Ben Chan9f3dcf82013-09-25 18:04:58 -07001660void Device::SetEnabledNonPersistent(bool enable,
1661 Error *error,
1662 const ResultCallback &callback) {
mukesh agrawal28185512013-10-18 16:57:09 -07001663 SetEnabledChecked(enable, false, error, callback);
Ben Chan9f3dcf82013-09-25 18:04:58 -07001664}
1665
Eric Shienbrood9a245532012-03-07 14:20:39 -05001666void Device::SetEnabledPersistent(bool enable,
1667 Error *error,
1668 const ResultCallback &callback) {
mukesh agrawal28185512013-10-18 16:57:09 -07001669 SetEnabledChecked(enable, true, error, callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001670}
1671
mukesh agrawal28185512013-10-18 16:57:09 -07001672void Device::SetEnabledChecked(bool enable,
1673 bool persist,
1674 Error *error,
1675 const ResultCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -04001676 DCHECK(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001677 SLOG(this, 2) << "Device " << link_name_ << " "
1678 << (enable ? "starting" : "stopping");
Paul Stewartff6be292014-11-24 17:05:03 -08001679 if (enable && manager_->IsTechnologyProhibited(technology())) {
1680 error->Populate(Error::kPermissionDenied, "The " +
1681 Technology::NameFromIdentifier(technology()) +
1682 " technology is prohibited");
1683 return;
1684 }
1685
Eric Shienbrood9a245532012-03-07 14:20:39 -05001686 if (enable == enabled_) {
Arman Uguray2f352e62013-08-28 19:12:53 -07001687 if (enable != enabled_pending_ && persist) {
1688 // Return an error, as there is an ongoing operation to achieve the
1689 // opposite.
1690 Error::PopulateAndLog(
Paul Stewart34f424e2015-01-16 15:30:20 -08001691 FROM_HERE, error, Error::kOperationFailed,
Arman Uguray2f352e62013-08-28 19:12:53 -07001692 enable ? "Cannot enable while the device is disabling." :
1693 "Cannot disable while the device is enabling.");
1694 return;
1695 }
mukesh agrawal28185512013-10-18 16:57:09 -07001696 LOG(INFO) << "Already in desired enable state.";
Jason Glasgow4a490792012-04-10 15:02:05 -04001697 error->Reset();
Eric Shienbrood9a245532012-03-07 14:20:39 -05001698 return;
1699 }
1700
1701 if (enabled_pending_ == enable) {
Paul Stewart34f424e2015-01-16 15:30:20 -08001702 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
Jason Glasgow4a490792012-04-10 15:02:05 -04001703 "Enable operation already in progress");
Eric Shienbrood9a245532012-03-07 14:20:39 -05001704 return;
1705 }
1706
1707 if (persist) {
1708 enabled_persistent_ = enable;
Darin Petkove7c6ad32012-06-29 10:22:09 +02001709 manager_->UpdateDevice(this);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001710 }
1711
mukesh agrawal28185512013-10-18 16:57:09 -07001712 SetEnabledUnchecked(enable, error, callback);
1713}
1714
1715void Device::SetEnabledUnchecked(bool enable, Error *error,
1716 const ResultCallback &on_enable_complete) {
Eric Shienbrood9a245532012-03-07 14:20:39 -05001717 enabled_pending_ = enable;
mukesh agrawal28185512013-10-18 16:57:09 -07001718 EnabledStateChangedCallback chained_callback =
Eric Shienbrood9a245532012-03-07 14:20:39 -05001719 Bind(&Device::OnEnabledStateChanged,
mukesh agrawal28185512013-10-18 16:57:09 -07001720 weak_ptr_factory_.GetWeakPtr(), on_enable_complete);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001721 if (enable) {
1722 running_ = true;
mukesh agrawal28185512013-10-18 16:57:09 -07001723 Start(error, chained_callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001724 } else {
1725 running_ = false;
1726 DestroyIPConfig(); // breaks a reference cycle
Ben Chancc225ef2014-09-30 13:26:51 -07001727 SelectService(nullptr); // breaks a reference cycle
Eric Shienbrood9a245532012-03-07 14:20:39 -05001728 rtnl_handler_->SetInterfaceFlags(interface_index(), 0, IFF_UP);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001729 SLOG(this, 3) << "Device " << link_name_ << " ipconfig_ "
1730 << (ipconfig_ ? "is set." : "is not set.");
1731 SLOG(this, 3) << "Device " << link_name_ << " ip6config_ "
1732 << (ip6config_ ? "is set." : "is not set.");
1733 SLOG(this, 3) << "Device " << link_name_ << " connection_ "
1734 << (connection_ ? "is set." : "is not set.");
1735 SLOG(this, 3) << "Device " << link_name_ << " selected_service_ "
1736 << (selected_service_ ? "is set." : "is not set.");
mukesh agrawal28185512013-10-18 16:57:09 -07001737 Stop(error, chained_callback);
Eric Shienbrood9a245532012-03-07 14:20:39 -05001738 }
1739}
1740
Paul Stewartd4f26482014-04-25 19:12:03 -07001741void Device::UpdateIPConfigsProperty() {
1742 adaptor_->EmitRpcIdentifierArrayChanged(
Ben Chancc225ef2014-09-30 13:26:51 -07001743 kIPConfigsProperty, AvailableIPConfigs(nullptr));
Paul Stewartd4f26482014-04-25 19:12:03 -07001744}
1745
Peter Qiu62abf312015-05-05 12:58:05 -07001746bool Device::ResolvePeerMacAddress(const string &input,
1747 string *output,
1748 Error *error) {
1749 if (!MakeHardwareAddressFromString(input).empty()) {
1750 // Input is already a MAC address.
1751 *output = input;
1752 return true;
1753 }
1754
1755 IPAddress ip_address(IPAddress::kFamilyIPv4);
1756 if (!ip_address.SetAddressFromString(input)) {
1757 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
1758 "Peer is neither an IP Address nor a MAC address");
1759 return false;
1760 }
1761
1762 // Peer address was specified as an IP address which we need to resolve.
1763 const DeviceInfo *device_info = manager()->device_info();
1764 if (!device_info->HasDirectConnectivityTo(interface_index_, ip_address)) {
1765 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
1766 "IP address is not local to this interface");
1767 return false;
1768 }
1769
1770 ByteString mac_address;
1771 if (device_info->GetMACAddressOfPeer(interface_index_,
1772 ip_address,
1773 &mac_address)) {
1774 *output = MakeStringFromHardwareAddress(
1775 vector<uint8_t>(mac_address.GetConstData(),
1776 mac_address.GetConstData() +
1777 mac_address.GetLength()));
1778 SLOG(this, 2) << "ARP cache lookup returned peer: " << *output;
1779 return true;
1780 }
1781
1782 if (!Icmp().TransmitEchoRequest(ip_address)) {
1783 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed,
1784 "Failed to send ICMP request to peer to setup ARP");
1785 } else {
1786 // ARP request was transmitted successfully, address resolution is still
1787 // pending.
1788 error->Populate(Error::kInProgress,
1789 "Peer MAC address was not found in the ARP cache, "
1790 "but an ARP request was sent to find it. "
1791 "Please try again.");
1792 }
1793 return false;
1794}
1795
1796// static
1797vector<uint8_t> Device::MakeHardwareAddressFromString(
1798 const string &address_string) {
1799 string address_nosep;
1800 base::RemoveChars(address_string, ":", &address_nosep);
1801 vector<uint8_t> address_bytes;
1802 base::HexStringToBytes(address_nosep, &address_bytes);
1803 if (address_bytes.size() != kHardwareAddressLength) {
1804 return vector<uint8_t>();
1805 }
1806 return address_bytes;
1807}
1808
1809// static
1810string Device::MakeStringFromHardwareAddress(
1811 const vector<uint8_t> &address_bytes) {
1812 CHECK_EQ(kHardwareAddressLength, address_bytes.size());
1813 return StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
1814 address_bytes[0], address_bytes[1], address_bytes[2],
1815 address_bytes[3], address_bytes[4], address_bytes[5]);
1816}
1817
Paul Stewart75897df2011-04-27 09:05:53 -07001818} // namespace shill